CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
tokenization_wav2vec2.py925 linesDownload Raw Back to wav2vec2
1# coding=utf-82# Copyright 2021 The Facebook Inc. and The HuggingFace Inc. team. All rights reserved.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 class for Wav2Vec2."""16 17import json18import os19import warnings20from dataclasses import dataclass21from itertools import groupby22from typing import TYPE_CHECKING, Optional, Union23 24import numpy as np25 26from ...tokenization_utils import PreTrainedTokenizer27from ...tokenization_utils_base import AddedToken, BatchEncoding28from ...utils import (29    ModelOutput,30    PaddingStrategy,31    TensorType,32    add_end_docstrings,33    is_flax_available,34    is_tf_available,35    is_torch_available,36    logging,37    to_py_obj,38)39 40 41logger = logging.get_logger(__name__)42 43 44if TYPE_CHECKING:45    if is_torch_available():46        import torch47    if is_tf_available():48        import tensorflow as tf49    if is_flax_available():50        import jax.numpy as jnp  # noqa: F40151 52 53VOCAB_FILES_NAMES = {54    "vocab_file": "vocab.json",55    "tokenizer_config_file": "tokenizer_config.json",56}57 58 59# Wav2Vec2 has no max input length60 61WAV2VEC2_KWARGS_DOCSTRING = r"""62            padding (`bool`, `str` or [`~utils.PaddingStrategy`], *optional*, defaults to `False`):63                Activates and controls padding. Accepts the following values:64 65                - `True` or `'longest'`: Pad to the longest sequence in the batch (or no padding if only a single66                  sequence if provided).67                - `'max_length'`: Pad to a maximum length specified with the argument `max_length` or to the maximum68                  acceptable input length for the model if that argument is not provided.69                - `False` or `'do_not_pad'` (default): No padding (i.e., can output a batch with sequences of different70                  lengths).71            max_length (`int`, *optional*):72                Controls the maximum length to use by one of the truncation/padding parameters.73 74                If left unset or set to `None`, this will use the predefined model maximum length if a maximum length75                is required by one of the truncation/padding parameters. If the model has no specific maximum input76                length (like XLNet) truncation/padding to a maximum length will be deactivated.77            pad_to_multiple_of (`int`, *optional*):78                If set will pad the sequence to a multiple of the provided value. This is especially useful to enable79                the use of Tensor Cores on NVIDIA hardware with compute capability `>= 7.5` (Volta).80            return_tensors (`str` or [`~utils.TensorType`], *optional*):81                If set, will return tensors instead of list of python integers. Acceptable values are:82 83                - `'tf'`: Return TensorFlow `tf.constant` objects.84                - `'pt'`: Return PyTorch `torch.Tensor` objects.85                - `'np'`: Return Numpy `np.ndarray` objects.86            verbose (`bool`, *optional*, defaults to `True`):87                Whether or not to print more information and warnings.88"""89 90ListOfDict = list[dict[str, Union[int, str]]]91 92 93@dataclass94class Wav2Vec2CTCTokenizerOutput(ModelOutput):95    """96    Output type of [` Wav2Vec2CTCTokenizer`], with transcription.97 98    Args:99        text (list of `str` or `str`):100            Decoded logits in text from. Usually the speech transcription.101        char_offsets (list of `list[dict[str, Union[int, str]]]` or `list[dict[str, Union[int, str]]]`):102            Offsets of the decoded characters. In combination with sampling rate and model downsampling rate char103            offsets can be used to compute time stamps for each character. Total logit score of the beam associated with104            produced text.105        word_offsets (list of `list[dict[str, Union[int, str]]]` or `list[dict[str, Union[int, str]]]`):106            Offsets of the decoded words. In combination with sampling rate and model downsampling rate word offsets107            can be used to compute time stamps for each word.108    """109 110    text: Union[list[str], str]111    char_offsets: Union[list[ListOfDict], ListOfDict] = None112    word_offsets: Union[list[ListOfDict], ListOfDict] = None113 114 115class Wav2Vec2CTCTokenizer(PreTrainedTokenizer):116    """117    Constructs a Wav2Vec2CTC tokenizer.118 119    This tokenizer inherits from [`PreTrainedTokenizer`] which contains some of the main methods. Users should refer to120    the superclass for more information regarding such methods.121 122    Args:123        vocab_file (`str`):124            File containing the vocabulary.125        bos_token (`str`, *optional*, defaults to `"<s>"`):126            The beginning of sentence token.127        eos_token (`str`, *optional*, defaults to `"</s>"`):128            The end of sentence token.129        unk_token (`str`, *optional*, defaults to `"<unk>"`):130            The unknown token. A token that is not in the vocabulary cannot be converted to an ID and is set to be this131            token instead.132        pad_token (`str`, *optional*, defaults to `"<pad>"`):133            The token used for padding, for example when batching sequences of different lengths.134        word_delimiter_token (`str`, *optional*, defaults to `"|"`):135            The token used for defining the end of a word.136        do_lower_case (`bool`, *optional*, defaults to `False`):137            Whether or not to accept lowercase input and lowercase the output when decoding.138        target_lang (`str`, *optional*):139            A target language the tokenizer should set by default. `target_lang` has to be defined for multi-lingual,140            nested vocabulary such as [facebook/mms-1b-all](https://huggingface.co/facebook/mms-1b-all).141 142        **kwargs143            Additional keyword arguments passed along to [`PreTrainedTokenizer`]144    """145 146    vocab_files_names = VOCAB_FILES_NAMES147    model_input_names = ["input_ids", "attention_mask"]148 149    def __init__(150        self,151        vocab_file,152        bos_token="<s>",153        eos_token="</s>",154        unk_token="<unk>",155        pad_token="<pad>",156        word_delimiter_token="|",157        replace_word_delimiter_char=" ",158        do_lower_case=False,159        target_lang=None,160        **kwargs,161    ):162        self._word_delimiter_token = word_delimiter_token163 164        self.do_lower_case = do_lower_case165        self.replace_word_delimiter_char = replace_word_delimiter_char166        self.target_lang = target_lang167 168        with open(vocab_file, encoding="utf-8") as vocab_handle:169            self.vocab = json.load(vocab_handle)170 171        # if target lang is defined vocab must be a nested dict172        # with each target lang being one vocabulary173        if target_lang is not None:174            self.encoder = self.vocab[target_lang]175        else:176            self.encoder = self.vocab177 178        self.decoder = {v: k for k, v in self.encoder.items()}179 180        super().__init__(181            unk_token=unk_token,182            bos_token=bos_token,183            eos_token=eos_token,184            pad_token=pad_token,185            do_lower_case=do_lower_case,186            word_delimiter_token=word_delimiter_token,187            replace_word_delimiter_char=replace_word_delimiter_char,188            target_lang=target_lang,189            **kwargs,190        )191 192        # make sure that tokens made of several193        # characters are not split at tokenization194        for token in self.encoder:195            if len(token) > 1:196                self.add_tokens(AddedToken(token, rstrip=True, lstrip=True, normalized=False))197 198    def set_target_lang(self, target_lang: str):199        """200        Set the target language of a nested multi-lingual dictionary201        """202        if self.vocab == self.encoder:203            raise ValueError(f"{self.vocab} is not a multi-lingual, nested tokenizer. Cannot set target language.")204 205        if target_lang not in self.vocab:206            raise ValueError(f"{target_lang} does not exist. Choose one of {', '.join(self.vocab.keys())}.")207 208        self.target_lang = target_lang209        self.init_kwargs["target_lang"] = target_lang210        self.encoder = self.vocab[target_lang]211        self.decoder = {v: k for k, v in self.encoder.items()}212 213        # make sure that tokens made of several214        # characters are not split at tokenization215        for token in self.encoder:216            if len(token) > 1:217                self.add_tokens(AddedToken(token, rstrip=True, lstrip=True, normalized=False))218 219    @property220    def word_delimiter_token(self) -> str:221        """222        `str`: Word delimiter token. Log an error if used while not having been set.223        """224        if self._word_delimiter_token is None and self.verbose:225            logger.error("Using word_delimiter_token, but it is not set yet.")226            return None227        return str(self._word_delimiter_token)228 229    @property230    def word_delimiter_token_id(self) -> Optional[int]:231        """232        `Optional[int]`: Id of the word_delimiter_token in the vocabulary. Returns `None` if the token has not been233        set.234        """235        if self._word_delimiter_token is None:236            return None237        return self.convert_tokens_to_ids(self.word_delimiter_token)238 239    @word_delimiter_token.setter240    def word_delimiter_token(self, value):241        self._word_delimiter_token = value242 243    @word_delimiter_token_id.setter244    def word_delimiter_token_id(self, value):245        self._word_delimiter_token = self.convert_tokens_to_ids(value)246 247    @property248    def vocab_size(self) -> int:249        return len(self.decoder)250 251    def get_vocab(self) -> dict:252        vocab = dict(self.encoder)253        vocab.update(self.added_tokens_encoder)254        return vocab255 256    def _add_tokens(self, new_tokens: Union[list[str], list[AddedToken]], special_tokens: bool = False) -> int:257        # Overwritten to never strip!258        to_add = []259        for token in new_tokens:260            if isinstance(token, str):261                to_add.append(AddedToken(token, rstrip=False, lstrip=False, normalized=False))262            else:263                to_add.append(token)264 265        return super()._add_tokens(to_add, special_tokens)266 267    def _tokenize(self, text, **kwargs):268        """269        Converts a string into a sequence of tokens (string), using the tokenizer.270        """271        if self.do_lower_case:272            text = text.upper()273 274        return list(text.replace(" ", self.word_delimiter_token))275 276    def _convert_token_to_id(self, token: str) -> int:277        """Converts a token (str) in an index (integer) using the vocab."""278        return self.encoder.get(token, self.encoder.get(self.unk_token))279 280    def _convert_id_to_token(self, index: int) -> str:281        """Converts an index (integer) in a token (str) using the vocab."""282        result = self.decoder.get(index, self.unk_token)283        return result284 285    def convert_tokens_to_string(286        self,287        tokens: list[str],288        group_tokens: bool = True,289        spaces_between_special_tokens: bool = False,290        output_char_offsets: bool = False,291        output_word_offsets: bool = False,292    ) -> dict[str, Union[str, float]]:293        """294        Converts a connectionist-temporal-classification (CTC) output tokens into a single string.295        """296        if len(tokens) == 0:297            return {"text": "", "char_offsets": [], "word_offsets": []}298        # group same tokens into non-repeating tokens in CTC style decoding299        if group_tokens:300            chars, char_repetitions = zip(*((token, len(list(group_iter))) for token, group_iter in groupby(tokens)))301        else:302            chars = tokens303            char_repetitions = len(tokens) * [1]304 305        # filter self.pad_token which is used as CTC-blank token306        processed_chars = list(filter(lambda char: char != self.pad_token, chars))307 308        # replace delimiter token309        processed_chars = [310            self.replace_word_delimiter_char if char == self.word_delimiter_token else char for char in processed_chars311        ]312 313        # retrieve offsets314        char_offsets = word_offsets = None315        if output_char_offsets or output_word_offsets:316            char_offsets = self._compute_offsets(char_repetitions, chars, self.pad_token)317 318            if len(char_offsets) != len(processed_chars):319                raise ValueError(320                    f"`char_offsets`: {char_offsets} and `processed_tokens`: {processed_chars}"321                    " have to be of the same length, but are: "322                    f"`len(offsets)`: {len(char_offsets)} and `len(processed_tokens)`:"323                    f" {len(processed_chars)}"324                )325 326            # set tokens to correct processed token327            for i, char in enumerate(processed_chars):328                char_offsets[i]["char"] = char329 330            # retrieve word offsets from character offsets331            word_offsets = None332            if output_word_offsets:333                word_offsets = self._get_word_offsets(char_offsets, self.replace_word_delimiter_char)334 335            # don't output chars if not set to True336            if not output_char_offsets:337                char_offsets = None338 339        # join to string340        join_char = " " if spaces_between_special_tokens else ""341        string = join_char.join(processed_chars).strip()342 343        if self.do_lower_case:344            string = string.lower()345 346        return {"text": string, "char_offsets": char_offsets, "word_offsets": word_offsets}347 348    @staticmethod349    def _compute_offsets(350        char_repetitions: list[int], chars: list[str], ctc_token: int351    ) -> list[dict[str, Union[str, int]]]:352        end_indices = np.asarray(char_repetitions).cumsum()353        start_indices = np.concatenate(([0], end_indices[:-1]))354 355        offsets = [356            {"char": t, "start_offset": s, "end_offset": e} for t, s, e in zip(chars, start_indices, end_indices)357        ]358 359        # filter out CTC token360        offsets = list(filter(lambda offsets: offsets["char"] != ctc_token, offsets))361        return offsets362 363    @staticmethod364    def _get_word_offsets(365        offsets: dict[str, Union[str, float]], word_delimiter_char: str = " "366    ) -> dict[str, Union[str, float]]:367        word_offsets = []368 369        last_state = "SPACE"370        word = ""371        start_offset = 0372        end_offset = 0373        for i, offset in enumerate(offsets):374            char = offset["char"]375            state = "SPACE" if char == word_delimiter_char else "WORD"376 377            if state == last_state:378                # If we are in the same state as before, we simply repeat what we've done before379                end_offset = offset["end_offset"]380                word += char381            else:382                # Switching state383                if state == "SPACE":384                    # Finishing a word385                    word_offsets.append({"word": word, "start_offset": start_offset, "end_offset": end_offset})386                else:387                    # Starting a new word388                    start_offset = offset["start_offset"]389                    end_offset = offset["end_offset"]390                    word = char391 392            last_state = state393        if last_state == "WORD":394            word_offsets.append({"word": word, "start_offset": start_offset, "end_offset": end_offset})395 396        return word_offsets397 398    def prepare_for_tokenization(self, text, is_split_into_words=False, **kwargs):399        if is_split_into_words:400            text = " " + text401        return (text, kwargs)402 403    def _decode(404        self,405        token_ids: list[int],406        skip_special_tokens: bool = False,407        clean_up_tokenization_spaces: Optional[bool] = None,408        group_tokens: bool = True,409        spaces_between_special_tokens: bool = False,410        output_word_offsets: Optional[bool] = False,411        output_char_offsets: Optional[bool] = False,412    ) -> str:413        """414        special _decode function is needed for Wav2Vec2Tokenizer because added tokens should be treated exactly the415        same as tokens of the base vocabulary and therefore the function `convert_tokens_to_string` has to be called on416        the whole token list and not individually on added tokens417        """418        filtered_tokens = self.convert_ids_to_tokens(token_ids, skip_special_tokens=skip_special_tokens)419 420        result = []421        for token in filtered_tokens:422            if skip_special_tokens and (423                token in self.all_special_ids or (token != self.pad_token and token in self.all_special_tokens)424            ):425                continue426            result.append(token)427 428        string_output = self.convert_tokens_to_string(429            result,430            group_tokens=group_tokens,431            spaces_between_special_tokens=spaces_between_special_tokens,432            output_word_offsets=output_word_offsets,433            output_char_offsets=output_char_offsets,434        )435 436        text = string_output["text"]437 438        clean_up_tokenization_spaces = (439            clean_up_tokenization_spaces440            if clean_up_tokenization_spaces is not None441            else self.clean_up_tokenization_spaces442        )443        if clean_up_tokenization_spaces:444            text = self.clean_up_tokenization(text)445 446        if output_word_offsets or output_char_offsets:447            return Wav2Vec2CTCTokenizerOutput(448                text=text,449                char_offsets=string_output["char_offsets"],450                word_offsets=string_output["word_offsets"],451            )452        else:453            return text454 455    # overwritten from `tokenization_utils_base.py` because tokenizer can output456    # `ModelOutput` which should not be a list for batched output and457    # because we need docs for `output_char_offsets` here458    def batch_decode(459        self,460        sequences: Union[list[int], list[list[int]], "np.ndarray", "torch.Tensor", "tf.Tensor"],461        skip_special_tokens: bool = False,462        clean_up_tokenization_spaces: Optional[bool] = None,463        output_char_offsets: bool = False,464        output_word_offsets: bool = False,465        **kwargs,466    ) -> list[str]:467        """468        Convert a list of lists of token ids into a list of strings by calling decode.469 470        Args:471            sequences (`Union[list[int], list[list[int]], np.ndarray, torch.Tensor, tf.Tensor]`):472                List of tokenized input ids. Can be obtained using the `__call__` method.473            skip_special_tokens (`bool`, *optional*, defaults to `False`):474                Whether or not to remove special tokens in the decoding.475            clean_up_tokenization_spaces (`bool`, *optional*):476                Whether or not to clean up the tokenization spaces.477            output_char_offsets (`bool`, *optional*, defaults to `False`):478                Whether or not to output character offsets. Character offsets can be used in combination with the479                sampling rate and model downsampling rate to compute the time-stamps of transcribed characters.480 481                <Tip>482 483                Please take a look at the Example of [`~Wav2Vec2CTCTokenizer.decode`] to better understand how to make484                use of `output_char_offsets`. [`~Wav2Vec2CTCTokenizer.batch_decode`] works the same way with batched485                output.486 487                </Tip>488 489            output_word_offsets (`bool`, *optional*, defaults to `False`):490                Whether or not to output word offsets. Word offsets can be used in combination with the sampling rate491                and model downsampling rate to compute the time-stamps of transcribed words.492 493                <Tip>494 495                Please take a look at the Example of [`~Wav2Vec2CTCTokenizer.decode`] to better understand how to make496                use of `output_word_offsets`. [`~Wav2Vec2CTCTokenizer.batch_decode`] works the same way with batched497                output.498 499                </Tip>500 501            kwargs (additional keyword arguments, *optional*):502                Will be passed to the underlying model specific decode method.503 504        Returns:505            `list[str]` or [`~models.wav2vec2.tokenization_wav2vec2.Wav2Vec2CTCTokenizerOutput`]: The list of decoded506            sentences. Will be a [`~models.wav2vec2.tokenization_wav2vec2.Wav2Vec2CTCTokenizerOutput`] when507            `output_char_offsets == True` or `output_word_offsets == True`.508        """509        batch_decoded = [510            self.decode(511                seq,512                skip_special_tokens=skip_special_tokens,513                clean_up_tokenization_spaces=clean_up_tokenization_spaces,514                output_char_offsets=output_char_offsets,515                output_word_offsets=output_word_offsets,516                **kwargs,517            )518            for seq in sequences519        ]520        if output_char_offsets or output_word_offsets:521            # transform list of dicts to dict of lists522            return Wav2Vec2CTCTokenizerOutput({k: [d[k] for d in batch_decoded] for k in batch_decoded[0]})523 524        return batch_decoded525 526    # overwritten from `tokenization_utils_base.py` because we need docs for `output_char_offsets`527    # and `output_word_offsets` here528    def decode(529        self,530        token_ids: Union[int, list[int], "np.ndarray", "torch.Tensor", "tf.Tensor"],531        skip_special_tokens: bool = False,532        clean_up_tokenization_spaces: Optional[bool] = None,533        output_char_offsets: bool = False,534        output_word_offsets: bool = False,535        **kwargs,536    ) -> str:537        """538        Converts a sequence of ids in a string, using the tokenizer and vocabulary with options to remove special539        tokens and clean up tokenization spaces.540 541        Similar to doing `self.convert_tokens_to_string(self.convert_ids_to_tokens(token_ids))`.542 543        Args:544            token_ids (`Union[int, list[int], np.ndarray, torch.Tensor, tf.Tensor]`):545                List of tokenized input ids. Can be obtained using the `__call__` method.546            skip_special_tokens (`bool`, *optional*, defaults to `False`):547                Whether or not to remove special tokens in the decoding.548            clean_up_tokenization_spaces (`bool`, *optional*):549                Whether or not to clean up the tokenization spaces.550            output_char_offsets (`bool`, *optional*, defaults to `False`):551                Whether or not to output character offsets. Character offsets can be used in combination with the552                sampling rate and model downsampling rate to compute the time-stamps of transcribed characters.553 554                <Tip>555 556                Please take a look at the example below to better understand how to make use of `output_char_offsets`.557 558                </Tip>559 560            output_word_offsets (`bool`, *optional*, defaults to `False`):561                Whether or not to output word offsets. Word offsets can be used in combination with the sampling rate562                and model downsampling rate to compute the time-stamps of transcribed words.563 564                <Tip>565 566                Please take a look at the example below to better understand how to make use of `output_word_offsets`.567 568                </Tip>569 570            kwargs (additional keyword arguments, *optional*):571                Will be passed to the underlying model specific decode method.572 573        Returns:574            `str` or [`~models.wav2vec2.tokenization_wav2vec2.Wav2Vec2CTCTokenizerOutput`]: The list of decoded575            sentences. Will be a [`~models.wav2vec2.tokenization_wav2vec2.Wav2Vec2CTCTokenizerOutput`] when576            `output_char_offsets == True` or `output_word_offsets == True`.577 578        Example:579 580        ```python581        >>> # Let's see how to retrieve time steps for a model582        >>> from transformers import AutoTokenizer, AutoFeatureExtractor, AutoModelForCTC583        >>> from datasets import load_dataset584        >>> import datasets585        >>> import torch586 587        >>> # import model, feature extractor, tokenizer588        >>> model = AutoModelForCTC.from_pretrained("facebook/wav2vec2-base-960h")589        >>> tokenizer = AutoTokenizer.from_pretrained("facebook/wav2vec2-base-960h")590        >>> feature_extractor = AutoFeatureExtractor.from_pretrained("facebook/wav2vec2-base-960h")591 592        >>> # load first sample of English common_voice593        >>> dataset = load_dataset("mozilla-foundation/common_voice_11_0", "en", split="train", streaming=True)594        >>> dataset = dataset.cast_column("audio", datasets.Audio(sampling_rate=16_000))595        >>> dataset_iter = iter(dataset)596        >>> sample = next(dataset_iter)597 598        >>> # forward sample through model to get greedily predicted transcription ids599        >>> input_values = feature_extractor(sample["audio"]["array"], return_tensors="pt").input_values600        >>> logits = model(input_values).logits[0]601        >>> pred_ids = torch.argmax(logits, axis=-1)602 603        >>> # retrieve word stamps (analogous commands for `output_char_offsets`)604        >>> outputs = tokenizer.decode(pred_ids, output_word_offsets=True)605        >>> # compute `time_offset` in seconds as product of downsampling ratio and sampling_rate606        >>> time_offset = model.config.inputs_to_logits_ratio / feature_extractor.sampling_rate607 608        >>> word_offsets = [609        ...     {610        ...         "word": d["word"],611        ...         "start_time": round(d["start_offset"] * time_offset, 2),612        ...         "end_time": round(d["end_offset"] * time_offset, 2),613        ...     }614        ...     for d in outputs.word_offsets615        ... ]616        >>> # compare word offsets with audio `en_train_0/common_voice_en_19121553.mp3` online on the dataset viewer:617        >>> # https://huggingface.co/datasets/mozilla-foundation/common_voice_11_0/viewer/en618        >>> word_offsets[:3]619        [{'word': 'THE', 'start_time': 0.7, 'end_time': 0.78}, {'word': 'TRICK', 'start_time': 0.88, 'end_time': 1.08}, {'word': 'APPEARS', 'start_time': 1.2, 'end_time': 1.64}]620        ```"""621        # Convert inputs to python lists622        token_ids = to_py_obj(token_ids)623 624        return self._decode(625            token_ids=token_ids,626            skip_special_tokens=skip_special_tokens,627            clean_up_tokenization_spaces=clean_up_tokenization_spaces,628            output_char_offsets=output_char_offsets,629            output_word_offsets=output_word_offsets,630            **kwargs,631        )632 633    def save_vocabulary(self, save_directory: str, filename_prefix: Optional[str] = None) -> tuple[str]:634        if not os.path.isdir(save_directory):635            logger.error(f"Vocabulary path ({save_directory}) should be a directory")636            return637        vocab_file = os.path.join(638            save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"]639        )640 641        with open(vocab_file, "w", encoding="utf-8") as f:642            f.write(json.dumps(self.vocab, indent=2, sort_keys=True, ensure_ascii=False) + "\n")643 644        return (vocab_file,)645 646 647class Wav2Vec2Tokenizer(PreTrainedTokenizer):648    """649    Constructs a Wav2Vec2 tokenizer.650 651    This tokenizer inherits from [`PreTrainedTokenizer`] which contains some of the main methods. Users should refer to652    the superclass for more information regarding such methods.653 654    Args:655        vocab_file (`str`):656            File containing the vocabulary.657        bos_token (`str`, *optional*, defaults to `"<s>"`):658            The beginning of sentence token.659        eos_token (`str`, *optional*, defaults to `"</s>"`):660            The end of sentence token.661        unk_token (`str`, *optional*, defaults to `"<unk>"`):662            The unknown token. A token that is not in the vocabulary cannot be converted to an ID and is set to be this663            token instead.664        pad_token (`str`, *optional*, defaults to `"<pad>"`):665            The token used for padding, for example when batching sequences of different lengths.666        word_delimiter_token (`str`, *optional*, defaults to `"|"`):667            The token used for defining the end of a word.668        do_lower_case (`bool`, *optional*, defaults to `False`):669            Whether or not to lowercase the output when decoding.670        do_normalize (`bool`, *optional*, defaults to `False`):671            Whether or not to zero-mean unit-variance normalize the input. Normalizing can help to significantly672            improve the performance for some models, *e.g.*,673            [wav2vec2-lv60](https://huggingface.co/models?search=lv60).674        return_attention_mask (`bool`, *optional*, defaults to `False`):675            Whether or not [`~Wav2Vec2Tokenizer.__call__`] should return `attention_mask`.676 677            <Tip>678 679            Wav2Vec2 models that have set `config.feat_extract_norm == "group"`, such as680            [wav2vec2-base](https://huggingface.co/facebook/wav2vec2-base-960h), have **not** been trained using681            `attention_mask`. For such models, `input_values` should simply be padded with 0 and no `attention_mask`682            should be passed.683 684            For Wav2Vec2 models that have set `config.feat_extract_norm == "layer"`, such as685            [wav2vec2-lv60](https://huggingface.co/facebook/wav2vec2-large-960h-lv60-self), `attention_mask` should be686            passed for batched inference.687 688            </Tip>689 690        **kwargs691            Additional keyword arguments passed along to [`PreTrainedTokenizer`]692    """693 694    vocab_files_names = VOCAB_FILES_NAMES695    pretrained_vocab_files_map = {696        "vocab_file": {697            "facebook/wav2vec2-base-960h": "https://huggingface.co/facebook/wav2vec2-base-960h/resolve/main/vocab.json"698        },699        "tokenizer_config_file": {700            "facebook/wav2vec2-base-960h": (701                "https://huggingface.co/facebook/wav2vec2-base-960h/resolve/main/tokenizer.json"702            ),703        },704    }705    model_input_names = ["input_values", "attention_mask"]706 707    def __init__(708        self,709        vocab_file,710        bos_token="<s>",711        eos_token="</s>",712        unk_token="<unk>",713        pad_token="<pad>",714        word_delimiter_token="|",715        do_lower_case=False,716        do_normalize=False,717        return_attention_mask=False,718        **kwargs,719    ):720        warnings.warn(721            "The class `Wav2Vec2Tokenizer` is deprecated and will be removed in version 5 of Transformers. Please use"722            " `Wav2Vec2Processor` or `Wav2Vec2CTCTokenizer` instead.",723            FutureWarning,724        )725 726        self._word_delimiter_token = word_delimiter_token727 728        self.do_lower_case = do_lower_case729        self.return_attention_mask = return_attention_mask730        self.do_normalize = do_normalize731 732        with open(vocab_file, encoding="utf-8") as vocab_handle:733            self.encoder = json.load(vocab_handle)734 735        self.decoder = {v: k for k, v in self.encoder.items()}736 737        super().__init__(738            unk_token=unk_token,739            bos_token=bos_token,740            eos_token=eos_token,741            pad_token=pad_token,742            do_lower_case=do_lower_case,743            do_normalize=do_normalize,744            return_attention_mask=return_attention_mask,745            word_delimiter_token=word_delimiter_token,746            **kwargs,747        )748 749    @property750    def word_delimiter_token(self) -> str:751        """752        `str`: Padding token. Log an error if used while not having been set.753        """754        if self._word_delimiter_token is None and self.verbose:755            logger.error("Using word_delimiter_token, but it is not set yet.")756            return None757        return str(self._word_delimiter_token)758 759    @property760    def word_delimiter_token_id(self) -> Optional[int]:761        """762        `Optional[int]`: Id of the word_delimiter_token in the vocabulary. Returns `None` if the token has not been763        set.764        """765        if self._word_delimiter_token is None:766            return None767        return self.convert_tokens_to_ids(self.word_delimiter_token)768 769    @word_delimiter_token.setter770    def word_delimiter_token(self, value):771        self._word_delimiter_token = value772 773    @word_delimiter_token_id.setter774    def word_delimiter_token_id(self, value):775        self._word_delimiter_token = self.convert_tokens_to_ids(value)776 777    @add_end_docstrings(WAV2VEC2_KWARGS_DOCSTRING)778    def __call__(779        self,780        raw_speech: Union[np.ndarray, list[float], list[np.ndarray], list[list[float]]],781        padding: Union[bool, str, PaddingStrategy] = False,782        max_length: Optional[int] = None,783        pad_to_multiple_of: Optional[int] = None,784        padding_side: Optional[str] = None,785        return_tensors: Optional[Union[str, TensorType]] = None,786        verbose: bool = True,787        **kwargs,788    ) -> BatchEncoding:789        """790        Main method to tokenize and prepare for the model one or several sequence(s) or one or several pair(s) of791        sequences.792 793        Args:794            raw_speech (`np.ndarray`, `list[float]`, `list[np.ndarray]`, `list[list[float]]`):795                The sequence or batch of sequences to be padded. Each sequence can be a numpy array, a list of float796                values, a list of numpy array or a list of list of float values. Must be mono channel audio, not797                stereo, i.e. single float per timestep.798 799            padding_side (`str`, *optional*):800                The side on which the model should have padding applied. Should be selected between ['right', 'left'].801                Default value is picked from the class attribute of the same name.802        """803 804        is_batched_numpy = isinstance(raw_speech, np.ndarray) and len(raw_speech.shape) > 1805        if is_batched_numpy and len(raw_speech.shape) > 2:806            raise ValueError(f"Only mono-channel audio is supported for input to {self}")807        is_batched = is_batched_numpy or (808            isinstance(raw_speech, (list, tuple)) and (isinstance(raw_speech[0], (np.ndarray, tuple, list)))809        )810 811        # make sure input is in list format812        if is_batched and not isinstance(raw_speech[0], np.ndarray):813            raw_speech = [np.asarray(speech) for speech in raw_speech]814        elif not is_batched and not isinstance(raw_speech, np.ndarray):815            raw_speech = np.asarray(raw_speech)816 817        # always return batch818        if not is_batched:819            raw_speech = [raw_speech]820 821        # zero-mean and unit-variance normalization822        if self.do_normalize:823            raw_speech = [(x - np.mean(x)) / np.sqrt(np.var(x) + 1e-5) for x in raw_speech]824 825        # convert into correct format for padding826        encoded_inputs = BatchEncoding({"input_values": raw_speech})827 828        padded_inputs = self.pad(829            encoded_inputs,830            padding=padding,831            max_length=max_length,832            pad_to_multiple_of=pad_to_multiple_of,833            padding_side=padding_side,834            return_attention_mask=self.return_attention_mask,835            return_tensors=return_tensors,836            verbose=verbose,837        )838 839        return padded_inputs840 841    @property842    def vocab_size(self) -> int:843        return len(self.decoder)844 845    def get_vocab(self) -> dict:846        return dict(self.encoder, **self.added_tokens_encoder)847 848    def _convert_token_to_id(self, token: str) -> int:849        """Converts a token (str) in an index (integer) using the vocab."""850        return self.encoder.get(token, self.encoder.get(self.unk_token))851 852    def _convert_id_to_token(self, index: int) -> str:853        """Converts an index (integer) in a token (str) using the vocab."""854        result = self.decoder.get(index, self.unk_token)855        return result856 857    def convert_tokens_to_string(self, tokens: list[str]) -> str:858        """859        Converts a connectionist-temporal-classification (CTC) output tokens into a single string.860        """861        # group same tokens into non-repeating tokens in CTC style decoding862        grouped_tokens = [token_group[0] for token_group in groupby(tokens)]863 864        # filter self.pad_token which is used as CTC-blank token865        filtered_tokens = list(filter(lambda token: token != self.pad_token, grouped_tokens))866 867        # replace delimiter token868        string = "".join([" " if token == self.word_delimiter_token else token for token in filtered_tokens]).strip()869 870        if self.do_lower_case:871            string = string.lower()872 873        return string874 875    def _decode(876        self,877        token_ids: list[int],878        skip_special_tokens: bool = False,879        clean_up_tokenization_spaces: Optional[bool] = None,880        **kwargs,881    ) -> str:882        """883        special _decode function is needed for Wav2Vec2Tokenizer because added tokens should be treated exactly the884        same as tokens of the base vocabulary and therefore the function `convert_tokens_to_string` has to be called on885        the whole token list and not individually on added tokens886        """887        filtered_tokens = self.convert_ids_to_tokens(token_ids, skip_special_tokens=skip_special_tokens)888 889        result = []890        for token in filtered_tokens:891            if skip_special_tokens and (892                token in self.all_special_ids or (token != self.pad_token and token in self.all_special_tokens)893            ):894                continue895            result.append(token)896 897        text = self.convert_tokens_to_string(result)898 899        clean_up_tokenization_spaces = (900            clean_up_tokenization_spaces901            if clean_up_tokenization_spaces is not None902            else self.clean_up_tokenization_spaces903        )904        if clean_up_tokenization_spaces:905            clean_text = self.clean_up_tokenization(text)906            return clean_text907        else:908            return text909 910    def save_vocabulary(self, save_directory: str, filename_prefix: Optional[str] = None) -> tuple[str]:911        if not os.path.isdir(save_directory):912            logger.error(f"Vocabulary path ({save_directory}) should be a directory")913            return914        vocab_file = os.path.join(915            save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"]916        )917 918        with open(vocab_file, "w", encoding="utf-8") as f:919            f.write(json.dumps(self.encoder, indent=2, sort_keys=True, ensure_ascii=False) + "\n")920 921        return (vocab_file,)922 923 924__all__ = ["Wav2Vec2CTCTokenizer", "Wav2Vec2Tokenizer"]925 
Aluode/PerceptionLabPortable · CoolFace