第02章:深度神经网络
- author: zhouyongsdzh@foxmail.com
- date: 2017-04-12
- weibo: @周永_52ML
本章关键词:多层感知机、全连接层、Softmax、激活函数、Normalization、Pooling、Embedding、注意力机制、Transformer等
DNN符号定义
符号 | 含义 |
---|---|
$n^{[0]}$ | 表示NN输入层的神经元个数,为了符号统一,规定输入层为第0层 |
$n^{[l]}$ | 第$l$层神经元个数 |
$a^{[l-1]}$ | 表示NN第$l$层输入信息,一条样本的维度为$(1, n^{[l]})$ |
$W^{[l]}$ | 表示第$l$层与$l-1$层之间的连接矩阵,维度:($n^{[l]}$, $n^{[l-1]}$),即:$W^{[1]} \in R^{n^{[1]} \times n^{[0]}}$ |
$b^{[l]}$ | 表示第$l$层的偏置项参数,维度:($n^{[l]}$, $1$) |
$z^{[l]}$ | 表示第$l$层的线性表达$z^{[l]} = W^{[l]} \cdot a^{[l-1]} + b^{[l]}$, 维度:($n^{[l]}$, $1$) |
$m$ | 表示Batch Size |
神经网络的前向与反向
以NN全连接层操作为例:
前向计算
$$
z^{[1]} = a^{[0]} \cdot {W^{[1]}}^T+ b^{[1]}, \\
a^{[1]} = \sigma(z^{[1]}), \\\
z^{[2]} = a^{[1]} \cdot {W^{[2]}}^T+ b^{[2]}, \\
a^{[2]} = \sigma(z^{[2]}), \\\
z^{[3]} = a^{[2]} \cdot {W^{[3]}}^T+ b^{[3]}, \\
a^{[3]} = \sigma(z^{[3]}), \\\
\hat{y} = sigmoid(a^{[3]})
$$
反向计算
$$
\mathcal{L}(a^{[3]};W^{[1]},\; \cdots,\;b^{[3]}) = - y \cdot \log(\hat{y}) - (1 - y) \cdot \log(1-\hat{y}) \\\
\mathbf{d}a^{[3]} = \frac{\partial{\mathcal{L}}}{\partial a^{[3]}} = \frac{\partial{\mathcal{L}}}{\partial{\sigma(z^{[3]})}} = (\hat{y} - y) \\\
\mathbf{d}z^{[3]} = \mathbf{d}a^{[3]} \cdot \frac{\partial{a^{[3]}}} {\partial z^{[3]}}, \\\
\quad 注:\frac{\partial{a^{[3]}}} {\partial z^{[3]}}是关于z^{[3]}的梯度公式,也是一个关于输入z^{[3]}和输出a^{[3]}的表达式。这里的z^{[3]},a^{[3]}也是“变量” \\\
\mathbf{d}W^{[3]} = \frac{\partial{\mathcal{L}}}{\partial{W^{[3]}}} = \frac{\partial{\mathcal{L}}}{\partial a^{[3]}} \cdot \frac{\partial{a^{[3]}} }{\partial z^{[3]}} \cdot \frac{\partial{z^{[3]}} }{\partial W^{[3]}} = \mathbf{d}z^{[3]} \cdot \frac{\partial{z^{[3]}} } {\partial W^{[3]}} = \mathbf{d}z^{[3]} \cdot a^{[2]} \\\
\qquad 注:可以看到,这里是矩阵相乘(前向的输入 * 反向的输入),写代码时⚠矩阵转秩问题 \\\
\mathbf{d}a^{[2]} = \frac{\partial{\mathcal{L}}} {\partial{a^{[2]}}} = \mathbf{d}z^{[3]} \cdot \frac{\partial{z^{[3]}}} {\partial{a^{[2]}}} = \mathbf{d}z^{[3]} \cdot W^{[3]} \\\
注:这里a^{[2]}也是中间变量,也存在自身前向信息(data)和反向信息(grad) \\\
\mathbf{d}b^{[3]} = \mathbf{d}z^{[3]} \cdot \frac{\partial{z^{[3]}}} {\partial{b^{[3]}}} = \mathbf{d}z^{[3]} \\\
注:注意维度,这里需要按cols求和 \\\
…..
$$
由此,总结NN前向计算和反向传播(梯度计算)的通用公式。变量如下:$a^{[l-1]} \in R^{k \times n^{[l-1]}}$, $\mathbf{d}a^{[l-1]} \in R^{k \times n^{l-1}}$, $W^{[l]} \in R^{n^{[l]} \times n^{[l-1]}}$, $b^{[l]} \in R^{1 \times n^{[l]}}$, $z^{[l]} \in R^{k \times n^{[l]}}$, $a^{[l]} \in R^{k \times n^{[l]}}$, $k$表示样本数,如此下去….
FC前向传播通用公式
$$
z^{[l]} = a^{[l-1]} \cdot {W^{[l]}}^{\mathrm{T}} + b^{[l]} \\\
a^{[l]} = \sigma(z^{[l]}) \\\
z^{[l+1]} = a^{[l]} \cdot {W^{[l+1]}}^{\mathrm{T}} + b^{[l+1]} \\\
…
$$
伪代码:
1 | Y.noalias() = (X * W.transpose()).rowwise() + b.row(0); |
这里
b.row(0)
的维度是(1,n[l]),使用了类似python中的广播机制 维度变为(k,n[l])
FC反向传播通用公式
$$
\mathbf{d}z^{[l]} = \mathbf{d}a^{[l]} \cdot \frac{\partial{a^{[l]}}}{\partial{z^{[l]}}} \\\
\mathbf{d}W^{[l]} = \mathbf{d}z^{[l]} \cdot \frac{\partial{z^{[l]}}}{\partial{W^{[l]}}} = {\mathbf{d}z^{[l]}}^{\mathrm{T}} \cdot a^{[l-1]} \\\
\mathbf{d}a^{[l-1]} = \mathbf{d}z^{[l]} \cdot W^{[l]} \\\
\mathbf{d}b^{[l]} = \mathbf{d}z^{[l]} \qquad // 注:需要按cols求和
$$
针对NN的全连接$z^{[l]} = {a^{[l-1]}} \cdot {W^{[l]}}^{\mathrm{T}} + b^{[l]}$,反向伪代码:
1 | dW.noalias() += dY.transpose() * X; |
深度MLP 小结:
- 前向传播由多层的矩阵运算、连接函数共同组成,分别对应两个Graph Op算子;
- 反向传播从Loss出发,分别由多层的连接函数、矩阵运算的梯度计算组成;
- 参与Op算子的变量均要保存当前变量数据(data)和对应的梯度信息(grad),二者shape一致;
Softmax
softmax是深度学习模型中重要的操作之一,在分类监督学习、Attention机制中均离不开该操作。 本节的目标是对softmax函数的来龙去脉以及在分类场景的应用讲清楚,安排如下:
- 首先,从数学和概率的角度理解soft(软化的)max的由来;
- 然后,讲清楚softmax函数为什么可以用在多分类问题上;
- 最后,给出它在开源深度学习框架tensorflow、openmi(Open-sourced Machine Intelligence)上的实现。
softmax函数由来
softmax函数表达式我想大家已经很清楚了,在此赘述:
$$
\text{softmax}(a_i) = \frac {\exp(a_i)} {\sum_{k=1}^{K} \exp(a_k)}
$$
下面这个函数与上式“貌似”不相同,但是它们又及其相关:
$$
g(x, y) = \text{log}_e(e^x + e^y)
$$
两个表达式的关联性先不谈,我们先要解释清楚$g(x,y)$函数的由来,就要从hardmax说起。
hardmax函数
softmax函数其实是从hardmax演变而来的,hardmax其实是我们生活中很常见的函数,表达式为:
$$
\text{hardmax} = max\{x, y\}
$$
物理含义很清楚,就是取x和y中较大的哪个值。如果y=0,可得表达式为$max\{x, 0\}$。画图可知,该函数在$x=0$处是连续不可导的。函数可导可以帮助我们做很多事情,那么有没有办法对其变形,找到一个连续可导的近似函数呢?此时就有了softmax函数$g(x,y) = \text{log}_e(e^x + e^y)$。
在基于梯度法求解机器学习模型最优解的过程中,函数可导是一个必要的前提条件。
我们先来看$g(x,y)$函数的数学特性。指数函数有一个特点,就是变化率非常快。当$x > y$时,通过指数的放大作用,使得二者的差距进一步变大,即$e^x \gg e^y$。所以有$e^x + e^y \approx e^x$,那么此时$g(x,y) = \text{log}_e(e^x + e^y) \approx \text{log}_e(e^x) = x$。根据推导过程,可以知道:$g(x,y)$约等于$x,y$中较大的值,即$g(x,y) \approx \text{max}(x,y)$。
所以我们得出一个结论:$g(x,y)$是$max(x,y)$的近似函数,两个函数有相似的数学特性。两个函数的图形如下:
可以看出,当$x,y$的差别越大时,$g(x,y)$和hardmax函数吻合度越高。同时也可以看出,softmax是一个连续且处处可导的函数,这时一个非常重要的特性:$g(x,y)$即具有与$\text{max}(x,y)$的相似性,又避免了$\text{max}(x,y)$函数会出现连续不可导的情况。
softmax函数概率模型
本节我们回答一个问题:上面提到的hardmax近似函数$g(x,y)$与神经网络分类层的softmax函数是什么关系?
假设我们要从a,b两个未知数中取一个较大的值,即$\text{max}(a,b)$,那么取到两个数字的概率分别是多少呢?我们可以构建一个概率模型:
- 当a=b时,取任意一个数字都可以,所以各占50%,即$p(a)=p(b)=50\%$;
- 当a=4,b=6时,b比a大,此时更倾向于b,取到b的概率应该会更大些,即$p(a)=40\%,p(b)=60\%$;
- 当a=8,b=2时,a比b大,此时更倾向于a,取到a的概率应该会更大些,即$p(a)=80\%,p(b)=20\%$.
当变量变多时,此时hardmax变成了$\text{max}(a_1, a_2, \cdots, a_K)$,根据假设的概率模型,取到每一个样本点的概率即为$p(a_i) = \frac{a_i}{\sum_{k=1}a_k}$
上述表达式与softmax“貌似”很熟,其实对于机器学习多分类问题来说,训练过程中需要对参数求导得到其梯度信息再用来更新参数,从上一节可知hardmax函数并不是处处可导的,那么此时就用hardmax的近似函数softmax来替代它,我们已知了二者之间的关系:
$$
f(a_1, a_2, \cdots, a_K) = \text{max}(a_1, a_2, \cdots, a_K) \approx g(a_1, a_2, \cdots, a_K) = \text{log}_e(e^{a_1} + e^{a_2} + \cdots + e^{a_K})
$$
因此,根据hardmax函数表达式,得出softmax的概率模型表达式为:
$$
\text{softmax}_{(i)} = \frac{e^{a_i}} {\sum_{k=1}^K e^{a_k}}
$$
以上就是softmax函数的由来。再次梳理下逻辑:softmax是hardmax的近似函数,也是对hardmax函数的优化(解决了hardmax不可导问题)。softmax函数+概率模型得到了深度学习结构中常见的softmax概率模型表达式。
$$
\text{softmax}函数+概率模型 \longrightarrow \text{softmax}概率模型表达式
$$
softmax表达式与概率的关系
根据概率的定义,一个事件发生的概率这里用$p\in [0,1]$表示,事件一定发生的概率是1,不会发生的概率是0,事件结果所有可能性的概率之和等于1。
以神经网络最后一层输出为例,经过softmax层计算后的表达式为:
$$
s_i = \frac{e^{z_i}} {e^{z_1} + e^{z_2} + \cdots + e^{z_K}} \qquad s_i \in [0,1]
$$
对所有神经元s求和,得到:
$$
\sum_{i=1}^K s_i = \frac {e^{z_1} + e^{z_2} + \cdots + e^{z_K}} {e^{z_1} + e^{z_2} + \cdots + e^{z_K}} = 1
$$
由此可知,神经网络输出层的数据,经过softmax层转换后的结果,即可满足概率的特性。因此,FC输出层的数据转化为概率表达式后的输出值就有了新的意义。对应分类问题来说,输出值表示这个结果属于不同类别的可能性大小。
SoftmaxOp和SoftmaxCrossEntropyWithLogitsOp
SoftmaxOp多用于多分类问题,假设为K类,那么属于第i类的概率为:
$$
p_i = \frac {\exp(a_i)} {\sum_{k=1}^{K} \exp(a_k)}
$$
Softmax计算优化
因为是指数计算,为了避免_指数越界出现NAN问题_,通常会分别对分子分母乘以一个常量C,即
$$
p_i = \frac{\exp(a_i)} {\sum_{k=1}^{K} \exp(a_k) } = \frac{C \exp(a_i)} { C \sum_{k=1}^{K} \exp(a_k) } = \frac {\exp(a_i + \log(C))} {\sum_{k=1}^{K} \exp(a_k + \log(C))}
$$
通常$\log(C)=-\max(a)$,如此相当于K维的向量a取值平移到[-, 0]之间,指数最大值是1而不是正无穷,避免了Nan问题。
Softmax梯度
$$
\frac {\partial p_i} {\partial a_j} = \frac {\partial \frac {\exp(a_i)} {\sum_{k=1}^{K} \exp(a_k)}} {\partial a_j}
$$
根据除法导数公式$f(x) = \frac {g(x)} {h(x)}$,存在$f’(x) = \frac {g’(x)h(x) - g(x)h’(x)} {h^2(x)}$。在这里$g(x) = \exp(a_i)$, $h(x) = \sum_{k=1}^K \exp(a_k)$。
对于$\frac {\partial h(x)} {\partial a_j}$,它的导数总是$\exp(a_j)$;对于$\frac{g(x)}{\partial a_j}$,分两种情况如果$i=j$ 梯度为$\exp(a_j)$,否则梯度为0(对于$a_j$来说,$a_i$是常数)。
所以Softmax梯度公式分两种情况:
当$i=j$时,
$$
\frac {\partial p_i} {\partial a_j} = \frac {\partial \frac {\exp(a_i)} {\sum_{k=1}^{K} \exp(a_k)}} {\partial a_j} = \frac {\exp(a_i) \cdot \sum_{k=1}^{K} \exp(a_k) - \exp(a_i) \cdot \exp(a_j)} {\left(\sum_{k=1}^{K} \exp(a_k)\right)^2} \\\
= \frac {\exp(a_i) } {\sum_{k=1}^{K} \exp(a_k)} \cdot \frac {\left(\sum_{k=1}^{K} \exp(a_k) - \exp(a_j) \right)} {\sum_{k=1}^{K} \exp(a_k)} = p_i * (1- p_j)
$$
当$i \neq j$时,
$$
\frac {\partial p_i} {\partial a_j} = \frac {\partial \frac {\exp(a_i)} {\sum_{k=1}^{K} \exp(a_k)}} {\partial a_j} = \frac {0 - \exp(a_i) \cdot \exp(a_j)} {\left(\sum_{k=1}^{K} \exp(a_k)\right)^2} = - p_i \cdot p_j
$$
因此Softmax梯度公式为:
$$
f(x) = \begin{cases} \displaystyle
p_i \cdot (1 - p_j) & \text{if} \; i=j \\\
-p_i \cdot p_j & \text{if} \; i \neq j
\end{cases}
\longrightarrow
\mathbf{\frac{\partial p_i} {\partial a_j} = p_i (\delta_{ij} - p_j)}, \;
\delta_{ij} = \begin{cases} \displaystyle
1 & \text{if} \; i = j \\\
0 & \text{if} \; i \neq j
\end{cases}
$$
交叉熵损失(Cross Entropy Loss)
交叉熵用来衡量相同事件空间里两个概率分布的差异。应用到分类问题里,就是实际label输出(概率)与期望输出(概率)之间的距离,交叉熵越小,说明两个概率分布越接近。这里假设概率分布Y为实际输出,P为期望输出,H(Y,P)为交叉熵,那么有:
$$
H(Y,P) = L(P) = - \sum_{x \in X} Y(x) \cdot \log P(x)
$$
具体含义和解释,详见52CAML交叉熵定义
Softmax交叉熵损失梯度 with Logits
注意:交叉熵损失函数对logits的梯度,而不是对softmax的梯度。
$$
\begin{align}
\frac {\partial L} {\partial a_i} &= - \sum_{k=1}^{K} y_k \cdot \frac{\partial \log(p_k)} {\partial a_i} = - \sum_{k=1}^{K} y_k \cdot \frac{\partial \log(p_k)} {\partial p_k} \cdot \frac{\partial p_k} {\partial a_i} \\\
&= - \sum_{k=1}^K y_k \frac{1}{p_k} \cdot \frac{\partial p_k} {\partial a_i} = - \sum_{k=1}^K y_k \frac{1}{p_k} \cdot \left(p_k (\delta_{ki} - p_i) \right) \\\
&= - \sum_{k=1}^K y_k (\delta_{ki} - p_i) = - y_i (1 - p_i) + \sum_{k \neq i} y_k p_i \\\
&= p_i \cdot \sum_{k=1}^K y_k - y_i = \mathbf{p_i - y_i}
\end{align}
$$
最后,针对分类问题,给定的结果$y_k$最终只会有一个类别是1,其他类别都是0,所以有$\sum_k y_k = 1$。所以基于Softmax函数的交叉熵损失梯度(对于logits $a_i$)表达式为:
$$
\mathbf{\frac{\partial L} {\partial a_i} = p_i - y_i}
$$
Normalization
参考:https://zhuanlan.zhihu.com/p/33173246
为什么需要Normalization
独立同分布与白化
机器学习最喜欢的数据特点莫过于“独立同分布”了,即Independent and Identically Distributed,简称IID。独立同步分并非所有机器学习模型的必然要求(比如Naive Bayes模型就建立在特征彼此独立的基础上,而LR和神经网络则在非独立的特征数据上依然可以训练出很好的模型),但独立同分布的数据可以简化常规机器学习模型的训练、提升机器学习模型的预测能力,已是一个共识。
因此,在把数据喂给机器学习模型之前,“白化(whitening)”是一个重要的数据预处理步骤。whitening一般包含两个目的:
- 去除特征之间的相关性$\rightarrow$独立;
- 使得所有特征具有相同的均值和方差$\rightarrow$同分布;
白化最典型的方法是PCA(主成分分析)。whitening的目的是获得独立同分布的数据,让模型更容易训练。
深度学习中的Internal Covariate Shift
深度学习网络模型的训练为什么比较困难?其中一个重要原因是:深度神经网络涉及多层的叠加,而每一层的参数更新会导致上一层的输入数据分布发生变化,通过层层叠加,高层的数据分布变化会非常剧烈,这就使得高层需要不断去重新适应底层的参数更新。为了训练好模型,我们需要非常谨慎的设定学习率、初始化权重以及尽可能细致的参数更新策略。
Google将这一现象总结为Internal Covariate Shift,简称ICS。
什么是ICS呢?
统计机器学习中的一个经典假设是“源空间(source domain)和目标空间(target domain)的数据分布(distribution)是一致的”。如果不一致,那么就出现了新的机器学习问题,如transfer learning/domain adaption等。而covariate shift就是分布不一致假设之下的一个分支问题,它是指源空间与目标空间的条件概率是一致的,但是边缘概率不同,即对于所有的$x \in \mathcal{X},有:$
$$
P_s(Y | X=x) = P_t(Y | X=x) \\ \quad P_s(X) \neq P_t(X)
$$的确,对于神经网络的各层输出,由于它们经过了层内操作作用,其分布显然与各层对应的输入信号分布不同,而且差异会随着网络深度增大而增大,可是它们所能指示的样本标记(label)仍然是不变的,这便符合了covariate shift的定义。由于是对各层间信号的分析,也即是“internal”的由来。
Internal Covariate Shift会导致什么问题?
深度神经网络,每个神经元的输入数据不再是“独立同分布”。具体表现在:
- 上层参数需要不断适应新的输入数据分布,降低学习速度;
- 下层输入的变化问题趋向于变大或变小,导致上层落入饱和区,使得学习过早停止;
- 每层的更新都会影响到其它层,因此每层的参数更新策略需要尽可能的谨慎。
Normalization的通用框架
这里我们以神经网络中的一个神经元为例,神经元接收一组输入向量$\mathbf{x}=(x_1, x_2, \cdots, x_d)$,通过中间运算后,输出一个标量值$y=f(\mathbf{x})$。
由于ICS问题的存在,$\mathbf{x}$的分布可能相差很大,要解决独立同分布的问题,“理论正确”的方法就是对每一层的数据都进行whitening操作。然而标准的白化操作代价很大,特别是我们还希望白化操作是可微的,保证白化操作可以通过反向传播来更新梯度。
因此,以Batch Normalization为代表的Normalization方法退而求其次,进行了简化的白化操作。基本思想是:在将$\mathbf{x}$送给神经元之前,先对其做平移和伸缩变换,将$\mathbf{x}$的分布规范化成在固定区间范围的标准分布。
通用变换框架如下所示:
$$
h = f \left( \mathbf{g} \cdot \frac{x-\mu}{\sigma} + \mathbf{b} \right)
$$
参数解释:
- $\mu$是平移参数(shift parameter),$\sigma$是缩放参数(scale parameter)。通过这两个参数进行shift和scale变换,得到的数据符合均值为0、方差为1的标准分布。
- $\mathbf{b}$是再平移参数(re-shift parameter),$\mathbf{g}$是再缩放参数(re-scale parameter)。将上一步得到的结果进一步变换,最终得到的数据符合均值为$\mathbf{b}$、方差为$\mathbf{g}^2$的分布。
第一步已经将x变成了标准分布,为什么第二步又变走了?答案是为了保证模型的表达能力不因规范化而下降。
我们可以看到,第一步的变换是将输入数据限制到了一个全局统一的确定范围(均值0,方差1)。下层神经元可能很努力的在学习,但不论其如何变化,其输出的结果在交给上层神经元进行处理之前,将被粗暴的重新调整到这一固定范围。
难道下层神经元在做无用功?
为了尊重底层神经网络的学习结果,我们将规范化后的数据进行再平移和再缩放,使得每个神经元对应的输入范围是针对该神经元量身定制的一个确定范围(均值为$\mathbf{b}$,方差为$\mathbf{g}^2$)。reshift和rescale的参数都是可以学习的,这就使得Normalization层可以学习如何去尊重下层的学习结果。
除了充分利用下层学习的能力,另一方面的重要意义在于保证获得非线性的表达能力。
经过这么变来变去,会不会跟没变一样?
不会。因为再变换引入的两个新参数$\mathbf{b}$和$\mathbf{g}$可以表示旧参数作为输入的同一族函数,但是新参数有不同的学习动态。在旧参数中,$\mathbf{x}$的均值取决于下层神经网络的复杂关联;但在新参数中,$\mathbf{y = g \cdot \hat{x} + b}$仅由$mathbf{b}$来决定,去除了与下层计算的密切耦合。新参数很容易通过梯度下降来学习,简化了神经网络的训练。
这里的Normalization离标准的白化还有多远?标准白化操作的目的是独立同分布。独立暂不考虑,变换为均值为$\mathbf{b}$、方差为$\mathbf{g}^2$的分布,并不是严格的同分布,只是映射到了一个确定的区间范围而已。
下面梳理下深度学习模型主流的Normalization方法。分别图示如下:
Batch Normalization
Batch Normalization是Google在2015年提出,开Normalization之先河。其规范化操作针对单个神经元进行,利用网络训练时一个batch的数据来计算该神经元$x_i$的均值和方差,因而称为BN。公式表示如下:
$$
\mu_i = \frac{1}{M} \sum x_i, \quad \sigma_i = \sqrt{\frac{1}{M} \sum(x_i - \mu_i)^2 + \epsilon} \qquad(M为\text{batch size})
$$
相对于一层神经元的水平排列,BN可以看作是一种纵向的规范化。由于BN是针对单个维度定义的,因此标准公式中的计算均为element wise的。
BN适合的场景:每个mini batch比较大,且batch间分布差距较小,数据分布比较接近。在训练之前,要做好充分的shuffle,否则效果会差很多。
BN不适合的场景:由于BN需要在运行的过程中统计每个batch的一阶和二阶统计量,因此不适用于动态神经网络和RNN网络。
Layer Normalization
与BN不同,LN是一种横向的规范化。它综合考虑一层所有维度的输入,计算该层的平均输入值和输入方差,然后用同一个规范化操作来转换各个维度的输入。公式表示为:
$$
\mu = \sum_i x_i, \quad \sigma = \sqrt{\sum_i (x_i - \mu)^2 + \epsilon}
$$
其中$i$表示一层所有神经元中第$i$个神经元。对应到通用框架中,四大参数$\mu, \sigma, \mathbf{g}, \mathbf{b}$均是标量(BN中是向量),所有输入共享一个规范化变换。
LN的适用场景:针对单个训练样本进行,不依赖其它数据,因此可以避免BN中受batch数据分布影响的问题,可以用于小batch的场景、动态神经网络和RNN,特别是NLP另一。此外,LN不需要保存batch的均值和方差,节省了额外的存储空间。
综合比较BN和LN:
- BN是针对单个神经元可训练的,不同神经元的输入经过再平移和再缩放后分布在不同的区间;
- LN对于一整层的神经元训练得到同一个转换,所有的输入都在同一个区间范围内。
如果不同输入特征不属于相似的特征,那么LN的处理可能会降低模型的表达能力。
Weight Normalization
BN和LN均将规范化应用于输入的特征数据$\mathbf{x}$,而WN则另辟蹊径,将规范化应用于线性变换函数的权重$w$,这就是WN名称的由来。
WN的方案是:将权重向量$\mathbf{w}$分别为向量方向$\mathbf{\hat{v}}$和向量模$\mathbf{g}$两部分,即$\mathbf{w} = g \cdot \hat{\mathbf{v}} = g \cdot \frac{\mathbf{v}} {||\mathbf{v}||}$。其中,$\mathbf{v}$是与$\mathbf{w}$同维度的向量,$||\mathbf{v}||$是欧式范数,$g$是标量决定了w的长度。由于$||\mathbf{w}|| \equiv |g|$,因此这一权重分解的方式将权重向量的欧式范数进行了固定,从而实现了正则化的效果。
WN的公式貌似脱离了前面讲的通用框架?其实并没有,从最终实现的效果来看,异曲同工。公式推导如下:
$$
\begin{align}
f_w(WN(\mathbf{x})) &= \mathbf{w} \cdot WN(\mathbf{x}) = g \cdot \frac{\mathbf{v}}{||\mathbf{v}||} \cdot \mathbf{x} \\\
&= \mathbf{v} \cdot g \cdot \frac{\mathbf{x}}{||\mathbf{v}||} = f_v(g \cdot \frac{\mathbf{x}}{||\mathbf{v}||})
\end{align}
$$
对照通用框架,WN只需令:$\sigma=||\mathbf{v}||, \mu=0, b=0$。
对比BN/LN与WN的区别:BN和LN是用输入的特征数据的方差进行scale(特征数据规范化),而WN则是用神经元权重的欧式范数对输入数据进行scale(权重规范化),本质上都上线了是对数据的规范化,只是用于scale的参数来源不同。
WN的规范化不直接使用输入数据的统计量,因此避免了BN过于依赖batch的不足,以及LN每层唯一转换器的限制,同时也可以用于动态网络结构。
另外,我们可以看到WN只是对数据做了scale,没有进行shift,因为我们简单的令$\mu=0$,但事实上,这里留下了与BN(或LN)相结合的余地,即利用BN(或LN)的方法来计算输入数据的均值$\mu$。
Cosine Normalization
我们先来看神经元的经典变换:$f_w(\mathbf{x}) = \mathbf{w} \cdot \mathbf{x}$。
对输入数据$\mathbf{x}$的变换有BN和LN;对模型参数$\mathbf{w}$的变换也已经做过了-WN。好像没啥好做的了。
然而,研究者们对中间的那个dot打起了“主意”,他们认为,之所以对数据进行规范化,是因为数据经过NN的计算之后可能会变得很大,导致数据分布的方差爆炸,而这一问题的根源是我们的计算方式-点积-权重向量$\mathbf{w}$和特征数据向量$\mathbf{x}$的点积。向量点积是无界的(unbounded)。
向量点积是衡量两个向量相似度的方法之一,为了保证有界,使用余弦夹角计算方式,于是Cosine Normalization就诞生了。线性变换函数如下:
$$
f_w(\mathbf{x}) = \cos (\theta) = \frac{\mathbf{w} \cdot \mathbf{x}} {||\mathbf{w}|| \cdot ||\mathbf{x}||}
$$
CN与WN时比较相似的,分子都是\mathbf{w}和\mathbf{x}的内积,CN则是在WN的基础上加上了输入向量的模$||\mathbf{x}||$对输入向量进行了进一步的scale。
Normalization为什么会有效
我们以一个简化的神经网络为例,解释Normalization为什么会有效?
神经网络结构表示为:$\text{x} \rightarrow FC_1 \rightarrow \text{wx} \rightarrow Norm(wx) \rightarrow FC_2 \rightarrow w_2 \cdot \text{Norm(wx)}$
- Normalization的权重伸缩不变性
权重伸缩不变性(weight scale invariance)指的是,当权重$w$按照常量$\lambda$进行伸缩时,得到的规范化后的值保持不变,即$Norm(W’x) = Norm(Wx)$,其中$W’ = \lambda W$。
该性质对上述N规范化方法均成立,因为当权重$W$伸缩时,对应的均值和标准差均等比例伸缩,分子分母相抵。
$$
\begin{align}
Norm(W’x) &= Norm \left(g \cdot \frac{W’x - \mu’}{\sigma’} + b \right) \\\
&= Norm \left(g \cdot \frac{\lambda Wx - \lambda \mu}{\lambda \sigma} + b \right) = Norm(Wx)
\end{align}
$$
伸缩权重不变性可以有效地提高反向传播的效率。 由于$\frac{\partial Norm(W’x)} {\partial x} = \frac{\partial Norm(Wx)} {\partial x}$,因此,权重的伸缩变化不会影响反向梯度的Jacobian矩阵,也就对反向传播没有影响,避免了反向传播时因为权重过大或过小导致的梯度消失或梯度爆炸问题,从而加速了神经网络的训练。(???需要进一步理解)
权重伸缩不变性还具有参数正则化的效果,可以使用更高的学习率。由于$\frac{\partial Norm(W’x)} {\partial W’} = \frac{1}{\lambda} \cdot \frac{\partial Norm(Wx)} {\partial W}$,因此,下层的权重值越大,其梯度值越小,这样参数的变化就越稳定,相当于实现了参数正则化的效果,避免参数的大幅震荡,提高网络的泛化性能。
- Normalization的数据伸缩不变性
数据伸缩不变性(data scale invariance)指的是,当数据$\mathbf{x}$按照常量$\lambda$进行伸缩时,得到的规范化后的值保持不变,即$Norm(Wx’) = Norm(Wx)$,其中$x’=\lambda x$。
数据伸缩不变性仅对BN、LN和CN成立。因为这三者对数据进行规范化,因此当数据进行常量伸缩时,其均值和方差都会相应变化,分子分母相互抵消。
数据伸缩不变性可以有效地减少梯度弥散,简化对学习率的选择。对于某一层神经元$h_l=f_{w_l}(x_l)$而言,展开可得
$$
h_l=f_{w_l}(x_l) = f_{w_l} \left( f_{w_{l-1}}(x_{l-1}) \right) = \cdots = x_0 \prod_{k=0}^{l} w_k
$$
每一层神经元的输出依赖于底下各层的计算结果。如果没有正则化,当下层发生伸缩变化时,经过层层传递,可能会出现数据发生剧烈的膨胀或弥散,从而导致了反向计算时的梯度爆炸或梯度弥散。
梯度弥散,又称梯度消失(vanishing gradient problem)。
- 梯度弥散:接近loss的layer梯度变化较大,远离loss的layer梯度变化越小,参数更新慢,几乎处于初始状态;
- 梯度爆炸:接近loss的layer梯度变化较小,远离loss的layer梯度指数级增大,最终超出了实数值范围,出现NaN;
加入Normalization后,不论底层的数据如何变化,对于某一层神经元$h_l = f_{w_l}(x_l)$而言,其输入$x_l$永远保持标准的分布,这就使得高层的训练更加简单。从梯度计算公式来看:
$$
\frac{\partial Norm(Wx’)} {\partial W} = \frac{\partial Norm(Wx)} {\partial W}
$$
数据的伸缩变化也不会影响到对该层的权重参数更新,使得训练过程更加鲁棒,简化了对学习率的选择。
本节参考资料: