【深度学习|学习笔记】目标检测里 使用预训练模型的优劣 + 从零训练(train from scratch)(含可运行 PyTorch 代码片段与实战建议)

【深度学习|学习笔记】目标检测里 使用预训练模型的优劣 + 从零训练(train from scratch)(含可运行 PyTorch 代码片段与实战建议)

【深度学习|学习笔记】目标检测里 使用预训练模型的优劣 + 从零训练(train from scratch)(含可运行 PyTorch 代码片段与实战建议)



欢迎铁子们点赞、关注、收藏!
祝大家逢考必过!逢投必中!上岸上岸上岸!upupup

大多数高校硕博生毕业要求需要参加学术会议,发表EI或者SCI检索的学术论文会议论文。详细信息可扫描博文下方二维码 “学术会议小灵通”或参考学术信息专栏:https://ais.cn/u/mmmiUz


前言

  1. 为什么/何时用预训练模型(优点与缺点详解);
  2. 什么时候/如何从零训练(风险、技巧与工程要点);
  3. 两段可运行 PyTorch 示例代码:A)基于 torchvision 的使用预训练权重微调(Faster R-CNN),B)从零开始训练同一架构(随机初始化 backbone),并给出训练调度与超参建议。

写得尽量实用——你可以把代码直接放到你的训练脚本里改造使用。

1)使用预训练模型的优点(为什么常用)

  • 收敛更快:ImageNet 等大规模分类预训练提供了很好的低/中层特征(边缘、纹理、语义),检测头只需较少更新就能快速收敛。
  • 数据效率高:在标注昂贵的检测任务上(尤其小/中数据集)能显著提升精度,减少过拟合风险。
  • 稳定性增强:预训练参数作为良好初始点,训练过程更稳定、对学习率更不敏感。
  • 工程便利:立即可用的基线,便于快速原型验证与调参。
  • 适配下游任务:通过微调(只训练 head 或分阶段解冻)可以在不同检测场景快速迁移。

2)使用预训练模型的缺点与限制

  • 域差异(domain gap):当目标域与预训练域(ImageNet、自然图像)差别很大(医学影像、卫星影像、红外、显微图像等),预训练特征可能并不理想,甚至成为限制因素。
  • 潜在偏置/上游任务限制:预训练可能携带上游数据偏差(类别、风格),影响目标检测的特定细节。
  • 限制架构选择:有些现代改进(特殊 normalization、不同通道数)与现成预训练权重不兼容,迫使你重新训练或复杂迁移。
  • 可解释性 / 可控性:如果需要严格控制特征学习过程(例如特定表征需求),从零训练可能更可控。

结论/经验法则:

  • 如果你的检测数据量有限或与自然图像相似 → 强烈建议使用预训练(ImageNet / COCO 等)
  • 如果你的数据与ImageNet差异极大、并且你有大量标注数据或可用大量无标签域数据做自监督/域自适应预训练 → 可以考虑从零训练或先做 domain-adaptive pretraining

3)什么时候要考虑“从零训练”(Train from scratch)

合适情形包括:

  • 大规模标注集(上十万图像),能支撑网络从零学习。
  • 上游任务域差距大(例如红外、医学、卫星),ImageNet 特征不适配。
  • 你想研究/改进骨干结构或归一化方式(例如想用不同通道数、不同 BN 策略或新型 layer),无法直接套用现成预训练权重。
  • 做学术研究:证明某方法在无预训练条件下是否有效(公平比较)。

从零训练的主要挑战:收敛慢、需要更长训练时间、更严格的超参(LR)调节、更强正则与大量数据增强、可能需要更复杂 warmup/优化器。

4)从零训练的关键技巧(详尽清单)

  1. 更长训练时间:通常比微调多数倍的 epochs 或 steps(例如 3–10×)。
  2. 初始化策略:Backbone & RPN & Head 使用合适初始化(Kaiming/He、Xavier);对层归一化/权重初值敏感。
  3. 学习率策略:小的初始学习率 + warmup(线性 warmup 数千 steps),或使用 OneCycle。对大 batch 使用线性缩放规则再配合 warmup。
  4. 优化器:SGD + momentum(0.9)常被用于从零训练,或 AdamW(配合学习率 schedule)。
  5. 更强的数据增强:随机裁剪、多尺度训练(multi-scale)、颜色抖动、随机翻转、mixup/cutmix(当适用)。
  6. 正则与正交手段:weight decay、标签平滑(如果是分类 head)、dropout(按需)、更严格的 anchor/matching 设计。
  7. 归一化策略:若 batch size 很小,BatchNorm 不稳定 → 使用 GroupNorm/SyncBN/LayerNorm 或训练时增大 batch via gradient accumulation。
  8. 更多负样本策略:RPN/anchor 的正负样本比、IoU thresholds 的调整可以帮助稳定训练早期。
  9. 监控与早停:频繁保存 checkpoint、可视化 loss/cls/box loss、mAP,在早期检测问题(如预测异常)。
  10. 有条件地用自监督或 domain-adaptive pretraining:当有大量无标签数据时,先做自监督(比如 MoCo、SimCLR、MAE 等)再微调,往往比纯从零训练更稳定且效果好。

