如果函数的形状非均向,搜索的路径就会非常低效,根本原因是梯度的方向没有指向最小值的方向
新增变量v,对应物理上的速度。
新增变量h,保存了以前的所有梯度值的平方和 在更新参数时,通过乘以1/根号h,就可以调整学习的尺度 参数的元素中变动较大(被大幅更新)的元素学习率将变小
融合了Momentum和AdaGrad的方法,也进行超参数的“偏置校正”也是其特点。
设置三个超参数,一个是学习率,另外两个是momentum系数和二次momentum系数
根据不同的问题选择不同的方法,SGD在mnist数据集中学习的表现比其他三种方法慢
一般而言,与SGD相比,其他三种方法可以学习得更快,有时最终的识别精度也更高
权重的初始值设为0,在误差反向传播法中,所有的权重值都会进行相同的更新,并拥有对称的值(重复的值),为了防止“权重均一化”(为了瓦解权重的对称结构),必须随机生成初始值。
向一个五层神经网络(激活函数使用sigmoid函数)传入随机生成的输入数据,用直方图绘制各层激活值的数据分布。
# coding: utf-8 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 #权重初始值设为1 # w = np.random.randn(node_num, node_num) * 0.01 # 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(): #item()方法把字典中每对key和value组成一个元组,并把这些元组放在列表中返回。 plt.subplot(1, len(activations), i+1) '''fig.add_subplot(numrows, numcols, fignum) 三个参数,分别代表子图的行数,列数,图索引号。''' plt.title(str(i+1) + "-layer") if i != 0: plt.yticks([], []) #设置y轴的刻度 plt.hist(a.flatten(), 30, range=(0,1)) #hist柱状图,a.flatten():a是个数组,a.flatten()就是把a降到一维,默认是按行的方向降,bin=30:有30个柱 plt.show()结果:
如果前一层的节点数为n,则初始值使用标准差为1/√ ̄n的分布
w = np.random.randn(node_num, node_num) * np.sqrt(1.0 / node_num)
如果用tanh函数代替sigmoid函数,会呈吊钟型分布。
用作激活函数的函数最好具有关于原点对称的性质。
当激活函数使用ReLu函数时,一般推荐使用ReLu专用的初始值,也称He初始值
当前一层的节点数为n时,He初始值使用标准差为√ ̄(2/n)的高斯分布
优点:
可以使学习快速进行(可以增大学习率)不那么依赖初始值(对于初始值不用那么神经质)抑制过拟合(降低Dropout等的必要性)思路: 调整各层的激活值分布使其适当的广度,为此,要向神经网络中插入对数据分布进行正规化的层。 以进行学习时的Mini-batch为单位,按Mini-batch进行正规化(使数据分布的均值为0,方差为1)
过拟合发生的原因:
模型拥有大量参数、表现力强训练数据少该方法通过在学习的过程中对大的权值进行惩罚,来抑制过拟合。 对于所有权重,权值衰减方法都会为损失函数加上1/2λW²,因此在求权重梯度的计算中,要为之前的误差反向传播法的结果加上正则化项的导数λW
网络模型复杂时只用权值衰减就很难应对。 在学习过程中随机删除神经元的方法,训练时,随机选出隐藏层的神经元,然后将其删除。被删除的神经元不再进行信号的传递。然后,测试时,虽然会传递所有的神经元信号,但是对于各个神经元的输出,要乘上训练时的删除比例再输出。
import numpy as np class Dropout: def __init__(self, dropout_ratio=0.5): self.dropout_ratio = dropout_ratio self.mask = None def forward(self, x, train_flg=True): if train_flg: self.mask = np.random.rand(*x.shape) > self.dropout_ratio #self.mask会随机生成和x形状相同的数组 return x * self.mask else: return x * (1.0 - self.dropout_ratio) def backward(self, dout): return dout * self.mask #每次正向传播时,self.mask都会以False的形式保存要删除的神经元正向传播时传递了信号的神经元,反向传播时按原样传递信号,正向传播时没有传递信号的神经元,反向传播时信号将停在那里。
让多个模型单独进行学习,推理时再取多个模型的输出的平均值。这个集成学习与Dropout有密切的关系。这是因为可以将Dropout理解为,通过在学习过程中随机删除神经元,从而每一次都让不同的模型进行学习。并且,推理时,通过对神经元的输出乘以删除比例,可以取得模型的平均值。
比如各层的神经元数量、batch大小、参数更新时的学习率或权值衰减等。 调整超参数时,必须使用超参数专用的确认数据。 用于调整超参数的数据一般称为验证数据。
(x_train, t_train),(x_test, t_test) = load_mnist() #打乱训练数据 x_train, t_train = shuffle_dataset(x_train, t_train) #分割验证数据 validation_rate = 0.20 validation_num = int(x_train.shape[0] * validation_rate) x_val = x_train[:validation_num] t_val = t_train[:validation_num] x_train = x_train[:validation_num] t_train = t_train[:validation_num]分割训练数据前,先打乱了输入数据和教师标签,这是因为数据集的数据可能存在偏向。
超参数的最优化:
设定超参数的范围从设定的超参数范围中随机采样使用步骤2中采样的超参数的值进行学习,通过验证数据评估识别精度(但是要将epoch设置的很小)重复步骤2和步骤3(100次等),根据它们的识别精度的结果,缩小超参数的范围。