[CV2NLP] 文本Tokenizer如何编码中文

 2024-01-23 01:03:26  阅读 0

为什么也可以生成中文呢?

库中正常的.txt由0到40407个字符组成,不包含汉字。 但输入汉字时,仍然可以返回对应的汉字。 为什么是这样? 我将继续推测。

首先,对中文“五”进行编码,得到[49406, 21078, 498, 49407]

c unicode编码转换中文_unicode编码转换中文_编码转换中文

其中49406和前49407为SOT和EOT,其余49407被pad至77长度。

那么中文“五”对应的编码就是21078和498。这两个ID在.txt中对应的字符是:

“α”:21078

“Ķ”:498,

那么为什么这两个难以理解的字会对应到中文的“五”呢?

我们先来了解一下UTF-8的概念。

它是什么?

为了解决传统字符编码的局限性,诞生了。 全称是-Octet Coded Set(通用多八位字符集,简称UCS)。 一个字符集包含了世界上所有的文字和符号,并进行统一编码,杜绝了因编码不同而造成的乱码问题。

这是一个庞大的集合,目前可容纳超过 100 万个符号。 每个符号的编码是不同的。 例如,\u0639 代表阿拉伯字母 Ain,\u0041 代表英文大写字母 A,\u4e94 代表汉字五。

下面是一个专门查询所有字符对应关系的网页:

unicode编码转换中文_c unicode编码转换中文_编码转换中文

可以看到汉字“五”的编码是\u4e94。

什么是UTF-8?

UTF-8是一种存储编码的特定方式,通常用二进制或十六进制表示。

它统一了所有字符的编码,是一个Set,即字符集。 字符集只是赋予所有字符一个唯一的编号(例如\u4e94代表汉字五),但没有指定如何存储它。 编号为 65 的字符只需要一个字节来存储(一个字节用 8 位二进制 0/1 表示,范围为 0 到 255),但是编号为 40657 的字符需要两个字节的空间来存储,而且是再往前走。 字符可能需要三个甚至四个字节的空间。

这时候关键是用什么规则来存储字符。 我们可以规定一个字符用四个字节来存储,也就是32位,这样就可以覆盖所有现有的字符。 这种编码方式称为UTF-32(UTF是UCS的缩写)。 UTF-32的规则虽然简单,但缺陷也很明显。 假设使用 UTF-32 和 ASCII 对仅包含西方字母的文档进行编码。 前者需要的空间是后者的四倍(ASCII的每个字符只需要存储一个字节)。

在存储和网络传输中,通常采用更节省空间的变长编码方式UTF-8。 UTF-8表示一种8位组表示字符的格式,使用1到4个字节来表示字符。

UTF-8的编码规则如下(U+后面的数字代表字符编码):

U+ 0000 ~ U+ 007F:

U+ 0080 ~ U+ 07FF:

U+ 0800 ~ U+ FFFF:

U+10000 ~ U+1FFFF:

可以看到,UTF-8通过开头的标志位数来实现可变长度。 对于单字节字符,只占用一个字节,实现了与ASCII的向后兼容。 与UTF-32一样,它可以包含其中的所有字符,可以有效减少存储和传输过程中占用的空间。

因此,UTF-8编码根据不同的字符将一个字符编码为1-6个字节。 英文字母为1个字节,汉字通常为3个字节,生僻字为4-6个字节。

例如,汉字“五”是\u4e94,汉字“五”的二进制表示为:

11

可见,汉字“五”由3个字节表示。

将上述二进制改写为十六进制,汉字“五”的十六进制如下:

了解了UTF-8后,如何将“ä”和“Ķ”解码为汉字“五”呢?

首先.txt是指在字符末尾添加特殊的结束标记

然后看下面几行代码及其对应的结果:

ids = tokenizer.encode("五“)# ids: [49406, 21078, 498, 49407]
tokens = tokenizer.convert_ids_to_tokens(ids)# tokens = ['<|startoftext|>', 'äº', 'Ķ', '<|endoftext|>']
string = tokenizer.convert_tokens_to_string(tokens)# string = '<|startoftext|>五 <|endoftext|>'
def convert_tokens_to_string(tokens): """Converts a sequence of tokens (string) in a single string.""" text = "".join(tokens) tmp = [tokenizer.byte_decoder[c] for c in text] byte_array = bytearray(tmp) # tt = bytearray([228, 186, 148]) # td = tt.decode("utf-8", errors=tokenizer.errors) text = byte_array.decode("utf-8", errors=tokenizer.errors).replace("", " ").strip() return text

事实上,每本都有一本字典。 字典的键是.txt中的每个字符,值是这些字符对应的十进制表示。

这里注意,.txt中的每个key不仅仅对应一个字节(即8位二进制)。 例如,字符“ä”:21078对应两个字节11010,“Ķ”对应这一个字节。 将这三个字节转换成十进制就是“[228, 186, 148]”。

并将([228, 186, 148]).("utf-8")转换为汉字“五”。

那么就会有另一个问题。 .txt 中的某些字符看起来是乱码。 为什么?

乱码实际上是多个二进制字节的UTF-8解码显示。

首先,这些乱码是通过Byte-Pair(BPE)编码UTF-8得到的(具体参见BPE),所以.txt中的一些字符没有实际意义。 例如,字符“ä°”实际上是两个字节11010的解码显示,“ä°”和“Ķ”放在一起就是汉字“五”的UTF-8编码。

大家好,我是OAOA

一个在人工智能领域非常好的wmls,但还没有超越它。

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码