PaddleClas 模型微调(Finetune)实战指南:从数据准备到配置修改与多卡训练

原创2026-10-12 12:07:371,837 阅读
文章标签:计算机视觉深度学习人工智能机器学习模型蒸馏

PaddleClas 模型微调(Finetune)实战指南:从数据准备到配置修改与多卡训练

本指南面向已在 Linux 上完成 PaddleClas 环境配置并跑通过快速开始(进阶版)的开发者,系统讲解如何使用 ImageNet 预训练模型在自己的分类数据集上完成微调(finetune):包括 txt 格式数据的组织方式、配置文件逐项修改要点、多卡训练命令,以及分辨率、数据增强、评价指标、精度提升等高频问题的处理方案。读完本文,你将能够把任意单标签图像分类数据集接入 PaddleClas,并基于预训练模型快速收敛、缓解过拟合。

PaddleClas 提供了丰富的 ImageNet 预训练模型,使用这些预训练权重作为初始化训练自己的任务,不仅可以快速收敛,还能在一定程度上避免模型在小数据集上的过拟合。微调流程可以概括为三条主线:组织数据(txt 清单)→ 修改配置(类别数 / 预训练 / 学习率 / 数据路径)→ 启动训练。下面以 ResNet50_vd 为例逐一展开,该模型的完整训练配置位于 ppcls/configs/ImageNet/ResNet/ResNet50_vd.yaml。

1. 数据准备:目录结构与 txt 清单格式

PaddleClas 通过 txt 文件读取数据,因此需要将分类数据单独存放在一个文件夹中,其中主要包含以下四部分内容:

├── train
├── train_list.txt
├── val
├── val_list.txt

其中 train 和 val 分别存放训练数据和验证数据;train_list.txt 和 val_list.txt 分别记录训练/验证数据的路径和标签。清单文件每一行采用空格分隔图像路径与标注,格式如下:

# 下面是 train_list.txt 中的格式样例
train/n01440764/n01440764_10026.JPEG 0
...

# 下面是 val_list.txt 中的格式样例
val/ILSVRC2012_val_00000001.JPEG 65
...

其中 train/n01440764/n01440764_10026.JPEG 表示该数据的路径(相对于 image_root),0 表示该数据属于第 0 类。注意:train_list.txt 和 val_list.txt 需要根据你的实际数据自行生成,PaddleClas 不会自动生成。

1.1 清单文件如何被解析:ImageNetDataset 源码解读

在配置文件中,数据读取由 DataLoader.Train.dataset.name: ImageNetDataset 指定,其实现位于 ppcls/data/dataloader/imagenet_dataset.py,核心逻辑如下:

  • 构造参数 image_root(图像根目录)与 cls_label_path(清单文件路径)由 CommonDataset 基类保存(见 ppcls/data/dataloader/common_dataset.py);
  • _load_anno 会逐行读取清单:以默认分隔符(空格)切分 line,将 line[0] 拼接到 image_root 下得到完整图像路径,将 line[1] 解析为 np.int64 标签;
  • 解析时会对每个路径做 os.path.exists 断言,路径或清单文件不存在会直接报错,这有助于在训练前快速定位数据路径问题;
  • 若设置 relabel: True,则会先收集清单中的全部标签并重新映射为从 0 开始的连续编号,适合原始标签不是从 0 开始或存在空缺的场景(例如仅使用全部 1000 类中的部分类别微调)。

以 ImageNet1k 为例,官方数据下载解压后按如下结构摆放即可直接使用(该结构也见图像分类任务数据集说明):

PaddleClas/dataset/ILSVRC2012/
├── train/
│   ├── n01440764/...
│   └── ...
├── val/
│   ├── ILSVRC2012_val_00000001.JPEG
│   └── ...
├── train_list.txt
└── val_list.txt

2. 模型训练

2.1 更改配置文件

在 ppcls/configs/ImageNet/ 目录下定义了所有模型在 ImageNet 数据上的训练配置,可以直接修改对应配置完成自己的训练任务。下面以 ResNet50_vd 为例(配置文件位于 ppcls/configs/ImageNet/ResNet/ResNet50_vd.yaml),详述微调时通常需要修改的四处配置。

2.1.1 修改类别数

类别数量默认是 1000(ImageNet-1k 的类别数),需要修改为实际任务的类别数量:

Arch:
  name: ResNet50_vd
  class_num: your_class_num

Arch.class_num 决定了分类头(全连接层)的输出维度。从模型定义源码 ppcls/arch/backbone/legendary_models/resnet.py 可以看到,class_num 会作为 kwargs 传入 ResNet 并最终影响 fc 层的输出节点数,因此该值必须与清单中的标签取值范围一致(或借助 relabel 自动重映射)。

2.1.2 加载预训练模型

增加预训练模型可以让 Loss 更快收敛,修改方式如下:

Arch:
  name: ResNet50_vd
  class_num: your_class_num
  pretrained: True

pretrained 支持两种取值:

  • True:加载 PaddleClas 官方发布的 ImageNet 预训练权重(自动从配置内置的 MODEL_URLS 下载);
  • 字符串路径:加载本地权重,例如 pretrained: "./pretrained/best_model",此时将直接以该路径作为预训练模型加载。

