当我们训练神经网络时,我们通常使用梯度下降,它依赖于一个连续的、可微分的实值成本函数。例如,最终成本函数可能采用均方误差。或者换一种说法,梯度下降隐含地假设最终目标是回归——最小化实值误差度量。
有时我们希望神经网络做的是执行分类——给定一个输入,将其分类为两个或多个离散类别。在这种情况下,用户关心的最终目标是分类准确性——正确分类的案例百分比。
但是当我们使用神经网络进行分类时,虽然我们的目标是分类准确率,但这并不是神经网络试图优化的目标。神经网络仍在尝试优化实值成本函数。有时它们指向同一个方向,但有时它们不指向同一个方向。特别是,我遇到过这样的情况:经过训练以正确最小化成本函数的神经网络,其分类精度比简单的手工编码阈值比较差。
我已经使用 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))