深度学习入门(十):权重初始值、Batch Norm、超参数的验证

权重的参数值

在神经网络的学习中,权重的初始值特别重要。实际上,设定什么样的权重初始值,经常关系到神经网络的学习能否成功。

是否能设置为0

首先要引入权值衰减的概念。简单地说,权值衰减就是一种以减小权重参数的值为目的进行学习的方法。通过减小权重参数的值来抑制过拟合的发生。
如果想减小权重的值,一开始就将初始值设为较小的值才是正途。但是如果设为0,将无法正确进行学习。这是因为在误差反向传播法中,所有的权重值都会进行相同的更新。因此,权重被更新为相同的值,并拥有了对称的值(重复的值)。如果设置为0,就会使得神经网络拥有许多不同的权重的意义丧失了。

隐藏层的激活值的分布

观察隐藏层的激活值(激活函数的输出数据)的分布,可以获得很多启发。

import numpy as np
import matplotlib.pyplot as plt


def sigmoid(x):
    return 1 / (1 + np.exp(-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
a = np.dot(x, w)
# 将激活函数的种类也改变,来进行实验!
z = sigmoid(a)

这里假设神经网络有5层,每层有100个神经元。然后,用高斯分布随机生成1000个数据作为输入数据,并把它们传给5层神经网络。激活函数使用sigmoid函数,各层的激活值的结果保存在activations变量中。
在这里插入图片描述
从图中可知,,各层的激活值呈偏向0和1的分布。这里使用的sigmoid函数是S型函数,随着输出不断地靠近0(或者靠近1),它的导数的值逐渐接近0。因此,偏向0和1的数据分布会造成反向传播中梯度的值不断变小,最后消失。这个问题称为梯度消失。层次加深的深度学习中,梯度消失的问题可能会更加严重。
将权重的标准差设为0.01,可得到以下结果:
在这里插入图片描述
这次呈集中在0.5附近的分布。因为不像刚才的例子那样偏向0和1,所以不会发生梯度消失的问题。但是,激活值的分布有所偏向,说明在表现力上会有很大问题。因为如果有多个神经元都输出几乎相同的值,那它们就没有存在的意义了。因此,激活值在分布上有所偏向会出现“表现力受限”的问题。

接下来尝试用推荐初始值:

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

在这里插入图片描述
从这个结果可知,越是后面的层,图像变得越歪斜,但是呈现了比之前更有广度的分布。因为各层间传递的数据有适当的广度,所以sigmoid函数的表现力不受限制,有望进行高效的学习。

ReLU的权重初始值

以下是激活函数使用ReLU时激活值的分布。依次是权重初始值为标准差是0.01的高斯分布(下文简写 为“std=0.01”)时、初始值为Xavier初始值时、初始值为ReLU专用的“He初始值”时的结果。

在这里插入图片描述
当“std=0.01”时,各层的激活值非常小A。神经网络上传递的是非常小的值,说明逆向传播时权重的梯度也同样很小。这是很严重的问题,实际上学习基本上没有进展。
接下来是初始值为Xavier初始值时的结果。在这种情况下,随着层的加深,偏向一点点变大。实际上,层加深后,激活值的偏向变大,学习时会出现梯度消失的问题。而当初始值为He初始值时,各层中分布的广度相同。由于即便层加深,数据的广度也能保持不变,因此逆向传播时,也会传递合适的值。
总结一下,当激活函数使用ReLU时,权重初始值使用He初始值,当激活函数为sigmoid或tanh等S型曲线函数时,初始值使用Xavier初始值。这是目前的最佳实践。

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

基于std=0.01、Xavier初始值、He初始值进行实验,如图所示:
在这里插入图片描述
这个实验中,神经网络有5层,每层有100个神经元,激活函数使用的是ReLU。结果和刚才观察到的激活值的分布一样。
因此,逆向传播时求到的梯度也很小,权重几乎不进行更新。相反,当权重初始值为Xavier初始值和He初始值时,学习进行得很顺利。并且,我们发现He初始值时的学习进度更快一些。
综上,在神经网络的学习中,权重初始值非常重要。很多时候权重初始值的设定关系到神经网络的学习能否成功。

Batch Normalization

为了使各层拥有适当的广度,“强制性”地调整激活值的分布,Batch Normalization方法就是基于这个想法而产生的。

Batch Normalization 的算法

Batch Normalization是 2015年提出的方法。Batch Norm虽然是一个问世不久的新方法,但已经被很多研究人员和技术人员广泛使用。具有以下优点:
• 可以使学习快速进行(可以增大学习率)。
• 不那么依赖初始值(对于初始值不用那么神经质)。
• 抑制过拟合(降低Dropout等的必要性)。
如前所述,Batch Norm的思路是调整各层的激活值分布使其拥有适当的广度。为此,要向神经网络中插入对数据分布进行正规化的层,即Batch Normalization层(下文简称Batch Norm层)。
在这里插入图片描述

Batch Norm,顾名思义,以进行学习时的mini-batch为单位,按minibatch进行正规化。具体而言,就是进行使数据分布的均值为0、方差为1的正规化。数学式如下:
在这里插入图片描述
这里对mini-batch的mmm个输入数据的集合BBB求均值和方差,然后,对输入数据进行均值为0、方差为1(合适的分布)的
正规化。式中的εεε是一个微小值(比如,10e−710e-710e7等),它是为了防止出现除以0的情况。该式将mini-batch的输入数据变换为均值0、方差1的数据。通过将这个处理插入到激活函数的前面(或者后面),可以减小数据分布的偏向。
接着,Batch Norm层会对正规化后的数据进行缩放和平移的交换,可以表示如下:
在这里插入图片描述
这里,γ和βγ和βγβ是参数。一开始γ=1γ=1γ=1β=0β=0β=0,然后再通过学习调整到合适的值。
在这里插入图片描述

Batch Normalization的评估

在这里插入图片描述
图中的实线是使用了Batch Norm时的结果,虚线是没有使用Batch Norm时的结果:图的标题处标明了权重初始值的标准差

使用Batch Norm后,学习进行得更快了。接着,给予不同的初始值尺度,观察学习的过程如何变化。
几乎所有的情况下都是使用Batch Norm时学习进行得更快。同时也可以发现,实际上,在不使用Batch Norm的情况下,如果不赋予一个尺度好的初始值,学习将完全无法进行。
综上,通过使用Batch Norm,可以推动学习的进行。并且,对权重初始值变得健壮(“对初始值健壮”表示不那么依赖初始值)。Batch Norm具备了如此优良的性质,一定能应用在更多场合中。

正则化

机器学习的问题中,过拟合是一个很常见的问题。过拟合指的是只能拟合训练数据,但不能很好地拟合不包含在训练数据中的其他数据的状态。机器学习的目标是提高泛化能力,即便是没有包含在训练数据里的未观测数据,也希望模型可以进行正确的识别。

过拟合

发生过拟合的原因,主要有以下两个。
• 模型拥有大量参数、表现力强。
• 训练数据少。
这里,我们故意满足这两个条件,制造过拟合现象。
在这里插入图片描述

过了100个epoch左右后,用训练数据测量到的识别精度几乎都为100%。但是,对于测试数据,离100%的识别精度还有较大的差距。从图中可知,模型对训练时没有使用的一般数据(测试数据)拟合得不是很好。

权值衰减

权值衰减是一直以来经常被使用的一种抑制过拟合的方法。该方法通过在学习的过程中对大的权重进行惩罚,来抑制过拟合。很多过拟合原本就是因为权重参数取值过大才发生的。
对于刚刚进行的实验,应用λ=0.1的权值衰减:
在这里插入图片描述
虽然训练数据的识别精度和测试数据的识别精度之间有差距,但是与没有使用权值衰减的图相比,差距变小了。这说明过拟合受到了抑制。此外,还要注意,训练数据的识别精度没有达到100%(1.0)。

Dropout

作为抑制过拟合的方法,前面我们介绍了为损失函数加上权重的L2范数的权值衰减方法。该方法可以简单地实现,在某种程度上能够抑制过拟合。但是,如果网络的模型变得很复杂,只用权值衰减就难以应对了。
Dropout是一种在学习的过程中随机删除神经元的方法。训练时,随机选出隐藏层的神经元,然后将其删除。被删除的神经元不再进行信号的传递,如图所示。训练时,每传递一次数据,就会随机选择要删除的神经元。然后,测试时,虽然会传递所有的神经元信号,但是对于各个神经元的输出,要乘上训练时的删除比例后再输出。
在这里插入图片描述
实现代码如下:

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
            return x * self.mask
        else:
            return x * (1.0 - self.dropout_ratio)
    def backward(self, dout):
        return dout * self.mask

在这里插入图片描述
这是使用Dropout的实验,和前面的实验一样,使用7层网络(每层有100个神经元,激活函数为ReLU)。通过使用Dropout,训练数据和测试数据的识别精度的差距变小了。并且,训练数据也没有到达100%的识别精度。像这样,通过使用Dropout,即便是表现力强的网络,也可以抑制过拟合。

超参数的验证

神经网络中,除了权重和偏置等参数,超参数(hyper-parameter)也经常出现。这里所说的超参数是指,比如各层的神经元数量、batch大小、参数更新时的学习率或权值衰减等。如果这些超参数没有设置合适的值,模型的性能就会很差。虽然超参数的取值非常重要,但是在决定超参数的过程中一般会伴随很多的试错。

验证数据

之前我们使用的数据集分成了训练数据和测试数据,训练数据用于学习,测试数据用于评估泛化能力。由此,就可以评估是否只过度拟合了训练数据(是否发生了过拟合),以及泛化能力如何等。
这里要注意的是,不能使用测试数据评估超参数的性能。。这一点非常重要,但也容易被忽视。
为什么不能用测试数据评估超参数的性能呢?这是因为如果使用测试数据调整超参数,超参数的值会对测试数据发生过拟合。换句话说,用测试数据确认超参数的值的“好坏”,就会导致超参数的值被调整为只拟合测试数据。这样的话,可能就会得到不能拟合其他数据、泛化能力低的模型。
因此,调整超参数时,必须使用超参数专用的确认数据。用于调整超参数的数据,一般称为验证数据(validation data)。我们使用这个验证数据来评估超参数的好坏。
根据不同的数据集,有的会事先分成训练数据、验证数据、测试数据三部分,有的只分成训练数据和测试数据两部分,有的则不进行分割。在这种情况下,用户需要自行进行分割。这里的案例使用的是MNIST数据集。

(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:]

这里,分割训练数据前,先打乱了输入数据和教师标签。代码如下:

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, t

超参数的最优化

进行超参数的最优化时,逐渐缩小超参数的“好值”的存在范围非常重要。所谓逐渐缩小范围,是指一开始先大致设定一个范围,从这个范围中随机选出一个超参数(采样),用这个采样到的值进行识别精度的评估;;然后,多次重复该操作,观察识别精度的结果,根据这个结果缩小超参数的“好值”的范围。通过重复这一操作,就可以逐渐确定超参数的合适范围。
超参数的范围只要“大致地指定”就可以了。所谓“大致地指定”,是指像0.001到 1000 这 样 , 以“ 10的阶乘”的尺度指定范围。
在超参数的最优化中,要注意的是深度学习需要很长时间(比如,几天或几周)。因此,在超参数的搜索中,需要尽早放弃那些不符合逻辑的超参数。于是,在超参数的最优化中,减少学习的epoch,缩短一次评估所需的时间是一个不错的办法。

超参数最优化的实现

现在,我们使用MNIST数据集进行超参数的最优化。
在该实验中,权值衰减系数的初始范围为10−810^{-8}10810−410^{-4}104,学习率的初始范围为10−610^{−6}10610−210^{−2}102。此时,超参数的随机采样的代码如下所示。

weight_decay = 10 ** np.random.uniform(-8, -4)
 lr = 10 ** np.random.uniform(-6, -2)

实验结果如图示:
在这里插入图片描述

=========== Hyper-Parameter Optimization Result ===========
Best-1(val acc:0.78) | lr:0.009930232212251769, weight decay:2.203543575921212e-05
Best-2(val acc:0.72) | lr:0.008115314597108339, weight decay:6.6578078918788525e-06
Best-3(val acc:0.72) | lr:0.008019645317648724, weight decay:2.2036785045470414e-05
Best-4(val acc:0.71) | lr:0.0048542246637880695, weight decay:3.5666845492784564e-07
Best-5(val acc:0.69) | lr:0.007094936879609039, weight decay:1.6170193015695176e-05

从这个结果可以看出,学习率在实验设置的范围内,学习可以顺利进行。像这样,观察可以使学习顺利进行的超参数的范围,从而缩小值的范围。然后,在这个缩小的范围中重复相同的操作。
这样就能缩小到合适的超参数的存在范围,然后在某个阶段,选择一个最终的超参数的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值