原创

深度学习入门06---权重初始值


在神经网络的学习中,权重的初始值特别重要。实际上,设定什么样的权重初始值,经常关系到神经网络的学习能否成功。

1.权重初始值可以为0吗

在此之前,我们使用的初始值都是 【0.01*np.random.randn(10,100)】这样标准差为0.01的高斯分布。如果把权重初始值设置为0,那么神经网络可能将无法进行学习。严格地说,权重初始化不能设置成一样的值,这是因为在反向误差传播中,所有权重都会进行相同的更新。比如:2层神经网络中,假设第1层和第2层的权重为0.那么,正向传播时,因为输入层权重为0,所以第2层的神经元全部会被传递相同的值。第2层神经元中全部输入相同的值,意味着反向传播时,第2层权重全部都会进行相同的更新。因此,权重被更新为相同的值,并且拥有了对称的值。这使得神经网络有许多不同的权重的意义丧失。为了防止“均值归一化”(为了瓦解权重的对称结构),必须随机生成初始值。

2.隐藏层的激活值分布

观察隐藏层的激活值分布,看看初始值权重是如何影响隐藏层的激活值分布的。这里,我们利用一个5层神经网络(激活函数:sigmoid函数)传入随机生成的输入数据,用直方图描绘各层的激活值数据分布情况。

import numpy as np
import matplotlib.pyplot as plt

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

input_data = np.random.randn(1000, 100)  # 1000个数据
node_num = 100  # 各隐藏层的节点(神经元)数
hidden_layer_size = 5  # 隐藏层有5层
activations = {}  # 激活值的结果保存在这里

x = input_data

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

    # 使用标准差为1的高斯分布作为权重
    w = np.random.randn(node_num, node_num) * 1
    a = np.dot(x, w)

    # 将激活函数的种类也改变,来进行实验!
    z = sigmoid(a)

    activations[i] = z

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

avatar

【说明】:各层的激活值呈现偏向0、1的分布。这里使用的sigmoid函数是S型函数,随着输出的不断靠近0(或者1),它的导数的值逐渐接近0.因此,偏向0、1数据分布会造成反向传播中梯度的值不断减小,最后消失。这个问题被人称为**“梯度消失”**,层次加深的深度学习中,梯度消失的问题可能会更加严重。

下面,我们将权重初始值设置为:标准差为0.01的高斯分布,进行相同的实验:

#w = np.random.randn(node_num, node_num) * 1
w = np.random.randn(node_num, node_num) * 0.01

avatar

【说明】:这次呈集中在0.5附近的分布,因为不像刚刚那样偏向0、1,所以不会发生梯度消失的问题。但是,激活值的分布有所偏向,说明在表现力上会有很大的问题。这是因为,如果多个神经元都输出几乎相同的值,那么它们就没有存在的意义了,100个神经元输出相同的值,完全可以由1个神经元来替代。因此,激活值在分布上有所偏向会出现“表现力受限”的问题。因此,在学习过程中我们要保证激活值的分布适当的广,让各层传递多样性数据,神经网络可以进行高效的学习。

根据Xavier的论文中,为了使各层的激活值呈现出具有相同广度的分布,推导出了合适的权重尺度:如果前一层的节点数为n,那么初始值使用标准差为 np.sqrt(1.0 / n) 的分布。

avatar

w = np.random.randn(node_num, node_num) * np.sqrt(1.0 / node_num)

avatar

【说明】:使用Xavier初始值后,前一层节点数越多,要设定为目标节点的初始值的权重尺度就越小。后面的层图像变得越来越歪斜,但是呈现了比之前更加广的分布。因为,各层间传递的数据有适当的广度,所以sigmoid函数表现力不受限制,有望进行高效的学习。

如果将sigmoid函数替换成tanh函数(都是S型曲线型函数,但是tanh是关于原点对称的,而sigmoid是关于(0,0.5)对称),稍微歪斜的问题就会得到改善。

def tanh(x):
    return np.tanh(x)

# z = sigmoid(a)
z = tanh(a)

avatar

3.ReLU的权重初始值

Xavier初始值是以激活函数是线性函数为前提推导出来的。因为sigmoid与tanh左右对称,且中央附近可以视为线性函数,所以适合使用Xavier初始值。但是,当面对ReLU这样非线性激活函数时,就不能再使用Xavier初始值,而是换成“He初始值”。当前一层的节点数为n时,He初始值使用标准差为 np.sqrt(2.0 / n)的高斯分布。当Xavier初始值是 np.sqrt(1.0 / n)时,可以解释为,因为ReLU的负值区域的值为0,为了使它更有广度,所以需要2倍的系数。

