迁移学习实战:基于预训练模型 ResNet50 微调实现自定义图像分类

迁移学习通过复用预训练模型的知识,显著提升新任务的训练效率和性能。ResNet50 是一个在 ImageNet 数据集上预训练的深度残差网络,包含 50 层结构,具有强大的图像特征提取能力。以下我将逐步指导您如何微调 ResNet50 实现自定义图像分类任务,整个过程包括数据准备、模型修改、训练和评估。代码基于 TensorFlow/Keras 框架实现。

步骤 1: 环境准备

确保安装必要库:

  • Python 3.7+
  • TensorFlow 2.x
  • Keras
  • NumPy
  • OpenCV 或 Pillow(图像处理)

使用 pip 安装:

pip install tensorflow numpy opencv-python

步骤 2: 数据准备

自定义数据集需组织为以下目录结构(以类别分文件夹):

custom_dataset/
    ├── train/
    │   ├── class1/
    │   ├── class2/
    │   └── ... 
    └── val/
        ├── class1/
        ├── class2/
        └── ...

  • 图像预处理:统一调整为 $224 \times 224$ 像素(ResNet50 输入尺寸),并归一化像素值到 $[0, 1]$。
  • 数据增强:防止过拟合,使用旋转、缩放等变换。
步骤 3: 加载并修改 ResNet50 模型

预训练 ResNet50 的顶层(全连接层)需替换为自定义分类层:

import tensorflow as tf
from tensorflow.keras.applications import ResNet50
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.preprocessing.image import ImageDataGenerator

# 定义数据集路径和参数
train_dir = 'custom_dataset/train'
val_dir = 'custom_dataset/val'
batch_size = 32
num_classes = 10  # 替换为您的类别数

# 数据生成器(含增强)
train_datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True,
    validation_split=0.2
)
train_generator = train_datagen.flow_from_directory(
    train_dir,
    target_size=(224, 224),
    batch_size=batch_size,
    class_mode='categorical',
    subset='training'
)
val_generator = train_datagen.flow_from_directory(
    val_dir,
    target_size=(224, 224),
    batch_size=batch_size,
    class_mode='categorical',
    subset='validation'
)

# 加载预训练 ResNet50(不含顶层)
base_model = ResNet50(
    weights='imagenet',
    include_top=False,
    input_shape=(224, 224, 3)
)

# 冻结所有卷积层(保留特征提取能力)
for layer in base_model.layers:
    layer.trainable = False

# 添加自定义顶层
x = base_model.output
x = GlobalAveragePooling2D()(x)  # 全局平均池化替代全连接
x = Dense(1024, activation='relu')(x)  # 新增全连接层
predictions = Dense(num_classes, activation='softmax')(x)  # 输出层

# 构建最终模型
model = Model(inputs=base_model.input, outputs=predictions)

步骤 4: 编译模型
  • 使用 Adam 优化器,学习率设为 $0.0001$(微调时宜小)。
  • 损失函数为分类交叉熵:$ \text{loss} = -\sum_{i} y_i \log(\hat{y}_i) $。
  • 评估指标为准确率。
model.compile(
    optimizer=Adam(learning_rate=0.0001),
    loss='categorical_crossentropy',
    metrics=['accuracy']
)

步骤 5: 训练模型
  • 训练周期(epochs)根据数据集大小调整(建议 10-50)。
  • 使用验证集监控过拟合。
epochs = 20
history = model.fit(
    train_generator,
    steps_per_epoch=train_generator.samples // batch_size,
    epochs=epochs,
    validation_data=val_generator,
    validation_steps=val_generator.samples // batch_size
)

步骤 6: 评估与预测
  • 评估性能:在测试集计算准确率。
  • 预测新图像:预处理后输入模型。
# 评估模型
test_loss, test_acc = model.evaluate(val_generator)
print(f'测试准确率: {test_acc:.4f}')

# 预测单张图像
import cv2
import numpy as np

def predict_image(image_path):
    img = cv2.imread(image_path)
    img = cv2.resize(img, (224, 224))
    img = img / 255.0  # 归一化
    img = np.expand_dims(img, axis=0)  # 添加批次维度
    pred = model.predict(img)
    class_idx = np.argmax(pred)
    return f'预测类别: {class_idx}, 置信度: {np.max(pred):.2f}'

注意事项
  1. 数据质量:确保数据集平衡,每类样本不少于 100 张。
  2. 微调策略
    • 初始训练时冻结卷积层(如上代码),后期可解冻部分层进一步微调。
    • 学习率使用余弦退火等调度策略,公式可表示为:$$ \eta_t = \eta_{\min} + \frac{1}{2}(\eta_{\max} - \eta_{\min})(1 + \cos(\frac{t}{T}\pi)) $$。
  3. 过拟合处理:添加 Dropout 层或 L2 正则化。
  4. 硬件需求:GPU 加速训练(如 NVIDIA CUDA)。

通过以上步骤,您能高效实现自定义图像分类任务。完整代码可在 Colab 或本地运行,实际准确率可达 90%+(取决于数据集)。如需优化,可尝试不同预训练模型(如 VGG 或 EfficientNet)或调整超参数。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