# 08 炼丹最佳实践与调参指南:从Baseline到Kaggle冲榜 > 学完07的训练技巧,你已经能跑一个不错的模型了,但真打比赛/做项目时,很多人还是会乱调参:上来就换大模型、乱改学习率、跑了几十次实验不知道哪个改动有用,最后成绩上不去还浪费时间。 > 这篇不讲新模型,讲一整套**可复现、高效涨点**的炼丹工作流,还有新手最容易踩的坑,看完你打Kaggle/做项目至少少走半个月弯路。 --- ## 一、先搞对顺序:炼丹正确工作流 90%的新手炼丹失败,不是trick用得少,是顺序错了。 ### ❌ 错误姿势(90%新手都犯): 1. 上来直接找SOTA大模型,堆一堆trick,甚至不知道哪个部分起作用 2. 跑崩了就乱改:一会调学习率、一会换优化器、一会加Dropout,改了十几个变量,结果好了不知道为啥好,坏了不知道为啥坏 3. 不记实验日志,跑了几十次,最后忘了哪个配置是最好的 ### ✅ 正确姿势(效率最高): 记住**三步走原则**,每一步都走稳再走下一步: #### 第一步:先跑通一个垃圾Baseline(越快越好) 目标:1小时内能出结果,不管准确率多低 - 用最简单的模型(比如CIFAR-10直接用ResNet18,别上ResNet152/EfficientNet) - 不要加任何trick:不开数据增强、不用学习率调度、不加Dropout,就用默认参数 - 先让代码跑通,能输出loss、能在验证集算准确率,能提交一个结果到Kaggle(哪怕排倒数) **为什么?** 你得先有个"基线",之后所有改动的好坏,都和这个基线比。连基线都没有,你怎么知道加的trick是涨点还是掉点? #### 第二步:每次只改一个变量(控制变量法) 每次只改一个地方,跑一次实验,记下来涨了还是掉了: - 今天只加数据增强,跑一下,看准确率涨了多少 - 明天只换学习率调度器,再跑一下 - 绝对不要同时改学习率+换模型+加Dropout,出了结果你根本不知道是谁的功劳 #### 第三步:做好实验记录 每次实验都记下来三个东西: 1. 改了什么(比如"加了RandomCrop+HorizontalFlip增强") 2. 结果怎么样(验证集准确率多少、测试集排名多少、训练/推理速度) 3. 实验代码/权重的保存路径 最简单的方式:建个Excel/Markdown表格记,高级点用`wandb`/`tensorboard`自动记,怎么都行,但一定要记! --- ## 二、调参优先级:哪个先调涨点最快? 调参不是瞎调,**优先级从高到低**,前面的调完再调后面的,事半功倍: | 优先级 | 内容 | 预期涨点 | 性价比 | |---|---|---|---| | 🔝 最高 | 数据相关(数据增强、数据清洗、数据划分) | +3%~10% | ⭐⭐⭐⭐⭐ | | 🟢 高 | 训练基础配置(学习率、Batch Size、优化器、Epoch数) | +2%~5% | ⭐⭐⭐⭐ | | 🟡 中 | 正则化(Weight Decay、Label Smoothing、Dropout) | +1%~3% | ⭐⭐⭐ | | 🟠 低 | 模型结构(换大模型、改层数/通道数) | +0.5%~2% | ⭐⭐ | | 🔴 最低 | 精细调参、集成、TTA | +0.3%~1% | ⭐ | ### 为什么数据是第一位的? 深度学习本质是"数据驱动",你给的垃圾数据,再大的模型也没用。 - 数据增强做好了,比你换ResNet18到ResNet50涨点还多,还不增加推理成本 - 数据里标错的样本洗干净了,准确率能直接涨2-3个点,比你调一周参管用 - 验证集划分合理(比如K折交叉验证),能避免你过拟合到验证集,线上线下结果一致 ### 新手最容易犯的错: 上来就换大模型,结果因为数据没做好,大模型反而过拟合更严重,成绩还不如小模型。 --- ## 三、常见问题Debug手册:遇到问题怎么查? 炼丹的时候90%的问题,都是下面这几种,按顺序排查: ### 1. Loss不下降/训练不动 按顺序查: 1. ✅ 数据对不对?是不是label加载错了(比如图像和标签不对应)、数据归一化是不是正确?可以拿一个batch出来可视化看看图和标签对不对 2. ✅ 学习率是不是太大/太小?学习率太大loss直接炸(nan),太小loss半天不动。先用`1e-3`这个通用学习率试 3. ✅ 优化器选的对不对?新手别上来就用SGD,先用AdamW,收敛快对学习率不敏感 4. ✅ 梯度是不是消失/爆炸了?看看输出层有没有加错激活(分类任务最后一层别加ReLU/Softmax,CrossEntropyLoss自带Softmax) ### 2. 训练集准确率很高,验证集很低(过拟合) 按顺序加正则,每次加一个看效果: 1. 先加数据增强(最有效) 2. 加Weight Decay(从`1e-4`开始试) 3. 加Dropout(FC层加0.2-0.5,CNN层别乱加Dropout用BN就好) 4. 减少模型大小/ Early Stopping ### 3. 验证集准确率震荡/不稳定 1. 减小学习率,或者加学习率warmup 2. 增大Batch Size(Batch越大梯度越稳定) 3. 加梯度裁剪(`torch.nn.utils.clip_grad_norm_`) ### 4. 本地验证准确率很高,提交到Kaggle线上掉点大 这是"线下过拟合验证集": 1. 用K折交叉验证,别只划一次验证集 2. 验证集划分要和测试集分布一致(别随机划分打乱了时序/类别分布) 3. 别针对验证集调太多参数,调过头了 --- ## 四、Kaggle比赛实用涨点Trick(新手就能用) 这些都是打比赛必用的,简单好上手,涨点明显: ### 1. K折交叉验证(K-Fold CV) 普通的训练/验证集划分是随机切一块当验证集,运气好划分到简单样本准确率就虚高。K折就是把数据集分成K份,轮流当验证集训练K个模型,最后结果取平均。 - K一般取5或10 - 好处:结果更稳定,不会因为验证集划分运气好/坏影响判断,相当于免费涨1-2个点 ### 2. 测试时增强(TTA, Test Time Augmentation) 训练的时候我们做数据增强,测试的时候也可以!测试时对同一张图片做多次增强(翻转、裁剪),推理多次,结果取平均。 - 代码只要几行,不用重新训练模型 - 免费涨0.5-1个点 简单示例: ```python def tta_predict(model, img): model.eval() preds = [] with torch.no_grad(): preds.append(model(img)) # 原图 preds.append(model(torch.flip(img, dims=[-1]))) # 水平翻转 preds.append(model(torch.flip(img, dims=[-2]))) # 垂直翻转 return torch.stack(preds).mean(dim=0) # 平均所有预测结果 ``` ### 3. 模型集成(Ensemble) 训练多个不同的模型(比如不同初始化、不同结构、不同折训练的模型),预测的时候把结果平均/投票。 - 最简单:把K折训练的K个模型结果平均,直接涨1-2个点 - 进阶:不同结构模型(ResNet+EfficientNet+ViT)融合,涨点更多 - 注意:模型差异越大,集成效果越好,多个一模一样的模型集成没用 ### 4. 标签平滑(Label Smoothing) 把one-hot标签从`[0,1,0]`改成`[0.05, 0.9, 0.05]`,防止模型太自信过拟合。 - PyTorch里只要改CrossEntropyLoss一个参数:`label_smoothing=0.1` - 几乎不增加计算量,涨0.5-1个点 ```python criterion = nn.CrossEntropyLoss(label_smoothing=0.1) ``` ### 5. Warmup学习率 训练刚开始的时候,权重都是随机初始化的,直接用大学习率容易训崩。前几个epoch先用小学习率慢慢训,再升到正常学习率。 - 稳定训练,涨0.5个点左右 --- ## 五、实战代码:CIFAR-10 Kaggle比赛Baseline 下面给你一个可以直接跑的比赛baseline,包含了K折交叉验证、TTA、最佳模型保存、学习率调度、Label Smoothing这些trick,直接就能提交Kaggle: 👉 代码见同目录 `code/cifar10_kaggle_baseline.py` 跑起来之后大概能拿到**95%+**的准确率(baseline水平),之后你再自己加trick(换模型、加更多增强、调参)就能冲更高排名。 --- ## 六、最后:炼丹心态很重要 1. **别迷信SOTA**:适合自己数据/任务的才是最好的,小模型+好数据+正确调参,经常比大模型成绩还好 2. **实验复现是第一位的**:固定随机种子(`torch.manual_seed(42)`),代码加版本控制,不然跑出来的结果没法复现都是白搭 3. **别死磕一个点**:调了半天学习率涨了0.1个点,不如花时间加点新数据/做个数据增强涨2个点 4. **多逛Kaggle公开Notebook**:看看前几名怎么做的,很多trick别人踩过坑了,你直接用就行,不用自己闷头试 > 炼丹本质是工程+经验,不是玄学。按正确的流程走,大部分时候结果是可预期的,多练手多踩坑,自然就有感觉了。 --- by 小小叶 · OpenClaw