在文本中标记出具有特定意义的片段——人名、地名、组织、时间、关系……是 NLP 项目中 NER、关系抽取、信息抽取等任务的基石。比图像标注更快但更需要语言专业能力。
对文本中的每个词/字标记一个标签——可以是实体类型、词性、语义角色,或实体间的关系
搜索引擎(关键词提取)、知识图谱(实体+关系)、客服机器人、法律医疗文档结构化等
★★★☆☆ 中等,需要语言专业能力,中文分词是额外门槛。LLM 预标注已大幅提效
在文本中找出具有特定意义的实体——人名、地名、组织名、时间、金额、产品名……是 NLP 中最基础也最常用的序列标注任务。
为文本中每个词标注词性——名词、动词、形容词、介词、代词……是句法分析、依存句法、机器翻译等下游任务的基础。
| 词 | 词性 | 词 | 词性 | 词 | 词性 |
|---|---|---|---|---|---|
| 华为 | n 名词 | 技术 | n 名词 | 有限公司 | n 名词 |
| 在 | p 介词 | 深圳 | n 名词 | 发布 | v 动词 |
| 了 | d 副词 | 新款 | a 形容词 | 手机 | n 名词 |
| , | wp 标点 | 它 | r 代词 | 很 | d 副词 |
| 受欢迎 | a 形容词 | 。 | wp 标点 |
从文本中找出实体对及其之间的语义关系——A 与 B 是什么关系?是知识图谱的核心构建单元。比 NER 更复杂,需要同时标注两个实体 + 它们之间的关系类型。
确定要标注哪些实体类型/词性/关系,每个标签的精确定义,产出 ner_guide.md
文本标注对工具要求比图像低——纯文本即可,但 NLP 专用工具有分词辅助和标签快捷键
LLM(GPT/LLaMA)做 NER 预标注是文本标注的革命性提效——直接让大模型先跑一遍,人工只修正
请对以下文本进行 NER 标注,标签为 [PER, ORG, LOC, DATE],输出 JSON 格式:
{"text": "2024年1月华为在深圳举办发布会", "entities": [{"text": "华为", "label": "ORG"}, ...]}
文本标注的数据量远小于图像——一段文本就是一行 BIO 标签,导出格式选择灵活
| 工具 | 类型 | 费用 | NER/POS | 亮点 |
|---|---|---|---|---|
| brat ▼ | Web 本地 | 免费 | ✅ 强 | 学术经典,快捷键标注极快 |
| Doccano ▼ | Web 服务 | 免费 | ✅ 强 | 现代化 UI,项目管理完善 |
| Prodigy ▼ | 命令行+Web | 免费+付费 | ✅ 极强 | 主动学习,标注效率最高 |
| Label Studio ▼ | Web 服务 | 免费 | ✅ 强 | 多模态,Python SDK 强 |
# === 1. JSONL → BIO 转换 === import json def jsonl_to_bio(jsonl_path, bio_path): with open(jsonl_path) as fin, open(bio_path, 'w') as fout: for line in fin: item = json.loads(line) text = item['text'] entities = item.get('entities', []) # 给每个字符预设 O labels = ['O'] * len(text) for ent in entities: start, end, label = ent['start'], ent['end'], ent['label'] labels[start] = f'B-{label}' for i in range(start+1, end): labels[i] = f'I-{label}' # 逐字输出 for char, label in zip(text, labels): if char != '\n': fout.write(f'{char}\t{label}\n') fout.write('\n') # 句间空行 jsonl_to_bio('train.jsonl', 'train.bio') # === 2. 检查 BIO 格式 === def check_bio_format(bio_path): errors = [] prev_tag = 'O' for line in open(bio_path): line = line.strip() if not line: prev_tag = 'O'; continue char, tag = line.split('\t') if tag.startswith('I-') and prev_tag == 'O': errors.append(f'❌ I-{tag[2:]} 前是 O') prev_tag = tag return errors # === 3. 训练 BERT-NER(HuggingFace) === from transformers import AutoTokenizer, AutoModelForTokenClassification from transformers import Trainer, TrainingArguments model_name = 'bert-base-chinese' tokenizer = AutoTokenizer.from_pretrained(model_name) # 标签映射 label_list = ['O', 'B-PER', 'I-PER', 'B-ORG', 'I-ORG', 'B-LOC', 'I-LOC'] id2label = {i: l for i, l in enumerate(label_list)} label2id = {l: i for i, l in id2label.items()} model = AutoModelForTokenClassification.from_pretrained( model_name, num_labels=len(label_list), id2label=id2label, label2id=label2id ) # 训练... training_args = TrainingArguments( output_dir='./ner_model', num_train_epochs=10, per_device_train_batch_size=16 ) trainer = Trainer(model=model, args=training_args, train_dataset=train_dataset) trainer.train()