深度学习的正则化技术综述附python代码

Introduction

数据科学专业人员面临的最常见问题之一是避免过度拟合。 您是否遇到过您的模型在训练数据上表现异常但无法预测测试数据的情况。 或者你在公共排行榜的竞争中处于领先地位,但在最终排名中只有数百个名额? 好吧 - 这是给你的文章!

避免过度拟合可以单独提高我们模型的性能。

在这里插入图片描述

在本文中,我们将理解过度拟合的概念以及正则化如何帮助克服同一问题。 然后,我们将研究一些不同的正则化技术,并在python中进行案例研究,以进一步巩固这些概念。

目录

什么是正规化?
正规化如何帮助减少过度拟合?
深度学习中的不同正则化技巧
L2和L1正则化
退出
数据增加
提前停止
使用Keras进行MNIST数据的案例研究
#####什么是正规化?
在我们深入研究这个主题之前,请看一下这个图像:
在这里插入图片描述

你以前见过这张照片吗? 当我们在此图像中向右移动时,我们的模型试图从训练数据中很好地学习细节和噪声,这最终导致对看不见的数据的不良表现。

换句话说,在向右移动时,模型的复杂性增加,使得训练误差减小但测试误差不会。 如下图所示。
在这里插入图片描述
如果你以前建立过神经网络,你就会知道它们有多复杂。 这使他们更容易过度拟合。
在这里插入图片描述

正则化是一种对学习算法进行细微修改以使模型更好地概括的技术。 这反过来又改善了模型在看不见的数据上的性能。

正规化如何帮助减少过度拟合?

让我们考虑一个过度拟合训练数据的神经网络,如下图所示。
在这里插入图片描述

如果您已经在机器学习中研究了正则化的概念,那么您将有一个公平的想法,即正则化会对系数进行惩罚。 在深度学习中,它实际上会惩罚节点的权重矩阵。

假设我们的正则化系数太高,以至于一些权重矩阵几乎等于零。
在这里插入图片描述

扫描二维码关注公众号,回复: 6009979 查看本文章

这将导致更简单的线性网络和训练数据的轻微不足。

正则化系数的这种大值不是那么有用。 我们需要优化正则化系数的值,以获得如下图所示的良好拟合模型。

在这里插入图片描述

深度学习中的不同正则化技术

现在我们已经了解了正则化如何帮助减少过度拟合,我们将学习一些不同的技术,以便在深度学习中应用正则化。

L2&L1正则化

L1和L2是最常见的正则化类型。 这些通过添加另一个称为正则化项的术语来更新一般成本函数。

成本函数=损失(比如二元交叉熵)+正则化项

由于该正则化项的增加,权重矩阵的值减小,因为它假设具有较小权重矩阵的神经网络导致更简单的模型。 因此,它也将在很大程度上减少过度拟合。

但是,该正则化项在L1和L2中不同。

在L2中,我们有:

在这里插入图片描述

这里,lambda是正则化参数。 它是超参数,其值已针对更好的结果进行了优化。 L2正则化也称为权重衰减,因为它迫使权重向零衰减(但不完全为零)。

在L1中,我们有:在这里插入图片描述

在这里,我们惩罚权重的绝对值。 与L2不同,这里的权重可以减少到零。 因此,当我们尝试压缩模型时,它非常有用。 否则,我们通常更喜欢L2而不是它。

在keras中,我们可以使用正则化器直接将正则化应用于任何层。

下面是将L2正则化应用于Dense层的示例代码。

