资讯专栏INFORMATION COLUMN

使用权重正则化较少模型过拟合

neroneroffy / 641人阅读

摘要:介绍权重正则化可以减轻深度神经网络模型的过拟合问题,可以提升对新数据的泛化能力。代码展示在卷积层中使用正则化。许多正则化方法通过向训练数据添加噪声来防止过拟合。模型使用损失函数,优化器。

介绍

权重正则化可以减轻深度神经网络模型的过拟合问题,可以提升对新数据的泛化能力。有多种正则方法可供选择,如:L1L2正则化,每种方法在使用前需要超参数配置。在这篇文章中,你将学习在keras如何使用权重正则化的方法来减轻模型过拟合问题。
读完本篇文章,你将学习到:

如何在keras中使用权重正则化应用到MLP,CNN,或者LSTM神经网络任务中

一些常见论文在模型中使用权重正则化的方法和经验

通过一个案例学习如何使用权重正则化解决过拟合问题

## keras中权重正则化方法 ##
keras提供了权重正则化方法,可以在损失函数中通过添加惩罚系数来使用。keras提供了三种正则化方法:

L1:绝对值权重之和

L2:平方权重之和

L1L2:两者累加之和

tf.keras.regularizers.l1(l=0.01)
tf.keras.regularizers.l2(l=0.01)
tf.keras.regularizers.l1_l2(l1=0.01,l2=0.01)

keras中,权重正则化可以应用到任意一层,不过,模型默认不使用任何权重正则化。

全连接层使用权重正则化

全连接层使用L2权重正则化:

import tensorflow as tf

model=tf.keras.models.Sequential(
  
# 权重正则化,bias正则化(应用较少)
tf.keras.layers.Dense(512,activation=tf.nn.relu,kernel_regularizer=tf.keras.regularizers.l2(l=0.001),bias_regularizer=tf.keras.regularizers.l2(l=0.001))
)
卷积层使用权重正则化

同全连接层一样,卷积层也使用kernel_regularizerbias_regularizer参数添加正则化。代码展示在卷积层中使用L2正则化。

import tensorflow as tf

model=tf.keras.models.Sequential(
  tf.keras.layers.Conv2D(32,3,activation=tf.nn.relu,kernel_regularizer=tf.keras.regularizers.l2(l=0.001),bias_regularizer=tf.keras.regularizers.l2(l=0.001))
)
RNN网络中使用权重正则化

代码展示在LSTM网络中使用L2权重正则化

import tensorflow as tf

model=tf.keras.models.Sequential(
  tf.keras.layers.LSTM(32,activation=tf.nn.tanh,recurrent_regularizer=tf.keras.regularizers.l2(l=0.001),kernel_regularizer=tf.keras.regularizers.l2(l=0.001),bias_regularizer=tf.keras.regularizers.l2(l=0.001))
)
权重正则化使用经验

最常见的权重正则化是L2正则化,数值通常是0-0.1之间,如:0.1,0.001,0.0001。

找到最优的系数并不容易,需要尝试不同的权重系数,找到模型表现最平稳优秀的系数

L2正则化在CNN网络中,建议系数设置小一些,如:0.0005

少量的权重正则对模型很重要,可以减少模型训练误差

LSTM网络中L2权重系数通常更小,如:10^-6

权重正则化案例学习

我们将使用标准二元分类问题来定义两个半圆观察:每个类一个半圆。每个观测值都有两个输入变量,它们具有相同的比例,类输出值为0或1.该数据集称为“月亮”数据集,因为绘制时每个类中的观测值的形状。

# 导入sklearn中的数据集
from sklearn.datasets import make_moons
from matplotlib import pyplot
from pandas import DataFrame
# 生成2分类数据集
X, y = make_moons(n_samples=100, noise=0.2, random_state=1)

print(X.shape)
print(X[:6])
print(y.shape)
print(y[:6])

df = DataFrame(dict(x=X[:,0], y=X[:,1], label=y))
colors = {0:"red", 1:"blue"}
fig, ax = pyplot.subplots()
grouped = df.groupby("label")
for key, group in grouped:
    group.plot(ax=ax, kind="scatter", x="x", y="y", label=key, color=colors[key])
