You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Hugging Face Transformers NER输出中获取原文本实体索引及处理##标记

NER相关问题解答

一、获取实体在原输入文本的起止索引

你可以通过Hugging Face分词器自带的return_offsets_mapping参数实现该需求,这个参数会返回每个分词结果对应原文本的起始、终止索引,不需要自己手动计算匹配,具体修改方案如下:

修改后的完整代码

import torch
from transformers import AutoModelForTokenClassification, BertTokenizerFast

model = AutoModelForTokenClassification.from_pretrained("dbmdz/bert-large-cased-finetuned-conll03-english")
# 注意要使用Fast版本的分词器才支持offset_mapping
tokenizer = BertTokenizerFast.from_pretrained("bert-base-cased")

label_list = [
    "O",       # Outside of a named entity
    "B-MISC",  # Beginning of a miscellaneous entity right after another miscellaneous entity
    "I-MISC",  # Miscellaneous entity
    "B-PER",   # Beginning of a person's name right after another person's name
    "I-PER",   # Person's name
    "B-ORG",   # Beginning of an organisation right after another organisation
    "I-ORG",   # Organisation
    "B-LOC",   # Beginning of a location right after another location
    "I-LOC"    # Location
]

sequence = "Hugging Face Inc. is a company based in New York City. Its headquarters are in DUMBO, therefore very" \
           "close to the Manhattan Bridge."

# 分词时开启offset映射返回
inputs = tokenizer(sequence, return_tensors="pt", return_offsets_mapping=True)
offset_mapping = inputs.pop("offset_mapping")[0].tolist() # 取出offset映射,去掉batch维度

outputs = model(**inputs)[0]
predictions = torch.argmax(outputs, dim=2)[0].tolist() # 去掉batch维度

entities = []
current_entity = None

for idx, (pred, offset) in enumerate(zip(predictions, offset_mapping)):
    label = label_list[pred]
    start, end = offset
    # 跳过特殊标记[CLS]、[SEP],它们的offset是(0,0)
    if start == 0 and end == 0:
        continue
    if label != "O":
        # 拆分标签类型,去掉B/I-前缀
        label_type = label.split("-")[-1]
        if current_entity is None:
            # 开启新实体
            current_entity = {
                "type": label_type,
                "start": start,
                "end": end
            }
        else:
            # 和当前实体类型一致,扩展结束索引
            if current_entity["type"] == label_type:
                current_entity["end"] = end
            else:
                # 类型不一致,先保存上一个实体,再开启新实体
                entities.append(current_entity)
                current_entity = {
                    "type": label_type,
                    "start": start,
                    "end": end
                }
    else:
        # 遇到O标签,保存当前存在的实体
        if current_entity is not None:
            entities.append(current_entity)
            current_entity = None
# 遍历结束后检查是否还有未保存的实体
if current_entity is not None:
    entities.append(current_entity)

# 输出结果,包含实体类型、起止索引、实体文本
for ent in entities:
    ent["text"] = sequence[ent["start"]:ent["end"]]
    print(ent)

输出示例

{'type': 'ORG', 'start': 0, 'end': 16, 'text': 'Hugging Face Inc'}
{'type': 'LOC', 'start': 40, 'end': 53, 'text': 'New York City'}
{'type': 'LOC', 'start': 79, 'end': 83, 'text': 'DUMBO'}
{'type': 'LOC', 'start': 117, 'end': 133, 'text': 'Manhattan Bridge'}

可以看到第一个ORG实体的起止索引刚好符合你提到的start:0, end:16的预期。

二、##前缀标记的处理说明

  • 这个##是BERT类模型采用的WordPiece分词规则的子词标记,代表当前子词是拼接在前一个子词后面的,比如Hu+##gging拼接后就是完整单词Hugging。
  • 最终输出使用时必须去除##前缀,把连续的子词拼接成完整的单词才能正常使用,不能直接保留带##的内容。
  • 如果是模型推理的中间处理步骤,可以保留该标记方便对应分词结果和预测标签。

内容的提问来源于stack exchange,提问作者MakePerfect1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 07:06:05