枣强网址建站,阿里巴巴指数查询,网站建设中 翻译,网站调整方案文章目录 1.参数的更新1#xff09;SGD2#xff09;Momentum3#xff09;AdaGrad4#xff09;Adam5#xff09;最优化方法的比较6#xff09;基于MNIST数据集的更新方法的比较 2.权重的初始值1#xff09;权重初始值不能为02#xff09;隐藏层的激活值的分布3#xff… 文章目录 1.参数的更新1SGD2Momentum3AdaGrad4Adam5最优化方法的比较6基于MNIST数据集的更新方法的比较 2.权重的初始值1权重初始值不能为02隐藏层的激活值的分布3ReLU的权重初始值4基于MNIST数据集的权重初始值的比较 3.Batch Normalization1Batch Normalization 的算法2Batch Normalization的评估 4.正则化1过拟合2权值衰减3Dropout4集成学习 5.超参数的验证1验证数据2超参数的最优化3步骤4超参数最优化的实现 1.参数的更新
神经网络的学习的目的是找到使损失函数的值尽可能小的参数。这是寻找最优参数的问题解决这个问题的过程称为最优化optimization。
使用参数的梯度沿梯度方向更新参数并重复这个步骤多次从而逐渐靠近最优参数这个过程称为随机梯度下降法stochastic gradient descent简称SGD。
1SGD
探险家虽然看不到周围的情况但是能够知道当前所在位置的坡度通过脚底感受地面的倾斜状况。于是朝着当前所在位置的坡度最大的方向前进就是SGD的策略。 SGD实现
class SGD:随机梯度下降法Stochastic Gradient Descent
#进行初始化时的参数lr表示learning rate学习率def __init__(self, lr0.01):self.lr lr#该方法在SGD中会被反复调用。def update(self, params, grads):for key in params.keys():params[key] - self.lr * grads[key]
SGD呈“之”字形移动。这是一个相当低效的路径。也就是说SGD 的缺点是如果函数的形状非均向anisotropic比如呈延伸状搜索的路径就会非常低效。因此我们需要比单纯朝梯度方向前进的SGD更聪明的方法。SGD低效的根本原因是梯度的方向并没有指向最小值的方向。
2Momentum
Momentum 是“动量”的意思和物理有关。Momentum方法给人的感觉就像是小球在地面上滚动。在物体不受任何力时担使物体逐渐减 速的任务
实现
class Momentum:Momentum SGDdef __init__(self, lr0.01, momentum0.9):self.lr lrself.momentum momentum#实例变量v会保存物体的速度。self.v Nonedef update(self, params, grads):if self.v is None:self.v {}for key, val in params.items(): #v会以字典型变量的形式保存与参数结构相同的数据self.v[key] np.zeros_like(val)for key in params.keys():self.v[key] self.momentum*self.v[key] - self.lr*grads[key] params[key] self.v[key]和SGD相比我们发现“之”字形的“程度”减轻了。这是因为虽然x轴方向上受到的力非常小但是一直在同一方向上受力所以朝同一个方向会有一定的加速。反过来虽然y轴方向上受到的力很大但是因为交互地受到正方向和反方向的力它们会互相抵消所以y轴方向上的速度不稳定。因此和SGD时的情形相比 可以更快地朝x轴方向靠近减弱“之”字形的变动程度。
3AdaGrad
在关于学习率的有效技巧中有一种被称为学习率衰减learning rate decay的方法即随着学习的进行使学习率逐渐减小。实际上一开始“多”学然后逐渐“少”学的方法在神经网络的学习中经常被使用。
逐渐减小学习率的想法相当于将“全体”参数的学习率值一起降低。而AdaGrad进一步发展了这个想法针对“一个一个”的参数赋予其“定制”的值。表达式如下 可以按参数的元素进行学习率衰减使变动大的参数的学习率逐渐减小。
4Adam
融合了Momentum和AdaGrad的方法。
5最优化方法的比较
完整代码如下
创建文件optimizer.py实现各种优化器 添加代码如下
# coding: utf-8
import numpy as npclass SGD:随机梯度下降法Stochastic Gradient Descentdef __init__(self, lr0.01):self.lr lrdef update(self, params, grads):for key in params.keys():params[key] - self.lr * grads[key] class Momentum:Momentum SGDdef __init__(self, lr0.01, momentum0.9):self.lr lrself.momentum momentumself.v Nonedef update(self, params, grads):if self.v is None:self.v {}for key, val in params.items(): self.v[key] np.zeros_like(val)for key in params.keys():self.v[key] self.momentum*self.v[key] - self.lr*grads[key] params[key] self.v[key]class Nesterov:Nesterovs Accelerated Gradient (http://arxiv.org/abs/1212.0901)def __init__(self, lr0.01, momentum0.9):self.lr lrself.momentum momentumself.v Nonedef update(self, params, grads):if self.v is None:self.v {}for key, val in params.items():self.v[key] np.zeros_like(val)for key in params.keys():self.v[key] * self.momentumself.v[key] - self.lr * grads[key]params[key] self.momentum * self.momentum * self.v[key]params[key] - (1 self.momentum) * self.lr * grads[key]class AdaGrad:AdaGraddef __init__(self, lr0.01):self.lr lrself.h Nonedef update(self, params, grads):if self.h is None:self.h {}for key, val in params.items():self.h[key] np.zeros_like(val)for key in params.keys():self.h[key] grads[key] * grads[key]params[key] - self.lr * grads[key] / (np.sqrt(self.h[key]) 1e-7)class RMSprop:RMSpropdef __init__(self, lr0.01, decay_rate 0.99):self.lr lrself.decay_rate decay_rateself.h Nonedef update(self, params, grads):if self.h is None:self.h {}for key, val in params.items():self.h[key] np.zeros_like(val)for key in params.keys():self.h[key] * self.decay_rateself.h[key] (1 - self.decay_rate) * grads[key] * grads[key]params[key] - self.lr * grads[key] / (np.sqrt(self.h[key]) 1e-7)class Adam:Adam (http://arxiv.org/abs/1412.6980v8)def __init__(self, lr0.001, beta10.9, beta20.999):self.lr lrself.beta1 beta1self.beta2 beta2self.iter 0self.m Noneself.v Nonedef update(self, params, grads):if self.m is None:self.m, self.v {}, {}for key, val in params.items():self.m[key] np.zeros_like(val)self.v[key] np.zeros_like(val)self.iter 1lr_t self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter) for key in params.keys():#self.m[key] self.beta1*self.m[key] (1-self.beta1)*grads[key]#self.v[key] self.beta2*self.v[key] (1-self.beta2)*(grads[key]**2)self.m[key] (1 - self.beta1) * (grads[key] - self.m[key])self.v[key] (1 - self.beta2) * (grads[key]**2 - self.v[key])params[key] - lr_t * self.m[key] / (np.sqrt(self.v[key]) 1e-7)#unbias_m (1 - self.beta1) * (grads[key] - self.m[key]) # correct bias#unbisa_b (1 - self.beta2) * (grads[key]*grads[key] - self.v[key]) # correct bias#params[key] self.lr * unbias_m / (np.sqrt(unbisa_b) 1e-7)
创建文件optimizer_compare_naive.py,引入优化器 添加代码如下
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
import matplotlib.pyplot as plt
from collections import OrderedDict
from optimizer import *def f(x, y):return x**2 / 20.0 y**2def df(x, y):return x / 10.0, 2.0*yinit_pos (-7.0, 2.0)
params {}
params[x], params[y] init_pos[0], init_pos[1]
grads {}
grads[x], grads[y] 0, 0optimizers OrderedDict()
optimizers[SGD] SGD(lr0.95)
optimizers[Momentum] Momentum(lr0.1)
optimizers[AdaGrad] AdaGrad(lr1.5)
optimizers[Adam] Adam(lr0.3)idx 1for key in optimizers:optimizer optimizers[key]x_history []y_history []params[x], params[y] init_pos[0], init_pos[1]for i in range(30):x_history.append(params[x])y_history.append(params[y])grads[x], grads[y] df(params[x], params[y])optimizer.update(params, grads)x np.arange(-10, 10, 0.01)y np.arange(-5, 5, 0.01)X, Y np.meshgrid(x, y) Z f(X, Y)# for simple contour line mask Z 7Z[mask] 0# plot plt.subplot(2, 2, idx)idx 1plt.plot(x_history, y_history, o-, colorred)plt.contour(X, Y, Z)plt.ylim(-10, 10)plt.xlim(-10, 10)plt.plot(0, 0, )#colorbar()#spring()plt.title(key)plt.xlabel(x)plt.ylabel(y)plt.show()运行结果 根据使用的方法不同参数更新的路径也不同。只看这个图的话AdaGrad似乎是最好的不过也要注意结果会根据要解决的问题而变。并且很显然超参数学习率等的设定值不同结果也会发生变化。
并不存在能在所有问题中都表现良好的方法。这4种方法各有各的特点都有各自擅长解决的问题和不擅长解决的问题。
很多研究中至今仍在使用SGD。Momentum和AdaGrad也是值得一试的方法。最近很多研究人员和技术人员都喜欢用Adam。
6基于MNIST数据集的更新方法的比较
完整代码如下
创建文件夹common移入optimizer.py
在文件夹common下创建文件util.py 添加代码如下
# coding: utf-8
import numpy as npdef smooth_curve(x):用于使损失函数的图形变圆滑参考http://glowingpython.blogspot.jp/2012/02/convolution-with-numpy.htmlwindow_len 11s np.r_[x[window_len-1:0:-1], x, x[-1:-window_len:-1]]w np.kaiser(window_len, 2)y np.convolve(w/w.sum(), s, modevalid)return y[5:len(y)-5]def shuffle_dataset(x, t):打乱数据集Parameters----------x : 训练数据t : 监督数据Returns-------x, t : 打乱的训练数据和监督数据permutation np.random.permutation(x.shape[0])x x[permutation,:] if x.ndim 2 else x[permutation,:,:,:]t t[permutation]return x, tdef conv_output_size(input_size, filter_size, stride1, pad0):return (input_size 2*pad - filter_size) / stride 1def im2col(input_data, filter_h, filter_w, stride1, pad0):Parameters----------input_data : 由(数据量, 通道, 高, 长)的4维数组构成的输入数据filter_h : 滤波器的高filter_w : 滤波器的长stride : 步幅pad : 填充Returns-------col : 2维数组N, C, H, W input_data.shapeout_h (H 2*pad - filter_h)//stride 1out_w (W 2*pad - filter_w)//stride 1img np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], constant)col np.zeros((N, C, filter_h, filter_w, out_h, out_w))for y in range(filter_h):y_max y stride*out_hfor x in range(filter_w):x_max x stride*out_wcol[:, :, y, x, :, :] img[:, :, y:y_max:stride, x:x_max:stride]col col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)return coldef col2im(col, input_shape, filter_h, filter_w, stride1, pad0):Parameters----------col :input_shape : 输入数据的形状例(10, 1, 28, 28)filter_h :filter_wstridepadReturns-------N, C, H, W input_shapeout_h (H 2*pad - filter_h)//stride 1out_w (W 2*pad - filter_w)//stride 1col col.reshape(N, out_h, out_w, C, filter_h, filter_w).transpose(0, 3, 4, 5, 1, 2)img np.zeros((N, C, H 2*pad stride - 1, W 2*pad stride - 1))for y in range(filter_h):y_max y stride*out_hfor x in range(filter_w):x_max x stride*out_wimg[:, :, y:y_max:stride, x:x_max:stride] col[:, :, y, x, :, :]return img[:, :, pad:H pad, pad:W pad]在文件夹common下创建文件multi_layer_net.py 添加代码如下
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
from collections import OrderedDict
from common.layers import *
from common.gradient import numerical_gradientclass MultiLayerNet:全连接的多层神经网络Parameters----------input_size : 输入大小MNIST的情况下为784hidden_size_list : 隐藏层的神经元数量的列表e.g. [100, 100, 100]output_size : 输出大小MNIST的情况下为10activation : relu or sigmoidweight_init_std : 指定权重的标准差e.g. 0.01指定relu或he的情况下设定“He的初始值”指定sigmoid或xavier的情况下设定“Xavier的初始值”weight_decay_lambda : Weight DecayL2范数的强度def __init__(self, input_size, hidden_size_list, output_size,activationrelu, weight_init_stdrelu, weight_decay_lambda0):self.input_size input_sizeself.output_size output_sizeself.hidden_size_list hidden_size_listself.hidden_layer_num len(hidden_size_list)self.weight_decay_lambda weight_decay_lambdaself.params {}# 初始化权重self.__init_weight(weight_init_std)# 生成层activation_layer {sigmoid: Sigmoid, relu: Relu}self.layers OrderedDict()for idx in range(1, self.hidden_layer_num1):self.layers[Affine str(idx)] Affine(self.params[W str(idx)],self.params[b str(idx)])self.layers[Activation_function str(idx)] activation_layer[activation]()idx self.hidden_layer_num 1self.layers[Affine str(idx)] Affine(self.params[W str(idx)],self.params[b str(idx)])self.last_layer SoftmaxWithLoss()def __init_weight(self, weight_init_std):设定权重的初始值Parameters----------weight_init_std : 指定权重的标准差e.g. 0.01指定relu或he的情况下设定“He的初始值”指定sigmoid或xavier的情况下设定“Xavier的初始值”all_size_list [self.input_size] self.hidden_size_list [self.output_size]for idx in range(1, len(all_size_list)):scale weight_init_stdif str(weight_init_std).lower() in (relu, he):scale np.sqrt(2.0 / all_size_list[idx - 1]) # 使用ReLU的情况下推荐的初始值elif str(weight_init_std).lower() in (sigmoid, xavier):scale np.sqrt(1.0 / all_size_list[idx - 1]) # 使用sigmoid的情况下推荐的初始值self.params[W str(idx)] scale * np.random.randn(all_size_list[idx-1], all_size_list[idx])self.params[b str(idx)] np.zeros(all_size_list[idx])def predict(self, x):for layer in self.layers.values():x layer.forward(x)return xdef loss(self, x, t):求损失函数Parameters----------x : 输入数据t : 教师标签Returns-------损失函数的值y self.predict(x)weight_decay 0for idx in range(1, self.hidden_layer_num 2):W self.params[W str(idx)]weight_decay 0.5 * self.weight_decay_lambda * np.sum(W ** 2)return self.last_layer.forward(y, t) weight_decaydef accuracy(self, x, t):y self.predict(x)y np.argmax(y, axis1)if t.ndim ! 1 : t np.argmax(t, axis1)accuracy np.sum(y t) / float(x.shape[0])return accuracydef numerical_gradient(self, x, t):求梯度数值微分Parameters----------x : 输入数据t : 教师标签Returns-------具有各层的梯度的字典变量grads[W1]、grads[W2]、...是各层的权重grads[b1]、grads[b2]、...是各层的偏置loss_W lambda W: self.loss(x, t)grads {}for idx in range(1, self.hidden_layer_num2):grads[W str(idx)] numerical_gradient(loss_W, self.params[W str(idx)])grads[b str(idx)] numerical_gradient(loss_W, self.params[b str(idx)])return gradsdef gradient(self, x, t):求梯度误差反向传播法Parameters----------x : 输入数据t : 教师标签Returns-------具有各层的梯度的字典变量grads[W1]、grads[W2]、...是各层的权重grads[b1]、grads[b2]、...是各层的偏置# forwardself.loss(x, t)# backwarddout 1dout self.last_layer.backward(dout)layers list(self.layers.values())layers.reverse()for layer in layers:dout layer.backward(dout)# 设定grads {}for idx in range(1, self.hidden_layer_num2):grads[W str(idx)] self.layers[Affine str(idx)].dW self.weight_decay_lambda * self.layers[Affine str(idx)].Wgrads[b str(idx)] self.layers[Affine str(idx)].dbreturn grads
在文件夹common下创建文件optimizer_compare_mnist.py 添加代码如下
# 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(normalizeTrue)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_size784, hidden_size_list[100, 100, 100, 100],output_size10)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]), markermarkers[key], markevery100, labelkey)
plt.xlabel(iterations)
plt.ylabel(loss)
plt.ylim(0, 1)
plt.legend()
plt.show() 与SGD相比其他3种方法学习得更快而且速度基本相同仔细看的话AdaGrad的学习进行得稍微快一点。这个实验需要注意的地方是实验结果会随学习率等超参数、神经网络的结构几层深等的不同而发生变化。不过一般而言与SGD相比其他3种方法可以学习得更快有时最终的识别精度也更高。
2.权重的初始值
权值衰减就是一种提高泛化能力的技巧,以减小权重参数的值为目的进行学习的方法。通过减小权重参数的值来抑制过拟合的发生。
如果想减小权重的值一开始就将初始值设为较小的值才是正途。
1权重初始值不能为0
将权重初始值设为0不是一个好主意。事实上将权重初始值设为0 的话将无法正确进行学习。
这是因为在误差反向传播法中所有的权重值都会进行相同的更新。比如在2层神经网络中假设第1层和第2层的权重为0。这样一来正向传播时因为输入层的权重为0所以第2层的神经元全部会被传递相同的值。
2隐藏层的激活值的分布
将激活函数的输出数据称为“激活值”但是有的文献中会将在层之间流动的数据也称为“激活值”。
实现
# coding: utf-8
import numpy as np
import matplotlib.pyplot as pltdef sigmoid(x):return 1 / (1 np.exp(-x))def ReLU(x):return np.maximum(0, x)def tanh(x):return np.tanh(x)#高斯分布随机生成1000个数据作为输入数据并把它们传给5层神经网络。
input_data np.random.randn(1000, 100) # 1000个数据
node_num 100 # 各隐藏层的节点神经元数
hidden_layer_size 5 # 隐藏层有5层
activations {} # 激活值的结果保存在这里x input_datafor 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), i1)plt.title(str(i1) -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的分布。偏向0和1的数据分布会造成反向传播中梯度的值不断变小最后消失。这个问题称为梯度消失gradient vanishing。层次加深的深度学习中梯度消失的问题可能会更加严重。
将权重的标准差设为0.01时这次呈集中在0.5附近的分布。因为不像刚才的例子那样偏向0和1所以不会发生梯度消失的问题。
因此激活值在分布上有所偏向会出现“表现力受限”的问题。
尝试使用Xavier Glorot等人的论文中推荐的权重初始值俗称“Xavier初始值”。Xavier 的论文中为了使各层的激活值呈现出具有相同广度的分布推导了合适的权重尺度。推导出的结论是如果前一层的节点数为n则初始值使用标准差为 1 / n 1/ \sqrt{n} 1/n 的分布。结果表明后面的层的分布呈稍微歪斜的形状。如果用tanh函数双曲线函数代替sigmoid函数这个稍微歪斜的问题就能得到改善。实际上使用tanh函数后会呈漂亮的吊钟型分布。tanh函数和sigmoid函数同是S型曲线函数但tanh函数是关于原点(0, 0)对称的S型曲线而sigmoid函数是关于(x, y)(0, 0.5)对称的S型曲线。众所周知用作激活函数的函数最好具有关于原点对称的性质。
3ReLU的权重初始值
当激活函数使用ReLU时一般推荐使用ReLU专用的初始值也就是Kaiming He等人推荐的初始值也称为He初始值。
在这种情况下随着层的加深偏向一点点变大。实际上层加深后激活值的偏向变大学习时会出现梯度消失的问题。而当初始值为He初始值时各层中分布的广度相同。由于即便层加深数据的广度也能保持不变因此逆向传播时也会传递合适的值。
总结一下当激活函数使用ReLU时权重初始值使用He初始值当激活函数为sigmoid或tanh等S型曲线函数时初始值使用Xavier初始值。这是目前的最佳实践。
4基于MNIST数据集的权重初始值的比较
创建文件weight_init_compare.py 添加代码如下
# coding: utf-8
import os
import syssys.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(normalizeTrue)train_size x_train.shape[0]
batch_size 128
max_iterations 2000# 1:进行实验的设置
weight_init_types {std0.01: 0.01, Xavier: sigmoid, He: relu}
optimizer SGD(lr0.01)networks {}
train_loss {}
for key, weight_type in weight_init_types.items():networks[key] MultiLayerNet(input_size784, hidden_size_list[100, 100, 100, 100],output_size10, weight_init_stdweight_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 {std0.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]), markermarkers[key], markevery100, labelkey)
plt.xlabel(iterations)
plt.ylabel(loss)
plt.ylim(0, 2.5)
plt.legend()
plt.show()运行结果
std 0.01时完全无法进行学习。这和刚才观察到的激活值的分布一样是因为正向传播中传递的值很小集中在0附近的数据。因此逆向传播时求到的梯度也很小权重几乎不进行更新。相反当权重初始值为Xavier初始值和He初始值时学习进行得很顺利。 并且我们发现He初始值时的学习进度更快一些。
3.Batch Normalization
Batch Normalization可以“强制性”地调整激活值的分布
1Batch Normalization 的算法
优点
• 可以使学习快速进行可以增大学习率。 • 不那么依赖初始值对于初始值不用那么神经质。 • 抑制过拟合降低Dropout等的必要性。
Batch Norm的思路是调整各层的激活值分布使其拥有适当的广度。为此要向神经网络中插入对数据分布进行正规化的层即Batch Normalization 层
2Batch Normalization的评估
使用 MNIST 数据集观察使用Batch Norm层和不使用Batch Norm层时学习的过程
实现
# 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(normalizeTrue)# 减少学习数据
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.01def __train(weight_init_std):bn_network MultiLayerNetExtend(input_size784, hidden_size_list[100, 100, 100, 100, 100], output_size10, weight_init_stdweight_init_std, use_batchnormTrue)network MultiLayerNetExtend(input_size784, hidden_size_list[100, 100, 100, 100, 100], output_size10,weight_init_stdweight_init_std)optimizer SGD(lrlearning_rate)train_acc_list []bn_train_acc_list []iter_per_epoch max(train_size / batch_size, 1)epoch_cnt 0for 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 1if epoch_cnt max_epochs:breakreturn train_acc_list, bn_train_acc_list# 3.绘制图形
weight_scale_list np.logspace(0, -4, num16)
x np.arange(max_epochs)for i, w in enumerate(weight_scale_list):print( str(i1) /16 )train_acc_list, bn_train_acc_list __train(w)plt.subplot(4,4,i1)plt.title(W: str(w))if i 15:plt.plot(x, bn_train_acc_list, labelBatch Normalization, markevery2)plt.plot(x, train_acc_list, linestyle --, labelNormal(without BatchNorm), markevery2)else:plt.plot(x, bn_train_acc_list, markevery2)plt.plot(x, train_acc_list, linestyle--, markevery2)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(loclower right)plt.show()运行结果
使用Batch Norm后学习进行得更快了。
4.正则化
1过拟合
发生过拟合的原因主要有以下两个。 • 模型拥有大量参数、表现力强。 • 训练数据少。
过拟合代码实现
创建文件overfit_weight_decay.py 添加代码如下
# coding: utf-8
import os
import syssys.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(normalizeTrue)# 为了再现过拟合减少学习数据
x_train x_train[:300]
t_train t_train[:300]# weight decay权值衰减的设定
#weight_decay_lambda 0 # 不使用权值衰减的情况
weight_decay_lambda 0.1
# network MultiLayerNet(input_size784, hidden_size_list[100, 100, 100, 100, 100, 100], output_size10,weight_decay_lambdaweight_decay_lambda)
optimizer SGD(lr0.01)max_epochs 201
train_size x_train.shape[0]
batch_size 100train_loss_list []
train_acc_list []
test_acc_list []iter_per_epoch max(train_size / batch_size, 1)
epoch_cnt 0for 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 1if epoch_cnt max_epochs:break# 3.绘制图形
markers {train: o, test: s}
x np.arange(max_epochs)
plt.plot(x, train_acc_list, markero, labeltrain, markevery10)
plt.plot(x, test_acc_list, markers, labeltest, markevery10)
plt.xlabel(epochs)
plt.ylabel(accuracy)
plt.ylim(0, 1.0)
plt.legend(loclower right)
plt.show()运行结果
过了 100 个 epoch 左右后用训练数据测量到的识别精度几乎都为100%。但是对于测试数据离 100% 的识别精度还有较大的差距。如此大的识别精度差距是只拟合了训练数据的结果。从图中可知模型对训练时没有使用的一般数据测试数据拟合得不是很好。
2权值衰减
权值衰减是一直以来经常被使用的一种抑制过拟合的方法。该方法通过在学习的过程中对大的权重进行惩罚来抑制过拟合。很多过拟合原本就是因为权重参数取值过大才发生的。
对于刚刚进行的实验应用λ 0.1的权值衰减。
虽然训练数据的识别精度和测试数据的识别精度之间有差距但是与没有使用权值衰减相比差距变小了。
3Dropout
Dropout 是一种在学习的过程中随机删除神经元的方法。训练时随机选出隐藏层的神经元然后将其删除。
在common文件夹下创建文件multi_layer_net_extend.py 添加代码如下
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
from collections import OrderedDict
from common.layers import *
from common.gradient import numerical_gradientclass MultiLayerNetExtend:扩展版的全连接的多层神经网络具有Weiht Decay、Dropout、Batch Normalization的功能Parameters----------input_size : 输入大小MNIST的情况下为784hidden_size_list : 隐藏层的神经元数量的列表e.g. [100, 100, 100]output_size : 输出大小MNIST的情况下为10activation : relu or sigmoidweight_init_std : 指定权重的标准差e.g. 0.01指定relu或he的情况下设定“He的初始值”指定sigmoid或xavier的情况下设定“Xavier的初始值”weight_decay_lambda : Weight DecayL2范数的强度use_dropout: 是否使用Dropoutdropout_ration : Dropout的比例use_batchNorm: 是否使用Batch Normalizationdef __init__(self, input_size, hidden_size_list, output_size,activationrelu, weight_init_stdrelu, weight_decay_lambda0, use_dropout False, dropout_ration 0.5, use_batchnormFalse):self.input_size input_sizeself.output_size output_sizeself.hidden_size_list hidden_size_listself.hidden_layer_num len(hidden_size_list)self.use_dropout use_dropoutself.weight_decay_lambda weight_decay_lambdaself.use_batchnorm use_batchnormself.params {}# 初始化权重self.__init_weight(weight_init_std)# 生成层activation_layer {sigmoid: Sigmoid, relu: Relu}self.layers OrderedDict()for idx in range(1, self.hidden_layer_num1):self.layers[Affine str(idx)] Affine(self.params[W str(idx)],self.params[b str(idx)])if self.use_batchnorm:self.params[gamma str(idx)] np.ones(hidden_size_list[idx-1])self.params[beta str(idx)] np.zeros(hidden_size_list[idx-1])self.layers[BatchNorm str(idx)] BatchNormalization(self.params[gamma str(idx)], self.params[beta str(idx)])self.layers[Activation_function str(idx)] activation_layer[activation]()if self.use_dropout:self.layers[Dropout str(idx)] Dropout(dropout_ration)idx self.hidden_layer_num 1self.layers[Affine str(idx)] Affine(self.params[W str(idx)], self.params[b str(idx)])self.last_layer SoftmaxWithLoss()def __init_weight(self, weight_init_std):设定权重的初始值Parameters----------weight_init_std : 指定权重的标准差e.g. 0.01指定relu或he的情况下设定“He的初始值”指定sigmoid或xavier的情况下设定“Xavier的初始值”all_size_list [self.input_size] self.hidden_size_list [self.output_size]for idx in range(1, len(all_size_list)):scale weight_init_stdif str(weight_init_std).lower() in (relu, he):scale np.sqrt(2.0 / all_size_list[idx - 1]) # 使用ReLU的情况下推荐的初始值elif str(weight_init_std).lower() in (sigmoid, xavier):scale np.sqrt(1.0 / all_size_list[idx - 1]) # 使用sigmoid的情况下推荐的初始值self.params[W str(idx)] scale * np.random.randn(all_size_list[idx-1], all_size_list[idx])self.params[b str(idx)] np.zeros(all_size_list[idx])def predict(self, x, train_flgFalse):for key, layer in self.layers.items():if Dropout in key or BatchNorm in key:x layer.forward(x, train_flg)else:x layer.forward(x)return xdef loss(self, x, t, train_flgFalse):求损失函数参数x是输入数据t是教师标签y self.predict(x, train_flg)weight_decay 0for idx in range(1, self.hidden_layer_num 2):W self.params[W str(idx)]weight_decay 0.5 * self.weight_decay_lambda * np.sum(W**2)return self.last_layer.forward(y, t) weight_decaydef accuracy(self, X, T):Y self.predict(X, train_flgFalse)Y np.argmax(Y, axis1)if T.ndim ! 1 : T np.argmax(T, axis1)accuracy np.sum(Y T) / float(X.shape[0])return accuracydef numerical_gradient(self, X, T):求梯度数值微分Parameters----------X : 输入数据T : 教师标签Returns-------具有各层的梯度的字典变量grads[W1]、grads[W2]、...是各层的权重grads[b1]、grads[b2]、...是各层的偏置loss_W lambda W: self.loss(X, T, train_flgTrue)grads {}for idx in range(1, self.hidden_layer_num2):grads[W str(idx)] numerical_gradient(loss_W, self.params[W str(idx)])grads[b str(idx)] numerical_gradient(loss_W, self.params[b str(idx)])if self.use_batchnorm and idx ! self.hidden_layer_num1:grads[gamma str(idx)] numerical_gradient(loss_W, self.params[gamma str(idx)])grads[beta str(idx)] numerical_gradient(loss_W, self.params[beta str(idx)])return gradsdef gradient(self, x, t):# forwardself.loss(x, t, train_flgTrue)# backwarddout 1dout self.last_layer.backward(dout)layers list(self.layers.values())layers.reverse()for layer in layers:dout layer.backward(dout)# 设定grads {}for idx in range(1, self.hidden_layer_num2):grads[W str(idx)] self.layers[Affine str(idx)].dW self.weight_decay_lambda * self.params[W str(idx)]grads[b str(idx)] self.layers[Affine str(idx)].dbif self.use_batchnorm and idx ! self.hidden_layer_num1:grads[gamma str(idx)] self.layers[BatchNorm str(idx)].dgammagrads[beta str(idx)] self.layers[BatchNorm str(idx)].dbetareturn grads在common文件夹下创建文件layers.py 添加Dropout类
完整layers.py如下
# coding: utf-8
import numpy as np
from common.functions import *
from common.util import im2col, col2imclass Relu:def __init__(self):self.mask Nonedef forward(self, x):self.mask (x 0)out x.copy()out[self.mask] 0return outdef backward(self, dout):dout[self.mask] 0dx doutreturn dxclass Sigmoid:def __init__(self):self.out Nonedef forward(self, x):out sigmoid(x)self.out outreturn outdef backward(self, dout):dx dout * (1.0 - self.out) * self.outreturn dxclass Affine:def __init__(self, W, b):self.W Wself.b bself.x Noneself.original_x_shape None# 权重和偏置参数的导数self.dW Noneself.db Nonedef forward(self, x):# 对应张量self.original_x_shape x.shapex x.reshape(x.shape[0], -1)self.x xout np.dot(self.x, self.W) self.breturn outdef backward(self, dout):dx np.dot(dout, self.W.T)self.dW np.dot(self.x.T, dout)self.db np.sum(dout, axis0)dx dx.reshape(*self.original_x_shape) # 还原输入数据的形状对应张量return dxclass SoftmaxWithLoss:def __init__(self):self.loss Noneself.y None # softmax的输出self.t None # 监督数据def forward(self, x, t):self.t tself.y softmax(x)self.loss cross_entropy_error(self.y, self.t)return self.lossdef backward(self, dout1):batch_size self.t.shape[0]if self.t.size self.y.size: # 监督数据是one-hot-vector的情况dx (self.y - self.t) / batch_sizeelse:dx self.y.copy()dx[np.arange(batch_size), self.t] - 1dx dx / batch_sizereturn dxclass Dropout:http://arxiv.org/abs/1207.0580def __init__(self, dropout_ratio0.5):self.dropout_ratio dropout_ratioself.mask Nonedef forward(self, x, train_flgTrue):if train_flg:self.mask np.random.rand(*x.shape) self.dropout_ratioreturn x * self.maskelse:return x * (1.0 - self.dropout_ratio)def backward(self, dout):return dout * self.maskclass BatchNormalization:http://arxiv.org/abs/1502.03167def __init__(self, gamma, beta, momentum0.9, running_meanNone, running_varNone):self.gamma gammaself.beta betaself.momentum momentumself.input_shape None # Conv层的情况下为4维全连接层的情况下为2维 # 测试时使用的平均值和方差self.running_mean running_meanself.running_var running_var # backward时使用的中间数据self.batch_size Noneself.xc Noneself.std Noneself.dgamma Noneself.dbeta Nonedef forward(self, x, train_flgTrue):self.input_shape x.shapeif x.ndim ! 2:N, C, H, W x.shapex x.reshape(N, -1)out self.__forward(x, train_flg)return out.reshape(*self.input_shape)def __forward(self, x, train_flg):if self.running_mean is None:N, D x.shapeself.running_mean np.zeros(D)self.running_var np.zeros(D)if train_flg:mu x.mean(axis0)xc x - muvar np.mean(xc**2, axis0)std np.sqrt(var 10e-7)xn xc / stdself.batch_size x.shape[0]self.xc xcself.xn xnself.std stdself.running_mean self.momentum * self.running_mean (1-self.momentum) * muself.running_var self.momentum * self.running_var (1-self.momentum) * var else:xc x - self.running_meanxn xc / ((np.sqrt(self.running_var 10e-7)))out self.gamma * xn self.beta return outdef backward(self, dout):if dout.ndim ! 2:N, C, H, W dout.shapedout dout.reshape(N, -1)dx self.__backward(dout)dx dx.reshape(*self.input_shape)return dxdef __backward(self, dout):dbeta dout.sum(axis0)dgamma np.sum(self.xn * dout, axis0)dxn self.gamma * doutdxc dxn / self.stddstd -np.sum((dxn * self.xc) / (self.std * self.std), axis0)dvar 0.5 * dstd / self.stddxc (2.0 / self.batch_size) * self.xc * dvardmu np.sum(dxc, axis0)dx dxc - dmu / self.batch_sizeself.dgamma dgammaself.dbeta dbetareturn dxclass Convolution:def __init__(self, W, b, stride1, pad0):self.W Wself.b bself.stride strideself.pad pad# 中间数据backward时使用self.x None self.col Noneself.col_W None# 权重和偏置参数的梯度self.dW Noneself.db Nonedef forward(self, x):FN, C, FH, FW self.W.shapeN, C, H, W x.shapeout_h 1 int((H 2*self.pad - FH) / self.stride)out_w 1 int((W 2*self.pad - FW) / self.stride)col im2col(x, FH, FW, self.stride, self.pad)col_W self.W.reshape(FN, -1).Tout np.dot(col, col_W) self.bout out.reshape(N, out_h, out_w, -1).transpose(0, 3, 1, 2)self.x xself.col colself.col_W col_Wreturn outdef backward(self, dout):FN, C, FH, FW self.W.shapedout dout.transpose(0,2,3,1).reshape(-1, FN)self.db np.sum(dout, axis0)self.dW np.dot(self.col.T, dout)self.dW self.dW.transpose(1, 0).reshape(FN, C, FH, FW)dcol np.dot(dout, self.col_W.T)dx col2im(dcol, self.x.shape, FH, FW, self.stride, self.pad)return dxclass Pooling:def __init__(self, pool_h, pool_w, stride1, pad0):self.pool_h pool_hself.pool_w pool_wself.stride strideself.pad padself.x Noneself.arg_max Nonedef forward(self, x):N, C, H, W x.shapeout_h int(1 (H - self.pool_h) / self.stride)out_w int(1 (W - self.pool_w) / self.stride)col im2col(x, self.pool_h, self.pool_w, self.stride, self.pad)col col.reshape(-1, self.pool_h*self.pool_w)arg_max np.argmax(col, axis1)out np.max(col, axis1)out out.reshape(N, out_h, out_w, C).transpose(0, 3, 1, 2)self.x xself.arg_max arg_maxreturn outdef backward(self, dout):dout dout.transpose(0, 2, 3, 1)pool_size self.pool_h * self.pool_wdmax np.zeros((dout.size, pool_size))dmax[np.arange(self.arg_max.size), self.arg_max.flatten()] dout.flatten()dmax dmax.reshape(dout.shape (pool_size,)) dcol dmax.reshape(dmax.shape[0] * dmax.shape[1] * dmax.shape[2], -1)dx col2im(dcol, self.x.shape, self.pool_h, self.pool_w, self.stride, self.pad)return dx
common下创建文件trainer.py 添加代码如下
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
from common.optimizer import *class Trainer:进行神经网络的训练的类def __init__(self, network, x_train, t_train, x_test, t_test,epochs20, mini_batch_size100,optimizerSGD, optimizer_param{lr:0.01}, evaluate_sample_num_per_epochNone, verboseTrue):self.network networkself.verbose verboseself.x_train x_trainself.t_train t_trainself.x_test x_testself.t_test t_testself.epochs epochsself.batch_size mini_batch_sizeself.evaluate_sample_num_per_epoch evaluate_sample_num_per_epoch# optimzeroptimizer_class_dict {sgd:SGD, momentum:Momentum, nesterov:Nesterov,adagrad:AdaGrad, rmsprpo:RMSprop, adam:Adam}self.optimizer optimizer_class_dict[optimizer.lower()](**optimizer_param)self.train_size x_train.shape[0]self.iter_per_epoch max(self.train_size / mini_batch_size, 1)self.max_iter int(epochs * self.iter_per_epoch)self.current_iter 0self.current_epoch 0self.train_loss_list []self.train_acc_list []self.test_acc_list []def train_step(self):batch_mask np.random.choice(self.train_size, self.batch_size)x_batch self.x_train[batch_mask]t_batch self.t_train[batch_mask]grads self.network.gradient(x_batch, t_batch)self.optimizer.update(self.network.params, grads)loss self.network.loss(x_batch, t_batch)self.train_loss_list.append(loss)if self.verbose: print(train loss: str(loss))if self.current_iter % self.iter_per_epoch 0:self.current_epoch 1x_train_sample, t_train_sample self.x_train, self.t_trainx_test_sample, t_test_sample self.x_test, self.t_testif not self.evaluate_sample_num_per_epoch is None:t self.evaluate_sample_num_per_epochx_train_sample, t_train_sample self.x_train[:t], self.t_train[:t]x_test_sample, t_test_sample self.x_test[:t], self.t_test[:t]train_acc self.network.accuracy(x_train_sample, t_train_sample)test_acc self.network.accuracy(x_test_sample, t_test_sample)self.train_acc_list.append(train_acc)self.test_acc_list.append(test_acc)if self.verbose: print( epoch: str(self.current_epoch) , train acc: str(train_acc) , test acc: str(test_acc) )self.current_iter 1def train(self):for i in range(self.max_iter):self.train_step()test_acc self.network.accuracy(self.x_test, self.t_test)if self.verbose:print( Final Test Accuracy )print(test acc: str(test_acc))
正向传播时传递了信号的神经元反向传播时按原样传递信号正向传播时没有传递信号的神经元反向传播时信号将停在那里。
使用MNIST数据集进行验证
创建文件overfit_dropout.py 添加代码如下
# 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(normalizeTrue)# 为了再现过拟合减少学习数据
x_train x_train[:300]
t_train t_train[:300]# 设定是否使用Dropuout以及比例
use_dropout True # 不使用Dropout的情况下为False
dropout_ratio 0.2
# network MultiLayerNetExtend(input_size784, hidden_size_list[100, 100, 100, 100, 100, 100],output_size10, use_dropoutuse_dropout, dropout_rationdropout_ratio)
trainer Trainer(network, x_train, t_train, x_test, t_test,epochs301, mini_batch_size100,optimizersgd, optimizer_param{lr: 0.01}, verboseTrue)
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, markero, labeltrain, markevery10)
plt.plot(x, test_acc_list, markers, labeltest, markevery10)
plt.xlabel(epochs)
plt.ylabel(accuracy)
plt.ylim(0, 1.0)
plt.legend(loclower right)
plt.show()运行结果
通过使用Dropout训练数据和测试数据的识别精度的差距变小了。并且训练数据也没有到达100%的识别精度。像这样通过使用Dropout即便是表现力强的网络也可以抑制过拟合。
4集成学习
机器学习中经常使用集成学习。所谓集成学习就是让多个模型单独进行学习推理时再取多个模型的输出的平均值。用神经网络的语境来说比如准备5个结构相同或者类似的网络分别进行学习测试时以这5个网络的输出的平均值作为答案。
通过进行集成学习神经网络的识别精度可以提高好几个百分点。
5.超参数的验证
超参数是指比如各层的神经元数量、batch大小、参数更新时的学习率或权值衰减等。如果这些超参数没有设置合适的值模型的性能就会很差。虽然超参数的取值非常重要但是在决定超参数的过程中一般会伴随很多的试错。
1验证数据
不能使用测试数据评估超参数的性能。
因为如果使用测试数据调整超参数超参数的值会对测试数据发生过拟合。换句话说用测试数据确认超参数的值的“好坏”就会导致超参数的值被调整为只拟合测试数据。这样的话可能就会得到不能拟合其他数据、泛化能力低的模型。
因此调整超参数时必须使用超参数专用的确认数据。用于调整超参数的数据一般称为验证数据
训练数据用于参数权重和偏置的学习验证数据用于超参数的性能评估。
2超参数的最优化
进行超参数的最优化时逐渐缩小超参数的“好值”的存在范围非常重要。所谓逐渐缩小范围是指一开始先大致设定一个范围从这个范围中随机选出一个超参数采样用这个采样到的值进行识别精度的评估然后多次重复该操作观察识别精度的结果根据这个结果缩小超参数的“好值”的范围。通过重复这一操作就可以逐渐确定超参数的合适范围。
3步骤
步骤0 设定超参数的范围。 步骤1 从设定的超参数范围中随机采样。 步骤2 使用步骤1中采样到的超参数的值进行学习通过验证数据评估识别精度但是要将epoch设置得很小。 步骤3 重复步骤1和步骤2100次等根据它们的识别精度的结果缩小超参数的范围。
在超参数的最优化中如果需要更精炼的方法可以使用贝叶斯最优化
4超参数最优化的实现
创建文件hyperparameter_optimization.py 添加代码如下
# 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(normalizeTrue)# 为了实现高速化减少训练数据
x_train x_train[:500]
t_train t_train[:500]# 分割验证数据
validation_rate 0.20
validation_num 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:]x_val x_train[:int(validation_num)]
t_val t_train[:int(validation_num)]
x_train x_train[int(validation_num):]
t_train t_train[int(validation_num):]def __train(lr, weight_decay, epocs50):network MultiLayerNet(input_size784, hidden_size_list[100, 100, 100, 100, 100, 100],output_size10, weight_decay_lambdaweight_decay)trainer Trainer(network, x_train, t_train, x_val, t_val,epochsepocs, mini_batch_size100,optimizersgd, optimizer_param{lr: lr}, verboseFalse)trainer.train()return trainer.test_acc_list, trainer.train_acc_list# 超参数的随机搜索
optimization_trial 100
results_val {}
results_train {}
for _ in range(optimization_trial):# 指定搜索的超参数的范围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_listresults_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 0for key, val_acc_list in sorted(results_val.items(), keylambda x:x[1][-1], reverseTrue):print(Best- str(i1) (val acc: str(val_acc_list[-1]) ) | key)plt.subplot(row_num, col_num, i1)plt.title(Best- str(i1))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 1if i graph_draw_num:breakplt.show()
运行结果
学习率在0.001到0.01、权值衰减系数在10−8到10−6之间时学习可以顺利进行。像这样观察可以使学习顺利进行的超参数的范围从而缩小值的范围。然后在这个缩小的范围中重复相同的操作。学习率在0.001到0.01、权值衰减系数在10−8到10−6之间时学习可以顺利进行。像这样观察可以使学习顺利进行的超参数的范围从而缩小值的范围。然后在这个缩小的范围中重复相同的操作。