为什么也可以生成中文呢?
库中正常的.txt由0到40407个字符组成,不包含汉字。 但输入汉字时,仍然可以返回对应的汉字。 为什么是这样? 我将继续推测。
首先,对中文“五”进行编码,得到[49406, 21078, 498, 49407]
其中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 代表汉字五。
下面是一个专门查询所有字符对应关系的网页:
可以看到汉字“五”的编码是\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):
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,但还没有超越它。