简介:面向YOLOv11算法改进与目标检测涨点需求的开发者,这份压缩包收录了6篇HTML格式的YOLOv11改进文档,总体约13.49MB。内容聚焦Conv卷积篇的模块替换与二次创新,覆盖ADown轻量化下采样、DCNv4可变形卷积、LDConv线性可变形卷积、HWD Haar小波下采样,以及MAB、MSCB等即插即用模块。每篇文档均交代模块设计原理、提供可直接运行的完整代码,并手把手说明替换位置与修改方式,部分还配有手撕结构图,便于理解结构后迁移到自己的模型中,解决模块不会用、程序跑不通等落地问题。这些HTML文档既可作为理论笔记,也可作为代码手册随查随用。已有543人学习浏览,适合具备一定YOLO基础、希望系统尝试多种Conv改进方案的读者快速上手。
1. YOLOv11改进文档到底在改什么:从改动清单到可复现实验闭环
很多人拿到YOLOv11改进文档,第一反应是往模型里堆模块:加注意力、换损失函数、扩特征层。结果往往是训练一个礼拜,mAP涨了0.3个点,换一个数据集又回到原点。我做目标检测这几年,最大的体会是:改进文档的价值不在那几段代码,而在它有没有帮你把每次改动变成可以回退、对比、复现的实验记录。YOLOv11改进文档要说清楚的,不只是“在哪里改”,更是“改了之后凭什么说有效”。
它解决三类问题:一是模型结构怎么改才不破坏原有推理路径;二是训练策略如何配合结构改动,避免无效调参;三是记录和改进的尺度,什么时候算有效,什么时候只是过拟合。适合的对象包括准备在检测任务里做结构微调的研究者,也包括需要在业务数据集上提升精度的算法工程师。下面内容我按自己习惯的改进流程展开,先立基线,再动手改,最后把坑写进文档,照着来至少能少走一半弯路。
2. 改进文档先立基线:YOLOv11骨架、可改点与第一份对照记录
2.1 从backbone到head:哪些模块值得动,哪些尽量别动
YOLOv11改进文档的第一步不是改代码,而是把模型结构拆成四段来看:backbone、neck、head,以及采样路径。backbone负责从边缘到语义的特征提取,neck负责把不同尺度特征融合起来,head负责对每个位置预测类别和边框,采样路径则决定了特征图缩小到原来的几分之一。这四个部分的风险完全不同,改动的成本和排查难度也不在一个量级。
常见YOLOv11结构里,主干部分由大量C3k2块堆叠而成,靠近输入侧是stem卷积。这部分提取的是通用视觉特征,迁移学习时几乎全部依赖预训练权重。如果在这一层动手,相当于把预训练权重废掉一大半。neck部分一般用PAN结构,自上而下和自下而上的路径都有大量Concat拼接,这里是最安全的改动点。head部分则是解耦的分类与回归分支,改动它会影响两个子任务的平衡。
我做改进前会先画一张可改点表格,把每一个候选改动标上风险等级,这张表同样应该出现在改进文档的开头:
| 部位 | 常见可改点 | 改动成本 | 我的建议 |
|---|---|---|---|
| backbone C3k2 | 在残差路径里挂注意力 | 中 | 可以试,保留外部模块命名 |
| neck特征融合 | Concat换加权融合 | 高 | 必须做权重归一化 |
| head检测头 | 增加P2小目标分支 | 高 | 小目标占比高的数据集才值得 |
| stem卷积 | 基本不动 | 极高 | 除非从头训练,否则别碰 |
| 损失函数 | CIoU换WIoU | 低 | 先单独回测再组合 |
| 训练策略 | EMA、数据增强调度 | 低 | 和结构改动分开验证 |
凡是涉及卷积stride、通道数拼接逻辑的改动,我会标红。这类改动一旦出错,往往训练不收敛但又不报错,整个训练过程看起来正常,就是loss降不下来,特别难查。我在改进文档里会把“可动”和“不建议动”分开写,这是很多人忽略的第一件事。
2.2 最小复现环境与基线训练:一份可抄的shell配置
改进文档如果没有一个能一键复现的环境,那它只能算草稿。我习惯先跑通基线,再改结构。环境上尽量少依赖,避免因为某个包版本问题让改进实验白跑。
# 1) 创建虚拟环境并安装基础依赖 python -m venv venv_yolo11 source venv_yolo11/bin/activate pip install --upgrade pip setuptools wheel # 2) 按本机CUDA版本安装GPU版torch,然后安装YOLOv11所在的开源仓库 pip install torch torchvision --index-url <你的torch安装源> pip install -e /path/to/yolov11-src # 3) 训练前确认显卡可用 nvidia-smi这里有两个容易翻车的地方。第一,torch一定要按本机CUDA版本选,别图省事装CPU版,后面训练慢到让你怀疑人生。第二,不要把依赖一股脑装到全局环境,不同的改进实验最好各自有独立环境,或者至少把requirements版本固定下来,否则你会遇到“昨天还能跑,今天复现不了”的情况。
基线训练命令我一般长这样:
# 用预训练权重训练基线,所有改进开始前先做这次实验 yolo detect train \ model=yolo11n.pt \ data=datasets/your_dataset.yaml \ epochs=100 \ batch=16 \ imgsz=640 \ device=0 \ project=experiments \ name=baseline_yolo11n \ seed=42 \ cache=True \ workers=8逐个说参数:model用预训练权重文件,YOLOv11的n/s/m/l/x代表从小到大不同规模,选n先跑通流程;data指向你自己的数据集配置文件;epochs先100轮,不要贪多,多了反而掩盖改进效果;batch和imgsz决定显存占用,按显卡情况调整;seed固定到42,后续每个实验都用同一个种子,对比才公平;cache=True把图片缓存到内存,速度提升明显但占内存;workers是数据加载进程数,本机系统上建议4左右,服务器可以用8。
跑完基线后,把weights目录里的best.pt和last.pt都复制一份,加上baseline前缀。为什么要两份?best是按验证集选的,last是训练最后一步的。有的改进会出现best反而过拟合,last更稳的情况。改进文档里两份都要记录,不能只留一个。
2.3 改进前必须记录的五个指标
没有对照记录的改进都是玄学。我见过太多同学改了一晚,mAP涨了一点,最后发现是换batch时数据加载方式不同导致的随机波动。改进文档里必须固定记录五个指标:mAP50、mAP50-95、precision、recall、单张推理时间。如果做嵌入式部署,再加上参数量和FLOPs。
| 指标 | 含义 | 怎么读 |
|---|---|---|
| mAP50 | IoU阈值0.5的平均精度 | 高说明框的粗位置准 |
| mAP50-95 | 不同IoU阈值下的平均精度 | 高说明定位精细,改进主要看它 |
| precision | 预测框里真阳性的比例 | 数值低说明虚检多 |
| recall | 真实目标被召回的比例 | 数值低说明漏检多 |
| 推理时间 | 单张图前向耗时 | 改进后不能忽略速度代价 |
记录时,每个改进实验至少跑两次同样的配置。如果两次mAP50-95差超过0.3,先去找实验环境波动,不要记录这个数。我还会额外做一个硬样本子集,把数据集里小目标、遮挡、低光照的图片单独抽出来,后续每个实验都用同一批图片评估。mAP整体涨不代表困难场景涨,改进文档的结论必须分两个维度写:整体指标和硬样本指标。基线阶段就生成这个硬样本列表,后面才有的比。
3. YOLOv11改进优先动这三处:注意力、特征融合与小目标头
3.1 用CA或CBAM侵入C3k2:最小改动与通道缩放
注意力是目前试错成本最低的改进方向。我推荐从Coordinate Attention(CA)开始,它在轻量模型上的精度收益通常好于SE,计算开销又比CBAM小。把注意力挂在C3k2的残差路径后面,比单独增加一个串联块更稳。原因是特征经过了原路径的卷积结构,注意力只负责重标定,不改变空间尺寸和通道拼接逻辑。
下面是一份做二次开发时常用的CA实现,我一般把它放在模型定义同级的modules文件里单独管理:
# modules/ca_attention.py import torch from torch import nn class CoordinateAttention(nn.Module): # 坐标注意力:分别压缩高度方向和宽度方向 def __init__(self, channels, reduction=32): super().__init__() # reduction控制中间层通道数,越大参数量越少 mid = max(8, channels // reduction) self.pool_h = nn.AdaptiveAvgPool2d((None, 1)) self.pool_w = nn.AdaptiveAvgPool2d((1, None)) self.conv_reduce = nn.Sequential( nn.Conv2d(channels, mid, 1, bias=False), nn.SiLU(), ) # 中间层后分别恢复h和w方向权重 self.conv_expand_h = nn.Conv2d(mid, channels, 1, bias=False) self.conv_expand_w = nn.Conv2d(mid, channels, 1, bias=False) self.sigmoid = nn.Sigmoid() def forward(self, x): b, c, h, w = x.shape x_h = self.pool_h(x) # b,c,h,1 x_h = x_h.permute(0, 1, 3, 2) # b,c,1,h x_w = self.pool_w(x) # b,c,1,w # 在高度方向拼接后过同一个卷积,让两个方向共享特征 x_cat = torch.cat([x_h, x_w], dim=2) # b,c,1,h+w x_cat = self.conv_reduce(x_cat) att_h = self.conv_expand_h(x_cat) # 恢复成h分支形状 att_w = self.conv_expand_w(x_cat) # 恢复成w分支形状 att_h = att_h.permute(0, 1, 3, 2) return x * self.sigmoid(att_h) * self.sigmoid(att_w)关键参数是reduction。当channels比较小比如64时,reduction=32会让中间层变成2个通道,信息丢失太严重,所以代码里用max(8, channels // reduction)兜底。pool_h和pool_w分别做长条形池化,提取水平方向和垂直方向的长程依赖,这是CA比SE多出来的优势。最后两个方向sigmoid出来的权重相乘,相当于在像素级做重标定,对小目标比较友好。
接入方式上,我建议在模型定义对应的模块调用处插入,而不是通过改yaml结构字符串去换模块名。直接调用能保留其他部分不动,改动面最小。插入后先跑50轮快速验证,观察训练损失曲线和验证集mAP是否比基线同期高。如果到第20轮还和基线完全一致,多半是前向计算没有把注意力接进主路径,赶紧检查模块被调用到了没有。
3.2 把Concat换成BiFPN风格加权特征融合
YOLOv11改进文档里第二常见的做法是改neck处的融合方式。默认的Concat把两层特征直接按通道拼接,不同特征图的贡献是相等的。换成BiFPN风格后,每个输入特征会带一个可学习的权重,训练时自己学哪个尺度更重要。改进点通常在上采样路径,特征图分别来自P3、P4、P5层,简单加权融合可以这样实现:
# modules/weighted_concat.py import torch from torch import nn class WeightedConcat(nn.Module): # 多输入特征加权融合,权重经过ReLU后除以和,保证稳定训练 def __init__(self, num_inputs): super().__init__() # 初始化成均值,避免一开始偏向某一层 self.weight = nn.Parameter(torch.ones(num_inputs) / num_inputs) def forward(self, inputs): # inputs是一个特征图列表,尺寸必须相同 assert len(inputs) == len(self.weight) # ReLU保证权重非负,再除以总和做归一化,防止数值爆炸 w = torch.relu(self.weight) w = w / (w.sum() + 1e-5) out = 0 for i, x in enumerate(inputs): out = out + w[i] * x return out使用前,需要把参与融合的特征图统一尺寸和通道数。常见做法是先加一个1x1卷积统一通道,再把小特征图双线性插值到大特征图的尺寸。参数上num_inputs对应融合几层特征,比如P3和P4融合时传2。ReLU和归一化这两步一步都不能省。我在第5章会细说去掉归一化之后的中期inf爆炸,这里先记住。
BiFPN论文里还有跨尺度的反复融合,即特征在不同层之间来回融合多轮。但多轮融合会明显增加推理时间,性价比不一定高。我建议先把单层加权融合跑通,确认收益是正向的,再加第二轮。不要一上来就按完整BiFPN搭,训练时间和显存成本都不是线性增长,很容易把自己卡死在“调不完”的境地。
3.3 加P2小目标输出头:参数与精度之间的妥协
小目标场景里,P2输出头是很多人想加的方向。原因是默认YOLOv11在stride 8、16、32三层输出,对应80x80、40x40、20x20的特征图。小目标在20x20这种低分辨率上几乎没有响应,而stride 4的P2层可以保留更多细节。改进方式是:在neck里新增一条自下而上的路径,把浅层高分辨率特征和高层语义特征融合,再单独接一个检测头。
这个方向的坑主要在参数爆炸和训练不稳定。我一般给P2头单独设置通道数,比如主干通道256,P2分支用128或96,而不是直接继承高层通道。下面是一段在模型结构配置里新增P2路径的示意:
# model_cfg/p2_head.yaml 节选 neck: p2_and_p3_fusion: in_channels: [128, 256] # p2输入是高分辨率浅层,p3输入是语义更强层 out_channels: 128 # 通道数设小一点,控制显存和参数量 upsample: bilinear detect: strides: [4, 8, 16, 32] # 加了P2后变成四个输出 head_channels: [128, 256, 256, 256]注意strides里4在最前面,顺序不能乱。显存成本怎么估算:imgsz=640时,stride4特征图是160x160,像素量是P3层80x80的4倍。所以batch通常要减半,并观察训练时显存占用曲线。改进文档里要写清楚:P2头只对“小目标占比高”的数据集有明显收益。如果数据集中目标尺寸都超过32x32像素,加P2很可能是只增加推理耗时,没有mAP提升。
新增检测头还有一个关键点:分支初始化。我习惯把新增头的分类分支偏置设置成bias_init,回归分支的偏置也单独设,避免起步时输出大框导致梯度爆炸。训练前先跑一次短实验,确认loss能从合理位置开始下降,而不是瞬间NaN。
4. YOLOv11改进超参与损失:WIoU、EMA和动态增强的搭配
4.1 把CIoU换成WIoU:困难样本权重怎么调
损失函数改进是最容易被低估的一项,代码改动小,但选错替换策略会把训练带入泥潭。YOLOv11默认边框损失使用CIoU,它考虑了重叠面积、中心点距离、宽高比,问题在于训练后期困难样本的梯度被平均化。WIoU v3的想法是对普通样本降权,对难样本适度提权,让模型把注意力集中在真正没学好的目标上,而不是被简单样本拖着走。
实现上不需要改模型前向代码,只需要在损失计算入口把边框损失替换掉。下面是简化版的接入示意,重点看权重怎么动态变化:
# train/wiou_loss.py # 简化版WIoU,用于替换原始边界框损失的接入示例 import torch import torch.nn as nn class WIoULoss(nn.Module): def __init__(self, alpha=0.5, gamma=1.5): super().__init__() self.alpha = alpha # 难样本权重上限 self.gamma = gamma # 难度放大倍数 def forward(self, pd, gt): # pd/gt: [..., 4] (x1,y1,x2,y2) 格式 pd_cx = (pd[..., 0] + pd[..., 2]) / 2 pd_cy = (pd[..., 1] + pd[..., 3]) / 2 gt_cx = (gt[..., 0] + gt[..., 2]) / 2 gt_cy = (gt[..., 1] + gt[..., 3]) / 2 # 中心点距离,作为最简单的难易度量 dist = torch.pow(pd_cx - gt_cx, 2) + torch.pow(pd_cy - gt_cy, 2) # 距离越大权重越高,alpha控制上限 weight = torch.clamp(dist.detach(), max=self.alpha) return (weight * dist).mean()这段是示意代码,接入真实模型时还要配合IoU项和宽高比惩罚项,不能直接照抄。核心思路是用一个可变的权重系数,让距离误差大的样本贡献更高梯度。实际调参时,我建议只调两个值:异常样本的裁切阈值和训练后期的权重上升速度。如果训练到中后期困难样本减少,需要把阈值抬高,否则模型会过度聚焦个别极端样本,验证集loss抖动。
损失替换后必须做一件事:把回归和分类两部分损失的权重比例打出来。很多改进文档只写换损失,没提box和cls的加权系数。我一般会把box权重从默认值上调一点,分类权重保持不变,先跑100轮,看回归分支loss在训练后期是否还在下降。如果回归部分占比太大,会出现“模型越来越会框,但分类精度原地踏步”的失衡。
4.2 EMA与超参联动:momentum、weight_decay和最大训练轮数
改进文档里如果写了EMA,说明作者踩过“训练指标高、测试指标低”的坑。EMA是模型参数的指数移动平均,推理时用平滑权重,通常比最后一阶段直接训练出的权重更抗噪声。YOLOv11训练时默认会维护EMA,但它的momentum和训练轮数强相关。轮数越短,EMA跟随得越差,反而可能比非EMA掉点。
# hyp/ema.yaml 节选 ema: enabled: True momentum: 0.998 # 越大,旧参数占比越高,适合长训练 decay_type: exp # 按轮数递增衰减,前几十轮别让EMA拖后腿momentum=0.998表示每个step更新后,新EMA参数约等于上一次EMA参数乘0.998,当前模型参数乘0.002。如果只跑80轮,EMA权重会近似停留在十轮前的旧状态,验证集自然掉点。我把它和训练轮数联动:epochs小于100用0.996,100到200用0.998,200以上用0.999。这个联动关系要写进改进文档,不然换个训练长度就复现不了。
weight_decay也和EMA有互动。weight_decay过大会让参数在训练后期持续收缩,EMA的历史区间被拉长,验证精度容易先升后跳水。改进文档应该把weight_decay、EMA momentum、最大训练轮数放进同一个参数表,不要分开调。我常用的起步组合是weight_decay=4e-5、momentum=0.9、EMA momentum=0.998、epochs=120,再依据loss曲线微调。
4.3 动态数据增强:mosaic、mixup和close_mosaic何时开何时关
数据增强这块,改进文档最忌讳只抄参数不抄调度。YOLOv11里Mosaic把四张图拼成一张,小目标提升明显;MixUp把两张图叠加混合,增强颜色和形状变化。这两个增强如果全程都开,后期很容易过拟合。常见做法是让增强强度随训练轮数衰减,训练初期开满,最后十几轮关闭Mosaic,让模型在接近真实分布的图片上微调。
# hyp/augment.yaml 节选 mosaic: 1.0 # 训练初期开启概率 mixup: 0.1 close_mosaic: 15 # 最后15轮关闭Mosaic copy_paste: 0.3 # 实例级复制粘贴,小目标场景有帮助close_mosaic是动态调度里的关键参数。它的逻辑是剩余轮数小于等于15时,Mosaic关闭,但MixUp可以保留,因为MixUp不改变目标位置的真实性。如果数据集小目标很多,我会把close_mosaic从10调到20,多给模型一段适应时间;如果图片尺寸普遍偏大,设10就够,再大反而影响上下文学习。
还有一个容易翻车的点:数据增强改了以后,如果从上次checkpoint恢复训练,调度状态不会自动同步。假设之前用close_mosaic=20训练到第80轮,然后改成15重新加载last.pt继续训练,增强调度器会从头算剩余轮数,导致最后20轮里Mosaic没关。改进文档里,凡涉及数据增强的改动,我宁可重新训练,也不要中途改配置继续跑,中途改动产生的“假性提升”特别多。
5. YOLOv11改进文档典型翻车记录:五个必须避开的改动盲区
5.1 改了backbone但没加载预训练权重,训练损失始终降不下去
现象:把主干里的C3k2换成带注意力的变体后,训练起始loss从0.5跳到3.2,到第20个epoch,mAP还是接近0。检查网络结构没有报错,但训练非常慢。
原因:自定义模块的名称和原始预训练权重的键名不匹配。训练框架加载checkpoint时,遇到权重字典里找不到的键或多余的键,默认跳过,只在日志里打一行提示。替换backbone后,前面几个大块的键名全变了,等于预训练权重一点没用上,整个模型从头学。
解决:替换模块时保留原模块的外部命名。我现在的做法是新模块直接继承原类名,用初始化参数区分是否加注意力。加载权重时写一小段检查代码,打印未匹配权重键的数量。如果未匹配键超过10组,先怀疑键名问题,不要盲目调学习率。这个问题在改进文档里必须放在最前面提醒。
5.2 新增P2小目标头只在训练后期出现NaN,前60轮一切正常
现象:加P2头后,前60轮loss正常,第61轮开始loss突然变成NaN,训练进程没崩,验证集mAP断崖下跌。
原因:P2层特征图分辨率大,检测头和颈部里的BatchNorm统计量在后期受噪声影响,加上学习率还没降到足够低,某个batch的极端梯度越过数值上限,BatchNorm更新产生NaN,后面所有使用该统计量的分支全部被污染。另一个诱因是训练后段Mosaic关闭,输入分布突变,噪声更容易产出。
解决:把训练学习率的最小值调低一倍,同时给新增P2分支加梯度裁剪,比如max_norm=10。还要在训练日志里加一个观察项,每隔5轮检查torch.isnan(loss),一旦发现就在当轮停止并保存快照,方便回退。我后来还发现一个变体:新增分支的BatchNorm默认初始化scale=1,改成0.1可以明显缓解后期NaN。
5.3 BiFPN加权融合没做归一化,正常训练中期突然出现inf梯度
现象:把neck里的Concat换成加权融合后,训练到第30轮左右,某个小时的loss变成inf,恢复上次训练后在同一个轮次附近再出现。
原因:加权融合的“权重”没有被限制为非负,也没做归一化。融合特征来自不同尺度,数值绝对值差异很大,某一层权重学到负值后,融合输出可能出现正负相抵后接近零的特征,引起后续BatchNorm和损失爆炸。单纯用ReLU或Sigmoid保证非负还不够,如果不除以总和,多尺度特征的绝对幅值会持续放大。
解决:在加权融合前,把权重经过ReLU并除以总和,再加1e-5的epsilon。输入特征都先做归一化:要么都用BatchNorm输出,要么先过1x1卷积统一通道再融合。改进文档里应该写:成熟稳定的做法是用等权重初始化跑通,确认数值稳定后再训练,不要一开始就把权重初始化为随机值。
5.4 多个改进一起上,整体涨点但逐项回测时每项都掉
现象:把注意力、WIoU、P2头和关闭Mosaic四个改进同时开,mAP50-95从0.41涨到0.44。为了写文档逐项回测,发现每个单项单独加进去都掉点,去掉某个又回到0.44,完全说不清是哪项起的作用。
原因:各改进之间存在强交互。如果数据集小目标占比高,P2头可能贡献了大部分提升,但注意力改变了浅层特征,掩盖了P2头能学到的信息,单项回测时自然受影响。更隐蔽的是:超参是按四个改进同时上场的配置去调的,单独跑单项时学习率或增强策略不再匹配。
解决:改成一次只改一个变量,每一步保留能回退的权重。至少分三组:基线、单向改进、取消单改进后的整体。回测时固定训练轮数和数据划分,不允许中途改超参。改进文档的结论里,用一张表列出每项改进单独和组合下的差异。宁可写“无显著变化”,也不要写“涨点但原因不明”。
5.5 EMA权重在短训练或迁移学习中反而降低测试精度
现象:用预训练好的权重做微调,只训练50轮,训练集上损失正常,验证集上的每类AP反而比加载原始模型直接推理还低。
原因:预训练权重本身已经是表现不错的模型,微调时EMA从零开始平滑新权重,可预训练权重不在EMA轨迹里。EMA轨迹需要足够多的新训练样本才能真正覆盖旧知识,50轮远远不够。框架默认推理用EMA,就会出现“你调好了新任务,推理时被EMA切回旧分布”的问题。
解决:微调或短训练场景下关闭EMA,或把EMA momentum下调到0.99,推理时切换到当前模型权重再验证。改进文档里每个实验记录要标注用best.pt、last.pt还是ema.pt,三者不能混着对比。我习惯在训练脚本里额外输出一份非EMA的best权重,验证时两套都测一遍,选高的作为发布版本,但文档里两种都要写清楚。
6. 改进结果验证技巧:用配置哈希和回归测试守住每一次改动
我给自己定了一条硬规则:任何改进结果如果没有配置哈希,就不算数。训练生成的hyp.yaml里几十个参数,老靠肉眼看不出差异。我会在改进文档的目录里放一个审计脚本,每次实验结束运行它,把配置和指标写进同一个json文件,保证后面回看时不会记错。
# audit.py: 为每次实验生成配置指纹和指标摘要 import hashlib, json, sys from pathlib import Path def sha12(path): return hashlib.sha256(Path(path).read_bytes()).hexdigest()[:12] exp_dir = Path(sys.argv[1]) # 示例: experiments/exp01_ca meta = { "exp": exp_dir.name, "cfg_hash": sha12(exp_dir / "hyp.yaml"), "model_hash": sha12(exp_dir / "args.yaml"), "map50_95": float(Path(exp_dir / "metrics.json").read_text().split(",")[0]), } out = exp_dir / "audit_result.json" out.write_text(json.dumps(meta, indent=2, ensure_ascii=False), encoding="utf-8")这个脚本的作用是给每次训练配置打唯一指纹。以后想比较两个实验,先比指纹,指纹不同,提的配置就不完全一致,不叫严格对照。我还会同时在两个数据集上验证:一个是原始数据集,一个是硬样本子集。某个改进如果在原始数据集上只涨0.2,但在硬样本子集上涨1.0,说明它确实加强了对困难样本的建模。如果原始数据集涨点而硬样本子集掉点,说明改进只是在整体指标上占便宜,实际部署要谨慎。
实验命名也要有纪律。exp01_ca、exp02_wiou、exp03_p2head,从名字就能反推出改了哪里。配置哈希锁住超参,回归清单锁住验证集,这两个东西组合起来之后,每一次改动就不是玄学。以前我有过顶着压力连调一周,最后发现真正有效的是某次很小的数据增强调整,但当时没记录,等于白做。希望帮到你。
本文还有配套的精品资源,点击获取