Skip to content

Commit 43248e5

Browse files
jaime-m-pjaggzhdragnil1ggerganov
authored
llama3 custom regex split (#6965)
* merged the changes from deepseeker models to main branch * Moved regex patterns to unicode.cpp and updated unicode.h * Moved header files * Resolved issues * added and refactored unicode_regex_split and related functions * Updated/merged the deepseek coder pr * Refactored code * Adding unicode regex mappings * Adding unicode regex function * Added needed functionality, testing remains * Fixed issues * Fixed issue with gpt2 regex custom preprocessor * unicode : fix? unicode_wstring_to_utf8 * lint : fix whitespaces * tests : add tokenizer tests for numbers * unicode : remove redundant headers * tests : remove and rename tokenizer test scripts * tests : add sample usage * gguf-py : reader prints warnings on duplicate keys * llama : towards llama3 tokenization support (wip) * unicode : shot in the dark to fix tests on Windows * unicode : first try custom implementations * convert : add "tokenizer.ggml.pre" GGUF KV (wip) * llama : use new pre-tokenizer type * convert : fix pre-tokenizer type writing * lint : fix * make : add test-tokenizer-0-llama-v3 * wip * models : add llama v3 vocab file * llama : adapt punctuation regex + add llama 3 regex * minor * unicode : set bomb * unicode : set bomb * unicode : always use std::wregex * unicode : support \p{N}, \p{L} and \p{P} natively * unicode : try fix windows * unicode : category support via std::regex * unicode : clean-up * unicode : simplify * llama3 custom regex split * convert : add convert-hf-to-gguf-update.py ggml-ci * lint : update * convert : add falcon ggml-ci * unicode : normalize signatures * lint : fix * lint : fix * convert : remove unused functions * convert : add comments * convert : exercise contractions ggml-ci * Using char32_t for codepoints * lint : fix * already exists unicode_tolower() * Typing * Restore BOM * cmake : refactor test targets * tests : refactor vocab tests ggml-ci * tests : add more vocabs and tests ggml-ci * unicode : cleanup * scripts : ignore new update script in check-requirements.sh * Fix merge * models : add phi-3, mpt, gpt-2, starcoder * tests : disable obsolete ggml-ci * tests : use faster bpe test ggml-ci * llama : more prominent warning for old BPE models * tests : disable test-tokenizer-1-bpe due to slowness ggml-ci * Move unused variable value * GPT2 custom regex split * Add alternative regex for custom aplit llama3 Co-authored-by: Georgi Gerganov <[email protected]> * Style * Add bruteforce random tests for token encoding * wip: fixing unicode codepoint ranges * Fix merge * Unicode tables: separator, lowercase, uppercase and whitespace * llama3 custom regex split: fix \s * Restore BOM * Style * wip: generate NDF table * Ignore special tokens for testing * Clean gen-unicode-data.py * Refactor random tokenizer test * lint : fix * tests : add fail test for llama-bpe --------- Co-authored-by: Jaggzh <[email protected]> Co-authored-by: Kazim Abrar Mahi <[email protected]> Co-authored-by: Georgi Gerganov <[email protected]> Co-authored-by: jaime-m-p <>
1 parent a743d76 commit 43248e5

File tree

8 files changed

+1463
-544
lines changed

8 files changed

+1463
-544
lines changed

convert-hf-to-gguf-update.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ def get_vocab_base_pre(self, tokenizer) -> str:
261261
"3333333",
262262
"33333333",
263263
"333333333",
264+
# "Cửa Việt", # llama-bpe fails on this
264265
chktxt,
265266
]
266267

