2018-04-06 | CS244n | UNLOCK

CS244n Lecture Notes3

Neural Networks: Foundations

现实生活中的数据往往是线性不可分,因此需要类似于NN这种具有非线性决策边界的模型来实现分类任务,那就来看下NN是如何来实现非线性分类的。

A Neuron

一个神经元就是一计算单元,它是构成NN的最基本单元,输入$n$ input生成一个输出,每个神经元的输出是和相连的边也即是权重来决定的。常见的神经元激活函数是Sigmod函数(binary logistics regression),它接收一个$n$维的x,产生一个scalar a,在输入之前会有一个n维的权重向量w和一个bias b作用于x,具体计算为,

通常我们会将b集成得到w中,以表示成向量的形式,结构如图所示。

image.png

A Single Layer of Neurons

将单个神经元扩展到多个神经元的情况,即我们将输入$x$输入到多个神经元中,但依然是单层网络,因为只有一层,结构图如下。
image.png
记不同神经元的权重为$\{w^{(1)},…,w^{(m)}\}$,每个神经元的bias为,相应的神经元输出为

其中,每个w都是一个向量,其维度与x维度相同,m为神经元个数,表示成向量形式。

上面就是多个神经元情况下的输出计算公式,那么如何理解多个神经元情况呢?多个神经元可以理解为不同特征的加权组合,这样一来就可以解释为什么深度学习不需要人工特征工程。

Feed-forward Computation

前面我们已经看到如何将一个输入向量$x \in R^{n}$送到sigmod函数,并产生激活值$a \in R^m$.这个操作背后的含义是什么,如何去理解这个过程。以实体识别为例,这句话“Museums in Pairs are amazing”,要判断Pairs是否是一个实体词。这种情况下,我们不但希望获得词窗口中每个词的词向量,同时也希望能够得到这些词的分类情况。直接通过softmax计算是不能得到期望的结果,通常也需要中间层的输出分数,因此可以采用另外一个矩阵$U \in R^{m \times 1}$来得到非归一化的score,

Maximum Margin Objective Function

和大多数机器学习模型一样,也需要有一种目标函数来度量NN模型,以最小化误差函数,这里介绍一种常用的误差函数-最大间隔,它的目标是使分为true label的score远远大于分为false label的score。
用前文提到NER的例子,记真实词窗口“Museums in Pairs are amazing”对应的score为$s$,错误词窗口“Not all museums in Pairs”对应的score为$s_c$(c的含义是“corrupt”)。我们的优化目标是$maximize(s-s_c)$或者$minimize(s_c-s)$.通常我们会将上述式子进一步变形为$s_c-s > 0$,因为我们关注的仅仅是正例得分大于负例得分其他情况并不关心,所以我们希望误差是这样一种情况,当$s_c> s$时误差为$s_c -s$,否则误差为0,这样目标函数变为,

上述目标函数存在一个问题,它所产生的间隔并不是非常安全,怎么理解这个问题呢。想想一下,我们在做的分类有两个label,正类和负类,我们的目标是找到一个分割平面将这两类样本分开,按照上面的目标函数,正类和负类在分割平面的上(因为是$s_c-s$与0比较),这就存在一个分类风险,平面上点既可以是正类也可是负类。我们期望找的正类的score尽可能高于负类,最好是大到多出来一个微小的$\Delta$,一般我们会令$\Delta=1$,那么新的目标函数为,

其中,$s_c=U^Tf(Wx_c+b)$和$s=U^Tf(Wx+b)$.最大间隔目标函数在SVM算法中有更多的讨论。

Training with Backpropagation - Elemental

这一节具体来讨论一下如何根据cost 函数训练模型参数,当cost为0时参数不需要更新,因为此时的梯度信息为零,参数更新公式为,

通过反向传播算法和链式法则来实现对每个参数的微分,为了进一步理解反向传播的过程,下面通过一个具体的例子来说明。网络结构图如下,
image.png
这个神经网络含有一个单隐层和一个输出单元,符号说明。

  • $x_i$ 网络输入
  • $s$ 网络输出
  • 每一层网络都有输入和输出包括输入层和输出层,记第k层网络的第j个神经元的输入为,神经元激活输出记作
  • 把第k层第j个神经元的反向传播误差记作$\delta_{j}^{k}$
  • 对于第一层来说是输入层,并不是第一个隐含层(出去输入层和输出层以为的层),对于输入层有,
  • 记第k层的输出到第k+1层的输入转换矩阵为$W^{(k)}$,有$W^{1}=W$和$W^{(2)}=U$
    令目标函数为,现在对上图中的(第一层中的第4个神经元的权重),从网络结构中可以看出,这个参数贡献给,由损失函数得到先来求score对权重$W_{ij}^{(1)}$的梯度,其中j=i,
    通过上面的推导过程发现,score对参数的梯度最终等于 是第2层第i个神经元的反向传播误差,乘以是第2层第i个神经元的输入。下图为更新参数的子图
    image.png
    结合上图具体分析在反向传播过程中误差共享对的好处,假设我们对参数$W_{14}^{(1)}$进行更新。
  • 神经元1的误差开始从$a_{1}^{(3)}$(它是神经元1的输出)开始传播
  • 误差乘以神经元1的local gradient,因为神经元1是由,此时的误差为1,即
  • 误差反向向前传播达到,现在误差开始向传播,同样误差也会向其他相连的神经元传播,这里以这个为例进行说明。
  • 此时的误差,因此在的误差为
  • 和第二步一样,误差需要通过神经元下欠传递,因为,所以此神经元的local gradient为
  • 因为的误差为
  • 最后这个误差通过相乘依然向前传播到,因此最终的梯度为
    通过分析网络得到的参数误差梯度和前面通过公式计算得到的一致,因为就可以通过这两种方式计算梯度。

Bias Updates:对于bias的更新和其他参数一样,对于第k层第i个神经元的bias误差是。例如更新,它的梯度为
Generalized steps to propagate ,
示例如图,
image.png
image.png

  • 记$\delta_{i}^{(k)}$为第k层第i神经元输入$z_{i}^{(k)}$的误差,如图上图
  • 通过将误差 乘以路径上的权重传播到,因此在$a_{j}^{(k-1)}$的误差为
  • 因为可能与下一层的多个神经元相连如上图8所示,它也接收第k层中其他节点m的误差,因此接收到的误差为,更进一步的,记作
  • 现在得到了的误差,然后通过乘以神经元的local gradient 继续向前传递
  • 误差传递到了,记作

以上就是误差从第k层传递到k-1层的具体过程。

Training with Backpropagation - Vectorized

上一节中我们讨论在模型中对某个具体的参数计算梯度,这节我们会用矩阵和向量的形式来表示模型参数和偏差,这样就可以通过一次运算计算出所有参数的梯度。对于一个给定参数的误差梯度为,我们记$W^{(k)}$表示从第k层的神经元输出$a^{(k)}$到下一层神经元输入$z^{(k+1)}$的权重矩阵,可以得到误差对整个权重矩阵的梯度,如下
image.png
通过前面的公式我们可以得到误差向量,将它变换为向量形式,

其中$\circ$表示向量之间进行 element wise product即两个向量对应元素之间进行相乘$(\circ: R^{N} \times R^{N} \to R^{N})$
为什么要以矩阵或者向量的形式进行计算呢?因为采用矩阵的形式进行计算,可以通过一个科学计算工具如Numpy/SciPy,而且还可以通过GPU在底层进行优化,另外也减少了计算的冗余。

Neural Networks: Tips and Tricks

前面从数学角度分析了NN背后的原理,这节将从实际应用的角度来分析一些tips 和 tricks。

Gradient Check

下面介绍一种通过数值计算的方式近似求解参数梯度,这种方式可以作为梯度检查的有效判断。给定一个模型参数向量$\theta$ 和loss 函数$J$,则由中心差分公式给出$\theta_i$的数值梯度,

