复习日
一、数据预处理增强
数据增强
随机裁剪 :使用
RandomCrop
对图像进行随机裁剪,可以增加模型对不同物体位置的适应性。例如,在 PyTorch 中可以使用transforms.RandomCrop
,设置裁剪的尺寸,如将 32×32 的图像随机裁剪为 28×28 的大小。这样可以迫使模型学习到物体的局部特征,而不是依赖于物体在图像中的固定位置。随机水平翻转 :对于许多自然图像数据集,物体在水平方向翻转后语义不变(如动物、车辆等)。使用
transforms.RandomHorizontalFlip
,以一定的概率(如 0.5)对图像进行水平翻转,可以有效地增加数据集的多样性,使模型在训练过程中看到更多的样本变化。颜色抖动 :通过调整图像的亮度、对比度、饱和度和色调,可以模拟不同的光照和色彩条件。使用
transforms.ColorJitter
,设置亮度(brightness)、对比度(contrast)、饱和度(saturation)和色调(hue)的抖动范围,如 brightness = (0.5, 1.5),表示随机将亮度调整为原来的 0.5 - 1.5 倍。这有助于模型更好地泛化到不同颜色条件下的图像。
数据归一化
计算数据集的均值和标准差,对图像数据进行归一化处理。这可以使数据分布更稳定,加速模型的收敛。在 PyTorch 中,使用
transforms.Normalize
,传入计算得到的均值和标准差。例如,对于一个 RGB 图像数据集,均值为 [0.485, 0.456, 0.406],标准差为 [0.229, 0.224, 0.225],通过归一化可以将像素值转换到合适的范围,通常为 [-1, 1] 或 [0, 1],这有助于优化器更好地更新模型参数。
二、模型优化
调整网络结构
增加网络深度(谨慎操作) :在简单 CNN 的基础上,可以尝试增加几层卷积层和池化层。例如,在原有的两层卷积层后,再添加一层卷积层和一层池化层。但需要注意的是,增加网络深度可能会导致梯度消失或爆炸问题,所以在添加层数的同时,可能需要引入批量归一化(Batch Normalization)层来缓解这些问题。批量归一化可以加速模型的收敛,并且在一定程度上起到正则化的作用,防止模型过拟合。
调整卷积核大小和通道数 :尝试不同的卷积核大小(如 5×5、7×7)和通道数。较大的卷积核可以捕获更大的局部特征,但计算量也会相应增加。增加通道数可以提取更多的特征,但也可能导致模型参数过多而过拟合。例如,将第一层卷积层的输出通道数从 16 增加到 32,同时合理地减少全连接层的神经元数量,以保持模型参数规模的平衡。
优化正则化手段
加强 L2 正则化 :适当增大 L2 正则化(权重衰减)的系数。在 PyTorch 的优化器(如 Adam、SGD)中,可以通过设置
weight_decay
参数来实现。例如,将weight_decay
从 1e-4 调整为 1e-3,这可以更有效地防止模型权重过大,减少过拟合的风险。但要注意不要设置得过大,以免导致模型欠拟合。添加 Dropout 层 :在全连接层之间添加 Dropout 层。Dropout 可以随机地将一部分神经元的输出置为 0,这在训练过程中可以防止神经元之间过度的相互适应,增强模型的泛化能力。在 PyTorch 中,使用
nn.Dropout
,并设置合适的 dropout 概率(如 0.5),通常在全连接层之后添加 Dropout 层,如在第一个全连接层(fc1)后添加nn.Dropout(0.5)
。
三、训练策略优化
学习率调整策略
使用学习率调度器 :采用学习率衰减策略。在训练初期,使用较高的学习率(如 0.001)使模型快速收敛,当训练到一定 epoch 后,逐渐减小学习率。例如,在 PyTorch 中可以使用
StepLR
学习率调度器。设置初始学习率为 0.001,每 10 个 epoch 将学习率乘以 0.1。这可以使模型在训练后期更精细地调整参数,提高模型的精度。尝试不同的优化器 :除了常用的 SGD 和 Adam 优化器外,可以尝试使用 AdamW 优化器。AdamW 在 Adam 的基础上对权重衰减进行了修正,使其更好地与 L2 正则化结合。在训练过程中,根据数据集和模型的具体情况,比较不同优化器的性能,选择合适的学习率和优化器组合。
早停(Early Stopping)
在训练过程中,设置早停机制。当验证集上的损失在一定数量的 epoch(如 5 个)内没有改善时,停止训练。这可以防止模型在训练后期过度拟合训练数据,同时节省训练时间和计算资源。在 PyTorch 中,可以通过自定义一个早停类或者在训练循环中添加相应的逻辑来实现这个功能。
作业:day43的时候我们安排大家对自己找的数据集用简单cnn训练,现在可以尝试下借助这几天的知识来实现精度的进一步提高
数据预处理(utils/data_loader.py)
在现有数据增强的基础上,增加更精细的数据增强策略:
import os
import numpy as np
from tensorflow.keras.preprocessing.image import ImageDataGenerator
def load_data(train_dir, test_dir, img_height, img_width, batch_size):
# 数据增强和加载
train_datagen = ImageDataGenerator(
rescale=1./255,
rotation_range=30, # 增加旋转范围
width_shift_range=0.3, # 增加宽度偏移
height_shift_range=0.3, # 增加高度偏移
shear_range=0.3, # 增加剪切强度
zoom_range=0.3, # 增加缩放范围
horizontal_flip=True,
vertical_flip=True, # 添加垂直翻转
validation_split=0.2 # 划分验证集
)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
train_dir,
target_size=(img_height, img_width),
batch_size=batch_size,
class_mode='binary',
subset='training'
)
validation_generator = train_datagen.flow_from_directory(
train_dir,
target_size=(img_height, img_width),
batch_size=batch_size,
class_mode='binary',
subset='validation'
)
test_generator = test_datagen.flow_from_directory(
test_dir,
target_size=(img_height, img_width),
batch_size=batch_size,
class_mode='binary',
shuffle=False
)
return train_generator, validation_generator, test_generator
模型定义(utils/model.py)
引入残差模块来构建更深的网络,以提取更复杂的特征:
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, BatchNormalization, Input, Add
def create_cnn_model(img_height, img_width):
inputs = Input(shape=(img_height, img_width, 3))
x = Conv2D(32, (3, 3), activation='relu')(inputs)
x = BatchNormalization()(x)
x = MaxPooling2D((2, 2))(x)
# 残差模块
residual = x
x = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
x = BatchNormalization()(x)
x = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
x = BatchNormalization()(x)
x = Add()([x, residual])
x = MaxPooling2D((2, 2))(x)
x = Conv2D(64, (3, 3), activation='relu')(x)
x = BatchNormalization()(x)
x = MaxPooling2D((2, 2))(x)
x = Conv2D(128, (3, 3), activation='relu')(x)
x = BatchNormalization()(x)
x = MaxPooling2D((2, 2))(x)
x = Flatten()(x)
x = Dense(512, activation='relu')(x)
x = Dropout(0.5)(x)
outputs = Dense(1, activation='sigmoid')(x)
model = Model(inputs=inputs, outputs=outputs)
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
return model
训练脚本(train.py)
增加学习率调度器,动态调整学习率:
import os
import numpy as np
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, LearningRateScheduler
from utils.data_loader import load_data
from utils.model import create_cnn_model
def lr_schedule(epoch):
lr = 1e-3
if epoch > 30:
lr *= 1e-3
elif epoch > 20:
lr *= 1e-2
elif epoch > 10:
lr *= 1e-1
return lr
if __name__ == "__main__":
# 参数设置
img_height = 150
img_width = 150
batch_size = 32
epochs = 50
# 加载数据
train_generator, validation_generator, _ = load_data(
'data/train',
'data/test',
img_height,
img_width,
batch_size
)
# 创建模型
model = create_cnn_model(img_height, img_width)
# 回调函数
checkpoint = ModelCheckpoint('models/best_model.h5', monitor='val_accuracy', save_best_only=True, mode='max')
early_stop = EarlyStopping(monitor='val_loss', patience=5, mode='min')
lr_scheduler = LearningRateScheduler(lr_schedule)
# 训练模型
history = model.fit(
train_generator,
steps_per_epoch=train_generator.samples // batch_size,
epochs=epochs,
validation_data=validation_generator,
validation_steps=validation_generator.samples // batch_size,
callbacks=[checkpoint, early_stop, lr_scheduler]
)
针对“Cats VS. Dogs”数据集优化模型时所做的改进总结:
数据预处理
增强数据多样性:扩大了图像数据增强的范围,通过增加旋转范围至30度、宽度和高度偏移至0.3、剪切强度至0.3以及缩放范围至0.3,使模型能够接触到更多样化的图像变化,有效提升其对不同图像条件的适应能力,有助于改善过拟合问题。
添加垂直翻转:在数据增强过程中加入垂直翻转操作,进一步丰富了训练数据的角度和形态,让模型可以学习到图像在垂直方向上的特征变化,增强对图像的全方位识别能力。
模型架构
引入残差模块:在模型中巧妙地融入残差模块,成功地解决了深层网络训练时易出现的梯度消失问题。这不仅使得网络结构能够顺利地加深,以捕获更为复杂的图像特征,还极大地提升了模型对图像细节的捕捉能力,为提高模型精度奠定了坚实基础。
训练策略
采用学习率调度:动态调整学习率,随着训练 epoch 的推进,学习率从初始的 1e-3 开始,每达到特定 epoch 阈值(10、20、30)就逐步减小至原来的十分之一。这种策略能够确保模型在训练初期快速收敛,同时在后期更精细地优化参数,有效提升了模型的最终精度。