权重的初始值

①权重的初始值十分重要,关系到神经网络的学习是否成功。

可以将权重初始值设置为0吗

为了抑制过拟合、提高泛化能力,采用权值衰减的方法,它是一种以减小权重参数的值为目的进行学习的方法。
在误差反向传播法中,所有的权重值都会进行相同的更新。比如,在2层神经网络中,假设第1层和第2层的权重为0。这样一来,正向传播时,因为输入层的权重为0,所以第2层的神经元全部会被传递相同的值。第2层的神经元中全部输入相同的值,这意味着反向传播时第2层的权重全部都会进行相同的更新。
简单的说,权重无法更新为新的值因此在初始化的时候必须随机生成初始值。

隐藏层的激活值分布

观察隐藏层的激活值(激活函数的输出数据)的分布,了解权重的初始值是如何影响隐藏层的激活值的分布。

向一个5层神经网络(激活函数使用sigmoid函数)传入随机生产的输入数据,绘制各层激活值的数据分布。

import numpy as np
import matplotlib.pyplot as plt

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

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

def tanh(x):
    return np.tanh(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) * 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 = sigmoid(a)
    # z = ReLU(a)
    # z = tanh(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()

神经网络 权重更新公式 神经网络 权重衰减_神经网络 权重更新公式


这次使用的是标准差为1的高斯分布,但实验的目的是通过改变这个尺度(标准差),观察激活值的分布如何变化。

可以看到,各层的激活值偏向0和1分布,这里使用的是sigmoid激活函数,当输入和输出不断靠近0或者1时,它的导数的值逐渐减小接近于0,偏向0和1的数据分布会造成反向传播中的梯度值不断减小。这个问题称为 梯度消失

当权重的标准差设置为0.1时

w = np.random.randn(node_num, node_num) * 0.1

神经网络 权重更新公式 神经网络 权重衰减_python_02


从图中可以看激活值的偏向较为平均,但大多数也分布在0.5附近。

当权重的标准差设置为0.01时

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

神经网络 权重更新公式 神经网络 权重衰减_python_03


标准差为0.01时,这次呈集中在0.5附近的分布,尽管不会发生梯度消失的问题,但是激活值的分布有所偏向,因为如果很多神经元输出几乎相同的值,那么就没有其存在的意义,导致“表现力受限”的问题。

各层的激活值的分布都要求有适当的广度,否则会出现梯度消失,或者表现力受限的问题!

如何使得激活值呈现具有相同广度的分布

根据Xavier的推论:

神经网络 权重更新公式 神经网络 权重衰减_神经网络 权重更新公式_04

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

激活函数 tanh()

神经网络 权重更新公式 神经网络 权重衰减_机器学习_05


神经网络 权重更新公式 神经网络 权重衰减_机器学习_06

ReLU的权重初始值

使用“He初始值”
w= np.random.randn(node_num, node_num) * np.sqrt(2.0 / node_num)

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

基于MNIST数据集的权重初始值的比较

以下实验将说明,不同的权重初始值的赋值方法会在多大程度上影响神经网络的学习。
神经网络有5层,每层有100个神经元,激活函数使用的是ReLU。

import os
import sys
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from common.util import smooth_curve
from common.multi_layer_net import MultiLayerNet
from 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()

神经网络 权重更新公式 神经网络 权重衰减_机器学习_07


可以看到使用ReLU作为激活函数时,使用He初始值,学习的效率

更高。