针对梯度消失或者梯度爆炸问题,我们想出了一个不完整的解决方案,虽然不能彻底解决问题,却很有用。有助于我们为神经网络更谨慎地选择随机初始化参数,为了更好地理解它,我们先举一个神经单元权重初始化的例子,然后再演变到整个神经网络。
来看只有一个神经元的情况,然后才是深度网络,如上图,单个神经元可能有4个输入特征,从
x
1
x_1
x1到
x
4
x_4
x4,经过
a
=
g
(
z
)
a=g(z)
a=g(z)处理,最终得到
y
^
\hat{y}
y^。 稍后讲深度网络时,这些输入表示为
a
[
l
]
a^{[l]}
a[l],暂时我们用
x
x
x表示,根据图,可知
z
=
w
1
x
1
+
w
2
x
2
+
.
.
.
+
w
n
x
n
z=w_1x_1+w_2x_2+...+w_nx_n
z=w1x1+w2x2+...+wnxn,
b
=
0
b=0
b=0,暂时忽略b。为了预防z值过大或者过小,你可以看到,n越大,我们希望
w
i
w_i
wi越小,因为z是
w
i
x
i
w_ix_i
wixi的和。如果你把很多此类项相加,希望每项值更小,最合理的方法就是设置
V
a
r
(
w
i
)
=
1
n
Var(w_i)=\frac{1}{n}
Var(wi)=n1,Var()代表方差,n表示神经元的输入特征数量,实际上你要做的就是设置某层权重矩阵
W
W
W等于
n
p
.
r
a
n
d
o
m
.
r
a
n
d
n
(
W
.
s
h
a
p
e
)
∗
n
p
.
s
q
r
t
(
1
n
[
l
−
1
]
)
np.random.randn(W.shape)*np.sqrt(\frac{1}{n^{[l-1]}})
np.random.randn(W.shape)∗np.sqrt(n[l−1]1)结果如果你使用的是Relu激活函数而不是
1
n
\frac{1}{n}
n1,方差
V
a
r
(
w
i
)
Var(w_i)
Var(wi)设置为
V
a
r
(
w
i
)
=
2
n
Var(w_i)=\frac{2}{n}
Var(wi)=n2效果会更好。
初始化时,尤其hi使用Relu激活函数时, g [ l ] ( z ) = R e l u ( z ) g^{[l]}(z)=Relu(z) g[l](z)=Relu(z),他取决于你对随机变量的熟悉程度,这是高斯随机变量,然后乘于它的平方根,也就是引用方差 V a r ( w i ) Var(w_i) Var(wi),方差公式中使用 n [ l − 1 ] n^{[l-1]} n[l−1]是因为这个例子中特征是不变的,但一般情况下,l层上的每个神经元都有 n [ l − 1 ] n^{[l-1]} n[l−1]个输入。如果激活函数的输入特征被零均值,标准方差为1,z也会调整到相似的范围,这就没解决问题,但它确实降低了梯度消失和梯度爆炸的问题,因为它给权重矩阵W设置了合理值,你也知道,他不能比1大很多,也不能比1小很多,所以梯度没有爆炸或者消失过快。
刚刚提到的函数是Relu激活函数,对于其它激活函数,如Tanh激活函数,常数1比常数2更有用,即 n p . s q r t ( 1 n [ l − 1 ] ) np.sqrt(\frac{1}{n^{[l-1]}}) np.sqrt(n[l−1]1) ,同时还有其它的公式,如 n p . s q r t ( 2 n [ l − 1 ] + n [ l ] ) np.sqrt(\frac{2}{n^{[l-1]}+n^{[l]}}) np.sqrt(n[l−1]+n[l]2)。
实际上,所有这些公式只是给你一个起点,它们给出初始化权重矩阵的方差的默认值,如果你想添加方差,方差参数则是另一个你需要调整的超级参数,可以给公式 n p . s q r t ( 2 n [ l − 1 ] ) np.sqrt(\frac{2}{n^{[l-1]}}) np.sqrt(n[l−1]2)添加一个乘数参数。有时候调优该超参数的效果一般,这并不是我们想调优的首要超参数,但已经发现调优过程中产生的问题,虽然调优该参数能起到一定作用,但考虑到相比调优其它超级参数的重要性,通常把这个超参数的优先级放的比较低。
希望可以对梯度下降或者梯度消失以及如何为权重矩阵初始化合理值有了一个直观认识,希望你设置的权重矩阵,既不会增长过快,也不会太快下降到0,从而训练出一个权重或梯度不会增长或消失过快的深度网络。我们在训练深度网络时,这也是加快训练速度的技巧。