spaCy 训练数据转换实战:用 spacy convert 将 NER/IOB 与旧版 JSON 转为 DocBin 格式 spaCy 训练数据转换实战用 spacy convert 将 NER/IOB 与旧版 JSON 转为 DocBin 格式【免费下载链接】spaCy Industrial-strength Natural Language Processing (NLP) in Python项目地址: https://gitcode.com/GitHub_Trending/sp/spaCy在 spaCy 中训练命名实体识别NER模型前把标注数据统一成.spacyDocBin 序列化格式是标准的第一步。仓库 extra/example_data/ner_example_data/ 目录提供了四组可直接用于练习的 NER/IOB 标注样例以及配套说明文档 README.md。本文以这份说明文档为主线结合 convert 命令实现 与各转换器源码完整讲解四种 IOB/NER 输入格式长什么样、spacy convert每个参数的真实含义、IOB→BILUO→实体标注的底层转换链路以及如何把 spaCy v2 时代的 JSON 训练文件平滑迁移到 v3。读完你就能手把手把自己手上的 IOB/JSON 标注数据转成可直接用于spacy train的.spacy文件。目录里有什么四组 NER 样例数据一览extra/example_data/ner_example_data/ 共包含 1 份 README 和 8 个数据文件内容全部来自同一段关于自动驾驶先驱 Sebastian Thrun 的英文访谈文本标注了PERSON人名、ORG机构、NORP民族/政治团体、DATE日期四类实体文件格式列结构ner-sent-per-line.iob每行一个句子词形\|词性\|IOB标签词条间以空格分隔ner-token-per-line.iob每行一个词两列制表符分隔词形 NER标签ner-token-per-line-with-pos.iob每行一个词三列词形 词性 NER标签ner-token-per-line-conll2003.iobCoNLL-2003 风格四列词形 词性 _ NER标签含-DOCSTART-文档分隔符对应同名 4 个.json文件spaCy v2 旧版 JSON 训练格式id / paragraphs / sentences / tokens(orth, tag, ner)其中 4 个.json文件并非手写而是 README 明确说明的这些 spaCy v2 JSON 训练文件是用 spaCy v2 的spacy convert从上述 IOB 文件自动生成的生成命令见后文“复现 v2 时代”一节。因此这 8 个文件构成了一条完整的格式演进链路手工 IOB 标注 → v2 JSON → v3.spacy。四种 IOB/NER 输入格式详解1. 每行一句词条以|分隔ner-sent-per-line.iobner-sent-per-line.iob 的每一行是一个完整的句子句中每个词条写作词形|词性|IOB标签词条之间用空格分隔When|WRB|O Sebastian|NNP|B-PERSON Thrun|NNP|I-PERSON started|VBD|O working|VBG|O ... Google|NNP|B-ORG in|IN|O 2007|CD|B-DATE ,|,|O ...这种格式正是 IOB 转换器 iob_to_docs.py 的直接输入。源码 docstring 给出了完全一致的样例语法并声明“IOB and IOB2 are accepted”同时接受 IOB/IOB2 两种变体且每个词条支持两种字段数量三字段词形|词性|IOB如London|NNP|I-GPE词性会被写入 Token 的tag_两字段词形|IOB如London|I-GPE此时词性统一置为-占位。解析时按空格line.split()切出词条、再按|切出字段字段数不是 2 或 3 会抛出Errors.E902。每个非空行都会被标记为一个句子起点is_sent_start。2. 每词一行、无词性ner-token-per-line.iobner-token-per-line.iob 改为每行一个词、两列词形与 NER 标签词与标签之间使用制表符空行作为句子分隔When O Sebastian B-PERSON Thrun I-PERSON ... Google B-ORG in O 2007 B-DATE注意它没有 POS 词性列。这类“首列为词、末列为 NER 标签”的空白分隔列式格式对应的是CoNLL NER 转换器conll_ner_to_docs.py其 docstring 写明“第一列是 token最后一列是 IOB 标签若存在第二列则第二列是词性标签”。因此它并不适合-c iobIOB 转换器要求|分隔应使用-c ner或-c conll。3. 每词一行、带词性ner-token-per-line-with-pos.iobner-token-per-line-with-pos.iob 在上一格式基础上增加了第二列词性标签When WRB O Sebastian NNP B-PERSON Thrun NNP I-PERSON三列对应关系为词形 | 词性(POS) | NER标签。转换时词性会保留为tag_可用于后续训练 tagger 与 NER 联合模型。4. CoNLL-2003 风格ner-token-per-line-conll2003.iobner-token-per-line-conll2003.iob 完全复刻 CoNLL-2003 共享任务的文件约定四列分别是词形 词性 句法占位(_) NER标签并用-DOCSTART- -X- O O行分隔文档、空行分隔句子-DOCSTART- -X- O O When WRB _ O Sebastian NNP _ B-PERSON Thrun NNP _ I-PERSON started VBD _ O ... Google NNP _ B-ORG ...conll_ner_to_docs.py 的源码专门处理了这种格式以-DOCSTART- -X- O O作为文档定界符空白行作为句子边界。源码还包含两条智能兼容逻辑若数据中已有\n\n句子边界且指定了-s会警告“发现句子边界自动断句已禁用”并把seg_sents置为False若数据中已含-DOCSTART-文档定界符且指定了-n会警告“发现文档定界符自动文档切分已禁用”并把n_sents置为0。也就是说对于本目录这种已经带完整边界标记的文件-s/-n参数会被自动安全地忽略不会破坏原有结构。spacy convert 命令全解从 CLI 定义到转换器注册表spacy convert的入口定义在 spacy/cli/convert.py其职责在源码 docstring 中写得很清楚“把文件转换为用于训练的 json 或 DocBin 格式产出的.spacy文件可被train命令及其他实验管理功能使用”。全部参数如下参数名与默认值均取自源码参数简写默认值含义--file-type-tspacy输出类型json或spacy--n-sents-n1每个 Doc 包含的句子数0表示禁用自动切分--seg-sents-sFalse对-c ner启用句子切分--model/--base-bNone用于句子切分的基础已训练 pipeline--morphology-mFalse是否把形态特征追加到词性标签后--merge-subtokens-TFalse合并 CoNLL-U 的子 token--converter-cAUTO指定转换器conllubio / conllu / conll / ner / iob / json--ner-map-nmNoneNER 标签映射JSON 编码的实体类型字典--lang-lNone需要 tokenizer 时指定的语言--concatenate-CNone把所有输出合并到单个文件转换器通过 CONVERTERS 注册表 分发conllubio/conllu走 CoNLL-U 转换器conll/ner走 CoNLL NER 转换器iob走 IOB 转换器json走 JSON 转换器。源码注释还说明了一个自动检测细节“转换器按文件扩展名匹配ner/iob除外它们是按扩展名和内容共同匹配的”——即AUTO模式下.iob这类文件会根据实际内容嗅探格式。另外当输出目录缺省为-stdout且输出格式为 JSON 时数据直接写到标准输出可配合重定向生成文件例如源码 docstring 中的spacy convert some_file.conllu --file-type json some_file.json。实战一把 IOB 文件转为 v3 .spacyDocBinREADME 给出的 spaCy v3 转换命令为python -m spacy convert -c iob -s -n 10 -b en_core_web_sm file.iob .逐项拆解这条命令-c iob强制指定 IOB 转换器。对 ner-sent-per-line.iob 这类词形|词性|IOB的|分隔格式是必需的-s启用句子切分-b en_core_web_sm指定作为切分基础的已训练英文 pipeline。需要说明的是从 iob_to_docs.py 的函数签名iob_to_docs(input_data, n_sents10, no_printFalse, *args, **kwargs)可以看到seg_sents与model对 IOB 转换器会落入**kwargs被忽略——IOB 格式的句子边界本来就来自行结构-s/-b真正发挥作用是在-c ner场景-n 10每 10 个句子组成一个 Doc。对应read_iob中按n_sents大小对行做minibatch分组的逻辑——组内所有词拼成一个 Doc首行标记为句子起点其余为后续句子.输出目录为当前目录默认-t spacy产出.spacy文件。对于目录中另外三个**列式制表符/空白分隔**的 IOB 文件则应改用 CoNLL NER 转换器python -m spacy convert -c ner -b en_core_web_sm ner-token-per-line.iob . python -m spacy convert -c ner -b en_core_web_sm ner-token-per-line-with-pos.iob . python -m spacy convert -c ner -b en_core_web_sm ner-token-per-line-conll2003.iob .转换过程在底层做了什么以iob_to_docs为例核心链路是 iob_to_docs.py 中的read_iob逐行解析出词表、词性表、IOB 标签表与句子起点标记用Doc(vocab, wordswords)构造最小 Doc把词性写入doc[i].tag_把 IOB 标签经 iob_to_biluo 转成 spaCy 内部使用的BILUO 方案B-开始、I-中间、L-结尾、U-单实体、O外部再经 tags_to_entities 合并为(label, start, end)跨度最后doc.ents [Span(doc, starts, ende1, labelL) ...]写入实体。最终 Doc 携带了词形、词性、句子边界与实体标注四类信息由DocBin定义于 spacy/tokens/_serialize.py通过to_disk落盘序列化为.spacy文件供 spacy/cli/train.py 等下游命令消费。实战二把 spaCy v2 JSON 训练文件转为 v3 .spacy如果你手头还留着 v2 时代的 JSON 训练数据本目录这 4 个.json就是典型样本README 给出的迁移命令非常简洁——直接用v3的 convert 即可python -m spacy convert file.json .v3 的 JSON 转换器 json_to_docs.py 内部通过json_iterate/json_to_annotations见 spacy/training/gold_io.py解析旧式 JSON再用_fix_legacy_dict_data兼容历史数据形态最终用annotations_to_doc还原成 Doc。从源码看当-b未指定时默认使用MultiLanguage()作为语言兜底spacy/lang/xx/init.py即纯规则 tokenizer 环境。以 ner-sent-per-line.json 为例v2 JSON 的结构是[ { id: 0, paragraphs: [ { sentences: [ { tokens: [ {orth: When, tag: WRB, ner: O}, {orth: Sebastian, tag: NNP, ner: B-PERSON}, {orth: Thrun, tag: NNP, ner: L-PERSON}, ... {orth: Google, tag: NNP, ner: U-ORG}, {orth: 2007, tag: CD, ner: U-DATE}, ... {orth: earlier, tag: RBR, ner: B-DATE}, {orth: this, tag: DT, ner: I-DATE}, {orth: week, tag: NN, ner: L-DATE} ] } ] } ] } ]注意一个印证底层原理的细节JSON 中ner字段已经是B-/I-/L-/U-组成的BILUO 标签如L-PERSON、U-ORG、U-DATE、L-DATE而对应的 IOB 源文件里是B-PERSON I-PERSON、B-ORG、B-DATE的 IOB 写法——这正是 v2 时代执行 convert 时iob_to_biluo转换留下的痕迹也解释了为什么 JSON 里单 token 实体写作U-、多 token 实体的最后一个 token 写作L-。四个 JSON 文件中ner-token-per-line.json 的词性统一为-源文件无词性列其余三个则保留真实 POS 标签。实战三复现 v2 JSON 的生成过程README 明确记录了这些 JSON 文件的出处——使用spaCy v2生成python -m spacy convert -c iob -s -n 10 -b en file.iob这条 v2 命令与 v3 版本的差异仅在基础模型参数v2 时代使用短名-b en对应当时的英语模型v3 则要求完整模型名如en_core_web_sm。如果你需要把旧 IOB 数据批量“复刻”出 v2 JSON 再做迁移可以先在 v2 环境跑上面的命令得到 JSON再到 v3 环境执行实战二中的命令。这也解释了本目录“IOB 源文件 JSON 中间产物”成对存放的用意——它们是同一份标注数据在不同格式时代的存档。转换结果如何衔接训练完成转换后产出物是与输入同名的.spacy文件如ner-sent-per-line.spacy内部是一个 DocBin 容器其中每个 Doc 已具备训练 NER 所需的全部标注token 文本doc[i].text词性标签doc[i].tag_来自 IOB 的第二字段或 JSON 的tag字段句子边界doc[i].is_sent_start来自 IOB 行结构或 JSON 的sentences分组实体标注doc.ents由 IOB/BILUO 标签经tags_to_entities换算出的 Span 集合。在 spacy/cli/train.py 对应的训练配置中将train.corpus的path指向该.spacy文件即可开始训练旧版 JSON 则建议先统一转成.spacy这也是 v3 官方推荐的数据流程。需要小样本验证时-n 10这类分组参数可让你把整份数据切成多个 Doc 以控制 batch 粒度。使用注意事项转换器与格式必须匹配|分隔的每行一句 IOB 用-c iob空白/Tab 分隔的列式含 CoNLL-2003用-c ner或-c conll。二者混用会导致解析失败或标签错位。-s/-b的作用范围句子切分参数只在-c ner链路生效-c iob时句子边界来自行结构-b指定的模型不会参与源码层面落入**kwargs被忽略。-n 0禁用自动切分若数据已自带文档边界如-DOCSTART-转换器会自动禁用-n/-s无需手动处理。标签体系输入支持 IOB/IOB2内部统一转为 BILUO 存储无需手工预转换。v2 与 v3 命令差异v3 中-b需使用完整的已训练 pipeline 名如en_core_web_smv2 用短名en若需 tokenizer 参与解析而模型不可用可用-l指定语言如-l en。仓库中的 ner_example_data 目录 是一份可直接复现、零成本的上手数据集无论你想验证 IOB 转换、练习 v2 JSON 迁移还是为 NER 训练准备.spacy语料都可以从本文的几条命令出发对照源码逐层理解 spaCy 数据管线的工作方式。【免费下载链接】spaCy Industrial-strength Natural Language Processing (NLP) in Python项目地址: https://gitcode.com/GitHub_Trending/sp/spaCy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考