4.5 层数比较深的网络训练
4.5.1 监督性区分性分层训练
比如训练一个20层的网络,直接去训练难以收敛,此时可以这么做
- 先用部分数据训练前7层,但是要加上一层到输出的线性变换层。
- 训练完后,去掉最后一层线性变换层,加入后7层和新的一层到输出的线性变换,去训练这个14层的网络,此时这14层的网络都做了梯度更新
- 加入后6层进行新的训练
- 在经历以上步骤后,就有了一个20层的初始网络,在这个初始网络的权重基础上正常进行全量数据的训练
4.5.2 加入残差结构
输入
x
x
x在经过三个神经网络block之后,得到输出
y
1
y_1
y1, 然后我们把输出
y
1
y_1
y1加上输入残差
x
x
x,有
y
1
=
f
(
x
)
y
2
=
y
1
+
x
=
f
(
x
)
+
x
\begin{array}{l} y_1=f(x) \\ y_2=y_1+x=f(x)+x \end{array}
y1=f(x)y2=y1+x=f(x)+x
如果损失函数对输入
x
x
x求导【对应上一讲中的
∂
J
∂
h
L
=
∂
J
∂
Z
L
d
Z
L
d
h
L
\dfrac{\partial J}{\partial h_{L}}=\dfrac{\partial J}{\partial Z_{L}} \dfrac{d Z_{L}}{d h_{L}}
∂hL∂J=∂ZL∂JdhLdZL】,我们有
∂
J
∂
x
=
(
∂
J
∂
y
2
)
(
∂
y
2
∂
x
)
=
(
∂
J
∂
y
2
)
(
f
′
(
x
)
+
1
)
=
f
′
(
x
)
∂
J
∂
y
2
+
∂
J
∂
y
2
\frac{\partial J}{\partial x}=\left(\frac{\partial J}{\partial y_2}\right)\left(\frac{\partial y_2}{\partial x}\right)=\left(\frac{\partial J}{\partial y_2}\right)\left(f^{\prime}(x)+1\right)=f^{\prime}(x) \frac{\partial J}{\partial y_2}+\frac{\partial J}{\partial y_2}
∂x∂J=(∂y2∂J)(∂x∂y2)=(∂y2∂J)(f′(x)+1)=f′(x)∂y2∂J+∂y2∂J
在不加残差前,那么就只有 f ′ ( x ) ∂ J ∂ y 2 f^{\prime}(x) \dfrac{\partial J}{\partial y_2} f′(x)∂y2∂J, 如果 f ′ ( x ) ≪ 1 f^{\prime}(x)\ll1 f′(x)≪1,那么整个梯度就几乎消失。
在加了残差之后,显然梯度 ( ∂ J ∂ y 2 ) ( f ′ ( x ) + 1 ) \left(\frac{\partial J}{\partial y_2}\right)\left(f^{\prime}(x)+1\right) (∂y2∂J)(f′(x)+1)就不会消失,因为 f ′ ( x ) + 1 > 1 f^{\prime}(x)+1 > 1 f′(x)+1>1。
4.5.3 中间加入损失函数
通过分流出来的线性分类层,我们可以多出一个损失函数,用分流出来的损失函数对输入求梯度,就可以得到一个相对距离较近,没有消失的梯度
4.5.4 非线性激活函数尽量不要用sigmoid,尽量用relu
对这两个函数分别有
y
=
relu
(
x
)
=
{
x
x
>
0
0
x
<
0
∂
J
∂
x
=
∂
J
∂
y
d
y
d
x
=
{
∂
J
∂
y
,
x
>
0
0
,
x
<
0
y
=
sigmoid
(
x
)
∂
J
∂
x
=
∂
J
∂
y
d
y
d
x
=
∂
J
∂
y
y
(
1
−
y
)
\begin{array}{l} y=\operatorname{relu}(x)=\left\{\begin{array}{ll} x & x > 0 \\ 0 & x<0 \end{array}\right. \\ \dfrac{\partial J}{\partial x}=\dfrac{\partial J}{\partial y} \dfrac{d y}{d x}=\left\{\begin{array}{c} \dfrac{\partial J}{\partial y}, & x > 0 \\ 0, & x<0 \end{array}\right. \\ y=\operatorname{sigmoid}(x) \\ \dfrac{\partial J}{\partial x}=\dfrac{\partial J}{\partial y} \dfrac{d y}{d x}=\dfrac{\partial J}{\partial y} y(1-y) \end{array}
y=relu(x)={x0x>0x<0∂x∂J=∂y∂Jdxdy=⎩⎨⎧∂y∂J,0,x>0x<0y=sigmoid(x)∂x∂J=∂y∂Jdxdy=∂y∂Jy(1−y)
显然,relu条件下的梯度在输入大于0的时候回保证有一个较大的梯度值,但是在sigmoid条件下,梯度就取决于y的值。如果我们把
y
(
1
−
y
)
y(1-y)
y(1−y)作为二次函数画出来,可以看到
y
(
1
−
y
)
y(1-y)
y(1−y)的最大值也不过
1
/
4
1/4
1/4, 而且很多时候会偏移到两边接近0的区域。
4.5.4 svd分解在前馈神经网络中的应用:加速以及减少参数
在上图中,我们首先由两层全连接的隐藏层,
w
w
w参数数量是
2048
×
2048
2048\times 2048
2048×2048. 我们可以通过增加一层维度小的中间层来做’svd’:
w
1
=
2048
×
512
,
w
2
=
512
×
2048
w_1=2048\times 512, w_2=512\times 2048
w1=2048×512,w2=512×2048, 这样总的参数数量就是
2048
×
1024
2048\times1024
2048×1024,比原来的数量少了整整一半!矩阵操作就变为
w
2
w
1
x
=
w
1
x
′
w_{2}w_{1}x = w_1 x^{\prime}
w2w1x=w1x′
因此训练步骤就变为
- 初始化训练原始网络
- 在原始网络中间加入中间层,做svd分解,可以灵活配置每一层,简单有效,最常用的加速方法。
- 然后对新的网络再做fine tuning.
【注意:权重矩阵分解中间,也就是中间层不用加relu】
【svd: A m × n = U m × m ν m × n V n × n ≈ U m × k ν k × k V k × n = U ˉ m × k V k × m ( k ≪ m , n ) A_{m\times n}=U_{m\times m}\nu_{m\times n} V_{n\times n} \approx U_{m\times k}\nu_{k\times k} V_{k\times n} = \bar{U}_{m\times k}V_{k\times m} (k \ll m, n) Am×n=Um×mνm×nVn×n≈Um×kνk×kVk×n=Uˉm×kVk×m(k≪m,n)】
4.5.5 特征降噪、变换
神经网络也可以作为自编码器做非监督学习
- 特征变换,降维度
假设我们把x输入放入一个神经层进行训练,输出维度与输入维度相同( x ⇔ y x\Leftrightarrow y x⇔y), 通过损失函数 J = ∥ y − x ∥ J=\|y-x\| J=∥y−x∥我们可以得到一个维度降低的特征 x ˉ \bar{x} xˉ。也就是self-encoder
- 特征降噪
同样是上图,我们如果在输入中加入噪声 x + Δ x x+\Delta x x+Δx,再进行训练,而输出的损失函数依然是 J = ∥ y − x ∥ J=\|y-x\| J=∥y−x∥,我们就能够让隐藏层学到如何去除噪声 Δ x \Delta x Δx。