其中,$\epsilon$ 是一个很小的数据通常为$1e^{-5}$,$J(\theta^{(i+)})$是在前向计算过程中对参数$\theta$的第i个元素输入施加一个很小的扰动形成的误差,同理$J(\theta^{(i-)})$施加一个很小的扰动$-\epsilon$.通过这两个前向计算,可以近似计算模型中参数的梯度,因为这种方式是来源梯度的计算公式。
我们知道可以通过梯度检查可以计算参数的梯度,一个很自然的问题是为什么我们不利用梯度检查的方式计算梯度而是使用反向传播呢?主要是因为梯度检查的方式效率太低,每个参数的梯度需要进行2次前向计算,模型中可能会含有成百上万、甚至几十万个参数,这样的计算非常庞大,系统是不可能接受的,而通过反向传播,在每一次迭代的过程中我们可以计算出所有参数的梯度,效率非常高,正是这个原因采用反向传播使得神经网络的训练得到了极大的发展。下面给出一段梯度检查的代码,可以利用这个代码进行梯度检查。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import numpy as np
def eval_numerical_gradient(f, x):
""" A naive implementation of numerical gradient of f at x
Args:
f: should be a function that takes a single argument
x: is the point (numpy array) to evaluate the gradient at
Return:
grad: numerical gradient
"""
fx = f(x) # evaluate function value at original point
grad = np.zeros(fx.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 at f(x+h)
x[ix] = old_value - h # decrement by h
fxh_right = f(x) # evaluate at f(x-h)
x[ix] = old_value # restore to previous value
# compute the partial derivative
grad[ix] = (fxh_left - fxh_right) / (2*h)
it.iternext() # nneext dimension
return grad

Regularization

神经网络和其他机器学习模型一样,很容易过拟合,因为模型会尽可能的利用训练数据去拟合,从而丢掉了泛华能力,也即是处理未知数据的能力。常用的解决过拟合问题(也称作高方差)技术手段是在损失函数中加入有参数构成的正则化项,一般可用的有L1-norm和L2-norm,如下,

在上式中,$\parallel{W^{(i)}}\parallel_{F}$是全中矩阵的范数,W是所有参数矩阵除去偏差,每个元素i都代表一个网络中的权重矩阵, $\lambda$是超参数,用来控制正则化项对损失函数的贡献。正则化项的作用是使模型中的参数不至于过大,从而避免模型过拟合。参数$\lambda$需要不断的进行finetune,过大说明模型参数比较小,导致模型学习能力不够,学习效果变差;过小会造成过拟合。有一点是需要注意的,正则化项中并不含bias。除L2-norm以外,还有L1-norm,dropout等都是正则化技术。

Dropout

Dropout同样是一个有效的正则化技术,首次在论文“Dropout: A Simple Way to Prevent Neural Networks from Overfitting”提出。主要思想在训练阶段,以(1-p)的概率在forward 和backword计算中,随机失活一部分神经元,p是需要设置的超参数,表示保留的概率,在测试阶段用全部的网络进行预测。这种随机失活神经元的做法可以从数据中学到更有价值的信息,防止过拟合,而且能够得到较好的效果。为什么dropout可以有如此的效果呢?一个直观感觉是,在训练阶段随机失活一部神经元,相当于形成了很多个不同的小的网络,而在预测的时候所有这些网络都加入预测,最终结果是这些网络融合的结果。
在实际的实现过程中,首先获得每个神经元的输出$h$,以概率p随机保留每个神经元,或者将其设置为0;在反向传播阶段,只计算那些在前向计算中保留的神经元的梯度,最后在测试阶段,用所有神经元进行预测。

Neuron Units

在神经网络中有各种各样的激活函数,这节会对常用的非线性激活函数进行介绍。

  • Sigmod:公式如下:

    其中,$\sigma(z) \in (0,1)$,函数曲线为:
    image.png
    sigmod函数的导数为,

  • tanh:它和sigmod函数的区别是,它的输出范围在-1 到1 直间,公式如下:

    其中,$tanh(z) \in (-1, 1)$
    函数图像为:
    image.png
    函数导数为:

  • Hard tanh: 有些时候我们会选择这各激活函数,因为它计算代价比较小。函数公式和导数为
    image.png
    函数图像为
    image.png

  • Soft sign:
    函数公式和导数为:
    image.png
    其中,sgn是符号函数,返回值取决于z的符号是+1 还是-1

  • ReLU: rectified liniear unit,在深度网络经常使用,

    导数为:
    image.png
    函数图像为:
    image.png

  • Leaky ReLU
    函数和导数为:
    image.png
    函数图像为:
    image.png

Data Preprocessing

在进行机器学习任务时,为了使得模型能够获得一个较好的效果,我们通常会对数据采取一些预处理策略,这些处理主要包括以下几个方面。

  • 去均值
    通常我们希望数据的中心在零点,因此我们会把数据集减去一个均值,这个均值是利用训练集计算出来,但它会应用在validation、training、testing数据集上,以确保数据分布相同。

  • 归一化
    归一化是指将输入特征的维度都转换为相同的数值范围,便于处理,因为不同的特征获取的方式和来源都不同,因此需要进行归一化处理。将训练集中每部数据除以他们响应的标准差而进行归一化。

  • 白化
    白化(whitening)处理在图像处理领域中使用较多,它的目的是减少数据的冗余性、减少数据间的相关性、使所有特征具有相同的方差。为什么会有白化操作呢,拿图像来说,相邻像素之间具有很强的相关性,所以输入数据是冗余的,因此需要进行白化处理。具体的操作来说,首先对数据进行去均值,得到一个新的数据集$X^{\prime}$,然后使用SVD分解对$X^{\prime}$进行处理,得到矩阵$U,S,V$,然后将新数据集采用$UX^{\prime}$映射,最后将映射后的结果的每个维度除以S中对应的奇异值,如果奇异值为零用一个很小的数代替,从而完成白化处理。

以上这些预处理操作也需要结合具体的任务来操作,这里只是简单介绍几种方法。

Parameter Initialization

深度学习另一外个需要注意点是参数的初始化策略,经过实际的验证发现,对于网络中的权重初利用正太分布进行随机初始化为0附件的一个值网络会获得一个较好的效果,而在实际的工程中,我们会选择Xavier初始化策略,该策略表明对于sigmoid 和tanh 函数,权重矩阵采用如下的一个正态分布进行初始化,bias初始化为0,会获得很好的效果.
image.png

learning Strategies

对于学习策略,这里指的是学习率的设置问题,在进行网络训练的时候,我们遵循的一个原则是,刚开始训练的时候网络的loss比较大,梯度需要大幅度的进行减少,因此这个阶段需要有大的学习率,而在网络训练的后期,loss减少了很多,这个时候应该采用较小的幅度减少梯度,以避免梯度来回波动而无法达到最优值。在工程中会根据梯度的情况对梯度进行clip,对学习率进行衰减。

Adaptive Optimization Methods

优化策略是深度学习中另外一个比较重要的策略。这里主要介绍一下AdaGrad,它是SGD的一种优化之后的方法,学习率对每个参数而言都是不相同的,它取决于前一次的梯度变化,换句话说如果之前的梯度改变不大那它的学习率会变大,具体公式如下
image.png
下面有几种实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# A1 RMS
# Assume the gradient dx and parameter vector x
cache += dx**2
x += - learning_rate * dx / np.sqrt(cache + 1e-8)

# --------------------------------
# A2 RMSProp
# Update rule for RMS prop
cache = decay_rate * cache + (1 - decay_rate) * dx**2
x += - learning_rate * dx / (np.sqrt(cache) + eps)

#----------------------------------
# A3 Adam
# 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)

详细的优化策略后续会有文章单独介绍,敬请期待!

评论加载中