动手深度学习-数值稳定性模型初始化激活函数
数值稳定性
假设有一个d是隐藏层的总数,而t是第t层。h为隐藏层
当前层就是前一层经过激活函数,那么y就等于每一层的累计,最后乘上损失函数
$$ \begin{align*} h_t &= f_t(h_{t-1}) \\ y &= \ell \circ f_d \circ \ldots \circ f_1 (x) \end{align*} $$
计算损失函数$\ell$关于参数$\mathbf w_t$的梯度
$$ \begin{equation} \frac{\partial \ell}{\partial W^t} = \frac{\partial \ell}{\partial h^{d}} \cdot \frac{\partial h^{d}}{\partial h^{d-1}} \cdots \frac{\partial h^{t+1}}{\partial h^{t}} \cdot \frac{\partial h^{t}}{\partial W^t} \end{equation} $$
以上有d-t次矩阵乘法。
带来俩个,数值稳定性常见的俩个问题,一个是梯度爆炸一个是梯度消失。
加入每一层是1.5然后有100层的话,那么就是1.5的100次方,而如果每层是0.8的话,那么就是0.8的100次方。
第一个数很容易带来浮点上线的问题,第二个可能就不见了
加入了如下MLP,$\sigma$是激活函数,为了简单起见,省略了偏移值,$h^{t-1}$代表了上一层的输出
$$ \begin{equation} f_t(h^{t-1}) = \sigma(W_th^{t-1}) \end{equation} $$
diag一般用来代表对角矩阵
diag
函数在几何上没有直接的、像旋转或缩放那样的直观变换意义,但它在描述和操作矩阵时具有重要的作用,特别是在处理线性变换的性质时。我们可以从几个不同的角度来理解diag
函数的几何意义:
- 对角矩阵的几何意义: 当
diag
函数用于创建一个对角矩阵时,它实际上定义了一个线性变换,该变换只在坐标轴方向上有影响,而在其他方向上不产生任何效果。换句话说,对角矩阵表示的线性变换仅在每个基向量的方向上进行伸缩,而不改变空间的方向。例如,一个二维空间中的对角矩阵将x轴上的点乘以a,将y轴上的点乘以b。
$$ \frac{\partial h^t}{\partial h^{t-1}} = \text{diag}\left(\sigma'\left(W^th^{t-1}\right)\right)(W^T) $$
$$ \prod_{i=t}^{d-1}\frac{\partial h^{i+1}}{\partial h^i} = \prod_{i=t}^{d-1} \text{diag}\left(\sigma'\left(W^ih^{i-1}\right)\right)(W^i)^T $$
Relu
如果使用relu作为激活函数,上式中的一些元素会来自于$\prod_{i=t}^{d-1}(W^i)^\top$
如果d-t很大,值将会很大:意思是在隐藏层很多的神经网络之中,前几层的值将会非常的大。
梯度爆炸
梯度爆炸会导致超出值域,对于16位浮点数尤为严重
会对于学习率非常铭感,容易造成每一层梯度明显不一样
- 如果学习率太大,会导致大参数值,更大的梯度
- 如果学习率太小训练无进展
- 我们可能需要在训练的过程中不断调整学习率
sigmoid
如果使用sigmoid作为激活函数
当输入很小或者很大的时候,梯度都会消失。
梯度消失的问题
在反向传播算法中,为了计算权重的梯度,我们需要对网络中的每一层应用链式法则。这意味着每一层的导数会被相乘,以得到最终层对输入层权重的梯度。如果每一层的导数都很小,那么经过多层之后,梯度会呈指数级衰减,最终可能变得如此之小以至于无法有效地更新网络的早期层的权重。这就是所谓的“梯度消失”问题。
梯度值变成0,无论学习率怎么设置,都不会有进展
这个现象对于底部层尤为严重
- 仅仅顶部层训练的较好
- 无法让神经网络更深
底部曾会消失,底部层是最接近输入层的
所以我们要避免梯度太大和太小
sigmoid的斜率是不可能大于1的,所以每层都用sigmoid就一定会发生梯度消失。
如何让训练更加稳定
目标让梯度值在合理的范围内 [1e-1e3]
将乘法变加法Resnet,LSTM
归一化:梯度归一化,梯度裁剪 合理的权重初始化和激活函数
让每层的方差是一个常数
将每层输出的梯度看成随机变量,让它们均值和方差都保持一致
正向,这里代表均值为0,方差为a
$$ \mathbb{E}[h_{i}^t] = 0 \\ Var[h_{i}^t] = a $$
反向,均值为0,方差为b
$$ \mathbb{E}\left[\frac{\partial \ell}{\partial h_i^t}\right]=0\\ Var\left[\frac{\partial \ell}{\partial h_i^t}\right]=b \quad \forall i,t $$
这里的a和b都是常数
权重初始化
在合理值区间里随机初始参数,因为在训练开始的时候,更容易出现数值不稳定
- 原理最优解的地方损失函数表面看可能很复杂
- 最优解附近表面会比较平
之前随机初始化的方式,都是在均值为0,方差为0.01(标准差为0.1)的正太分布中随机的,可以用于小网络,但是不能保证速度神经网络。
正向方差
假设
$w^t_{i,j}$是独立同分布,$\mathbb{E}[w^{t}_{i,j}]=0,w^{t}_{i,j},Var[w^{t}_{i,j}]=\gamma_t$,
$h^{t-1}_i$独立由于$w^t_{i,j}$:即当前层的权重和输入是独立的
假设有激活函数$\mathbf h^ t=\mathbf w^t\mathbf h^{t-1}$,这里$W^t \in \mathbb{R}^{n_t \times n_{t-1}}$
$$ \begin{equation} \mathbb{E}[h_i^t] = \mathbb{E}\left[\sum_j w_{i, j}^{t} h_j^{t - 1}\right] = \sum_j \mathbb{E}[w_{i, j}^{t}] \mathbb{E}[h_j^{t - 1}] = 0 \end{equation} $$
这里i指的是t-1层神经元的标号,j指的是t层神经元的标号(权重为第i行第j列)。这里假设了当前层的输出维度是$n_t$(因为每层的输出维度是不一样的),输入维度是$n_t-1$,t指的是第t层,h就是第t层的输入,$\gamma_t$就是初始选择的方差。$\mathbb{E}$一般表示期望值
最后的方差:输入的方差和输出的方差是一样的
$$ Var[h^t_i]=n_{t-1}\gamma_t=1 $$
反向方差
$$ \frac{\partial \ell}{\partial h^{t-1}} = W^t \frac{\partial \ell}{\partial h^{t}} \quad \xrightarrow[]{} \quad \left(\frac{\partial \ell}{\partial h^{t-1}}\right)^T = \left(W^t\right)^T \left(\frac{\partial \ell}{\partial h^{t}}\right)^T $$
$$ \mathbb{E} \left[ \frac{\partial \ell}{\partial h_{i}^{t-1}} \right] = 0 $$
$$ \text{Var}\left[ \frac{\partial \ell}{\partial h_{i}^{t-1}} \right] = n_t \gamma_t \text{Var}\left[ \frac{\partial \ell}{\partial h_j^{t}} \right] \quad \xrightarrow[]{} \quad n_t \gamma_t = 1 $$
xavier初始
Xavier初始化的策略是将权重初始化为一个均值为0,方差为特定值的高斯分布或均匀分布。
这种初始化方法有助于确保在网络的前向传播和反向传播过程中,各层的信号既不过分放大也不过分缩小,从而使梯度保持在合理的范围内,提高训练的稳定性和效率。Xavier初始化尤其适用于使用sigmoid或tanh作为激活函数的网络,而对于ReLU激活函数,可能会使用稍微不同的初始化策略,例如He初始化,以考虑到ReLU的非线性性质。
难以满足$n_{t-1}\gamma_t=1$和$ \gamma_t = 1$,$n_{t-1}$是第t层输入的维度$n_{t}$是第7层输出的维度,很难去控制$n_{t-1}$的值
有一个叫做xavier的方法,是取这种
t层权重的方差乘以(输入加上维度除以2),给定当前层输入和输出的大小,就可以确定权重需要满足的方差的大小。
他确定了随机分布的方式,可以对应的策略在正态分布和均匀分布中采样。
$$ \gamma_t(n_{t-1} + n_t)/2 = 1 \quad \rightarrow \quad \gamma_t = 2/(n_{t-1} + n_t) $$
- 正态分布$N \left( (0, \sqrt{2}/(n_{t-1} + n_t) ) \right) $
- 均匀分布$ u \left( -\sqrt{\frac{6}{(n_{t-1} + n_t)}}, \sqrt{\frac{6}{(n_{t-1} + n_t)}} \right)$
分布u[-a,a]和方差是$a^2/3$
根据输入输出来,适配权重形状变换,特别是$n_t$
这就是在输出和梯度都是随机分布的情况下如何做初始化
假设激活函数为$\sigma(x)=\alpha x+\beta$
为了让前向输入的均值为0,方差为1,可以推导出$\alpha =1,\beta=0$。也假设激活函数只能等于本身,反向同理。
意味着激活函数必须f(x)=x,即近似为一个恒等函数(identity function)
relu和tanh在0点附近确实大约等于0,而sogmoid可以进行调整为4 x sigmoid(x)-2实现2在0点附近为0
总结
合理的权重初始值和激活函数的选取可以提升数值稳定性:每一层的输出和每以层的梯度都初始化为均值为0,方差为常数的随机变量
在训练中出现NAN有可能是梯度太大造成的,python中会出现inf,0*inf就会出现nan
a= 1.7976931348623157e+308
print(0*(a+a))
梯度爆炸不是由激活函数引起的,而是每个权重太大了。
为什么从正态分布中取值?可以限制输出是在某一个范围中的。
大数定理(Law of Large Numbers, LLN)是概率论中的一个核心概念,它描述了当随机试验被重复许多次时,样本均值趋向于期望值的趋势。这个定理保证了随着试验次数的增加,随机事件的频率会越来越接近该事件的实际概率。
浮点数在0附近最近最密集。可以参考指数偏移机制。
从数学上来讲不管取什么数字都不会影响模型的可表达性。所以防止梯度爆炸的做的事情就是以免硬件无法计算。
因为最优解的附近一般来说是稳定的,所以我们让我们的采样稳定在一个范围内,可能会得到相对最优的解。
注意4 x sigmoid(x)-2还是无法避免梯度消失。