赞
踩
①权重的初始值十分重要,关系到神经网络的学习是否成功。
为了抑制过拟合、提高泛化能力,采用权值衰减的方法,它是一种以减小权重参数的值为目的进行学习的方法。
在误差反向传播法中,所有的权重值都会进行相同的更新。比如,在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
从图中可以看激活值的偏向较为平均,但大多数也分布在0.5附近。
当权重的标准差设置为0.01时
w = np.random.randn(node_num, node_num) * 0.01
标准差为0.01时,这次呈集中在0.5附近的分布,尽管不会发生梯度消失的问题,但是激活值的分布有所偏向,因为如果很多神经元输出几乎相同的值,那么就没有其存在的意义,导致“表现力受限”的问题。
各层的激活值的分布都要求有适当的广度,否则会出现梯度消失,或者表现力受限的问题!
根据Xavier的推论:
w= np.random.randn(node_num, node_num) * np.sqrt(1.0 / node_num)
激活函数 tanh()
使用“He初始值”
w= np.random.randn(node_num, node_num) * np.sqrt(2.0 / node_num)
总结:
当激活函数使用ReLU时,权重初始值使用He初始值。
当激活函数为sigmoid或tanh等S型曲线函数时,初始值使用Xavier初始值。
以下实验将说明,不同的权重初始值的赋值方法会在多大程度上影响神经网络的学习。
神经网络有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()
可以看到使用ReLU作为激活函数时,使用He初始值,学习的效率
更高。
《深度学习入门:基于Python的理论与实现》 斋藤康毅
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。