其底层逻辑见 ppcls/arch/backbone/legendary_models/resnet.py 中的 _load_pretrained:pretrained is True 时调用 load_dygraph_pretrain(model, model_url, use_ssld=use_ssld);pretrained 为字符串时调用 load_dygraph_pretrain(model, pretrained);其余类型会抛出运行时错误。此外,若希望在 pretrained=True 时加载 SSLD 蒸馏得到的更强预训练权重,只需在 Arch 下追加 use_ssld: True(详见下文 FAQ-Q4)。

2.1.3 修改学习率

当训练任务的数据量远小于 ImageNet 时,学习率需要减小若干倍。具体减小的幅度需要调试,可以先从减小 10 倍开始:

Optimizer:
  name: Momentum
  momentum: 0.9
  lr:
    name: Cosine
    learning_rate: your_learning_rate

在 ResNet50_vd.yaml 中默认配置为 learning_rate: 0.1(配合 regularizer.name: 'L2'、coeff: 0.00007)。学习率调度器 Cosine 的实现位于 ppcls/optimizer/learning_rate.py,其按公式 lr = 0.05 * (cos(epoch * π / epochs) + 1) 做余弦退火,并可配置 eta_min(最小学习率,默认 0.0)、warmup_epoch、warmup_start_lr 等参数;Momentum 优化器与各类调度器的装配逻辑见 ppcls/optimizer/init.py。关于学习率策略的深入讨论(piecewise_decay 与 cosine_decay 对比、warmup、batch_size 与学习率线性缩放关系等),可参考图像分类训练调参策略。

2.1.4 修改数据路径

数据路径需要改为第 1 节中准备好的数据路径:

DataLoader:
  Train:
    dataset:
      name: ImageNetDataset
      image_root: your_image_root
      cls_label_path: your_train_cls_label_path

  Eval:
    dataset:
      name: ImageNetDataset
      image_root: your_image_root
      cls_label_path: your_eval_cls_label_path

以原配置为例,image_root: ./dataset/ILSVRC2012/、cls_label_path: ./dataset/ILSVRC2012/train_list.txt(Eval 对应 val_list.txt)。训练阶段默认的预处理流水线为 DecodeImage → RandCropImage(size=224) → RandFlipImage → NormalizeImage,并可选 MixupOperator(alpha: 0.2);验证阶段为 DecodeImage → ResizeImage(resize_short=256) → CropImage(size=224) → NormalizeImage;DistributedBatchSampler 的 batch_size 默认为 64,loader.num_workers 默认为 4。这些字段在微调时通常保持不变,只需替换数据路径即可。

2.2 模型训练

修改完配置文件后即可开始训练,此处默认使用 4 卡训练,命令如下:

export CUDA_VISIBLE_DEVICES=0,1,2,3
python3 -m paddle.distributed.launch \
    --gpus="0,1,2,3" \
    tools/train.py \
        -c ppcls/configs/ImageNet/ResNet/ResNet50_vd.yaml

训练入口 tools/train.py 的执行链路为:config.parse_args() 解析命令行参数 → config.get_config(args.config, overrides=args.override) 读取并(可选)覆盖 YAML 配置 → 构造 Engine(config, mode="train") 并调用 engine.train()。每个 epoch 的训练循环(前向、Loss 计算、反向、优化器更新、学习率步进、EMA 更新与日志打印)实现在 ppcls/engine/train/train.py。

2.2.1 单卡与多卡切换时的学习率调整

如果你只有单卡,可将 CUDA_VISIBLE_DEVICES 与 --gpus 同时指定为同一张卡:

export CUDA_VISIBLE_DEVICES=0
python3 -m paddle.distributed.launch \
    --gpus="0" \
    tools/train.py \
        -c ppcls/configs/ImageNet/ResNet/ResNet50_vd.yaml \
        -o Optimizer.lr.learning_rate=0.01

由于初始学习率与 batch_size 需要保持线性关系,从 4 卡切换到 1 卡训练时,总 batch_size 缩减为原来的 1/4,学习率也应缩减为原来的 1/4(例如从 0.04 调到 0.01)。该经验在快速开始(进阶版)的 CIFAR-100 迁移学习示例中同样被采用。

2.2.2 用 -o 参数覆盖配置,避免改动文件

ppcls/utils/config.py 提供了命令行覆盖机制:-o(--override)参数可追加任意配置键值对,例如上面的 -o Optimizer.lr.learning_rate=0.01、-o Global.output_dir="output_CIFAR"、-o Arch.pretrained=True。其原理是 override_config 将 key0.key1.key2=value 字符串按 . 拆分为键路径,递归定位并替换目标值;若键不存在则会打印 "A new field detected!" 并自动创建该字段。这让你在微调时可以复用现成配置文件、通过命令行临时覆盖路径/学习率/预训练开关等参数,不必为每次实验复制一份 YAML。

FAQ

Q1:如何更改输入分辨率?

