资讯动态

主动学习关系抽取实战:降低标注成本,用更少样本稳定模型效果

发布时间:2026/10/14 5:32:19 来源:尧图企业网站定制
简介面向NLP关系抽取研究者的主动学习完整项目包基于BERT等预训练模型针对监督学习依赖大量标注样本的问题实现不确定性、多样性、代表性多种采样算法并提出多标准融合策略以提升小样本场景下的抽取效果。压缩包共60个文件包含26个Python源码模型训练、数据处理、评估模块、11个YAML配置超参与环境设定、6份Markdown说明文档、4个CSV数据文件以及毕业设计论文PDF大小仅3.8MB结构清晰便于复盘。已有531人学习适合需要借鉴主动学习与关系抽取实验设计的科研人员。从数据选择、训练器到PCNN、Attention、Transformer等模型实现一应俱全配合可视化图片、配置文件和论文可快速复现实验或扩展自己的采样策略。1. 主动学习关系抽取用更少标注样本换来不掉点的关系模型关系抽取模型的训练成本主要不是算力而是标注。一个工程师要标完一批实体关系样本光搞清楚 schema 和实体边界就能耗掉两周。主动学习的思路是让模型从候选池里挑选“最值得标”的样本而不是随机抽一批。它把标注预算当成有限资源来规划每标一条都争取让模型决策边界的移动最大。我以主动学习关系抽取这个方向为切入点直接梳理完整落地路径从采样策略原理讲起到项目结构、可跑代码和关键参数最后把在真实任务里踩过的坑列一遍。适合正被标注成本卡住、想用更少数据把关系抽取做起来的工程师和研究者。2. 为什么关系抽取离不开主动学习标注瓶颈与核心采样策略关系抽取的标注复杂度和成本远超文本分类这也让主动学习天然成为这个任务里的高杠杆手段。这一章先把“为什么需要”讲透再给出采样策略的选型理由让你后面看代码时不至于只知命令、不知取舍。2.1 关系抽取的标注成本为什么“多标注”不一定是好事关系抽取的标签不是句子级而是实体对级。一个文档里可能同时出现五六组实体每组实体之间有没有关系、是什么关系都需要单独判断。标注者往往要先识别实体边界再跑到 schema 里找关系类型遇到“毕业于”和“任教于”这类易混类别还要反复确认。如果实体对之间没有关系还得标一个“other”或者“无关系”。这个流程决定了标注单价天然比分类标注高不少。更麻烦的是自然文本里实体对大多没有关系负例比例往往超过七成。如果采用随机采样标回来的数据大部分是模型已经能轻松判断的“大路货”信息密度很低。模型真正不能区分的样本比如“A 创立了 B”和“A 接管了 B”这两类语义接近的触发词反而很少被随机抽中。换句话说标注预算花得越多模型效果可能增长越快但边际递减非常严重。主动学习在这里的价值不是增加数据量而是改变“该标哪一批数据”。它用当前模型对未标注池做预测再按一定策略挑出模型最没有把握的样本。这样每一轮新标注数据都能补上模型决策边界的短板而不是在已经学得很好的区域继续叠加相似样本。我在实际项目里见过的最直观对比是同样 5000 条标注预算随机采样做到 73% 的 F1主动学习用了不到一半预算就追平后面两千条几乎每一轮都在涨点。不过要提一个反直觉的坑主动学习会把标注规范里模糊的地方全部挖出来。当模型挑出那些它特别不确定的句子标注者也会发现“自己其实也不知道怎么标”。所以做主动学习之前最好先把 schema 和标注手册收敛好否则模型不仅不能帮你降本反而会加速暴露标注质量问题。这不算坏事但你要有这个预期。2.2 主动学习循环模型、标注者、数据池三者怎么配合主动学习不是单独的一个算法也不是一个模型结构而是一套训练-采样-标注-再训练的闭环。我先描述标准流程第一步用初始已标注样本训练一个关系抽取模型第二步用这个模型对未标注池里的所有样本做推理第三步按采样策略给每个样本打分取出分数最高的 k 个第四步把这 k 个样本交给标注工具或标注者得到新标注数据第五步把新数据并入训练集重新训练模型然后重复第二步到第五步直到标注预算用完或模型效果达到目标。这个循环里初始样本的规模很关键。我一般会用总预算的 10% 到 20% 做随机采样来训练初始模型。如果初始样本太少模型本身什么都学不到它对所有样本的预测都会接近均匀分布采样分数也就变成了随机数。主动学习的前提是“模型当前的不确定性是可信的”而可信的前提是模型至少见过一些正例和反例。每一轮的采样数量也要控制。占比太大模型一次学太多新样本容易把训练分布拉偏占比太小训练次数太多工程成本又不划算。常见做法是每轮采样量设为总预算的 5% 到 10%。另外每一轮训练结束都要在固定验证集上进行评估不仅是为了看涨没涨更重要的是判断当前模型是否过拟合到上一批样本。如果验证 F1 开始掉下一个采样轮次的结果就会不可靠因为模型已经不太记得更早的训练分布了。2.3 采样策略怎么选不确定性、多样性与预期模型变化采样策略是整个主动学习循环的灵魂。做关系抽取时最常用的基线是“熵不确定性采样”对每个未标注样本模型输出在关系类别上的概率分布计算这个分布的熵熵越高说明模型越没把握优先采样这些样本。如果用的是多分类关系头熵直接作用在 softmax 输出上就行如果用的是多标签关系头就得分关系计算熵再取平均或最大值否则一个模型明明只对某个关系不确定其他关系都确定会被平均熵稀释掉。熵采样的问题也很明显它只关注单点不确定性完全不关心样本之间的相似度。未标注池里如果有大量同一事件模板的句子比如同一个公司新闻里反复出现的“某某担任CEO”熵采样会挑出一堆语义几乎相同的句子。标第一批还有用标到后面就全是重复信息。这个时候需要补一个多样性模块。我习惯的多样性做法是把未标注池里的句子用预训练模型转成稠密向量再做聚类。聚类数设为采样数的 2 到 3 倍然后每个簇内选一个熵最高的样本。这样既保留了模型的“不确定”又强制样本覆盖不同语义区域。这个组合在中文关系抽取任务上比纯熵采样普遍高 5 到 8 个点的最终 F1而且训练曲线更稳。更贵的方法还有预期模型变化、基于梯度模长采样它们需要计算加入样本后模型损失的期望变化或梯度影响效果理论上更好但对算力和代码复杂度的要求高。我的建议是先用“熵 聚类”跑通如果后面确实发现数据分布特别复杂再往更贵的方法迁移。主动学习这个方向里策略复杂度不是越大越好而是要能解释每一轮采样为什么选这些样本。3. 解压后的主动学习关系抽取目录结构、数据模型与控制循环标题里挂着 zip那我直接按一个可复跑的项目结构来讲。拿到这类项目我最先关心的不是模型用的哪个预训练权重而是目录是不是解耦。主动学习流程里数据、模型、采样和控制循环必须互相独立否则后面换策略、换模型、换数据集都会牵一发动全身。3.1 目录结构与模块划分让采样、训练、标注解耦我一般会把项目组织成四个核心目录加一个结果目录。数据目录负责管理已标注集、未标注池和 schema模型目录只放编码器和分类头训练逻辑active 目录放采样与循环控制scripts 目录放入口脚本和配置文件。results 目录用来记录每轮采样结果和学习曲线这个目录很多人忽略等到想复盘时才发现前面没有落盘。project_root/ ├── data/ │ ├── labeled/ │ ├── unlabeled/ │ ├── schema.json │ └── preprocess.py ├── model/ │ ├── bert_rel.py │ ├── train.py │ └── predict.py ├── active/ │ ├── sampling.py │ ├── diversity.py │ └── loop.py ├── scripts/ │ ├── run_active_learning.sh │ └── config.yaml └── results/这个结构里“模型”和“主动学习”是两条独立的链路。训练代码不需要感知采样策略采样代码也不需要关心模型内部梯度。这样做的最大好处是当你从熵采样换成聚类多样性只需要替换 active 模块里的函数模型训练代码一行不动当你把 BERT 换成一个更小的编码器也不会影响采样逻辑。另一个容易被忽略的是 config.yaml。它应该统一管理预训练模型名、路径、采样比例、最大长度等参数而不是让这些常量在各脚本里到处飞。我会把 config 做得足够细并且对每个参数加注释因为主动学习每轮训练迭代次数多参数一变前后采样分数可能就完全不可比了。3.2 数据层设计已标注集、未标注池与 schema 定义关系抽取的主动学习数据层核心是三块已标注集用于训练未标注池用于采样schema 定义关系类别和实体类型。已标注集和未标注池最好是同构的也就是相同字段结构否则采样模块要写两套解析逻辑。{ relations: [works_at, graduated_from, located_in, founded_by, other], entity_types: [PERSON, ORG, GEO, DATE], max_length: 256 }这里把“other”显式放进 relations非常关键。很多关系抽取数据会把无关系表示成“实体对不出现在样本里”但主动学习采样时你必须让模型对“无关系”也能产生一个类别的置信度否则无法计算不确定性。我建议把 other 作为一个独立的类别采样时才能捕获那些模型分不清有关系还是没关系的高难样本。数据预处理上我强烈建议保存实体的字符偏移位置而不是分词后的索引。中文预训练模型用 tokenizer 分词后一个汉字可能被拆成多个 token字符偏移和 token 偏移之间要做映射处理不好就会错位。我的习惯是在预处理时先得到字符级位置再在模型输入阶段转换成 token 级位置这样数据文件和模型解耦后续换 tokenizer 也不用重新标数据。3.3 模型层预训练编码器加实体对分类头的实现关系抽取模型不必一上来就做端到端联合抽取。主动学习场景下我更推荐两阶段方案先用 NER 定位实体再对实体对做关系分类。这个方案在采样时更有解释力因为你可以分别观察实体识别的不确定性和关系分类的不确定性。端到端模型虽然效果好但主动学习采样的可解释性差出了问题不好定位。下面给出一个最常用的关系分类模型实现用预训练编码器得到 token 表示把两个实体 span 各自做平均池化再拼接两个实体表示和它们的差值接一个分类头。差值特征对方向性关系很有效比如“被任命为”和“任命了谁”在语义上有方向差异。# model/bert_rel.py from transformers import BertModel import torch.nn as nn class BertRelClassifier(nn.Module): def __init__(self, num_classes, dropout0.15): super().__init__() self.bert BertModel.from_pretrained(bert-base-chinese) self.dropout nn.Dropout(dropout) self.classifier nn.Linear(self.bert.config.hidden_size * 3, num_classes) def forward(self, input_ids, attention_mask, head_pos, tail_pos): outputs self.bert(input_ids, attention_maskattention_mask) last_hidden outputs.last_hidden_state heads self._span_pool(last_hidden, head_pos) tails self._span_pool(last_hidden, tail_pos) features torch.cat([heads, tails, heads - tails], dim-1) logits self.classifier(self.dropout(features)) return logits def _span_pool(self, hidden, span_positions): pooled [] for i, (s, e) in enumerate(span_positions): span_vec hidden[i, s:e 1, :].mean(dim0) pooled.append(span_vec) return torch.stack(pooled)这段代码里span_pool 用的是平均池化而不是只取首尾 token。关系触发词经常出现在实体中间的上下文里平均池化能把整个 span 的语义都带进去。head_pos 和 tail_pos 是每个样本的实体位置形状是 (batch, 2)分别表示 head 和 tail 实体的起始与结束索引。这里有个容易踩雷的参数dropout。主动学习每轮数据量小dropout 太大会让模型欠拟合太小又会让采样分数对同一个样本在不同轮次之间波动太大因为模型训练不稳定。我一般设置在 0.1 到 0.2 之间并且根据验证集表现微调不会一上来就套用文本分类常用的 0.1。3.4 控制循环把采样、标注、训练串成闭环控制器是整个项目的骨架。它不实现具体模型也不实现采样策略只负责把流程串起来。常见做法是一个独立模块暴露“采样一批样本 → 返回待标注列表 → 接收标注结果 → 更新训练集”四个步骤。每轮循环的状态都落盘这样进程中断后可以断点续跑不用重新采样。# active/loop.py def run_cycle(model, unlabeled_pool, sampler, label_func, query_size): scores sampler.score(model, unlabeled_pool) selected sampler.select(scores, query_size) labeled label_func(selected) return labeled控制器最重要的约束是不要直接访问模型内部参数也不要让 sampler 接收训练函数。如果采样模块依赖了模型的权重更新方式你后面换训练策略就会连带改采样逻辑耦合度一下就上去了。保持边界干净才能保证主动学习和关系抽取这两个方向可以独立迭代。4. 从零跑通主动学习关系抽取最小命令、采样代码与参数这一章直接给你能上手的命令和代码。我默认你已经准备好了已标注小集和未标注池格式是上面章节里的实体对样本。如果你的数据还是原始文本先用预处理脚本转成实体对样本格式。4.1 最小复现流程用 Shell 脚本串联第一轮主动学习先给一个入口脚本把“预处理 → 初始训练 → 采样 → 标注 → 重训”串起来。这个脚本把每个阶段独立成命令方便你在某一阶段失败后单独重跑。# scripts/run_active_learning.sh set -e CONFIGscripts/config.yaml python data/preprocess.py --config $CONFIG python model/train.py --config $CONFIG --train data/labeled/round0.json python active/sampling.py --config $CONFIG \ --checkpoint output/round0_model.pt \ --pool data/unlabeled/pool.json \ --query-size 200 \ --output data/to_label/round1.json # 标注完成后把 results/annotation_round1.json 并入训练集 python model/train.py --config $CONFIG --train data/labeled/round1.json这个流程看起来简单但有一个细节容易翻车第二轮训练一定要从同一个初始 checkpoint 开始而不是接着 round0 的模型权重继续训练。如果直接接着上一轮模型权重往下训采样分数和训练分布都会被上轮的随机性影响主动学习曲线会出现明显抖动。我一直用 round0 生成的 checkpointer 作为每次新训练的基础再在上一轮已有数据上继续训。这里的--query-size 200是单轮采样量我一般按总标注预算的 5% 到 10% 设置。比如预算总共 4000 条初始随机标 600 条剩下 3400 条分给后续多轮每轮 200 到 300 条比较合适。config.yaml 里要把 checkpoint 路径、数据路径、模型名全部写清楚不要写在 shell 脚本里否则每换一轮实验就要改脚本。4.2 核心采样代码熵不确定性采样与多样性去重先实现最基础的熵采样。这里要注意 scipy 的 entropy 函数默认按行计算熵输入 shape 需要是 (n_classes, n_samples)所以对概率矩阵要做转置。这个细节不处理好算出来的分数完全是错的。# active/sampling.py import numpy as np from scipy.stats import entropy def uncertainty_score(logits): # logits: [num_samples, num_classes] probs np.exp(logits - np.max(logits, axis-1, keepdimsTrue)) probs probs / probs.sum(axis-1, keepdimsTrue) # 转置后计算每个样本的熵 return entropy(probs.T)这个函数输入的是模型输出的 logits而不是概率。先用减最大值的方式做数值稳定再归一化成概率最后计算熵。熵越大模型在类别之间越摇摆。对文本里那些模棱两可的“其他”关系样本这个分数通常比较高因为它们会同时激活多个关系类别。但纯熵采样在关系抽取里很容易崩因为大多数未标注池里的普通句子模型都给很高的“无关系”概率熵其实不高。真正被选出来的是少量类别概率均匀的样本如果这些样本恰好都是无法判断的噪声那你采回来的标注质量会很差。所以我把多样性去重放在同一轮采样里二者不是二选一。# active/diversity.py from sklearn.cluster import KMeans import numpy as np def diversity_select(embeddings, scores, query_size, n_clusters_factor3): n_clusters min(len(embeddings), query_size * n_clusters_factor) km KMeans(n_clustersn_clusters, n_init10, random_state42) labels km.fit_predict(embeddings) selected [] for c in range(n_clusters): idx_c np.where(labels c)[0] best_in_cluster idx_c[np.argmax(scores[idx_c])] selected.append(best_in_cluster) if len(selected) query_size: break return np.array(selected)这段代码先对句向量做 K-Means簇数设置为 query_size 的三倍然后每个簇内选一个熵最高的样本。n_clusters_factor是多样性强度核心参数。太小时簇数量不足每个簇太大选出来的样本仍然会扎堆太大时每个簇里样本太少和随机挑一个没什么区别。我在中文关系抽取上常用 2 到 3但建议你在自己的数据上扫一遍对比不同值下的最终 F1。聚类用的 embeddings 从哪来我一般直接用关系抽取模型里 BERT 的 [CLS] 向量或者对句子求平均池化。用当前模型得到的向量比外部通用 embedding 更好因为它携带了关系分类任务的信息能反映出“模型觉得哪些句子语义接近”。这也是主动学习里常见做法。4.3 参数表与调参方向预算、截断长度、学习率与轮数主动学习关系抽取的参数分两类一类是主动学习循环参数一类是模型训练参数。下面这张表是我每次做新任务都会先固定的默认值。参数建议值说明初始标注数总预算的 10% - 20%太少模型学不动采样分数不可信每轮采样数总预算的 5% - 10%太多样本冗余太少则迭代太慢最大长度256 或 384实体对和触发词可能跨句首尾128 容易截断学习率2e-5 到 5e-5每轮训练数据量小学习率太大会遗忘旧知识训练轮数3 - 10 轮建议用验证集早停不固定轮数聚类 factor2 - 3控制多样性去重强度dropout0.1 - 0.2防止小样本过拟合也防止采样不稳定最大长度这个参数我踩过重坑。关系抽取里一个句子可能前面提到实体 A后面隔了几十个词才出现实体 B触发词在中间。如果最大长度设置成 128实体 B 被截断样本直接不可用。后来我把一个长文本类的数据集从 128 改成 384关系抽取的召回率立刻提升了十多个点。所以遇到这种任务先看样本长度分布再定 max_length别直接用文本分类的经验值。学习率在主动学习里比普通训练更敏感。因为初始模型已经在标注集 A 上收敛加入新标注集 B 后如果学习率太大模型会迅速倒向 B丢失 A 里学到的旧知识如果太小又学不动新样本。我习惯用和学习率预热类似的做法新数据进来先用较小学习率训练一个 epoch 稳定一下再恢复正常学习率。4.4 评估与可视化学习曲线如何证明策略有效评估主动学习不能用“最终一次训练后的准确率”作为唯一标准。更科学的方法是画学习曲线横轴是累计标注样本数纵轴是固定测试集上的 P、R、F1。每轮训练结束记录当前训练集大小和验证集 F1。# 记录每轮结果 results [] for round_idx in range(total_rounds): train_and_update(...) p, r, f1 evaluate(checkpoint, test_set) results.append({round: round_idx, labeled: len(train_set), f1: f1})有了这条曲线你还要跑一条随机采样基线。随机基线用相同预算随机抽取样本同样每轮记录学习曲线。如果主动学习的曲线始终在随机基线上方且涨得更快才能证明你的采样策略有效。如果两条曲线基本重合说明采样策略并没有带来信息增益可能是数据池分布已经接近随机水平也可能是模型容量不够导致选出来的样本学完后提升有限。我在实际项目里还会额外记录每轮被采样样本的标注来源用来排查是不是某一批标注质量出了问题。主动学习是一个依赖每轮反馈的系统中间任何一环被污染最终效果都会失真。没有落盘记录的话出了脏数据很难定位到具体轮次。5. 主动学习关系抽取避坑指南五个高频翻车现场这一章把我做主动学习关系抽取以来遇到过的、也看别人翻过车的五个问题写下来。每一条都按“现象、原因、解决”展开你可以直接对着排查。5.1 现象采样样本全扎堆在同一个触发词上模型一直在原地打转如果只用纯熵采样很容易出现这个问题。模型对高频触发词比如“任职于”相关的句子已经有一定信心但对某些变体会反复摇摆低频触发词句子因为分布稀疏看起来熵很高但它们彼此语义差异很大。纯熵采样不关心这种差异于是每轮挑回来的样本都围绕几个高频触发词的变体模型过了一轮又一轮能力并没有扩展。原因是没有多样性约束或者说聚类特征选得不好。如果聚类用的向量不是从当前模型里出的而是通用文本向量簇的划分可能跟任务语义不一致。解决方法是把多样性和不确定性组合起来用上一章给的 diversity_select 实现并确认聚类向量来自关系抽取模型的瓶颈输出而不是外部静态词向量。我自己的血泪经验是把聚类向量从 TF-IDF 换成 BERT [CLS] 向量后F1 才有明显的阶梯式上升。5.2 现象标回来的负例太多模型越训越保守关系抽取文本里实体对无关系的比例本来就很高。不确定性采样会偏向那些模型在多个类别间摇摆的样本而这些样本里相当一部分就是没有明确关系的“other”。标回来一大批负例后正例比例被稀释模型下一轮预测会变得更加倾向于 other进而采样器又继续挑出更多看似模糊的负例形成一个负循环。解决时要在采样前加一个过滤规则。比如模型预测“other”概率超过 0.7 的样本先不进采样池只对剩余样本计算熵。或者采用边际采样即取最大类概率和第二大概率之间的差值差值越小说明模型越纠结这类样本通常比纯熵更能抓到“两个关系分类之间摇摆”的样本。同时控制每轮标注中负例不超过 30%如果不够就在标注阶段优先让标注者挑出正例。5.3 现象加入新批次后测试 F1 不升反降模型大幅回退出现这个情况第一反应不是数据问题而是训练策略问题。主动学习每轮加入的新样本不是随机分布的它的分布与上一轮训练集有明显偏移。模型用了原来较大的学习率继续训练很容易在新样本上过拟合把旧样本的知识以很快速度冲掉。尤其在前几轮新样本占比大训练曲线会剧烈震荡。我现在的做法是“新批次先稳再训”拿到新标注后先用 1/10 的学习率训练一个 epoch把模型参数拉到一个新分布上稳定区域再恢复正常学习率继续训练。同时每一轮训练都用提前停止用固定验证集判断要不要继续而不是盲目训到固定轮数。这个改动让我后续轮次的 F1 基本都是单调上涨。5.4 现象测试集 F1 漂亮放到线上关系抽取却不稳定主动学习只能从你的未标注池里采样如果未标注池本身不代表性测试集再高也没有用。最常见的情况是未标注池只来自某一个单一来源比如某篇爬取列表而真实线上文本的句法结构、实体密度和触发词分布完全不同。主动学习虽然很智能但它的调度再聪明也受候选池分布限制。解决思路是构建未标注池时就做源多样化。我一般会把历史日志、公开文本、已有标注数据之外的随机文本都放进去并按来源统计样本数量比例。如果某个来源占比太高采样时要限制单来源样本量上限。主动学习真正的目标不是把一个池子榨干而是通过学习池子里多种分布让模型在真实场景里有更高的鲁棒性。5.5 现象模型置信度虚高不确定性采样失效预训练语言模型在分类任务上往往过度自信。一个模型即使预测错误softmax 概率也可能给出 0.9。这样用置信度或熵做不确定性采样时很多错误样本因为概率分布很尖熵很小根本不会被选中。你会发现自己采回来的样本都是模型本来就做得好的模型越来越强但只是在强项上更强。解决方法是先做模型校准。常见且简单的做法是温度缩放在验证集上拟合一个温度系数 T将 logits 除以 T 后再算 softmax然后再计算熵。T 大于 1 时概率分布会被拉平模型的不确定性更可信。或者用 MC Dropout在推理时打开 dropout 多次前向将多次预测结果的方差作为不确定性指标。虽然计算量大但它不需要额外训练也能对不确定性进行更稳定的估计。我在项目里先试温度缩放因为它不改变训练过程只影响采样分数。6. 把主动学习关系抽取用于真实任务验证技巧与我的习惯主动学习做到能跑通只是第一步真正值不值得用要看它能不能稳定地帮你省标注预算。这一章给三个验证与落地的技巧都是我自己的习惯。6.1 用学习曲线判断主动学习策略是否值得任何主动学习方案至少要对比三个基线随机采样、纯熵采样、熵加多样性。在相同初始种子、相同预算、相同测试集上跑画学习曲线。判断标准不是“最终谁最高”而是“在 20% 到 50% 预算阶段谁涨得更快”。主动学习如果只在最后阶段追平随机说明前面挑的样本并没什么信息量策略需要调整。6.2 把 NER 阶段也纳入主动学习联合采样关系抽取的错误很多是实体识别引入的。实体边界标错或类型预测错后面关系分类再准也没用。所以我后来会在采样时同时计算 NER 头部的不确定性对实体 span 的边界置信度和实体类型熵都比较高的样本优先采样。联合采样会让主动学习的收益更整体而不是只优化关系分类器。6.3 我的习惯先跑小闭环再上全量数据每次做新的主动学习任务我会先用 200 条数据、两个采样轮次跑通整个循环确认采样分数能排序、标注结果能写回、训练不报错然后再上全量。这个习惯救了我很多次。主动学习循环里每一步出错都会浪费标注预算而小闭环能让我在几分钟内发现流程问题。我印象最深的一次是在某跨平台系统里做关系抽取第一版纯不确定性采样用了 4000 条标注才到 75% 的 F1后来加上多样性约束和温度校准用 2300 条就到了同样效果。从那以后我接这类任务一定会先问清楚标注预算再决定主动学习用多深。这个教训也让我明白主动学习不是模型技巧而是数据工程策略。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