Code: https://github.com/OctopusMind/BBPE
1、正则表达式分词
pat_str = r"'s|'t|'re|'ve|'m|'ll|'d| ?[\p{L}]+| ?[\p{N}]+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+"
各部分含义如下:
's|'t|'re|'ve|'m|'ll|'d
- 匹配一些英文中最常见的缩写后缀(类似于词素/词缀):
- ’s(is 或 has 的缩写,如 it’s, John’s)
- ‘t(not 的缩写,如 can’t, won’t)
- ‘re(are 的缩写,如 you’re)
- ‘ve(have 的缩写,如 I’ve)
- ‘m(am 的缩写,如 I’m)
- ‘ll(will 的缩写,如 I’ll)
- ‘d(would 或 had 的缩写,如 I’d)
- 匹配一些英文中最常见的缩写后缀(类似于词素/词缀):
?[\p{L}]+
- 匹配以可选空格开始,后面连着至少一个“字母”(Unicode类别 L,涵盖所有语言的字母)。
- 例: hello、你好、Привет。
- 注意前面的空格是可选的,目的是保留词前可能的空格信息(对BPE分词很关键)。
?[\p{N}]+
- 匹配以可选空格开始,后面连着至少一个“数字”(Unicode类别 N)。
- 例: 2024、345(全角数字也可,因范围广)。
- 同样空格是 token 的一部分。
?[^\s\p{L}\p{N}]+
- 匹配以可选空格开始,后面是至少一个既不是空白(\s),也不是字母(\p{L}),也不是数字(\p{N})的字符。
- 例:标点、符号,如: !、,、@# 等。
\s+(?!\S)
- 匹配连续的空白字符(\s+),但后面不能跟非空白字符((?!\S))。即只能匹配那些在文本末尾的空格。
- 例:句子末尾的多个空格。
\s+
- 匹配一个或多个空白字符。用于捕获普通的空格分隔。
- 注意:整体顺序也很重要,整体分词时通常优先匹配前面的规则。
2、utf-8字节值到unicode可打印字符的映射
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def bytes_to_unicode():
"""
返回utf-8字节列表和到unicode字符串的映射。我们特别避免映射到bbpe代码所依赖的空白/控制字符。
可逆的bbpe代码在unicode字符串上工作。这意味着如果您想避免UNKs,您需要在您的词汇表中使用大量的unicode字符。
当你有一个10B的token数据集时,你最终需要大约5K才能获得良好的覆盖。这是你正常情况下的一个显著比例,
比如说,32K的词汇量。为了避免这种情况,我们希望查找表介于utf-8字节和unicode字符串之间。
"""
# 初始化bs均为可打印字符
bs = (
# 33 - 126
list(range(ord("!"), ord("~") + 1)) + \
# 162 - 172
list(range(ord("¡"), ord("¬") + 1)) + \
# 174 - 255
list(range(ord("®"), ord("ÿ") + 1))
)
cs = bs[:]
n = 0
# 处理非可打印字符(映射到其他可打印的unicode字符)
for b in range(2 ** 8):
# 如果不在bs中,说明是非可打印字符,需要映射到其他可打印的unicode字符 (256 + n)
if b not in bs:
bs.append(b)
cs.append(2 ** 8 + n)
n += 1
# 将cs转换为unicode字符串
cs = [chr(n) for n in cs]
# 构建bs到cs的映射
return dict(zip(bs, cs))