wangzhengtao commited on
Commit
fce056b
·
1 Parent(s): 100231d

remove slow tokenizer

Browse files
Files changed (1) hide show
  1. tokenization_kimi.py +0 -353
tokenization_kimi.py DELETED
@@ -1,353 +0,0 @@
1
- import os
2
- from collections import OrderedDict
3
- from logging import getLogger
4
- from pathlib import Path
5
- from shutil import copyfile
6
- from typing import Any, Dict, Iterator, List, Optional, Tuple, Union, cast
7
-
8
- import tiktoken
9
- from tiktoken.load import load_tiktoken_bpe
10
- from tokenizers import AddedToken
11
- from transformers.convert_slow_tokenizer import bytes_to_unicode
12
- from transformers.tokenization_utils import PreTrainedTokenizer
13
-
14
- from .tool_declaration_ts import encode_tools_to_typescript_style
15
-
16
- logger = getLogger(__name__)
17
- VOCAB_FILES_NAMES = {"vocab_file": "tiktoken.model"}
18
-
19
-
20
- class TikTokenTokenizer(PreTrainedTokenizer):
21
- """
22
- Tokenizing and encoding/decoding text using the Tiktoken tokenizer. See megatron/tokenizer/tiktoken_tokenizer.py.
23
-
24
- This tokenizer inherits from [`PreTrainedTokenizer`] which contains most of the main methods. Users should refer to
25
- this superclass for more information regarding those methods.
26
-
27
- Args:
28
- vocab_file (`str`):
29
- The path to the Tiktoken model file.
30
- bos_token (`str` or `tokenizers.AddedToken`, *optional*, defaults to `"<|begin_of_text|>",`):
31
- The beginning of sequence token that was used during pretraining. Can be used a sequence classifier token.
32
- eos_token (`str` or `tokenizers.AddedToken`, *optional*, defaults to `"<|end_of_text|>"`):
33
- The end of sequence token.
34
- unk_token (`str` or `tokenizers.AddedToken`, *optional*, defaults to `"<|reserved_special_token_249|>"`):
35
- The unknown token. A token that is not in the vocabulary cannot be converted to an ID and is set to be this
36
- token instead. The second to last item in special_tokens.
37
- pad_token (`str` or `tokenizers.AddedToken`, *optional*, defaults to `"<|reserved_special_token_250|>"`):
38
- The token used for padding, for example when batching sequences of different lengths.
39
- additional_special_tokens (list of `str`, *optional*):
40
- A tuple or a list of additional tokens, which will be marked as `special`, meaning that they will be
41
- skipped when decoding if `skip_special_tokens` is set to `True`.
42
- """
43
-
44
- vocab_files_names = VOCAB_FILES_NAMES
45
-
46
- model_input_names = ["input_ids", "attention_mask"]
47
-
48
- special_tokens: Dict[str, int]
49
-
50
- num_reserved_special_tokens = 256
51
-
52
- pat_str = "|".join([
53
- r"""[\p{Han}]+""",
54
- r"""[^\r\n\p{L}\p{N}]?[\p{Lu}\p{Lt}\p{Lm}\p{Lo}\p{M}&&[^\p{Han}]]*[\p{Ll}\p{Lm}\p{Lo}\p{M}&&[^\p{Han}]]+(?i:'s|'t|'re|'ve|'m|'ll|'d)?""",
55
- r"""[^\r\n\p{L}\p{N}]?[\p{Lu}\p{Lt}\p{Lm}\p{Lo}\p{M}&&[^\p{Han}]]+[\p{Ll}\p{Lm}\p{Lo}\p{M}&&[^\p{Han}]]*(?i:'s|'t|'re|'ve|'m|'ll|'d)?""",
56
- r"""\p{N}{1,3}""",
57
- r""" ?[^\s\p{L}\p{N}]+[\r\n]*""",
58
- r"""\s*[\r\n]+""",
59
- r"""\s+(?!\S)""",
60
- r"""\s+""",
61
- ])
62
-
63
- def __init__(
64
- self,
65
- vocab_file,
66
- bos_token: Union[str, AddedToken] = "[BOS]",
67
- eos_token: Union[str, AddedToken] = "[EOS]",
68
- unk_token: Union[str, AddedToken, None] = None,
69
- pad_token: Union[str, AddedToken, None] = None,
70
- additional_special_tokens: List[str] = None,
71
- added_tokens_decoder: Optional[dict] = None,
72
- **kwargs,
73
- ):
74
- assert os.path.isfile(vocab_file), vocab_file
75
-
76
- if additional_special_tokens is None:
77
- additional_special_tokens = [
78
- "<|im_end|>",
79
- "<|im_user|>",
80
- "<|im_assistant|>",
81
- "<|start_header_id|>",
82
- "<|end_header_id|>",
83
- "[EOT]",
84
- "<|im_system|>",
85
- "<|im_middle|>",
86
- ]
87
-
88
- if added_tokens_decoder:
89
- special_tokens_mapping = {
90
- i: added_tokens_decoder[i].content
91
- for i in added_tokens_decoder
92
- }
93
- else:
94
- special_tokens_mapping = {}
95
-
96
- self.vocab_file = vocab_file
97
- mergeable_ranks = load_tiktoken_bpe(vocab_file)
98
- num_base_tokens = len(mergeable_ranks)
99
- self.special_tokens = {
100
- special_tokens_mapping.get(i, f"<|reserved_token_{i}|>"): i
101
- for i in range(num_base_tokens, num_base_tokens +
102
- self.num_reserved_special_tokens)
103
- }
104
-
105
- self.model = tiktoken.Encoding(
106
- name=Path(vocab_file).name,
107
- pat_str=self.pat_str,
108
- mergeable_ranks=mergeable_ranks,
109
- special_tokens=self.special_tokens,
110
- )
111
- logger.info(f"Reloaded tiktoken model from {vocab_file}")
112
-
113
- self.n_words: int = self.model.n_vocab
114
- # BOS / EOS token IDs
115
- self.bos_id: int = self.special_tokens[str(bos_token)]
116
- self.eos_id: int = self.special_tokens[str(eos_token)]
117
- logger.info(
118
- f"#words: {self.n_words} - BOS ID: {self.bos_id} - EOS ID: {self.eos_id}"
119
- )
120
-
121
- self.pad_id: int = self.special_tokens[str(pad_token)]
122
- self.unk_id: int = self.special_tokens[str(unk_token)]
123
-
124
- self.byte_encoder = bytes_to_unicode()
125
- self.byte_decoder = {v: k for k, v in self.byte_encoder.items()}
126
-
127
- self.decoder = {}
128
- for i in range(self.n_words):
129
- # Taken from https://gist.github.com/xenova/a452a6474428de0182b17605a98631ee
130
- decoding = ''.join([
131
- self.byte_encoder[ord(char)] for char in
132
- self.model.decode_single_token_bytes(i).decode('latin-1')
133
- ])
134
- self.decoder[i] = decoding
135
-
136
- self.encoder = {}
137
- for i in range(self.n_words):
138
- if i in self.decoder:
139
- self.encoder[self.decoder[i]] = i
140
-
141
- self._token_config_cache = OrderedDict()
142
- self._cache_max_size = 128
143
-
144
- super().__init__(
145
- bos_token=bos_token,
146
- eos_token=eos_token,
147
- unk_token=unk_token,
148
- pad_token=pad_token,
149
- additional_special_tokens=additional_special_tokens,
150
- added_tokens_decoder=added_tokens_decoder,
151
- **kwargs,
152
- )
153
- self.all_special_ids_set = set(self.all_special_ids)
154
-
155
- def encode(self,
156
- text: str,
157
- allow_special_tokens: bool = True,
158
- **kwargs) -> List[int]:
159
- """
160
- Encodes a string into a list of token IDs.
161
-
162
- Args:
163
- text (str): The input string to be encoded.
164
-
165
- Returns:
166
- list[int]: A list of token IDs.
167
- """
168
- # If there are other args, we should call super().encode because there are a lot of code
169
- # to handle those args. supper().encode finally will call _tokenize and _convert_token_to_id.
170
- # NOTE: our encode method is not compatible with the super().encode method,
171
- # e.g. split_special_tokens' default is True in our encode method.
172
- if len(kwargs) > 0:
173
- logger.warning(f"Calling super().encode with {kwargs}")
174
- return super().encode(text, **kwargs)
175
-
176
- assert type(text) is str
177
-
178
- # The tiktoken tokenizer can handle <=400k chars without
179
- # pyo3_runtime.PanicException.
180
- TIKTOKEN_MAX_ENCODE_CHARS = 400_000
181
-
182
- # https://github.com/openai/tiktoken/issues/195
183
- # Here we iterate over subsequences and split if we exceed the limit
184
- # of max consecutive non-whitespace or whitespace characters.
185
- MAX_NO_WHITESPACES_CHARS = 25_000
186
-
187
- texts = self.pre_tokenizer_process(text)
188
-
189
- all_substrs = []
190
- for text in texts:
191
- substrs = (
192
- substr for i in range(0, len(text), TIKTOKEN_MAX_ENCODE_CHARS)
193
- for substr in self._split_whitespaces_or_nonwhitespaces(
194
- text[i:i +
195
- TIKTOKEN_MAX_ENCODE_CHARS], MAX_NO_WHITESPACES_CHARS))
196
- all_substrs.extend(substrs)
197
-
198
- t: List[int] = []
199
- for substr in all_substrs:
200
- if allow_special_tokens:
201
- t.extend(
202
- # we should consider special token as a common token
203
- self.model.encode(
204
- substr,
205
- allowed_special="all",
206
- ))
207
- else:
208
- t.extend(
209
- # we should consider special token as a common token
210
- self.model.encode(
211
- substr,
212
- disallowed_special=(),
213
- ))
214
-
215
- return t
216
-
217
- def decode(self, token_ids: Union[int, List[int]], **kwargs) -> str:
218
- """
219
- Decodes a list of token IDs into a string.
220
-
221
- Args:
222
- token_ids (List[int]): The list of token IDs to be decoded.
223
-
224
- Returns:
225
- str: The decoded string.
226
- """
227
- # If there are other args, we should call super().decode because there are a lot of code
228
- # to handle those args. supper().encode finally will call convert_tokens_to_string and _convert_id_to_token.
229
- if len(kwargs) > 0:
230
- return super().decode(token_ids, **kwargs)
231
-
232
- if type(token_ids) is int:
233
- token_ids = [token_ids]
234
-
235
- return self.model.decode(cast(List[int], token_ids))
236
-
237
- @staticmethod
238
- def _split_whitespaces_or_nonwhitespaces(
239
- s: str, max_consecutive_slice_len: int) -> Iterator[str]:
240
- """
241
- Splits the string `s` so that each substring contains no more than `max_consecutive_slice_len`
242
- consecutive whitespaces or consecutive non-whitespaces.
243
- """
244
- current_slice_len = 0
245
- current_slice_is_space = s[0].isspace() if len(s) > 0 else False
246
- slice_start = 0
247
-
248
- for i in range(len(s)):
249
- is_now_space = s[i].isspace()
250
-
251
- if current_slice_is_space ^ is_now_space:
252
- current_slice_len = 1
253
- current_slice_is_space = is_now_space
254
- else:
255
- current_slice_len += 1
256
- if current_slice_len > max_consecutive_slice_len:
257
- yield s[slice_start:i]
258
- slice_start = i
259
- current_slice_len = 1
260
- yield s[slice_start:]
261
-
262
- def pre_tokenizer_process(self, text: str) -> List[str]:
263
- """
264
- pre-tokenizes the input text into a list of tokens.
265
- This method is used to split the input text into smaller chunks for internal processing.
266
- """
267
- return [text]
268
-
269
- """ ----- Below are the abstract methods required by PreTrainedTokenizer ----- """
270
-
271
- @property
272
- def vocab_size(self) -> int:
273
- return self.n_words
274
-
275
- def get_vocab(self) -> Dict[str, int]:
276
- return self.encoder
277
-
278
- def _tokenize(self, text: str, **kwargs) -> List[str]:
279
- return [self.decoder[t] for t in self.encode(text)]
280
-
281
- def _convert_token_to_id(self, token: str) -> int:
282
- return self.encoder.get(token, self.unk_id)
283
-
284
- def _convert_id_to_token(self, index: int) -> str:
285
- return self.decoder.get(index)
286
-
287
- @staticmethod
288
- def clean_up_tokenization(out_string: str) -> str:
289
- return out_string
290
-
291
- def convert_tokens_to_string(self, tokens: List[str]) -> str:
292
- text = ''.join(tokens)
293
- text = bytearray([self.byte_decoder[c]
294
- for c in text]).decode('utf-8', 'replace')
295
- return text
296
-
297
- def save_vocabulary(self,
298
- save_directory: str,
299
- filename_prefix: Optional[str] = None) -> Tuple[str]:
300
- if not os.path.isdir(save_directory):
301
- raise ValueError(
302
- f"vocabulary path ({save_directory}) should be a directory")
303
- out_vocab_file = os.path.join(
304
- save_directory,
305
- (filename_prefix + "-" if filename_prefix else "") +
306
- VOCAB_FILES_NAMES["vocab_file"])
307
-
308
- if os.path.abspath(self.vocab_file) != os.path.abspath(
309
- out_vocab_file) and os.path.isfile(self.vocab_file):
310
- copyfile(self.vocab_file, out_vocab_file)
311
-
312
- return (out_vocab_file, )
313
-
314
- def apply_chat_template(self,
315
- conversation,
316
- tools: Optional[list[dict]] = None,
317
- tokenize: bool = False,
318
- add_generation_prompt: bool = True,
319
- thinking: bool = True,
320
- preserve_thinking: bool = False,
321
- **kwargs):
322
-
323
- tools = deep_sort_dict(tools)
324
-
325
- # Convert tools to TypeScript style string if tools are provided
326
- tools_ts_str = None
327
- if tools:
328
- try:
329
- tools_ts_str = encode_tools_to_typescript_style(tools)
330
-
331
- except Exception as e:
332
- print(f"Failed to convert tools to TypeScript style: {e}")
333
- tools_ts_str = None
334
-
335
- # Store the TypeScript string in kwargs so it can be accessed by the template
336
- if tools_ts_str is not None:
337
- kwargs['tools_ts_str'] = tools_ts_str
338
- return super().apply_chat_template(
339
- conversation,
340
- tools=tools,
341
- tokenize=tokenize,
342
- add_generation_prompt=add_generation_prompt,
343
- thinking=thinking,
344
- preserve_thinking=preserve_thinking,
345
- **kwargs)
346
-
347
-
348
- def deep_sort_dict(obj: Any) -> Any:
349
- if isinstance(obj, dict):
350
- return {k: deep_sort_dict(v) for k, v in sorted(obj.items())}
351
- if isinstance(obj, list):
352
- return [deep_sort_dict(item) for item in obj]
353
- return obj