以将 224 分辨率修改为 320 为例。如果只做训练和评测,只需修改以下三个字段:

  1. DataLoader.Train.dataset.transform_ops.1.RandCropImage.size:从 224 修改为 320;
  2. DataLoader.Eval.dataset.transform_ops.1.ResizeImage.resize_short:从 256 修改为 366(保持约 1.14 的短边缩放比例);
  3. DataLoader.Eval.dataset.transform_ops.2.CropImage.size:从 224 修改为 320。

如果后续还涉及模型导出或 infer,需要同时修改以下字段(与导出配置的联动逻辑见 ppcls/utils/config.py 中的 dump_infer_config,它会将 DataLoader.Eval 或 Infer 的预处理转换写入推理配置):

  1. Global.image_shape:从 [3, 224, 224] 修改为 [3, 320, 320](用于静态图模式与模型导出);
  2. Infer.transforms.1.ResizeImage.resize_short:从 256 修改为 366;
  3. Infer.transforms.2.CropImage.size:从 224 修改为 320。

经验:更大的分辨率通常带来更高的精度,但训练与推理耗时、显存占用也会相应上升;修改时需同步调整 Global.image_shape,避免导出后的 inference 模型输入尺寸与训练/评测阶段不一致。

Q2:如何更改数据增强?

数据增强部分的详细说明参见数据增强文档。PaddleClas 除 ImageNet 标准增强(RandCropImage、RandFlipImage、NormalizeImage)外,还内置了多种增强算子,可归为三类:

  • 裁剪后变换类:AutoAugment、RandAugment;
  • 通道重排后裁剪类:Cutout、RandomErasing、HideAndSeek、GridMask;
  • Batch 级混合类:Mixup、Cutmix。

以 ResNet50_vd.yaml 为例,训练阶段的 batch_transform_ops 中默认启用了 MixupOperator(alpha: 0.2),它属于对 batch 内图像与标签同时做线性混合的增广方式,在 ResNet50 300 epoch 的 ImageNet 实验中可使 Top-1 从 77.31% 提升到 78.28% 量级。更多增强算子的用法、参数与对应配置文件可直接查阅该文档及 ppcls/configs/ImageNet/DataAugment/ 下的配置文件。

Q3:如何更改评价指标?

PaddleClas 的分类指标目前支持 Top-k 准确率。如果需要更改 k 值,可修改配置文件中 Metric.Eval 下的 TopkAcc.topk,例如从 [1, 5] 修改为 [1, 3],即评测指标从 Top-1、Top-5 改为 Top-1、Top-3:

Metric:
  Train:
  Eval:
    - TopkAcc:
        topk: [1, 3]

指标计算与更新逻辑位于 ppcls/metric/metrics.py(TopkAcc 实现)及 ppcls/engine/train/utils.py(update_metric 在训练循环中每 batch 更新指标并用于日志输出)。

Q4:如何进一步提升模型的精度?

  1. 更换更强的模型:如果不考虑推理速度,可以更换在 ImageNet 上精度更高的模型,或使用更大的输入分辨率;如果在意推理速度,建议使用经 PaddleClas 优化的 PP 系列模型,如 PP-LCNet、PP-HGNet 等;
  2. 使用 SSLD 蒸馏预训练权重:PaddleClas 提供 20+ 个 SSLD(Simple Semi-supervised Label Distillation)预训练权重,在很多任务中都能带来 1 个百分点以上的提升。使用方式只需在 Arch 字段下增加 use_ssld: True:
Arch:
  name: ResNet50_vd
  class_num: your_class_num
  pretrained: True
  use_ssld: True

从源码看,use_ssld 会透传到各 backbone 工厂函数(如 ppcls/arch/backbone/legendary_models/resnet.py 的 ResNet50_vd)并最终影响 _load_pretrained 中预训练 URL 的选择。关于 SSLD 的原理(无需真实标签、基于 ImageNet22k 扩充数据、soft label 与 JS 散度蒸馏等)与使用方式,可参考 SSLD 知识蒸馏实战; 3. 调整训练轮数:实际任务中训练轮数对结果影响较大,初期调试可以先使用较小的轮数(如 20)快速验证流程与配置,再逐步增大(Global.epochs 默认为 200,注意余弦退火学习率在轮数较少时收敛效果有限,具体讨论见图像分类训练调参策略); 4. 多尝试几组学习率:模型在微调过程中对学习率较为敏感,建议在参考值(如 ImageNet 默认 0.1 的 1/10)附近多尝试几组,并注意学习率与 batch_size 保持线性关系(切换 GPU 数量后同步缩放学习率)。

此外,若任务数据集较小、存在过拟合倾向,还可结合 图像分类训练调参策略 中的建议进一步调整:适当增大 L2 正则系数(Optimizer.regularizer.coeff)、启用 label smoothing(Loss.Train.CELoss.epsilon,ImageNet 实验中常设为 0.1,大模型上通常有稳定提升)、使用 warmup 策略等;数据规模有限时也可参考 Q2 引入数据增强来提升泛化能力。

相关文档导航

登录后查看全文
PaddleClas