5)实用对比表(预训练 vs 从零训练)

维度预训练微调从零训练
收敛速度慢(需要更多 steps)
数据需求低 / 中高(大量标注)
推荐场景小/中样本,自然图像大样本或域差距大
工程成本高(计算、调参)
性能上限通常高于小样本从零在大量数据 + 精细调参下可比肩或更好

6)示例代码(PyTorch + torchvision):A)微调(使用预训练 backbone);B)从零训练(随机初始化 backbone)

说明:代码使用 torchvision.models.detection.fasterrcnn_resnet50_fpn

  • pretrained=True:使用在 COCO 上预训练的 weights(或 torchvision 早期是 ImageNet resume for backbone)。
  • pretrained_backbone=False:从随机初始化 backbone(注意一些 torchvision 版本有 pretrained_backbone 参数;如果没有,需要手动替换或重新初始化)。

下面示例给出训练 loop 的核心(可扩展到 COCO/Dataset),并标注关键超参与注意点。

通用依赖与 Dataset 说明(先看整体)

# pip install torch torchvision
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision.models.detection import fasterrcnn_resnet50_fpn
from torchvision.transforms import functional as F
from torch.utils.data import DataLoader, Dataset
import torchvision.transforms as T
import random
import numpy as np

  • 你需要准备一个符合 torchvision detection 接口的数据集(每个 item 返回 image (C,H,W) tensor 与 target dict:
target = {
  "boxes": Tensor[N,4],
  "labels": Tensor[N],
  "image_id": Tensor[1],
  "area": Tensor[N],
  "iscrowd": Tensor[N]  # optional
}

  • 建议先用 COCO / VOC 或自定义 DataSet(示例省略数据加载实现细节)。

A)示例:微调(预训练)(推荐用于多数场景)

def get_model_pretrained(num_classes):
    # num_classes includes background (so for COCO 91 or for custom tasks classes+1)
    model = fasterrcnn_resnet50_fpn(pretrained=True)  # backbone + heads pre-trained (torchvision)
    # 替换 box predictor(分类 head)以适配新的 num_classes
    in_features = model.roi_heads.box_predictor.cls_score.in_features
    model.roi_heads.box_predictor = \
        torchvision.models.detection.faster_rcnn.FastRCNNPredictor(in_features, num_classes)
    return model

# 超参(微调)
num_classes = 1 + 20  # example: 20 classes + background
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = get_model_pretrained(num_classes).to(device)

# 优化器:只训练可训练参数(如果你冻结了一些层)
params = [p for p in model.parameters() if p.requires_grad]
optimizer = optim.SGD(params, lr=0.005, momentum=0.9, weight_decay=0.0005)
# 学习率 schedule:例如 step lr 或 ReduceLROnPlateau
lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=8, gamma=0.1)

# 训练 loop(简要)
num_epochs = 12
for epoch in range(num_epochs):
    model.train()
    for images, targets in dataloader_train:
        images = list(img.to(device) for img in images)
        targets = [{k: v.to(device) for k, v in t.items()} for t in targets]

        loss_dict = model(images, targets)
        losses = sum(loss for loss in loss_dict.values())

        optimizer.zero_grad()
        losses.backward()
        optimizer.step()

    lr_scheduler.step()
    # 验证 & 保存 checkpoint

微调提示:

  • 可先冻结 backbone 的大部分层(for name,param in model.backbone.body.named_parameters(): param.requires_grad=False),只训练 RPN + ROI heads +最后几个 backbone 层。
  • head lr 可以稍大(0.005),解冻 backbone 后对 backbone 设置较小 lr(1e-4–5e-5)。
  • 对小 batch(如单卡 batch 2)考虑用 GroupNorm 或 SyncBN(需要改模型并使用分布式训练)。

B)示例:从零训练(随机初始化 backbone)(更挑剔的配置)

