Xavier initialization 理解与实现(python 与 C)

初始化原因

具体的初始化原因可以关注这篇博客-浅谈深度学习初始化参数

基本思想

基本思想是保持输入和输出的方差一致,这样就避免了所有输出值都趋向于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 =nin 1

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(iwixi)=iVar(wixi)=iVar(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完整的实现代码,评论邮箱。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TransientYear

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值