CS224N课程笔记:神经网络与反向传播
The following article is from NewBeeNLP Author Ryan
NewBeeNLP原创出品
公众号专栏作者@Ryan
知乎 | 机器学习课程笔记
CS224N课程笔记系列,持续更新中
课程主页:http://web.stanford.edu/class/cs224n/
1、Neural Networks: Foundations
在前面的讨论中认为,因为大部分数据是线性不可分的所以需要非线性分类器,不然的话线性分类器在这些数据上的表现是有限的。神经网络就是如下图所示的一类具有非线性决策分界的分类器。现在我们知道神经网络创建的决策边界,让我们看看这是如何创建的。
1.1 Neural
一个神经元是用 个输入和生成单个输出的通用的计算单元。不同的神经元根据它们不同的参数(一般认为是神经元的权值)会有不同的输出。对神经元来说一个常见的选择是“ ”,或者称为“二元逻辑回归”单元。这种神经元以 维的向量作为输入,然后计算出一个激活标量(输出) 。这种神经元也和一个 维的权值向量 和一个偏置标量 相关联。然后这个神经元的输出是:
我们也可以把上面公式中的权值和偏置项结合在一起:
这个公式可以以下图的形式可视化:
1.2 A Single Layer of Neurons
考虑如下图所示将输入 作为多个神经元的输入的情况,我们可以把上述的概念扩展到多个神经元上,如下图所示。
如果我们定义不同的神经元的权值为、偏置为和相对应的激活输出为:
....
让我们定义简化公式以便于更好地表达复杂的网络:
我们现在可以将缩放和偏差的输出写成:
激活函数
那么这些激活的作用是什么呢?我们可以把这些激活看作是一些特征加权组合的存在的指标。然后,我们可以使用这些激活的组合来执行分类任务。
1.3 Feed-forward Computation
到目前为止我们知道一个输入向量
其中
1.4 Maximum Margin Objective Function
类似很多的机器学习模型,神经网络需要一个优化目标函数,一个我们想要最小化或最大化的误差。这里我们讨论一个常用的误差度量方法:最大间隔目标函数。使用这个目标函数的背后的思想是保证对“真”标签数据的计算得分要比“假”标签数据的计算得分要高。
回到前面的例子,如果我们令“真”标签窗口
然后,我们对目标函数最大化
然而,上面的优化目标函数是有风险的,因为它不能创造一个安全的间隔。我们希望“真”数据要比“假”数据的得分大于某个正的间隔
我们可以把这个间隔缩放使得
按照上面的公式有,
在这部分我们讨论损失函数
反向传播是一种利用微分链式法则来计算模型上任意参数的损失梯度的方法。为了更进一步理解反向传播,我们先看下图中的一个简单的网络
这里我们使用只有单个隐藏层和单个输出单元的神经网络。现在让我们先建立一些符号定义:
是神经网络的输入。 是神经网络的输出。每层(包括输入和输出层)的神经元都接收一个输入和生成一个输出。第 层的第 个神经元接收标量输入 和生成一个标量激活输出 。我们把反向传播误差在 的计算定义为 。第1层认为是输入层而不是第1个隐藏层。对输入层, 。 是将第k层的输出映射到第k+1层的输入的转移矩阵,因此将这个新的符号用在 中的例子 和 。
现在我们开始反向传播:假设损失函数
为了简化我们只分析
我们可以看到梯度计算最后可以简化为
我们以下图为例,让我们从“误差共享/分配”的来阐释一下反向传播,现在我们要更新
如果要控制列表的层级,则需要在符号-
前使用空格。如下:
我们从 的1的误差信号开始反向传播。然后我们把误差与把 映射到 的神经元的局部梯度相乘。在这个例子中梯度正好等于1 ,则误差仍然为1。所以有 。这里误差信号1已经到达 。我们现在需要分配误差信号使得误差的“误差共享”到达 。现在在 的误差为 (在 的误差信号为 )。因此在 的误差为 。与第2步的做法相同,我们把在 的误差 映射到 的神经元的局部梯度相乘。在这里局部梯度为 。因此在 的误差是 ,我们将其定义为 。最后,我们通过将上面的误差与参与前向计算的 相乘,把误差的“误差共享”分配到 。所以,对于 的梯度损失可以计算为 。注意我们使用这个方法得到的结果是和之前微分的方法的结果是完全一样的。因此,计算网络中的相应参数的梯度误差既可以使用链式法则也可以使用误差共享和分配的方法-这两个方法能得到相同结果。
「偏置更新」 偏置项
「从
我们有从
向后传播的误差 ,如下图所示我们通过把
与路径上的权值 相乘,将这个误差反向传播到 。因此在
接收的误差是 。然而,
在前向计算可能出下图的情况,会参与下一层中的多个神经元的计算。那么第 层的第 个神经元的误差也要使用上一步方法将误差反向传播到 上。因此现在在
接收的误差是。实际上,我们可以把上面误差和简化为
。现在我们有在
正确的误差,然后将其与局部梯度 相乘,把误差信息反向传到第 层的第 个神经元上。因此到达
的误差为。
1.6 Training with Backpropagation – Vectorized
到目前为止,我们讨论了对模型中的给定参数计算梯度的方法。这里会一般泛化上面的方法,让我们可以直接一次过更新权值矩阵和偏置向量。注意这只是对上面模型的简单地扩展,这将有助于更好理解在矩阵-向量级别上进行误差反向传播的方法。
对更定的参数
因此我们可以将整个矩阵形式的梯度写为在矩阵的中反向传播的误差向量和前向激活输出的外积。
现在我们来看看如何能够计算误差向量
在上面的公式中
「计算效率:」 在探索了 element-wise 的更新和 vector-wise 的更新之后,必须认识到在科学计算环境中,如 MATLAB 或 Python(使用 Numpy / Scipy 库),向量化运算的计算效率是非常高的。因此在实际中应该使用向量化运算。此外,我们也要减少反向传播中的多余的计算-例如,注意到
2、 Neural Networks: Tips and Tricks
2.1 Gradient Check
在上一部分中,我们详细地讨论了如何用基于微积分的方法计算神经网络中的参数的误差梯度/更新。这里我们介绍一种用数值近似这些梯度的方法-虽然在计算上的低效不能直接用于训练神经网络,这种方法可以非常准确地估计任何参数的导数;因此,它可以作为对导数的正确性的有用的检查。给定一个模型的参数向量
其中
当然,还是有一点不同-上面的定义仅仅在正向扰动
现在你可能会产生疑问,如果这个方法这么准确,为什么我们不用它而不是用反向传播来计算神经网络的梯度?这是因为效率的问题-每当我们想计算一个元素的梯度,需要在网络中做两次前向传播,这样是很耗费计算资源的。再者,很多大规模的神经网络含有几百万的参数,对每个参数都计算两次明显不是一个好的选择。同时在例如SGD这样的优化技术中,我们需要通过数千次的迭代来计算梯度,使用这样的方法很快会变得难以应付。这种低效性是我们只使用梯度检验来验证我们的分析梯度的正确性的原因。梯度检验的实现如下所示:
def eval_numerical_gradient(f, x):
"""
a naive implementation of numerical gradient of f at x
- f should be a function that takes a single argument
- x is the point (numpy array) to evaluate the gradient
at
"""
f(x) = f(x) # evaluate function value at original point
grad = np.zeros(x.shape)
h = 0.00001
# iterate over all indexes in x
it = np.nditer(x, flags=['multi_index',
op_flags=['readwrite'])
while not it.finished:
# evaluate function at x+h
ix = it.multi_index
old_value = x[ix]
x[ix] = old_value + h # increment by h
fxh_left = f(x) # evaluate f(x + h)
x[ix] = old_value - h # decrement by h
fxh_right = f(x) # evaluate f(x - h)
# restore to previous value (very important!)
x[ix] = old_value
# compute the partial derivative
# the slope
grad[ix] = (fxh_left - fxh_right) / (2 * h)
it.iternext() # step to next dimension
return grad
2.2 Regularization
和很多机器学习的模型一样,神经网络很容易过拟合,这令到模型在训练集上能获得近乎完美的表现,但是却不能泛化到测试集上。一个常见的用于解决过拟合(“高方差问题”)的方法是使用
在上面的公式中,
由于
选择一个合适的
有时候我们会用到其他类型的正则项,例如
2.3 Dropout
这个想法是简单而有效的-在训练过程中,在每次的前向/反向传播中我们按照一定概率(1-p)随机地“
在实际中,在实践中,我们使用
2.4 Neuron Units
到目前为止,我们讨论了含有 sigmoidal neurons 的非线性分类的神经网络。但是在很多应用中,使用其他激活函数可以设计更好的神经网络。下面列出一些常见的激活函数和激活函数的梯度定义,它们可以和前面讨论过的 sigmoidal 函数互相替换。
Sigmoid:这是我们讨论过的常用选择,激活函数
其中
「
其中
「
「
softsign
其中
「
「
其中
2.5 Data Preprocessing
与机器学习模型的情况一样,要想模型在当前任务上获得合理的表现的关键步骤是对数据进行合理的预处理。
「Mean Subtraction:」 给定一组输入数据
「Normalization:」 另外一个常见的技术(虽然没有Mean Subtraction常用)是将每个输入特征维度缩小,让每个输入特征维度具有相似的幅度范围。这是很有用的,因此不同的输入特征是用不同“单位”度量,但是最初的时候我们经常认为所有的特征同样重要。实现方法是将特征除以它们各自在训练集中计算的标准差。
「Whitening:」 相比上述的两个方法,Whitening没有那么常用,它本质上是数据经过转换后,特征之间相关性较低,所有特征具有相同的方差(协方差阵为1)。首先对数据进行Mean Subtraction处理,得到
2.6 Parameter Initialization
让神经网络实现最佳性能的关键一步是以合理的方式初始化参数。一个好的起始方法是将权值初始化为通常分布在0附近的很小的随机数-在实践中效果还不错。在论文《Understanding the difficulty of training deep feedforward neural networks (2010)》研究不同权值和偏置初始化方案对训练动力(training dynamics)的影响。实验结果表明,对于sigmoid和tanh激活单元,当一个权值矩阵
其中
2.7 Learning Strategies
训练期间模型参数更新的速率/幅度可以使用学习率进行控制。在最简单的梯度下降公式中,
你可能会认为如果要更快地收敛,我们应该对 取一个较大的值-然而,在更快的收敛速度下并不能保证更快的收敛。实际上,如果学习率非常高,我们可能会遇到损失函数难以收敛的情况,因为参数更新幅度过大,会导致模型越过凸优化的极小值点,如下图所示。在非凸模型中(我们很多时候遇到的模型都是非凸),高学习率的结果是难以预测的,但是损失函数难以收敛的可能性是非常高的。
避免损失函数难以收敛的一个简答的解决方法是使用一个很小的学习率,让模型谨慎地在参数空间中迭代-当然,如果我们使用了一个太小的学习率,损失函数可能不会在合理的时间内收敛,或者会困在局部最优点。因此,与任何其他超参数一样,学习率必须有效地调整。
深度学习系统中最消耗计算资源的是训练阶段,一些研究已在尝试提升设置学习率的新方法。例如, 通过取
还有其他已经被证明有效的技术-这个方法叫 annealing,在多次迭代之后,学习率以以下方式降低:保证以一个高的的学习率开始训练和快速逼近最小值;当越来越接近最小值时,开始降低学习率,让我们可以在更细微的范围内找到最优值。一个常见的实现 annealing 的方法是在 [公式] 每次的迭代学习后,通过一个因子
在上述的方案中,
2.8 Momentum Updates
动量方法,灵感来自于物理学中的对动力学的研究,是梯度下降方法的一种变体,尝试使用更新的“速度”的一种更有效的更新方案。动量更新的伪代码如下所示:
# Computes a standard momentum update
# on parameters x
v = mu * v - alpha * grad_x
x += v
2.9 Adaptive Optimization Methods
其中
在这个技术中,我们看到如果梯度的历史的
# Assume the gradient dx and parameter vector x
cache += dx ** 2
x += -learning_rate * dx / np.sqrt(cache + 1e-8)
其他常见的自适应方法有
# Update rule for RMS prop
cache = decay_rate * cache + (1 - decay_rate) * dx ** 2
x += -learning_rate * dx / (np.sqrt(cache) + eps)
# Update rule for Adam
m = beta * m + (1 - beta1) * dx
v = beta * v + (1 - beta2) * (dx ** 2)
x += -learning_rate * m / (np.sqrt(v) + eps)
2.10 More reference
如果希望了解以上的梯度优化算法的具体细节,可以阅读这篇文章:An overview of gradient descent optimization algorithms。
今天给大家推荐一本机器学习、深度学习的人都应该听说过一本经典教材:《Pattern Recognition and Machine Learning》,中文译名《模式识别与机器学习》,简称 PRML。出自微软剑桥研究院实验室主任 Christopher Bishop 大神之手。对,就是豆瓣评分 9.5 的这本书。