NMT Tutorial 3扩展c. 神经网络的初始化

深度学习中,在具体网络结构之上,有三种应用广泛而且比较微妙的技术,分别是

  • 初始化,即如何恰当地初始化网络参数。不恰当的初始化方法甚至会使网络无法被训练,而好的初始化方法可以缩短网络训练的时间
  • 优化,即如何让参数更新,最后达到最优解。这部分内容实际上并非深度学习所特有,各个优化器可以应用在其它基于梯度的机器学习模型上,例如线性回归、逻辑回归等等。因此这部分放在了深度学习部分之前介绍:优化方法
  • 泛化(generalization),或者说正则化(regularization),即如何防止模型过拟合。一些泛化方法也在其它机器学习模型上得到了应用,如L1正则化、L2正则化以及衍生出来的弹性网等。但是针对深度学习,有一些比较专门的泛化方法

本文将对初始化方法做一些介绍,下一篇文章介绍泛化(正则化)方法

基本初始化方法

比较常用和基本的初始化方法有两种,分别是均匀分布初始化和正态分布初始化法。核心思想就是根据给定的某个概率分布随机生成参数。例如,

  • tf.initializers.random_uniform(-0.1, 0.1)会在区间[-0.1, 0.1]内根据均匀分布产生一个随机数
  • tf.initializers.truncated_normal(0, 1)会根据均值为0,方差为1的正态分布产生一个随机数。如果生成的随机数超出了均值+/-2倍标准差的临界值,那么该值会被丢弃,重新产生一个随机数。TF官方文档推荐使用这个方法来初始化神经网络的权重,而不是普通的正态分布生成器tf.initializaers.random_normal

然而,普通的随机初始化方法有缺陷,不适合复杂网络。主要原因是对于非线性激活函数,其导数通常都有一大部分非常平坦的区域。如果初始化得到的权重落在了这个区域里,神经元会饱和,权重很难得到更新。例如,对于常见的激活函数\(\tanh\),如果输入\(x\)的绝对值大于2,就会落入到饱和区域。对于最简单的前馈神经网络,假设隐藏层每个节点都与输入的每个节点全连接,那么对某个节点,有 \[ h_j = x_1w_{1j} + x_2w_{2j} + x_3w_{3j} + \ldots \] 对求和项的每一项,其方差根据独立变量的乘积定理,有 \[ {\rm Var}(x_iw_{ij}) = [{\rm E}(x_i)]^2{\rm Var}(w_{ij}) + [{\rm E}(w_{ij})]^2{\rm Var}(x_i) + {\rm Var}(x_i){\rm Var}(w_{ij}) \] 假设输入的均值为0,方差为1,而且初始化权重时,也是从一个均值为0,方差为1的分布初始化,代入上式,有 \[ {\rm Var}(x_iw_{ij}) = 0 \times 1 + 0 \times 1 + 1 \times 1 = 1 \] 该节点的方差使用不相关独立变量加和定理,有 \[ {\rm Var}(h_j) = \sum_{i=0}^n {\rm Var}(x_iw_{ij}) = n \times 1 = n \] 其中\(n\)是输入节点的个数。假设输入节点数为784,那么方差就是784,标准差为\(\sqrt{ {\rm Var}(h_j)} = \sqrt{784} = 28\),因此大多数权重都会有\(|w| > 2\),进入饱和区域。因此需要其它初始化方法

LeCun初始化

Yann LeCun在1998年的一篇文章[LeCun1998]上率先提出了一种初始化方法。首先,要求节点的输出所属的分布必须标准差接近1,因此首先需要输出的方差为1,这可以通过一个归一化操作来解决。然后,假设某个神经元的输入\(y_i\)不相关且方差为1,那么该单元的所有权重之和的标准差为 \[ \sigma_{y_i} = \sqrt{\left(\sum_j w_{ij}^2\right)} \] 为了使该值接近1,权重必须来自于均值为0,标准差\(\sigma_w = m^{-1/2}\)的分布,其中\(m\)是该单元的输入数。文章没有点名必须用什么样的分布,只是说可以是均匀分布