pyplot.show()

sklearn常用数据集:

数据集格式:

matplot结果显示:

如图所示,该问题是非线性问题,可以使用神经网络来解决。我们只生成了100个样本,对神经网络来说数据量很少,这很容易造成过拟合问题。我们使用正则化,添加噪声数据来处理问题。

虽然卷积神经网络(CNN)功能强大,并广泛应用于各种计算机视觉任务中,但由于参数过多而导致过度拟合[22]。神经网络的最初发展受到人脑机制的启发[18],它不像计算机那样精确。受到差异的启发,我们推断在训练过程中添加噪音可能会指示CNN学习更强大的特征表示以抵消噪音的影响,从而降低过度拟合的风险。许多正则化方法通过向训练数据添加噪声来防止过拟合。数据增强的输入图像,如随机裁剪,翻转和阻塞[9,21,30]已广泛用于提高CNNs的泛化能力。 Adversarial Training [1]被提出来通过在图像中添加基于梯度的扰动来调整网络。 DisturbLabel [26]随机地将样本的一小部分子集的标签改变为不正确的值,从而在损失层上规则化CNN。
过拟合模型

我们创建一个只有一层隐藏层的MLP模型,并让神经元数量大于样本数量,然后过长时间训练模型,以此来人为造成过拟合问题。训练模型之前,我们拆分下数据集,训练数据30%,验证数据70%,来训练模型表现。

X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
# 拆分数据集
n_train = 30
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]

模型隐藏层有500个神经元,激活函数使用relu,输出层使用sigmoid激活函数,输出一项类别。模型使用bind_crossentropy损失函数,adam优化器。

model = Sequential()
model.add(Dense(500, input_dim=2, activation="relu"))
model.add(Dense(1, activation="sigmoid"))
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])

模型迭代数据集400次,batch_size=32

model.fit(trainX, trainy, epochs=4000, verbose=0)

在测试集上评估模型表现:

# model.evaluate返回:loss value;metrics value
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print("Train: %.3f, Test: %.3f" % (train_acc, test_acc))

模型输出结果:

我们看到训练表现远大于测试表现,这是过拟合问题的典型标志。我们将train和test训练精度过程图形化展示出来。

from sklearn.datasets import make_moons
from keras.layers import Dense
from keras.models import Sequential
from matplotlib import pyplot

X, y = make_moons(n_samples=100, noise=0.2, random_state=1)

n_train = 30
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# 创建模型
model = Sequential()
model.add(Dense(500, input_dim=2, activation="relu"))
model.add(Dense(1, activation="sigmoid"))
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])
# 返回训练,验证集的损失和准确率
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0)
pyplot.plot(history.history["acc"], label="train")
pyplot.plot(history.history["val_acc"], label="test")
pyplot.legend()
pyplot.show()

如图所示,在某一点,train和test的准确率出现分叉口。

使用正则化的模型

我们将在隐藏层中使用权重正则化,并设置系数为0.001,以此来减轻过拟合问题。

model.add(Dense(500, input_dim=2, activation="relu", kernel_regularizer=l2(0.001)))

完整代码如下:

from sklearn.datasets import make_moons
from keras.layers import Dense
from keras.models import Sequential
from keras.regularizers import l2
# 创建数据集
X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
# 拆分数据集
n_train = 30
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# 创建模型
model = Sequential()
# 设置权重正则化
model.add(Dense(500, input_dim=2, activation="relu", kernel_regularizer=l2(0.001)))
model.add(Dense(1, activation="sigmoid"))
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])
# 训练模型
model.fit(trainX, trainy, epochs=4000, verbose=0)
# 评估模型
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print("Train: %.3f, Test: %.3f" % (train_acc, test_acc))

乍一看,好像除了test准确率降低些,其它也没什么了。让我们画图看下train和test的训练过程。

from sklearn.datasets import make_moons
from keras.layers import Dense
from keras.models import Sequential
from keras.regularizers import l2
from matplotlib import pyplot

