【问题标题】:Transformers get named entity prediction for words instead of tokensTransformers 获得单词而不是标记的命名实体预测
【发布时间】:2020-11-04 17:01:51
【问题描述】:

这是一个非常基本的问题,但我花了几个小时努力寻找答案。我使用 Hugginface 转换器构建了 NER。

说我有输入句子

input = "Damien Hirst oil in canvas"

我将其标记化以获取

tokenizer = transformers.BertTokenizer.from_pretrained('bert-base-uncased')
tokenized = tokenizer.encode(input) #[101, 12587, 7632, 12096, 3514, 1999, 10683, 102]

将标记化的句子输入模型以获取标记的预测标签

['B-ARTIST' 'B-ARTIST' 'I-ARTIST' 'I-ARTIST' 'B-MEDIUM' 'I-MEDIUM'
 'I-MEDIUM' 'B-ARTIST']

prediction 作为模型的输出。它将标签分配给不同的令牌。

如何重新组合这些数据来获取单词标签而不是标记?所以我会知道的

"Damien Hirst" = ARTIST
"Oil in canvas" = MEDIUM

【问题讨论】:

    标签: nlp pytorch huggingface-transformers


    【解决方案1】:

    这里有两个问题。

    注释标记分类

    一种常见的顺序标记,尤其是在命名实体识别中,遵循这样的方案:开头带有标记X 的标记序列得到B-X,并且在重置标签时得到I-X。 问题是大多数带注释的数据集都是用空间标记的!例如:

    [CSL]  O
    Damien  B-ARTIST
    Hirst  I-ARTIST
    oil  B-MEDIUM
    in  I-MEDIUM
    canvas  I-MEDIUM
    [SEP]  O
    

    其中O 表示它不是一个命名实体,B-ARTIST 是标记为ARTIST 的标记序列的开始,I-ARTIST 在序列内部——MEDIUM 的模式类似。

    在我发布这个答案的那一刻,这里的拥抱脸文档中有一个 NER 的例子: https://huggingface.co/transformers/usage.html#named-entity-recognition

    该示例并未完全回答此处的问题,但可以添加一些说明。该示例中命名实体标签的类似样式如下:

    label_list = [
        "O", # not a named entity
        "B-ARTIST", # beginning of an artist name
        "I-ARTIST", # an artist name
        "B-MEDIUM", # beginning of a medium name
        "I-MEDIUM", # a medium name
    ]
    

    适应标记化

    关于注解模式,BERT 和其他几个模型有不同的标记化模型。因此,我们必须调整这两种标记化。 在这种bert-base-uncased 的情况下,预期的结果是这样的:

    damien  B-ARTIST
    hi  I-ARTIST
    ##rst  I-ARTIST
    oil  B-MEDIUM
    in  I-MEDIUM
    canvas  I-MEDIUM
    

    为了完成这项工作,您可以遍历原始注释中的每个标记,然后对其进行标记并再次添加其标签:

    tokens_old = ['Damien', 'Hirst', 'oil', 'in', 'canvas']
    labels_old = ["B-ARTIST", "I-ARTIST", "B-MEDIUM", "I-MEDIUM", "I-MEDIUM"]
    label2id = {label: idx for idx, label in enumerate(label_list)}
    
    tokens, labels = zip(*[
       (token, label)
       for token_old, label in zip(tokens_old, labels_old)
       for token in tokenizer.tokenize(token_old)
    ])
    

    当您在tokens 中添加[CLS][SEP] 时,它们的标签"O" 必须添加到labels

    使用上面的代码,可能会遇到这样的情况:当开头的单词分裂成片段时,像B-ARTIST 这样的开头标记会重复。根据 huggingface 文档中的描述,您可以使用 -100 对这些标签进行编码以被忽略: https://huggingface.co/transformers/custom_datasets.html#token-classification-with-w-nut-emerging-entities

    这样的事情应该可以工作:

    tokens, labels = zip(*[
       (token, label2id[label] if (label[:2] != "B-" or i == 0) else -100)
       for token_old, label in zip(tokens_old, labels_old)
       for i, token in enumerate(tokenizer.tokenize(token_old))
    ])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-06
      • 1970-01-01
      • 1970-01-01
      • 2020-01-25
      • 1970-01-01
      • 1970-01-01
      • 2021-10-25
      • 1970-01-01
      相关资源
      最近更新 更多