CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
tokenization_code_llama_fast.py375 linesDownload Raw Back to code_llama
1# coding=utf-82# Copyright 2023 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 at7#8#     http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing, software11# 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 and14# limitations under the License.15import os16from shutil import copyfile17from typing import Optional18 19from tokenizers import normalizers, processors20 21from ...tokenization_utils_fast import PreTrainedTokenizerFast22from ...utils import is_sentencepiece_available, logging23 24 25if is_sentencepiece_available():26    from .tokenization_code_llama import CodeLlamaTokenizer27else:28    CodeLlamaTokenizer = None29 30logger = logging.get_logger(__name__)31VOCAB_FILES_NAMES = {"vocab_file": "tokenizer.model", "tokenizer_file": "tokenizer.json"}32 33SPIECE_UNDERLINE = "▁"34 35 36B_INST, E_INST = "[INST]", "[/INST]"37B_SYS, E_SYS = "<<SYS>>\n", "\n<</SYS>>\n\n"38 39# fmt: off40DEFAULT_SYSTEM_PROMPT = """You are a helpful, respectful and honest assistant. Always answer as helpfully as possible, while being safe. Your \41answers should not include any harmful, unethical, racist, sexist, toxic, dangerous, or illegal content. Please ensure\42 that your responses are socially unbiased and positive in nature.43 44If a question does not make any sense, or is not factually coherent, explain why instead of answering something not \45correct. If you don't know the answer to a question, please don't share false information."""46# fmt: on47 48 49class CodeLlamaTokenizerFast(PreTrainedTokenizerFast):50    """51    Construct a Llama tokenizer. Based on byte-level Byte-Pair-Encoding.52 53    This uses notably ByteFallback and no normalization.54 55    ```python56    >>> from transformers import CodeLlamaTokenizerFast57 58    >>> tokenizer = CodeLlamaTokenizerFast.from_pretrained("hf-internal-testing/llama-tokenizer")59    >>> tokenizer.encode("Hello this is a test")60    [1, 15043, 445, 338, 263, 1243]61    ```62 63    If you want to change the `bos_token` or the `eos_token`, make sure to specify them when initializing the model, or64    call `tokenizer.update_post_processor()` to make sure that the post-processing is correctly done (otherwise the65    values of the first token and final token of an encoded sequence will not be correct). For more details, checkout66    [post-processors] (https://huggingface.co/docs/tokenizers/api/post-processors) documentation.67 68 69    This tokenizer inherits from [`PreTrainedTokenizerFast`] which contains most of the main methods. Users should70    refer to this superclass for more information regarding those methods. The default configuration match that of71    [meta-llama/CodeLlama-7b-Instruct-hf](https://huggingface.co/meta-llama/CodeLlama-7b-Instruct-hf/blob/main/tokenizer_config.json)72    which supports prompt infilling.73 74    Args:75        vocab_file (`str`, *optional*):76            [SentencePiece](https://github.com/google/sentencepiece) file (generally has a .model extension) that77            contains the vocabulary necessary to instantiate a tokenizer.78        tokenizer_file (`str`, *optional*):79            [tokenizers](https://github.com/huggingface/tokenizers) file (generally has a .json extension) that80            contains everything needed to load the tokenizer.81        clean_up_tokenization_spaces (`str`, *optional*, defaults to `False`):82            Whether to cleanup spaces after decoding, cleanup consists in removing potential artifacts like extra83            spaces.84        unk_token (`str`, *optional*, defaults to `"<unk>"`):85            The unknown token. A token that is not in the vocabulary cannot be converted to an ID and is set to be this86            token instead.87        bos_token (`str`, *optional*, defaults to `"<s>"`):88            The beginning of sequence token that was used during pretraining. Can be used a sequence classifier token.89        eos_token (`str`, *optional*, defaults to `"</s>"`):90            The end of sequence token.91        prefix_token (`str`, *optional*, defaults to `"▁<PRE>"`):92            Prefix token used for infilling.93        middle_token (`str`, *optional*, defaults to `"▁<MID>"`):94            Middle token used for infilling.95        suffix_token (`str`, *optional*, defaults to `"▁<SUF>"`):96            Suffix token used for infilling.97        eot_token (`str`, *optional*, defaults to `"▁<EOT>"`):98            End of text token used for infilling.99        fill_token (`str`, *optional*, defaults to `"<FILL_ME>"`):100            The token used to split the input between the prefix and suffix.101        additional_special_tokens (`list[str]`, *optional*):102            Additional special tokens used by the tokenizer.103        add_bos_token (`bool`, *optional*, defaults to `True`):104            Whether to add a beginning of sequence token at the start of sequences.105        add_eos_token (`bool`, *optional*, defaults to `False`):106            Whether to add an end of sequence token at the end of sequences.107        use_default_system_prompt (`bool`, *optional*, defaults to `False`):108            Whether or not the default system prompt for Llama should be used.109    """110 111    vocab_files_names = VOCAB_FILES_NAMES112    slow_tokenizer_class = CodeLlamaTokenizer113    padding_side = "left"114    model_input_names = ["input_ids", "attention_mask"]115 116    def __init__(117        self,118        vocab_file=None,119        tokenizer_file=None,120        clean_up_tokenization_spaces=False,121        unk_token="<unk>",122        bos_token="<s>",123        eos_token="</s>",124        prefix_token="▁<PRE>",125        middle_token="▁<MID>",126        suffix_token="▁<SUF>",127        eot_token="▁<EOT>",128        fill_token="<FILL_ME>",129        additional_special_tokens=None,130        add_bos_token=True,131        add_eos_token=False,132        use_default_system_prompt=False,133        **kwargs,134    ):135        # mark tokens special to skip them136        additional_special_tokens = additional_special_tokens or []137        for token in [prefix_token, middle_token, suffix_token, eot_token]:138            additional_special_tokens += [token] if token is not None else []139        self.use_default_system_prompt = use_default_system_prompt140 141        super().__init__(142            vocab_file=vocab_file,143            tokenizer_file=tokenizer_file,144            clean_up_tokenization_spaces=clean_up_tokenization_spaces,145            additional_special_tokens=additional_special_tokens,146            unk_token=unk_token,147            bos_token=bos_token,148            eos_token=eos_token,149            add_bos_token=add_bos_token,150            add_eos_token=add_eos_token,151            prefix_token=prefix_token,152            middle_token=middle_token,153            suffix_token=suffix_token,154            eot_token=eot_token,155            fill_token=fill_token,156            use_default_system_prompt=use_default_system_prompt,157            **kwargs,158        )159        self._add_bos_token = add_bos_token160        self._add_eos_token = add_eos_token161        self.update_post_processor()162 163        self.vocab_file = vocab_file164 165        self._prefix_token = prefix_token166        self._middle_token = middle_token167        self._suffix_token = suffix_token168        self._eot_token = eot_token169        self.fill_token = fill_token170 171    # Copied from transformers.models.llama.tokenization_llama_fast.LlamaTokenizerFast.update_post_processor172    def update_post_processor(self):173        """174        Updates the underlying post processor with the current `bos_token` and `eos_token`.175        """176        bos = self.bos_token177        bos_token_id = self.bos_token_id178        if bos is None and self.add_bos_token:179            raise ValueError("add_bos_token = True but bos_token = None")180 181        eos = self.eos_token182        eos_token_id = self.eos_token_id183        if eos is None and self.add_eos_token:184            raise ValueError("add_eos_token = True but eos_token = None")185 186        single = f"{(bos + ':0 ') if self.add_bos_token else ''}$A:0{(' ' + eos + ':0') if self.add_eos_token else ''}"187        pair = f"{single}{(' ' + bos + ':1') if self.add_bos_token else ''} $B:1{(' ' + eos + ':1') if self.add_eos_token else ''}"188 189        special_tokens = []190        if self.add_bos_token:191            special_tokens.append((bos, bos_token_id))192        if self.add_eos_token:193            special_tokens.append((eos, eos_token_id))194        self._tokenizer.post_processor = processors.TemplateProcessing(195            single=single, pair=pair, special_tokens=special_tokens196        )197 198    @property199    def prefix_token(self):200        return self._prefix_token201 202    @property203    def prefix_id(self):204        if self._prefix_token is None:205            return None206        return self.convert_tokens_to_ids(self.prefix_token)207 208    @property209    def middle_token(self):210        return self._middle_token211 212    @property213    def middle_id(self):214        if self._middle_token is None:215            return None216        return self.convert_tokens_to_ids(self.middle_token)217 218    @property219    def suffix_token(self):220        return self._suffix_token221 222    @property223    def suffix_id(self):224        if self._suffix_token is None:225            return None226        return self.convert_tokens_to_ids(self.suffix_token)227 228    @property229    def eot_id(self):230        if self._eot_token is None:231            return None232        return self.convert_tokens_to_ids(self.eot_token)233 234    @property235    def eot_token(self):236        return self._eot_token237 238    @property239    def add_eos_token(self):240        return self._add_eos_token241 242    @property243    def add_bos_token(self):244        return self._add_bos_token245 246    @add_eos_token.setter247    def add_eos_token(self, value):248        self._add_eos_token = value249        self.update_post_processor()250 251    @add_bos_token.setter252    def add_bos_token(self, value):253        self._add_bos_token = value254        self.update_post_processor()255 256    def set_infilling_processor(self, reset, suffix_first=False, add_special_tokens=True):257        """258        Updates the normalizer to make sure the prompt format for `infilling` is respected. The infilling format is the259        following: if suffix_first260            " <PRE> <SUF>{suf} <MID> {pre}"261        else:262            " <PRE> {pre} <SUF>{suf} <MID>"263 264        If `reset` is set to `True`, the `normalizer` and `post_processor` are reset to their "normal" behaviour, which265        is to add a prefix space for the normalizer, and add a `bos_token` to the input text for the `post_processor`.266        """267        if reset:268            self._tokenizer.normalizer = normalizers.Sequence(269                [270                    normalizers.Prepend(prepend="▁"),271                    normalizers.Replace(pattern=" ", content="▁"),272                ]273            )274            self.update_post_processor()275            return276 277        self._tokenizer.normalizer = normalizers.Replace(pattern=" ", content="▁")278        pair = [self.bos_token] if self.add_bos_token and add_special_tokens else []279        special_tokens = [(self.bos_token, self.bos_token_id)] if self.add_bos_token and add_special_tokens else []280        if suffix_first:281            # format as " <PRE> <SUF>{suf} <MID> {pre}"282            pair += [self.prefix_token, self.suffix_token, "$B", self.middle_token, "$A"]283            special_tokens += [284                (self.prefix_token, self.prefix_id),285                (self.suffix_token, self.suffix_id),286                (self.middle_token, self.middle_id),287            ]288        else:289            # format as " <PRE> {pre} <SUF>{suf} <MID>"290            pair += [self.prefix_token, "$A", self.suffix_token, "$B", self.middle_token]291            special_tokens += [292                (self.prefix_token, self.prefix_id),293                (self.suffix_token, self.suffix_id),294                (self.middle_token, self.middle_id),295            ]296 297        if self.add_eos_token and add_special_tokens:298            pair += [self.eos_token]299            special_tokens += [(self.eos_token, self.eos_token_id)]300        self._tokenizer.post_processor = processors.TemplateProcessing(301            single="$A", pair=pair, special_tokens=special_tokens302        )303 304    def encode_plus(self, text, text_pair=None, suffix_first=False, add_special_tokens=True, **kwargs):305        # hack to make sure the input is pre-process but outside rust306        text_pair = kwargs.pop("suffix", text_pair)307        if self.fill_token is not None and self.fill_token in text and text_pair is None:308            text, text_pair = text.split(self.fill_token)309 310        if text_pair is None or len(text_pair) < 1:311            return super().encode_plus(text, text_pair, add_special_tokens=add_special_tokens, **kwargs)312 313        if None in (self.prefix_id, self.middle_id, self.suffix_id):314            raise ValueError(315                "Then input includes a `prefix` and a `suffix` used for the infilling task,"316                " the `prefix_id, middle_id, suffix_id` must all be initialized. Current"317                f" values : {self.prefix_id, self.middle_id, self.suffix_id}"318            )319 320        self.set_infilling_processor(False, suffix_first=suffix_first, add_special_tokens=add_special_tokens)321        tokens = super().encode_plus(" " + text, text_pair=text_pair, add_special_tokens=True, **kwargs)322        self.set_infilling_processor(True)323        return tokens324 325    # Copied from transformers.models.llama.tokenization_llama_fast.LlamaTokenizerFast.save_vocabulary326    def save_vocabulary(self, save_directory: str, filename_prefix: Optional[str] = None) -> tuple[str]:327        if not self.can_save_slow_tokenizer:328            raise ValueError(329                "Your fast tokenizer does not have the necessary information to save the vocabulary for a slow "330                "tokenizer."331            )332 333        if not os.path.isdir(save_directory):334            logger.error(f"Vocabulary path ({save_directory}) should be a directory")335            return336        out_vocab_file = os.path.join(337            save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"]338        )339 340        if os.path.abspath(self.vocab_file) != os.path.abspath(out_vocab_file):341            copyfile(self.vocab_file, out_vocab_file)342 343        return (out_vocab_file,)344 345    def build_inputs_with_special_tokens(346        self, token_ids_0: list[int], token_ids_1: Optional[list[int]] = None347    ) -> list[int]:348        """349        Build model inputs from a sequence or a pair of sequence for sequence classification tasks by concatenating and350        adding special tokens. The special tokens depend on calling set_lang.351 352        An NLLB sequence has the following format, where `X` represents the sequence:353 354        - `input_ids` (for encoder) `X [eos, src_lang_code]`355        - `decoder_input_ids`: (for decoder) `X [eos, tgt_lang_code]`356 357        BOS is never used. Pairs of sequences are not the expected use case, but they will be handled without a358        separator.359 360        Args:361            token_ids_0 (`list[int]`):362                List of IDs to which the special tokens will be added.363            token_ids_1 (`list[int]`, *optional*):364                Optional second list of IDs for sequence pairs.365 366        Returns:367            `list[int]`: list of [input IDs](../glossary#input-ids) with the appropriate special tokens.368        """369        if token_ids_1 is None:370            return self.bos_token_id + token_ids_0 + self.eos_token_id371        return self.bos_token_id + token_ids_0 + token_ids_1 + self.eos_token_id372 373 374__all__ = ["CodeLlamaTokenizerFast"]375