from keras import regularizers
model.add(Dense(64, input_dim=64,
                kernel_regularizer=regularizers.l2(0.01)

注意:这里值0.01是正则化参数的值,即lambda,我们需要进一步优化。 我们可以使用网格搜索方法对其进行优化。

同样,我们也可以应用L1正则化。 我们将在本文后面的案例研究中更详细地研究这一点。

Dropout

这是最有趣的正则化技术之一。 它还产生非常好的结果,因此是深度学习领域中最常用的正则化技术。

为了解Dropout,我们假设我们的神经网络结构类似于下图所示:

在这里插入图片描述
那么辍学者呢? 在每次迭代时,它会随机选择一些节点并将它们与所有传入和传出连接一起删除,如下所示。
在这里插入图片描述
因此,每次迭代都有一组不同的节点,这会产生一组不同的输出。 它也可以被认为是机器学习中的集成技术。

集合模型通常比单个模型表现更好,因为它们捕获更多随机性。 类似地,丢失也比正常的神经网络模型表现更好。

选择应丢弃多少节点的这种概率是丢失函数的超参数。 如上图所示,dropout可以应用于隐藏层和输入层。在这里插入图片描述
由于这些原因,当我们具有大的神经网络结构以引入更多随机性时,通常优选丢失。

在keras中,我们可以使用keras核心层实现dropout。 下面是它的python代码:

from keras.layers.core import Dropout

model = Sequential([
 Dense(output_dim=hidden1_num_units, input_dim=input_num_units, activation='relu'),
 Dropout(0.25),

Dense(output_dim=output_num_units, input_dim=hidden5_num_units, activation='softmax'),
 ])

如您所见,我们将0.25定义为丢弃的概率。 我们可以使用网格搜索方法进一步调整它以获得更好的结果。

数据扩充

减少过度拟合的最简单方法是增加训练数据的大小。 在机器学习中,由于标签数据成本太高,我们无法增加培训数据的大小。

但是,现在让我们考虑一下我们正在处理图像。 在这种情况下,有几种方法可以增加训练数据的大小 - 旋转图像,翻转,缩放,移位等。在下图中,对手写数字数据集进行了一些转换。
在这里插入图片描述

这种技术称为数据增强。 这通常会提高模型的准确性。 它可以被视为一个强制性的技巧,以改善我们的预测。

在keras中,我们可以使用ImageDataGenerator执行所有这些转换。 它有一个很大的参数列表,您可以使用它们来预处理您的训练数据。

下面是实现它的示例代码。

from keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(horizontal flip=True)
datagen.fit(train)

提早停止

早期停止是一种交叉验证策略,我们将训练集的一部分作为验证集。 当我们发现验证集上的性能变差时,我们会立即停止对模型的培训。 这被称为提前停止。在这里插入图片描述

在上图中,我们将停止在虚线处进行训练,因为之后我们的模型将开始过度拟合训练数据。

在keras中,我们可以使用callbacks函数应用早期停止。 下面是它的示例代码。

from keras.callbacks import EarlyStopping

EarlyStopping(monitor='val_err', patience=5)

这里,monitor表示需要监视的数量,'val_err’表示验证错误。

耐心表示没有进一步改进的时期数,之后训练将被停止。为了更好地理解,让我们再看一下上面的图像。在虚线之后,每个时期将导致更高的验证错误值。因此,在虚线之后的5个时期(因为我们的耐心等于5),我们的模型将停止,因为没有看到进一步的改善。

注意:有可能在5个时期之后(这是为一般耐心定义的值),模型可能再次开始改进,验证错误也开始减少。因此,在调整这个超参数时我们需要格外小心。

关于使用keras的MNIST数据的案例研究

到目前为止,您应该对我们所经历的不同技术有一个理论上的理解。我们现在将这些知识应用于我们的深度学习实践问题 - 识别数字。下载数据集后,请按照以下代码开始!首先,我们将导入一些基本库。

%pylab inline

import numpy as np
import pandas as pd
from scipy.misc import imread
from sklearn.metrics import accuracy_score

from matplotlib import pyplot

import tensorflow as tf
import keras

# To stop potential randomness
seed = 128
rng = np.random.RandomState(seed)

载入数据集

root_dir = os.path.abspath('/Users/shubhamjain/Downloads/AV/identify the digits/')
data_dir = os.path.join(root_dir, 'data')
sub_dir = os.path.join(root_dir, 'sub')

## reading train file only
train = pd.read_csv(os.path.join(data_dir, 'Train', 'train.csv'))
train.head()

在这里插入图片描述

现在看看我们的一些图片。

img_name = rng.choice(train.filename)

filepath = os.path.join(data_dir, 'Train', 'Images', 'train', img_name)

img = imread(filepath, flatten=True)

pylab.imshow(img, cmap='gray')
pylab.axis('off')
pylab.show()

在这里插入图片描述

#storing images in numpy arrays
temp = []
for img_name in train.filename:
 image_path = os.path.join(data_dir, 'Train', 'Images', 'train', img_name)
 img = imread(image_path, flatten=True)
 img = img.astype('float32')
 temp.append(img)
 
x_train = np.stack(temp)

x_train /= 255.0
x_train = x_train.reshape(-1, 784).astype('float32')

y_train = keras.utils.np_utils.to_categorical(train.label.values)

创建验证数据集,以优化我们的模型以获得更好的分数。 我们将使用70:30的列车和验证数据集比率。

split_size = int(x_train.shape[0]*0.7)

x_train, x_test = x_train[:split_size], x_train[split_size:]
y_train, y_test = y_train[:split_size], y_train[split_size:]

首先,让我们从构建一个包含5个隐藏层的简单神经网络开始,每个隐藏层有500个节点。

# import keras modules
from keras.models import Sequential
from keras.layers import Dense
# define vars
input_num_units = 784
hidden1_num_units = 500
hidden2_num_units = 500
hidden3_num_units = 500
hidden4_num_units = 500
hidden5_num_units = 500
output_num_units = 10

epochs = 10
batch_size = 128

model = Sequential([
 Dense(output_dim=hidden1_num_units, input_dim=input_num_units, activation='relu'),
 Dense(output_dim=hidden2_num_units, input_dim=hidden1_num_units, activation='relu'),
 Dense(output_dim=hidden3_num_units, input_dim=hidden2_num_units, activation='relu'),
 Dense(output_dim=hidden4_num_units, input_dim=hidden3_num_units, activation='relu'),
 Dense(output_dim=hidden5_num_units, input_dim=hidden4_num_units, activation='relu'),

Dense(output_dim=output_num_units, input_dim=hidden5_num_units, activation='softmax'),
 ])

请注意,我们只运行了10个时代。 让我们快速检查一下我们模型的性能。

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

trained_model_5d = model.fit(x_train, y_train, nb_epoch=epochs, batch_size=batch_size, validation_data=(x_test, y_test))

在这里插入图片描述
现在,让我们尝试L2正则化器,检查它是否比简单的神经网络模型提供更好的结果。

from keras import regularizers

model = Sequential([
 Dense(output_dim=hidden1_num_units, input_dim=input_num_units, activation='relu',
 kernel_regularizer=regularizers.l2(0.0001)),
 Dense(output_dim=hidden2_num_units, input_dim=hidden1_num_units, activation='relu',
 kernel_regularizer=regularizers.l2(0.0001)),
 Dense(output_dim=hidden3_num_units, input_dim=hidden2_num_units, activation='relu',
 kernel_regularizer=regularizers.l2(0.0001)),
 Dense(output_dim=hidden4_num_units, input_dim=hidden3_num_units, activation='relu',
 kernel_regularizer=regularizers.l2(0.0001)),
 Dense(output_dim=hidden5_num_units, input_dim=hidden4_num_units, activation='relu',
 kernel_regularizer=regularizers.l2(0.0001)),

Dense(output_dim=output_num_units, input_dim=hidden5_num_units, activation='softmax'),
 ])
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

trained_model_5d = model.fit(x_train, y_train, nb_epoch=epochs, batch_size=batch_size, validation_data=(x_test, y_test))

在这里插入图片描述

请注意,lambda的值等于0.0001。 大! 我们刚刚获得的精度高于我们之前的NN模型。

现在,让我们尝试L1正则化技术。

## l1

model = Sequential([
 Dense(output_dim=hidden1_num_units, input_dim=input_num_units, activation='relu',
 kernel_regularizer=regularizers.l1(0.0001)),
 Dense(output_dim=hidden2_num_units, input_dim=hidden1_num_units, activation='relu',
 kernel_regularizer=regularizers.l1(0.0001)),
 Dense(output_dim=hidden3_num_units, input_dim=hidden2_num_units, activation='relu',
 kernel_regularizer=regularizers.l1(0.0001)),
 Dense(output_dim=hidden4_num_units, input_dim=hidden3_num_units, activation='relu',
 kernel_regularizer=regularizers.l1(0.0001)),
 Dense(output_dim=hidden5_num_units, input_dim=hidden4_num_units, activation='relu',
 kernel_regularizer=regularizers.l1(0.0001)),

Dense(output_dim=output_num_units, input_dim=hidden5_num_units, activation='softmax'),
 ])
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
trained_model_5d = model.fit(x_train, y_train, nb_epoch=epochs, batch_size=batch_size, validation_data=(x_test, y_test))

在这里插入图片描述

这并没有显示出对以前型号的任何改进。 让我们跳到dropout技术。

## dropout

from keras.layers.core import Dropout
model = Sequential([
 Dense(output_dim=hidden1_num_units, input_dim=input_num_units, activation='relu'),
 Dropout(0.25),
 Dense(output_dim=hidden2_num_units, input_dim=hidden1_num_units, activation='relu'),
 Dropout(0.25),
 Dense(output_dim=hidden3_num_units, input_dim=hidden2_num_units, activation='relu'),
 Dropout(0.25),
 Dense(output_dim=hidden4_num_units, input_dim=hidden3_num_units, activation='relu'),
 Dropout(0.25),
 Dense(output_dim=hidden5_num_units, input_dim=hidden4_num_units, activation='relu'),
 Dropout(0.25),

Dense(output_dim=output_num_units, input_dim=hidden5_num_units, activation='softmax'),
 ])
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
trained_model_5d = model.fit(x_train, y_train, nb_epoch=epochs, batch_size=batch_size, validation_data=(x_test, y_test))

在这里插入图片描述

不错! Dropout也比我们简单的NN模型有了一些改进。

现在,让我们尝试数据扩充。

from keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(zca_whitening=True)
# loading data
train = pd.read_csv(os.path.join(data_dir, 'Train', 'train.csv'))
temp = []
for img_name in train.filename:
 image_path = os.path.join(data_dir, 'Train', 'Images', 'train', img_name)
 img = imread(image_path, flatten=True)
 img = img.astype('float32')
 temp.append(img)
 
x_train = np.stack(temp)

X_train = x_train.reshape(x_train.shape[0], 1, 28, 28)

X_train = X_train.astype('float32')

Now, fit the training data in order to augment.

# fit parameters from data
datagen.fit(X_train)

在这里,我使用了zca_whitening作为参数,它突出显示了每个数字的轮廓,如下图所示。
在这里插入图片描述

## splitting
y_train = keras.utils.np_utils.to_categorical(train.label.values)
split_size = int(x_train.shape[0]*0.7)

x_train, x_test = X_train[:split_size], X_train[split_size:]
y_train, y_test = y_train[:split_size], y_train[split_size:]
## reshaping
x_train=np.reshape(x_train,(x_train.shape[0],-1))/255
x_test=np.reshape(x_test,(x_test.shape[0],-1))/255
## structure using dropout
from keras.layers.core import Dropout
model = Sequential([
 Dense(output_dim=hidden1_num_units, input_dim=input_num_units, activation='relu'),
 Dropout(0.25),
 Dense(output_dim=hidden2_num_units, input_dim=hidden1_num_units, activation='relu'),
 Dropout(0.25),
 Dense(output_dim=hidden3_num_units, input_dim=hidden2_num_units, activation='relu'),
 Dropout(0.25),
 Dense(output_dim=hidden4_num_units, input_dim=hidden3_num_units, activation='relu'),
 Dropout(0.25),
 Dense(output_dim=hidden5_num_units, input_dim=hidden4_num_units, activation='relu'),
 Dropout(0.25),

Dense(output_dim=output_num_units, input_dim=hidden5_num_units, activation='softmax'),
 ])
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
trained_model_5d = model.fit(x_train, y_train, nb_epoch=epochs, batch_size=batch_size, validation_data=(x_test, y_test))

在这里插入图片描述
哇! 我们的准确度得分有了很大的提升。 好的是它每次都有效。 我们只需根据数据集中的图像选择合适的参数。

现在,让我们试试我们的最终技术 - 提前停止。

from keras.callbacks import EarlyStopping
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
trained_model_5d = model.fit(x_train, y_train, nb_epoch=epochs, batch_size=batch_size, validation_data=(x_test, y_test)
 , callbacks = [EarlyStopping(monitor='val_acc', patience=2)])

在这里插入图片描述

您可以看到我们的模型仅在5次迭代后停止,因为验证准确性没有提高。 如果我们为更大的历元值运行它,它会给出很好的结果。 你可以说这是一种优化时代数量值的技术。

结束注释

我希望你现在已经理解了正则化以及在深度学习模型中实现它所需的不同技术。 我强烈建议您在处理深度学习任务时应用它。 它将帮助您扩展视野并更好地理解该主题。

你觉得这篇文章有用吗? 请在下面的评论部分分享您的意见/想法。

猜你喜欢

转载自blog.csdn.net/weixin_41697507/article/details/89507971
今日推荐