jon-tow commited on
Commit
aceea5b
·
1 Parent(s): 99cb326

init: first commit

Browse files
README.md ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ # Arcade100kTokenizer
2
+
3
+ BPE tokenizer based on `tiktoken.cl100k_base`.
4
+
5
+ ```
6
+ from transformers import AutoTokenizer
7
+ tokenizer = AutoTokenizer.from_pretrained("jon-tow/arcade100k", trust_remote_code=True)
8
+ tokenizer("hello, world!", return_tensors='pt')
9
+ ```
arcade100k.tiktoken ADDED
The diff for this file is too large to render. See raw diff
 
tokenization_arcade100k.py ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2023 Stability AI, Alibaba Cloud, The Open AI Team Authors, and The HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Tokenization classes for Arcade100k."""
16
+
17
+ import base64
18
+ import os
19
+ import unicodedata
20
+ from typing import Collection, Dict, List, Set, Tuple, Union
21
+
22
+ import tiktoken
23
+ from transformers.utils import logging
24
+ from transformers import PreTrainedTokenizer, AddedToken
25
+
26
+ logger = logging.get_logger(__name__)
27
+
28
+ VOCAB_FILES_NAMES = {"vocab_file": "arcade100k.tiktoken"}
29
+ NAME = "arcade100k"
30
+
31
+
32
+ def _load_tiktoken_bpe(tiktoken_bpe_file: str) -> Dict[bytes, int]:
33
+ with open(tiktoken_bpe_file, "rb") as f:
34
+ contents = f.read()
35
+ return {
36
+ base64.b64decode(token): int(rank)
37
+ for token, rank in (line.split() for line in contents.splitlines() if line)
38
+ }
39
+
40
+
41
+ def _arcade100k(vocab_file: str):
42
+ mergeable_ranks = _load_tiktoken_bpe(vocab_file)
43
+
44
+ # Special Tokens
45
+ ENDOFTEXT = "<|endoftext|>"
46
+ FIM_PREFIX = "<|fim_prefix|>"
47
+ FIM_MIDDLE = "<|fim_middle|>"
48
+ FIM_SUFFIX = "<|fim_suffix|>"
49
+ ENDOFPROMPT = "<|endofprompt|>"
50
+
51
+ # Custom Special Tokens
52
+ IM_START = "<|im_start|>" # Chat: Input message start
53
+ IM_END = "<|im_end|>" # Chat: Input message end
54
+ PAUSE = "<|pause|>" # Think before you speak (https://arxiv.org/abs/2310.02226)
55
+ # Register/sink tokens (https://arxiv.org/abs/2309.17453)
56
+ REGISTERS = [f"<|reg{i}|>" for i in range(0, 8)]
57
+ custom_special_tokens = {
58
+ t: 100261 + i for i, t in enumerate([IM_START, IM_END, PAUSE, *REGISTERS])
59
+ }
60
+ ENDOFPROMPT_ID = 100276
61
+
62
+ # Fill-out extra tokens
63
+ for i in range(100261 + len(custom_special_tokens), ENDOFPROMPT_ID + 1):
64
+ custom_special_tokens[f"<|extra{i}|>"] = i
65
+
66
+ special_tokens = {
67
+ ENDOFTEXT: 100257,
68
+ FIM_PREFIX: 100258,
69
+ FIM_MIDDLE: 100259,
70
+ FIM_SUFFIX: 100260,
71
+ **custom_special_tokens,
72
+ ENDOFPROMPT: 100276,
73
+ }
74
+
75
+ return {
76
+ "name": NAME,
77
+ "pat_str": r"""(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+""",
78
+ "mergeable_ranks": mergeable_ranks,
79
+ "special_tokens": special_tokens,
80
+ }
81
+
82
+
83
+ class Arcade100kTokenizer(PreTrainedTokenizer):
84
+ """
85
+ Construct a Arcade100k tokenizer backed by `tiktoken`.
86
+
87
+ Args:
88
+ vocab_file (`str`):
89
+ Path to the vocabulary file.
90
+ errors (`str`, *optional*, defaults to `"replace"`):
91
+ How to handle errors in decoding UTF-8 byte sequences.
92
+ WARNING: the default behaviour of this function is lossy, since decoded bytes are not
93
+ guaranteed to be valid UTF-8. You can control this behaviour using the `errors` parameter,
94
+ for instance, setting `errors=strict`.
95
+ """
96
+
97
+ vocab_files_names = VOCAB_FILES_NAMES
98
+ model_input_names = ["input_ids", "attention_mask"]
99
+
100
+ def __init__(
101
+ self,
102
+ vocab_file: str,
103
+ errors: str = "replace",
104
+ **kwargs,
105
+ ):
106
+ super().__init__(errors=errors, **kwargs)
107
+ self._tiktoken_config = _arcade100k(self.vocab_files_names["vocab_file"])
108
+ self.tokenizer = tiktoken.Encoding(**self._tiktoken_config)
109
+ # TODO: Remove this assertion
110
+ assert (
111
+ len(self._tiktoken_config["mergeable_ranks"])
112
+ + len(self._tiktoken_config["special_tokens"])
113
+ == self.tokenizer.n_vocab
114
+ ), f"{len(self._tiktoken_config['mergeable_ranks']) + len(self._tiktoken_config['special_tokens'])} != {self.tokenizer.n_vocab} in encoding"
115
+
116
+ self.decoder = {
117
+ i: n for n, i in self._tiktoken_config["mergeable_ranks"].items()
118
+ }
119
+ self.decoder.update(
120
+ {i: n for n, i in self._tiktoken_config["special_tokens"].items()}
121
+ )
122
+ self.eos_token = self.decoder[self.tokenizer.eot_token]
123
+ self.pad_token = self.decoder[self.tokenizer.eot_token]
124
+
125
+ @property
126
+ def vocab_size(self):
127
+ return self.tokenizer.n_vocab
128
+
129
+ def get_vocab(self) -> Dict[bytes, int]:
130
+ return self._tiktoken_config["mergeable_ranks"]
131
+
132
+ def convert_tokens_to_ids(
133
+ self, tokens: Union[bytes, str, List[Union[bytes, str]]]
134
+ ) -> List[int]:
135
+ ids = []
136
+ if isinstance(tokens, (str, bytes)):
137
+ if tokens in self._tiktoken_config["special_tokens"]:
138
+ return self._tiktoken_config["special_tokens"][tokens]
139
+ else:
140
+ return self._tiktoken_config["mergeable_ranks"].get(tokens)
141
+ for token in tokens:
142
+ if token in self._tiktoken_config["special_tokens"]:
143
+ ids.append(self._tiktoken_config["special_tokens"][token])
144
+ else:
145
+ ids.append(self._tiktoken_config["mergeable_ranks"].get(token))
146
+ return ids
147
+
148
+ def _add_tokens(
149
+ self,
150
+ new_tokens: Union[List[str], List[AddedToken]],
151
+ special_tokens: bool = False,
152
+ ) -> int:
153
+ if not special_tokens and new_tokens:
154
+ raise ValueError("Adding regular tokens is not supported")
155
+ for token in new_tokens:
156
+ surface_form = token.content if isinstance(token, AddedToken) else token
157
+ if surface_form not in SPECIAL_TOKENS_SET:
158
+ raise ValueError("Adding unknown special tokens is not supported")
159
+ return 0
160
+
161
+ def save_vocabulary(self, save_directory: str, **kwargs) -> Tuple[str]:
162
+ """
163
+ Save only the vocabulary of the tokenizer (vocabulary).
164
+
165
+ Returns:
166
+ `Tuple(str)`: Paths to the files saved.
167
+ """
168
+ file_path = os.path.join(save_directory, "qwen.tiktoken")
169
+ with open(file_path, "w", encoding="utf8") as w:
170
+ for k, v in self._tiktoken_config["mergeable_ranks"].items():
171
+ line = base64.b64encode(k).decode("utf8") + " " + str(v) + "\n"
172
+ w.write(line)
173
+ return (file_path,)
174
+
175
+ def tokenize(
176
+ self,
177
+ text: str,
178
+ allowed_special: Union[Set, str] = "all",
179
+ disallowed_special: Union[Collection, str] = (),
180
+ **kwargs,
181
+ ) -> List[Union[bytes, str]]:
182
+ """
183
+ Converts a string in a sequence of tokens.
184
+
185
+ Args:
186
+ text (`str`):
187
+ The sequence to be encoded.
188
+ allowed_special (`Literal["all"]` or `set`):
189
+ The surface forms of the tokens to be encoded as special tokens in regular texts.
190
+ Default to "all".
191
+ disallowed_special (`Literal["all"]` or `Collection`):
192
+ The surface forms of the tokens that should not be in regular texts and trigger errors.
193
+ Default to an empty tuple.
194
+
195
+ kwargs (additional keyword arguments, *optional*):
196
+ Will be passed to the underlying model specific encode method.
197
+
198
+ Returns:
199
+ `List[bytes|str]`: The list of tokens.
200
+ """
201
+ tokens = []
202
+ text = unicodedata.normalize("NFC", text)
203
+
204
+ # this implementation takes a detour: text -> token id -> token surface forms
205
+ for t in self.tokenizer.encode(
206
+ text, allowed_special=allowed_special, disallowed_special=disallowed_special
207
+ ):
208
+ tokens.append(self.decoder[t])
209
+ return tokens
210
+
211
+ def convert_tokens_to_string(self, tokens: List[Union[bytes, str]]) -> str:
212
+ """
213
+ Converts a sequence of tokens in a single string.
214
+ """
215
+ text = ""
216
+ temp = b""
217
+ for t in tokens:
218
+ if isinstance(t, str):
219
+ if temp:
220
+ text += temp.decode("utf-8", errors=self.errors)
221
+ temp = b""
222
+ text += t
223
+ elif isinstance(t, bytes):
224
+ temp += t
225
+ else:
226
+ raise TypeError("token should only be of type types or str")
227
+ if temp:
228
+ text += temp.decode("utf-8", errors=self.errors)
229
+ return text
230
+
231
+ def _convert_id_to_token(self, index: int) -> Union[bytes, str]:
232
+ """Converts an id to a token, special tokens included"""
233
+ if index in self.decoder:
234
+ return self.decoder[index]
235
+ raise ValueError("unknown ids")
236
+
237
+ def _convert_token_to_id(self, token: Union[bytes, str]) -> int:
238
+ """Converts a token to an id using the vocab, special tokens included"""
239
+ if token in self._tiktoken_config["special_tokens"]:
240
+ return self._tiktoken_config["special_tokens"][token]
241
+ if token in self._tiktoken_config["mergeable_ranks"]:
242
+ return self._tiktoken_config["mergeable_ranks"][token]
243
+ raise ValueError("unknown token")
244
+
245
+ def _tokenize(self, text: str, **kwargs):
246
+ """
247
+ Converts a string in a sequence of tokens (string), using the tokenizer. Split in words for word-based
248
+ vocabulary or sub-words for sub-word-based vocabularies (BPE/SentencePieces/WordPieces).
249
+
250
+ Do NOT take care of added tokens.
251
+ """
252
+ raise NotImplementedError
253
+
254
+ def _decode(
255
+ self,
256
+ token_ids: Union[int, List[int]],
257
+ skip_special_tokens: bool = False,
258
+ errors: str = None,
259
+ **kwargs,
260
+ ) -> str:
261
+ if isinstance(token_ids, int):
262
+ token_ids = [token_ids]
263
+ if skip_special_tokens:
264
+ token_ids = [i for i in token_ids if i < self.tokenizer.eot_token]
265
+ return self.tokenizer.decode(token_ids, errors=errors or self.errors)
tokenizer_config.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "tokenizer_class": "Arcade100kTokenizer",
3
+ "auto_map": {
4
+ "AutoTokenizer": [
5
+ "tokenization_arcade100k.Arcade100kTokenizer",
6
+ null
7
+ ]
8
+ }
9
+ }