import numpy as np
import matplotlib.pyplot as plt

def ReLU(x):
    return np.maximum(0, x)

input_data = np.random.randn(1000, 100)  # 1000个数据
node_num = 100  # 各隐藏层的节点(神经元)数
hidden_layer_size = 5  # 隐藏层有5层
activations = {}  # 激活值的结果保存在这里

x = input_data

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

    # 改变初始值进行实验!
    # w = np.random.randn(node_num, node_num) * 0.01
    # w = np.random.randn(node_num, node_num) * np.sqrt(1.0 / node_num)
    w = np.random.randn(node_num, node_num) * np.sqrt(2.0 / node_num)

    a = np.dot(x, w)!
    z = ReLU(a)

    activations[i] = z

# 绘制直方图
for i, a in activations.items():
    plt.subplot(1, len(activations), i+1)
    plt.title(str(i+1) + "-layer")
    if i != 0: plt.yticks([], [])
    plt.xlim(0.1, 1)
    plt.ylim(0, 7000)
    plt.hist(a.flatten(), 30, range=(0,1))
plt.show()

avatar avatar avatar

【说明】:上图依次代表初始值为:标准差为0.01的高斯分布、Xavier初始值、He初始值所对应的神经网络各层激活值的分布图像。目前,激活函数使用ReLU时,使用He初始值;激活函数使用sigmoid或tanh等S型曲线函数时,使用Xavier初始值比较好。

4.基于MINIST数据集的权重初始值的比较

神经网络有5层,每层100个神经元,激活函数使用ReLU:

import numpy as np
import matplotlib.pyplot as plt
from Deep_Learning_From_Scratch.dataset.mnist import load_mnist
from Deep_Learning_From_Scratch.common.util import smooth_curve
from Deep_Learning_From_Scratch.common.multi_layer_net import MultiLayerNet
from Deep_Learning_From_Scratch.common.optimizer import SGD

# 0:===============================读入MNIST数据===============================
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)

train_size = x_train.shape[0]
batch_size = 128
max_iterations = 2000

# 1:============================进行实验的设置============================
weight_init_types = {'std=0.01': 0.01, 'Xavier': 'sigmoid', 'He': 'relu'}
optimizer = SGD(lr=0.01)

networks = {}
train_loss = {}
for key, weight_type in weight_init_types.items():
    networks[key] = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100],
                                  output_size=10, weight_init_std=weight_type)
    train_loss[key] = []

# 2:===============================开始训练===============================
for i in range(max_iterations):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]
    
    for key in weight_init_types.keys():
        grads = networks[key].gradient(x_batch, t_batch)
        optimizer.update(networks[key].params, grads)
    
        loss = networks[key].loss(x_batch, t_batch)
        train_loss[key].append(loss)
    
    if i % 100 == 0:
        print("===========" + "iteration:" + str(i) + "===========")
        for key in weight_init_types.keys():
            loss = networks[key].loss(x_batch, t_batch)
            print(key + ":" + str(loss))

# 3.===============================绘制图形===============================
markers = {'std=0.01': 'o', 'Xavier': 's', 'He': 'D'}
x = np.arange(max_iterations)
for key in weight_init_types.keys():
    plt.plot(x, smooth_curve(train_loss[key]), marker=markers[key], markevery=100, label=key)
plt.xlabel("iterations")
plt.ylabel("loss")
plt.ylim(0, 2.5)
plt.legend()
plt.show()

【最后几轮输出的结果】:

===========iteration:1700===========
std=0.01:2.298198439563669
He:0.19434636746048634
Xavier:0.28333386536516436
===========iteration:1800===========
std=0.01:2.3020314622408478
He:0.16930605269839896
Xavier:0.29410226096966463
===========iteration:1900===========
std=0.01:2.2924850352663366
He:0.11283947983831456
Xavier:0.17132804367962812

avatar

【说明】:std=0.01时,完全无法学习,和刚刚讨论的情况一样,这是因为正向传播中传递的值很小(集中在0附近),因此反向传播求得的梯度也很小,权重几乎不进行更新。相反,当权重初始值设置为Xavier、He初始值时,学习进行的很顺利。

Python
深度学习
神经网络
机器学习
  • 作者:李延松(联系作者)
  • 发表时间:2020-08-06 10:04
  • 版本声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 公众号转载:请在文末添加作者公众号二维码

评论

留言