共计 2501 个字符,预计需要花费 7 分钟才能阅读完成。
背景痛点:为什么 BART 标注特别难?
BART(Bidirectional and Auto-Regressive Transformers)作为同时支持文本生成和文本理解的混合模型,其数据标注需要兼顾两种任务特性:

- 双向上下文理解 :需标注实体 / 关系时(如 NER 任务),要考虑前后文影响
- 自回归生成需求 :对文本续写、摘要生成等任务,需标注连贯的上下文片段
新手常见翻车现场:
- 标注不一致 :同一实体在不同位置标注格式不同(如『北京』有时标为 LOC,有时标为 GPE)
- 任务混淆 :在文本生成任务中误标实体标签,或在理解任务中标注不完整的上下文
- 边界错误 :对长文本的截断标注破坏原始语义(特别在多轮对话场景)
工具选型:标注界的兵器谱
Prodigy
- 优势:
- 主动学习集成好(适合后期优化阶段)
- 支持自定义快捷键标注
- 短板:
- 商业软件($490/ 年起)
- 对中文符号兼容性一般
Label Studio
- 优势:
- 开源免费
- 内置 BART 预设模板
- 支持多人协作标注
- 注意点:
- 需要自行配置服务器
- 复杂任务需编写 XML 配置
选型建议 :
– 小型团队 / 个人项目 → Label Studio
– 企业级持续标注 → Prodigy
核心实现:从标注到校验
标准 JSON 格式示例
{
"text": "故宫位于北京中轴线中心",
"entities": [
{
"start": 3,
"end": 5,
"label": "LOC"
},
{
"start": 6,
"end": 8,
"label": "LOC"
}
],
"relations": [
{
"from": 0,
"to": 1,
"type": "located_in"
}
]
}
数据转换代码(含异常处理)
import json
from pathlib import Path
def convert_to_bart_format(raw_file, output_dir):
"""
将原始标注转为 BART 标准格式
:param raw_file: 原始标注文件路径
:param output_dir: 输出目录
:raises ValueError: 当实体边界超出文本长度时抛出
"""
try:
with open(raw_file, 'r', encoding='utf-8') as f:
raw_data = json.load(f)
bart_data = {"text": raw_data["text"],
"entities": [],
"relations": []}
# 实体边界校验
text_len = len(raw_data["text"])
for ent in raw_data.get("entities", []):
if ent["end"] > text_len:
raise ValueError(f"实体 {ent} 超出文本长度 {text_len}")
bart_data["entities"].append(ent)
# 保存转换结果
output_path = Path(output_dir) / f"{Path(raw_file).stem}_bart.json"
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(bart_data, f, ensure_ascii=False, indent=2)
except json.JSONDecodeError as e:
print(f"JSON 解析失败: {e}")
except KeyError as e:
print(f"缺少必要字段: {e}")
# 使用示例
convert_to_bart_format("raw_annotations.json", "converted_data")
质量校验代码
from transformers import BartTokenizer
def check_annotation_quality(annotation_file):
"""
检查标注质量
:param annotation_file: 标注文件路径
:return: 通过校验返回 True,否则返回 False
"""tokenizer = BartTokenizer.from_pretrained('facebook/bart-base')
with open(annotation_file, 'r') as f:
data = json.load(f)
# 检查实体是否被 tokenizer 切碎
for ent in data["entities"]:
entity_text = data["text"][ent["start"]:ent["end"]]
tokens = tokenizer.tokenize(entity_text)
if len(tokens) > 3: # 超过 3 个 token 可能影响模型理解
print(f"警告:实体'{entity_text}'被切分为多个 token: {tokens}")
return False
return True
避坑指南:血泪经验总结
陷阱 1:特殊符号破坏标注
- 现象 :文本中含 \n、\t 等符号导致标注偏移
- 解决 :预处理时统一替换为空格
text = text.replace('\n', '').replace('\t',' ')
陷阱 2:多轮对话上下文断裂
- 现象 :单独标注某轮对话导致语义缺失
- 正确做法 :
- 保持至少 3 轮对话上下文
- 给每轮对话打 speaker 标签
陷阱 3:生成任务标注过短
- 现象 :摘要任务只标关键词不标完整句子
- 改进 :
- 强制标注完整从句
- 最小长度≥15 字符
进阶技巧:像专家一样标注
主动学习工作流
- 初始标注 500 条数据
- 训练初始 BART 模型
- 用模型预测未标注数据
- 优先标注模型不确定的样本
标注效率提升技巧
- 设置文本片段快捷键(如 F1 标注 PER,F2 标注 LOC)
- 使用正则预标注(如自动标出所有日期格式)
动手实践
练习数据集 :
[
{
"text": "马云毕业于杭州师范大学",
"hint": "需要标注人名和学校名称"
},
{
"text": "特斯拉股价在 2023 年上涨了 120%",
"hint": "标注公司名和时间范围"
}
]
任务要求 :
1. 使用 Label Studio 创建 BART 标注项目
2. 标注实体和关系
3. 用提供的 Python 代码校验标注质量
通过这个完整流程,你标注的数据可以直接用于 BART 模型训练。记住:好的标注数据比模型结构更重要!
正文完
