目录
与学习相关的技巧
题涉及寻找最优权重 参数的最优化方法、权重参数的初始值、超参数的设定方法等
为了应对过拟合,本章还将介绍权值衰减、Dropout等正则化方法,对近年来众多研究中使用的Batch Normalization方法进行简单的介绍
6.1 参数的更新
神经网络的学习的目的是找到使损失函数的值尽可能小的参数。
前面我们通过的梯度(导数)作为了线索寻找最优参赛
随机梯度下降法(stochastic gradient descent), 简称SGD
6.1.1 探险家的故事
简称瞎走,通过感觉找到
6.1.2 SGD
教学式:
式子中的←表示用右边的值更新左边的值。
参数更新:
后面我们马上会实现另一个最优化方法Momentum,optimizer = SGD()这一语句换成optimizer = Momentum(),就可以从SGD切 换为Momentum。
6.1.3 SGD的缺点
举个例子:
上式(6.2)表示的函数的梯度,如果用图表示,则如下:
虽然式 (6.2)的最小值在(x, y) = (0, 0)处,但是图6-2中的梯度在很多地方并没有指 向(0, 0)。
SGD的缺点是,如果函数的形状非均向(anisotropic),比如呈延伸状,搜索 的路径就会非常低效。
我们需要比单纯朝梯度方向前进的SGD更聪明的方法。SGD低效的根本原因是,梯度的方向并没有指向最小值的方向
将介绍Momentum、AdaGrad、Adam这3 种方法来取代SGD。
6.1.4 Momentum
这里新出现了一个变量v,对应物理上的速度。
式(6.3)表示了物体在梯度方向上受力,在这个力的作用下,物体的速度增 加这一物理法则。
实现代码:
和SGD相比,我们发现 “之”字形的“程度”减轻了。这是因为虽然x轴方向上受到的力非常小,但 是一直在同一方向上受力,所以朝同一个方向会有一定的加速。
6.1.5 AdaGrad
在关于学习率的有效技巧中,有一种被称为学习率衰减(learning rate decay)的方法,即随着学习的进行,使学习率逐渐减小。
在更新参数时,通过乘以1/根号h ,就可以调整学习的尺度。这意味着, 参数的元素中变动较大(被大幅更新)的元素的学习率将变小.
注意:
AdaGrad会记录过去所有梯度的平方和。学习越深入,更新 的幅度就越小,所以可以使用 RMSProp“指数移动平均”,呈指数函数式地减小 过去的梯度的尺度。
使用AdaGrad解决式(6.2)的最优化问题
由图6-6的结果可知,函数的取值高效地向着最小值移动。由于y轴方 向上的梯度较大,因此刚开始变动较大,但是后面会根据这个较大的变动按 比例进行调整,减小更新的步伐。因此,y轴方向上的更新程度被减弱,“之” 字形的变动程度有所衰减
6.1.6 Adam
Momentum参照小球在碗中滚动的物理规则进行移动,AdaGrad为参 数的每个元素适当地调整更新步伐。
于是乎两个结合在一起?这就是Adam方法的基本思路
通过组合前面两个方法的优点,有望 实现参数空间的高效搜索。具体的原理后面的时候可以看论文
注意:
Adam会设置 3个超参数。一个是学习率(论文中以α出现),另外两 个是一次momentum系数β1和二次momentum系数β2。根据论文, 标准的设定值是β1为 0.9,β2 为 0.999。设置了这些值后,大多数情 况下都能顺利运行。
6.1.7 使用哪种更新方法呢
非常遗憾,(目前)并不存在能在所有问题中都表现良好 的方法。这4种方法各有各的特点,都有各自擅长解决的问题和不擅长解决 的问题。
最近,很多研究人员和技术人员都喜欢用Adam。本书将主要使用 SGD或者Adam,读者可以根据自己的喜好多多尝试。
6.1.8 基于MNIST数据集的更新方法的比较
# coding: utf-8
import os
import sys
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
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 *
# 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:进行实验的设置==========
optimizers = {}
optimizers['SGD'] = SGD()
optimizers['Momentum'] = Momentum()
optimizers['AdaGrad'] = AdaGrad()
optimizers['Adam'] = Adam()
#optimizers['RMSprop'] = RMSprop()
networks = {}
train_loss = {}
for key in optimizers.keys():
networks[key] = MultiLayerNet(
input_size=784, hidden_size_list=[100, 100, 100, 100],
output_size=10)
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 optimizers.keys():
grads = networks[key].gradient(x_batch, t_batch)
optimizers[key].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 optimizers.keys():
loss = networks[key].loss(x_batch, t_batch)
print(key + ":" + str(loss))
# 3.绘制图形==========
markers = {"SGD": "o", "Momentum": "x", "AdaGrad": "s", "Adam": "D"}
x = np.arange(max_iterations)
for key in optimizers.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, 1)
plt.legend()
plt.show()
效果图:
这个实验以一个5层神经网络为对象,其中每层有100个神经元。激活 函数使用的是ReLU。
与SGD相比,其他3种方法学习得更快,而且 速度基本相同,仔细看的话,AdaGrad的学习进行得稍微快一点
6.2 权重的初始值
设定什么样的 权重初始值,经常关系到神经网络的学习能否成功
6.2.1 可以将权重初始值设为0吗
抑制过拟合、提高泛化能力的技巧——权值衰减(weight decay)。
在这之前的权重初始值都是像0.01 * np.random.randn(10, 100)这样,使用 由高斯分布生成的值乘以0.01后得到的值(标准差为0.01的高斯分布)
事实上,将权重初始值设为 0的话,将无法正确进行学习。为什么不能将权重初始值设为0呢?严格地说,为什么不能将权重初始 值设成一样的值呢?这是因为在误差反向传播法中,所有的权重值都会进行 相同的更新。
为了防止“权重均一化” (严格地讲,是为了瓦解权重的对称结构),必须随机生成初始值
6.2.2 隐藏层的激活值的分布
观察隐藏层的激活值 A (激活函数的输出数据)的分布,可以获得很多启 发。
实验的目的是通过改变这个尺度(标准差),观察激活值的分布如何变 化。现在,我们将保存在activations中的各层数据画成直方图
随着输出不断地靠近0(或者靠近1),它的导数的值逐渐接 近0。
因此,偏向0和1的数据分布会造成反向传播中梯度的值不断变小,最后消失。这个问题称为梯度消失(gradient vanishing)。层次加深的深度学习 中,梯度消失的问题可能会更加严重。
下面,将权重的标准差设为0.01,进行相同的实验。实验的代码只需要 把设定权重初始值的地方换成下面的代码即可。
使用标准差为0.01的高斯分布时,各层的激活值的分布 如图6-11所示
因为不像刚才的例子那样偏向0和1,所 以不会发生梯度消失的问题。但是,激活值的分布有所偏向,说明在表现力 上会有很大问题。为什么这么说呢?因为如果有多个神经元都输出几乎相同 的值,那它们就没有存在的意义了。
表现力受限问题、
为了使各层的激活值呈现出具有相同广度的分布,推导了合适的权重尺度。
前一层的节点数越多,要设定为目标节点的初始值的权重尺度就越小
使用Xavier初始值后的结果如图6-13所示。从这个结果可知,越是后 面的层,图像变得越歪斜,但是呈现了比之前更有广度的分布。
如果用tanh 函数(双曲线函数)代替sigmoid函数,这个稍微歪斜的问题就能得 到改善。
6.2.3 ReLU的权重初始值
Xavier初始值是以激活函数是线性函数为前提而推导出来的。因为 sigmoid函数和tanh函数左右对称,且中央附近可以视作线性函数,所以适 合使用Xavier初始值。但当激活函数使用ReLU时,一般推荐使用ReLU专 用的初始值,也就是Kaiming He等人推荐的初始值,也称为“He初始值“
因此:
总结一下:
当激活函数使用ReLU时,权重初始值使用He初始值;
当 激活函数为sigmoid或tanh等S型曲线函数时,初始值使用Xavier初始值。
这是目前的最佳实践。
6.2.4 基于MNIST数据集的权重初始值的比较
实现代码:
# coding: utf-8
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()
基于MNIST数据集的权重初始值的比较:横轴是学习的迭代次数(iterations), 纵轴是损失函数的值(loss)
从图6-15的结果可知,std = 0.01时完全无法进行学习。这和刚 才观察到的激活值的分布一样,是因为正向传播中传递的值很小(集中在0 附近的数据)。因此,逆向传播时求到的梯度也很小,权重几乎不进行更新。 相反,当权重初始值为Xavier初始值和He初始值时,学习进行得很顺利。 并且,我们发现He初始值时的学习进度更快一些。
综上:
权重初始值非常重要,关系到学习能否成功。
6.3 Batch Normalization
为了使各层拥有适当的广度,“强制性”地调整激活值的分布 会怎样呢?实际上,Batch Normalization为了使各层拥有适当的广度,“强制性”地调整激活值的分布 会怎样呢?实际上,Batch Normalization。
6.3.1 Batch Normalization 的算法
为什么Batch Norm这么惹人注目呢?因为Batch Norm有以下优点
- 可以使学习快速进行(可以增大学习率)。
- 不那么依赖初始值(对于初始值不用那么神经质)。
- 抑制过拟合(降低Dropout等的必要性)。
要向神经网络中插入对数据分布进行正规化的层,即Batch Normalization层(下文简称Batch Norm层)
Batch Norm,顾名思义,以进行学习时的mini-batch为单位,按minibatch进行正规化。
具体而言,就是进行使数据分布的均值为0、方差为1的 正规化
式(6.7)中的ε是一个微小值(比如,10e-7等),它是为了防止出现 除以0的情况。
式(6.7)所做的是将mini-batch的输入数据{x1, x2, ... , xm}变换为均值为0、方差为1的数据 ,非常简单。通过将这个处理插入到 激活函数的前面(或者后面)A,可以减小数据分布的偏向。
Batch Norm层会对正规化后的数据进行缩放和平移的变换
Batch Norm可以表示为图6-17
Batch Norm的反向传播的推导有些复杂,这里我们不进行介绍。
6.3.2 Batch Normalization的评估
实现代码:
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from common.multi_layer_net_extend import MultiLayerNetExtend
from common.optimizer import SGD, Adam
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)
# 减少学习数据
x_train = x_train[:1000]
t_train = t_train[:1000]
max_epochs = 20
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.01
def __train(weight_init_std):
bn_network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100], output_size=10,
weight_init_std=weight_init_std, use_batchnorm=True)
network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100], output_size=10,
weight_init_std=weight_init_std)
optimizer = SGD(lr=learning_rate)
train_acc_list = []
bn_train_acc_list = []
iter_per_epoch = max(train_size / batch_size, 1)
epoch_cnt = 0
for i in range(1000000000):
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
for _network in (bn_network, network):
grads = _network.gradient(x_batch, t_batch)
optimizer.update(_network.params, grads)
if i % iter_per_epoch == 0:
train_acc = network.accuracy(x_train, t_train)
bn_train_acc = bn_network.accuracy(x_train, t_train)
train_acc_list.append(train_acc)
bn_train_acc_list.append(bn_train_acc)
print("epoch:" + str(epoch_cnt) + " | " + str(train_acc) + " - " + str(bn_train_acc))
epoch_cnt += 1
if epoch_cnt >= max_epochs:
break
return train_acc_list, bn_train_acc_list
# 3.绘制图形==========
weight_scale_list = np.logspace(0, -4, num=16)
x = np.arange(max_epochs)
for i, w in enumerate(weight_scale_list):
print( "============== " + str(i+1) + "/16" + " ==============")
train_acc_list, bn_train_acc_list = __train(w)
plt.subplot(4,4,i+1)
plt.title("W:" + str(w),fontsize = 10)
if i == 15:
plt.plot(x, bn_train_acc_list, label='Batch Normalization', markevery=2)
plt.plot(x, train_acc_list, linestyle = "--", label='Normal(without BatchNorm)', markevery=2)
else:
plt.plot(x, bn_train_acc_list, markevery=2)
plt.plot(x, train_acc_list, linestyle="--", markevery=2)
plt.ylim(0, 1.0)
if i % 4:
plt.yticks([])
else:
plt.ylabel("accuracy")
if i < 12:
plt.xticks([])
else:
plt.xlabel("epochs")
plt.legend(loc='lower right')
plt.show()
实验效果图字体比较难调,所以用书本上的了
学习过程时间特别短:
综上,通过使用Batch Norm,可以推动学习的进行。并且,对权重初 始值变得健壮(“对初始值健壮”表示不那么依赖初始值)。Batch Norm具备 了如此优良的性质,一定能应用在更多场合中”
6.4 正则化
6.4.1 过拟合
发生过拟合的原因,主要有以下两个。
• 模型拥有大量参数、表现力强。
• 训练数据少
我们在实验过程中,先尝试这两个错误:
从 MNIST数据集原本的60000个训练数据中只选定300个,并且,为了增加网 络的复杂度,使用7层网络(每层有100个神经元,激活函数为ReLU)。
过了 100 个 epoch 左右后,用训练数据测量到的识别精度几乎都为 100%。但是,对于测试数据,离100%的识别精度还有较大的差距。如此大 的识别精度差距,是只拟合了训练数据的结果。从图中可知,模型对训练时 没有使用的一般数据(测试数据)拟合得不是很好。
6.4.2 权值衰减
权值衰减是一直以来经常被使用的一种抑制过拟合的方法。
对于所有权重,权值衰减方法都会为损失函数加上
因此,在求权 重梯度的计算中,要为之前的误差反向传播法的结果加上正则化项的导数λW
实现代码:
# coding: utf-8
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.multi_layer_net import MultiLayerNet
from common.optimizer import SGD
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)
# 为了再现过拟合,减少学习数据
x_train = x_train[:300]
t_train = t_train[:300]
# weight decay(权值衰减)的设定 =======================
#weight_decay_lambda = 0 # 不使用权值衰减的情况
weight_decay_lambda = 0.1
# ====================================================
network = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100], output_size=10,
weight_decay_lambda=weight_decay_lambda)
optimizer = SGD(lr=0.01)
max_epochs = 201
train_size = x_train.shape[0]
batch_size = 100
train_loss_list = []
train_acc_list = []
test_acc_list = []
iter_per_epoch = max(train_size / batch_size, 1)
epoch_cnt = 0
for i in range(1000000000):
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
grads = network.gradient(x_batch, t_batch)
optimizer.update(network.params, grads)
if i % iter_per_epoch == 0:
train_acc = network.accuracy(x_train, t_train)
test_acc = network.accuracy(x_test, t_test)
train_acc_list.append(train_acc)
test_acc_list.append(test_acc)
print("epoch:" + str(epoch_cnt) + ", train acc:" + str(train_acc) + ", test acc:" + str(test_acc))
epoch_cnt += 1
if epoch_cnt >= max_epochs:
break
# 3.绘制图形==========
markers = {'train': 'o', 'test': 's'}
x = np.arange(max_epochs)
plt.plot(x, train_acc_list, marker='o', label='train', markevery=10)
plt.plot(x, test_acc_list, marker='s', label='test', markevery=10)
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()
结果:
如图6-21所示,虽然训练数据的识别精度和测试数据的识别精度之间有 差距,但是与没有使用权值衰减的图6-20的结果相比,差距变小了
6.4.3 Dropout
如果网络的模型变得很复杂,我们经常会使用Dropout方法.
Dropout是一种在学习的过程中随机删除神经元的方法。训练时,每传递一次数据,就会随机选择要删除的神经元。
下面我们来实现Dropout。这里的实现重视易理解性。不过,因为训练 时如果进行恰当的计算的话,正向传播时单纯地传递数据就可以了(不用乘 以删除比例),所以深度学习的框架中进行了这样的实现。关于高效的实现, 可以参考Chainer中实现的Dropou
这里的要点是,每次正向传播时,self.mask中都会以False的形式保 存要删除的神经元。self.mask会随机生成和x形状相同的数组,并将值比 dropout_ratio大的元素设为True。反向传播时的行为和ReLU相同
我们使用MNIST数据集进行验证,以确认Dropout的效果。源代 码在ch06/overfit_dropout.py中。另外,源代码中使用了Trainer类来简化实现
# coding: utf-8
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.multi_layer_net_extend import MultiLayerNetExtend
from common.trainer import Trainer
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)
# 为了再现过拟合,减少学习数据
x_train = x_train[:300]
t_train = t_train[:300]
# 设定是否使用Dropuout,以及比例 ========================
use_dropout = True # 不使用Dropout的情况下为False
dropout_ratio = 0.2
# ====================================================
#用Dropout的情况下
network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100],
output_size=10, use_dropout=use_dropout, dropout_ration=dropout_ratio)
trainer = Trainer(network, x_train, t_train, x_test, t_test,
epochs=301, mini_batch_size=100,
optimizer='sgd', optimizer_param={'lr': 0.01}, verbose=True)
trainer.train()
train_acc_list, test_acc_list = trainer.train_acc_list, trainer.test_acc_list
# 绘制图形==========
markers = {'train': 'o', 'test': 's'}
x = np.arange(len(train_acc_list))
plt.plot(x, train_acc_list, marker='o', label='train', markevery=10)
plt.plot(x, test_acc_list, marker='s', label='test', markevery=10)
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()
结果:
图6-23中,通过使用Dropout,训练数据和测试数据的识别精度的差距 变小了。
6.5 超参数的验证
这里所说的超参数是指,比如各层的神经元数量、batch大小、参 数更新时的学习率或权值衰减等
6.5.1 验证数据
为什么不能用测试数据评估超参数的性能呢?这是因为如果使用测试数 据调整超参数,超参数的值会对测试数据发生过拟合。
用于调整超参 数的数据,一般称为验证数据(validation data)。我们使用这个验证数据来 评估超参数的好坏。
与吴恩达的三部分数据划分一致。有的会事先分成训练数据、验证数据、测试数据三 部分,有的只分成训练数据和测试数据两部分。
6.5.2 超参数的最优化
所谓逐渐缩小范围,是指一开始先大致设定一个范围,从这个范围中随机选 出一个超参数(采样),用这个采样到的值进行识别精度的评估
超参数的范围只要“大致地指定”就可以了。所谓“大致地指定”,是指 像0.001(10^−3 )到1000(10^3 )这样,以“10的阶乘”的尺度指定范围(也表述 为“用对数尺度(log scale)指定”)。
超参数的最优化的内容,简单归纳一下,如下所示。
这里介绍的超参数的最优化方法是实践性的方法。... 人为调参
6.5.3 超参数最优化的实现
如前所述,通过从 0.001(10^−3 )到 1000(10^3)
这样的对数尺度的范围 中随机采样进行超参数的验证。
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from common.multi_layer_net import MultiLayerNet
from common.util import shuffle_dataset
from common.trainer import Trainer
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)
# 为了实现高速化,减少训练数据
x_train = x_train[:500]
t_train = t_train[:500]
# 分割验证数据
validation_rate = 0.20
validation_num = int(x_train.shape[0] * validation_rate)
x_train, t_train = shuffle_dataset(x_train, t_train)
x_val = x_train[:validation_num]
t_val = t_train[:validation_num]
x_train = x_train[validation_num:]
t_train = t_train[validation_num:]
def __train(lr, weight_decay, epocs=50):
network = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100],
output_size=10, weight_decay_lambda=weight_decay)
trainer = Trainer(network, x_train, t_train, x_val, t_val,
epochs=epocs, mini_batch_size=100,
optimizer='sgd', optimizer_param={'lr': lr}, verbose=False)
trainer.train()
return trainer.test_acc_list, trainer.train_acc_list
# 超参数的随机搜索======================================
optimization_trial = 100
results_val = {}
results_train = {}
for _ in range(optimization_trial):
# 指定搜索的超参数的范围===============
# 0.001(10^−3 )到 1000(10^3) 对数尺度的范围
# 中随机采样进行超参数的验证
# 权值衰减系数的初始范围为10−8 到10−4
# 学习率的初始范围为10^−6到10^−2
weight_decay = 10 ** np.random.uniform(-8, -4)
lr = 10 ** np.random.uniform(-6, -2)
# ================================================
val_acc_list, train_acc_list = __train(lr, weight_decay)
print("val acc:" + str(val_acc_list[-1]) + " | lr:" + str(lr) + ", weight decay:" + str(weight_decay))
key = "lr:" + str(lr) + ", weight decay:" + str(weight_decay)
results_val[key] = val_acc_list
results_train[key] = train_acc_list
# 绘制图形========================================================
print("=========== Hyper-Parameter Optimization Result ===========")
graph_draw_num = 20
col_num = 5
row_num = int(np.ceil(graph_draw_num / col_num))
i = 0
for key, val_acc_list in sorted(results_val.items(), key=lambda x:x[1][-1], reverse=True):
print("Best-" + str(i+1) + "(val acc:" + str(val_acc_list[-1]) + ") | " + key)
plt.subplot(row_num, col_num, i+1)
plt.title("Best-" + str(i+1))
plt.ylim(0.0, 1.0)
if i % 5: plt.yticks([])
plt.xticks([])
x = np.arange(len(val_acc_list))
plt.plot(x, val_acc_list)
plt.plot(x, results_train[key], "--")
i += 1
if i >= graph_draw_num:
break
plt.show()
这样就能缩小到合适的超参数的存在范围,然后在某个阶段,选择一个最终 的超参数的值
6.6 小结
本章我们介绍了神经网络的学习中的几个重要技巧。
参数的更新方法、 权重初始值的赋值方法、Batch Normalization、Dropout等,这些都是现代 神经网络中不可或缺的技术。另外,这里介绍的技巧,在最先进的深度学习 中也被频繁使用。
吴恩达的视屏看完后看这个真的会有不一样的收获。