我正在阅读一本有关深度学习的书,该书将两层神经元之间的权重初始化为:
w = np.random.randn(layers[i] + 1, layers[i + 1] + 1)
self.W.append(w / np.sqrt(layers[i]))
根据这本书,由于以下原因,在第二行代码中用np.sqrt(layers [i])进行了除法:
通过除以当前层中节点数的平方根来缩放w 归一化每个神经元输出的差异
这到底是什么意思?如果我们不这样做,会产生什么影响?
答案 0 :(得分:0)
权重初始化对于解决消失/爆炸梯度非常重要。为了使输出/渐变(反向)正常流动,每层输出的方差等于其输入方差。反向的梯度也是如此。一层的输入和输出流称为该层的 fan-in 和 fan-out 。
为了更好地解释我的意思,让我举一个例子。假设我们有一百个连续的层,并且我们应用了具有线性激活的前馈计算(毕竟这只是矩阵乘法),数据是100个特征的500个样本:
neurons, features = 100, 100
n_layers = 100
X = np.random.normal(size=(500, features)) # your input
mean, var = 0, 0
for layer in range(n_layers):
W = np.random.normal(size=(features, neurons))
X = np.dot(X, W)
mean = mean + X.mean()
var = var + X.var()
mean/n_layers, np.sqrt(var/n_layers)
# output:
(-4.055498760574568e+95, 8.424477240271639e+98)
您将看到它将具有巨大的平均值和标准差。让我们分解这个问题;矩阵乘法的一个属性,其结果的标准偏差将非常接近(输入)连接中 fan 个的平方根。可以使用以下代码段验证此属性:
fan_in = 1000 # change it to any number
X = np.random.normal(size=(100, fan_in))
W = np.random.normal(size=(fan_in, 1))
np.dot(X, W).std()
# result:
32.764359213560454
之所以发生这种情况,是因为我们将输入X的一个元素与W的一列进行元素乘积的fan_in(在上述情况下为1000)乘积。因此,如果我们按 1 / sqrt缩放每个权重(fan_in)来保持流的分布,如以下代码片段所示:
neurons, features = 100, 100
n_layers = 100
X = np.random.normal(size=(500, features)) # your input
mean, var = 0, 0
for layer in range(n_layers):
W = np.random.normal(size=(features, neurons), scale=np.sqrt(1 / neurons)) # scaled the weights with the fan-in
X = np.dot(X, W)
mean = mean + X.mean()
var = var + X.var()
mean/n_layers, np.sqrt(var/n_layers)
# output:
(0.0002608301398189543, 1.021452570914829)
您可以在以下blog
中阅读有关内核初始化的更多信息。