【深度学习|学习笔记】如何提高小型网络的精度?原则 → 方法 → 代码骨架 → 落地细节!(二)

【深度学习|学习笔记】如何提高小型网络的精度?原则 → 方法 → 代码骨架 → 落地细节!(二)



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

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


前言

  • 下面给你一份“小型网络提效路线图 + 可直接复用的 PyTorch 配方”。内容按“原则 → 方法 → 代码骨架 →
    落地细节/坑位”展开,你可以把代码片段按需拼装到自己的训练脚本中。

2) PyTorch“可拼装”训练配方(小网络专用)

  • 说明:下面是可直接集成的函数/模块Label SmoothingMixup/CutMixFocal/类平衡损失Warmup+CosineEMAKD 蒸馏TTASE 模块GroupNorm 小批训练稳定化。你可以把它们嵌入自己的 train_one_epochevaluate 中。

2.1 训练循环(支持 Mixup/CutMix + Label Smoothing + KD + EMA)

def train_one_epoch(
    model, loader, optimizer, epoch,
    criterion_ce, device,
    teacher=None, kd_T=4.0, kd_alpha=0.5,
    use_mixup=True, use_cutmix=False,  # 二选一或都关
    grad_clip=1.0, ema: EMA=None
):
    model.train()
    total_loss = 0.0
    for x, y in loader:
        x, y = x.to(device, non_blocking=True), y.to(device, non_blocking=True)

        lam, y_a, y_b = 1.0, y, y
        if use_cutmix:
            x, y_a, y_b, lam = cutmix_data(x, y, alpha=1.0)
        elif use_mixup:
            x, y_a, y_b, lam = mixup_data(x, y, alpha=0.2)

        logits = model(x)
        ce = mix_criterion(criterion_ce, logits, y_a, y_b, lam) if (use_mixup or use_cutmix) else criterion_ce(logits, y)

        loss = ce
        if teacher is not None:
            with torch.no_grad():
                t_logits = teacher(x)  # 可以用 EMA 教师或预训练大教师
            loss = kd_alpha * ce + (1 - kd_alpha) * kd_loss(logits, t_logits, T=kd_T)

        optimizer.zero_grad(set_to_none=True)
        loss.backward()
        if grad_clip is not None:
            nn.utils.clip_grad_norm_(model.parameters(), grad_clip)
        optimizer.step()

        if ema is not None:
            ema.update(model)

        total_loss += loss.item() * x.size(0)
    return total_loss / len(loader.dataset)

2.2 评估(含 TTA)

@torch.no_grad()
def evaluate(model, loader, device, num_classes):
    model.eval()
    correct, total = 0, 0
    for x, y in loader:
        x, y = x.to(device), y.to(device)
        logits = tta_logits(model, x)  # 如需关闭 TTA,改为 model(x)
        pred = logits.argmax(1)
        correct += (pred == y).sum().item()
        total += y.numel()
    return correct / total

2.3 一把梭的 main(展示:类平衡 + Label Smoothing + Warmup-Cosine + EMA + 自蒸馏)

def run_training(train_loader, val_loader, num_classes=10, epochs=100, lr=0.1, wd=5e-4, device='cuda'):
    student = SmallSEConvNet(num_classes=num_classes).to(device)
    # EMA 自蒸馏:以学生的 EMA 作为教师(无须大教师)
    ema_teacher = EMA(student, decay=0.999)

    # 类平衡权重(从 train_loader 首批统计或预先统计)
    all_labels = torch.cat([y for _, y in train_loader], dim=0)
    cb_weight = class_balanced_weight(all_labels, num_classes=num_classes, beta=0.999).to(device)

    criterion = SmoothCE(eps=0.1, weight=cb_weight)  # Label Smoothing + 类平衡
    optimizer = torch.optim.SGD(student.parameters(), lr=lr, momentum=0.9, weight_decay=wd, nesterov=True)
    scheduler = build_warmup_cosine(optimizer, warmup_epochs=5, total_epochs=epochs)

    best_acc, best_state = 0.0, None
    for ep in range(epochs):
        # 用上一轮 EMA 权重复制到一个“冻结教师”上做蒸馏
        teacher_model = copy.deepcopy(student).to(device)
        ema_teacher.apply_to(teacher_model)  # teacher = EMA(student)
        for p in teacher_model.parameters(): p.requires_grad_(False)

        tr_loss = train_one_epoch(
            student, train_loader, optimizer, ep, criterion, device,
            teacher=teacher_model, kd_T=4.0, kd_alpha=0.6,
            use_mixup=True, use_cutmix=False, grad_clip=1.0, ema=ema_teacher
        )
        scheduler.step()
        val_acc = evaluate(student, val_loader, device, num_classes)

        if val_acc > best_acc:
            best_acc, best_state = val_acc, copy.deepcopy(student.state_dict())

        print(f"Epoch {ep+1}/{epochs} | train_loss={tr_loss:.4f} | val_acc={val_acc:.4f}")

    # 加载最佳权重并再套一次 EMA(提升泛化)
    student.load_state_dict(best_state)
    ema_teacher.apply_to(student)
    return student, best_acc

  • 以上主干可直接搬到你的项目里:无外部依赖(除数据加载外),能在小网络上稳定吃到一波“白给”的精度。

3) 怎么选与怎么调:给出“有数的”优先级与期望收益

  • RandAugment + Mixup/CutMix + Label Smoothing:最先上,常见 +1%~+3% Top-1(小模型更明显)。
  • Warmup+Cosine、合适的 weight_decay、梯度裁剪、SiLU/GELU:训练更稳,+0.5%~+1.5%。
  • EMA 权重:几乎“白嫖”的提升,+0.3%~+1.0%。
  • 类不平衡(Focal/类平衡权重):长尾分布下,目标类 F1/AUC 提升显著。
  • 知识蒸馏(大教师/EMA 自蒸馏):常见 +1%~+4%(视教师质量/温度与 α)。
  • SE/ECA 模块:参数上涨很小,特征选择更好,+0.2%~+1%。
  • TTA:线上允许多次前向时,+0.2%~+0.5%。

注:收益取决于数据规模/噪声/不平衡程度;对极小模型(比如 <1M 参数),蒸馏与数据增广的边际收益更高

4) 常见坑与对策

  • Batch 太小 BN 不稳 → 用 GroupNorm/LayerNorm,或冻结 BN 的统计(eval BN)。
  • 过度增广导致欠拟合 → 降低强度/概率;Mixup/CutMix 仅在中后期使用;或对难样本降低增广强度。
  • 长尾数据下总体 Acc 上升但关键类掉点 → 使用类平衡损失/重采样 + 分层评估(macro-F1、per-class Acc)。
  • 蒸馏不收敛 → 调高温度 T=4~8,减小 kd_alpha,保证教师精度显著高于学生或用 EMA 教师。
  • 小网络欠表达 → 加 SE/ECA、适当加深而非加宽;替换激活为 SiLU/GELU。
  • 复现实验 → 固定随机种子、控制数据顺序、记录所有超参;把“配方”写入配置文件便于 A/B。

5) 针对遥感/时空栅格(如果你的数据是格网/影像)

  • 分块训练 + 重叠滑窗(训练/推理一致),边界 label smoothing 抑制边缘噪声。
  • 多尺度训练/推理(TTA):短边缩放若干尺度后投票。
  • 时序样本构造:用邻近时刻堆叠成多通道;或短序列→Transformer/LSTM 小头部。
  • 类别不平衡:罕见地物/工况用 Focal/类平衡 + 目标挖矿(hard example mining)。
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