以下内容为结合李沐老师的课程和教材补充的学习笔记,以及对课后练习的一些思考,自留回顾,也供同学之人交流参考。
本节课程地址:14 数值稳定性 + 模型初始化和激活函数【动手学深度学习v2】_哔哩哔哩_bilibili
本节教材地址:4.8. 数值稳定性和模型初始化 — 动手学深度学习 2.0.0 documentation (d2l.ai)
本节开源代码:...>d2l-zh>pytorch>chapter_multilayer-perceptrons>numerical-stability-and-init.ipynb
数值稳定性和模型初始化
到目前为止,我们实现的每个模型都是根据某个预先指定的分布来初始化模型的参数。 有人会认为初始化方案是理所当然的,忽略了如何做出这些选择的细节。甚至有人可能会觉得,初始化方案的选择并不是特别重要。 相反,初始化方案的选择在神经网络学习中起着举足轻重的作用, 它对保持数值稳定性至关重要。 此外,这些初始化方案的选择可以与非线性激活函数的选择有趣的结合在一起。 我们选择哪个函数以及如何初始化参数可以决定优化算法收敛的速度有多快。 糟糕选择可能会导致我们在训练时遇到梯度爆炸或梯度消失。 本节将更详细地探讨这些主题,并讨论一些有用的启发式方法。 这些启发式方法在整个深度学习生涯中都很有用。
梯度消失和梯度爆炸
考虑一个具有 层、输入 和输出 的深层网络。 每一层 由变换 定义, 该变换的参数为权重, 其隐藏变量是 (令 )。 我们的网络可以表示为:
因此
如果所有隐藏变量和输入都是向量, 我们可以将 关于任何一组参数 的梯度写为下式:
换言之,该梯度是 个矩阵 与梯度向量 的乘积。 因此,我们容易受到数值下溢问题的影响. 当将太多的概率乘在一起时,这些问题经常会出现。 在处理概率时,一个常见的技巧是切换到对数空间, 即将数值表示的压力从尾数转移到指数。 不幸的是,上面的问题更为严重: 最初,矩阵 可能具有各种各样的特征值。 他们可能很小,也可能很大; 他们的乘积可能非常大,也可能非常小。
不稳定梯度带来的风险不止在于数值表示; 不稳定梯度也威胁到我们优化算法的稳定性。 我们可能面临一些问题。 要么是梯度爆炸(gradient exploding)问题: 参数更新过大,破坏了模型的稳定收敛; 要么是梯度消失(gradient vanishing)问题: 参数更新过小,在每次更新时几乎不会移动,导致模型无法学习。
(梯度消失)
曾经sigmoid函数 ( 4.1节 提到过)很流行, 因为它类似于阈值函数。 由于早期的人工神经网络受到生物神经网络的启发, 神经元要么完全激活要么完全不激活(就像生物神经元)的想法很有吸引力。 然而,它却是导致梯度消失问题的一个常见的原因, 让我们仔细看看sigmoid函数为什么会导致梯度消失。
%matplotlib inline
import torch
from d2l import torch as d2l
x = torch.arange(-8.0, 8.0, 0.1, requires_grad=True)
y = torch.sigmoid(x)
y.backward(torch.ones_like(x))
# .detach().numpy()转换为不计算梯度的Numpy数组
d2l.plot(x.detach().numpy(), [y.detach().numpy(), x.grad.numpy()],
legend=['sigmoid', 'gradient'], figsize=(4.5, 2.5))
正如上图,当sigmoid函数的输入很大或是很小时,它的梯度都会消失。 此外,当反向传播通过许多层时,除非我们在刚刚好的地方, 这些地方sigmoid函数的输入接近于零,否则整个乘积的梯度可能会消失。 当我们的网络有很多层时,除非我们很小心,否则在某一层可能会切断梯度。 事实上,这个问题曾经困扰着深度网络的训练。 因此,更稳定的ReLU系列函数已经成为从业者的默认选择(虽然在神经科学的角度看起来不太合理)。
[梯度爆炸]
相反,梯度爆炸可能同样令人烦恼。 为了更好地说明这一点,我们生成100个高斯随机矩阵,并将它们与某个初始矩阵相乘。 对于我们选择的尺度(方差 ),矩阵乘积发生爆炸。 当这种情况是由于深度网络的初始化所导致时,我们没有机会让梯度下降优化器收敛。
M = torch.normal(0, 1, size=(4,4))
print('一个矩阵 \n',M)
for i in range(100):
M = torch.mm(M,torch.normal(0, 1, size=(4, 4)))
print('乘以100个矩阵后\n', M)
一个矩阵
tensor([[ 1.1677, 0.3804, -0.7343, -1.8798],
[ 0.5325, -2.4282, 0.2886, 0.0961],
[-0.6474, -1.2622, -0.0183, -0.0958],
[-0.9811, 0.9840, -1.4430, 0.1905]])
乘以100个矩阵后
tensor([[-2.0338e+22, -1.2461e+21, 1.6642e+22, 1.4078e+21],
[ 1.4095e+22, 8.6345e+20, -1.1534e+22, -9.7620e+20],
[ 3.1960e+22, 1.9580e+21, -2.6153e+22, -2.2129e+21],
[ 9.7268e+21, 5.9587e+20, -7.9593e+21, -6.7356e+20]])
补充:
以MLP为例(省略偏移b):
是激活函数
𝜎′是𝜎的导数
(这里对角矩阵diag的意思是, 为一维向量,求导结果为对角矩阵)
,(𝑑−𝑡次连乘)
- 对于梯度消失的情况,如上述教材所示,可从sigmoid激活函数角度理解:
当sigmoid函数输入较大或较小时都会出现d-t个小数值连乘,可能导致结果接近于0,也即梯度消失,会引发如下问题:
- 梯度值变为0
- 对16为浮点数尤为严重
- 训练没有进展
- 无论如何选择学习率
- 对于底部层尤为严重
- 仅顶部层训练较好,神经网络无法深入
2. 对于梯度爆炸的情况,可从ReLU激活函数角度理解:
由于ReLU函数的特性,仅为大于1的梯度值连乘,当d-t很大时,梯度值将会很大,也即梯度爆炸,导致如下问题:
- 梯度值接近无穷大,超出值域
- 对16为浮点数尤为严重 (数值区间为6e-5~6e4)
- 对学习率敏感
- 学习率太大,则参数值大,梯度值更大
- 学习率太小,则训练无进展
- 需要在训练过程中不断调整学习率
打破对称性
神经网络设计中的另一个问题是其参数化所固有的对称性。 假设我们有一个简单的多层感知机,它有一个隐藏层和两个隐藏单元。 在这种情况下,我们可以对第一层的权重 进行重排列, 并且同样对输出层的权重进行重排列,可以获得相同的函数。 第一个隐藏单元与第二个隐藏单元没有什么特别的区别。 换句话说,我们在每一层的隐藏单元之间具有排列对称性。
假设输出层将上述两个隐藏单元的多层感知机转换为仅一个输出单元。 想象一下,如果我们将隐藏层的所有参数初始化为 , 为常量,会发生什么? 在这种情况下,在前向传播期间,两个隐藏单元采用相同的输入和参数, 产生相同的激活,该激活被送到输出单元。 在反向传播期间,根据参数 对输出单元进行微分, 得到一个梯度,其元素都取相同的值。 因此,在基于梯度的迭代(例如,小批量随机梯度下降)之后, 的所有元素仍然采用相同的值。 这样的迭代永远不会打破对称性,我们可能永远也无法实现网络的表达能力。 隐藏层的行为就好像只有一个单元。 请注意,虽然小批量随机梯度下降不会打破这种对称性,但暂退法正则化可以。
参数初始化
解决(或至少减轻)上述问题的一种方法是进行参数初始化, 优化期间的注意和适当的正则化也可以进一步提高稳定性。
默认初始化
在前面的部分中,例如在 3.3节 中, 我们使用正态分布来初始化权重值。如果我们不指定初始化方法, 框架将使用默认的随机初始化方法,对于中等难度的问题,这种方法通常很有效。
Xavier初始化
让我们看看某些没有非线性的全连接层输出(例如,隐藏变量) 的尺度分布。 对于该层 输入 及其相关权重 ,输出由下式给出
权重 都是从同一分布中独立抽取的。 此外,让我们假设该分布具有零均值和方差 。 请注意,这并不意味着分布必须是高斯的,只是均值和方差需要存在。 现在,让我们假设层 的输入也具有零均值和方差 , 并且它们独立于 并且彼此独立。
对于正向传播的均值与方差:
假设:
与相互独立
在这种情况下,我们可以按如下方式计算 的平均值和方差:
保持方差不变( )的一种方法是设置 。 现在考虑反向传播过程,我们面临着类似的问题,尽管梯度是从更靠近输出的层传播的。对于反向传播的均值与方差:
假设:
使用与前向传播相同的推断,我们可以看到,除非 , 否则梯度的方差可能会增大,其中 𝑛out 是该层的输出的数量。
这使得我们进退两难:我们不可能同时满足这两个条件。 相反,我们只需满足:
或等价于 .
这就是现在标准且实用的Xavier初始化的基础, 它以其提出者第一作者的名字命名(论文链接:glorot10a.pdf (mlr.press))。 通常,Xavier初始化从均值为零,方差 的高斯分布中采样权重。 我们也可以将其改为选择从均匀分布中抽取权重时的方差。 注意均匀分布 的方差为 。 将 代入到 的条件中,将得到初始化值域:
尽管在上述数学推理中,“不存在非线性”的假设在神经网络中很容易被违反, 但Xavier初始化方法在实践中被证明是有效的。
(注:以上正向和反向传播的均值和方差推论以及Xavier初始化方法在MLP中也适用。)
补充:从激活函数的角度提升数值稳定性
假设一个线性的激活函数,
对于正向传播的均值和方差:
假设:
激活函数
若要每层的输入和输出均值保持不变,则需: , 也即: ;
若要每层的输入和输出方差保持不变,则需: 也即: .
对于反向传播的均值和方差:
假设:
激活函数
若要每层的输入和输出方差保持不变,则需: 也即:
由以上推理可知:从激活函数的角度保持每层的输入和输出的均值和方差不变,必须使得激活函数 .
对于常用激活函数使用泰勒展开:
对于 𝑇𝑎𝑛ℎ 和 𝑅𝑒𝐿𝑈 函数,在零点附近均满足 。 对于 𝑠𝑖𝑔𝑚𝑜𝑖𝑑 函数,需要进行调整:
额外阅读
上面的推理仅仅触及了现代参数初始化方法的皮毛。 深度学习框架通常实现十几种不同的启发式方法。 此外,参数初始化一直是深度学习基础研究的热点领域。 其中包括专门用于参数绑定(共享)、超分辨率、序列模型和其他情况的启发式算法。 例如,Xiao等人演示了通过使用精心设计的初始化方法 (论文链接:[1806.05393] Dynamical Isometry and a Mean Field Theory of CNNs: How to Train 10,000-Layer Vanilla Convolutional Neural Networks (arxiv.org)), 可以无须架构上的技巧而训练10000层神经网络的可能性。
如果有读者对该主题感兴趣,我们建议深入研究本模块的内容, 阅读提出并分析每种启发式方法的论文,然后探索有关该主题的最新出版物。 也许会偶然发现甚至发明一个聪明的想法,并为深度学习框架提供一个实现。
补充:
上文提到的文献名为:"Dynamical Isometry and a Mean Field Theory of CNNs: How to Train 10,000-Layer Vanilla Convolutional Neural Networks"。
其独特之处在于:
提出了一种新的Delta-Orthogonal初始化方案和对应的训练方法,使得可以有效地训练具有极深层次(例如10,000层)的CNNs,而不依赖于如残差连接(residual connections)和批量归一化(batch normalization)等特殊的架构技巧。
算法核心:
Delta-Orthogonal初始化方法———结合正交性和空间非均匀性:
- 正交性意味着卷积操作保持了数据的范数不变,有助于信号在网络中的稳定传播。在Delta-Orthogonal初始化中,卷积核的权重被设置为正交的,这样每一层的输出都能保持与输入相同的范数;
- 在标准的正交初始化中,权重的方差在空间上是均匀分布的。然而,这种均匀性可能导致网络在训练过程中逐渐失去对空间结构的敏感性,因为所有位置的权重都以相同的方式影响输出。Delta-Orthogonal初始化通过在空间上引入非均匀性来解决这个问题,使得网络能够更好地捕捉和维持输入数据的空间特征;
- Delta-Orthogonal初始化中的“Delta”指的是将权重的方差集中在卷积核的中心,形成一个类似于Dirac Delta函数的分布。这意味着网络的每个卷积核都有一个主要的、集中的影响区域,并且这个区域在空间上是非均匀分布的;
- Delta-Orthogonal初始化可以在网络的每一层实现动态等距性(Dynamical Isometry),有助于保持梯度的稳定性,并且允许不同空间频率的信号在网络中均匀地传播,有助于避免梯度消失或爆炸问题,从而提高了网络的学习能力和泛化性能,即使是非常深的网络也能够有效地训练。
算法步骤:
1. 定义卷积核的参数:
- 确定卷积核的大小(例如, ),输入通道数( ),输出通道数( )和非均匀方差向量 , 定义了卷积核中每个位置的权重方差。
2. 生成正交矩阵:
- 随机生成两个大小为 的正交矩阵 和 ,满足 和 ,其中 是单位矩阵。这意味着 和 分别是 维空间中的一组正交基。
3. 构造非均匀方差分布的权重
- 根据非均匀方差向量 ,为卷积核中的每个位置生成权重。权重是根据 中的值从高斯分布中采样得到的,其中方差由 给出。这样可以确保卷积核的中心具有更高的权重方差,而边缘的方差较低。
4. 应用分块卷积操作
- 定义一个分块卷积操作,它将正交矩阵 和 应用到权重矩阵上,生成一个新的块矩阵 。这个操作涉及到将 和 与权重矩阵中的相应块相乘。
5. 组合权重矩阵
- 将生成的权重矩阵与正交矩阵 相结合,其中 是一个具有正交行的矩阵,其行向量是从标准正态分布中采样得到的。这样,最终的卷积核 将具有正交性和非均匀的空间方差分布。
6. 细化步骤
- 对于每个卷积核的大小,重复步骤 2 到 5,逐步构建出所需的卷积核。
- 对于二维卷积核,这个过程涉及到构建一个分块循环结构,其中每个小块是一个 的矩阵, 是卷积核空间维度的一个因子。
7. 集成到神经网络中
- 将生成的正交卷积核 作为神经网络中卷积层的初始权重。
- 在训练过程中,这些权重将根据反向传播算法进行更新,但由于初始的正交性和非均匀分布,网络的训练将更加稳定,有助于避免梯度消失或爆炸问题。
小结
- 梯度消失和梯度爆炸是深度网络中常见的问题。在参数初始化时需要非常小心,以确保梯度和参数可以得到很好的控制。
- 需要用启发式的初始化方法来确保初始梯度既不太大也不太小。
- ReLU激活函数缓解了梯度消失问题,这样可以加速收敛。
- 随机初始化是保证在进行优化前打破对称性的关键。
- Xavier初始化表明,对于每一层,输出的方差不受输入数量的影响,任何梯度的方差不受输出数量的影响。
练习
- 除了多层感知机的排列对称性之外,还能设计出其他神经网络可能会表现出对称性且需要被打破的情况吗?
解:
1)权重共享: 在某些网络结构中,例如卷积神经网络(CNN),可能会采用权重共享的方式。这意味着在网络的不同部分使用相同的权重。这种权重共享可能导致对称性,因为网络的不同部分具有相同的参数。为了打破这种对称性,可以引入随机初始化或者使用不同的权重初始化策略。
2)对称激活函数: 如果在网络中使用了对称的激活函数,例如ReLU的负部分与正部分关于原点对称,可能会导致对称性。为了打破这种对称性,可以使用具有非对称性的激活函数,例如ReLU。
3)输入数据对称性: 如果输入数据具有某种对称性,例如图像中的平移对称性,那么网络可能会学习到这种对称性而导致过拟合。为了避免这种情况,可以通过数据增强技术,如随机裁剪或旋转,来打破输入数据的对称性。
4)任务特定的对称性: 在特定的任务中,可能存在一些对称性质,例如序列任务中的时间对称性或者图像任务中的空间对称性。这些对称性可能会影响网络的学习能力。为了克服这种影响,可以通过引入任务特定的正则化或者损失函数来打破这种对称性。
2. 我们是否可以将线性回归或softmax回归中的所有权重参数初始化为相同的值?
解:
不行,如果将线性回归中的所有权重参数初始化为相同的值,那么模型将只是对输入特征的简单求和,失去了对特征的区分能力,这会导致模型无法拟合数据。
如果将softmax回归中的所有权重参数初始化为相同的值,那么对于每个输入,模型的输出都会趋向于相同的概率分布,这会导致模型无法区分不同类别,从而降低模型的分类性能。
3. 在相关资料中查找两个矩阵乘积特征值的解析界。这对确保梯度条件合适有什么启示?
解:
两个矩阵乘积特征值的解析界是指:当遇到高阶矩阵时,两个高阶矩阵的乘积的特征值求解非常困难,也没有必要逐一计算精确的特征值。在实际计算中,通常通过估计特征值的解析界来估计特征值,解析界越小,所估计的特征值就越精确。
特征值的解析解包含整体特征值的上下界和特征值的包含区域(盖尔圆),可参考链接:https://blog.csdn.net/SL_World/article/details/106551514。
对于确保梯度条件合适,可以从以下几点考虑:
- 特征值的大小与梯度稳定性:特征值描述了矩阵变换的放大或缩小倍数。当特征值较大时,意味着在对应特征向量方向上的变化较大,可能导致梯度爆炸的问题;而当特征值较小时,可能导致梯度消失的问题。因此,我们需要确保矩阵乘积的特征值解析界处于合适的范围内,以保证梯度的稳定性。
- 条件数的影响:条件数是矩阵的最大奇异值与最小奇异值的比值,描述了矩阵的稳定性。当矩阵的条件数较大时,意味着矩阵具有较大的扰动敏感性,可能导致数值计算的不稳定性。因此,我们需要确保矩阵乘积的条件数不要过大,以保证梯度计算的稳定性。
- 参数初始化的影响:初始参数的选择可能会影响矩阵乘积的特征值分布。合适的参数初始化可以帮助避免梯度爆炸或者梯度消失的问题,从而提高模型的训练稳定性。
4. 如果我们知道某些项是发散的,我们能在事后修正吗?看看关于按层自适应速率缩放的论文 (论文链接:[1708.03888] Large Batch Training of Convolutional Networks (arxiv.org) )。
解:
如果在训练过程中发现某些项(比如梯度)出现发散的情况,可以尝试通过以下方法来进行事后修正:
- 参数初始化优化:合适的参数初始化策略可以有助于避免梯度发散问题的发生,例如使用Xavier初始化。
- 梯度裁剪:当梯度的范数超过某个阈值时,可以对梯度进行裁剪,将其缩放到一个合适的范围内,从而防止梯度爆炸的问题。
- 学习率调整:可以尝试降低学习率,以缓解梯度更新过大导致的发散现象。
- 模型结构调整:有时候发散问题可能与模型结构有关,可以考虑调整模型的结构或损失函数的设计。
- 使用稳定的优化算法: 有些优化算法(如Adam、RMSprop等)对梯度的变化更为稳定,可以尝试使用这些算法来缓解梯度发散问题。
按层自适应学习率缩放的论文提出了一种按层自适应学习率缩放(Layer-wise Adaptive Rate Scaling, LARS)的优化方法,降低了大批量训练时的优化困难。
- 研究背景:
加速大型神经网络计算的常用方法是增加更多的计算能力(比如将更大的batch size放在更多的GPU节点上训练)。但在保持epochs不变的情况下,增加全局batch size,意味着更新权重的迭代次数减少。
补偿迭代次数减少的直接方法是提高learning rate(LR)。Krizhevsky(2014)建议依据batch size增大水平线性放大LR,即当batch size增加k倍时,LR也相应增加k倍。
但这也引发了新的问题:当batch size很大时,LR也会过大,导致优化困难,并且出现发散,尤其时在训练的初始阶段。
标准 SGD 对所有层使用相同的LR = λ:
当 λ 较大时,更新 可能大于 ,可能导致发散,这使得训练的初始阶段对权重初始化和初始LR高度敏感。
此外,采用网络每层权重范数与梯度更新范数之间的比率来评估LR较大时的训练稳定性时,如果这个比率太高,训练可能会变得不稳定。另一方面,如果比率太低,则权重变化不够快。并且,这个比率在不同层之间差异很大,因此有必要为每一层设置单独的LR。
-解决方法:
论文提出按层自适应学习率缩放(Layer-wise Adaptive Rate Scaling, LARS)算法:
网络每层引入一个local LR = :
其中, 为超参数,其值 < 1,为每层在一次更新中改变权重的置信度。
则权重更新为:
其中, 为 global LR, 相当于对梯度进行L2归一化,因此,local LR的引入使得权重更新的幅度不在依赖于梯度的大小,梯度只决定权重更新方向,从而有助于缓解梯度消失和梯度爆炸。
local LR的定义可拓展至包含权重衰减的参数更新:
LARS算法的独特之处在于:
1)首先,LARS是对每一层设置单独的学习率,而不是对每个权重设置单独的学习率,从而获得更好的稳定性。
2)其次,更新的幅度是相对于权重范数来控制的,以便更好地控制训练速度。
-实验结果:
AlexNet-BN网络在应用LARS的情况下,batch size从512增加到8192,设置相同的epochs,测试精度无明显差异。
ResNet50网络在应用LARS的情况下,batch size从256增加到32k,设置相同的epochs,测试精度无明显差异。
参考链接:
https://www.jianshu.com/p/e430620d3acf Large Batch Training of Convolutional Networks - 郑之杰的个人网站