import tiktoken from typing import List class TiktokenTokenizer: def __init__(self, tiktoken_model: str, tokenizer_pad_to_multiple: int = 8, bos="", pad="", eos="", unk="", ): self.symbols = [bos, pad, eos, unk] self.indices = {s: i for i, s in enumerate(self.symbols)} self.tokenizer_pad_to_multiple = tokenizer_pad_to_multiple cl100k_base = tiktoken.get_encoding(tiktoken_model) self._model = tiktoken.Encoding( # If you're changing the set of special tokens, make sure to use a different name # It should be clear from the name what behaviour to expect. name="cl100k_im", pat_str=cl100k_base._pat_str, mergeable_ranks=cl100k_base._mergeable_ranks, special_tokens={ **cl100k_base._special_tokens, "": 100264, "": 100265, "": 100266, "": 100267, "": 100268, "": 100269, "": 100270, "": 100271, "": 100272, "": 100273, "": 100274, "": 100275, "": 100276, "": 100277, "": 100278, "": 100279, "": 100280, "": 100281, } ) @property def n_words(self) -> int: n_words = self._model.n_vocab + len(self.symbols) n_words = (n_words + self.tokenizer_pad_to_multiple - 1) // self.tokenizer_pad_to_multiple * self.tokenizer_pad_to_multiple return n_words @property def bos_id(self) -> int: return self.indices[""] @property def eos_id(self) -> int: return self.indices[""] @property def pad_id(self) -> int: return self.indices[""] @property def unk_id(self) -> int: return self.indices[""] def encode(self, s: str, bos: bool = False, eos: bool = False) -> List[int]: assert isinstance(s, str) t = self._model.encode(s, allowed_special="all") t = [i + len(self.symbols) for i in t] if bos: t = [self.bos_id, *t] if eos: t = [*t, self.eos_id] return t def decode(self, t: List[int]) -> str: t = [i - len(self.symbols) for i in t if i >= len(self.symbols)] return self._model.decode(t)