在TensorFlow的实现里,有两种实现:

  • tf.initializers.lecun_uniform,权重来源的分布是\(\rm [-limit, limit]\)的均匀分布,其中\({\rm limit} = \sqrt{3/m}\)
  • tf.initializers.lecun_normal,权重来源的分布是均值为0,标准差为\(\sqrt{1/m}\)的正态分布

Xavier初始化(Glorot初始化)

对神经网络的每一层,记其输入是\({\boldsymbol{z}^i}\),输出(也就是下一层的输入)为\(\boldsymbol{z}^{i+1}\),有 \[ \begin{aligned} \boldsymbol{s}^i &= \boldsymbol{z}^i\boldsymbol{W}^i + \boldsymbol{b}^i \\ \boldsymbol{z}^{i+1} &= f(\boldsymbol{s}^i) \end{aligned} \] 其中\(f\)是非线性激活函数,且在0点处导数为1(\(f'(0) = 1\))。根据反向传播的定义,有 \[ \begin{aligned} \frac{\partial {\rm cost}}{\partial s_k^i} &= \frac{\partial z_k^{i+1}}{\partial s_k^i} \cdot \frac{\partial \boldsymbol{s}^{i+1}}{\partial z_k^{i+1}} \cdot \frac{\partial {\rm cost}}{\partial \boldsymbol{s}^{i+1}} \\ &= f'(s_k^i)\boldsymbol{W}_{k\cdot}^i\frac{\partial {\rm cost}}{\partial \boldsymbol{s}^{i+1}} \\ \frac{\partial {\rm cost}}{\partial W_{kl}^i} &= z_l^i\frac{\partial {\rm cost}}{\partial s_k^i} \end{aligned} \] 假设权重矩阵中的每一项都是独立初始化,而且输入的每一项方差都相同,记为\({\rm Var}[x]\),则对于网络的第\(i\)层,假设它有\(n_i\)个节点,\(x\)是网络的输入,有 \[ \begin{aligned} f'(s_k^i) &\approx 1 \\ {\rm Var}[z^i] &= {\rm Var}[x]\prod_{i'=0}^{i-1}n_{i'}{\rm Var}[W^{i'}] \end{aligned} \] (这里似乎隐含了两个假设。第一点,激活前的隐藏单元值在0点附近。这个假设我觉得是合理的,因为如果隐藏单元值不在0点附近,使用S型激活函数会导致饱和;第二点,各层输入的均值都是0)

