神经网络中权重的初始值如何设定?

为了使模型具有更好的表现力,往往需要各层的激活值的分布都要求有适当的广度。为什么呢?因为通过在各层间传递多样性的数据,神经网络可以进行高效的学习。反过来想,如果有多个神经元都输出几乎相同的值,那他们就没有存在的意义了。比如,如果100个神经元都输出几乎相同的值,那么也可以由1个神经元来表达基本相同的事情。因此,激活值在分布上有所偏向会出现“表现力受限”的问题。


这里我们通过一个实验,观察权重初始值对隐藏层激活值分布的影响。具体做法是准备一个5层的神经网络,用直方图绘制各层激活值的数据分布。

  • 权重初始值使用标准差为1的高斯分布。(w = np.random.randn() * 1)
import numpy as np
import matplotlib.pyplot as plt


def sigmod(x):
    return 1 / (1 + np.exp(-x))


x = np.random.randn(1000, 100)  # 生成1000个数据
hidden_node_num = 100  # 隐藏层的节点数
hidden_layer_size = 5  # 隐藏层的层数
activations = {}       # 存放激活函数的值

for i in range(hidden_layer_size):
    if i != 0:
        x = activations[i-1]

    w = np.random.randn(hidden_node_num, hidden_node_num) * 1
    z = np.dot(x, w)
    a = sigmod(z)
    activations[i] = a

for i, a in activations.items():
    plt.subplot(1, len(activations), i+1)
    plt.title(str(i+1) + "-layer")
    plt.hist(a.flatten(), range=(0, 1))  # 绘制直方图

plt.show()

运行这段代码,得到下面的直方图:

可以看出各层的激活值往往分布在0和1附近。由于sigmod函数是S型函数,随着输出不断地靠近0或1,它的到数值逐渐接近0。因此,偏向0和1的数据分布会造成反向传播中梯度的值不断变小,最后消失。这个问题称为“梯度消失”(gradient vanishing)。

  • 将权重初始值使用标准差为0.01的高斯分布,其余代码不变。(w = np.random.randn() * 0.01)

运行后,得到下面的直方图:

可以发现数据集中在0.5附近。这就是之前所说的,激活值在分布上有所偏向会出现“表现力受限”的问题。


1. Xavier初始值(sigmod、tanh等S型曲线的权重初始值)

Xavier等人发现,为了使各层的激活值呈现出具有相同广度的分布,推导了合适的权重尺度。推导出的结论是,如果前一层的节点数为n,则初始值使用标准差为\frac{1}{\sqrt{n}}的分布。

所以将权重初始值的代码改为

    w = np.random.randn(hidden_node_num, hidden_node_num) / np.sqrt(hidden_node_num)

运行后,得到下面的直方图:

从这个结果可知,越是后面的层,分布就变得越有所偏向,但是呈现了比之前更有广度的分布,所以sigmod函数的表现力不受限制,可以进行高效的学习。实际上,tanh函数使用xavier的权重初始值的分布会更好。

2. He初始值(ReLU的权重初始值)

当前一层的节点数为n时,He初始值使用标准差为\sqrt{\frac{2}{n}}的高斯分布。

现在来看一下激活函数使用ReLU时激活值的分布。

import numpy as np
import matplotlib.pyplot as plt


def sigmod(x):
    return 1 / (1 + np.exp(-x))


def relu(x):
    mask = (x <= 0)
    out = x.copy()
    out[mask] = 0
    return out



x = np.random.randn(1000, 100)  # 生成1000个数据
hidden_node_num = 100  # 隐藏层的节点数
hidden_layer_size = 5  # 隐藏层的层数
activations = {}       # 存放激活函数的值

for i in range(hidden_layer_size):
    if i != 0:
        x = activations[i-1]

    w = np.random.randn(hidden_node_num, hidden_node_num) * np.sqrt(2 / hidden_node_num)
    z = np.dot(x, w)
    a = relu(z)
    activations[i] = a

for i, a in activations.items():
    plt.subplot(1, len(activations), i+1)
    plt.title(str(i+1) + "-layer")
    plt.hist(a.flatten(), range=(0, 1))  # 绘制直方图

plt.show()

运行:

可以发现,当激活函数使用ReLU时,各层中分布的广度相同。由于即便层加深,数据的广度也能保持不变,因此逆向传播时,也会传递合适的值。


总结一下,当激活函数为sigmod或tanh等S型曲线函数时,初始值使用Xavier初始值,当激活函数使用ReLU时,权重初始值使用He初始值。

 

 

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值