|
1 | | -import itertools |
2 | 1 | import os |
3 | 2 | import regex as re |
4 | 3 | from typing import BinaryIO |
5 | | -import multiprocessing as mp |
6 | 4 | import cProfile |
7 | 5 | import pstats |
8 | | -from collections import Counter |
9 | | -import heapq |
10 | | -# from rusty_tokey import rusty_merge |
11 | 6 | from rusty_tokey import rusty_full_merge |
12 | | -# from rusty_tokey import rusty_pre_tok |
13 | 7 |
|
14 | 8 |
|
15 | 9 | PAT = r"""'(?:[sdmt]|ll|ve|re)| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+""" |
@@ -58,132 +52,7 @@ def find_chunk_boundaries(file: BinaryIO, desired_num_chunks: int, split_special |
58 | 52 | # Make sure all boundaries are unique, but might be fewer than desired_num_chunks |
59 | 53 | return sorted(set(chunk_boundaries)) |
60 | 54 |
|
61 | | - |
62 | | -def pre_tokenize_chunk(input_path: str, start: int, end: int, pattern: re.Pattern[str]): |
63 | | - with open(input_path, "rb") as f: |
64 | | - f.seek(start) |
65 | | - chunk = f.read(end - start).decode("utf-8", errors="ignore") |
66 | | - sub_chunks = pattern.split(chunk) |
67 | | - # run tokenization for each of the sub_chunks. |
68 | | - iterators = [PAT_RE.finditer(sub_chunk) for sub_chunk in sub_chunks] |
69 | | - flattened_iterators = itertools.chain(*iterators) |
70 | | - store = Counter() |
71 | | - for match in flattened_iterators: |
72 | | - res = match.group() |
73 | | - res_bytes = tuple(bytes([c]) for c in res.encode("utf-8")) |
74 | | - store[res_bytes] += 1 |
75 | | - return store |
76 | | - |
77 | | -# def rusty_pre_tokenize_chunk(input_path: str, start: int, end: int, pattern: re.Pattern[str], special_tokens: list[str]) -> dict[list[list[int]],int]: |
78 | | -# with open(input_path, "rb") as f: |
79 | | -# f.seek(start) |
80 | | -# chunk = f.read(end - start).decode("utf-8", errors="ignore") |
81 | | - |
82 | | -# result = rusty_pre_tok(chunk,special_tokens) |
83 | | - |
84 | | -# sub_chunks = pattern.split(chunk) |
85 | | -# # run tokenization for each of the sub_chunks. |
86 | | -# iterators = [PAT_RE.finditer(sub_chunk) for sub_chunk in sub_chunks] |
87 | | -# flattened_iterators = itertools.chain(*iterators) |
88 | | -# store = Counter() |
89 | | -# for match in flattened_iterators: |
90 | | -# res = match.group() |
91 | | -# res_bytes = tuple(bytes([c]) for c in res.encode("utf-8")) |
92 | | -# store[res_bytes] += 1 |
93 | | -# return store |
94 | | - |
95 | | - |
96 | | -def get_all_simple_pairs( |
97 | | - pre_tok_dic: Counter[tuple[bytes], int], |
98 | | -) -> tuple[dict[tuple[bytes, bytes], int], dict[tuple[bytes, bytes], set[tuple[bytes]]]]: |
99 | | - pair_to_count = Counter() |
100 | | - pair_to_tokens = {} |
101 | | - for pre_token_key, count in pre_tok_dic.items(): |
102 | | - if len(pre_token_key) < 2: |
103 | | - continue |
104 | | - for i in range(len(pre_token_key) - 1): |
105 | | - pair = (pre_token_key[i], pre_token_key[i + 1]) |
106 | | - pair_to_count[pair] += count |
107 | | - if pair not in pair_to_tokens: |
108 | | - pair_to_tokens[pair] = set() |
109 | | - pair_to_tokens[pair].add(pre_token_key) |
110 | | - return (pair_to_count, pair_to_tokens) |
111 | | - |
112 | | - |
113 | | -# not optimized for now. |
114 | | -def merge(pre_tok_dic: Counter[tuple[bytes], int], stopping_condition: int): |
115 | | - max_pairs: list[tuple[bytes, bytes]] = [] |
116 | | - (pair_to_count, pair_to_tokens) = get_all_simple_pairs(pre_tok_dic) |
117 | | - |
118 | | - # build heap from pair_to_count, to efficiently find max_pair |
119 | | - heap = [(-count, pair) for pair, count in pair_to_count.items()] |
120 | | - heapq.heapify(heap) |
121 | | - |
122 | | - while len(max_pairs) < stopping_condition and heap: |
123 | | - # neg_count, max_pair = heapq.heappop(heap) |
124 | | - # if max_pair not in pair_to_count or -neg_count != pair_to_count[max_pair]: |
125 | | - # continue |
126 | | - max_pair = max(pair_to_count, key=lambda pair: (pair_to_count[pair], pair)) |
127 | | - # max_pair = alt_max_pair |
128 | | - max_pairs.append(max_pair) |
129 | | - |
130 | | - # INSERT_YOUR_CODE |
131 | | - # Print the pair at the top of the heap (heap max) and the pair with the max count (max max) |
132 | | - # print("heap max:", alt_max_pair, -neg_count, "max max:", max_pair, pair_to_count[max_pair]) |
133 | | - |
134 | | - # ------------ EFFICIENTLY UPDATE ------------ |
135 | | - affected_pre_toks = set(pair_to_tokens[max_pair]) |
136 | | - for pre_tok in affected_pre_toks: |
137 | | - count = pre_tok_dic[pre_tok] |
138 | | - for i in range(len(pre_tok) - 1): |
139 | | - # calculate pair |
140 | | - pair = (pre_tok[i], pre_tok[i + 1]) |
141 | | - # decrement count from pair |
142 | | - pair_to_count[pair] -= count |
143 | | - # ------ HEAP MAINTENANCE ------ |
144 | | - heapq.heappush(heap, (-pair_to_count[pair], pair)) |
145 | | - # ------ HEAP MAINTENANCE ------ |
146 | | - # remove token from pairs_to_tokens |
147 | | - pair_to_tokens[pair].discard(pre_tok) |
148 | | - # if pair doesn't occur anymore remove all together. |
149 | | - if pair_to_count[pair] == 0: |
150 | | - del pair_to_count[pair] |
151 | | - del pair_to_tokens[pair] |
152 | | - # construct new merged_token. |
153 | | - new_pre_tok = [] |
154 | | - i = 0 |
155 | | - while i < len(pre_tok): |
156 | | - if i < len(pre_tok) - 1 and (pre_tok[i], pre_tok[i + 1]) == max_pair: |
157 | | - new_pre_tok.append(pre_tok[i] + pre_tok[i + 1]) |
158 | | - i += 2 |
159 | | - else: |
160 | | - new_pre_tok.append(pre_tok[i]) |
161 | | - i += 1 |
162 | | - new_pre_tok = tuple(new_pre_tok) |
163 | | - |
164 | | - # update dic. |
165 | | - pre_tok_dic[new_pre_tok] += count |
166 | | - pre_tok_dic[pre_tok] -= count |
167 | | - |
168 | | - # remove all together if appropriate |
169 | | - if pre_tok_dic[pre_tok] == 0: |
170 | | - del pre_tok_dic[pre_tok] |
171 | | - |
172 | | - for i in range(len(new_pre_tok) - 1): |
173 | | - pair = (new_pre_tok[i], new_pre_tok[i + 1]) |
174 | | - pair_to_count[pair] += count |
175 | | - # ------ HEAP MAINTENANCE ------ |
176 | | - heapq.heappush(heap, (-pair_to_count[pair], pair)) |
177 | | - # ------ HEAP MAINTENANCE ------ |
178 | | - if pair not in pair_to_tokens: |
179 | | - pair_to_tokens[pair] = set() |
180 | | - pair_to_tokens[pair].add(new_pre_tok) |
181 | | - |
182 | | - # ------------ EFFICIENTLY UPDATE ------------ |
183 | | - return max_pairs |
184 | | - |
185 | | - |
186 | | -def train_bpe( |
| 55 | +def rusty_train_bpe( |
187 | 56 | input_path: str, vocab_size: int, special_tokens: list[str] |
188 | 57 | ) -> tuple[dict[int, bytes], list[tuple[bytes, bytes]]]: |
189 | 58 | special_tokens_len = len(special_tokens) |
@@ -212,8 +81,9 @@ def train_bpe( |
212 | 81 | if __name__ == "__main__": |
213 | 82 | profiler = cProfile.Profile() |
214 | 83 | profiler.enable() |
215 | | - (vocab, max_pairs) = train_bpe("./python/rusty_tokey/data/tinystories_sample_5M.txt", 400, ["<|endoftext|>"]) |
| 84 | + (vocab, max_pairs) = rusty_train_bpe("./python/rusty_tokey/data/tinystories_sample_5M.txt", 400, ["<|endoftext|>"]) |
216 | 85 | print("max_pairs", max_pairs) |
| 86 | + print("vocab", vocab) |
217 | 87 | profiler.disable() |
218 | 88 | stats = pstats.Stats(profiler).sort_stats("cumtime") |
219 | 89 | stats.print_stats(20) # Show top 20 slowest functions |
0 commit comments