CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
tokenization_albert.py321 linesDownload Raw Back to albert
1# coding=utf-82# Copyright 2018 Google AI, Google Brain and 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.15"""Tokenization classes for ALBERT model."""16 17import os18import unicodedata19from shutil import copyfile20from typing import Any, Optional21 22import sentencepiece as spm23 24from ...tokenization_utils import AddedToken, PreTrainedTokenizer25from ...utils import logging26from ...utils.import_utils import requires27 28 29logger = logging.get_logger(__name__)30VOCAB_FILES_NAMES = {"vocab_file": "spiece.model"}31 32 33SPIECE_UNDERLINE = "▁"34 35 36@requires(backends=("sentencepiece",))37class AlbertTokenizer(PreTrainedTokenizer):38    """39    Construct an ALBERT tokenizer. Based on [SentencePiece](https://github.com/google/sentencepiece).40 41    This tokenizer inherits from [`PreTrainedTokenizer`] which contains most of the main methods. Users should refer to42    this superclass for more information regarding those methods.43 44    Args:45        vocab_file (`str`):46            [SentencePiece](https://github.com/google/sentencepiece) file (generally has a *.spm* extension) that47            contains the vocabulary necessary to instantiate a tokenizer.48        do_lower_case (`bool`, *optional*, defaults to `True`):49            Whether or not to lowercase the input when tokenizing.50        remove_space (`bool`, *optional*, defaults to `True`):51            Whether or not to strip the text when tokenizing (removing excess spaces before and after the string).52        keep_accents (`bool`, *optional*, defaults to `False`):53            Whether or not to keep accents when tokenizing.54        bos_token (`str`, *optional*, defaults to `"[CLS]"`):55            The beginning of sequence token that was used during pretraining. Can be used a sequence classifier token.56 57            <Tip>58 59            When building a sequence using special tokens, this is not the token that is used for the beginning of60            sequence. The token used is the `cls_token`.61 62            </Tip>63 64        eos_token (`str`, *optional*, defaults to `"[SEP]"`):65            The end of sequence token.66 67            <Tip>68 69            When building a sequence using special tokens, this is not the token that is used for the end of sequence.70            The token used is the `sep_token`.71 72            </Tip>73 74        unk_token (`str`, *optional*, defaults to `"<unk>"`):75            The unknown token. A token that is not in the vocabulary cannot be converted to an ID and is set to be this76            token instead.77        sep_token (`str`, *optional*, defaults to `"[SEP]"`):78            The separator token, which is used when building a sequence from multiple sequences, e.g. two sequences for79            sequence classification or for a text and a question for question answering. It is also used as the last80            token of a sequence built with special tokens.81        pad_token (`str`, *optional*, defaults to `"<pad>"`):82            The token used for padding, for example when batching sequences of different lengths.83        cls_token (`str`, *optional*, defaults to `"[CLS]"`):84            The classifier token which is used when doing sequence classification (classification of the whole sequence85            instead of per-token classification). It is the first token of the sequence when built with special tokens.86        mask_token (`str`, *optional*, defaults to `"[MASK]"`):87            The token used for masking values. This is the token used when training this model with masked language88            modeling. This is the token which the model will try to predict.89        sp_model_kwargs (`dict`, *optional*):90            Will be passed to the `SentencePieceProcessor.__init__()` method. The [Python wrapper for91            SentencePiece](https://github.com/google/sentencepiece/tree/master/python) can be used, among other things,92            to set:93 94            - `enable_sampling`: Enable subword regularization.95            - `nbest_size`: Sampling parameters for unigram. Invalid for BPE-Dropout.96 97              - `nbest_size = {0,1}`: No sampling is performed.98              - `nbest_size > 1`: samples from the nbest_size results.99              - `nbest_size < 0`: assuming that nbest_size is infinite and samples from the all hypothesis (lattice)100                using forward-filtering-and-backward-sampling algorithm.101 102            - `alpha`: Smoothing parameter for unigram sampling, and dropout probability of merge operations for103              BPE-dropout.104 105    Attributes:106        sp_model (`SentencePieceProcessor`):107            The *SentencePiece* processor that is used for every conversion (string, tokens and IDs).108    """109 110    vocab_files_names = VOCAB_FILES_NAMES111 112    def __init__(113        self,114        vocab_file,115        do_lower_case=True,116        remove_space=True,117        keep_accents=False,118        bos_token="[CLS]",119        eos_token="[SEP]",120        unk_token="<unk>",121        sep_token="[SEP]",122        pad_token="<pad>",123        cls_token="[CLS]",124        mask_token="[MASK]",125        sp_model_kwargs: Optional[dict[str, Any]] = None,126        **kwargs,127    ) -> None:128        # Mask token behave like a normal word, i.e. include the space before it and129        # is included in the raw text, there should be a match in a non-normalized sentence.130        mask_token = (131            AddedToken(mask_token, lstrip=True, rstrip=False, normalized=False)132            if isinstance(mask_token, str)133            else mask_token134        )135 136        self.sp_model_kwargs = {} if sp_model_kwargs is None else sp_model_kwargs137 138        self.do_lower_case = do_lower_case139        self.remove_space = remove_space140        self.keep_accents = keep_accents141        self.vocab_file = vocab_file142 143        self.sp_model = spm.SentencePieceProcessor(**self.sp_model_kwargs)144        self.sp_model.Load(vocab_file)145 146        super().__init__(147            do_lower_case=do_lower_case,148            remove_space=remove_space,149            keep_accents=keep_accents,150            bos_token=bos_token,151            eos_token=eos_token,152            unk_token=unk_token,153            sep_token=sep_token,154            pad_token=pad_token,155            cls_token=cls_token,156            mask_token=mask_token,157            sp_model_kwargs=self.sp_model_kwargs,158            **kwargs,159        )160 161    @property162    def vocab_size(self) -> int:163        return len(self.sp_model)164 165    def get_vocab(self) -> dict[str, int]:166        vocab = {self.convert_ids_to_tokens(i): i for i in range(self.vocab_size)}167        vocab.update(self.added_tokens_encoder)168        return vocab169 170    def __getstate__(self):171        state = self.__dict__.copy()172        state["sp_model"] = None173        return state174 175    def __setstate__(self, d):176        self.__dict__ = d177 178        # for backward compatibility179        if not hasattr(self, "sp_model_kwargs"):180            self.sp_model_kwargs = {}181 182        self.sp_model = spm.SentencePieceProcessor(**self.sp_model_kwargs)183        self.sp_model.Load(self.vocab_file)184 185    def preprocess_text(self, inputs):186        if self.remove_space:187            outputs = " ".join(inputs.strip().split())188        else:189            outputs = inputs190        outputs = outputs.replace("``", '"').replace("''", '"')191 192        if not self.keep_accents:193            outputs = unicodedata.normalize("NFKD", outputs)194            outputs = "".join([c for c in outputs if not unicodedata.combining(c)])195        if self.do_lower_case:196            outputs = outputs.lower()197 198        return outputs199 200    def _tokenize(self, text: str) -> list[str]:201        """Tokenize a string."""202        text = self.preprocess_text(text)203        pieces = self.sp_model.encode(text, out_type=str)204        new_pieces = []205        for piece in pieces:206            if len(piece) > 1 and piece[-1] == "," and piece[-2].isdigit():207                # Logic to handle special cases see https://github.com/google-research/bert/blob/master/README.md#tokenization208                # `9,9` -> ['▁9', ',', '9'] instead of [`_9,`, '9']209                cur_pieces = self.sp_model.EncodeAsPieces(piece[:-1].replace(SPIECE_UNDERLINE, ""))210                if piece[0] != SPIECE_UNDERLINE and cur_pieces[0][0] == SPIECE_UNDERLINE:211                    if len(cur_pieces[0]) == 1:212                        cur_pieces = cur_pieces[1:]213                    else:214                        cur_pieces[0] = cur_pieces[0][1:]215                cur_pieces.append(piece[-1])216                new_pieces.extend(cur_pieces)217            else:218                new_pieces.append(piece)219 220        return new_pieces221 222    def _convert_token_to_id(self, token):223        """Converts a token (str) in an id using the vocab."""224        return self.sp_model.PieceToId(token)225 226    def _convert_id_to_token(self, index):227        """Converts an index (integer) in a token (str) using the vocab."""228        return self.sp_model.IdToPiece(index)229 230    def convert_tokens_to_string(self, tokens):231        """Converts a sequence of tokens (string) in a single string."""232        current_sub_tokens = []233        out_string = ""234        prev_is_special = False235        for token in tokens:236            # make sure that special tokens are not decoded using sentencepiece model237            if token in self.all_special_tokens:238                if not prev_is_special:239                    out_string += " "240                out_string += self.sp_model.decode(current_sub_tokens) + token241                prev_is_special = True242                current_sub_tokens = []243            else:244                current_sub_tokens.append(token)245                prev_is_special = False246        out_string += self.sp_model.decode(current_sub_tokens)247        return out_string.strip()248 249    def build_inputs_with_special_tokens(250        self, token_ids_0: list[int], token_ids_1: Optional[list[int]] = None251    ) -> list[int]:252        """253        Build model inputs from a sequence or a pair of sequence for sequence classification tasks by concatenating and254        adding special tokens. An ALBERT sequence has the following format:255 256        - single sequence: `[CLS] X [SEP]`257        - pair of sequences: `[CLS] A [SEP] B [SEP]`258 259        Args:260            token_ids_0 (`List[int]`):261                List of IDs to which the special tokens will be added.262            token_ids_1 (`List[int]`, *optional*):263                Optional second list of IDs for sequence pairs.264 265        Returns:266            `List[int]`: List of [input IDs](../glossary#input-ids) with the appropriate special tokens.267        """268        sep = [self.sep_token_id]269        cls = [self.cls_token_id]270        if token_ids_1 is None:271            return cls + token_ids_0 + sep272        return cls + token_ids_0 + sep + token_ids_1 + sep273 274    def get_special_tokens_mask(275        self, token_ids_0: list[int], token_ids_1: Optional[list[int]] = None, already_has_special_tokens: bool = False276    ) -> list[int]:277        """278        Retrieve sequence ids from a token list that has no special tokens added. This method is called when adding279        special tokens using the tokenizer `prepare_for_model` method.280 281        Args:282            token_ids_0 (`List[int]`):283                List of IDs.284            token_ids_1 (`List[int]`, *optional*):285                Optional second list of IDs for sequence pairs.286            already_has_special_tokens (`bool`, *optional*, defaults to `False`):287                Whether or not the token list is already formatted with special tokens for the model.288 289        Returns:290            `List[int]`: A list of integers in the range [0, 1]: 1 for a special token, 0 for a sequence token.291        """292 293        if already_has_special_tokens:294            return super().get_special_tokens_mask(295                token_ids_0=token_ids_0, token_ids_1=token_ids_1, already_has_special_tokens=True296            )297 298        if token_ids_1 is not None:299            return [1] + ([0] * len(token_ids_0)) + [1] + ([0] * len(token_ids_1)) + [1]300        return [1] + ([0] * len(token_ids_0)) + [1]301 302    def save_vocabulary(self, save_directory: str, filename_prefix: Optional[str] = None) -> tuple[str]:303        if not os.path.isdir(save_directory):304            logger.error(f"Vocabulary path ({save_directory}) should be a directory")305            return306        out_vocab_file = os.path.join(307            save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"]308        )309 310        if os.path.abspath(self.vocab_file) != os.path.abspath(out_vocab_file) and os.path.isfile(self.vocab_file):311            copyfile(self.vocab_file, out_vocab_file)312        elif not os.path.isfile(self.vocab_file):313            with open(out_vocab_file, "wb") as fi:314                content_spiece_model = self.sp_model.serialized_model_proto()315                fi.write(content_spiece_model)316 317        return (out_vocab_file,)318 319 320__all__ = ["AlbertTokenizer"]321 
Aluode/PerceptionLabPortable · CoolFace