spaCy 如何用 spancat 组件构建 Span 级文本分类流水线?

发布时间:2026/9/12 6:58:44
spaCy 如何用 spancat 组件构建 Span 级文本分类流水线? spaCy 如何用 spancat 组件构建 Span 级文本分类流水线【免费下载链接】spaCy Industrial-strength Natural Language Processing (NLP) in Python项目地址: https://gitcode.com/GitHub_Trending/sp/spaCy如果你需要的不是整句分一个类而是文本中任意位置的若干 Span 各打一个标签——比如一句话里同时标出人名和机构名或者给文档里出现的每个条款片段打上状态标签——spaCy 提供的spancat组件就是为这种 Span 级多标签分类设计的。它由两部分组成一个 suggester 函数负责提出候选 Span可以重叠一个 labeler 模型负责给每个候选预测零个或多个标签。预测结果保存在doc.spans[spans_key]这个SpanGroup中各 Span 的分数存放在doc.spans[spans_key].attrs[scores]。需要注意spancat目前被文档标注为实验性experimental组件。spancat与spancat_singlelabelv3.5.1 新增是两种形态一个 Span 可能同时命中多个类别时用spancat内部用Logistic层各类别概率独立一个 Span 至多属于一个类别时用spancat_singlelabel内部用Softmax层按多分类问题处理。本文按spancat多标签场景组织单标签分支在结尾给出。第一步用 init config 生成带 spancat 的配置文件spaCy 推荐的训练入口是命令行spacy train它只依赖一个config.cfg配置文件包含全部设置与超参数。配置文件由 quickstart 模板生成模板中已经内置了spancat的组件块所以可以直接通过--pipeline参数把它包含进来$ python -m spacy init config base_config.cfg --lang en --pipeline spancat--pipeline是逗号分隔的可训练组件列表--lang指定语言。生成的是基础配置还要用init fill-config填充其余默认值——spaCy 要求训练配置完整、没有隐藏默认值实验才可复现$ python -m spacy init fill-config base_config.cfg config.cfg生成的config.cfg中[components.spancat]块对应文档给出的默认配置factory spancat、spans_key sc、threshold 0.5、max_positive null不限制每个 Span 的正类数量模型为spacy.SpanCategorizer.v1suggester 为spacy.ngram_suggester.v1且sizes [1, 2, 3]即候选 Span 长度为 1 到 3 个 token。调整候选 Span 的范围更换 suggester默认ngram_suggester会提出所有指定长度的 Span文档提供了三种注册 suggester按需替换[components.spancat.suggester]块# 指定长度集合提出 1 或 2 个 token 组成的 Span [components.spancat.suggester] misc spacy.ngram_suggester.v1 sizes [1, 2] # 长度区间提出 min_size 到 max_size含两端之间的所有长度 [components.spancat.suggester] misc spacy.ngram_range_suggester.v1 min_size 2 max_size 4 # 只评估上游组件已经写入 doc.spans 的 Span [components.spancat.suggester] misc spacy.preset_spans_suggester.v1 spans_key my_spanspreset_spans_suggester适用于前一个组件如SpanRuler或SpanFinder已经在doc.spans[spans_key]里写好了 Span 的情况spancat 只对这些既有 Span 打分。第二步准备带 spans 标注的训练数据spaCy 的训练数据是二进制的.spacy文件序列化的DocBin。对 spancat 来说关键是在Doc上把标注写到与spans_key相同的 key 下——初始化和训练时组件会在参考文档的同一个 key 下查找 Span。用 Python 构造数据的做法对每段文本先用nlp(text)得到Doc再用字符偏移char_span创建Span写进doc.spans[spans_key]然后加入DocBin并落盘import spacy from spacy.tokens import DocBin nlp spacy.blank(en) # (文本, [(start_char, end_char, 标签), ...]) training_data [ (Apple is looking at buying U.K. startup, [(0, 5, ORG), (34, 41, GPE)]), ] db DocBin() for text, spans in training_data: doc nlp(text) doc.spans[sc] [ doc.char_span(start, end, labellabel) for start, end, label in spans ] db.add(doc) db.to_disk(./train.spacy)这里spans_key使用默认值sc与你训练用的 key 保持一致。开发集dev.spacy用同样方法生成spacy train会用它在每个 epoch 结束后评估。数据格式的文档定义也印证了这个结构spans字段是spans_key - List[Tuple]的字典每个 tuple 为(start_char, end_char, label, kb_id)数据格式说明。数据就绪后可以用debug data命令分析训练与开发数据、统计标签分布、发现无效标注等问题$ python -m spacy debug data config.cfg第三步确认 score_weights 与 spans_key 一致spancat 文档给出一个必须注意的坑如果你把spans_key改成非默认值必须同步更新[training.score_weights]否则指标权重无法正确计算。例如spans_key myspankey时配置里要写成[training.score_weights] spans_myspankey_f 1.0 spans_myspankey_p 0.0 spans_myspankey_r 0.0score_weights决定训练日志中显示哪些指标、以及它们如何加权进决定最佳模型的最终得分设为null的权重会排除在日志和加权之外。保持默认spans_key sc则无需改动由init config生成的权重直接可用。第四步运行训练训练命令只需传入 config 和输出目录数据路径写在[paths]段或直接在命令行传入$ python -m spacy train config.cfg --output ./output --paths.train ./train.spacy --paths.dev ./dev.spacy训练过程中每个 pass 结束会打印指标表。与 spancat 相关的指标包括 Loss训练损失代表优化器剩余的工作量应下降但通常不会到 0、Precision预测标注中正确的比例、Recall参考标注被召回的比例、F-Score两者的调和平均与 Speedwords per second应保持平稳。spacy train结束时会把最终填充完成的config.cfg与管道一起导出所以你始终留有一份实际使用的设置记录。可选如果训练使用 GPU加--gpu-id$ python -m spacy train config.cfg --gpu-id 0标签初始化方面组件可以通过get_examples回调自动从训练数据中读取标签为了加速也可以先用init labels生成标签 JSON再在[initialize.components.spancat.labels]中通过readers spacy.read_labels.v1与path指过去参考 SpanCategorizer.initialize 的示例。文档强调标签 JSON 的格式因组件而异应始终让init labels自动生成不要手写。第五步加载模型并验证预测训练产出是./output下的一个模型目录未打包的数据目录。加载后对文本做预测结果落在doc.spans下你配置的 key 中import spacy nlp spacy.load(./output) doc nlp(Apple is looking at buying U.K. startup) for span in doc.spans[sc]: score doc.spans[sc].attrs[scores] print(span.text, span.label_, span.start_char, span.end_char)判断方式很直接doc.spans[sc]中出现的每个Span都是一个正预测span.label_是命中的类别span.start_char/span.end_char是字符偏移attrs[scores]里保存的是各 Span 的分数threshold默认 0.5低于该值的预测不会被写入 Doc。如果doc.spans[sc]为空说明模型在当前threshold下没有产生正预测——此时先确认训练数据里 Span 标注确实写在同一个 key 下再考虑训练轮数或候选范围是否覆盖了目标 Span 长度。另外两个文档给出的验证/调试手段spancat.set_candidates(docs, candidates)用 suggester 把候选 Span 写入指定 key文档明确说明该方法是调试用途——用它检查模型实际在评估哪些候选 Span单标签的spancat_singlelabel默认add_negative_label True未标注 Span 会被学成特殊负标签这些负标签 Span 不会作为标注存储。单标签场景spancat_singlelabelv3.5.1若一个 Span 至多属于一个类别把管道中的组件换成spancat_singlelabel即可配置与 spancat 类似但多了几个参数见 SpanCategorizer 文档的示例from spacy.pipeline.spancat import DEFAULT_SPANCAT_SINGLELABEL_MODEL config { spans_key: labeled_spans, model: DEFAULT_SPANCAT_SINGLELABEL_MODEL, suggester: {misc: spacy.ngram_suggester.v1, sizes: [1, 2, 3]}, negative_weight: 0.8, allow_overlap: True, } nlp.add_pipe(spancat_singlelabel, configconfig)相关设置的含义以文档为准negative_weight是损失项乘子负样本过多时可用它降权allow_overlap表示数据中允许重叠 Span仅当max_positive恰好为 1 时可用add_negative_label在使用Softmax层时应当为True这也是spancat_singlelabel的默认值。训练路径不变init config --pipeline spancat_singlelabel→init fill-config→train。限制与边界spancat组件带 experimental 标记API 可能随版本调整。spancat组件会覆盖doc.spans[spans_key]下已有的内容如果你的上游组件如SpanRuler、SpanFinder也写doc.spans请让它们用不同的 key再用preset_spans_suggester读取上游 key避免互相覆盖。候选范围完全由 suggester 决定目标 Span 如果超出sizes或min_size/max_size范围模型根本没有机会为它打分预测为空不是模型没学会而是候选不存在。改了spans_key却没同步[training.score_weights]指标计算会不对——这是 spancat 文档单独用警告框提示的点。更多组件方法predict、set_annotations、update、序列化字段等见 SpanCategorizer API 文档训练配置系统变量插值、CLI 覆盖、自定义函数见 Training Pipelines Models。【免费下载链接】spaCy Industrial-strength Natural Language Processing (NLP) in Python项目地址: https://gitcode.com/GitHub_Trending/sp/spaCy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考