news 2026/5/29 2:50:58

018、困难样本挖掘策略:训练中自动发现易错样本,定向补充标注

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
018、困难样本挖掘策略:训练中自动发现易错样本,定向补充标注

018、困难样本挖掘策略:训练中自动发现易错样本,定向补充标注

去年秋天我在调试一个工业质检项目,模型在产线上跑了一周,漏检率始终卡在0.3%下不去。翻看日志发现,那些漏掉的缺陷样本几乎全是同一个类型——边缘模糊的划痕,标注框里只有几个像素宽。我盯着检测结果看了半小时,突然意识到一个残酷的事实:训练集里这类样本太少了,模型根本没见过足够多的“难例”。

这就是困难样本挖掘(Hard Example Mining)要解决的问题。不是所有样本对模型提升都有同等价值,那些让模型“犹豫不决”的样本,才是真正能推动性能边界的关键。

从损失函数里“抓”出困难样本

困难样本挖掘的核心思路很简单:在训练过程中,让模型自己告诉我们哪些样本它学得不好。最直接的做法就是看损失值——损失大的样本,就是模型当前阶段搞不定的。

我在YOLOv8里实现过一个粗糙版本,代码大概长这样:

# 别这样写,这只是演示思路defhard_example_mining(batch_losses,ratio=0.3):# 按损失降序排列,取前30%sorted_indices=torch.argsort(batch_losses,descending=True)hard_indices=sorted_indices[:int(len(batch_losses)*ratio)]returnhard_indices

这里踩过坑:直接按损失排序取top-k,会导致训练初期大量背景样本被选进来。因为模型刚开始啥都认不出来,背景区域的损失反而最大。正确的做法是只对正样本(包含目标的区域)计算损失排序,或者至少给正负样本分别设置不同的采样比例。

OHEM:在线困难样本挖掘的经典实现

OHEM(Online Hard Example Mining)是目标检测领域的老牌方法,核心思想是让模型先跑一次前向传播,找出损失最大的那些样本,然后只在这些样本上做反向传播。

在YOLOv6里集成OHEM时,我踩过一个坑:OHEM要求两次前向传播,第一次只做推理不更新梯度,第二次才在选出的困难样本上训练。这会带来显存翻倍的问题。我的解决方案是共享特征图——第一次前向传播时把中间特征缓存下来,第二次直接复用。

# 伪代码,实际实现要处理batch维度defohem_forward(model,images,targets):# 第一次前向:只算损失,不更新梯度withtorch.no_grad():features=model.extract_features(images)losses=model.compute_loss(features,targets)# 按损失排序,选出困难样本索引_,hard_indices=torch.topk(losses,k=int(len(losses)*0.3))# 第二次前向:只在困难样本上训练hard_images=images[hard_indices]hard_targets=[targets[i]foriinhard_indices]hard_features=model.extract_features(hard_images)loss=model.compute_loss(hard_features,hard_targets)loss.backward()

这里有个细节容易被忽略:OHEM的采样比例不是固定的。我试过0.1到0.5之间的各种比例,发现0.25左右效果最好。比例太小,模型学不到足够多的难例;比例太大,又退化成全量训练。

Focal Loss:让模型自己“关注”困难样本

OHEM需要显式的采样操作,而Focal Loss是一种更优雅的隐式方案。它通过修改损失函数,让模型自动给困难样本分配更大的梯度权重。

Focal Loss的公式看起来简单,但调参是个技术活:

deffocal_loss(pred,target,gamma=2.0,alpha=0.25):# gamma控制困难样本的关注程度# alpha平衡正负样本ce_loss=F.binary_cross_entropy_with_logits(pred,target,reduction='none')pt=torch.exp(-ce_loss)focal_weight=(1-pt)**gammaifalphaisnotNone:alpha_weight=target*alpha+(1-target)*(1-alpha)focal_weight=focal_weight*alpha_weightreturn(focal_weight*ce_loss).mean()

我在YOLOv11上试过Focal Loss,发现gamma=2.0对大多数场景都够用,但有个例外:当你的数据集里困难样本占比特别高(比如超过40%),gamma反而要调低到1.5左右。因为gamma太大,模型会过度关注那些极难样本,反而忽略了中等难度的样本——这些样本才是提升泛化能力的关键。

动态阈值策略:让挖掘过程自适应

固定比例的困难样本挖掘有个问题:训练初期和后期,模型的“困难”标准完全不同。初期可能所有样本都难,后期可能只有极少数样本难。固定比例会导致后期选进来的样本其实并不难。

我后来在YOLOv8里实现了一个动态阈值策略,效果比固定比例好不少:

