成本函数训练目标与准确度期望目标

Posted

技术标签:

【中文标题】成本函数训练目标与准确度期望目标【英文标题】:Cost function training target versus accuracy desired goal 【发布时间】:2018-06-02 03:18:33 【问题描述】:

当我们训练神经网络时,我们通常使用梯度下降,它依赖于一个连续的、可微分的实值成本函数。例如,最终成本函数可能采用均方误差。或者换一种说法,梯度下降隐含地假设最终目标是回归 - 以最小化实值误差度量。

有时我们希望神经网络执行分类 - 给定输入,将其分类为两个或多个离散类别。在这种情况下,用户关心的最终目标是分类准确率——正确分类的案例百分比。

但是当我们使用神经网络进行分类时,虽然我们的目标是分类准确率,这并不是神经网络试图优化的目标。神经网络仍在尝试优化实值成本函数。有时它们指向同一个方向,但有时它们不指向同一个方向。特别是,我遇到过这样的情况:经过训练以正确最小化成本函数的神经网络,其分类准确度比简单的手工编码阈值比较差。

我使用 TensorFlow 将其归结为一个最小的测试用例。它设置了一个感知器(没有隐藏层的神经网络),在绝对最小的数据集(一个输入变量,一个二进制输出变量)上对其进行训练,评估结果的分类准确度,然后将其与简单手的分类准确度进行比较-编码阈值比较;结果分别为 60% 和 80%。直观地说,这是因为具有较大输入值的单个异常值会生成相应较大的输出值,因此最小化成本函数的方法是更加努力地适应这种情况,在此过程中误分类另外两种普通情况。感知器正在正确地做它被告知要做的事情;只是这与我们真正想要的分类器不匹配。但是分类精度不是一个连续可微的函数,所以不能作为梯度下降的目标。

我们如何训练神经网络以使其最终最大化分类准确度?

import numpy as np
import tensorflow as tf
sess = tf.InteractiveSession()
tf.set_random_seed(1)

# Parameters
epochs = 10000
learning_rate = 0.01

# Data
train_X = [
    [0],
    [0],
    [2],
    [2],
    [9],
]
train_Y = [
    0,
    0,
    1,
    1,
    0,
]

rows = np.shape(train_X)[0]
cols = np.shape(train_X)[1]

# Inputs and outputs
X = tf.placeholder(tf.float32)
Y = tf.placeholder(tf.float32)

# Weights
W = tf.Variable(tf.random_normal([cols]))
b = tf.Variable(tf.random_normal([]))

# Model
pred = tf.tensordot(X, W, 1) + b
cost = tf.reduce_sum((pred-Y)**2/rows)
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)
tf.global_variables_initializer().run()

# Train
for epoch in range(epochs):
    # Print update at successive doublings of time
    if epoch&(epoch-1) == 0 or epoch == epochs-1:
        print('   '.format(
            epoch,
            cost.eval(X: train_X, Y: train_Y),
            W.eval(),
            b.eval(),
            ))
    optimizer.run(X: train_X, Y: train_Y)

# Classification accuracy of perceptron
classifications = [pred.eval(X: x) > 0.5 for x in train_X]
correct = sum([p == y for (p, y) in zip(classifications, train_Y)])
print('/ = perceptron accuracy'.format(correct, rows))

# Classification accuracy of hand-coded threshold comparison
classifications = [x[0] > 1.0 for x in train_X]
correct = sum([p == y for (p, y) in zip(classifications, train_Y)])
print('/ = threshold accuracy'.format(correct, rows))

【问题讨论】:

只是为了确保我理解你的问题:你真的在问,在 SO,我们如何 [逃离连续函数的数学优化的整个大厦,这样我们就可以直接优化准确性(最好在一个简短的 Tensorflow 脚本中进行演示)]?或者您真的在要求为什么我们不能 [直接优化准确性,而不是损失等代理] 的解释/直觉?诚然,鉴于论坛 (SO),第一个问题是荒谬的,而第二个问题可以说是合理的...... @desertnaut 我正在寻求一种方法来获得更接近准确性的连续代理功能,或者解释为什么没有代理功能,或者解释为什么我忽略了某些东西我没有想到这会让问题消失,而不会影响哪个更有可能。 【参考方案1】:

我们如何训练神经网络以使其最终最大化分类准确度?

我正在寻求一种方法来获得更接近准确度的连续代理函数

首先,今天用于(深度)神经网络中的分类任务的损失函数并不是他们发明的,但它可以追溯到几十年前,它实际上来自逻辑回归的早期阶段。这是二分类的简单情况的方程:

其背后的想法正是提出一个连续且可微的函数,以便我们能够利用凸优化的(庞大且仍在扩展的)武器库来解决分类问题。

可以肯定地说,鉴于上述所需的数学约束,上述损失函数是我们目前拥有的最好的损失函数。

我们是否应该考虑解决并完成这个问题(即更好地近似准确度)?至少在原则上,不会。我已经大到可以记住一个时代,当时唯一可用的激活函数是 tanhsigmoid;然后是 ReLU 并真正推动了该领域。同样,有人最终可能会提出更好的损失函数,但可以说这将发生在研究论文中,而不是作为 SO 问题的答案......

也就是说,当前的损失函数来自概率和信息论的非常基本考虑(这些领域与当前的深度学习领域形成鲜明对比,站在坚定的理论基础上)基金会)至少让人怀疑是否有更好的损失提案即将到来。


关于损失和准确性之间的关系还有一个微妙的点,这使得后者在性质上与前者有所不同,并且经常在此类讨论中丢失。让我详细说明...

与本次讨论相关的所有分类器(即神经网络、逻辑回归等)都是概率分类器;也就是说,它们不返回硬类成员资格 (0/1),而是返回类概率([0, 1] 中的连续实数)。

