使用自定义suggester时SpanCategorizer训练数据格式及零损失问题
spaCy自定义主张抽取Pipeline问题解答
问题1:SpanCategorizer训练数据的span起止用字符偏移还是token索引?
必须使用token索引。
spaCy的Span对象基于文档的token序列创建,Span(doc, start, end, label)中的start和end是token的索引(左闭右开区间,比如(1,2)对应文档第2个token,索引从0开始)。字符偏移仅用于doc.char_span(start_char, end_char)方法生成Span,但SpanCategorizer训练时,标注数据的span必须以token索引形式提供,因为模型内部基于token级特征学习。
你的训练数据示例中使用(1, 2, "SOURCE")的token索引格式是正确的。
问题2:训练循环返回0损失的原因及修复
训练损失为0的核心问题是训练数据未正确传递给模型的gold标注,同时存在其他配置疏漏,具体修复如下:
1. 修复Example构建逻辑
你的示例构建代码中,Example.from_dict(doc, {})传入空字典作为gold数据,导致模型没有标注可学习,损失始终为0。
修正代码:
examples = [] for text, annots in training_data: doc = nlp.make_doc(text) # 直接将标注数据传入Example作为gold标准 example = Example.from_dict(doc, annots) examples.append(example)
若需手动构建Span后生成Example,也要确保gold标注正确传入:
examples = [] for text, annots in training_data: doc = nlp.make_doc(text) spans_to_add = [] for span in annots["spans"]["sc"]: start, end, label = span new_span = Span(doc, start, end, label) spans_to_add.append(new_span) doc.spans["sc"] = spans_to_add # 传入完整标注数据而非空字典 examples.append(Example.from_dict(doc, annots))
2. 修正训练数据格式
你的training_data存在语法错误,正确格式应为包含(text, annots)元组的列表:
training_data = [ ( "The report states that AI risks are increasing significantly.", { "spans": { "sc": [ (1, 2, "SOURCE"), (2, 3, "CLAIM_VERB"), (4, 8, "CLAIM_CONTENTS"), (8, 9, "CLAIM_MOD"), ] } } ) ]
3. 确保Suggester生成候选包含gold span
SpanCategorizer仅对suggester返回的候选span分类,若gold span不在候选列表中,模型无法学习对应标签,也会导致损失异常。需检查自定义suggester逻辑:
- 确保训练数据中的每个gold span,都能通过依存解析逻辑生成对应的
(start, end)候选区间 - 比如验证gold span
(4,8,"CLAIM_CONTENTS")是否能被suggester正确识别并加入候选
4. 规范训练循环写法
确保已正确获取spancat组件并完成配置:
# 加载预训练模型并添加spancat组件 nlp = spacy.load("en_core_web_sm") config = { "threshold": 0.5, "spans_key": "sc", # 与训练数据中的spans键对应 "suggester": {"@misc": "claim_suggester.v1"}, "labels": ["SOURCE", "CLAIM_VERB", "CLAIM_CONTENTS", "CLAIM_MOD"] } nlp.add_pipe("spancat", config=config) # 训练循环 spancat = nlp.get_pipe("spancat") optimizer = nlp.initialize() epochs = 30 for itn in range(epochs): random.shuffle(examples) losses = {} batches = spacy.util.minibatch(examples, size=4) for batch in batches: spancat.update(batch, drop=0.2, losses=losses, sgd=optimizer) print(f"Iteration: {itn + 1}, Losses: {losses}") print(f"Number of examples processed: {len(training_data)}")
内容的提问来源于stack exchange,提问作者muelikath_8
相关产品推荐
相关产品推荐

