如何将spaCy偏移格式转为GoldDoc以CLI训练带自定义LABEL的NER模型
如何将spaCy偏移训练格式转换为Gold格式以用于CLI训练
我完全懂你的需求——你已经把NER数据转成了spaCy的偏移格式,现在想切换到更灵活的CLI训练方式,但卡在了偏移格式转Gold格式这一步,而且不想依赖现成的nlp实例,毕竟要从零构建带自定义标签(PERSON、PHONE、ADDRESS)的模型对吧?下面给你两种可行的解决方案:
方案一:用空白nlp实例生成BILUO标签(推荐)
你提到的biluo_tags_from_offsets确实需要一个Doc对象,但咱们不需要用预训练的nlp模型,只需要初始化一个空白的nlp实例,并手动添加你的自定义标签就行,这样既不会有预训练模型的干扰,又能利用spaCy内置的工具函数完成转换。
具体步骤代码如下:
import spacy from spacy.training import biluo_tags_from_offsets # 1. 初始化空白的nlp实例(根据你的文本语言指定,比如法语fr,或者用xx表示多语言) nlp = spacy.blank("fr") # 2. 添加NER组件,并注册你的自定义标签 ner = nlp.add_pipe("ner") for label in ["PERSON", "PHONE", "ADDRESS"]: ner.add_label(label) # 3. 处理你的偏移格式数据 offset_data = [ [ "Bonjour\r\n\r\n\r\n\r\ncordialement, Thomas\r\n\r\n tel 0102030405", {"entities": [[70,79,"PHONE"],[56,61,"PERSON"]]} ] ] # 4. 转换为Gold格式(BILUO标签序列) gold_data = [] for text, annotations in offset_data: doc = nlp(text) # 提取实体偏移的三元组格式(start, end, label) offsets = [(start, end, label) for start, end, label in annotations["entities"]] biluo_tags = biluo_tags_from_offsets(doc, offsets) gold_data.append({"text": text, "tags": biluo_tags}) # 5. 保存为JSONL格式(spaCy CLI训练要求的输入格式) import json with open("train_gold.jsonl", "w", encoding="utf-8") as f: for item in gold_data: json.dump(item, f, ensure_ascii=False) f.write("\n")
方案二:手动实现偏移到BILUO标签的转换
如果不想依赖spaCy的nlp实例,也可以手动写逻辑生成BILUO标签。核心思路是:
- 先初始化一个全为
O的标签列表,长度和文本的token数一致 - 遍历每个实体偏移,找到对应的token位置,然后根据实体的token个数标记B(开头)、I(中间)、L(结尾)、U(单个token)标签
不过这种方法需要保证tokenization逻辑和spaCy的tokenizer完全一致,否则CLI训练时会出现标签对齐问题,所以不如方案一省心,这里给你一个简化的示例思路:
def offsets_to_biluo(text, entities, tokenizer): tokens = tokenizer(text) tags = ["O"] * len(tokens) # 记录每个token的起始和结束位置 token_start_end = [(token.idx, token.idx + len(token)) for token in tokens] for ent_start, ent_end, ent_label in entities: # 找到实体覆盖的所有token索引 token_indices = [] for i, (tok_start, tok_end) in enumerate(token_start_end): # 判断token和实体是否有重叠 if not (ent_end <= tok_start or ent_start >= tok_end): token_indices.append(i) if not token_indices: continue # 标记BILUO标签 if len(token_indices) == 1: tags[token_indices[0]] = f"U-{ent_label}" else: tags[token_indices[0]] = f"B-{ent_label}" for i in token_indices[1:-1]: tags[i] = f"I-{ent_label}" tags[token_indices[-1]] = f"L-{ent_label}" return tags # 使用空白nlp的tokenizer保证和CLI训练时的tokenization一致 nlp = spacy.blank("fr") tokenizer = nlp.tokenizer # 调用函数生成标签
CLI训练的额外注意事项
转换完Gold格式后,你需要在spaCy的训练配置文件(config.cfg)里指定你的自定义标签,比如在[components.ner]部分添加:
[components.ner] factory = "ner" labels = ["PERSON", "PHONE", "ADDRESS"]
这样CLI训练时就能正确识别你的自定义标签了。
内容的提问来源于stack exchange,提问作者Nicolas Roche
相关产品推荐
相关产品推荐

