本系列笔记前文介绍了若干神经网络常用的泛化方法,本文将延续这一话题,介绍若干适用于RNN的泛化/正则化方法
[Ba2016]认为批归一化(BN)虽然原理简洁能有效提升收敛速度,但是很难适用于RNN上。因为RNN的输入是变长的,因此需要对不同的时间步保存不同的统计量。但是对序列到序列任务,很难保证测试时句子会有多长,因此分时间步保存统计量不是一个好的选择。此外,实验证明当每个小批量样本的数据量太小时,BN的效果不好,而训练RNN时基本都是使用小批量样本(这段存疑)。基于以上考量,该文章提出了层归一化的方法,核心思想是在统计量里不使用跟每批样本个数相关的信息,只考虑隐藏单元的个数。具体说,对神经网络的第 l l l层,假设该层共有 H H H个隐藏节点,输入是 h l \boldsymbol{h}^l hl,激活前经线性变换 W l \boldsymbol{W}^l Wl得到的向量是 a l \boldsymbol{a}^l al,该层第 i i i个隐藏节点的的输入权重是 w i l \boldsymbol{w}_i^l wil(因此 a i l = w i l T h l a_i^l = {\boldsymbol{w}_i^l}^\mathsf{T}\boldsymbol{h}^l ail=wilThl),则层归一化使用的统计量为
μ l = 1 H ∑ i = 1 H a i l σ l = 1 H ∑ i = 1 H ( a i l − μ l ) 2 \begin{aligned} \mu^l &= \frac{1}{H}\sum_{i=1}^H a_i^l \\ \sigma^l &= \sqrt{\frac{1}{H}\sum_{i=1}^H\left(a_i^l - \mu^l\right)^2} \end{aligned} μlσl=H1i=1∑Hail=H1i=1∑H(ail−μl)2
可见各统计量与样本个数完全无关,因此对每次只处理一条样本的情况(例如在线学习)也适用。使用层归一化后RNN隐藏单元的计算如下所示
a ( t ) = U x ( t ) + W h ( t − 1 ) μ ( t ) = 1 H ∑ i = 1 H a i ( t ) σ ( t ) = 1 H ∑ i = 1 H ( a i ( t ) − μ ( t ) ) 2 h ( t ) = tanh [ γ σ t ⊙ ( a ( t ) − μ ( t ) ) + β ] \begin{aligned} \boldsymbol{a}^{(t)} &= \boldsymbol{U}\boldsymbol{x}^{(t)} + \boldsymbol{W}\boldsymbol{h}^{(t-1)} \\ \mu^{(t)} &= \frac{1}{H}\sum_{i=1}^H a_i^{(t)} \\ \sigma^{(t)} &= \sqrt{\frac{1}{H}\sum_{i=1}^H\left(a_i^{(t)} - \mu^{(t)}\right)^2} \\ \boldsymbol{h}^{(t)} &= \tanh\left[\frac{\boldsymbol{\gamma}}{\sigma^t}\odot\left(\boldsymbol{a}^{(t)}-\mu^{(t)}\right)+\boldsymbol{\beta}\right] \\ \end{aligned} a(t)μ(t)σ(t)h(t)=Ux(t)+Wh(t−1)=H1i=1∑Hai(t)=H1i=1∑H(ai(t)−μ(t))2=tanh[σtγ⊙(a(t)−μ(t))+β]
下图比较直观地解释了批归一化与层归一化的区别。图自(Weight Normalization and Layer Normalization Explained (Normalization in Deep Learning Part 2))
层归一化被提出背后的直觉是,由于RNN通常使用ReLU做激活函数,而ReLU的取值范围为 [ 0 , + ∞ ) [0, +\infty) [0,+∞),因此前一层的某个神经元可能产生特别大的值。为了避免这种情况产生的共变量偏移(covariance shift,批归一化首先提出来的概念),可以对神经元的结果做归一化,避免很大值的出现,进而稳定训练过程。原文还说明了层归一化同时具有权重不变性(整个权重矩阵乘以某个系数再偏移以后,对结果没有影响——这个证明过程我没太看懂),以及数据不变性(输入乘以某个系数再偏移,对结果没有影响)。根据stats stackexchange的回答,这使得网络可以1. 对权重的初始化不敏感,2. 对异常的数据不敏感
在批归一化被NeurIPS2018的两篇文章重新分析以后,时隔一年,层归一化也被[XuJingjing2019]做了进一步讨论。文章通过实验提出了如下观点
在RNN出现的早期,人们使用的结构通常都比较小,因为实践中发现大的RNN比较容易过拟合。Dropout问世以后不久,[Zaremba2014]对其进行了修改并加在了RNN上,取得了不错的效果。该工作认为,如果将dropout加在RNN的状态传递(从上一个时间步传到下一个时间步的连接),会影响网络的记忆力,因此只将dropout加在了RNN各层的输入-输出上
之后,[Gal2015]指出[Zaremba2014]的做法并不能从根本上解决过拟合问题,并使用变分推断提出了一种新的dropout方法——变分dropout(variational dropout)。该方法的核心思路包括如下两点
更具体地,以LSTM为例,使用之前神经翻译笔记4扩展a第一部分. RNN在TF1.x中的实现方法略览中各个门计算方式紧凑形式的记法,并略去偏置项和激活函数,原始计算方式为
[ i ( t ) c ~ ( t ) f ( t ) o ( t ) ] = σ ( [ x ( t ) h ( t − 1 ) ] ⋅ [ U i U c U f U o W i W c W f W o ] ) \left[\begin{matrix}\boldsymbol{i}^{(t)} & \tilde{\boldsymbol{c}}^{(t)} & \boldsymbol{f}^{(t)} & \boldsymbol{o}^{(t)}\end{matrix}\right] = \sigma\left(\left[\begin{matrix}\boldsymbol{x}^{(t)} & \boldsymbol{h}^{(t-1)}\end{matrix}\right] \cdot \left[\begin{matrix}\boldsymbol{U}_i & \boldsymbol{U}_c & \boldsymbol{U}_f & \boldsymbol{U}_o \\ \boldsymbol{W}_i & \boldsymbol{W}_c & \boldsymbol{W}_f & \boldsymbol{W}_o \end{matrix}\right] \right) [i(t)c~(t)f(t)o(t)]=σ([x(t)h(t−1)]⋅[UiWiUcWcUfWfUoWo])
引入变分dropout则变为
[ i ( t ) c ~ ( t ) f ( t ) o ( t ) ] = σ ( [ x ( t ) ∘ z x h ( t − 1 ) ∘ z h ] ⋅ [ U i U c U f U o W i W c W f W o ] ) \left[\begin{matrix}\boldsymbol{i}^{(t)} & \tilde{\boldsymbol{c}}^{(t)} & \boldsymbol{f}^{(t)} & \boldsymbol{o}^{(t)}\end{matrix}\right] = \sigma\left(\left[\begin{matrix}\boldsymbol{x}^{(t)} \circ \boldsymbol{z}_x & \boldsymbol{h}^{(t-1)} \circ \boldsymbol{z}_h \end{matrix}\right] \cdot \left[\begin{matrix}\boldsymbol{U}_i & \boldsymbol{U}_c & \boldsymbol{U}_f & \boldsymbol{U}_o \\ \boldsymbol{W}_i & \boldsymbol{W}_c & \boldsymbol{W}_f & \boldsymbol{W}_o \end{matrix}\right] \right) [i(t)c~(t)f(t)o(t)]=σ([x(t)∘zxh(t−1)∘zh]⋅[UiWiUcWcUfWfUoWo])
其中 z x \boldsymbol{z}_x zx和 z h \boldsymbol{z}_h zh是两个dropout mask矩阵,不随时间步的变化而变化
目前,大部分框架都使用了变分dropout来作为RNN dropout的实现
(变分dropout的理论推导比较复杂,这里就不记录了)
[Krueger2016]提出了另一种dropout的变种zoneout。与dropout随机丢弃神经元不同,zoneout是随机将某个神经元的激活值替换为其前一个时间步神经元的激活值( h t = h t − 1 h_t = h_{t-1} ht=ht−1)。这种方案可以保留前面时间步的状态,因此更适合于RNN。对于LSTM,注意其向下一个时间步传递的是两个值 c t c_t ct和 h t h_t ht,对应地,zoneout通常对两者分别使用不同的mask
正则WD-LSTM[Merity2017]自提出以后在Penn Treebank和WikiText-2这两个数据集上长期处于"霸榜"的状态(直到GPT-2出现之前)。其主要贡献是为基于LSTM的RNN提供了一套组合的z化方法,以及一种新的优化方法
对RNN做正则化的一个常见方向是在其循环连接上做文章。前人的工作通常是针对传递进来的隐藏状态 h t − 1 \boldsymbol{h}_{t-1} ht−1,例如在时间步之间加入dropout,或者对更新 c t \boldsymbol{c}_t ct的操作做dropout。这种做法破坏了RNN的黑盒性,可能导致底层做的一些针对硬件的优化无效。文章采取了一种DropConnect方法,在隐层和隐层之间传递的权重矩阵 [ W c , W i , W f , W o ] [\boldsymbol{W}_c, \boldsymbol{W}_i, \boldsymbol{W}_f, \boldsymbol{W}_o] [Wc,Wi,Wf,Wo]上加dropout。由于多个时间步共享这四个权重,因此在整个正向和反向传播过程中被丢弃掉的权重都相同,结果就有点像变分dropout了。当然DropConnect也可以用在 [ U i , U f , U o ] [\boldsymbol{U}_i, \boldsymbol{U}_f, \boldsymbol{U}_o] [Ui,Uf,Uo]上,但是本文的目的还是防止循环连接用的参数过拟合
对其它权重矩阵,文章使用了变分dropout来做正则化,以保证每个矩阵在不同时间步被掩盖掉的部分都相同。不过这里没有把一个dropout掩码矩阵从头用到尾,而是每一小批数据使用相同的掩码。此外,对嵌入矩阵,文章也加入了dropout,丢弃概率为 p e p_e pe,因此剩下的词向量值要乘 1 1 − p e \frac{1}{1-p_e} 1−pe1倍。词嵌入端加入dropout,如前所述,相当于在这一次正向和反向传播中这个词所有本该出现的地方都被抹去了,也就等价于在独热嵌入和embedding lookup之间的连接加变分dropout
当RNN的时间步比较多时,BPTT需要很大的计算量。因此对于比较长的文本序列,通常方法是将其截断成若干节,把每一节看作是单独的一批数据。正向传播时,每节最后一个数据产生的隐藏状态会传给下一节数据,作为下一节数据的初始状态;但是反向传播时,每一节最后一个时间步的节点不会收到后面数据传来的梯度更新。这种做法称作"被截断的反向传播" (Truncated BPTT),是训练语言模型常用的手段之一
这种做法存在的最大问题是总有一部分元素不会收到隐藏层后续节点传进来的梯度更新。假设BPTT的窗口长度为 n n n,那么有 1 n \frac{1}{n} n1的元素不会被后续节点更新,对于语言模型问题,其只能收到输出层传回的梯度。另外 n − 2 n \frac{n-2}{n} nn−2的元素只能收到 1 , ⋯ , n − 2 1, \cdots, n-2 1,⋯,n−2个元素的梯度,效率比较低
文章的对策是随机选取BPTT的序列长度,采用如下策略:首先设计一个"基序列长度",记为 b p t t \rm bptt bptt,以概率 p p p将其设计为 s e q \rm seq seq,以概率 1 − p 1-p 1−p设计为 s e q 2 \frac{\rm seq}{2} 2seq,其中 p p p是一个接近1的值。然后,每个batch都根据正态分布 N ( b p t t , s ) \mathcal{N}({\rm bptt}, s) N(bptt,s)采样一个实际使用的BPTT窗口长度 l e n \rm len len (这里 s s s是一个超参数,默认为5)。对应地,每个batch也会根据 l e n \rm len len的值动态调整学习率
γ ′ = γ ⋅ l e n s e q \gamma' = \gamma \cdot \frac{\rm len}{\rm seq} γ′=γ⋅seqlen
这是因为对于短序列来说,损失值在每个时间步上分摊的值更大。如果将每个时间步对应的标记符看做是一个样本(当然这样可能不是很科学),那么根据[Goyal2017],对大批量的数据,训练时需要增大学习率。也就是对长序列学习率应该更大。(对此的一个解释可参考如何评价Facebook Training ImageNet in 1 Hour这篇论文? - 廉相如的回答 - 知乎)
嵌入共享 (原文weight typing) 是将输入词嵌入矩阵和softmax层矩阵共享的技术。这种方案可以降低模型参数数量,而且[Inan2016]证明这种方法可以提高模型效果
本文使用的另一个方案是减小词向量维度,同时不再将隐藏层维度与词向量维度绑定,而是单独设置
L2正则化除了可以用来约束权重,也可以用在每个独立的激活单元上,或者用在RNN不同时间步的输出之间的差值上。这两种策略分别称为"激活单元的正则化" (activation regularization, AR)和"时序激活单元的正则化" (temporal activation regularization, TAR)
AR对那些显著大于0的激活值施加惩罚,以此达到正则化网络的目的。具体定义为
α ℓ 2 ( m ⊙ h t ) \alpha \ell_2(m \odot \boldsymbol{h}_t) αℓ2(m⊙ht)
其中 m m m是dropout掩码, ℓ 2 ( ⋅ ) = ∥ ⋅ ∥ 2 \ell_2(\cdot) = \|\cdot\|_2 ℓ2(⋅)=∥⋅∥2, h t \boldsymbol{h}_t ht是RNN在时刻 t t t的输出, α \alpha α是缩放因子
TAR则是惩罚模型让其不要在隐藏状态发生突变。使用上面相似的记号,TAR定义为
β ℓ 2 ( h t − h t + 1 ) \beta \ell_2(\boldsymbol{h}_t - \boldsymbol{h}_{t+1}) βℓ2(ht−ht+1)
AR和TAR都只对RNN最后一层的输出使用
深度网络的优化问题可以抽象为
min W 1 N ∑ i = 1 N f i ( W ) \min_{\boldsymbol{W}}\frac{1}{N}\sum_{i=1}^Nf_i(\boldsymbol{W}) WminN1i=1∑Nfi(W)
其中 f i f_i fi是第 i i i个数据点的损失函数, W \boldsymbol{W} W是网络权重,最小化的目标函数实际上就是损失值在整个数据集上的期望。常见的优化方法是SGD,形式为
W k + 1 = W k − γ k ∇ f ( W k ) \boldsymbol{W}_{k+1} = \boldsymbol{W}_k - \gamma_k \nabla f(\boldsymbol{W}_k) Wk+1=Wk−γk∇f(Wk)
理论证明其可以有线性收敛性,可避开鞍点,而且有更好的泛化性能。对神经语言模型来说,无动量的SGD比其它优化方法效果都要好。对SGD的一种改进策略是使用平均SGD (Averaged SGD, ASGD) 的方法,即对最后 K − T + 1 K-T+1 K−T+1个迭代得到的参数求平均,返回 1 K − T + 1 ∑ i = T K W i \frac{1}{K-T+1}\sum_{i=T}^K \boldsymbol{W}_i K−T+11∑i=TKWi。这种方法尽管有一些很好的理论性质 (例如收敛过程近似于使用二阶导数的收敛过程),但是在实际应用中却用得比较少,究其原因是人们还不太清楚该如何调优 γ k \gamma_k γk和触发计算平均值的时刻 T T T:太早求均值会影响算法效果,太晚的话又需要很多步额外的迭代来收敛
本文的策略是使用了一种ASGD的变体,称为"非单调触发的ASGD" (Non-monotonically Triggered variant of ASGD, NT-ASGD),免去了调优 T T T的过程,而且使用的是常量学习率,也不涉及学习率的动态调整
上图给出了NT-ASGD的实现思路。论文采用的策略是将 L L L设为每个epoch迭代的次数, n = 5 n = 5 n=5。因此在这样的参数设置下,NT-ASGD的思想为:每个epoch结束以后计算一次验证集上的困惑度ppl,记为 v v v。如果已经训练了超过5个epoch,且此时 v v v不是最好的验证集ppl,那么就从这一时刻开始对之后迭代得到的所有参数求平均
从经验上看,NT-ASGD需要比较大的batch size
NT-ASGD还尝试了使用神经缓存模型来改善语言模型的预测效果。实验表明使用连续缓存指针后模型对罕见词的预测效果有明显提升,但是对常见词的预测效果降低很多
文章还通过对比实验的方法试图找出引用进来的所有技术哪一种起的作用比较关键。实验表明移除隐藏层之间传递的权重矩阵上DropConnect对模型效果影响最大。将嵌入矩阵的维度与隐藏层维度对齐不仅增大了参数数量,同时也降低了模型的效果 (增大约8个ppl点)。去掉嵌入层dropout、AR/TAR和权重递减会增大约2-6个ppl点,如果使用定长的反向传播也会增大约1个ppl点
[Ba2016] Lei Ba, J., Kiros, J. R., & Hinton, G. E. (2016). Layer normalization. arXiv preprint arXiv:1607.06450.
[XuJingjing2019] Xu, J., Sun, X., Zhang, Z., Zhao, G., & Lin, J. (2019). Understanding and Improving Layer Normalization. In Advances in Neural Information Processing Systems, (NeurIPS 2019) (pp. 4383-4393).
[Zaremba2014] Zaremba, W., Sutskever, I., & Vinyals, O. (2014). Recurrent neural network regularization. arXiv preprint arXiv:1409.2329.
[Gal2015] Gal, Y., & Ghahramani, Z. (2016). A theoretically grounded application of dropout in recurrent neural networks. In Advances in neural information processing systems (NeurIPS 2016) (pp. 1019-1027).
[Krueger2016] Krueger, D., Maharaj, T., Kramár, J., Pezeshki, M., Ballas, N., Ke, N. R., Goyal, A., Bengio, Y., Courville, A. & Pal, C. (2016). Zoneout: Regularizing rnns by randomly preserving hidden activations. arXiv preprint arXiv:1606.01305 (Accepted by ICLR 2017).
[Merity2017] Merity, S., Keskar, N. S., & Socher, R. (2017). Regularizing and optimizing LSTM language models. In Proceedings of the Sixth International Conference on Learning Representations, ICLR 2018.
[Wan2013] Wan, L., Zeiler, M., Zhang, S., Le Cun, Y., & Fergus, R. (2013, February). Regularization of neural networks using dropconnect. In International conference on machine learning, ICML 2013 (pp. 1058-1066).
[Goyal2017] Goyal, P., Dollár, P., Girshick, R., Noordhuis, P., Wesolowski, L., Kyrola, A., … & He, K. (2017). Accurate, large minibatch sgd: Training imagenet in 1 hour. arXiv preprint arXiv:1706.02677.
[Inan2016] Inan, H., Khosravi, K., & Socher, R. (2016). Tying word vectors and word classifiers: A loss framework for language modeling. In Proceedings of the Fifth International Conference on Learning Representations, ICLR 2017.