为什么在英语上训练并应用于孟加拉语的 BPE 编码不会返回未知标记?

Sou*_*mya 2 huggingface-transformers huggingface-tokenizers roberta-language-model

我使用tokenizer = RobertaTokenizerFast.from_pretrained('roberta-base',add_prefix_space=True)在英语数据上训练的 roberta-base 分词器来对孟加拉语进行分词,只是为了看看它的行为如何。当我尝试对孟加拉语字符进行编码时tokenizer.encode('\xe0\xa6\xac\xe0\xa6\xbe'),我得到[0, 1437, 35861, 11582, 35861, 4726, 2]的结果是,即使在英语上进行训练,它也会在词汇表中找到一些与孟加拉语字符匹配的标记。经过进一步探索,我发现这些都是特殊字符['<s>', '\xc4\xa0', '\xc3\xa0\xc2\xa6', '\xc2\xac', '\xc3\xa0\xc2\xa6', '\xc2\xbe', '</s>']。我的问题是为什么会发生这种情况,当应用于新语言时,它不应该输出未知的标记吗?非常感谢任何帮助

\n

Jin*_*ich 5

正如评论中提到的,原因是 RoBERTa 分词器是基于字节的,而不是基于字符的。

\n

UTF-8中,字符由不同数量的字节表示,这严重偏向于拉丁字母:ASCII 字符是单字节,“最长”字符最多为四个字节。维基百科的一个例子:

\n
Char | UTF code | Bytes\n------------------------------\n$    | U+0024   | 24\n\xc2\xa2    | U+00A2   | C2 A2\n\xe0\xa4\xb9    | U+0939   | E0 A4 B9\n\xe2\x82\xac    | U+20AC   | E2 82 AC\n    | U+10348  | F0 90 8D 88\n
Run Code Online (Sandbox Code Playgroud)\n

RoBERTa 使用的SentecePiece分词器首先将文本分割成字节,这总是可能的而且只有 256 个字节,所以没有什么是每个 OOV 的。然后,已知的字节组被分组为词汇表中的已知标记。

\n

SentencePiece 还对空格和特殊字符进行特殊处理。首先,它根据特殊字符和空格对文本进行分段,并用特殊字符替换空格。在最初的实现中,它是一个特殊的 UTF-8 下划线\xe2\x96\x81,在 Huggingface 实现中,它是\xc4\xa0。这个特殊字符也被添加到句子的开头,因此当单词位于句子的开头或中间时,它们的表示方式是一致的。

\n

因此,您看到的输出基本上是:

\n
    \n
  1. 每个字符串前面的特殊空格符号 ( \xc4\xa0),以及
  2. \n
  3. 四个字节代表你的角色,
  4. \n
\n

这意味着该字符\xe0\xa6\xac\xe0\xa6\xbe 不在词汇表中,因此它最终被表示为四个字节,并且字节总是已知的。

\n