初始化原因
具体的初始化原因可以关注这篇博客-浅谈深度学习初始化参数。
基本思想
基本思想是保持输入和输出的方差一致
,这样就避免了所有输出值都趋向于0。注意,为了问题的简便,其推导过程是基于线性函数的,但是它在一些非线性神经元中也很有效。
caffe 下的 xavier 实现
caffe
中,网络参数初始化通过从一个 0 均值
和特定方差
的分布(一般为正态分布
或均匀分布
)中获得:
Var
(
W
)
=
1
n
i
n
\operatorname{Var}(W)=\frac{1}{n_{\mathrm{in}}}
Var(W)=nin1
stddev
=
1
n
i
n
\text { stddev }=\frac{1}{\sqrt{n_{\mathrm{in}}}}
stddev =nin1
python
实现:
def initialize_parameters_he(layers_dims):
"""
Arguments:
layer_dims -- python array (list) containing the size of each layer.
Returns:
parameters -- python dictionary containing your parameters "W1", "b1", ..., "WL", "bL":
W1 -- weight matrix of shape (layers_dims[1], layers_dims[0])
b1 -- bias vector of shape (layers_dims[1], 1)
...
WL -- weight matrix of shape (layers_dims[L], layers_dims[L-1])
bL -- bias vector of shape (layers_dims[L], 1)
"""
np.random.seed(3)
parameters = {}
L = len(layers_dims) # integer representing the number of layers
for l in range(1, L):
parameters['W' + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1]) * np.sqrt(1 / layers_dims[l - 1])
parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))
return parameters
C语言
实现:
typedef struct {
int row, col;
float** element;
}Mat;
float gaussrand_NORMAL() {
float V1=0., V2=0., S=0.;
int phase = 0;
int count = 0;
float X;
if (phase == 0) {
while (count == 0 || (S >= 1 || S == 0)){
float U1 = (float)(rand() % 10000) / 10000.f;
float U2 = (float)(rand() % 10000) / 10000.f;
V1 = 2 * U1 - 1;
V2 = 2 * U2 - 1;
S = V1 * V1 + V2 * V2;
count += 1;
} ;
float temp_S_1 = log(S);
X = V1 * sqrt(-2 * temp_S_1 / S);
}
else
{
float temp_S_2 = log(S);
X = V2 * sqrt(-2 * temp_S_2 / S);
}
phase = 1 - phase;
return X;
}
float gaussrand(float mean, float stdc) {
return mean + gaussrand_NORMAL() * stdc;
}
Mat* MatInitXavier(Mat *src)
{
srand((unsigned int)time(NULL)); // set randon seed
int row, col;
//weight
for (row = 0; row < src->row; ++row){
for (col = 0; col < src->col; ++col){
(src->element[row])[col] = gaussrand(0.f, 0.1f) * sqrt(1.f/src->row); // mean stdc
}
}
//bias
for (row = 0; row < src->row; ++row){
(src->element[row])[0] = 0.f;
}
return src;
}
C语言
实现结果:
Glorot & Bengio xavier 实现
在 Glorot & Bengio’s 的文章(Understanding the difficulty of training deep feedforward neural networks)中,推荐的却是如下形式:
V a r ( W ) = 2 n i n + n o u t Var(W) = \frac{2}{n_{in}+n_{out}} Var(W)=nin+nout2
简单推导
n
个成分构成的输入向量 x
,经过一个随机矩阵为 w
的线性神经元,得到输出
y
=
w
x
=
w
1
x
1
+
w
2
x
2
+
…
+
w
n
x
n
\boldsymbol{y}=w \boldsymbol{x}=w_{1} x_{1}+w_{2} x_{2}+\ldots+w_{n} x_{n}
y=wx=w1x1+w2x2+…+wnxn
已知 x i x_i xi 是独立同分布的,且均值方差已知,此时求输出 y y y 的方差。
推导如下,由独立变量积的方差计算公式(Product of independent variables)可知,
Var
(
W
i
X
i
)
=
[
E
(
X
i
)
]
2
Var
(
W
i
)
+
[
E
(
W
i
)
]
2
Var
(
X
i
)
+
Var
(
X
i
)
Var
(
W
i
)
\operatorname{Var}\left(W_{i} X_{i}\right)=\left[E\left(X_{i}\right)\right]^{2} \operatorname{Var}\left(W_{i}\right)+\left[E\left(W_{i}\right)\right]^{2} \operatorname{Var}\left(X_{i}\right)+\operatorname{Var}\left(X_{i}\right) \operatorname{Var}\left(W_{i}\right)
Var(WiXi)=[E(Xi)]2Var(Wi)+[E(Wi)]2Var(Xi)+Var(Xi)Var(Wi)
又已对输入向量取均值,输入和权值矩阵均值均为 0,则:
Var
(
W
i
X
i
)
=
Var
(
X
i
)
Var
(
W
i
)
\operatorname{Var}\left(W_{i} X_{i}\right)=\operatorname{Var}\left(X_{i}\right) \operatorname{Var}\left(W_{i}\right)
Var(WiXi)=Var(Xi)Var(Wi)
所以进一步有:
Var
(
y
)
=
Var
(
∑
i
w
i
x
i
)
=
∑
i
Var
(
w
i
x
i
)
=
∑
i
Var
(
x
i
)
Var
(
w
i
)
=
n
Var
(
x
i
)
Var
(
w
i
)
\operatorname{Var}(\boldsymbol{y})=\operatorname{Var}\left(\sum_{i} w_{i} x_{i}\right)=\sum_{i} \operatorname{Var}\left(w_{i} x_{i}\right)=\sum_{i} \operatorname{Var}\left(x_{i}\right) \operatorname{Var}\left(w_{i}\right)=n \operatorname{Var}\left(x_{i}\right) \operatorname{Var}\left(w_{i}\right)
Var(y)=Var(i∑wixi)=i∑Var(wixi)=i∑Var(xi)Var(wi)=nVar(xi)Var(wi)
因此为使得,输出 y 与输入 x 具有相同的均值和方差,权值矩阵的方差则要求:
Var ( w i ) = 1 n = 1 n i n \operatorname{Var}\left(w_{i}\right)=\frac{1}{n}=\frac{1}{n_{\mathrm{in}}} Var(wi)=n1=nin1
这里的 n 指的是输入样本的维数,这即是 caffe 中关于 xavier 的实现。
Glorot & Bengio’s 论文中
,在基础上,还需考虑反向传播
时的情形,反向传播是正向传播的逆过程,此时的输入是前向传播的输出,则有:
Var
(
w
i
)
=
1
n
=
1
n
o
u
t
\operatorname{Var}\left(w_{i}\right)=\frac{1}{n}=\frac{1}{n_{\mathrm{out}}}
Var(wi)=n1=nout1
综合以下两点要求,则可得到满足以上两点要求的权值矩阵的方差为:
Var ( W i ) = 2 n i n + n o u t \operatorname{Var}\left(W_{i}\right)=\frac{2}{n_{\mathrm{in}}+n_{\mathrm{out}}} Var(Wi)=nin+nout2
注:这里的实现是只考虑正向传播。
C完整的实现代码,评论邮箱。