在深度学习领域,模型训练的核心目标是构建一个能够从训练数据中学习并泛化到新数据的模型。然而,一个常见的问题是模型在训练集上表现良好,但在测试集上表现不佳,这种现象被称为过拟合。过拟合意味着模型过于复杂,捕捉到了训练数据中的噪声而非潜在的模式,导致模型泛化能力下降。
过拟合的一个明显标志是在训练集上的损失(loss)很低,而在测试集上的损失却相对较高。通过绘制损失和准确率(accuracy)随迭代次数(epoch)变化的图表,可以直观地识别过拟合。模型在训练集上的准确率可能很高,但在测试集上却显著下降,这表明模型可能过于复杂,需要调整。
对于深度学习模型,建议将数据集分为训练集、验证集和测试集三个部分。验证集用于微调模型,直到对其性能满意,然后使用测试集来训练模型的最佳版本。以下是如何使用Python的sklearn库中的train_test_split函数来分割数据集的示例代码:
from sklearn.model_selection import train_test_split
# 创建验证数据集
Xtrain, Xval, ytrain, yval = train_test_split(train_images, train_labels_final, train_size=0.9, test_size=0.1, random_state=42)
# 创建测试和最终训练数据集
Xtrain, Xtest, ytrain, ytest = train_test_split(Xtrain, ytrain, train_size=0.78, random_state=42)
这里进行了两次train_test_split函数调用。第一次调用是在初始训练集的图像和标签上,以形成验证集。设置random_state参数以保持函数运行结果的一致性,设置test_size参数以指定验证集的大小为训练数据的10%,train_size参数设置为剩余数据的百分比。第二次调用是从新形成的训练数据Xtrain和ytrain中生成测试数据集。
如果模型过拟合,可以通过调整超参数来解决。以下是一些常用的技术:
正则化通过惩罚复杂模型来优化模型,从而最小化损失和复杂度。这迫使神经网络变得更简单。在这里,将使用L2正则化器,因为它比L1正则化器更常见且更稳定。以下是如何在网络的第二和第三层添加正则化的示例代码:
# 隐藏层1
model2.add(layers.Conv2D(64, (4, 4), activation='relu', kernel_regularizer=regularizers.l2(l=0.01)))
model2.add(layers.MaxPooling2D((2, 2)))
# 隐藏层2
model2.add(layers.Conv2D(128, (3, 3), activation='relu', kernel_regularizer=regularizers.l2(l=0.01)))
model2.add(layers.MaxPooling2D((2,2)))
正则化有助于减少模型的复杂度,提高其泛化能力。
权重初始化是在训练过程开始之前为所有神经元设置权重向量的初始值。选择正确的权重至关重要,因为希望在合理的时间内尽可能接近成本函数的全局最小值。在这个模型迭代中,将使用He初始化:
# 第三模型的输入层
model3.add(layers.Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', input_shape=(96, 96, 3)))
正确的权重初始化可以加速训练过程,并提高模型的性能。
Dropout正则化在训练阶段随机忽略某些层中的单元,并将其权重设置为零。对于输入和隐藏层,理想的比率是0.4,对于输出层是0.2。以下是如何在模型中应用Dropout的示例代码:
random.seed(123) # 保持结果的一致性
model4 = Sequential() # 实例化第四模型
model4.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(96, 96, 3)))
model4.add(layers.MaxPooling2D((2, 2)))
model4.add(Dropout(0.4))
model4.add(layers.Conv2D(64, (4, 4), activation='relu'))
model4.add(layers.MaxPooling2D((2, 2)))
model4.add(Dropout(0.4))
# 展平 - 将2D矩阵转换为1D向量
model4.add(layers.Flatten())
model4.add(layers.Dense(512, activation='relu'))
model4.add(Dropout(0.2))
model4.add(layers.Dense(1, activation='sigmoid'))
Dropout正则化有助于减少模型对训练数据的依赖,提高其泛化能力。
权重约束检查网络权重的大小,并在大小超过预定义限制时重新调整它们。以下是如何使用unit_norm约束的示例代码,它强制权重的大小为1.0:
model5.add(layers.Conv2D(32, (3, 3), activation='relu', kernel_constraint=unit_norm(), input_shape=(96, 96, 3)))
权重约束有助于控制模型的复杂度,防止过拟合。
datagen = ImageDataGenerator(rotation_range = 0,
width_shift_range = 0,
height_shift_range = 0,
rescale = None,
shear_range = 0,
zoom_range = 0,
horizontal_flip = False,
fill_mode = 'nearest')
# 导入原始训练数据集
train_gen2 = ImageDataGenerator(rescale=1./255).flow_from_directory(train_dir, target_size=(128,128), batch_size=15200)
# 导入原始验证数据集
val_gen2 = ImageDataGenerator(rescale=1./255).flow_from_directory(val_dir, target_size=(128,128), batch_size=16)
# 导入原始测试数据集
test_gen2 = ImageDataGenerator(rescale=1./255).flow_from_directory(test_dir, target_size=(128,128), batch_size=624)