本文由斯坦福CS224n翻译整理而来
单个神经元是神经网络的基本单位,其主要接受一个n维的向量x,输出为一个激活函数的输出a
每个神经元均可拟合一种非线性的变化形势,上图采用的主要是基于sigmoid函数的神经元。神经元内部的主要参数为一个n维向量的参数 ω 和一个偏移量b。
每一个神经网络可以看作是同时运行多个逻辑回归
如果将多个神经元组合在一起那么就形成了一个单层神经网络,其参数也将变成一个集合 {ω(1),⋯,ω(m)} 以及 {b(1),⋯,b(m)}
为了更加好的表示多个复杂的变量,利用矩阵标记的形式标记如下
以一个实体识别的例子介绍,考虑如下的实体识别任务
“Museums in Paris are amazing”
这里我们要识别Paris是否是一个命名实体。在这个例子当中,我们不仅仅需要了解中心词的上下文是否存在,因为只计算上下文是否存在并不能得到上下文的 全部信息,还有一些其它的联系可以用于改进分类,比如只有当in在第二个词的时候,Museums才会成为第一个词。这种非线性的关系无法通过直接利用Softmax函数得到,因此,需要多个神经元提取不同的特征。因此,我们可以用另一个矩阵 U∈ℝ 生成一个未经规范化的分数用于分类任务
同众多的机器学习方法相同,神经网络也需要目标函数,最为有效的目标函数是最大边缘目标函数,他的主要目的是让对的标签得到的分数尽可能高
利用我们之前的例子,我们有两个句子,分别为正确的和错误的标签
“Museums in Paris are amazing”(True)
“Not all Museums in Paris”(False)
我们假定正确的句子的分数为s,错误的句子的分数为 sc ,因此我们可以得到一个目标函数
基本设定如下
- xi 为神经网络的输入,s为神经网络的输出
- 在每一层(包括输入层和输出层),第k层的第j个神经元接受输入 z(k)j 并输出 a(k)j
- 我们将在向后传导过程中在 z(k)j 处的错误为 δ(k)j
- 当k等于1时,指的是第一层而不是第一层隐层,对于输入层 xj=z(k)j=a(k)j
- W(k) 是从k层到k+1层到转移矩阵
整个bp算法本质在于从目标函数出发,逐层计算每一个对于最终目标函数到误差所作出到贡献
只需要记住三个公式就可以
为了更加简便的计算,引入矩阵形式的公式,分别如下
这里主要介绍了一个梯度检查方法,主要用于对分析得到的梯度进行检查,其基本公式为
def eval_numerical_gradient(f, x):
"""
- f 为代价函数
- x 需要计算梯度的点
"""
fx = f(x) # 原始点的损失函数值
grad = np.zeros(x.shape)
h = 0.00001
# 遍历x的所有位置的数字
it = np.nditer(x, flags=[’multi_index’],
op_flags=[’readwrite’])
while not it.finished:
ix = it.multi_index
old_value = x[ix]
x[ix] = old_value + h #添加一个增量
fxh_left = f(x) #计算f(x + h)
x[ix] = old_value - h #减少一个增量
fxh_right = f(x) #计算f(x - h)
x[ix] = old_value #还原现场
#计算偏导数
grad[ix] = (fxh_left - fxh_right) / (2*h)
it.iternext() #跳到下一个维度
return grad
如同一般的机器学习方法一样,正则化的引入可以避免陷入过拟合的情况,我们可以对目标函数加入L2正则化参数
Dropout是一种非常有用的正则化方法。模型训练时,在每个前向后向的传导中,以 1−p 的概率随机丢弃一部分神经元;在测试时,利用整个网络进行预测。实验证明,这可以有效的避免了过拟合,并且获得更好的性能。关于这一技术的解释,一种比较直观的说法认为通过这种方式可以同时训练很多小网络并且在预测时取其均值。
在实际使用过程中,对于每一层得到的结果,以概率 p 保留每一个神经元的值,其余设置为0。这样,在BP的过程中,我们只传导这些保留神经元的梯度。最后,在预测的时候,利用整个网络进行预测。然而,dropout能顺利工作的关键一点在于每个神经元在测试时的期望输出应该同训练时相同。因此,在测试时,需要对每个神经元除以一个固定的值。
备注:这里查阅了一下其他的资料,在做rescale的时候,有两种选择:一种是测试阶段不同,在训练阶段每一个保留的神经元的输出除以p;第二种是训练阶段不变,在测试阶段每一个神经元的输出乘以 1−p
常用对激活函数总结如下:
sigmoid
最为常用的函数
Tanh
tanh函数是sigmoid函数的另一种变形,它被发现可以比sigmoid函数更加快速的收敛
Hard tanh
这个函数比tanh函数的计算更为简便,因为作为一个分段线性函数,计算速度更加快速
Soft sign
该函数是类似于tanh函数的另一种非线性函数,相比于hard tanh,该函数变化更加柔和
ReLU
ReLU是目前一种非常流行的选择,因为当z取很大也不会饱和
Leaky ReLU
传统的ReLU函数对于非正的z不会传递一点误差,这种函数做了一定的调整,使得当z为负的时候依旧可以传递一点误差
一些常见的数据预处理的手段有:
Mean Subtraction
零中心化(zero-center)是较为常见的一种数据预处理手段,即对于数据中的每一个维度减去对应的均值。在实际使用中,需要注意的是均值只通过训练集计算得到,在训练集、测试集和交叉验证集中均要减去这个向量。
Normalization
这是另一个常用的预处理手段。对于输入的每一个特征维度,将其保持在相同的数据范围中。通过该处理,可以保证特征的重要程度相同。在实现的过程中,对于每个特征除以其对应的标准差,同上一种一样,标注差只通过训练集合计算得到。
Whitening
这个使用相对上述两种并不是十分广泛。该方法希望将数据转化为一个具有单位协方差矩阵的数据,即特征之间线性无关且每个特征的方差为1。实现的过程为:首先通过零中心化处理数据 X 得到X′,随后进行SVD分解得到矩阵 U,S,V ;计算 UX′ 将数据投影到 U 所对应的线性空间;最终,对于得到的矩阵中的每个维度,除以其对应于S中的奇异值来合理控制数据的范围。(如果奇异值为0,那么可以除以一个比较小的值)
关于参数的初始化,经验研究表明在sigmoid和tanh激活函数中,当W处于如下的均匀分布时,会得到最好的收敛剂速度
两种研究成果
RONAN COLLOBERT
对于 Wij,W∈ℝn(l+1)×n(l) ,该参数的学习率为
decrease by time
学习率随着时间的变化而变化,有两种方式:
这是受物理力学概念影响得到的一种梯度下降的变种。
AdaGrad是一种SGD的变种实现,同SGD的主要区别在于每个参数的学习率依赖于该参数过去的梯度更新历史。形式化表述为
# Assume the gradient dx and parameter vector x
cache += dx**2
x += - learning_rate * dx / np.sqrt(cache + 1e-8)
另外两种种常用的学习率方式为RMSProp和Adam,他们的实现方式如下
# 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 = beta1*m + (1-beta1)*dx
v = beta2*v + (1-beta2)*(dx**2)
x += - learning_rate * m / (np.sqrt(v) + eps)
RMSProp是AdaGrad的一个变种,不同的是,学习率不一定会单调变小。
Adam将RMSProp和动量更新的方式进行了融合,一般来说可以作为一个通用选择。
[1] Williams D E R G E H R J, Hinton G E. Learning representations by back-propagating errors[J]. Nature, 1986, 323: 533-536.
[2] Srivastava N, Hinton G, Krizhevsky A, et al. Dropout: A simple way to prevent neural networks from overfitting[J]. The Journal of Machine Learning Research, 2014, 15(1): 1929-1958.