transformers BartTokenizer::add_tokens() 不能像我期望的那样工作后缀

transformers BartTokenizer::add_tokens() Doesn't Work as I'd Expect for Suffixes

我似乎能够毫无问题地添加标记,但如果我尝试添加后缀(即..前面没有初始字符 'Ġ' 的后缀),标记器不会不要在正确的位置放置空格。这是一些非常简化的测试代码。

from   copy import deepcopy
from   transformers import BartTokenizer
# Get the different tokenizers
tokenizer     = BartTokenizer.from_pretrained('facebook/bart-base')
tokenizer_ext = deepcopy(tokenizer)
# Note that putting Ġ after the token causes the token not to be used
num_added     = tokenizer_ext.add_tokens(['-of', '_01', 'WXYZ'])
# Original sentence
print('Original')
serial  = ':ARG0-of ( sense_01 :ARG1 ( urgencyWXYZ )'
print(serial)
print()
# Baseline tokenizer
print('Bart default tokenizer')
tokens  = tokenizer.tokenize(serial)
out_str = tokenizer.convert_tokens_to_string(tokens)
print(tokens)
print(out_str)
print()
# extended tokenizer
print('Extended tokenizer')
tokens  = tokenizer_ext.tokenize(serial)
out_str = tokenizer_ext.convert_tokens_to_string(tokens)
print(tokens)
print(out_str) 

这给...

Original
:ARG0-of ( sense_01 :ARG1 ( urgencyWXYZ )

Bart default tokenizer
[':', 'AR', 'G', '0', '-', 'of', 'Ġ(', 'Ġsense', '_', '01', 'Ġ:', 'AR', 'G', '1', 'Ġ(', 'Ġurgency', 'W', 'XY', 'Z', 'Ġ)']
:ARG0-of ( sense_01 :ARG1 ( urgencyWXYZ )

Extended tokenizer
[':', 'AR', 'G', '0', '-of', '(', 'Ġsense', '_01', ':', 'AR', 'G', '1', 'Ġ(', 'Ġurgency', 'WXYZ', ')']
:ARG0-of( sense_01:ARG1 ( urgencyWXYZ)

请注意,默认的 bart 分词器产生与原始句子相同的输出,但扩展分词器不会在新后缀分词后放置空格。即.. 它选择 '(' 而不是 'Ġ('。知道这是为什么吗?添加后缀标记的正确方法是什么?

简短的回答是,在为 Bart(和 RoBerta、GPT2 等)处理添加的标记时存在“行为”(错误?),它明确地从相邻的标记(左侧和右侧)中去除空格到添加的令牌的位置。我没有看到一个简单的解决方法。

添加的标记在转换器的标记器代码中的处理方式不同。文本首先被拆分,使用 Trie 来标识添加的标记列表中的任何标记(参见 tokenization_utils.py::tokenize())。在文本中找到任何添加的标记后,其余部分将使用现有的 vocab/bpe 编码方案进行标记化(参见 tokenization_gpt2.py::_tokenize()

添加的标记被添加到 self.unique_no_split_tokens 列表中,以防止它们被进一步分解成更小的块。处理此问题的代码(请参阅 tokenization_utils.py::tokenize() 显式地从标记中去除左右两边的空格。

您可以手动将它们从“不拆分”列表中删除,但随后它们可能会分解成更小的子组件。

请注意,对于“特殊标记”,如果您在 AddedToken class 中添加标记,您可以设置 lstriprstrip 行为,但这是不适用于非特殊令牌。

有关去除空格的 else 语句,请参阅 https://github.com/huggingface/transformers/blob/v4.12.5-release/src/transformers/tokenization_utils.py#L517