CoolFace
Modelpublic

ramixpe/1.8testing

sourceHugging Faceupdated 3y agoView on Hugging Face
0likes7downloads
tokenization_qwen.py277 linesDownload Raw Back to root
1# Copyright (c) Alibaba Cloud.2#3# This source code is licensed under the license found in the4# LICENSE file in the root directory of this source tree.5 6"""Tokenization classes for QWen."""7 8import base649import logging10import os11import unicodedata12from typing import Collection, Dict, List, Set, Tuple, Union13 14import tiktoken15from transformers import PreTrainedTokenizer, AddedToken16 17logger = logging.getLogger(__name__)18 19 20VOCAB_FILES_NAMES = {"vocab_file": "qwen.tiktoken"}21 22PAT_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+"""23ENDOFTEXT = "<|endoftext|>"24IMSTART = "<|im_start|>"25IMEND = "<|im_end|>"26# as the default behavior is changed to allow special tokens in27# regular texts, the surface forms of special tokens need to be28# as different as possible to minimize the impact29EXTRAS = tuple((f"<|extra_{i}|>" for i in range(205)))30# changed to use actual index to avoid misconfiguration with vocabulary expansion31SPECIAL_START_ID = 15164332SPECIAL_TOKENS = tuple(33    enumerate(34        (35            (36                ENDOFTEXT,37                IMSTART,38                IMEND,39            )40            + EXTRAS41        ),42        start=SPECIAL_START_ID,43    )44)45SPECIAL_TOKENS_SET = set(t for i, t in SPECIAL_TOKENS)46 47 48def _load_tiktoken_bpe(tiktoken_bpe_file: str) -> Dict[bytes, int]:49    with open(tiktoken_bpe_file, "rb") as f:50        contents = f.read()51    return {52        base64.b64decode(token): int(rank)53        for token, rank in (line.split() for line in contents.splitlines() if line)54    }55 56 57class QWenTokenizer(PreTrainedTokenizer):58    """QWen tokenizer."""59 60    vocab_files_names = VOCAB_FILES_NAMES61 62    def __init__(63        self,64        vocab_file,65        errors="replace",66        extra_vocab_file=None,67        **kwargs,68    ):69        super().__init__(**kwargs)70 71        # how to handle errors in decoding UTF-8 byte sequences72        # use ignore if you are in streaming inference73        self.errors = errors  74 75        self.mergeable_ranks = _load_tiktoken_bpe(vocab_file)  # type: Dict[bytes, int]76        self.special_tokens = {77            token: index78            for index, token in SPECIAL_TOKENS79        }80 81        # try load extra vocab from file82        if extra_vocab_file is not None:83            used_ids = set(self.mergeable_ranks.values()) | set(self.special_tokens.values())84            extra_mergeable_ranks = _load_tiktoken_bpe(extra_vocab_file)85            for token, index in extra_mergeable_ranks.items():86                if token in self.mergeable_ranks:87                    logger.info(f"extra token {token} exists, skipping")88                    continue89                if index in used_ids:90                    logger.info(f'the index {index} for extra token {token} exists, skipping')91                    continue92                self.mergeable_ranks[token] = index93            # the index may be sparse after this, but don't worry tiktoken.Encoding will handle this94 95        enc = tiktoken.Encoding(96            "Qwen",97            pat_str=PAT_STR,98            mergeable_ranks=self.mergeable_ranks,99            special_tokens=self.special_tokens,100        )101        assert (102            len(self.mergeable_ranks) + len(self.special_tokens) == enc.n_vocab103        ), f"{len(self.mergeable_ranks) + len(self.special_tokens)} != {enc.n_vocab} in encoding"104 105        self.decoder = {106            v: k for k, v in self.mergeable_ranks.items()107        }  # type: dict[int, bytes|str]108        self.decoder.update({v: k for k, v in self.special_tokens.items()})109 110        self.tokenizer = enc  # type: tiktoken.Encoding111 112        self.eod_id = self.tokenizer.eot_token113        self.im_start_id = self.special_tokens[IMSTART]114        self.im_end_id = self.special_tokens[IMEND]115 116    def __getstate__(self):117        # for pickle lovers118        state = self.__dict__.copy()119        del state["tokenizer"]120        return state121 122    def __setstate__(self, state):123        # tokenizer is not python native; don't pass it; rebuild it124        self.__dict__.update(state)125        enc = tiktoken.Encoding(126            "Qwen",127            pat_str=PAT_STR,128            mergeable_ranks=self.mergeable_ranks,129            special_tokens=self.special_tokens,130        )131        self.tokenizer = enc132 133    def __len__(self) -> int:134        return self.tokenizer.n_vocab135 136    def get_vocab(self) -> Dict[bytes, int]:137        return self.mergeable_ranks138 139    def convert_tokens_to_ids(140        self, tokens: Union[bytes, str, List[Union[bytes, str]]]141    ) -> List[int]:142        ids = []143        if isinstance(tokens, (str, bytes)):144            if tokens in self.special_tokens:145                return self.special_tokens[tokens]146            else:147                return self.mergeable_ranks.get(tokens)148        for token in tokens:149            if token in self.special_tokens:150                ids.append(self.special_tokens[token])151            else:152                ids.append(self.mergeable_ranks.get(token))153        return ids154 155    def _add_tokens(156        self,157        new_tokens: Union[List[str], List[AddedToken]],158        special_tokens: bool = False,159    ) -> int:160        if not special_tokens and new_tokens:161            raise ValueError("Adding regular tokens is not supported")162        for token in new_tokens:163            surface_form = token.content if isinstance(token, AddedToken) else token164            if surface_form not in SPECIAL_TOKENS_SET:165                raise ValueError("Adding unknown special tokens is not supported")166        return 0167 168    def save_vocabulary(self, save_directory: str, **kwargs) -> Tuple[str]:169        """170        Save only the vocabulary of the tokenizer (vocabulary).171 172        Returns:173            `Tuple(str)`: Paths to the files saved.174        """175        file_path = os.path.join(save_directory, "qwen.tiktoken")176        with open(file_path, "w", encoding="utf8") as w:177            for k, v in self.mergeable_ranks.items():178                line = base64.b64encode(k).decode("utf8") + " " + str(v) + "\n"179                w.write(line)180        return (file_path,)181 182    def tokenize(183        self,184        text: str,185        allowed_special: Union[Set, str] = "all",186        disallowed_special: Union[Collection, str] = (),187        **kwargs,188    ) -> List[Union[bytes, str]]:189        """190        Converts a string in a sequence of tokens.191 192        Args:193            text (`str`):194                The sequence to be encoded.195            allowed_special (`Literal["all"]` or `set`):196                The surface forms of the tokens to be encoded as special tokens in regular texts.197                Default to "all".198            disallowed_special (`Literal["all"]` or `Collection`):199                The surface forms of the tokens that should not be in regular texts and trigger errors.200                Default to an empty tuple.201 202            kwargs (additional keyword arguments, *optional*):203                Will be passed to the underlying model specific encode method.204 205        Returns:206            `List[bytes|str]`: The list of tokens.207        """208        tokens = []209        text = unicodedata.normalize("NFC", text)210 211        # this implementation takes a detour: text -> token id -> token surface forms212        for t in self.tokenizer.encode(213            text, allowed_special=allowed_special, disallowed_special=disallowed_special214        ):215            tokens.append(self.decoder[t])216        return tokens217 218    def convert_tokens_to_string(self, tokens: List[Union[bytes, str]]) -> str:219        """220        Converts a sequence of tokens in a single string.221        """222        text = ""223        temp = b""224        for t in tokens:225            if isinstance(t, str):226                if temp:227                    text += temp.decode("utf-8", errors=self.errors)228                    temp = b""229                text += t230            elif isinstance(t, bytes):231                temp += t232            else:233                raise TypeError("token should only be of type types or str")234        if temp:235            text += temp.decode("utf-8", errors=self.errors)236        return text237 238    @property239    def vocab_size(self):240        return self.tokenizer.n_vocab241 242    def _convert_id_to_token(self, index: int) -> Union[bytes, str]:243        """Converts an id to a token, special tokens included"""244        if index in self.decoder:245            return self.decoder[index]246        raise ValueError("unknown ids")247 248    def _convert_token_to_id(self, token: Union[bytes, str]) -> int:249        """Converts a token to an id using the vocab, special tokens included"""250        if token in self.special_tokens:251            return self.special_tokens[token]252        if token in self.mergeable_ranks:253            return self.mergeable_ranks[token]254        raise ValueError("unknown token")255 256    def _tokenize(self, text: str, **kwargs):257        """258        Converts a string in a sequence of tokens (string), using the tokenizer. Split in words for word-based259        vocabulary or sub-words for sub-word-based vocabularies (BPE/SentencePieces/WordPieces).260 261        Do NOT take care of added tokens.262        """263        raise NotImplementedError264 265    def _decode(266        self,267        token_ids: Union[int, List[int]],268        skip_special_tokens: bool = False,269        errors: str = None,270        **kwargs,271    ) -> str:272        if isinstance(token_ids, int):273            token_ids = [token_ids]274        if skip_special_tokens:275            token_ids = [i for i in token_ids if i < self.eod_id]276        return self.tokenizer.decode(token_ids, errors=errors or self.errors)277