llama.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12488,7 +12488,7 @@ struct llm_tokenizer_wpm {
1248812488
continue;
1248912489
}
1249012490
code = unicode_tolower(code);
12491-
if (type == CODEPOINT_TYPE_WHITESPACE) {
12491+
if (type == CODEPOINT_TYPE_SEPARATOR) {
1249212492
code = ' ';
1249312493
}
1249412494
std::string s = unicode_cpt_to_utf8(code);

scripts/gen-unicode-data.py

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,14 @@
11
import regex
22

33

4-
def cpt_to_utf8_str(cpt):
5-
if cpt <= 0xFF:
6-
return bytes([cpt, 0, 0, 0])
7-
elif cpt <= 0xFFFF:
8-
return bytes([cpt & 0xFF, cpt >> 8, 0, 0])
9-
elif cpt <= 0xFFFFFF:
10-
return bytes([cpt & 0xFF, (cpt >> 8) & 0xFF, (cpt >> 16) & 0xFF, 0])
11-
else:
12-
return bytes([cpt & 0xFF, (cpt >> 8) & 0xFF, (cpt >> 16) & 0xFF, cpt >> 24])
13-
14-
15-
def is_match(codepoint, regex_expr):
16-
try:
17-
res = regex.match(regex_expr, cpt_to_utf8_str(codepoint).decode('utf-32'))
18-
return res is not None
19-
except Exception:
20-
return False
21-
22-
234
def get_matches(regex_expr):
5+
regex_expr_compiled = regex.compile(regex_expr)
246
unicode_ranges = []
257
current_range = None
268

279
for codepoint in range(0x110000):
28-
if is_match(codepoint, regex_expr):
10+
char = chr(codepoint)
11+
if regex_expr_compiled.match(char):
2912
if current_range is None:
3013
current_range = [codepoint, codepoint]
3114
else:
@@ -40,27 +23,42 @@ def get_matches(regex_expr):
4023
return unicode_ranges
4124

4225

43-
def print_cat(cat, ranges):
44-
print("const std::vector<std::pair<uint32_t, uint32_t>> unicode_ranges_{} = {{".format(cat)) # noqa: NP100
45-
cnt = 0
46-
for start, end in ranges:
47-
if cnt % 4 != 0:
48-
print(" ", end="") # noqa: NP100
49-
print("{{0x{:08X}, 0x{:08X}}},".format(start, end), end="") # noqa: NP100
50-
if cnt % 4 == 3:
51-
print("") # noqa: NP100
52-
cnt += 1
53-
54-
if cnt % 4 != 0:
55-
print("") # noqa: NP100
26+
def print_cat(mode, cat, ranges):
27+
if mode == "range":
28+
print("const std::vector<std::pair<uint32_t, uint32_t>> unicode_ranges_{} = {{".format(cat)) # noqa: NP100
29+
if mode == "map":
30+
print("const std::map<uint32_t, uint32_t> unicode_map_{} = {{".format(cat)) # noqa: NP100
31+
for i, values in enumerate(ranges):
32+
end = ",\n" if (i % 4 == 3 or i + 1 == len(ranges)) else ", "
33+
values = ["0x%08X" % value for value in values]
34+
print("{" + ", ".join(values) + "}", end=end) # noqa: NP100
5635
print("};") # noqa: NP100
5736
print("") # noqa: NP100
5837

5938

60-
print_cat("number", get_matches(r'\p{N}'))
61-
print_cat("letter", get_matches(r'\p{L}'))
62-
print_cat("whitespace", get_matches(r'\p{Z}'))
63-
print_cat("accent_mark", get_matches(r'\p{M}'))
64-
print_cat("punctuation", get_matches(r'\p{P}'))
65-
print_cat("symbol", get_matches(r'\p{S}'))
66-
print_cat("control", get_matches(r'\p{C}'))
39+
print_cat("range", "number", get_matches(r'\p{N}'))
40+
print_cat("range", "letter", get_matches(r'\p{L}'))
41+
print_cat("range", "separator", get_matches(r'\p{Z}'))
42+
print_cat("range", "accent_mark", get_matches(r'\p{M}'))
43+
print_cat("range", "punctuation", get_matches(r'\p{P}'))
44+
print_cat("range", "symbol", get_matches(r'\p{S}'))
45+
print_cat("range", "control", get_matches(r'\p{C}'))
46+
47+
print_cat("range", "whitespace", get_matches(r'\s'))
48+
49+
50+
map_lowercase = []
51+
map_uppercase = []
52+
for codepoint in range(0x110000):
53+
char = chr(codepoint)
54+
lower = ord(char.lower()[0])
55+
upper = ord(char.upper()[0])
56+
if codepoint != lower:
57+
map_lowercase.append((codepoint, lower))
58+
if codepoint != upper:
59+
map_uppercase.append((codepoint, upper))
60+
print_cat("map", "lowercase", map_lowercase)
61+
print_cat("map", "uppercase", map_uppercase)
62+
63+
64+
# TODO: generate unicode_map_nfd

0 commit comments

Comments
 (0)