CoolFace
Modelpublic

IntMeGroup/ICCVW_st2_mos2

sourceHugging Faceapache-2.0updated 1y agoView on Hugging Face
0likes3downloads
tokenization_internlm3.py295 linesDownload Raw Back to root
1import os2from shutil import copyfile3from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple4 5import sentencepiece as spm6from transformers.tokenization_utils import AddedToken, PreTrainedTokenizer7from transformers.utils import logging8 9if TYPE_CHECKING:10    from transformers.tokenization_utils_base import TextInput11 12logger = logging.get_logger(__name__)13 14VOCAB_FILES_NAMES = {"vocab_file": "tokenizer.model"}15 16SPIECE_UNDERLINE = "โ–"17 18 19class InternLM3Tokenizer(PreTrainedTokenizer):20    """21    Construct a InternLM3 tokenizer. Based on byte-level Byte-Pair-Encoding. The default padding token is unset as there is22    no padding token in the original model.23 24    Args:25        vocab_file (`str`):26            Path to the vocabulary file.27        unk_token (`str` or `tokenizers.AddedToken`, *optional*, defaults to `"<unk>"`):28            The unknown token. A token that is not in the vocabulary cannot be converted to an ID and is set to be this29            token instead.30        bos_token (`str` or `tokenizers.AddedToken`, *optional*, defaults to `"<s>"`):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 `"</s>"`):33            The end of sequence token.34        pad_token (`str` or `tokenizers.AddedToken`, *optional*):35            A special token used to make arrays of tokens the same size for batching purpose. Will then be ignored by36            attention mechanisms or loss computation.37        sp_model_kwargs (`Dict[str, Any]`, `Optional`, *optional*):38            Will be passed to the `SentencePieceProcessor.__init__()` method. The [Python wrapper for39            SentencePiece](https://github.com/google/sentencepiece/tree/master/python) can be used, among other things,40            to set:41 42            - `enable_sampling`: Enable subword regularization.43            - `nbest_size`: Sampling parameters for unigram. Invalid for BPE-Dropout.44 45              - `nbest_size = {0,1}`: No sampling is performed.46              - `nbest_size > 1`: samples from the nbest_size results.47              - `nbest_size < 0`: assuming that nbest_size is infinite and samples from the all hypothesis (lattice)48                using forward-filtering-and-backward-sampling algorithm.49 50            - `alpha`: Smoothing parameter for unigram sampling, and dropout probability of merge operations for51              BPE-dropout.52 53        add_bos_token (`bool`, *optional*, defaults to `True`):54            Whether or not to add an `bos_token` at the start of sequences.55        add_eos_token (`bool`, *optional*, defaults to `False`):56            Whether or not to add an `eos_token` at the end of sequences.57        clean_up_tokenization_spaces (`bool`, *optional*, defaults to `False`):58            Whether or not to cleanup spaces after decoding, cleanup consists in removing potential artifacts like59            extra spaces.60        use_default_system_prompt (`bool`, *optional*, defaults to `False`):61            Whether or not the default system prompt for InternLM3 should be used.62        spaces_between_special_tokens (`bool`, *optional*, defaults to `False`):63            Whether or not to add spaces between special tokens.64        spaces_for_interleaved_special_tokens (`bool`, *optional*, defaults to `False`):65           Whether or not to add spaces between special tokens that are interleaved with normal tokens.66        add_prefix_space (`bool`, *optional*, defaults to `True`):67            Whether or not to add an initial space to the input. This allows to treat the leading word just as any68            other word. Again, this should be set with `from_slow=True` to make sure it's taken into account.69    """70 71    vocab_files_names = VOCAB_FILES_NAMES72    model_input_names = ["input_ids", "attention_mask"]73 74    def __init__(75        self,76        vocab_file,77        unk_token="<unk>",78        bos_token="<s>",79        eos_token="</s>",80        pad_token=None,81        sp_model_kwargs: Optional[Dict[str, Any]] = None,82        add_bos_token=True,83        add_eos_token=False,84        clean_up_tokenization_spaces=False,85        use_default_system_prompt=False,86        spaces_between_special_tokens=False,87        spaces_for_interleaved_special_tokens=False,88        add_prefix_space=True,89        **kwargs,90    ):91        self.sp_model_kwargs = {} if sp_model_kwargs is None else sp_model_kwargs92        bos_token = AddedToken(bos_token, normalized=False, special=True) if isinstance(bos_token, str) else bos_token93        eos_token = AddedToken(eos_token, normalized=False, special=True) if isinstance(eos_token, str) else eos_token94        unk_token = AddedToken(unk_token, normalized=False, special=True) if isinstance(unk_token, str) else unk_token95        pad_token = AddedToken(pad_token, normalized=False, special=True) if isinstance(pad_token, str) else pad_token96 97        self.vocab_file = vocab_file98        self.add_bos_token = add_bos_token99        self.add_eos_token = add_eos_token100        self.use_default_system_prompt = use_default_system_prompt101        self.sp_model = spm.SentencePieceProcessor(**self.sp_model_kwargs)102        self.sp_model.Load(vocab_file)103        self.add_prefix_space = add_prefix_space104        self.spaces_for_interleaved_special_tokens = spaces_for_interleaved_special_tokens105 106        vocab_size = self.sp_model.get_piece_size()107        self.decoder = {i: self.sp_model.id_to_piece(i) for i in range(vocab_size)}108 109        super().__init__(110            bos_token=bos_token,111            eos_token=eos_token,112            unk_token=unk_token,113            pad_token=pad_token,114            add_bos_token=add_bos_token,115            add_eos_token=add_eos_token,116            sp_model_kwargs=sp_model_kwargs,117            clean_up_tokenization_spaces=clean_up_tokenization_spaces,118            use_default_system_prompt=use_default_system_prompt,119            spaces_between_special_tokens=spaces_between_special_tokens,120            add_prefix_space=add_prefix_space,121            **kwargs,122        )123 124    def __getstate__(self):125        state = self.__dict__.copy()126        state["sp_model"] = None127        state["sp_model_proto"] = self.sp_model.serialized_model_proto()128        return state129 130    def __setstate__(self, d):131        self.__dict__.update(d)132        self.sp_model = spm.SentencePieceProcessor(**self.sp_model_kwargs)133        self.sp_model.LoadFromSerializedProto(self.sp_model_proto)134 135    @property136    def vocab_size(self):137        """Returns vocab size"""138        return self.sp_model.get_piece_size()139 140    def get_vocab(self):141        """Returns vocab as a dict"""142        vocab = {self.convert_ids_to_tokens(i): i for i in range(self.vocab_size)}143        vocab.update(self.added_tokens_encoder)144        return vocab145 146    def tokenize(self, text: "TextInput", **kwargs) -> List[str]:147        """148        Args:149            text: TextInput150        Simply calls PreTrainedTokenizer's method151        """152        return super().tokenize(text, **kwargs)153 154    def _tokenize(self, text, **kwargs):155        """156        Args:157            text: TextInput158        Returns a tokenized string. The Gemma tokenizer never adds a prefix space.159        """160        return self.sp_model.encode(text, out_type=str)161 162    def _convert_token_to_id(self, token):163        """Converts a token (str) in an id using the vocab."""164        return self.sp_model.piece_to_id(token)165 166    def _convert_id_to_token(self, index):167        """Converts an index (integer) in a token (str) using the vocab."""168        return self.decoder.get(index, "")169 170    def convert_tokens_to_string(self, tokens):171        """Converts a sequence of tokens (string) in a single string."""172        # since we manually add the prefix space, we have to remove it when decoding173        if tokens[0].startswith(SPIECE_UNDERLINE) and self.add_prefix_space:174            tokens[0] = tokens[0][1:]175 176        current_sub_tokens = []177        out_string = ""178        prev_is_special = False179        for i, token in enumerate(tokens):180            # make sure that special tokens are not decoded using sentencepiece model181            if token in self.all_special_tokens:182                if not prev_is_special and i != 0 and self.spaces_for_interleaved_special_tokens:183                    out_string += " "184                out_string += self.sp_model.decode(current_sub_tokens) + token185                prev_is_special = True186                current_sub_tokens = []187            else:188                if (189                    prev_is_special190                    and i == 1191                    and self.add_prefix_space192                    and not token.startswith(SPIECE_UNDERLINE)193                    and self.spaces_for_interleaved_special_tokens194                ):195                    out_string += " "196                current_sub_tokens.append(token)197                prev_is_special = False198        out_string += self.sp_model.decode(current_sub_tokens)199        return out_string200 201    def save_vocabulary(self, save_directory, filename_prefix: Optional[str] = None) -> Tuple[str]:202        """203        Save the vocabulary and special tokens file to a directory.204 205        Args:206            save_directory (`str`):207                The directory in which to save the vocabulary.208 209        Returns:210            `Tuple(str)`: Paths to the files saved.211        """212        if not os.path.isdir(save_directory):213            logger.error(f"Vocabulary path ({save_directory}) should be a directory")214            return215        out_vocab_file = os.path.join(save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"])216 217        if os.path.abspath(self.vocab_file) != os.path.abspath(out_vocab_file) and os.path.isfile(self.vocab_file):218            copyfile(self.vocab_file, out_vocab_file)219        elif not os.path.isfile(self.vocab_file):220            with open(out_vocab_file, "wb") as fi:221                content_spiece_model = self.sp_model.serialized_model_proto()222                fi.write(content_spiece_model)223 224        return (out_vocab_file,)225 226    def build_inputs_with_special_tokens(self, token_ids_0, token_ids_1=None):227        bos_token_id = [self.bos_token_id] if self.add_bos_token else []228        eos_token_id = [self.eos_token_id] if self.add_eos_token else []229 230        output = bos_token_id + token_ids_0 + eos_token_id231 232        if token_ids_1 is not None:233            output = output + bos_token_id + token_ids_1 + eos_token_id234 235        return output236 237    def get_special_tokens_mask(238        self, token_ids_0: List[int], token_ids_1: Optional[List[int]] = None, already_has_special_tokens: bool = False239    ) -> List[int]:240        """241        Retrieve sequence ids from a token list that has no special tokens added. This method is called when adding242        special tokens using the tokenizer `prepare_for_model` method.243 244        Args:245            token_ids_0 (`List[int]`):246                List of IDs.247            token_ids_1 (`List[int]`, *optional*):248                Optional second list of IDs for sequence pairs.249            already_has_special_tokens (`bool`, *optional*, defaults to `False`):250                Whether or not the token list is already formatted with special tokens for the model.251 252        Returns:253            `List[int]`: A list of integers in the range [0, 1]: 1 for a special token, 0 for a sequence token.254        """255        if already_has_special_tokens:256            return super().get_special_tokens_mask(token_ids_0=token_ids_0, token_ids_1=token_ids_1, already_has_special_tokens=True)257 258        bos_token_id = [1] if self.add_bos_token else []259        eos_token_id = [1] if self.add_eos_token else []260 261        if token_ids_1 is None:262            return bos_token_id + ([0] * len(token_ids_0)) + eos_token_id263        return bos_token_id + ([0] * len(token_ids_0)) + eos_token_id + bos_token_id + ([0] * len(token_ids_1)) + eos_token_id264 265    def create_token_type_ids_from_sequences(self, token_ids_0: List[int], token_ids_1: Optional[List[int]] = None) -> List[int]:266        """267        Creates a mask from the two sequences passed to be used in a sequence-pair classification task. An ALBERT268        sequence pair mask has the following format:269 270        ```271        0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1272        | first sequence    | second sequence |273        ```274 275        if token_ids_1 is None, only returns the first portion of the mask (0s).276 277        Args:278            token_ids_0 (`List[int]`):279                List of ids.280            token_ids_1 (`List[int]`, *optional*):281                Optional second list of IDs for sequence pairs.282 283        Returns:284            `List[int]`: List of [token type IDs](../glossary#token-type-ids) according to the given sequence(s).285        """286        bos_token_id = [self.bos_token_id] if self.add_bos_token else []287        eos_token_id = [self.eos_token_id] if self.add_eos_token else []288 289        output = [0] * len(bos_token_id + token_ids_0 + eos_token_id)290 291        if token_ids_1 is not None:292            output += [1] * len(bos_token_id + token_ids_1 + eos_token_id)293 294        return output295