标记器解码步骤拥抱脸中的标记到单词映射?

Posted

技术标签:

【中文标题】标记器解码步骤拥抱脸中的标记到单词映射?【英文标题】:Tokens to Words mapping in the tokenizer decode step huggingface? 【发布时间】:2020-09-30 16:53:15 【问题描述】:

有没有办法知道tokenizer.decode() 函数中从标记到原始单词的映射? 例如:

from transformers.tokenization_roberta import RobertaTokenizer

tokenizer = RobertaTokenizer.from_pretrained('roberta-large', do_lower_case=True)

str = "This is a tokenization example"
tokenized = tokenizer.tokenize(str) 
## ['this', 'Ġis', 'Ġa', 'Ġtoken', 'ization', 'Ġexample']

encoded = tokenizer.encode_plus(str) 
## encoded['input_ids']=[0, 42, 16, 10, 19233, 1938, 1246, 2]

decoded = tokenizer.decode(encoded['input_ids']) 
## '<s> this is a tokenization example</s>'

目标是有一个函数将decode 进程中的每个标记映射到正确的输入单词,因为这里将是:desired_output = [[1],[2],[3],[4,5],[6]] 因为this 对应于 id @ 987654326@,而tokenization 对应于ID [19244,1938],它们位于input_ids 数组的索引4,5

【问题讨论】:

您能否补充一下您是如何创建分词器对象的以及您使用了哪些导入(可能是基于 BERT 的分词器)? 添加了完整的例子,谢谢! 【参考方案1】:

据我所知,它们没有内置方法,但您可以自己创建一个:

from transformers.tokenization_roberta import RobertaTokenizer

tokenizer = RobertaTokenizer.from_pretrained('roberta-large', do_lower_case=True)

example = "This is a tokenization example"

print(x : tokenizer.encode(x, add_special_tokens=False, add_prefix_space=True) for x in example.split())

输出:

'This': [42], 'is': [16], 'a': [10], 'tokenization': [19233, 1938], 'example': [1246]

要准确获得所需的输出,您必须使用列表推导:

#start index because the number of special tokens is fixed for each model (but be aware of single sentence input and pairwise sentence input)
idx = 1

enc =[tokenizer.encode(x, add_special_tokens=False, add_prefix_space=True) for x in example.split()]

desired_output = []

for token in enc:
    tokenoutput = []
    for ids in token:
      tokenoutput.append(idx)
      idx +=1
    desired_output.append(tokenoutput)

print(desired_output)

输出:

[[1], [2], [3], [4, 5], [6]]

【讨论】:

谢谢。在添加特殊标记之后,我需要相关编码标记的索引,因为稍后我会在这些 idxs 上平均模型的特征输出(你可以看到我们的示例输出不同?) 不管怎样,如果不存在这样的默认函数,那就很简单了,我会写出来发在这里,谢谢? 这是一种解决方法,因为它忽略了其他特殊标记,如 等。但总体思路很清楚,谢谢:)【参考方案2】:

如果您使用快速分词器,即来自 tokenizers 库的 rust 支持版本,则编码包含一个 word_ids 方法,可用于将子词映射回其原始词。什么构成 wordsubword 取决于分词器,词是由预分词阶段生成的东西,即由空格分隔,子词由实际模型生成(BPEUnigram示例)。

下面的代码应该可以正常工作,即使预标记化执行了额外的拆分。例如,我创建了自己的基于 PascalCase 拆分的自定义步骤 - 这里的 wordsPascalCase,在这种情况下接受的答案将不起作用,因为它假定单词是空格分隔的。

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained('roberta-large', do_lower_case=True)

example = "This is a tokenization example"

encoded = tokenizer(example)

desired_output = []
for word_id in encoded.word_ids():
    if word_id is not None:
        start, end = encoded.word_to_tokens(word_id)
        if start == end - 1:
            tokens = [start]
        else:
            tokens = [start, end-1]
        if len(desired_output) == 0 or desired_output[-1] != tokens:
            desired_output.append(tokens)
desired_output

【讨论】:

以上是关于标记器解码步骤拥抱脸中的标记到单词映射?的主要内容,如果未能解决你的问题,请参考以下文章

拥抱脸中的 tokenizer.encode 和 tokenizer.encode_plus 有啥区别

将拥抱脸标记映射到原始输入文本

如何为拥抱脸重新下载标记器?

滚动到数组中的每个标记标签并将其显示在屏幕上

标记位存储在直接映射缓存中的啥位置?

高级编码和解码技术