我们在创建深度神经网络时,通常要对网络的权重初始化,而在dl4j中大概有如下权重类型(枚举型):
DISTRIBUTION,ZERO,SIGMOID_UNIFORM,UNIFORM,XAVIER,XAVIER_UNIFORM,XAVIER_FAN_IN,XAVIER_LEGACY,RELU,RELU_UNIFORM;
接下来我会对这些类型做进一步说明(其中可能会引用一些其他杂志或论文的图片,如果涉及侵权,请及时联系本人,谢谢)
为什么要进行权重初始化:(数学符合这个编辑器无法打出来,直接写文字)权重w,输入x,偏置b
简单来说根据公式有 f=sum(xi*wi)+b,计算出的f,而f有可能是一个远小于-1或者远大于1的数,通过激活函数(比如sigmoid)后所得到的输出会非常接近0或者1,也就是隐藏层神经元处于饱和的状态。为了避免这种情况,我们应该调整权重大小,而这种改变会影响f值,使f值接近于0,进而会影响激活值。
图-1
如果激活函数是这个f(t)=sigmoid(t),那么可以看到,当f是一个远小于-1或者远大于1的数,那么通过激活函数计算出的值将会非常接近于0或者1,这样造成了什么严重后果呐,从图中我们可以看到梯度消失了,非常接近于0了,既然如此,那么nn只能两眼发呆,啥也学不到。
如何进行权重初始化:
综上,初始化weight是非常重要的,容不得半点马虎,我们必须保证权重初始化在一个合理的范围。或者说为了让f接近于值0,使神经元处于不太饱和状态,我们需要赋予它一个合适的值。当然,大多数情况下我们需要根据不同的激活函数初始化不同的权重类型。对于许多人来说,我们在构建满足自己业务需求的nn时,有个疑问?到底哪一个权重是适合的?一种通用的方式就是选用高斯分布(正太分布)权重。还是说说具体的吧,比如在dl4j的权重初始化大概有以下几类。
(一)DISTRIBUTION:
ret = dist.sample(shape);
Sample weights from a provided distribution
给定分布的样例权重
很明显高斯分布或者正太分布将趋向0均值和有限的方差
(二)RELU:
ret = Nd4j.randn(order, shape).muli(FastMath.sqrt(2.0 / fanIn)); //N(0, 2/nIn)
He et al. (2015), "Delving Deep into Rectifiers". Normal distribution with variance 2.0/nIn
(三)RELU_UNIFORM:
double u = Math.sqrt(6.0 / fanIn);
ret = Nd4j.rand(shape, Nd4j.getDistributions().createUniform(-u, u)); //U(-sqrt(6/fanIn), sqrt(6/fanIn)
He et al. (2015), "Delving Deep into Rectifiers". Uniform distribution U(-s,s) with s = sqrt(6/fanIn)
(四)SIGMOID_UNIFORM:
double r = 4.0 * Math.sqrt(6.0 / (fanIn + fanOut));
ret = Nd4j.rand(shape, Nd4j.getDistributions().createUniform(-r, r));
A version of XAVIER_UNIFORM for sigmoid activation functions. U(-r,r) with r=4*sqrt(6/(fanIn + fanOut))
(五)UNIFORM:
double a = 1.0 / Math.sqrt(fanIn);
ret = Nd4j.rand(shape, Nd4j.getDistributions().createUniform(-a, a));
Uniform U[-a,a] with a=1/sqrt(fanIn). "Commonly used heuristic" as per Glorot and Bengio 2010
(六)XAVIER:
ret = Nd4j.randn(order, shape).muli(FastMath.sqrt(2.0 / (fanIn + fanOut)));
As per Glorot and Bengio 2010: Gaussian distribution with mean 0, variance 2.0/(fanIn + fanOut)
如何执行xavier初始化?
如果我们想让通过nn的每一个layer的方差相同,我们就必须计算y的方差,也就是输入值f的方差
var(y) = var(w1x1 + w2x2 + ... + wNxN + b)
我们计算上面等式右边的方差,如果考虑通用术语,那么进一步我们会有如下公式:
var(wixi) = E(xi)2var(wi) + E(wi)2var(xi) + var(wi)var(xi)
这里E()代表给定变量的期望值,一般来说就是表示平均值,我们假定输入值x和权重w来自0均值方差的高斯分布,于是E()可以取消,公式更变如下:(0均值就是样本的数学期望是0)
var(wixi) = var(wi)var(xi)
注意b是一个静态变量,且是一个0方差,所以b在这里可以不写,我们替代原始的等式,则如下显示
var(y) = var(w1)var(x1) + ... + var(wN)var(xN)
由于它们有相同的分布,所以公式继续可以写为:
var(y) = N * var(wi) * var(xi)
如果我们想让y的方差和x的方差相等,那么术语中N * var(wi)应当等于1,于是有如下公式:
N * var(wi) = 1
var(wi) = 1/N
var(wi) = 1/Navg
where Navg = (Nin + Nout)/2
参考论文:http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf
(七)XAVIER_UNIFORM:
double s = Math.sqrt(6.0) / Math.sqrt(fanIn + fanOut);
ret = Nd4j.rand(shape, Nd4j.getDistributions().createUniform(-s, s));
As per Glorot and Bengio 2010: Uniform distribution U(-s,s) with s = sqrt(6/(fanIn + fanOut))
(八)XAVIER_FAN_IN:
ret = Nd4j.randn(order, shape).divi(FastMath.sqrt(fanIn));
Similar to Xavier, but 1/fanIn -> Caffe originally used this.
(九)XAVIER_LEGACY:
ret = Nd4j.randn(order, shape).divi(FastMath.sqrt(shape[0] + shape[1]));
Xavier weight init in DL4J up to 0.6.0. XAVIER should be preferred.
(十)ZERO:
ret = Nd4j.create(shape, order);
Generate weights as zeros