主动学习基础:不确定性采样、查询策略与设定
各位同学,今天我们来聊聊主动学习的核心。说白了,就是让模型学会「主动提问」。
我刚开始做这个方向时,总觉得有点玄乎。模型还能自己挑数据学?后来踩过几次坑才明白——这玩意儿本质上是个「效率游戏」。你想想看,标注数据那么贵,能不能让模型自己挑最有价值的样本去学?
一、不确定性采样:模型最「困惑」的地方
不确定性采样,是主动学习里最直观的策略。核心思想很简单:模型对哪些样本最没把握,就优先学哪些。
我个人习惯把不确定性分成三类来理解:
- 熵(Entropy):信息论里的概念,衡量混乱程度。模型输出概率分布越均匀,熵越大,说明它越不确定。
- 边际(Margin):看最高概率和第二高概率的差值。差值越小,说明模型在两个类别间摇摆不定。
- 置信度(Confidence):直接看最高概率值。值越低,模型越没信心。
举个例子,假设模型要对一张图片做三分类:
| 样本 | 类别A概率 | 类别B概率 | 类别C概率 | 熵 | 边际 | 置信度 |
|---|---|---|---|---|---|---|
| 样本1 | 0.95 | 0.03 | 0.02 | 0.28 | 0.92 | 0.95 |
| 样本2 | 0.40 | 0.35 | 0.25 | 1.08 | 0.05 | 0.40 |
| 样本3 | 0.60 | 0.20 | 0.20 | 0.95 | 0.40 | 0.60 |
看到没?样本2的熵最高、边际最小、置信度最低。三种指标都指向同一个结论——这个样本最值得标注。
核心原则:不确定性采样不是选「模型已经会的」,而是选「模型最不会的」。
二、查询策略:怎么选?选多少?
策略这东西,说白了就是「怎么挑样本」的规则。我见过不少新手一上来就堆复杂策略,结果效果还不如简单的。嗯,这里要注意:先跑通基线,再谈优化。
2.1 不确定性采样策略
刚才提到的三种指标,都可以直接作为查询策略:
- 熵采样:选熵最大的前K个样本。适合多分类任务。
- 边际采样:选边际最小的前K个样本。对二分类特别有效。
- 置信度采样:选置信度最低的前K个样本。计算最简单,但容易受异常值影响。
我在项目中遇到过一个问题:用置信度采样时,模型对某些「噪声样本」特别没信心,结果选了一堆垃圾数据回来。后来我加了多样性约束,才把效果拉回来。
2.2 池化设定 vs 流式设定
这两个概念,决定了你的主动学习系统怎么「喂数据」。
| 特性 | 池化设定 | 流式设定 |
|---|---|---|
| 数据来源 | 预先收集好的未标注池 | 实时到达的数据流 |
| 查询时机 | 每轮从池中批量选 | 每个样本到达时决定是否标注 |
| 典型场景 | 图像分类、文本分类 | 推荐系统、实时监控 |
| 计算开销 | 每轮需评估整个池 | 每个样本单独评估 |
我个人更推荐新手从池化设定开始。为什么?因为好调试。你可以把整个未标注池存下来,反复实验不同的查询策略。流式设定虽然更贴近真实场景,但一旦策略选错,数据就流走了,想追都追不回来。
小技巧:做池化设定时,建议每轮选5%-10%的池子大小。选太多,模型学不到新东西;选太少,迭代太慢。
三、知识体系总览
下面这张图,是我自己总结的主动学习核心逻辑。你看一遍,应该能对整体框架有个清晰印象。
四、代码实战:一个最小实现
光说不练假把式。下面这个代码片段,是我常用的不确定性采样实现。你直接拿去改改就能用。
import numpy as np
def uncertainty_sampling(probs, strategy='entropy', k=10):
"""
probs: 模型输出的概率矩阵,shape=(n_samples, n_classes)
strategy: 'entropy' | 'margin' | 'confidence'
k: 要选择的样本数
"""
if strategy == 'entropy':
# 熵:-sum(p * log(p))
scores = -np.sum(probs * np.log(probs + 1e-10), axis=1)
elif strategy == 'margin':
# 边际:最高概率 - 第二高概率
sorted_probs = np.sort(probs, axis=1)
scores = sorted_probs[:, -1] - sorted_probs[:, -2]
# 边际越小越不确定,取负号
scores = -scores
elif strategy == 'confidence':
# 置信度:最高概率
scores = -np.max(probs, axis=1)
else:
raise ValueError(f"Unknown strategy: {strategy}")
# 选分数最高的k个样本
selected_indices = np.argsort(scores)[-k:]
return selected_indices
# 使用示例
probs = np.array([
[0.95, 0.03, 0.02],
[0.40, 0.35, 0.25],
[0.60, 0.20, 0.20]
])
indices = uncertainty_sampling(probs, strategy='entropy', k=2)
print(f"选中的样本索引: {indices}")
# 输出: [1 2] —— 样本1和样本2最不确定
避坑指南:我曾经在熵的计算里忘了加 1e-10,结果 log(0) 直接报错。这种小细节,跑一次线上就记住了。
五、实际项目中的选择建议
说了这么多,到底该用哪种策略?我根据经验给个参考:
- 二分类任务:边际采样效果最好,计算也快。
- 多分类任务:熵采样更稳定,但计算稍慢。
- 类别极度不平衡:置信度采样 + 类别平衡约束,防止模型只挑多数类样本。
- 流式设定:用阈值法,置信度低于某个阈值就标注。阈值设0.6-0.7比较安全。
嗯,最后提醒一句:没有银弹。我见过有人在图像任务上用熵采样效果爆炸,换到文本任务上就拉胯。多试几种策略,用验证集跑一轮,哪个好就用哪个。
公众号:蓝海资料掘金营,微信deep3321