import torchvision

def get_model_scratch(num_classes):
    # 检查 torchvision 版本是否允许 pretrained_backbone flag
    # 在某些版本:fasterrcnn_resnet50_fpn(pretrained=False, pretrained_backbone=False)
    model = fasterrcnn_resnet50_fpn(pretrained=False, pretrained_backbone=False)
    # 需要对 backbone/neck/heads 做合理初始化(torchvision 默认会初始化 head)
    # 替换 box predictor:
    in_features = model.roi_heads.box_predictor.cls_score.in_features
    model.roi_heads.box_predictor = torchvision.models.detection.faster_rcnn.FastRCNNPredictor(in_features, num_classes)
    return model

model = get_model_scratch(num_classes).to(device)

# 对模型参数做合理初始化(示例性 He init for convs)
def init_weights_he(m):
    if isinstance(m, torch.nn.Conv2d):
        torch.nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
        if m.bias is not None:
            torch.nn.init.constant_(m.bias, 0)
    elif isinstance(m, torch.nn.Linear):
        torch.nn.init.normal_(m.weight, 0, 0.01)
        if m.bias is not None:
            torch.nn.init.constant_(m.bias, 0)

model.apply(init_weights_he)

# 优化器:更保守 lr + warmup
# 建议:使用 SGD+momentum,初始 lr 较小,配合 warmup
params = [p for p in model.parameters() if p.requires_grad]
optimizer = optim.SGD(params, lr=0.01, momentum=0.9, weight_decay=0.0005)

# 实现简单 linear warmup scheduler(示例)
def warmup_lr_scheduler(optimizer, warmup_iters, warmup_factor):
    def f(x):
        if x >= warmup_iters:
            return 1
        alpha = float(x) / float(warmup_iters)
        return warmup_factor * (1 - alpha) + alpha
    return torch.optim.lr_scheduler.LambdaLR(optimizer, f)

warmup_iters = 1000
warmup_factor = 0.1
warmup_scheduler = warmup_lr_scheduler(optimizer, warmup_iters, warmup_factor)
# 后续再使用 StepLR/Cosine decay 等

# 训练 loop(更长)
num_epochs = 24  # 比微调时可能要多几倍
global_step = 0
for epoch in range(num_epochs):
    model.train()
    for images, targets in dataloader_train:
        images = list(img.to(device) for img in images)
        targets = [{k: v.to(device) for k, v in t.items()} for t in targets]

        loss_dict = model(images, targets)
        losses = sum(loss for loss in loss_dict.values())

        optimizer.zero_grad()
        losses.backward()
        optimizer.step()

        # warmup 步进(按 step)
        if global_step < warmup_iters:
            warmup_scheduler.step()
        global_step += 1

    # epoch-level scheduler step(如 StepLR)
    # 验证 & checkpoint

从零训练特别注意:

  • 训练更久:把 epoch 数设长并定期评估(mAP)。
  • 数据增强:强烈建议使用多尺度训练(在训练中随机改变输入短边/长边)、随机裁剪、颜色扰动等。
  • 归一化:如果 batch 很小,避免使用 BatchNorm,改用 GroupNorm(需要修改 backbone)或用 SyncBN(多卡训练)。
  • RPN/anchor tuning:不同数据集物体尺度/纵横比不同,可能需要调整 anchor 尺寸与比例、NMS thresholds、positive IoU threshold 等。
  • 监控多个 loss 项(RPN cls/box, ROI cls/box),尤其训练早期可能 RPN 很弱需要手动检查和调整。

7)目标检测从零训练与预训练比较的实战建议(最终总结)

  • 优先策略:能用预训练就用——特别是数据少或资源有限。
  • 若决定从零训练:
    (1)准备好大量标注或先做自监督/域自适应预训练;
    (2)使用合理初始化、warmup、SGD+momentum、小初始 lr、强 augment、更多训练 epoch;
    (3)使用 GroupNorm 或 SyncBN 来应对小批量问题;
    (4)调整 anchor、NMS、IoU thresholds 以匹配目标尺度分布;
    (5)保存大量 checkpoint 并频繁评估(避免白白训练很久在错误设置上)。
  • 混合策略:当域差距中等时,常见做法是先用 ImageNet/COCO 预训练的 backbone,再在目标域大量无标签数据上做自监督微调(MAE / MoCo / SimCLR),最后再做目标检测微调——通常优于直接从零训练。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不想努力的小土博

您的鼓励是我创作的动力!谢谢!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值