记第\(i'\)层的所有权重方差都为\({\rm Var}[W^{i'}]\),那么对于有\(d\)层的网络,有 \[ \begin{aligned} {\rm Var}\left[\frac{\partial {\rm Cost}}{\partial s^i}\right] &= {\rm Var}\left[\frac{\partial {\rm Cost}}{\partial s^d}\right]\prod_{i'=i}^d n_{i'+1}{\rm Var}[W^{i'}] \\ {\rm Var}\left[\frac{\partial {\rm Cost}}{\partial w^i}\right] &= \prod_{i'=0}^{i-1} n_{i'}{\rm Var}[W^{i'}]\prod_{i'=i}^{d-1}n_{i'+1}{\rm Var}[W^{i'}]\times {\rm Var}[x]{\rm Var}\left[\frac{\partial {\rm Cost}}{\partial s^d}\right] \end{aligned} \] 从前向传播的角度,我们希望 \[ \forall(i, i'), {\rm Var}[z^i] = {\rm Var}[z^{i'}] \] 从反向传播的角度,我们希望 \[ \forall (i, i'), {\rm Var}\left[\frac{\partial {\rm Cost}}{\partial s^i}\right] = {\rm Var}\left[\frac{\partial {\rm Cost}}{\partial s^{i'}}\right] \] 综合上述条件,希望有 \[ \forall i,\ \ \ n_i{\rm Var}[W^i] = 1,\ n_{i+1}{\rm Var}[W^i] = 1 \]\[ \forall i,\ \ \ {\rm Var}[W^i] = \frac{2}{n_i + n_{i+1}} \] 假设对所有的权重都是用同样的初始化方法,则有 \[ \begin{aligned} \forall i,\ \ {\rm Var}\left[\frac{\partial {\rm Cost}}{\partial s^i}\right] &= {\Big[}n{\rm Var}[W]{\Big]}^{d-i}{\rm Var}[x] \\ \forall i,\ \ {\rm Var}\left[\frac{\partial {\rm Cost}}{\partial w^i}\right] &= {\Big[}n{\rm Var}[W]{\Big]}^{d}{\rm Var}[x]{\rm Var}\left[\frac{\partial {\rm Cost}}{\partial s^d}\right] \end{aligned} \] 即每层权重的梯度都是一样的

假设使用如下分布初始化 \[ W_{ij} \sim U\left[-\frac{1}{\sqrt{n}}, \frac{1}{\sqrt{n}}\right] \] 其中\(U\)是均匀分布,\(n\)是前一层节点的数量(每层的输入数量),那么有\(n{\rm Var}[W] = \frac{1}{3}\)。综合上面的推导,更合适的初始化是 \[ W \sim U\left[-\frac{\sqrt{6}}{\sqrt{n_j + n_{j+1}}}, \frac{\sqrt{6}}{\sqrt{n_j + n_{j+1}}}\right] \] 其中\(n_j\)又称“扇入数”(fan_in),\(n_{j+1}\)又称“扇出数”(fan_out)

这种初始化方法称为Xavier初始化法,又称为Glorot初始化法,最初见于文献[Glorot2010]。TensorFlow的标准实现是tf.initializers.glorot_uniform。此外,TensorFlow还提供了tf.initializers.glorot_normal,用于从均值为0,标准差为\(\sqrt{2}/\sqrt{n_j + n_{j+1}}\)的正态分布中采样(如果采样结果的绝对值超出了两个标准差,则重新采样)。Xavier初始化法适用于激活函数为sigmoid或tanh的情况

何恺明初始化(He初始化)

前面提到的Xavier初始化方法在神经网络使用S型函数做激活函数的情况下比较有效,但是近几年,随着整流线性单元函数(ReLU)的兴起,人们发现这种激活函数在卷积神经网络(CNN)中效果不群,同时传统的正态分布初始化和Xavier初始化都有一些缺陷。何恺明等人在[He2015]中针对使用ReLU的神经网络,尤其是CNN提出了一种新的初始化方法

(关于卷积神经网络的内容可以先参看CS20SI的笔记Hinton的笔记,不过本系列笔记后面应该还会再回顾)

这种方法也可以分为两个视角,分别是前向视角和反向视角

前向视角

对于CNN的一个卷积层,有 \[ \boldsymbol{y}_l = \boldsymbol{W}_l\boldsymbol{x}_l + \boldsymbol{b}_l \] 这里\(\boldsymbol{x}\)是一个\(k^2c \times 1\)的向量,表示\(c\)个输入信道共存的\(k\times k\)个像素,其中\(k\)是空间滤波器的大小。\(n = k^2c\)是连接的数量。\(\boldsymbol{W}\)\(d\times n\)的矩阵,每一行是一个滤波器的权重,\(d\)是滤波器的数量。\(\boldsymbol{b}\)是偏置向量,\(\boldsymbol{y}\)是输出的一个“像素点”。\(l\)是网络每一层的索引,\(\boldsymbol{x}_l = f(\boldsymbol{y}_{l-1})\)其中\(f\)是激活函数。\(c_l = d_{l-1}\)

假设初始化时\(\boldsymbol{W}_l\)的每一项都是独立的,且来自于同样的分布;\(\boldsymbol{x}_l\)的每一项也都如此,且与\(\boldsymbol{W}_l\)的每一项互相独立,则 \[ {\rm Var[y}_l] = n_l{\rm Var[w}_l{\rm x}_l] \] 其中\({\rm y}_l\)\({\rm w}_l\)\({\rm x}_l\)是分别来自于\(\boldsymbol{y}_l\)\(\boldsymbol{W}_l\)\(\boldsymbol{x}_l\)的随机变量。令\({\rm w}_l\)均值为0,则根据前面的定理以及方差的计算公式,有 \[ \begin{align} {\rm Var}[{\rm w}_l{\rm x}_l] &= [{\rm E}[{\rm x}_l]]^2{\rm Var}[{\rm w}_l] + [{\rm E}[{\rm w}_l]]^2{\rm Var}[{\rm x}_l] + {\rm Var}[{\rm w}_l]{\rm Var}[{\rm x}_l] \\ &= [{\rm E}[{\rm x}_l]]^2{\rm Var}[{\rm w}_l] + {\rm Var}[{\rm w}_l]{\rm Var}[{\rm x}_l] \\ &= {\rm Var}[{\rm w}_l]\Big([{\rm E}[{\rm x}_l]]^2 + {\rm Var}[{\rm x}_l]\Big) \\ &= {\rm Var}[{\rm w}_l]{\rm E[{\rm x}}_l^2] \end{align} \] 所以 \[ {\rm Var}[{\rm y}_l] = n_l{\rm var}[{\rm w}_l]{\rm E[{\rm x}}_l^2]\tag{1} \] 注意除非\({\rm x}_l\)均值为0,否则\({\rm E}[{\rm x}_l^2] \not= {\rm var}[{\rm x}_l]\)。而对ReLU来说,有\({\rm x}_l = \max(0, {\rm y}_{l-1})\),因此一定不会均值为0。由于激活函数性质发生了变化,前面适用于Xavier初始化的假设已经不再可用

假设\({\rm w}_{l-1}\)是围绕零点对称分布,\({\rm b}_{l-1} = 0\),那么\({\rm y}_{l-1}\)也围绕零点对称分布且均值为0。因此 \[ {\rm Var}[{\rm y}_{l-1}] = {\rm E}[{\rm y}_{l-1}^2] - [{\rm E}[{\rm y}_{l-1}]]^2 = {\rm E}[{\rm y}_{l-1}^2] \]\(f\)为ReLU时有

\[ \begin{aligned} {\rm E}[{\rm x}_l^2] &= {\rm E}[\max(0, {\rm y}_{l-1}^2)] \\ &= {\rm E}[0] + {\rm E}[{\rm y}_{l-1}^2]\Big|_{ {\rm y}_{l-1} > 0}\\ &= \frac{1}{2}{\rm E}[{\rm y}_{l-1}^2] \\ &= \frac{1}{2}{\rm var}[{\rm y}_{l-1}] \end{aligned} \] 代回到(1)式有 \[ {\rm Var}[{\rm y}_l] = \frac{1}{2}n_l{\rm var}[{\rm w}_l]{\rm var}[{\rm y}_{l-1}] \] 因此\(L\)层连乘起来有 \[ {\rm Var}[{\rm y}_L] = {\rm Var}[{\rm y}_1]\left(\prod_{l=2}^L\frac{1}{2}n_l{\rm Var}[{\rm w}_l]\right) \] 好的初始化方法应该避免将输入信号成指数级别地增大或缩小,因此希望连乘的每一项都近似为1。因此需要\({\rm w}_l\)满足来自于均值为0,标准差为\(\sqrt{2/n_l}\)的正态分布才能使得 \[ \forall l,\ \ \frac{1}{2}n_l{\rm Var}[{\rm w}_l] = 1\tag{2} \] 此外,还应该有\(\boldsymbol{b} = {\bf 0}\)

反向视角

在反向阶段,卷积层的梯度计算方法为 \[ \Delta \boldsymbol{x}_l = \hat{\boldsymbol{W}}_l\Delta \boldsymbol{y}_l\tag{3} \] 这里\(\Delta \boldsymbol{x}\)\(\Delta \boldsymbol{y}\)代表梯度 \[ \Delta \boldsymbol{x} = \frac{\partial \mathcal{E}}{\partial \boldsymbol{x}},\ \ \Delta \boldsymbol{y} = \frac{\partial \mathcal{E}}{\partial \boldsymbol{y}} \] 这里\(\Delta \boldsymbol{y}\)\(d\)个信道\(k\times k\)个像素点,被重新组合成一个\(k^2d\times 1\)的向量。记\(\hat{n} = k^2d\)。注意\(\hat{n} \not= n = k^2c\)\(\hat{\boldsymbol{W}}\)是一个\(c \times \hat{n}\)的矩阵,滤波器被按照反向传播的方法重新调整(\(\boldsymbol{W}\)\(\hat{\boldsymbol{W}}\)可以互相转换)。\(\Delta \boldsymbol{x}\)\(c\times 1\)的向量,代表带层某个像素点的梯度。假设\({\rm w}_l\)\(\Delta {\rm y}_l\)是相互独立的,且\({\rm w}_l\)是用在0点对称的分布做初始化,那么对所有\(l\)\(\Delta {\rm x}_l\)的均值为0

(注意这里的\(\boldsymbol{x}\)和前向视角的\(\boldsymbol{x}\)不是一个概念,\(\boldsymbol{y}\)也如此。在前向视角里,\(\boldsymbol{x}\)是输入图像的一片区域,被卷积核覆盖,而\(\boldsymbol{y}\)是根据这片区域做卷积操作以后输出的一个像素点。后向视角里,\(\boldsymbol{x}\)是输入图像的一个像素点,\(\boldsymbol{y}\)是被这个\(\boldsymbol{x}\)影响到的所有区域)

在反向传播中,还有\(\Delta {\rm y}_l = f'({\rm y}_l) \Delta {\rm x}_{l+1}\)。如果激活函数\(f\)是ReLU,那么\(f'({\rm y}_l)\)为0或1,概率相等。假设\(f'({\rm y}_l)\)\(\Delta {\rm x}_{l+1}\)相互独立,那么\({\rm E}[\Delta {\rm y}_l] = \frac{1}{2}{\rm E}[\Delta {\rm x}_{l+1}] = 0\)。且\({\rm E}[(\Delta {\rm y}_l)^2] = {\rm Var}[\Delta {\rm y}_l] = \frac{1}{2}{\rm Var}[\Delta {\rm x}_{l+1}]\) 。代入(3)式有 \[ \begin{aligned} {\rm Var}[\Delta {\rm x}_l] &= \hat{n}_l {\rm Var}[{\rm w}_l]{\rm Var}[\Delta {\rm y}_l] \\ &= \frac{1}{2}\hat{n}_l{\rm Var}[{\rm w}_l]{\rm Var}[\Delta {\rm x}_{l+1}] \end{aligned} \] 与前面推导类似地,这需要 \[ {\rm Var}[\Delta{\rm x}_2] = {\rm Var}[\Delta{\rm x}_{L+1}]\left(\prod_{l=2}^L\frac{1}{2}\hat{n}_l{\rm Var}[{\rm w}_l]\right) \] 因此需要 \[ \forall l,\ \frac{1}{2}\hat{n}_l{\rm Var}[{\rm w}_l] = 1\tag{4} \] 即需要使用一个均值为0,标准差为\(\sqrt{2/\hat{n}_l}\)的正态分布

注意单独使用(2)式或者(4)式都可以。如果单独使用(4)式,则\(\prod_{l=2}^L \frac{1}{2}\hat{n}_l{\rm Var}[{\rm w}_l] = 1\),因此\(\prod_{l=2}^L\frac{1}{2}n_l{\rm Var}[{\rm w}_l] = \prod_{l=2}^L n_l/\hat{n}_l = c_2/d_L\),一般都不会是一个小于1的数。也就是说,如果初始化是适当的,可以放大反向传播的信号,那么也可以放大前向传播的信号。实验也表明两种形式都能收敛

实验表明,在较深(例如30层)的卷积神经网络上,使用传统的初始化和Xavier初始化都会出现梯度消失的情况,而He初始化不会

TensorFlow里对he初始化的标准实现是tf.initializers.he_normal,这里使用了前向视角的计算方法,即会使用均值为0,标准差为\(\sqrt{2/{\rm fan\_in}}\)的正态分布采样(如果采样结果的绝对值超出两个标准差则重新采样)。此外,对应于Xavier初始化,TensorFlow也提供了he初始化的一种均匀分布实现tf.initializers.he_uniform。再次重申,he初始化适用于激活函数为ReLU的情况

不要使用常数初始化

前面所列举的初始化方法虽然都不能适用于所有情况,但是至少有各自适用的场合,或者不会出乱子。但是如果要是把所有参数都初始成一个值,就会有灭顶之灾。为了简明起见,想象输入\(\boldsymbol{x}\)有三个维度,将输入送进一个只有一个隐藏层的神经网络,隐藏层只有两个节点,输出为标量\(y\)。输入层到隐层的权重为\(\boldsymbol{W}\),隐层到输出的权重为\(\boldsymbol{U}\),没有偏置项。非线性转化使用tanh函数(记为\(f\))。那么可以直接把前向计算过程展开列出来 \[ \begin{aligned} s_1 &= W_{11}x_1 + W_{21}x_2 + W_{31}x_3 \\ s_2 &= W_{12}x_1 + W_{22}x_2 + W_{32}x_3 \\ h_1 &= f(s_1) \\ h_2 &= f(s_2) \\ y &= U_{11}h_1 + U_{21}h_2 \end{aligned} \] 如果所有参数初始化都使用常数,则所有\(W_{ij}\)都相等,记为\(w\),那么显然\(s_1 = s_2 = s = w(x_1 + x_2 + x_3)\)\(h_1 = h_2 = f(s) = h\)。所有\(U_{ij}\)都相等,记为\(u\),则\(y = 2uh\)

接下来来到反向传播的情况,由于 \[ \frac{\partial y}{\partial U_{11}} = h_1,\ \frac{\partial y}{\partial U_{21}} = h_2 \] 而根据前面的推导,\(h_1 = h_2\),因此隐层每个节点前向传播得到的值相等,反向传播获得的更新量也相等。同样的道理,也可以推出对\(j = 1, 2\),有 \[ \frac{\partial y}{\partial W_{ij}} = x_i\cdot f'(s) \cdot u,\ \ \forall i = 1, 2, 3 \] 这意味着,对于隐藏层的每个节点,它与其它节点有同样的输入梯度,也有同样的输出梯度。此时神经网络的隐藏层相当于只有一个节点在工作!

当然,对于给定的这个例子,更糟的情况下是将所有权重都初始化为0。此时\(s_1, s_2\)都会为0,因此后面的变量\(h_1, h_2\)\(y\)也都会为0,反向传播的每个梯度也都是0,网络更是什么都没学到了。此外,上述例子可以很容易地推广到多个隐藏层,带有偏置的前馈神经网络

所以,为了使神经网络能够得到训练,一定不要在初始化参数的时候全都使用常数。按照花书的说法

初始参数需要在不同单元间“破坏对称性”。如果具有相同激活函数的两个隐藏单元连接到相同的输入,那么这些单元必须具有不同的初始参数。如果它们具有相同的初始参数,应用到确定性损失和模型的确定性学习算法将一直以相同的方式更新这两个单元

——花书184页

小结

通过前面的分析,可以看出使用正确的初始化方法,能够让神经网络训练更稳定。不同的初始化方法的共同目的都是在于让各层各神经元的方差控制在一个可控范围内,一定程度上可以起到避免梯度消失或梯度爆炸的效果(关于梯度消失和梯度爆炸,将在后面的文章中再深入探讨)。下图(来自于博客Understanding Neural Network Weight Initialization)给出了一个例子,将使用不同分布来初始化参数对神经元造成的影响做了可视化

使用不同分布初始化参数对使用ReLU的神经网络的影响。中间的初始化方法类似于使用He初始化
使用不同分布初始化参数对使用ReLU的神经网络的影响。中间的初始化方法类似于使用He初始化

总而言之,神经网络的初始化方法可以总结成如下几条:

  • 不要用常数初始化,更不要用全0初始化(不过可以把偏置初始化成0)
  • 如果使用tanh或sigmoid做激活函数,用Xavier初始化
  • 如果使用ReLU做激活函数(尤其是如果网络还很深),用He初始化

参考文献

TensorFlow的权重初始化教程

[LeCun1998] LeCun, Y., Bottou, L., Orr, G. B., & Müller, K. R. (1998). Efficient BackProp. In Neural Networks: Tricks of the Trade(pp. 9-50). Springer, Berlin, Heidelberg.

[Glorot2010] Glorot, X., & Bengio, Y. (2010, March). Understanding the difficulty of training deep feedforward neural networks. In Proceedings of the thirteenth international conference on artificial intelligence and statistics (pp. 249-256).

[He2015] He, K., Zhang, X., Ren, S., & Sun, J. (2015). Delving deep into rectifiers: Surpassing human-level performance on imagenet classification. In Proceedings of the IEEE international conference on computer vision (ICCV) (pp. 1026-1034).

坚持原创技术分享,您的支持将鼓励我继续创作!