classAdaptiveHardMining:def__init__(self,initial_ratio=0.3,decay_factor=0.95):self.ratio=initial_ratio self.decay_factor=decay_factor self.loss_history=[]defupdate_ratio(self,current_losses):# 记录最近N个batch的平均损失self.loss_history.append(current_losses.mean().item())iflen(self.loss_history)>100:self.loss_history.pop(0)# 如果平均损失持续下降,说明模型在变好,可以降低采样比例iflen(self.loss_history)>=10:recent_avg=np.mean(self.loss_history[-10:])old_avg=np.mean(self.loss_history[-20:-10])ifrecent_avg<old_avg*0.9:self.ratio=max(0.1,self.ratio*self.decay_factor)# 根据当前比例计算阈值threshold=np.percentile(current_losses.cpu().numpy(),(1-self.ratio)*100)returnthreshold

这个策略的核心逻辑是:模型学得越好,需要挖掘的困难样本就越少。但要注意,decay_factor不能设得太小,否则采样比例下降太快,模型会错过一些潜在的难例。

数据层面的补充标注策略

困难样本挖掘不只是训练时的技巧,它还能指导数据标注。我在项目中做过一个“主动学习”流程:

  1. 用当前模型对未标注数据做推理
  2. 选出置信度在0.3-0.7之间的样本(这些是模型最不确定的)
  3. 把这些样本交给标注员补充标注
  4. 用新标注的数据继续训练

这个流程跑三轮,标注效率提升至少3倍。因为标注员不再需要标注那些模型已经能搞定的简单样本,只聚焦在模型搞不定的难例上。

个人经验总结

写了这么多,说点实在的。困难样本挖掘不是银弹,它解决的是“样本分布不均衡”的问题。如果你的数据集本身质量很高、分布均匀,强行上困难样本挖掘反而可能破坏训练稳定性。

我的建议是:先用全量数据训练一个baseline,然后分析错误样本的类型。如果错误集中在某几类样本上,再针对性地做困难样本挖掘。别一上来就上OHEM或Focal Loss,先搞清楚问题出在哪。

另外,困难样本挖掘和模型结构是耦合的。YOLOv6的RepVGG结构对OHEM比较友好,因为它的梯度传播更稳定;而YOLOv11的C2f结构配合Focal Loss效果更好。这个没有标准答案,得自己试。

最后提醒一句:困难样本挖掘会增加训练时间,OHEM大概增加30%-50%,Focal Loss基本不增加。如果你的项目对训练速度敏感,优先考虑Focal Loss。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/29 2:46:16

实战Scrapy管道存储:一次爬取,同时存入JSON、CSV和MySQL数据库

大家好,我是老周。上周接了个活——帮一个电商小团队抓取竞品价格数据。需求很简单:每天定时跑爬虫,数据既要给运营的同事直接用Excel打开(CSV格式),又要给数据分析组做历史趋势分析(存MySQL),还得留一份原始数据做备份(JSON格式)。 刚开始我图省事,跑三次爬虫,换…

作者头像 李华
网站建设 2026/5/29 2:45:40

从toad到Scorecard:一个完整Python评分卡模型的落地实战(附代码)

从TOAD到Scorecard&#xff1a;Python评分卡模型全流程开发指南信用风险评估是金融科技领域最核心的应用场景之一。想象一下&#xff0c;当你在线申请信用卡或消费贷款时&#xff0c;后台系统如何在几秒内判断你的信用等级&#xff1f;这背后往往运行着一个经过精心调校的评分卡…

作者头像 李华
网站建设 2026/5/29 2:43:20

数据结构 树

makefileMakefile 是一个自动化编译工具的控制文件&#xff0c;用于管理程序的编译和链接过程。它定义了源文件之间的依赖关系&#xff0c;并指定如何编译和链接程序。通过 make 命令执行 Makefile 中的指令。只重新编译修改过的文件&#xff0c;避免重复编译自动化复杂的编译过…

作者头像 李华
网站建设 2026/5/29 2:20:00

YOLOv11吸烟场景香烟目标检测数据集-18269张-Smoking-Detection-2

YOLOv11吸烟场景香烟目标检测数据集 &#x1f4ca; 数据集基本信息 目标类别&#xff1a; [‘adult’, ‘cigarette’, ‘cige’, ‘person’, ‘smoke’, ‘smoking’]中文类别&#xff1a;[‘成年人’, ‘香烟’, ‘香烟’, ‘人’, ‘烟雾’, ‘吸烟’]训练集&#xff1a;…

作者头像 李华