如何获取spaCy NER模型各输出类别的softmax预测值
获取spaCy NER模型Softmax预测值与标签映射的方法
你之前的实现存在两个核心误区:
- 全局修改thinc的
Model.predict拿到的ParserStepModel是NER转移解码器的中间状态对象,vec2scores输出的是逐token未加转移约束的原始分类分数,不是经过解码对齐的最终实体预测结果 - 模型加载后默认处于推理模式,
is_train参数不会触发dropout等训练专属逻辑,因此传True/False输出无变化是正常现象,且vec2scores返回的是未归一化的分数,不是softmax结果。
正确获取Softmax预测值的实现
直接通过NER组件的内置接口获取模型原始输出,手动计算softmax即可,不需要修改thinc底层方法:
import spacy import numpy as np def softmax(x, axis=-1): # 数值稳定版softmax实现 e_x = np.exp(x - np.max(x, axis=axis, keepdims=True)) return e_x / e_x.sum(axis=axis, keepdims=True) # 加载模型与文本 nlp = spacy.load("en_core_web_sm") ner_component = nlp.get_pipe("ner") doc = nlp.make_doc("Apple is looking at buying U.K. startup for $1 billion") # 拿到NER模型原始输出,形状为(批大小, 序列长度, 标签总数) raw_scores, _ = ner_component.model.predict([doc]) # 单样本取第一个维度,计算逐token的softmax概率 token_softmax = softmax(raw_scores[0])
注意:这里拿到的token_softmax是逐token的BIO标签概率,还没有经过转移解码器的合法性约束,最终doc.ents里的实体是解码器基于转移规则筛选后的合法结果。如果需要实体级别的置信度,可以将识别出的实体覆盖范围内对应token的标签概率做聚合(取平均/最小值均可)。
预测值对应的类别映射关系
模型输出最后一维的索引和BIO格式标签的映射,存在NER组件的转移规则配置中,和模型训练时的标签顺序完全一致:
- 基础实体类型可以通过
ner_component.labels获取,比如ORG、GPE、MONEY等 - 逐token概率对应的完整BIO标签列表可以通过
ner_component.move_recipe.labels获取,列表下标对应softmax数组最后一维的索引,标签格式为B-实体类型(实体起始token)、I-实体类型(实体内部token)、O(非实体)
可以通过以下代码打印映射关系,对齐预测结果:
# 加载索引到标签的映射 id2label = ner_component.move_recipe.labels # 打印标签映射 print("索引-BIO标签对应关系:") for idx, label in enumerate(id2label): print(f"{idx}: {label}") # 逐token打印最高概率的预测结果 print("\n逐token预测结果:") for token, prob_list in zip(doc, token_softmax): max_idx = np.argmax(prob_list) print(f"文本:{token.text:10} 预测标签:{id2label[max_idx]:8} 概率:{prob_list[max_idx]:.4f}")
运行后可以直接看到每个token对应所有BIO标签的softmax概率,和最终解码出的实体标签做对齐即可。
内容的提问来源于stack exchange,提问作者wind_junkie
相关产品推荐
相关产品推荐

