收藏!改善TensorFlow模型的4种方法-你需要了解的关键正则化技术(1)

2020-12-14 15:24:15 浏览数 (1)

正则化技术对于防止模型过度拟合至关重要,并能使它们在验证和测试集上表现更好。本指南提供了可用于TensorFlow中正则化的四种关键方法的代码的全面概述。

正则化

根据维基百科,

在数学,统计学和计算机科学中,尤其是在机器学习和逆问题中,正则化 是添加信息以解决不适定问题或防止过度拟合的过程。

这意味着我们添加了一些额外的信息,以解决问题并防止过度拟合。

过度拟合只是意味着我们的机器学习模型已针对某些数据进行了训练,并且将在这些数据上运行得非常好,但是无法对未见过的新示例进行概括。

我们可以在这个简单的例子中看到过度拟合。

我们的数据严格附加到我们的训练集中。这导致测试集的性能较差,而训练集的性能却较好。

因此,为了提高模型的性能,我们使用了不同的正则化技术。有几种技术,但是我们将讨论4种主要技术。

  1. L1正则化
  2. L2正则化
  3. Dropout
  4. 批量归一化(BatchNormalization)

我将简要解释这些技术如何工作以及如何在Tensorflow 2中实现它们。

为了更好地了解它们的工作原理和工作原理,我请您参考吴恩达教授关于所有这些主题的讲座,这些讲座可以在Youtube上轻松获得。

首先,我将编写没有正则化的模型,然后,我将展示如何通过添加不同的正则化技术来改进模型。我们将使用IRIS数据集来表明使用正则化可以大大改善同一模型。

没有正则化的模型

代码:

基本预处理

代码语言:javascript复制
from sklearn.datasets import load_iris
from tensorflow.keras.models import Sequential
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.layers import Dense
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
iris = load_iris()
X = iris.data
y = iris.target
y = to_categorical(y) #converting output to one-hot vector
ss = StandardScaler() #standardizing the data
X = ss.fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split(X,y) #splitting dataset into 2 halves

建立模型

