四种抑制过拟合的方法

过拟合指的是只能拟合训练数据,但不能很好地拟合不包含训练数据的其他数据。神经网络要求模型能够具有较高的泛化能力,也就是对不包含训练数据的未观测数据也能进行正确识别。所以在训练表现力强的模型同时,抑制过拟合的技巧也很重要。

防止过拟合的方法:(1)人为增加训练数据集;(2)正则化 regularization(权值衰减);(3)Dropout;(4)早停(early stopping)

1、人为增加训练数据集

发生过拟合的原因主要有:

  • 模型拥有大量参数,表现力强;
  • 训练数据少。

所以通过增加训练数据可以抑制过拟合,提高模型的泛化能力。例如增加图像数据集可以对原始图像进行旋转、镜像。

2、正则化(权值衰减)

    权值衰减是一直以来经常被使用的一种抑制过拟合的方法。该方法通过在学习过程中对大的权重进行惩罚,来抑制过拟合。因为很多过拟合原本就是因为权重参数取值过大才发生的。

    神经网络的习目的是减小损失函数的值。这时,例如为损失函数加上权值的平方范数(L2范数)。这样就可以抑制权重变大。用符号表示的话,如果将权重记为W,L2范数的权值衰减就是\frac{1}{2}\lambda W^{2},然后将\frac{1}{2}\lambda W^{2}加到损失函数上。这里,\lambda是控制正则化强度的超参数。\lambda设置的越大,对大的权重施加惩罚就越重。此外,\frac{1}{2}\lambda W^{2}开头的\frac{1}{2}是用于将\frac{1}{2}\lambda W^{2}的求导结果变成\lambda W的调整用常量。

    对于所有权重,权值衰减方法都会为损失函数加上\frac{1}{2}\lambda W^{2}。因此在求权重梯度的计算中,要为之前的误差反向传播算法的结果加上正则化项的导数\lambda W。正则化项可以使用L1,L2,L∞,这里使用比较常用的L2。

所以用python搭建神经网络时,损失函数和计算梯度的代码要改为:

    def loss(self, x, t):
        # 前向传播
        y = self.predict(x)

        weight_decay = 0
        # 计算所有权重的L2范数
        for 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_decay


    def gradient(self, x, t):
        # 计算损失函数
        self.loss(x, t)

        # backward
        dout = 1
        dout = 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_num+2):
            grads['W' + str(idx)] = self.layers['Affine' + str(idx)].dW + self.weight_decay_lambda * self.layers['Affine' + str(idx)].W
            grads['b' + str(idx)] = self.layers['Affine' + str(idx)].db

        return grads

 

3、Dropout

       上面介绍的损失函数加上权重的L2范数的权值衰减方法,在某种程度上可以抑制过拟合。但是,如果网络模型变得复杂,只有权值衰减就显得力不从心了。在这种情况下,往往使用Dropout方法。

       Dropout是一种在学习过程中随机删除神经元的方法。训练时,随机选出隐藏层的神经元,然后将其删除。被删除的神经元不再进行信号传递。如下图所示。训练时,每传递一次数据,就会随机选择要删除的神经元。然后,测试时,虽然会传递所有的神经元信号,但是对于各个神经元的输出,要乘上训练时的删除比例后再输出。

               四种抑制过拟合的方法_第1张图片

下面来实现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

    def backward(self, dout):
        return dout * self.mask

说明:每次正向传播时,self.mask中都会以False的形式保存要删除的神经元。self.mask会随机生成和x形状相同的数组,并将值比dropout_ratio大的元素设为True。传播行为和RuLU相同。

在搭建神经网络时可以这样使用Dropout:

def __init__(self, input_size, hidden_size_list, output_size,
                 activation='relu', weight_init_std='relu', weight_decay_lambda=0, 
                 use_dropout = False, dropout_ration = 0.5):
        self.input_size = input_size
        self.output_size = output_size
        self.hidden_size_list = hidden_size_list
        self.hidden_layer_num = len(hidden_size_list)
        self.use_dropout = use_dropout
        self.weight_decay_lambda = weight_decay_lambda
        self.params = {}

        # 权重初始化方法
        self.__init_weight(weight_init_std)

        # 每层网络生成
        activation_layer = {'sigmoid': Sigmoid, 'relu': Relu}
        self.layers = OrderedDict()
        for idx in range(1, self.hidden_layer_num+1):
            self.layers['Affine' + str(idx)] = Affine(self.params['W' + str(idx)],
                                                      self.params['b' + str(idx)])

            if self.use_dropout:
                self.layers['Dropout' + str(idx)] = Dropout(dropout_ration)

        idx = self.hidden_layer_num + 1
        self.layers['Affine' + str(idx)] = Affine(self.params['W' + str(idx)], self.params['b' + str(idx)])

        self.last_layer = SoftmaxWithLoss()

也就是一个全连接层后面使用Dropout。

4、早停(early stopping)

      将数据分成训练集和验证集,训练集用来计算梯度、更新连接权和阈值;验证集用来估计误差。若训练集误差降低但验证集误差升高,则停止训练,同时返回具有最小验证集误差的连接权和阈值。

                                                                                                                 ——引自周志华老师《机器学习》一书

拓展:

       机器学习中经常使用集成学习。所谓集成学习,就是让多个模型单独进行学习,推理时再取多个模型的输出的平均值。用神经网络的语境来说,比如,准备5个结构相同的网络,分别进行学习,测试时,以这5个网络的输出的平均值作为答案。通过实验可以发现,使用集成学习,神经网络的识别精度可以提高好几个百分点。

       这个集成学习与Dropout有密切的关系。这是因为可以将Dropout理解为,通过在学习过程中随机删除神经元,从而每一次都让不同的模型进行学习。并且,推理时,通过对神经元的输出乘以删除比例(比如0.5),可以取模型的平均值。也就是说,可以理解成,Dropout将集成学习的效果通过一个网络实现了。

 

你可能感兴趣的:(深度学习入门,防止过拟合,权值衰减,Dropout,正则化)