为了简单起见,将讨论限制为二元情况,当将类概率转换为(硬)类成员时,我们隐含地涉及一个阈值,通常等于 0.5,例如如果@987654330 @,然后是 class[i] = "1"。现在,我们可以发现很多情况下,这种幼稚的默认阈值选择不起作用(首先想到的是严重不平衡的数据集),我们将不得不选择不同的。但是我们在这里讨论的重点是,这个阈值选择虽然对准确性至关重要,但对于最小化损失的数学优化问题完全是外部,并且作为进一步的“绝缘”层”,损害了损失只是准确性的一个简单的观点(它不是)。就像this Cross Validated thread的答案一样好:

当您为新样本的每个类别输出一个概率时,您的练习的统计部分就结束了。选择一个阈值,将新观察分类为 1 与 0 的阈值不再是 统计数据 的一部分。它是 decision 组件的一部分。


扩大已经很广泛的讨论:我们能否完全摆脱(非常)连续和可微函数的数学优化的限制约束?换句话说,我们可以取消反向传播和梯度下降吗?

嗯,我们实际上已经在这样做了,至少在强化学习的子领域:2017 年是 new research from OpenAI 在称为进化策略 made headlines 的一年。作为额外奖励,这里有一个关于该主题的超新鲜(2017 年 12 月)paper by Uber,再次在社区中生成much enthusiasm。

【讨论】:

【参考方案2】:

我认为您忘记通过 simgoid 传递您的输出。固定如下:

import numpy as np
import tensorflow as tf
sess = tf.InteractiveSession()
tf.set_random_seed(1)

# Parameters
epochs = 10000
learning_rate = 0.01

# Data
train_X = [
    [0],
    [0],
    [2],
    [2],
    [9],
]
train_Y = [
    0,
    0,
    1,
    1,
    0,
]

rows = np.shape(train_X)[0]
cols = np.shape(train_X)[1]

# Inputs and outputs
X = tf.placeholder(tf.float32)
Y = tf.placeholder(tf.float32)

# Weights
W = tf.Variable(tf.random_normal([cols]))
b = tf.Variable(tf.random_normal([]))

# Model
# CHANGE HERE: Remember, you need an activation function!
pred = tf.nn.sigmoid(tf.tensordot(X, W, 1) + b)
cost = tf.reduce_sum((pred-Y)**2/rows)
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)
tf.global_variables_initializer().run()

# Train
for epoch in range(epochs):
    # Print update at successive doublings of time
    if epoch&(epoch-1) == 0 or epoch == epochs-1:
        print('   '.format(
            epoch,
            cost.eval(X: train_X, Y: train_Y),
            W.eval(),
            b.eval(),
            ))
    optimizer.run(X: train_X, Y: train_Y)

# Classification accuracy of perceptron
classifications = [pred.eval(X: x) > 0.5 for x in train_X]
correct = sum([p == y for (p, y) in zip(classifications, train_Y)])
print('/ = perceptron accuracy'.format(correct, rows))

# Classification accuracy of hand-coded threshold comparison
classifications = [x[0] > 1.0 for x in train_X]
correct = sum([p == y for (p, y) in zip(classifications, train_Y)])
print('/ = threshold accuracy'.format(correct, rows))

输出:

0 0.28319069743156433 [ 0.75648874] -0.9745011329650879
1 0.28302448987960815 [ 0.75775659] -0.9742625951766968
2 0.28285878896713257 [ 0.75902224] -0.9740257859230042
4 0.28252947330474854 [ 0.76154679] -0.97355717420578
8 0.28187844157218933 [ 0.76656926] -0.9726400971412659
16 0.28060704469680786 [ 0.77650583] -0.970885694026947
32 0.27818527817726135 [ 0.79593837] -0.9676888585090637
64 0.2738055884838104 [ 0.83302218] -0.9624817967414856
128 0.26666420698165894 [ 0.90031379] -0.9562843441963196
256 0.25691407918930054 [ 1.01172411] -0.9567816257476807
512 0.2461051195859909 [ 1.17413962] -0.9872989654541016
1024 0.23519910871982574 [ 1.38549554] -1.088881492614746
2048 0.2241383194923401 [ 1.64616168] -1.298340916633606
4096 0.21433120965957642 [ 1.95981205] -1.6126530170440674
8192 0.2075471431016922 [ 2.31746769] -1.989408016204834
9999 0.20618653297424316 [ 2.42539024] -2.1028473377227783
4/5 = perceptron accuracy
4/5 = threshold accuracy

【讨论】:

谢谢! sigmoid 可能会有所帮助似乎是合理的。当我尝试你的代码时,它仍然不起作用,但我认为那是因为你的 TF 使用了不同的随机数序列。当我尝试你的起始 W/b 时,它确实有效...... 使用我的起始 W/b 它仍然无法工作,即使使用相同的代码,它也会到达不同的端点,但这很奇怪,感知器应该总是收敛到全局最优,它们是不应该有局部最优。仍在试图弄清楚这是怎么回事。 好吧,我记得'感知器总是收敛到全局最优',但忘记了正确版本的后半部分'如果数据是线性可分的'。所以全局最优值确实是 sigmoid 的 4/5。 没错,单层网络无法完美解决你的问题(看异或问题home.agh.edu.pl/~vlsi/AI/xor_t/en/main.htm)。尝试添加第二层,看看会发生什么。

以上是关于成本函数训练目标与准确度期望目标的主要内容,如果未能解决你的问题,请参考以下文章

YoloV5+GSConv:基于YoloV5GSConv得小目标检测算法训练

关于模型优化的思考

基于EfficientNet的目标识别仿真

机器学习:梯度下降

常用机器学习算法

方法论机器学习算法概览