代码语言:javascript复制
model1 = Sequential([
    Dense(512, activation='tanh', input_shape = X_train[0].shape),
    Dense(512//2, activation='tanh'),
    Dense(512//4, activation='tanh'),
    Dense(512//8, activation='tanh'),
    Dense(32, activation='relu'),
    Dense(3, activation='softmax')
])
print(model1.summary())
model1.compile(optimizer='sgd',loss='categorical_crossentropy', metrics=['acc', 'mse'])

hist = model1.fit(X_train, y_train, epochs=350, batch_size=128, validation_data=(X_test,y_test))

model1.summary()

代码语言:javascript复制
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
dense_6 (Dense)              (None, 512)               2560
_________________________________________________________________
dense_7 (Dense)              (None, 256)               131328
_________________________________________________________________
dense_8 (Dense)              (None, 128)               32896
_________________________________________________________________
dense_9 (Dense)              (None, 64)                8256
_________________________________________________________________
dense_10 (Dense)             (None, 32)                2080
_________________________________________________________________
dense_11 (Dense)             (None, 3)                 99
=================================================================
Total params: 177,219
Trainable params: 177,219
Non-trainable params: 0
_________________________________________________________________

训练模型后,如果我们在Tensorflow中使用以下代码评估模型,则可以在测试集处找到我们的 准确性损失Mse

代码语言:javascript复制
loss1, acc1, mse1 = model1.evaluate(X_test, y_test)
print(f"Loss is {loss1},nAccuracy is {acc1*100},nMSE is {mse1}")

让我们检查验证损失和训练损失的图。

代码语言:javascript复制
import matplotlib.pyplot as plt
plt.style.use('ggplot')
plt.plot(hist.history['loss'], label = 'loss')
plt.plot(hist.history['val_loss'], label='val loss')
plt.title("Loss vs Val_Loss")
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.legend()
plt.show()

在这里,我们可以看到,与训练损失相比,验证损失在大约 60个Epochs后逐渐增加 。这表明我们的模型过拟合。

同样,对于模型精度图,

代码语言:javascript复制
plt.plot(hist.history['acc'], label = 'acc')
plt.plot(hist.history['val_acc'], label='val acc')
plt.title("acc vs Val_acc")
plt.xlabel("Epochs")
plt.ylabel("acc")
plt.legend()
plt.show()

这再次表明,与训练准确性相比,验证准确性较低,这又显示出过度拟合的迹象。

L1正则化

常用的正则化技术是L1正则化,也称为套索正则化。

L1正则化的主要概念是,我们必须在损失函数中加上权重的绝对值,再乘以正则化参数lambdaλ 其中的 λ 手动调整为大于0)来惩罚权重 。

L1的等式为

Tensorflow 代码:

代码语言:javascript复制
model2 = Sequential([
    Dense(512, activation='tanh', input_shape = X_train[0].shape, kernel_regularizer='l1'), #Only change is here where we add kernel_regularizer
    Dense(512//2, activation='tanh'),
    Dense(512//4, activation='tanh'),
    Dense(512//8, activation='tanh'),
    Dense(32, activation='relu'),
    Dense(3, activation='softmax')
])

model2.compile(optimizer='sgd',loss='categorical_crossentropy', metrics=['acc', 'mse'])
hist2 = model2.fit(X_train, y_train, epochs=350, batch_size=128, validation_data=(X_test,y_test))

在这里,我们添加了一个额外的参数 kernel_regularizer,我们将其设置为“ l1”以进行L1正则化。

让我们现在评估并绘制模型。

代码语言:javascript复制
loss2, acc2, mse2 = model2.evaluate(X_test, y_test)
print(f"Loss is {loss2},nAccuracy is {acc2 * 100},nMSE is {mse2}")

嗯,准确性几乎一样,让我们检查一下图表以获得更好的直觉。

代码语言:javascript复制
plt.plot(hist2.history[‘loss’], label = ‘loss’)
plt.plot(hist2.history[‘val_loss’], label=’val loss’)
plt.title(“Loss vs Val_Loss”)
plt.xlabel(“Epochs”)
plt.ylabel(“Loss”)
plt.legend()
plt.show()

对于准确率

代码语言:javascript复制
plt.figure(figsize=(15,8))
plt.plot(hist2.history['acc'], label = 'acc')
plt.plot(hist2.history['val_acc'], label='val acc')
plt.title("acc vs Val_acc")
plt.xlabel("Epochs")
plt.ylabel("acc")
plt.legend()
plt.show()

好吧,我想这是一个很大的进步,因为过度验证损失并没有像以前那样增加太多,但是验证准确性却没有增加。让我们在更多的层中添加l1,以检查它是否改善了模型。

代码语言:javascript复制
model3 = Sequential([
    Dense(512, activation='tanh', input_shape = X_train[0].shape, kernel_regularizer='l1'),
    Dense(512//2, activation='tanh', kernel_regularizer='l1'),
    Dense(512//4, activation='tanh', kernel_regularizer='l1'),
    Dense(512//8, activation='tanh', kernel_regularizer='l1'),
    Dense(32, activation='relu', kernel_regularizer='l1'),
    Dense(3, activation='softmax')
])
model3.compile(optimizer='sgd',loss='categorical_crossentropy', metrics=['acc', 'mse'])
hist3 = model3.fit(X_train, y_train, epochs=350, batch_size=128, validation_data=(X_test,y_test), verbose=2)

训练之后,我们来评价一下模型。

代码语言:javascript复制
loss3, acc3, mse3 = model3.evaluate(X_test, y_test)
print(f"Loss is {loss3},nAccuracy is {acc3 * 100},nMSE is {mse3}")

好吧,现在的准确度有了很大提高,从92跃升至94。让我们检查一下绘图。

Loss

代码语言:javascript复制
plt.figure(figsize=(15,8))
plt.plot(hist3.history['loss'], label = 'loss')
plt.plot(hist3.history['val_loss'], label='val loss')
plt.title("Loss vs Val_Loss")
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.legend()
plt.show()

现在,两条线大致重叠,这意味着我们的模型在测试集上的表现与在训练集上的表现相同。

准确率

代码语言:javascript复制
plt.figure(figsize =(15,8))
plt.plot(hist3.history ['acc'],label ='ACC')
plt.plot(hist3.history ['val_acc'],label ='val acc' )
plt.title(“ acc vs Val_acc”)
plt.xlabel(“ 
Epochs ”)plt.ylabel(“ acc”)
plt.legend()
plt.show()

我们可以看到,模型的验证损失与训练损失相比并没有增加,验证准确性也在增加。

L2正则化

L2正则化是另一种正则化技术,也称为 Ridge正则化。在L2正则化中,我们添加权重的平方大小以惩罚我们的损失函数。

TensorFlow代码

代码语言:javascript复制
model5 = Sequential([
    Dense(512, activation='tanh', input_shape = X_train[0].shape, kernel_regularizer='l2'),
    Dense(512//2, activation='tanh'),
    Dense(512//4, activation='tanh'),
    Dense(512//8, activation='tanh'),
    Dense(32, activation='relu'),
    Dense(3, activation='softmax')
])
model5.compile(optimizer='sgd',loss='categorical_crossentropy', metrics=['acc', 'mse'])
hist5 = model5.fit(X_train, y_train, epochs=350, batch_size=128, validation_data=(X_test,y_test), verbose=2)

训练之后我们来评价模型

代码语言:javascript复制
loss5, acc5, mse5 = model5.evaluate(X_test, y_test)
print(f"Loss is {loss5},nAccuracy is {acc5 * 100},nMSE is {mse5}")

输出是

在这里我们可以看到验证准确性为97%,这是相当不错的。让我们作图以获得更多的直觉。

在这里,我们可以看到我们并没有过度拟合数据。让我们绘制精度。

仅在1层中添加“ L2”正则化就大大改善了我们的模型。

现在, 在所有其他层中添加 L2

代码语言:javascript复制
model6 = Sequential([
    Dense(512, activation='tanh', input_shape = X_train[0].shape, kernel_regularizer='l2'),
    Dense(512//2, activation='tanh', kernel_regularizer='l2'),
    Dense(512//4, activation='tanh', kernel_regularizer='l2'),
    Dense(512//8, activation='tanh', kernel_regularizer='l2'),
    Dense(32, activation='relu', kernel_regularizer='l2'),
    Dense(3, activation='softmax')
])
model6.compile(optimizer='sgd',loss='categorical_crossentropy', metrics=['acc', 'mse'])
hist6 = model6.fit(X_train, y_train, epochs=350, batch_size=128, validation_data=(X_test,y_test), verbose=2)

在这里,所有层都有L2。经过训练后,让我们对其进行评估。

代码语言:javascript复制
loss6, acc6, mse6 = model6.evaluate(X_test, y_test)
print(f"Loss is {loss6},nAccuracy is {acc6 * 100},nMSE is {mse6}")

让我们获得更多的直觉。

代码语言:javascript复制
plt.figure(figsize =(15,8))
plt.plot(hist6.history ['loss'],label ='loss')
plt.plot(hist6.history ['val_loss'],label ='val loss' )
plt.title(“ Loss vs Val_Loss”)
plt.xlabel(“ Epochs ”)plt.ylabel(“ Loss”)
plt.legend()
plt.show()

准确性

我们可以看到该模型也很好,并且不会过度拟合数据集。

下期为同学们讲解其余两种技术。

0 人点赞