X, y = make_moons(n_samples=100, noise=0.2, random_state=1)

n_train = 30
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]

model = Sequential()
model.add(Dense(500, input_dim=2, activation="relu", kernel_regularizer=l2(0.001)))
model.add(Dense(1, activation="sigmoid"))
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])

history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0
pyplot.plot(history.history["acc"], label="train")
pyplot.plot(history.history["val_acc"], label="test")
pyplot.legend()
pyplot.show()

如图所示,现在就很清楚了,test与train一致。

网格搜索正则化超参数

当确定权重正则化可以改善模型的时候,这时你可以尝试不同的权重系数值。首先对0.0到0.1之间的一些数量级进行网格搜索,然后再找到一个级别后进行网格搜索,这是一个很好的做法。

# 待测权重正则化值
values = [1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6]
all_train, all_test = list(), list()
for param in values:
    ...
    model.add(Dense(500, input_dim=2, activation="relu", kernel_regularizer=l2(param)))
    ...
    all_train.append(train_acc)
    all_test.append(test_acc)

我们依然可以图形化展示训练过程:

pyplot.semilogx(values, all_train, label="train", marker="o")
pyplot.semilogx(values, all_test, label="test", marker="o")

完整代码如下:

from sklearn.datasets import make_moons
from keras.layers import Dense
from keras.models import Sequential
from keras.regularizers import l2
from matplotlib import pyplot
# 创建数据集
X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
# 拆分数据集
n_train = 30
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# 待测权重系数值
values = [1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6]
all_train, all_test = list(), list()
for param in values:
    # 创建模型
    model = Sequential()
    model.add(Dense(500, input_dim=2, activation="relu", kernel_regularizer=l2(param)))
    model.add(Dense(1, activation="sigmoid"))
    model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])
    # 训练模型
    model.fit(trainX, trainy, epochs=4000, verbose=0)
    # 评估模型
    _, train_acc = model.evaluate(trainX, trainy, verbose=0)
    _, test_acc = model.evaluate(testX, testy, verbose=0)
    print("Param: %f, Train: %.3f, Test: %.3f" % (param, train_acc, test_acc))
    all_train.append(train_acc)
    all_test.append(test_acc)
# plot train and test means
pyplot.semilogx(values, all_train, label="train", marker="o")
pyplot.semilogx(values, all_test, label="test", marker="o")
pyplot.legend()
pyplot.show()

总结

降低过拟合问题,我们一般需要从“数据”,“模型结构”,“模型参数”,“模型训练方法”等角度,采用的方法如下:

数据增强:图像的平移,旋转,裁剪等;利用GAN生成新数据;利用机器翻译生成新数据。

降低模型复杂度:减少网络层数,神经元个数;

添加正则化项,如:L1,L2

集成学习:神经网络,dropout

避免过长时间训练模型,设置提前终止。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/19965.html

相关文章

  • 神经网络训练tricks

    摘要:下面介绍一些值得注意的部分,有些简单解释原理,具体细节不能面面俱到,请参考专业文章主要来源实战那我们直接从拿到一个问题决定用神经网络说起。当你使用时可以适当减小学习率,跑过神经网络的都知道这个影响还蛮大。 神经网络构建好,训练不出好的效果怎么办?明明说好的拟合任意函数(一般连续)(为什么?可以参考http://neuralnetworksanddeeplearning.com/),说好的足够...

    Jenny_Tong 评论0 收藏0
  • 正则化&&逻辑回归

    摘要:以用于检测垃圾邮件的逻辑回归模型为例。逻辑回归的损失函数线性回归的损失函数是平方损失。正则化在逻辑回归建模中极其重要。 正则化:简单性 查看以下泛化曲线,该曲线显示的是训练集和验证集相对于训练迭代次数的损失。 showImg(https://segmentfault.com/img/bVbahiL?w=750&h=322);上图显示的是某个模型的训练损失逐渐减少,但验证损失最终增加。换...

    xushaojieaaa 评论0 收藏0

发表评论

0条评论

neroneroffy

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<