当我们训练神经网络时,我们通常使用梯度下降,它依赖于连续的,可微分的实值成本函数。例如,最终成本函数可能采用均方误差。或者换句话说,梯度下降隐含地假设最终目标是回归 - 以最小化实值误差测量。
有时我们希望神经网络做的是执行分类 - 给定输入,将其分类为两个或更多个离散类别。在这种情况下,用户关心的最终目标是分类准确性 - 正确分类的案例百分比。
但是当我们使用神经网络进行分类时,虽然我们的目标是分类准确性,并不是神经网络试图优化的。神经网络仍在尝试优化实值成本函数。有时候这些指向同一个方向,但有时它们并不是。特别是,我一直在遇到神经网络经过训练以正确最小化成本函数的情况,其分类精度比简单的手工编码阈值比较差。
我已经使用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))
答案 0 :(得分:4)
我仍然不确定这是否是一个好的问题,更不用说适合SO了;不过,我会尝试一下,也许你会发现我的答案中至少有一些元素有用。
我们如何训练神经网络以最终最大化分类准确度?
我想要一种方法来获得更接近准确度的连续代理功能
首先,今天用于(深层)神经网络中的分类任务的损失函数并没有用它们发明,但它可以追溯到几十年,它实际上来自逻辑回归的早期阶段。以下是二元分类的简单情况的等式:
背后的想法恰恰是提出连续& amp;可微的函数,这样我们就可以利用(广泛的,仍在扩展的)凸优化库来解决分类问题。
可以肯定地说,鉴于上述所需的数学约束,上述损失函数是迄今为止 的最佳值。
我们是否应该考虑这个问题(即更接近准确度)解决并完成?至少在原则上,没有。我已经足够老了,可以记住一个时代,即实际可用的唯一激活函数是tanh
和sigmoid
;然后是ReLU并给了这个领域一个真正的推动力。同样,有人可能最终会想出一个更好的损失函数,但可以说这会发生在研究论文中,而不是作为SO问题的答案......
也就是说,当前的损失函数来自概率和信息理论的非常基本的考虑因素(与当前的深度学习领域形成鲜明对比的领域,是坚定的理论基础)基金会)至少会产生一些疑问,以确定更好的损失提议是否即将到来。
关于损失与准确性之间的关系还有另一个微妙的观点,这使得后者在质量上与前者不同,并且在这种讨论中经常丢失。让我详细说明......
与此讨论相关的所有分类器(即神经网络,逻辑回归等)都是概率;也就是说,它们不会返回硬类成员资格(0/1),而是返回类概率([0,1]中的连续实数)。
将简单讨论限制为二进制情况,在将类概率转换为(硬)类成员资格时,我们隐含地涉及阈值,通常等于0.5,例如if {{ 1}},然后是p[i] > 0.5
。现在,我们可以发现许多情况,这种天真的默认阈值选择不起作用(首先想到的是严重不平衡的数据集),我们必须选择不同的数据集。但我们在这里讨论的重点是,这个阈值选择虽然对准确性至关重要,但它完全外部到最小化损失的数学优化问题,并作为进一步的&# 34;绝缘层"在他们之间,妥协了简单的观点,即损失只是准确性的代表(事实并非如此)。
扩大了一些已经广泛的讨论:我们是否可以完全摆脱连续和数学优化的(非常)限制约束?可区分的功能?换句话说,我们可以消除反向传播和梯度下降吗?
嗯,我们实际上已经这样做了,至少在强化学习的子领域:2017年是new research from OpenAI所谓的进化策略 made headlines 。作为额外的奖励,这里有一个超新鲜的(2017年12月)paper by Uber,在社区中再次产生much enthusiasm。
这是我的想法,基于我对你的问题的理解。即使这种理解不正确,正如我已经说过的那样,希望你能在这里找到一些有用的元素......
答案 1 :(得分:1)
我认为你忘了通过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