mirror of
https://gitee.com/fastnlp/fastNLP.git
synced 2024-11-30 19:28:17 +08:00
迁移transformers ver.4.11.3的bert bart roberta gpt2和cpt模型
This commit is contained in:
parent
2dc1199402
commit
df1db2535a
@ -1,4 +1,5 @@
|
||||
|
||||
import functools
|
||||
|
||||
class DummyClass:
|
||||
pass
|
||||
def __call__(self, *args, **kwargs):
|
||||
return
|
||||
|
1
fastNLP/transformers/__init__.py
Normal file
1
fastNLP/transformers/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""基于 transformers-4.11.3 版本迁移"""
|
9
fastNLP/transformers/torch/__init__.py
Normal file
9
fastNLP/transformers/torch/__init__.py
Normal file
@ -0,0 +1,9 @@
|
||||
"""
|
||||
为了防止因 https://github.com/huggingface/transformers 版本变化导致代码不兼容,当前 folder 以及子 folder
|
||||
都复制自 https://github.com/huggingface/transformers 的4.11.3版本。
|
||||
In order to avoid the code change of https://github.com/huggingface/transformers to cause version
|
||||
mismatch, we copy code from https://github.com/huggingface/transformers(version:4.11.3) in this
|
||||
folder and its subfolder.
|
||||
"""
|
||||
__version__ = "4.11.3"
|
||||
from .models import *
|
125
fastNLP/transformers/torch/activations.py
Normal file
125
fastNLP/transformers/torch/activations.py
Normal file
@ -0,0 +1,125 @@
|
||||
# Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import math
|
||||
|
||||
from packaging import version
|
||||
|
||||
from fastNLP.envs.imports import _NEED_IMPORT_TORCH
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
if _NEED_IMPORT_TORCH:
|
||||
import torch
|
||||
from torch import nn, tanh, sigmoid
|
||||
from torch.nn.functional import relu
|
||||
else:
|
||||
from fastNLP.core.utils.dummy_class import (
|
||||
DummyClass as relu,
|
||||
DummyClass as tanh,
|
||||
DummyClass as sigmoid,
|
||||
)
|
||||
|
||||
|
||||
def _gelu_python(x):
|
||||
"""
|
||||
Original Implementation of the GELU activation function in Google BERT repo when initially created. For
|
||||
information: OpenAI GPT's GELU is slightly different (and gives slightly different results): 0.5 * x * (1 +
|
||||
torch.tanh(math.sqrt(2 / math.pi) * (x + 0.044715 * torch.pow(x, 3)))) This is now written in C in nn.functional
|
||||
Also see the Gaussian Error Linear Units paper: https://arxiv.org/abs/1606.08415
|
||||
"""
|
||||
return x * 0.5 * (1.0 + torch.erf(x / math.sqrt(2.0)))
|
||||
|
||||
|
||||
def gelu_new(x):
|
||||
"""
|
||||
Implementation of the GELU activation function currently in Google BERT repo (identical to OpenAI GPT). Also see
|
||||
the Gaussian Error Linear Units paper: https://arxiv.org/abs/1606.08415
|
||||
"""
|
||||
return 0.5 * x * (1.0 + torch.tanh(math.sqrt(2.0 / math.pi) * (x + 0.044715 * torch.pow(x, 3.0))))
|
||||
|
||||
if _NEED_IMPORT_TORCH:
|
||||
if version.parse(torch.__version__) < version.parse("1.4"):
|
||||
gelu = _gelu_python
|
||||
else:
|
||||
gelu = nn.functional.gelu
|
||||
else:
|
||||
from fastNLP.core.utils.dummy_class import DummyClass as gelu
|
||||
|
||||
def gelu_fast(x):
|
||||
return 0.5 * x * (1.0 + torch.tanh(x * 0.7978845608 * (1.0 + 0.044715 * x * x)))
|
||||
|
||||
|
||||
def quick_gelu(x):
|
||||
return x * torch.sigmoid(1.702 * x)
|
||||
|
||||
|
||||
def _silu_python(x):
|
||||
"""
|
||||
See Gaussian Error Linear Units (Hendrycks et al., https://arxiv.org/abs/1606.08415) where the SiLU (Sigmoid Linear
|
||||
Unit) was originally introduced and coined, and see Sigmoid-Weighted Linear Units for Neural Network Function
|
||||
Approximation in Reinforcement Learning (Elfwing et al., https://arxiv.org/abs/1702.03118) and Swish: a Self-Gated
|
||||
Activation Function (Ramachandran et al., https://arxiv.org/abs/1710.05941v1) where the SiLU was experimented with
|
||||
later.
|
||||
"""
|
||||
return x * torch.sigmoid(x)
|
||||
|
||||
if _NEED_IMPORT_TORCH:
|
||||
if version.parse(torch.__version__) < version.parse("1.7"):
|
||||
silu = _silu_python
|
||||
else:
|
||||
silu = nn.functional.silu
|
||||
else:
|
||||
from fastNLP.core.utils.dummy_class import DummyClass as silu
|
||||
|
||||
|
||||
def _mish_python(x):
|
||||
"""
|
||||
See Mish: A Self-Regularized Non-Monotonic Activation Function (Misra., https://arxiv.org/abs/1908.08681). Also
|
||||
visit the official repository for the paper: https://github.com/digantamisra98/Mish
|
||||
"""
|
||||
return x * torch.tanh(nn.functional.softplus(x))
|
||||
|
||||
if _NEED_IMPORT_TORCH:
|
||||
if version.parse(torch.__version__) < version.parse("1.9"):
|
||||
mish = _mish_python
|
||||
else:
|
||||
mish = nn.functional.mish
|
||||
else:
|
||||
from fastNLP.core.utils.dummy_class import DummyClass as mish
|
||||
|
||||
|
||||
def linear_act(x):
|
||||
return x
|
||||
|
||||
|
||||
ACT2FN = {
|
||||
"relu": relu,
|
||||
"silu": silu,
|
||||
"swish": silu,
|
||||
"gelu": gelu,
|
||||
"tanh": tanh,
|
||||
"gelu_new": gelu_new,
|
||||
"gelu_fast": gelu_fast,
|
||||
"quick_gelu": quick_gelu,
|
||||
"mish": mish,
|
||||
"linear": linear_act,
|
||||
"sigmoid": sigmoid,
|
||||
}
|
||||
|
||||
|
||||
def get_activation(activation_string):
|
||||
if activation_string in ACT2FN:
|
||||
return ACT2FN[activation_string]
|
||||
else:
|
||||
raise KeyError(f"function {activation_string} not found in ACT2FN mapping {list(ACT2FN.keys())}")
|
777
fastNLP/transformers/torch/configuration_utils.py
Normal file
777
fastNLP/transformers/torch/configuration_utils.py
Normal file
@ -0,0 +1,777 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team.
|
||||
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
""" Configuration base class and utilities."""
|
||||
|
||||
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
from typing import Any, Dict, Tuple, Union
|
||||
|
||||
from . import __version__
|
||||
from .file_utils import (
|
||||
CONFIG_NAME,
|
||||
cached_path,
|
||||
hf_bucket_url,
|
||||
is_offline_mode,
|
||||
is_remote_url,
|
||||
)
|
||||
from fastNLP.envs.imports import _NEED_IMPORT_TORCH
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
|
||||
class PretrainedConfig:
|
||||
r"""
|
||||
Base class for all configuration classes. Handles a few parameters common to all models' configurations as well as
|
||||
methods for loading/downloading/saving configurations.
|
||||
|
||||
Note:
|
||||
A configuration file can be loaded and saved to disk. Loading the configuration file and using this file to
|
||||
initialize a model does **not** load the model weights. It only affects the model's configuration.
|
||||
|
||||
Class attributes (overridden by derived classes)
|
||||
|
||||
- **model_type** (:obj:`str`) -- An identifier for the model type, serialized into the JSON file, and used to
|
||||
recreate the correct object in :class:`~transformers.AutoConfig`.
|
||||
- **is_composition** (:obj:`bool`) -- Whether the config class is composed of multiple sub-configs. In this
|
||||
case the config has to be initialized from two or more configs of type
|
||||
:class:`~transformers.PretrainedConfig` like: :class:`~transformers.EncoderDecoderConfig` or
|
||||
:class:`~RagConfig`.
|
||||
- **keys_to_ignore_at_inference** (:obj:`List[str]`) -- A list of keys to ignore by default when looking at
|
||||
dictionary outputs of the model during inference.
|
||||
- **attribute_map** (:obj:`Dict[str, str]`) -- A dict that maps model specific attribute names to the
|
||||
standardized naming of attributes.
|
||||
|
||||
Common attributes (present in all subclasses)
|
||||
|
||||
- **vocab_size** (:obj:`int`) -- The number of tokens in the vocabulary, which is also the first dimension of
|
||||
the embeddings matrix (this attribute may be missing for models that don't have a text modality like ViT).
|
||||
- **hidden_size** (:obj:`int`) -- The hidden size of the model.
|
||||
- **num_attention_heads** (:obj:`int`) -- The number of attention heads used in the multi-head attention layers
|
||||
of the model.
|
||||
- **num_hidden_layers** (:obj:`int`) -- The number of blocks in the model.
|
||||
|
||||
Args:
|
||||
name_or_path (:obj:`str`, `optional`, defaults to :obj:`""`):
|
||||
Store the string that was passed to :func:`~transformers.PreTrainedModel.from_pretrained` or
|
||||
:func:`~transformers.TFPreTrainedModel.from_pretrained` as ``pretrained_model_name_or_path`` if the
|
||||
configuration was created with such a method.
|
||||
output_hidden_states (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not the model should return all hidden-states.
|
||||
output_attentions (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not the model should returns all attentions.
|
||||
return_dict (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Whether or not the model should return a :class:`~transformers.file_utils.ModelOutput` instead of a plain
|
||||
tuple.
|
||||
is_encoder_decoder (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether the model is used as an encoder/decoder or not.
|
||||
is_decoder (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether the model is used as decoder or not (in which case it's used as an encoder).
|
||||
add_cross_attention (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether cross-attention layers should be added to the model. Note, this option is only relevant for models
|
||||
that can be used as decoder models within the `:class:~transformers.EncoderDecoderModel` class, which
|
||||
consists of all models in ``AUTO_MODELS_FOR_CAUSAL_LM``.
|
||||
tie_encoder_decoder (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether all encoder weights should be tied to their equivalent decoder weights. This requires the encoder
|
||||
and decoder model to have the exact same parameter names.
|
||||
prune_heads (:obj:`Dict[int, List[int]]`, `optional`, defaults to :obj:`{}`):
|
||||
Pruned heads of the model. The keys are the selected layer indices and the associated values, the list of
|
||||
heads to prune in said layer.
|
||||
|
||||
For instance ``{1: [0, 2], 2: [2, 3]}`` will prune heads 0 and 2 on layer 1 and heads 2 and 3 on layer 2.
|
||||
chunk_size_feed_forward (:obj:`int`, `optional`, defaults to :obj:`0`):
|
||||
The chunk size of all feed forward layers in the residual attention blocks. A chunk size of :obj:`0` means
|
||||
that the feed forward layer is not chunked. A chunk size of n means that the feed forward layer processes
|
||||
:obj:`n` < sequence_length embeddings at a time. For more information on feed forward chunking, see `How
|
||||
does Feed Forward Chunking work? <../glossary.html#feed-forward-chunking>`__ .
|
||||
|
||||
Parameters for sequence generation
|
||||
|
||||
- **max_length** (:obj:`int`, `optional`, defaults to 20) -- Maximum length that will be used by default in the
|
||||
:obj:`generate` method of the model.
|
||||
- **min_length** (:obj:`int`, `optional`, defaults to 10) -- Minimum length that will be used by default in the
|
||||
:obj:`generate` method of the model.
|
||||
- **do_sample** (:obj:`bool`, `optional`, defaults to :obj:`False`) -- Flag that will be used by default in the
|
||||
:obj:`generate` method of the model. Whether or not to use sampling ; use greedy decoding otherwise.
|
||||
- **early_stopping** (:obj:`bool`, `optional`, defaults to :obj:`False`) -- Flag that will be used by default
|
||||
in the :obj:`generate` method of the model. Whether to stop the beam search when at least ``num_beams``
|
||||
sentences are finished per batch or not.
|
||||
- **num_beams** (:obj:`int`, `optional`, defaults to 1) -- Number of beams for beam search that will be used by
|
||||
default in the :obj:`generate` method of the model. 1 means no beam search.
|
||||
- **num_beam_groups** (:obj:`int`, `optional`, defaults to 1) -- Number of groups to divide :obj:`num_beams`
|
||||
into in order to ensure diversity among different groups of beams that will be used by default in the
|
||||
:obj:`generate` method of the model. 1 means no group beam search.
|
||||
- **diversity_penalty** (:obj:`float`, `optional`, defaults to 0.0) -- Value to control diversity for group
|
||||
beam search. that will be used by default in the :obj:`generate` method of the model. 0 means no diversity
|
||||
penalty. The higher the penalty, the more diverse are the outputs.
|
||||
- **temperature** (:obj:`float`, `optional`, defaults to 1) -- The value used to module the next token
|
||||
probabilities that will be used by default in the :obj:`generate` method of the model. Must be strictly
|
||||
positive.
|
||||
- **top_k** (:obj:`int`, `optional`, defaults to 50) -- Number of highest probability vocabulary tokens to keep
|
||||
for top-k-filtering that will be used by default in the :obj:`generate` method of the model.
|
||||
- **top_p** (:obj:`float`, `optional`, defaults to 1) -- Value that will be used by default in the
|
||||
:obj:`generate` method of the model for ``top_p``. If set to float < 1, only the most probable tokens with
|
||||
probabilities that add up to ``top_p`` or higher are kept for generation.
|
||||
- **repetition_penalty** (:obj:`float`, `optional`, defaults to 1) -- Parameter for repetition penalty that
|
||||
will be used by default in the :obj:`generate` method of the model. 1.0 means no penalty.
|
||||
- **length_penalty** (:obj:`float`, `optional`, defaults to 1) -- Exponential penalty to the length that will
|
||||
be used by default in the :obj:`generate` method of the model.
|
||||
- **no_repeat_ngram_size** (:obj:`int`, `optional`, defaults to 0) -- Value that will be used by default in the
|
||||
:obj:`generate` method of the model for ``no_repeat_ngram_size``. If set to int > 0, all ngrams of that size
|
||||
can only occur once.
|
||||
- **encoder_no_repeat_ngram_size** (:obj:`int`, `optional`, defaults to 0) -- Value that will be used by
|
||||
default in the :obj:`generate` method of the model for ``encoder_no_repeat_ngram_size``. If set to int > 0,
|
||||
all ngrams of that size that occur in the ``encoder_input_ids`` cannot occur in the ``decoder_input_ids``.
|
||||
- **bad_words_ids** (:obj:`List[int]`, `optional`) -- List of token ids that are not allowed to be generated
|
||||
that will be used by default in the :obj:`generate` method of the model. In order to get the tokens of the
|
||||
words that should not appear in the generated text, use :obj:`tokenizer.encode(bad_word,
|
||||
add_prefix_space=True)`.
|
||||
- **num_return_sequences** (:obj:`int`, `optional`, defaults to 1) -- Number of independently computed returned
|
||||
sequences for each element in the batch that will be used by default in the :obj:`generate` method of the
|
||||
model.
|
||||
- **output_scores** (:obj:`bool`, `optional`, defaults to :obj:`False`) -- Whether the model should return the
|
||||
logits when used for generation
|
||||
- **return_dict_in_generate** (:obj:`bool`, `optional`, defaults to :obj:`False`) -- Whether the model should
|
||||
return a :class:`~transformers.file_utils.ModelOutput` instead of a :obj:`torch.LongTensor`
|
||||
- **forced_bos_token_id** (:obj:`int`, `optional`) -- The id of the token to force as the first generated token
|
||||
after the :obj:`decoder_start_token_id`. Useful for multilingual models like :doc:`mBART
|
||||
<../model_doc/mbart>` where the first generated token needs to be the target language token.
|
||||
- **forced_eos_token_id** (:obj:`int`, `optional`) -- The id of the token to force as the last generated token
|
||||
when :obj:`max_length` is reached.
|
||||
- **remove_invalid_values** (:obj:`bool`, `optional`) -- Whether to remove possible `nan` and `inf` outputs of
|
||||
the model to prevent the generation method to crash. Note that using ``remove_invalid_values`` can slow down
|
||||
generation.
|
||||
|
||||
|
||||
Parameters for fine-tuning tasks
|
||||
|
||||
- **architectures** (:obj:`List[str]`, `optional`) -- Model architectures that can be used with the model
|
||||
pretrained weights.
|
||||
- **finetuning_task** (:obj:`str`, `optional`) -- Name of the task used to fine-tune the model. This can be
|
||||
used when converting from an original (TensorFlow or PyTorch) checkpoint.
|
||||
- **id2label** (:obj:`Dict[int, str]`, `optional`) -- A map from index (for instance prediction index, or
|
||||
target index) to label.
|
||||
- **label2id** (:obj:`Dict[str, int]`, `optional`) -- A map from label to index for the model.
|
||||
- **num_labels** (:obj:`int`, `optional`) -- Number of labels to use in the last layer added to the model,
|
||||
typically for a classification task.
|
||||
- **task_specific_params** (:obj:`Dict[str, Any]`, `optional`) -- Additional keyword arguments to store for the
|
||||
current task.
|
||||
- **problem_type** (:obj:`str`, `optional`) -- Problem type for :obj:`XxxForSequenceClassification` models. Can
|
||||
be one of (:obj:`"regression"`, :obj:`"single_label_classification"`, :obj:`"multi_label_classification"`).
|
||||
Please note that this parameter is only available in the following models: `AlbertForSequenceClassification`,
|
||||
`BertForSequenceClassification`, `BigBirdForSequenceClassification`, `ConvBertForSequenceClassification`,
|
||||
`DistilBertForSequenceClassification`, `ElectraForSequenceClassification`, `FunnelForSequenceClassification`,
|
||||
`LongformerForSequenceClassification`, `MobileBertForSequenceClassification`,
|
||||
`ReformerForSequenceClassification`, `RobertaForSequenceClassification`,
|
||||
`SqueezeBertForSequenceClassification`, `XLMForSequenceClassification` and `XLNetForSequenceClassification`.
|
||||
|
||||
Parameters linked to the tokenizer
|
||||
|
||||
- **tokenizer_class** (:obj:`str`, `optional`) -- The name of the associated tokenizer class to use (if none is
|
||||
set, will use the tokenizer associated to the model by default).
|
||||
- **prefix** (:obj:`str`, `optional`) -- A specific prompt that should be added at the beginning of each text
|
||||
before calling the model.
|
||||
- **bos_token_id** (:obj:`int`, `optional`)) -- The id of the `beginning-of-stream` token.
|
||||
- **pad_token_id** (:obj:`int`, `optional`)) -- The id of the `padding` token.
|
||||
- **eos_token_id** (:obj:`int`, `optional`)) -- The id of the `end-of-stream` token.
|
||||
- **decoder_start_token_id** (:obj:`int`, `optional`)) -- If an encoder-decoder model starts decoding with a
|
||||
different token than `bos`, the id of that token.
|
||||
- **sep_token_id** (:obj:`int`, `optional`)) -- The id of the `separation` token.
|
||||
|
||||
PyTorch specific parameters
|
||||
|
||||
- **torchscript** (:obj:`bool`, `optional`, defaults to :obj:`False`) -- Whether or not the model should be
|
||||
used with Torchscript.
|
||||
- **tie_word_embeddings** (:obj:`bool`, `optional`, defaults to :obj:`True`) -- Whether the model's input and
|
||||
output word embeddings should be tied. Note that this is only relevant if the model has a output word
|
||||
embedding layer.
|
||||
- **torch_dtype** (:obj:`str`, `optional`) -- The :obj:`dtype` of the weights. This attribute can be used to
|
||||
initialize the model to a non-default ``dtype`` (which is normally ``float32``) and thus allow for optimal
|
||||
storage allocation. For example, if the saved model is ``float16``, ideally we want to load it back using the
|
||||
minimal amount of memory needed to load ``float16`` weights. Since the config object is stored in plain text,
|
||||
this attribute contains just the floating type string without the ``torch.`` prefix. For example, for
|
||||
``torch.float16`` ``torch_dtype`` is the ``"float16"`` string.
|
||||
|
||||
This attribute is currently not being used during model loading time, but this may change in the future
|
||||
versions. But we can already start preparing for the future by saving the dtype with save_pretrained.
|
||||
|
||||
TensorFlow specific parameters
|
||||
|
||||
- **use_bfloat16** (:obj:`bool`, `optional`, defaults to :obj:`False`) -- Whether or not the model should use
|
||||
BFloat16 scalars (only used by some TensorFlow models).
|
||||
"""
|
||||
model_type: str = ""
|
||||
is_composition: bool = False
|
||||
attribute_map: Dict[str, str] = {}
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
if key in super().__getattribute__("attribute_map"):
|
||||
key = super().__getattribute__("attribute_map")[key]
|
||||
super().__setattr__(key, value)
|
||||
|
||||
def __getattribute__(self, key):
|
||||
if key != "attribute_map" and key in super().__getattribute__("attribute_map"):
|
||||
key = super().__getattribute__("attribute_map")[key]
|
||||
return super().__getattribute__(key)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
# Attributes with defaults
|
||||
self.return_dict = kwargs.pop("return_dict", True)
|
||||
self.output_hidden_states = kwargs.pop("output_hidden_states", False)
|
||||
self.output_attentions = kwargs.pop("output_attentions", False)
|
||||
self.torchscript = kwargs.pop("torchscript", False) # Only used by PyTorch models
|
||||
self.torch_dtype = kwargs.pop("torch_dtype", None) # Only used by PyTorch models
|
||||
self.use_bfloat16 = kwargs.pop("use_bfloat16", False)
|
||||
self.pruned_heads = kwargs.pop("pruned_heads", {})
|
||||
self.tie_word_embeddings = kwargs.pop(
|
||||
"tie_word_embeddings", True
|
||||
) # Whether input and output word embeddings should be tied for all MLM, LM and Seq2Seq models.
|
||||
|
||||
# Is decoder is used in encoder-decoder models to differentiate encoder from decoder
|
||||
self.is_encoder_decoder = kwargs.pop("is_encoder_decoder", False)
|
||||
self.is_decoder = kwargs.pop("is_decoder", False)
|
||||
self.add_cross_attention = kwargs.pop("add_cross_attention", False)
|
||||
self.tie_encoder_decoder = kwargs.pop("tie_encoder_decoder", False)
|
||||
|
||||
# Parameters for sequence generation
|
||||
self.max_length = kwargs.pop("max_length", 20)
|
||||
self.min_length = kwargs.pop("min_length", 0)
|
||||
self.do_sample = kwargs.pop("do_sample", False)
|
||||
self.early_stopping = kwargs.pop("early_stopping", False)
|
||||
self.num_beams = kwargs.pop("num_beams", 1)
|
||||
self.num_beam_groups = kwargs.pop("num_beam_groups", 1)
|
||||
self.diversity_penalty = kwargs.pop("diversity_penalty", 0.0)
|
||||
self.temperature = kwargs.pop("temperature", 1.0)
|
||||
self.top_k = kwargs.pop("top_k", 50)
|
||||
self.top_p = kwargs.pop("top_p", 1.0)
|
||||
self.repetition_penalty = kwargs.pop("repetition_penalty", 1.0)
|
||||
self.length_penalty = kwargs.pop("length_penalty", 1.0)
|
||||
self.no_repeat_ngram_size = kwargs.pop("no_repeat_ngram_size", 0)
|
||||
self.encoder_no_repeat_ngram_size = kwargs.pop("encoder_no_repeat_ngram_size", 0)
|
||||
self.bad_words_ids = kwargs.pop("bad_words_ids", None)
|
||||
self.num_return_sequences = kwargs.pop("num_return_sequences", 1)
|
||||
self.chunk_size_feed_forward = kwargs.pop("chunk_size_feed_forward", 0)
|
||||
self.output_scores = kwargs.pop("output_scores", False)
|
||||
self.return_dict_in_generate = kwargs.pop("return_dict_in_generate", False)
|
||||
self.forced_bos_token_id = kwargs.pop("forced_bos_token_id", None)
|
||||
self.forced_eos_token_id = kwargs.pop("forced_eos_token_id", None)
|
||||
self.remove_invalid_values = kwargs.pop("remove_invalid_values", False)
|
||||
|
||||
# Fine-tuning task arguments
|
||||
self.architectures = kwargs.pop("architectures", None)
|
||||
self.finetuning_task = kwargs.pop("finetuning_task", None)
|
||||
self.id2label = kwargs.pop("id2label", None)
|
||||
self.label2id = kwargs.pop("label2id", None)
|
||||
if self.id2label is not None:
|
||||
kwargs.pop("num_labels", None)
|
||||
self.id2label = dict((int(key), value) for key, value in self.id2label.items())
|
||||
# Keys are always strings in JSON so convert ids to int here.
|
||||
else:
|
||||
self.num_labels = kwargs.pop("num_labels", 2)
|
||||
|
||||
if self.torch_dtype is not None and isinstance(self.torch_dtype, str):
|
||||
# we will start using self.torch_dtype in v5, but to be consistent with
|
||||
# from_pretrained's torch_dtype arg convert it to an actual torch.dtype object
|
||||
if _NEED_IMPORT_TORCH:
|
||||
import torch
|
||||
|
||||
self.torch_dtype = getattr(torch, self.torch_dtype)
|
||||
|
||||
# Tokenizer arguments TODO: eventually tokenizer and models should share the same config
|
||||
self.tokenizer_class = kwargs.pop("tokenizer_class", None)
|
||||
self.prefix = kwargs.pop("prefix", None)
|
||||
self.bos_token_id = kwargs.pop("bos_token_id", None)
|
||||
self.pad_token_id = kwargs.pop("pad_token_id", None)
|
||||
self.eos_token_id = kwargs.pop("eos_token_id", None)
|
||||
self.sep_token_id = kwargs.pop("sep_token_id", None)
|
||||
|
||||
self.decoder_start_token_id = kwargs.pop("decoder_start_token_id", None)
|
||||
|
||||
# task specific arguments
|
||||
self.task_specific_params = kwargs.pop("task_specific_params", None)
|
||||
|
||||
# regression / multi-label classification
|
||||
self.problem_type = kwargs.pop("problem_type", None)
|
||||
allowed_problem_types = ("regression", "single_label_classification", "multi_label_classification")
|
||||
if self.problem_type is not None and self.problem_type not in allowed_problem_types:
|
||||
raise ValueError(
|
||||
f"The config parameter `problem_type` was not understood: received {self.problem_type}"
|
||||
"but only 'regression', 'single_label_classification' and 'multi_label_classification' are valid."
|
||||
)
|
||||
|
||||
# TPU arguments
|
||||
if kwargs.pop("xla_device", None) is not None:
|
||||
logger.warning(
|
||||
"The `xla_device` argument has been deprecated in v4.4.0 of Transformers. It is ignored and you can "
|
||||
"safely remove it from your `config.json` file."
|
||||
)
|
||||
|
||||
# Name or path to the pretrained checkpoint
|
||||
self._name_or_path = str(kwargs.pop("name_or_path", ""))
|
||||
|
||||
# Drop the transformers version info
|
||||
self.transformers_version = kwargs.pop("transformers_version", None)
|
||||
|
||||
# Deal with gradient checkpointing
|
||||
if kwargs.get("gradient_checkpointing", False):
|
||||
logger.warn(
|
||||
"Passing `gradient_checkpointing` to a config initialization is deprecated and will be removed in v5 "
|
||||
"Transformers. Using `model.gradient_checkpointing_enable()` instead, or if you are using the "
|
||||
"`Trainer` API, pass `gradient_checkpointing=True` in your `TrainingArguments`."
|
||||
)
|
||||
|
||||
# Additional attributes without default values
|
||||
for key, value in kwargs.items():
|
||||
try:
|
||||
setattr(self, key, value)
|
||||
except AttributeError as err:
|
||||
logger.error(f"Can't set {key} with value {value} for {self}")
|
||||
raise err
|
||||
|
||||
@property
|
||||
def name_or_path(self) -> str:
|
||||
return self._name_or_path
|
||||
|
||||
@name_or_path.setter
|
||||
def name_or_path(self, value):
|
||||
self._name_or_path = str(value) # Make sure that name_or_path is a string (for JSON encoding)
|
||||
|
||||
@property
|
||||
def use_return_dict(self) -> bool:
|
||||
"""
|
||||
:obj:`bool`: Whether or not return :class:`~transformers.file_utils.ModelOutput` instead of tuples.
|
||||
"""
|
||||
# If torchscript is set, force `return_dict=False` to avoid jit errors
|
||||
return self.return_dict and not self.torchscript
|
||||
|
||||
@property
|
||||
def num_labels(self) -> int:
|
||||
"""
|
||||
:obj:`int`: The number of labels for classification models.
|
||||
"""
|
||||
return len(self.id2label)
|
||||
|
||||
@num_labels.setter
|
||||
def num_labels(self, num_labels: int):
|
||||
if not hasattr(self, "id2label") or self.id2label is None or len(self.id2label) != num_labels:
|
||||
self.id2label = {i: f"LABEL_{i}" for i in range(num_labels)}
|
||||
self.label2id = dict(zip(self.id2label.values(), self.id2label.keys()))
|
||||
|
||||
def save_pretrained(self, save_directory: Union[str, os.PathLike], **kwargs):
|
||||
"""
|
||||
Save a configuration object to the directory ``save_directory``, so that it can be re-loaded using the
|
||||
:func:`~transformers.PretrainedConfig.from_pretrained` class method.
|
||||
|
||||
Args:
|
||||
save_directory (:obj:`str` or :obj:`os.PathLike`):
|
||||
Directory where the configuration JSON file will be saved (will be created if it does not exist).
|
||||
push_to_hub (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to push your model to the Hugging Face model hub after saving it.
|
||||
|
||||
.. warning::
|
||||
|
||||
Using :obj:`push_to_hub=True` will synchronize the repository you are pushing to with
|
||||
:obj:`save_directory`, which requires :obj:`save_directory` to be a local clone of the repo you are
|
||||
pushing to if it's an existing folder. Pass along :obj:`temp_dir=True` to use a temporary directory
|
||||
instead.
|
||||
|
||||
kwargs:
|
||||
Additional key word arguments passed along to the
|
||||
:meth:`~transformers.file_utils.PushToHubMixin.push_to_hub` method.
|
||||
"""
|
||||
if os.path.isfile(save_directory):
|
||||
raise AssertionError(f"Provided path ({save_directory}) should be a directory, not a file")
|
||||
|
||||
os.makedirs(save_directory, exist_ok=True)
|
||||
# If we save using the predefined names, we can load using `from_pretrained`
|
||||
output_config_file = os.path.join(save_directory, CONFIG_NAME)
|
||||
|
||||
self.to_json_file(output_config_file, use_diff=True)
|
||||
logger.info(f"Configuration saved in {output_config_file}")
|
||||
|
||||
@classmethod
|
||||
def from_pretrained(cls, pretrained_model_name_or_path: Union[str, os.PathLike], **kwargs) -> "PretrainedConfig":
|
||||
r"""
|
||||
Instantiate a :class:`~transformers.PretrainedConfig` (or a derived class) from a pretrained model
|
||||
configuration.
|
||||
|
||||
Args:
|
||||
pretrained_model_name_or_path (:obj:`str` or :obj:`os.PathLike`):
|
||||
This can be either:
|
||||
|
||||
- a string, the `model id` of a pretrained model configuration hosted inside a model repo on
|
||||
huggingface.co. Valid model ids can be located at the root-level, like ``bert-base-uncased``, or
|
||||
namespaced under a user or organization name, like ``dbmdz/bert-base-german-cased``.
|
||||
- a path to a `directory` containing a configuration file saved using the
|
||||
:func:`~transformers.PretrainedConfig.save_pretrained` method, e.g., ``./my_model_directory/``.
|
||||
- a path or url to a saved configuration JSON `file`, e.g.,
|
||||
``./my_model_directory/configuration.json``.
|
||||
cache_dir (:obj:`str` or :obj:`os.PathLike`, `optional`):
|
||||
Path to a directory in which a downloaded pretrained model configuration should be cached if the
|
||||
standard cache should not be used.
|
||||
force_download (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to force to (re-)download the configuration files and override the cached versions if
|
||||
they exist.
|
||||
resume_download (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to delete incompletely received file. Attempts to resume the download if such a file
|
||||
exists.
|
||||
proxies (:obj:`Dict[str, str]`, `optional`):
|
||||
A dictionary of proxy servers to use by protocol or endpoint, e.g., :obj:`{'http': 'foo.bar:3128',
|
||||
'http://hostname': 'foo.bar:4012'}.` The proxies are used on each request.
|
||||
use_auth_token (:obj:`str` or `bool`, `optional`):
|
||||
The token to use as HTTP bearer authorization for remote files. If :obj:`True`, will use the token
|
||||
generated when running :obj:`transformers-cli login` (stored in :obj:`~/.huggingface`).
|
||||
revision(:obj:`str`, `optional`, defaults to :obj:`"main"`):
|
||||
The specific model version to use. It can be a branch name, a tag name, or a commit id, since we use a
|
||||
git-based system for storing models and other artifacts on huggingface.co, so ``revision`` can be any
|
||||
identifier allowed by git.
|
||||
return_unused_kwargs (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
If :obj:`False`, then this function returns just the final configuration object.
|
||||
|
||||
If :obj:`True`, then this functions returns a :obj:`Tuple(config, unused_kwargs)` where `unused_kwargs`
|
||||
is a dictionary consisting of the key/value pairs whose keys are not configuration attributes: i.e.,
|
||||
the part of ``kwargs`` which has not been used to update ``config`` and is otherwise ignored.
|
||||
kwargs (:obj:`Dict[str, Any]`, `optional`):
|
||||
The values in kwargs of any keys which are configuration attributes will be used to override the loaded
|
||||
values. Behavior concerning key/value pairs whose keys are *not* configuration attributes is controlled
|
||||
by the ``return_unused_kwargs`` keyword parameter.
|
||||
|
||||
.. note::
|
||||
|
||||
Passing :obj:`use_auth_token=True` is required when you want to use a private model.
|
||||
|
||||
|
||||
Returns:
|
||||
:class:`PretrainedConfig`: The configuration object instantiated from this pretrained model.
|
||||
|
||||
Examples::
|
||||
|
||||
# We can't instantiate directly the base class `PretrainedConfig` so let's show the examples on a
|
||||
# derived class: BertConfig
|
||||
config = BertConfig.from_pretrained('bert-base-uncased') # Download configuration from huggingface.co and cache.
|
||||
config = BertConfig.from_pretrained('./test/saved_model/') # E.g. config (or model) was saved using `save_pretrained('./test/saved_model/')`
|
||||
config = BertConfig.from_pretrained('./test/saved_model/my_configuration.json')
|
||||
config = BertConfig.from_pretrained('bert-base-uncased', output_attentions=True, foo=False)
|
||||
assert config.output_attentions == True
|
||||
config, unused_kwargs = BertConfig.from_pretrained('bert-base-uncased', output_attentions=True,
|
||||
foo=False, return_unused_kwargs=True)
|
||||
assert config.output_attentions == True
|
||||
assert unused_kwargs == {'foo': False}
|
||||
|
||||
"""
|
||||
config_dict, kwargs = cls.get_config_dict(pretrained_model_name_or_path, **kwargs)
|
||||
if "model_type" in config_dict and hasattr(cls, "model_type") and config_dict["model_type"] != cls.model_type:
|
||||
logger.warn(
|
||||
f"You are using a model of type {config_dict['model_type']} to instantiate a model of type "
|
||||
f"{cls.model_type}. This is not supported for all configurations of models and can yield errors."
|
||||
)
|
||||
|
||||
return cls.from_dict(config_dict, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def get_config_dict(
|
||||
cls, pretrained_model_name_or_path: Union[str, os.PathLike], **kwargs
|
||||
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
||||
"""
|
||||
From a ``pretrained_model_name_or_path``, resolve to a dictionary of parameters, to be used for instantiating a
|
||||
:class:`~transformers.PretrainedConfig` using ``from_dict``.
|
||||
|
||||
|
||||
|
||||
Parameters:
|
||||
pretrained_model_name_or_path (:obj:`str` or :obj:`os.PathLike`):
|
||||
The identifier of the pre-trained checkpoint from which we want the dictionary of parameters.
|
||||
|
||||
Returns:
|
||||
:obj:`Tuple[Dict, Dict]`: The dictionary(ies) that will be used to instantiate the configuration object.
|
||||
|
||||
"""
|
||||
cache_dir = kwargs.pop("cache_dir", None)
|
||||
force_download = kwargs.pop("force_download", False)
|
||||
resume_download = kwargs.pop("resume_download", False)
|
||||
proxies = kwargs.pop("proxies", None)
|
||||
use_auth_token = kwargs.pop("use_auth_token", None)
|
||||
local_files_only = kwargs.pop("local_files_only", False)
|
||||
revision = kwargs.pop("revision", None)
|
||||
from_pipeline = kwargs.pop("_from_pipeline", None)
|
||||
from_auto_class = kwargs.pop("_from_auto", False)
|
||||
|
||||
user_agent = {"file_type": "config", "from_auto_class": from_auto_class}
|
||||
if from_pipeline is not None:
|
||||
user_agent["using_pipeline"] = from_pipeline
|
||||
|
||||
if is_offline_mode() and not local_files_only:
|
||||
logger.info("Offline mode: forcing local_files_only=True")
|
||||
local_files_only = True
|
||||
|
||||
pretrained_model_name_or_path = str(pretrained_model_name_or_path)
|
||||
if os.path.isdir(pretrained_model_name_or_path):
|
||||
config_file = os.path.join(pretrained_model_name_or_path, CONFIG_NAME)
|
||||
elif os.path.isfile(pretrained_model_name_or_path) or is_remote_url(pretrained_model_name_or_path):
|
||||
config_file = pretrained_model_name_or_path
|
||||
else:
|
||||
config_file = hf_bucket_url(
|
||||
pretrained_model_name_or_path, filename=CONFIG_NAME, revision=revision, mirror=None
|
||||
)
|
||||
|
||||
try:
|
||||
# Load from URL or cache if already cached
|
||||
resolved_config_file = cached_path(
|
||||
config_file,
|
||||
cache_dir=cache_dir,
|
||||
force_download=force_download,
|
||||
proxies=proxies,
|
||||
resume_download=resume_download,
|
||||
local_files_only=local_files_only,
|
||||
use_auth_token=use_auth_token,
|
||||
user_agent=user_agent,
|
||||
)
|
||||
# Load config dict
|
||||
config_dict = cls._dict_from_json_file(resolved_config_file)
|
||||
|
||||
except EnvironmentError as err:
|
||||
logger.error(err)
|
||||
msg = (
|
||||
f"Can't load config for '{pretrained_model_name_or_path}'. Make sure that:\n\n"
|
||||
f"- '{pretrained_model_name_or_path}' is a correct model identifier listed on 'https://huggingface.co/models'\n\n"
|
||||
f"- or '{pretrained_model_name_or_path}' is the correct path to a directory containing a {CONFIG_NAME} file\n\n"
|
||||
)
|
||||
|
||||
if revision is not None:
|
||||
msg += f"- or '{revision}' is a valid git identifier (branch name, a tag name, or a commit id) that exists for this model name as listed on its model page on 'https://huggingface.co/models'\n\n"
|
||||
|
||||
raise EnvironmentError(msg)
|
||||
|
||||
except (json.JSONDecodeError, UnicodeDecodeError):
|
||||
msg = (
|
||||
f"Couldn't reach server at '{config_file}' to download configuration file or "
|
||||
"configuration file is not a valid JSON file. "
|
||||
f"Please check network or file content here: {resolved_config_file}."
|
||||
)
|
||||
raise EnvironmentError(msg)
|
||||
|
||||
if resolved_config_file == config_file:
|
||||
logger.info(f"loading configuration file {config_file}")
|
||||
else:
|
||||
logger.info(f"loading configuration file {config_file} from cache at {resolved_config_file}")
|
||||
|
||||
return config_dict, kwargs
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, config_dict: Dict[str, Any], **kwargs) -> "PretrainedConfig":
|
||||
"""
|
||||
Instantiates a :class:`~transformers.PretrainedConfig` from a Python dictionary of parameters.
|
||||
|
||||
Args:
|
||||
config_dict (:obj:`Dict[str, Any]`):
|
||||
Dictionary that will be used to instantiate the configuration object. Such a dictionary can be
|
||||
retrieved from a pretrained checkpoint by leveraging the
|
||||
:func:`~transformers.PretrainedConfig.get_config_dict` method.
|
||||
kwargs (:obj:`Dict[str, Any]`):
|
||||
Additional parameters from which to initialize the configuration object.
|
||||
|
||||
Returns:
|
||||
:class:`PretrainedConfig`: The configuration object instantiated from those parameters.
|
||||
"""
|
||||
return_unused_kwargs = kwargs.pop("return_unused_kwargs", False)
|
||||
|
||||
config = cls(**config_dict)
|
||||
|
||||
if hasattr(config, "pruned_heads"):
|
||||
config.pruned_heads = dict((int(key), value) for key, value in config.pruned_heads.items())
|
||||
|
||||
# Update config with kwargs if needed
|
||||
to_remove = []
|
||||
for key, value in kwargs.items():
|
||||
if hasattr(config, key):
|
||||
setattr(config, key, value)
|
||||
if key != "torch_dtype":
|
||||
to_remove.append(key)
|
||||
for key in to_remove:
|
||||
kwargs.pop(key, None)
|
||||
|
||||
logger.info(f"Model config {config}")
|
||||
if return_unused_kwargs:
|
||||
return config, kwargs
|
||||
else:
|
||||
return config
|
||||
|
||||
@classmethod
|
||||
def from_json_file(cls, json_file: Union[str, os.PathLike]) -> "PretrainedConfig":
|
||||
"""
|
||||
Instantiates a :class:`~transformers.PretrainedConfig` from the path to a JSON file of parameters.
|
||||
|
||||
Args:
|
||||
json_file (:obj:`str` or :obj:`os.PathLike`):
|
||||
Path to the JSON file containing the parameters.
|
||||
|
||||
Returns:
|
||||
:class:`PretrainedConfig`: The configuration object instantiated from that JSON file.
|
||||
|
||||
"""
|
||||
config_dict = cls._dict_from_json_file(json_file)
|
||||
return cls(**config_dict)
|
||||
|
||||
@classmethod
|
||||
def _dict_from_json_file(cls, json_file: Union[str, os.PathLike]):
|
||||
with open(json_file, "r", encoding="utf-8") as reader:
|
||||
text = reader.read()
|
||||
return json.loads(text)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__dict__ == other.__dict__
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__} {self.to_json_string()}"
|
||||
|
||||
def to_diff_dict(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Removes all attributes from config which correspond to the default config attributes for better readability and
|
||||
serializes to a Python dictionary.
|
||||
|
||||
Returns:
|
||||
:obj:`Dict[str, Any]`: Dictionary of all the attributes that make up this configuration instance,
|
||||
"""
|
||||
config_dict = self.to_dict()
|
||||
|
||||
# get the default config dict
|
||||
default_config_dict = PretrainedConfig().to_dict()
|
||||
|
||||
# get class specific config dict
|
||||
class_config_dict = self.__class__().to_dict() if not self.is_composition else {}
|
||||
|
||||
serializable_config_dict = {}
|
||||
|
||||
# only serialize values that differ from the default config
|
||||
for key, value in config_dict.items():
|
||||
if (
|
||||
key not in default_config_dict
|
||||
or key == "transformers_version"
|
||||
or value != default_config_dict[key]
|
||||
or (key in class_config_dict and value != class_config_dict[key])
|
||||
):
|
||||
serializable_config_dict[key] = value
|
||||
|
||||
self.dict_torch_dtype_to_str(serializable_config_dict)
|
||||
|
||||
return serializable_config_dict
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Serializes this instance to a Python dictionary.
|
||||
|
||||
Returns:
|
||||
:obj:`Dict[str, Any]`: Dictionary of all the attributes that make up this configuration instance.
|
||||
"""
|
||||
output = copy.deepcopy(self.__dict__)
|
||||
if hasattr(self.__class__, "model_type"):
|
||||
output["model_type"] = self.__class__.model_type
|
||||
|
||||
# Transformers version when serializing the model
|
||||
output["transformers_version"] = __version__
|
||||
|
||||
self.dict_torch_dtype_to_str(output)
|
||||
|
||||
return output
|
||||
|
||||
def to_json_string(self, use_diff: bool = True) -> str:
|
||||
"""
|
||||
Serializes this instance to a JSON string.
|
||||
|
||||
Args:
|
||||
use_diff (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
If set to ``True``, only the difference between the config instance and the default
|
||||
``PretrainedConfig()`` is serialized to JSON string.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: String containing all the attributes that make up this configuration instance in JSON format.
|
||||
"""
|
||||
if use_diff is True:
|
||||
config_dict = self.to_diff_dict()
|
||||
else:
|
||||
config_dict = self.to_dict()
|
||||
return json.dumps(config_dict, indent=2, sort_keys=True) + "\n"
|
||||
|
||||
def to_json_file(self, json_file_path: Union[str, os.PathLike], use_diff: bool = True):
|
||||
"""
|
||||
Save this instance to a JSON file.
|
||||
|
||||
Args:
|
||||
json_file_path (:obj:`str` or :obj:`os.PathLike`):
|
||||
Path to the JSON file in which this configuration instance's parameters will be saved.
|
||||
use_diff (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
If set to ``True``, only the difference between the config instance and the default
|
||||
``PretrainedConfig()`` is serialized to JSON file.
|
||||
"""
|
||||
with open(json_file_path, "w", encoding="utf-8") as writer:
|
||||
writer.write(self.to_json_string(use_diff=use_diff))
|
||||
|
||||
def update(self, config_dict: Dict[str, Any]):
|
||||
"""
|
||||
Updates attributes of this class with attributes from ``config_dict``.
|
||||
|
||||
Args:
|
||||
config_dict (:obj:`Dict[str, Any]`): Dictionary of attributes that should be updated for this class.
|
||||
"""
|
||||
for key, value in config_dict.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
def update_from_string(self, update_str: str):
|
||||
"""
|
||||
Updates attributes of this class with attributes from ``update_str``.
|
||||
|
||||
The expected format is ints, floats and strings as is, and for booleans use ``true`` or ``false``. For example:
|
||||
"n_embd=10,resid_pdrop=0.2,scale_attn_weights=false,summary_type=cls_index"
|
||||
|
||||
The keys to change have to already exist in the config object.
|
||||
|
||||
Args:
|
||||
update_str (:obj:`str`): String with attributes that should be updated for this class.
|
||||
|
||||
"""
|
||||
|
||||
d = dict(x.split("=") for x in update_str.split(","))
|
||||
for k, v in d.items():
|
||||
if not hasattr(self, k):
|
||||
raise ValueError(f"key {k} isn't in the original config dict")
|
||||
|
||||
old_v = getattr(self, k)
|
||||
if isinstance(old_v, bool):
|
||||
if v.lower() in ["true", "1", "y", "yes"]:
|
||||
v = True
|
||||
elif v.lower() in ["false", "0", "n", "no"]:
|
||||
v = False
|
||||
else:
|
||||
raise ValueError(f"can't derive true or false from {v} (key {k})")
|
||||
elif isinstance(old_v, int):
|
||||
v = int(v)
|
||||
elif isinstance(old_v, float):
|
||||
v = float(v)
|
||||
elif not isinstance(old_v, str):
|
||||
raise ValueError(
|
||||
f"You can only update int, float, bool or string values in the config, got {v} for key {k}"
|
||||
)
|
||||
|
||||
setattr(self, k, v)
|
||||
|
||||
def dict_torch_dtype_to_str(self, d: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Checks whether the passed dictionary has a `torch_dtype` key and if it's not None, converts torch.dtype to a
|
||||
string of just the type. For example, :obj:`torch.float32` get converted into `"float32"` string, which can
|
||||
then be stored in the json format.
|
||||
"""
|
||||
if d.get("torch_dtype", None) is not None and not isinstance(d["torch_dtype"], str):
|
||||
d["torch_dtype"] = str(d["torch_dtype"]).split(".")[1]
|
388
fastNLP/transformers/torch/deepspeed.py
Normal file
388
fastNLP/transformers/torch/deepspeed.py
Normal file
@ -0,0 +1,388 @@
|
||||
# Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
Integration with Deepspeed
|
||||
"""
|
||||
|
||||
import importlib.util
|
||||
import io
|
||||
import json
|
||||
import weakref
|
||||
from copy import deepcopy
|
||||
from functools import partialmethod
|
||||
|
||||
from .dependency_versions_check import dep_version_check
|
||||
from fastNLP.envs.imports import _NEED_IMPORT_TORCH
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
if _NEED_IMPORT_TORCH:
|
||||
import torch
|
||||
|
||||
|
||||
def is_deepspeed_available():
|
||||
return importlib.util.find_spec("deepspeed") is not None
|
||||
|
||||
|
||||
class HfDeepSpeedConfig:
|
||||
"""
|
||||
This object contains a DeepSpeed configuration dictionary and can be quickly queried for things like zero stage.
|
||||
|
||||
A ``weakref`` of this object is stored in the module's globals to be able to access the config from areas where
|
||||
things like the Trainer object is not available (e.g. ``from_pretrained`` and ``_get_resized_embeddings``).
|
||||
Therefore it's important that this object remains alive while the program is still running.
|
||||
|
||||
:class:`~transformers.Trainer` uses the ``HfTrainerDeepSpeedConfig`` subclass instead. That subclass has logic to
|
||||
sync the configuration with values of :class:`~transformers.TrainingArguments` by replacing special placeholder
|
||||
values: ``"auto"``. Without this special logic the DeepSpeed configuration is not modified in any way.
|
||||
|
||||
Args:
|
||||
config_file_or_dict (:obj:`Union[str, Dict]`): path to DeepSpeed config file or dict.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, config_file_or_dict):
|
||||
# set global weakref object
|
||||
set_hf_deepspeed_config(self)
|
||||
|
||||
dep_version_check("deepspeed")
|
||||
|
||||
if isinstance(config_file_or_dict, dict):
|
||||
# Don't modify user's data should they want to reuse it (e.g. in tests), because once we
|
||||
# modified it, it will not be accepted here again, since `auto` values would have been overridden
|
||||
config = deepcopy(config_file_or_dict)
|
||||
elif isinstance(config_file_or_dict, str):
|
||||
with io.open(config_file_or_dict, "r", encoding="utf-8") as f:
|
||||
config = json.load(f)
|
||||
else:
|
||||
raise ValueError("expecting either a path to a DeepSpeed config file or a pre-populated dict")
|
||||
self.config = config
|
||||
|
||||
# zero stage - this is done as early as possible, before model is created, to allow
|
||||
# ``is_deepspeed_zero3_enabled`` query and getting to the early deepspeed config object
|
||||
# during ``zero.Init()`` which needs whether fp16 is enabled, dtype, etc.
|
||||
self._stage = self.get_value("zero_optimization.stage", -1)
|
||||
|
||||
# offload
|
||||
self._offload = False
|
||||
if self.is_zero2() or self.is_zero3():
|
||||
offload_devices_valid = set(["cpu", "nvme"])
|
||||
offload_devices = set(
|
||||
[
|
||||
self.get_value("zero_optimization.offload_optimizer.device"),
|
||||
self.get_value("zero_optimization.offload_param.device"),
|
||||
]
|
||||
)
|
||||
if len(offload_devices & offload_devices_valid) > 0:
|
||||
self._offload = True
|
||||
|
||||
def find_config_node(self, ds_key_long):
|
||||
config = self.config
|
||||
|
||||
# find the config node of interest if it exists
|
||||
nodes = ds_key_long.split(".")
|
||||
ds_key = nodes.pop()
|
||||
for node in nodes:
|
||||
config = config.get(node)
|
||||
if config is None:
|
||||
return None, ds_key
|
||||
|
||||
return config, ds_key
|
||||
|
||||
def get_value(self, ds_key_long, default=None):
|
||||
"""
|
||||
Returns the set value or ``default`` if no value is set
|
||||
"""
|
||||
config, ds_key = self.find_config_node(ds_key_long)
|
||||
if config is None:
|
||||
return default
|
||||
return config.get(ds_key, default)
|
||||
|
||||
def is_true(self, ds_key_long):
|
||||
"""
|
||||
Returns :obj:`True`/:obj:`False` only if the value is set, always :obj:`False` otherwise. So use this method to
|
||||
ask the very specific question of whether the value is set to :obj:`True` (and it's not set to :obj:`False` or
|
||||
isn't set).
|
||||
|
||||
"""
|
||||
value = self.get_value(ds_key_long)
|
||||
return False if value is None else bool(value)
|
||||
|
||||
def is_false(self, ds_key_long):
|
||||
"""
|
||||
Returns :obj:`True`/:obj:`False` only if the value is set, always :obj:`False` otherwise. So use this method to
|
||||
ask the very specific question of whether the value is set to :obj:`False` (and it's not set to :obj:`True` or
|
||||
isn't set).
|
||||
"""
|
||||
value = self.get_value(ds_key_long)
|
||||
return False if value is None else not bool(value)
|
||||
|
||||
def is_zero2(self):
|
||||
return self._stage == 2
|
||||
|
||||
def is_zero3(self):
|
||||
return self._stage == 3
|
||||
|
||||
def is_offload(self):
|
||||
return self._offload
|
||||
|
||||
|
||||
class HfTrainerDeepSpeedConfig(HfDeepSpeedConfig):
|
||||
"""
|
||||
The ``HfTrainerDeepSpeedConfig`` object is meant to be created during ``TrainingArguments`` object creation and has
|
||||
the same lifespan as the latter.
|
||||
"""
|
||||
|
||||
def __init__(self, config_file_or_dict):
|
||||
super().__init__(config_file_or_dict)
|
||||
self._dtype = torch.float16
|
||||
self.mismatches = []
|
||||
|
||||
def dtype(self):
|
||||
return self._dtype
|
||||
|
||||
def fill_match(self, ds_key_long, hf_val, hf_key=None, must_match=True):
|
||||
"""
|
||||
A utility method that massages the config file and can optionally verify that the values match.
|
||||
|
||||
1. Replace "auto" values with ``TrainingArguments`` value.
|
||||
|
||||
2. If it wasn't "auto" and ``must_match`` is true, then check that DS config matches Trainer
|
||||
config values and if mismatched add the entry to ``self.mismatched`` - will assert during
|
||||
``trainer_config_finalize`` for one or more mismatches.
|
||||
|
||||
"""
|
||||
config, ds_key = self.find_config_node(ds_key_long)
|
||||
if config is None:
|
||||
return
|
||||
|
||||
if config.get(ds_key) == "auto":
|
||||
config[ds_key] = hf_val
|
||||
return
|
||||
|
||||
if not must_match:
|
||||
return
|
||||
|
||||
ds_val = config.get(ds_key)
|
||||
if ds_val is not None and ds_val != hf_val:
|
||||
self.mismatches.append(f"- ds {ds_key_long}={ds_val} vs hf {hf_key}={hf_val}")
|
||||
|
||||
fill_only = partialmethod(fill_match, must_match=False)
|
||||
|
||||
def trainer_config_process(self, args):
|
||||
"""
|
||||
Adjust the config with ``TrainingArguments`` values. This stage is run during ``TrainingArguments`` object
|
||||
creation.
|
||||
"""
|
||||
# DeepSpeed does:
|
||||
# train_batch_size = world_size * train_micro_batch_size_per_gpu * gradient_accumulation_steps
|
||||
train_batch_size = args.world_size * args.per_device_train_batch_size * args.gradient_accumulation_steps
|
||||
self.fill_match(
|
||||
"train_micro_batch_size_per_gpu", args.per_device_train_batch_size, "per_device_train_batch_size"
|
||||
)
|
||||
self.fill_match("gradient_accumulation_steps", args.gradient_accumulation_steps, "gradient_accumulation_steps")
|
||||
self.fill_match("train_batch_size", train_batch_size, "train_batch_size (calculated)")
|
||||
self.fill_match("gradient_clipping", args.max_grad_norm, "max_grad_norm")
|
||||
|
||||
self.fill_match("optimizer.params.lr", args.learning_rate, "learning_rate")
|
||||
self.fill_match("optimizer.params.betas", [args.adam_beta1, args.adam_beta2], "adam_beta1+adam_beta2")
|
||||
self.fill_match("optimizer.params.eps", args.adam_epsilon, "adam_epsilon")
|
||||
self.fill_match("optimizer.params.weight_decay", args.weight_decay, "weight_decay")
|
||||
|
||||
self.fill_only("scheduler.params.warmup_min_lr", 0) # not a trainer arg
|
||||
self.fill_match("scheduler.params.warmup_max_lr", args.learning_rate, "learning_rate")
|
||||
# total_num_steps - will get set in trainer_config_finalize
|
||||
|
||||
# fp16
|
||||
if args.fp16:
|
||||
fp16_backend = "apex" if args.fp16_backend == "apex" else "amp"
|
||||
else:
|
||||
fp16_backend = None
|
||||
|
||||
# amp: similar to the pytorch native amp - it has a bunch of optional params but we won't set
|
||||
# any here unless the user did the work
|
||||
self.fill_match("fp16.enabled", fp16_backend == "amp", "fp16+fp16_backend(amp)")
|
||||
|
||||
# apex: delegates amp work to apex (which needs to be available), but it cannot be used with any
|
||||
# ZeRO features
|
||||
self.fill_match("amp.enabled", fp16_backend == "apex", "fp16+fp16_backend(apex)")
|
||||
self.fill_match("amp.opt_level", args.fp16_opt_level, "fp16_opt_level")
|
||||
|
||||
# only if we have an explicit fp16.enabled = False then it's fp32, if it's True or this
|
||||
# whole config section is missing then the fallback is fp16
|
||||
if self.is_false("fp16.enabled"):
|
||||
self._dtype = torch.float32
|
||||
# later there will be other dtypes besides just fp16 and fp32
|
||||
# also not quite sure what dtype should be under apex, defaulting to fp16 for now
|
||||
|
||||
def trainer_config_finalize(self, args, model, num_training_steps):
|
||||
"""
|
||||
This stage is run after we have the model and know num_training_steps.
|
||||
|
||||
Now we we can complete the configuration process.
|
||||
"""
|
||||
# zero
|
||||
if self.is_zero3():
|
||||
# automatically assign the optimal config values based on model config
|
||||
hidden_size = model.config.hidden_size
|
||||
self.fill_only("zero_optimization.reduce_bucket_size", hidden_size * hidden_size)
|
||||
self.fill_only("zero_optimization.stage3_prefetch_bucket_size", 0.9 * hidden_size * hidden_size)
|
||||
self.fill_only("zero_optimization.stage3_param_persistence_threshold", 10 * hidden_size)
|
||||
|
||||
# scheduler
|
||||
self.fill_match("scheduler.params.total_num_steps", num_training_steps, "num_training_steps (calculated)")
|
||||
self.fill_match("scheduler.params.warmup_num_steps", args.get_warmup_steps(num_training_steps), "warmup_steps")
|
||||
|
||||
if len(self.mismatches) > 0:
|
||||
mismatches = "\n".join(self.mismatches)
|
||||
raise ValueError(
|
||||
f"Please correct the following DeepSpeed config values that mismatch TrainingArguments values:\n{mismatches}\n"
|
||||
"The easiest method is to set these DeepSpeed config values to 'auto'."
|
||||
)
|
||||
|
||||
|
||||
# keep the config object global to be able to access it anywhere during TrainingArguments life-cycle
|
||||
_hf_deepspeed_config_weak_ref = None
|
||||
|
||||
|
||||
def set_hf_deepspeed_config(hf_deepspeed_config_obj):
|
||||
# this is a special weakref global object to allow us to get to Deepspeed config from APIs
|
||||
# that don't have an easy way to get to the Deepspeed config outside of the Trainer domain.
|
||||
global _hf_deepspeed_config_weak_ref
|
||||
# will go away automatically when HfDeepSpeedConfig is destroyed (when TrainingArguments is destroyed)
|
||||
_hf_deepspeed_config_weak_ref = weakref.ref(hf_deepspeed_config_obj)
|
||||
|
||||
|
||||
def is_deepspeed_zero3_enabled():
|
||||
if _hf_deepspeed_config_weak_ref is not None and _hf_deepspeed_config_weak_ref() is not None:
|
||||
return _hf_deepspeed_config_weak_ref().is_zero3()
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def deepspeed_config():
|
||||
if _hf_deepspeed_config_weak_ref is not None and _hf_deepspeed_config_weak_ref() is not None:
|
||||
return _hf_deepspeed_config_weak_ref().config
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def deepspeed_init(trainer, num_training_steps, resume_from_checkpoint=None):
|
||||
"""
|
||||
Init DeepSpeed, after updating the DeepSpeed configuration with any relevant Trainer's args.
|
||||
|
||||
If ``resume_from_checkpoint`` was passed then an attempt to resume from a previously saved checkpoint will be made.
|
||||
|
||||
Args:
|
||||
trainer: Trainer object
|
||||
num_training_steps: per single gpu
|
||||
resume_from_checkpoint: path to a checkpoint if to resume from after normal DeepSpeedEngine load
|
||||
|
||||
Returns: model, optimizer, lr_scheduler
|
||||
|
||||
"""
|
||||
import deepspeed
|
||||
from deepspeed.utils import logger as ds_logger
|
||||
|
||||
model = trainer.model
|
||||
args = trainer.args
|
||||
|
||||
hf_deepspeed_config = args.hf_deepspeed_config
|
||||
hf_deepspeed_config.trainer_config_finalize(args, model, num_training_steps)
|
||||
|
||||
# resume config update - some bits like `model` and `num_training_steps` only become available during train
|
||||
config = hf_deepspeed_config.config
|
||||
|
||||
# Optimizer + Scheduler
|
||||
# Currently supported combos:
|
||||
# 1. DS scheduler + DS optimizer: Yes
|
||||
# 2. HF scheduler + HF optimizer: Yes
|
||||
# 3. DS scheduler + HF optimizer: Yes
|
||||
# 4. HF scheduler + DS optimizer: Yes
|
||||
#
|
||||
# Unless Offload is enabled in which case it's:
|
||||
# 1. DS scheduler + DS optimizer: Yes
|
||||
# 2. HF scheduler + HF optimizer: Mostly*
|
||||
# 3. DS scheduler + HF optimizer: Mostly*
|
||||
# 4. HF scheduler + DS optimizer: Yes
|
||||
#
|
||||
# Mostly*: All non-native DeepSpeed optimizers that have both CPU and GPU implementation should work (except LAMB)
|
||||
|
||||
optimizer = None
|
||||
if "optimizer" in config:
|
||||
if args.adafactor:
|
||||
raise ValueError(
|
||||
"--adafactor was passed, but also found `optimizer` configured in the DeepSpeed config. "
|
||||
"Only one optimizer can be configured."
|
||||
)
|
||||
else:
|
||||
if hf_deepspeed_config.is_offload():
|
||||
logger.info(
|
||||
"Detected ZeRO Offload and non-DeepSpeed optimizers: This combination should work as long as the custom optimizer has both CPU and GPU implementation (except LAMB)"
|
||||
)
|
||||
|
||||
# ds supports Adam, OneBitAdam, and Lamb optimizers and can import other optimizers from torch.
|
||||
# But trainer uses AdamW by default.
|
||||
optimizer = trainer.create_optimizer()
|
||||
# To use other optimizers requires voiding warranty with: `zero_allow_untested_optimizer`
|
||||
config["zero_allow_untested_optimizer"] = True
|
||||
|
||||
def _lr_scheduler_callable(optimizer):
|
||||
return trainer.create_scheduler(num_training_steps=num_training_steps, optimizer=optimizer)
|
||||
|
||||
lr_scheduler = None
|
||||
if "scheduler" not in config:
|
||||
if optimizer is None:
|
||||
# Optimizer is not available, so use callable to defer lr_scheduler creation to DS init
|
||||
lr_scheduler = _lr_scheduler_callable
|
||||
else:
|
||||
lr_scheduler = trainer.create_scheduler(num_training_steps=num_training_steps, optimizer=optimizer)
|
||||
|
||||
# keep for quick debug:
|
||||
# from pprint import pprint; pprint(config)
|
||||
|
||||
# set the Deepspeed log level consistent with the trainer
|
||||
ds_logger.setLevel(args.get_process_log_level())
|
||||
|
||||
model_parameters = filter(lambda p: p.requires_grad, model.parameters())
|
||||
|
||||
model, optimizer, _, lr_scheduler = deepspeed.initialize(
|
||||
model=model,
|
||||
model_parameters=model_parameters,
|
||||
config_params=config,
|
||||
optimizer=optimizer,
|
||||
lr_scheduler=lr_scheduler,
|
||||
)
|
||||
|
||||
if resume_from_checkpoint is not None:
|
||||
|
||||
# it's possible that the user is trying to resume from model_path, which doesn't necessarily
|
||||
# contain a deepspeed checkpoint. e.g. examples just check if the dir exists and assume it's
|
||||
# a resume from a checkpoint and not just a local pretrained weight. So we check here if the
|
||||
# path contains what looks like a deepspeed checkpoint
|
||||
import glob
|
||||
|
||||
deepspeed_checkpoint_dirs = sorted(glob.glob(f"{resume_from_checkpoint}/global_step*"))
|
||||
|
||||
if len(deepspeed_checkpoint_dirs) > 0:
|
||||
logger.info(f"Attempting to resume from {resume_from_checkpoint}")
|
||||
# this magically updates self.optimizer and self.lr_scheduler
|
||||
load_path, _ = model.load_checkpoint(
|
||||
resume_from_checkpoint, load_optimizer_states=True, load_lr_scheduler_states=True
|
||||
)
|
||||
if load_path is None:
|
||||
raise ValueError(f"[deepspeed] failed to resume from checkpoint {resume_from_checkpoint}")
|
||||
else:
|
||||
logger.info(f"{resume_from_checkpoint} doesn't have deepspeed checkpoints, doing nothing")
|
||||
|
||||
return model, optimizer, lr_scheduler
|
20
fastNLP/transformers/torch/dependency_versions_check.py
Normal file
20
fastNLP/transformers/torch/dependency_versions_check.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import sys
|
||||
|
||||
from .dependency_versions_table import deps
|
||||
from .utils.versions import require_version
|
||||
|
||||
def dep_version_check(pkg, hint=None):
|
||||
require_version(deps[pkg], hint)
|
76
fastNLP/transformers/torch/dependency_versions_table.py
Normal file
76
fastNLP/transformers/torch/dependency_versions_table.py
Normal file
@ -0,0 +1,76 @@
|
||||
# THIS FILE HAS BEEN AUTOGENERATED. To update:
|
||||
# 1. modify the `_deps` dict in setup.py
|
||||
# 2. run `make deps_table_update``
|
||||
deps = {
|
||||
"Pillow": "Pillow",
|
||||
"black": "black==21.4b0",
|
||||
"codecarbon": "codecarbon==1.2.0",
|
||||
"cookiecutter": "cookiecutter==1.7.2",
|
||||
"dataclasses": "dataclasses",
|
||||
"datasets": "datasets",
|
||||
"deepspeed": "deepspeed>=0.5.3",
|
||||
"docutils": "docutils==0.16.0",
|
||||
"fairscale": "fairscale>0.3",
|
||||
"faiss-cpu": "faiss-cpu",
|
||||
"fastapi": "fastapi",
|
||||
"filelock": "filelock",
|
||||
"flake8": "flake8>=3.8.3",
|
||||
"flax": "flax>=0.3.4",
|
||||
"fugashi": "fugashi>=1.0",
|
||||
"GitPython": "GitPython<3.1.19",
|
||||
"huggingface-hub": "huggingface-hub>=0.0.17",
|
||||
"importlib_metadata": "importlib_metadata",
|
||||
"ipadic": "ipadic>=1.0.0,<2.0",
|
||||
"isort": "isort>=5.5.4",
|
||||
"jax": "jax>=0.2.8",
|
||||
"jaxlib": "jaxlib>=0.1.65",
|
||||
"jieba": "jieba",
|
||||
"keras2onnx": "keras2onnx",
|
||||
"nltk": "nltk",
|
||||
"numpy": "numpy>=1.17",
|
||||
"onnxconverter-common": "onnxconverter-common",
|
||||
"onnxruntime-tools": "onnxruntime-tools>=1.4.2",
|
||||
"onnxruntime": "onnxruntime>=1.4.0",
|
||||
"optuna": "optuna",
|
||||
"optax": "optax>=0.0.8",
|
||||
"packaging": "packaging>=20.0",
|
||||
"parameterized": "parameterized",
|
||||
"protobuf": "protobuf",
|
||||
"psutil": "psutil",
|
||||
"pyyaml": "pyyaml>=5.1",
|
||||
"pydantic": "pydantic",
|
||||
"pytest": "pytest",
|
||||
"pytest-timeout": "pytest-timeout",
|
||||
"pytest-xdist": "pytest-xdist",
|
||||
"python": "python>=3.6.0",
|
||||
"ray[tune]": "ray[tune]",
|
||||
"recommonmark": "recommonmark",
|
||||
"regex": "regex!=2019.12.17",
|
||||
"requests": "requests",
|
||||
"rouge-score": "rouge-score",
|
||||
"sacrebleu": "sacrebleu>=1.4.12,<2.0.0",
|
||||
"sacremoses": "sacremoses",
|
||||
"sagemaker": "sagemaker>=2.31.0",
|
||||
"scikit-learn": "scikit-learn",
|
||||
"sentencepiece": "sentencepiece>=0.1.91,!=0.1.92",
|
||||
"sigopt": "sigopt",
|
||||
"soundfile": "soundfile",
|
||||
"sphinx-copybutton": "sphinx-copybutton",
|
||||
"sphinx-markdown-tables": "sphinx-markdown-tables",
|
||||
"sphinx-rtd-theme": "sphinx-rtd-theme==0.4.3",
|
||||
"sphinx": "sphinx==3.2.1",
|
||||
"sphinxext-opengraph": "sphinxext-opengraph==0.4.1",
|
||||
"sphinx-intl": "sphinx-intl",
|
||||
"starlette": "starlette",
|
||||
"tensorflow-cpu": "tensorflow-cpu>=2.3",
|
||||
"tensorflow": "tensorflow>=2.3",
|
||||
"timeout-decorator": "timeout-decorator",
|
||||
"timm": "timm",
|
||||
"tokenizers": "tokenizers>=0.10.1,<0.11",
|
||||
"torch": "torch>=1.0",
|
||||
"torchaudio": "torchaudio",
|
||||
"tqdm": "tqdm>=4.27",
|
||||
"unidic": "unidic>=1.0.2",
|
||||
"unidic_lite": "unidic_lite>=1.0.7",
|
||||
"uvicorn": "uvicorn",
|
||||
}
|
934
fastNLP/transformers/torch/file_utils.py
Normal file
934
fastNLP/transformers/torch/file_utils.py
Normal file
@ -0,0 +1,934 @@
|
||||
import copy
|
||||
import fnmatch
|
||||
import importlib.util
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import tarfile
|
||||
import tempfile
|
||||
import operator
|
||||
from collections import OrderedDict, UserDict
|
||||
from contextlib import contextmanager
|
||||
from dataclasses import fields
|
||||
from enum import Enum
|
||||
from functools import partial
|
||||
from hashlib import sha256
|
||||
from pathlib import Path
|
||||
from typing import Any, BinaryIO, Dict, Optional, Tuple, Union
|
||||
from urllib.parse import urlparse
|
||||
from uuid import uuid4
|
||||
from zipfile import ZipFile, is_zipfile
|
||||
|
||||
import numpy as np
|
||||
# from tqdm.auto import tqdm
|
||||
|
||||
import requests
|
||||
|
||||
from . import __version__
|
||||
from .utils.versions import importlib_metadata
|
||||
from fastNLP.envs.imports import _NEED_IMPORT_TORCH, _TORCH_GREATER_EQUAL_1_8
|
||||
from fastNLP.envs.utils import _compare_version
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
if _NEED_IMPORT_TORCH:
|
||||
import torch
|
||||
_torch_version = importlib_metadata.version("torch")
|
||||
|
||||
hf_cache_home = os.path.expanduser(
|
||||
os.getenv("HF_HOME", os.path.join(os.getenv("XDG_CACHE_HOME", "~/.cache"), "huggingface"))
|
||||
)
|
||||
default_cache_path = os.path.join(hf_cache_home, "transformers")
|
||||
|
||||
PYTORCH_PRETRAINED_BERT_CACHE = os.getenv("PYTORCH_PRETRAINED_BERT_CACHE", default_cache_path)
|
||||
PYTORCH_TRANSFORMERS_CACHE = os.getenv("PYTORCH_TRANSFORMERS_CACHE", PYTORCH_PRETRAINED_BERT_CACHE)
|
||||
TRANSFORMERS_CACHE = os.getenv("TRANSFORMERS_CACHE", PYTORCH_TRANSFORMERS_CACHE)
|
||||
SESSION_ID = uuid4().hex
|
||||
|
||||
ENV_VARS_TRUE_VALUES = {"1", "ON", "YES", "TRUE"}
|
||||
|
||||
DISABLE_TELEMETRY = os.getenv("DISABLE_TELEMETRY", False) in ENV_VARS_TRUE_VALUES
|
||||
|
||||
WEIGHTS_NAME = "pytorch_model.bin"
|
||||
DUMMY_INPUTS = [[7, 6, 0, 0, 1], [1, 2, 3, 0, 0], [0, 0, 0, 4, 5]]
|
||||
|
||||
_staging_mode = os.environ.get("HUGGINGFACE_CO_STAGING", "NO").upper() in ENV_VARS_TRUE_VALUES
|
||||
_default_endpoint = "https://moon-staging.huggingface.co" if _staging_mode else "https://huggingface.co"
|
||||
|
||||
HUGGINGFACE_CO_RESOLVE_ENDPOINT = os.environ.get("HUGGINGFACE_CO_RESOLVE_ENDPOINT", _default_endpoint)
|
||||
HUGGINGFACE_CO_PREFIX = HUGGINGFACE_CO_RESOLVE_ENDPOINT + "/{model_id}/resolve/{revision}/{filename}"
|
||||
|
||||
CONFIG_NAME = "config.json"
|
||||
|
||||
_is_offline_mode = True if os.environ.get("TRANSFORMERS_OFFLINE", "0").upper() in ENV_VARS_TRUE_VALUES else False
|
||||
|
||||
@contextmanager
|
||||
def filelock(path):
|
||||
try:
|
||||
import fcntl
|
||||
open_mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC
|
||||
fd = os.open(path, open_mode)
|
||||
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
except:
|
||||
pass
|
||||
|
||||
yield
|
||||
|
||||
try:
|
||||
fcntl.flock(fd, fcntl.LOCK_UN)
|
||||
os.close(fd)
|
||||
except:
|
||||
pass
|
||||
|
||||
def is_offline_mode():
|
||||
return _is_offline_mode
|
||||
|
||||
def is_training_run_on_sagemaker():
|
||||
return "SAGEMAKER_JOB_NAME" in os.environ
|
||||
|
||||
def add_start_docstrings(*docstr):
|
||||
def docstring_decorator(fn):
|
||||
fn.__doc__ = "".join(docstr) + (fn.__doc__ if fn.__doc__ is not None else "")
|
||||
return fn
|
||||
|
||||
return docstring_decorator
|
||||
|
||||
|
||||
def add_start_docstrings_to_model_forward(*docstr):
|
||||
def docstring_decorator(fn):
|
||||
class_name = f":class:`~transformers.{fn.__qualname__.split('.')[0]}`"
|
||||
intro = f" The {class_name} forward method, overrides the :func:`__call__` special method."
|
||||
note = r"""
|
||||
|
||||
.. note::
|
||||
Although the recipe for forward pass needs to be defined within this function, one should call the
|
||||
:class:`Module` instance afterwards instead of this since the former takes care of running the pre and post
|
||||
processing steps while the latter silently ignores them.
|
||||
"""
|
||||
fn.__doc__ = intro + note + "".join(docstr) + (fn.__doc__ if fn.__doc__ is not None else "")
|
||||
return fn
|
||||
|
||||
return docstring_decorator
|
||||
|
||||
|
||||
def add_end_docstrings(*docstr):
|
||||
def docstring_decorator(fn):
|
||||
fn.__doc__ = fn.__doc__ + "".join(docstr)
|
||||
return fn
|
||||
|
||||
return docstring_decorator
|
||||
|
||||
PT_RETURN_INTRODUCTION = r"""
|
||||
Returns:
|
||||
:class:`~{full_output_type}` or :obj:`tuple(torch.FloatTensor)`: A :class:`~{full_output_type}` or a tuple of
|
||||
:obj:`torch.FloatTensor` (if ``return_dict=False`` is passed or when ``config.return_dict=False``) comprising
|
||||
various elements depending on the configuration (:class:`~transformers.{config_class}`) and inputs.
|
||||
|
||||
"""
|
||||
|
||||
def _get_indent(t):
|
||||
"""Returns the indentation in the first line of t"""
|
||||
search = re.search(r"^(\s*)\S", t)
|
||||
return "" if search is None else search.groups()[0]
|
||||
|
||||
|
||||
def _convert_output_args_doc(output_args_doc):
|
||||
"""Convert output_args_doc to display properly."""
|
||||
# Split output_arg_doc in blocks argument/description
|
||||
indent = _get_indent(output_args_doc)
|
||||
blocks = []
|
||||
current_block = ""
|
||||
for line in output_args_doc.split("\n"):
|
||||
# If the indent is the same as the beginning, the line is the name of new arg.
|
||||
if _get_indent(line) == indent:
|
||||
if len(current_block) > 0:
|
||||
blocks.append(current_block[:-1])
|
||||
current_block = f"{line}\n"
|
||||
else:
|
||||
# Otherwise it's part of the description of the current arg.
|
||||
# We need to remove 2 spaces to the indentation.
|
||||
current_block += f"{line[2:]}\n"
|
||||
blocks.append(current_block[:-1])
|
||||
|
||||
# Format each block for proper rendering
|
||||
for i in range(len(blocks)):
|
||||
blocks[i] = re.sub(r"^(\s+)(\S+)(\s+)", r"\1- **\2**\3", blocks[i])
|
||||
blocks[i] = re.sub(r":\s*\n\s*(\S)", r" -- \1", blocks[i])
|
||||
|
||||
return "\n".join(blocks)
|
||||
|
||||
def _prepare_output_docstrings(output_type, config_class):
|
||||
"""
|
||||
Prepares the return part of the docstring using `output_type`.
|
||||
"""
|
||||
docstrings = output_type.__doc__
|
||||
|
||||
# Remove the head of the docstring to keep the list of args only
|
||||
lines = docstrings.split("\n")
|
||||
i = 0
|
||||
while i < len(lines) and re.search(r"^\s*(Args|Parameters):\s*$", lines[i]) is None:
|
||||
i += 1
|
||||
if i < len(lines):
|
||||
docstrings = "\n".join(lines[(i + 1) :])
|
||||
docstrings = _convert_output_args_doc(docstrings)
|
||||
|
||||
# Add the return introduction
|
||||
full_output_type = f"{output_type.__module__}.{output_type.__name__}"
|
||||
intro = PT_RETURN_INTRODUCTION
|
||||
intro = intro.format(full_output_type=full_output_type, config_class=config_class)
|
||||
return intro + docstrings
|
||||
|
||||
PT_TOKEN_CLASSIFICATION_SAMPLE = r"""
|
||||
Example::
|
||||
|
||||
>>> from transformers import {tokenizer_class}, {model_class}
|
||||
>>> import torch
|
||||
|
||||
>>> tokenizer = {tokenizer_class}.from_pretrained('{checkpoint}')
|
||||
>>> model = {model_class}.from_pretrained('{checkpoint}')
|
||||
|
||||
>>> inputs = tokenizer("Hello, my dog is cute", return_tensors="pt")
|
||||
>>> labels = torch.tensor([1] * inputs["input_ids"].size(1)).unsqueeze(0) # Batch size 1
|
||||
|
||||
>>> outputs = model(**inputs, labels=labels)
|
||||
>>> loss = outputs.loss
|
||||
>>> logits = outputs.logits
|
||||
"""
|
||||
|
||||
PT_QUESTION_ANSWERING_SAMPLE = r"""
|
||||
Example::
|
||||
|
||||
>>> from transformers import {tokenizer_class}, {model_class}
|
||||
>>> import torch
|
||||
|
||||
>>> tokenizer = {tokenizer_class}.from_pretrained('{checkpoint}')
|
||||
>>> model = {model_class}.from_pretrained('{checkpoint}')
|
||||
|
||||
>>> question, text = "Who was Jim Henson?", "Jim Henson was a nice puppet"
|
||||
>>> inputs = tokenizer(question, text, return_tensors='pt')
|
||||
>>> start_positions = torch.tensor([1])
|
||||
>>> end_positions = torch.tensor([3])
|
||||
|
||||
>>> outputs = model(**inputs, start_positions=start_positions, end_positions=end_positions)
|
||||
>>> loss = outputs.loss
|
||||
>>> start_scores = outputs.start_logits
|
||||
>>> end_scores = outputs.end_logits
|
||||
"""
|
||||
|
||||
PT_SEQUENCE_CLASSIFICATION_SAMPLE = r"""
|
||||
Example::
|
||||
|
||||
>>> from transformers import {tokenizer_class}, {model_class}
|
||||
>>> import torch
|
||||
|
||||
>>> tokenizer = {tokenizer_class}.from_pretrained('{checkpoint}')
|
||||
>>> model = {model_class}.from_pretrained('{checkpoint}')
|
||||
|
||||
>>> inputs = tokenizer("Hello, my dog is cute", return_tensors="pt")
|
||||
>>> labels = torch.tensor([1]).unsqueeze(0) # Batch size 1
|
||||
>>> outputs = model(**inputs, labels=labels)
|
||||
>>> loss = outputs.loss
|
||||
>>> logits = outputs.logits
|
||||
"""
|
||||
|
||||
PT_MASKED_LM_SAMPLE = r"""
|
||||
Example::
|
||||
|
||||
>>> from transformers import {tokenizer_class}, {model_class}
|
||||
>>> import torch
|
||||
|
||||
>>> tokenizer = {tokenizer_class}.from_pretrained('{checkpoint}')
|
||||
>>> model = {model_class}.from_pretrained('{checkpoint}')
|
||||
|
||||
>>> inputs = tokenizer("The capital of France is {mask}.", return_tensors="pt")
|
||||
>>> labels = tokenizer("The capital of France is Paris.", return_tensors="pt")["input_ids"]
|
||||
|
||||
>>> outputs = model(**inputs, labels=labels)
|
||||
>>> loss = outputs.loss
|
||||
>>> logits = outputs.logits
|
||||
"""
|
||||
|
||||
PT_BASE_MODEL_SAMPLE = r"""
|
||||
Example::
|
||||
|
||||
>>> from transformers import {tokenizer_class}, {model_class}
|
||||
>>> import torch
|
||||
|
||||
>>> tokenizer = {tokenizer_class}.from_pretrained('{checkpoint}')
|
||||
>>> model = {model_class}.from_pretrained('{checkpoint}')
|
||||
|
||||
>>> inputs = tokenizer("Hello, my dog is cute", return_tensors="pt")
|
||||
>>> outputs = model(**inputs)
|
||||
|
||||
>>> last_hidden_states = outputs.last_hidden_state
|
||||
"""
|
||||
|
||||
PT_MULTIPLE_CHOICE_SAMPLE = r"""
|
||||
Example::
|
||||
|
||||
>>> from transformers import {tokenizer_class}, {model_class}
|
||||
>>> import torch
|
||||
|
||||
>>> tokenizer = {tokenizer_class}.from_pretrained('{checkpoint}')
|
||||
>>> model = {model_class}.from_pretrained('{checkpoint}')
|
||||
|
||||
>>> prompt = "In Italy, pizza served in formal settings, such as at a restaurant, is presented unsliced."
|
||||
>>> choice0 = "It is eaten with a fork and a knife."
|
||||
>>> choice1 = "It is eaten while held in the hand."
|
||||
>>> labels = torch.tensor(0).unsqueeze(0) # choice0 is correct (according to Wikipedia ;)), batch size 1
|
||||
|
||||
>>> encoding = tokenizer([prompt, prompt], [choice0, choice1], return_tensors='pt', padding=True)
|
||||
>>> outputs = model(**{{k: v.unsqueeze(0) for k,v in encoding.items()}}, labels=labels) # batch size is 1
|
||||
|
||||
>>> # the linear classifier still needs to be trained
|
||||
>>> loss = outputs.loss
|
||||
>>> logits = outputs.logits
|
||||
"""
|
||||
|
||||
PT_CAUSAL_LM_SAMPLE = r"""
|
||||
Example::
|
||||
|
||||
>>> import torch
|
||||
>>> from transformers import {tokenizer_class}, {model_class}
|
||||
|
||||
>>> tokenizer = {tokenizer_class}.from_pretrained('{checkpoint}')
|
||||
>>> model = {model_class}.from_pretrained('{checkpoint}')
|
||||
|
||||
>>> inputs = tokenizer("Hello, my dog is cute", return_tensors="pt")
|
||||
>>> outputs = model(**inputs, labels=inputs["input_ids"])
|
||||
>>> loss = outputs.loss
|
||||
>>> logits = outputs.logits
|
||||
"""
|
||||
|
||||
PT_SAMPLE_DOCSTRINGS = {
|
||||
"SequenceClassification": PT_SEQUENCE_CLASSIFICATION_SAMPLE,
|
||||
"QuestionAnswering": PT_QUESTION_ANSWERING_SAMPLE,
|
||||
"TokenClassification": PT_TOKEN_CLASSIFICATION_SAMPLE,
|
||||
"MultipleChoice": PT_MULTIPLE_CHOICE_SAMPLE,
|
||||
"MaskedLM": PT_MASKED_LM_SAMPLE,
|
||||
"LMHead": PT_CAUSAL_LM_SAMPLE,
|
||||
"BaseModel": PT_BASE_MODEL_SAMPLE,
|
||||
}
|
||||
|
||||
def add_code_sample_docstrings(
|
||||
*docstr, tokenizer_class=None, checkpoint=None, output_type=None, config_class=None, mask=None, model_cls=None
|
||||
):
|
||||
def docstring_decorator(fn):
|
||||
# model_class defaults to function's class if not specified otherwise
|
||||
model_class = fn.__qualname__.split(".")[0] if model_cls is None else model_cls
|
||||
|
||||
sample_docstrings = PT_SAMPLE_DOCSTRINGS
|
||||
|
||||
doc_kwargs = dict(model_class=model_class, tokenizer_class=tokenizer_class, checkpoint=checkpoint)
|
||||
|
||||
if "SequenceClassification" in model_class:
|
||||
code_sample = sample_docstrings["SequenceClassification"]
|
||||
elif "QuestionAnswering" in model_class:
|
||||
code_sample = sample_docstrings["QuestionAnswering"]
|
||||
elif "TokenClassification" in model_class:
|
||||
code_sample = sample_docstrings["TokenClassification"]
|
||||
elif "MultipleChoice" in model_class:
|
||||
code_sample = sample_docstrings["MultipleChoice"]
|
||||
elif "MaskedLM" in model_class or model_class in ["FlaubertWithLMHeadModel", "XLMWithLMHeadModel"]:
|
||||
doc_kwargs["mask"] = "[MASK]" if mask is None else mask
|
||||
code_sample = sample_docstrings["MaskedLM"]
|
||||
elif "LMHead" in model_class or "CausalLM" in model_class:
|
||||
code_sample = sample_docstrings["LMHead"]
|
||||
elif "Model" in model_class or "Encoder" in model_class:
|
||||
code_sample = sample_docstrings["BaseModel"]
|
||||
else:
|
||||
raise ValueError(f"Docstring can't be built for model {model_class}")
|
||||
|
||||
output_doc = _prepare_output_docstrings(output_type, config_class) if output_type is not None else ""
|
||||
built_doc = code_sample.format(**doc_kwargs)
|
||||
fn.__doc__ = (fn.__doc__ or "") + "".join(docstr) + output_doc + built_doc
|
||||
return fn
|
||||
|
||||
return docstring_decorator
|
||||
|
||||
def replace_return_docstrings(output_type=None, config_class=None):
|
||||
def docstring_decorator(fn):
|
||||
docstrings = fn.__doc__
|
||||
lines = docstrings.split("\n")
|
||||
i = 0
|
||||
while i < len(lines) and re.search(r"^\s*Returns?:\s*$", lines[i]) is None:
|
||||
i += 1
|
||||
if i < len(lines):
|
||||
lines[i] = _prepare_output_docstrings(output_type, config_class)
|
||||
docstrings = "\n".join(lines)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"The function {fn} should have an empty 'Return:' or 'Returns:' in its docstring as placeholder, current docstring is:\n{docstrings}"
|
||||
)
|
||||
fn.__doc__ = docstrings
|
||||
return fn
|
||||
|
||||
return docstring_decorator
|
||||
|
||||
def is_remote_url(url_or_filename):
|
||||
parsed = urlparse(url_or_filename)
|
||||
return parsed.scheme in ("http", "https")
|
||||
|
||||
def hf_bucket_url(
|
||||
model_id: str, filename: str, subfolder: Optional[str] = None, revision: Optional[str] = None, mirror=None
|
||||
) -> str:
|
||||
"""
|
||||
Resolve a model identifier, a file name, and an optional revision id, to a huggingface.co-hosted url, redirecting
|
||||
to Cloudfront (a Content Delivery Network, or CDN) for large files.
|
||||
|
||||
Cloudfront is replicated over the globe so downloads are way faster for the end user (and it also lowers our
|
||||
bandwidth costs).
|
||||
|
||||
Cloudfront aggressively caches files by default (default TTL is 24 hours), however this is not an issue here
|
||||
because we migrated to a git-based versioning system on huggingface.co, so we now store the files on S3/Cloudfront
|
||||
in a content-addressable way (i.e., the file name is its hash). Using content-addressable filenames means cache
|
||||
can't ever be stale.
|
||||
|
||||
In terms of client-side caching from this library, we base our caching on the objects' ETag. An object' ETag is:
|
||||
its sha1 if stored in git, or its sha256 if stored in git-lfs. Files cached locally from transformers before v3.5.0
|
||||
are not shared with those new files, because the cached file's name contains a hash of the url (which changed).
|
||||
"""
|
||||
if subfolder is not None:
|
||||
filename = f"{subfolder}/{filename}"
|
||||
|
||||
if mirror:
|
||||
if mirror in ["tuna", "bfsu"]:
|
||||
raise ValueError("The Tuna and BFSU mirrors are no longer available. Try removing the mirror argument.")
|
||||
legacy_format = "/" not in model_id
|
||||
if legacy_format:
|
||||
return f"{mirror}/{model_id}-{filename}"
|
||||
else:
|
||||
return f"{mirror}/{model_id}/{filename}"
|
||||
|
||||
if revision is None:
|
||||
revision = "main"
|
||||
return HUGGINGFACE_CO_PREFIX.format(model_id=model_id, revision=revision, filename=filename)
|
||||
|
||||
def url_to_filename(url: str, etag: Optional[str] = None) -> str:
|
||||
"""
|
||||
Convert `url` into a hashed filename in a repeatable way. If `etag` is specified, append its hash to the url's,
|
||||
delimited by a period. If the url ends with .h5 (Keras HDF5 weights) adds '.h5' to the name so that TF 2.0 can
|
||||
identify it as a HDF5 file (see
|
||||
https://github.com/tensorflow/tensorflow/blob/00fad90125b18b80fe054de1055770cfb8fe4ba3/tensorflow/python/keras/engine/network.py#L1380)
|
||||
"""
|
||||
url_bytes = url.encode("utf-8")
|
||||
filename = sha256(url_bytes).hexdigest()
|
||||
|
||||
if etag:
|
||||
etag_bytes = etag.encode("utf-8")
|
||||
filename += "." + sha256(etag_bytes).hexdigest()
|
||||
|
||||
if url.endswith(".h5"):
|
||||
filename += ".h5"
|
||||
|
||||
return filename
|
||||
|
||||
def cached_path(
|
||||
url_or_filename,
|
||||
cache_dir=None,
|
||||
force_download=False,
|
||||
proxies=None,
|
||||
resume_download=False,
|
||||
user_agent: Union[Dict, str, None] = None,
|
||||
extract_compressed_file=False,
|
||||
force_extract=False,
|
||||
use_auth_token: Union[bool, str, None] = None,
|
||||
local_files_only=False,
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
Given something that might be a URL (or might be a local path), determine which. If it's a URL, download the file
|
||||
and cache it, and return the path to the cached file. If it's already a local path, make sure the file exists and
|
||||
then return the path
|
||||
|
||||
Args:
|
||||
cache_dir: specify a cache directory to save the file to (overwrite the default cache dir).
|
||||
force_download: if True, re-download the file even if it's already cached in the cache dir.
|
||||
resume_download: if True, resume the download if incompletely received file is found.
|
||||
user_agent: Optional string or dict that will be appended to the user-agent on remote requests.
|
||||
use_auth_token: Optional string or boolean to use as Bearer token for remote files. If True,
|
||||
will get token from ~/.huggingface.
|
||||
extract_compressed_file: if True and the path point to a zip or tar file, extract the compressed
|
||||
file in a folder along the archive.
|
||||
force_extract: if True when extract_compressed_file is True and the archive was already extracted,
|
||||
re-extract the archive and override the folder where it was extracted.
|
||||
|
||||
Return:
|
||||
Local path (string) of file or if networking is off, last version of file cached on disk.
|
||||
|
||||
Raises:
|
||||
In case of non-recoverable file (non-existent or inaccessible url + no cache on disk).
|
||||
"""
|
||||
if cache_dir is None:
|
||||
cache_dir = TRANSFORMERS_CACHE
|
||||
if isinstance(url_or_filename, Path):
|
||||
url_or_filename = str(url_or_filename)
|
||||
if isinstance(cache_dir, Path):
|
||||
cache_dir = str(cache_dir)
|
||||
|
||||
if is_offline_mode() and not local_files_only:
|
||||
logger.info("Offline mode: forcing local_files_only=True")
|
||||
local_files_only = True
|
||||
|
||||
if is_remote_url(url_or_filename):
|
||||
# URL, so get it from the cache (downloading if necessary)
|
||||
output_path = get_from_cache(
|
||||
url_or_filename,
|
||||
cache_dir=cache_dir,
|
||||
force_download=force_download,
|
||||
proxies=proxies,
|
||||
resume_download=resume_download,
|
||||
user_agent=user_agent,
|
||||
use_auth_token=use_auth_token,
|
||||
local_files_only=local_files_only,
|
||||
)
|
||||
elif os.path.exists(url_or_filename):
|
||||
# File, and it exists.
|
||||
output_path = url_or_filename
|
||||
elif urlparse(url_or_filename).scheme == "":
|
||||
# File, but it doesn't exist.
|
||||
raise EnvironmentError(f"file {url_or_filename} not found")
|
||||
else:
|
||||
# Something unknown
|
||||
raise ValueError(f"unable to parse {url_or_filename} as a URL or as a local path")
|
||||
|
||||
if extract_compressed_file:
|
||||
if not is_zipfile(output_path) and not tarfile.is_tarfile(output_path):
|
||||
return output_path
|
||||
|
||||
# Path where we extract compressed archives
|
||||
# We avoid '.' in dir name and add "-extracted" at the end: "./model.zip" => "./model-zip-extracted/"
|
||||
output_dir, output_file = os.path.split(output_path)
|
||||
output_extract_dir_name = output_file.replace(".", "-") + "-extracted"
|
||||
output_path_extracted = os.path.join(output_dir, output_extract_dir_name)
|
||||
|
||||
if os.path.isdir(output_path_extracted) and os.listdir(output_path_extracted) and not force_extract:
|
||||
return output_path_extracted
|
||||
|
||||
# Prevent parallel extractions
|
||||
lock_path = output_path + ".lock"
|
||||
with filelock(lock_path):
|
||||
shutil.rmtree(output_path_extracted, ignore_errors=True)
|
||||
os.makedirs(output_path_extracted)
|
||||
if is_zipfile(output_path):
|
||||
with ZipFile(output_path, "r") as zip_file:
|
||||
zip_file.extractall(output_path_extracted)
|
||||
zip_file.close()
|
||||
elif tarfile.is_tarfile(output_path):
|
||||
tar_file = tarfile.open(output_path)
|
||||
tar_file.extractall(output_path_extracted)
|
||||
tar_file.close()
|
||||
else:
|
||||
raise EnvironmentError(f"Archive format of {output_path} could not be identified")
|
||||
|
||||
return output_path_extracted
|
||||
|
||||
return output_path
|
||||
|
||||
def define_sagemaker_information():
|
||||
try:
|
||||
instance_data = requests.get(os.environ["ECS_CONTAINER_METADATA_URI"]).json()
|
||||
dlc_container_used = instance_data["Image"]
|
||||
dlc_tag = instance_data["Image"].split(":")[1]
|
||||
except Exception:
|
||||
dlc_container_used = None
|
||||
dlc_tag = None
|
||||
|
||||
sagemaker_params = json.loads(os.getenv("SM_FRAMEWORK_PARAMS", "{}"))
|
||||
runs_distributed_training = True if "sagemaker_distributed_dataparallel_enabled" in sagemaker_params else False
|
||||
account_id = os.getenv("TRAINING_JOB_ARN").split(":")[4] if "TRAINING_JOB_ARN" in os.environ else None
|
||||
|
||||
sagemaker_object = {
|
||||
"sm_framework": os.getenv("SM_FRAMEWORK_MODULE", None),
|
||||
"sm_region": os.getenv("AWS_REGION", None),
|
||||
"sm_number_gpu": os.getenv("SM_NUM_GPUS", 0),
|
||||
"sm_number_cpu": os.getenv("SM_NUM_CPUS", 0),
|
||||
"sm_distributed_training": runs_distributed_training,
|
||||
"sm_deep_learning_container": dlc_container_used,
|
||||
"sm_deep_learning_container_tag": dlc_tag,
|
||||
"sm_account_id": account_id,
|
||||
}
|
||||
return sagemaker_object
|
||||
|
||||
def http_user_agent(user_agent: Union[Dict, str, None] = None) -> str:
|
||||
"""
|
||||
Formats a user-agent string with basic info about a request.
|
||||
"""
|
||||
ua = f"transformers/{__version__}; python/{sys.version.split()[0]}; session_id/{SESSION_ID}"
|
||||
if _NEED_IMPORT_TORCH:
|
||||
ua += f"; torch/{_torch_version}"
|
||||
if DISABLE_TELEMETRY:
|
||||
return ua + "; telemetry/off"
|
||||
if is_training_run_on_sagemaker():
|
||||
ua += "; " + "; ".join(f"{k}/{v}" for k, v in define_sagemaker_information().items())
|
||||
# CI will set this value to True
|
||||
if os.environ.get("TRANSFORMERS_IS_CI", "").upper() in ENV_VARS_TRUE_VALUES:
|
||||
ua += "; is_ci/true"
|
||||
if isinstance(user_agent, dict):
|
||||
ua += "; " + "; ".join(f"{k}/{v}" for k, v in user_agent.items())
|
||||
elif isinstance(user_agent, str):
|
||||
ua += "; " + user_agent
|
||||
return ua
|
||||
|
||||
def http_get(url: str, temp_file: BinaryIO, proxies=None, resume_size=0, headers: Optional[Dict[str, str]] = None):
|
||||
"""
|
||||
Download remote file. Do not gobble up errors.
|
||||
"""
|
||||
headers = copy.deepcopy(headers)
|
||||
if resume_size > 0:
|
||||
headers["Range"] = f"bytes={resume_size}-"
|
||||
r = requests.get(url, stream=True, proxies=proxies, headers=headers)
|
||||
r.raise_for_status()
|
||||
content_length = r.headers.get("Content-Length")
|
||||
total = resume_size + int(content_length) if content_length is not None else None
|
||||
# progress = tqdm(
|
||||
# unit="B",
|
||||
# unit_scale=True,
|
||||
# unit_divisor=1024,
|
||||
# total=total,
|
||||
# initial=resume_size,
|
||||
# desc="Downloading",
|
||||
# disable=bool(logging.get_verbosity() == logging.NOTSET),
|
||||
# )
|
||||
for chunk in r.iter_content(chunk_size=1024):
|
||||
if chunk: # filter out keep-alive new chunks
|
||||
# progress.update(len(chunk))
|
||||
temp_file.write(chunk)
|
||||
# progress.close()
|
||||
|
||||
def get_from_cache(
|
||||
url: str,
|
||||
cache_dir=None,
|
||||
force_download=False,
|
||||
proxies=None,
|
||||
etag_timeout=10,
|
||||
resume_download=False,
|
||||
user_agent: Union[Dict, str, None] = None,
|
||||
use_auth_token: Union[bool, str, None] = None,
|
||||
local_files_only=False,
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
Given a URL, look for the corresponding file in the local cache. If it's not there, download it. Then return the
|
||||
path to the cached file.
|
||||
|
||||
Return:
|
||||
Local path (string) of file or if networking is off, last version of file cached on disk.
|
||||
|
||||
Raises:
|
||||
In case of non-recoverable file (non-existent or inaccessible url + no cache on disk).
|
||||
"""
|
||||
if cache_dir is None:
|
||||
cache_dir = TRANSFORMERS_CACHE
|
||||
if isinstance(cache_dir, Path):
|
||||
cache_dir = str(cache_dir)
|
||||
|
||||
os.makedirs(cache_dir, exist_ok=True)
|
||||
|
||||
headers = {"user-agent": http_user_agent(user_agent)}
|
||||
if isinstance(use_auth_token, str):
|
||||
headers["authorization"] = f"Bearer {use_auth_token}"
|
||||
elif use_auth_token:
|
||||
raise RuntimeError("`use_auth_token=True` is not supported in FastNLP now")
|
||||
# token = HfFolder.get_token()
|
||||
# if token is None:
|
||||
# raise EnvironmentError("You specified use_auth_token=True, but a huggingface token was not found.")
|
||||
# headers["authorization"] = f"Bearer {token}"
|
||||
|
||||
url_to_download = url
|
||||
etag = None
|
||||
if not local_files_only:
|
||||
try:
|
||||
r = requests.head(url, headers=headers, allow_redirects=False, proxies=proxies, timeout=etag_timeout)
|
||||
r.raise_for_status()
|
||||
etag = r.headers.get("X-Linked-Etag") or r.headers.get("ETag")
|
||||
# We favor a custom header indicating the etag of the linked resource, and
|
||||
# we fallback to the regular etag header.
|
||||
# If we don't have any of those, raise an error.
|
||||
if etag is None:
|
||||
raise OSError(
|
||||
"Distant resource does not have an ETag, we won't be able to reliably ensure reproducibility."
|
||||
)
|
||||
# In case of a redirect,
|
||||
# save an extra redirect on the request.get call,
|
||||
# and ensure we download the exact atomic version even if it changed
|
||||
# between the HEAD and the GET (unlikely, but hey).
|
||||
if 300 <= r.status_code <= 399:
|
||||
url_to_download = r.headers["Location"]
|
||||
except (requests.exceptions.SSLError, requests.exceptions.ProxyError):
|
||||
# Actually raise for those subclasses of ConnectionError
|
||||
raise
|
||||
except (requests.exceptions.ConnectionError, requests.exceptions.Timeout):
|
||||
# Otherwise, our Internet connection is down.
|
||||
# etag is None
|
||||
pass
|
||||
|
||||
filename = url_to_filename(url, etag)
|
||||
|
||||
# get cache path to put the file
|
||||
cache_path = os.path.join(cache_dir, filename)
|
||||
|
||||
# etag is None == we don't have a connection or we passed local_files_only.
|
||||
# try to get the last downloaded one
|
||||
if etag is None:
|
||||
if os.path.exists(cache_path):
|
||||
return cache_path
|
||||
else:
|
||||
matching_files = [
|
||||
file
|
||||
for file in fnmatch.filter(os.listdir(cache_dir), filename.split(".")[0] + ".*")
|
||||
if not file.endswith(".json") and not file.endswith(".lock")
|
||||
]
|
||||
if len(matching_files) > 0:
|
||||
return os.path.join(cache_dir, matching_files[-1])
|
||||
else:
|
||||
# If files cannot be found and local_files_only=True,
|
||||
# the models might've been found if local_files_only=False
|
||||
# Notify the user about that
|
||||
if local_files_only:
|
||||
raise FileNotFoundError(
|
||||
"Cannot find the requested files in the cached path and outgoing traffic has been"
|
||||
" disabled. To enable model look-ups and downloads online, set 'local_files_only'"
|
||||
" to False."
|
||||
)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Connection error, and we cannot find the requested files in the cached path."
|
||||
" Please try again or make sure your Internet connection is on."
|
||||
)
|
||||
|
||||
# From now on, etag is not None.
|
||||
if os.path.exists(cache_path) and not force_download:
|
||||
return cache_path
|
||||
|
||||
# Prevent parallel downloads of the same file with a lock.
|
||||
lock_path = cache_path + ".lock"
|
||||
with filelock(lock_path):
|
||||
|
||||
# If the download just completed while the lock was activated.
|
||||
if os.path.exists(cache_path) and not force_download:
|
||||
# Even if returning early like here, the lock will be released.
|
||||
return cache_path
|
||||
|
||||
if resume_download:
|
||||
incomplete_path = cache_path + ".incomplete"
|
||||
|
||||
@contextmanager
|
||||
def _resumable_file_manager() -> "io.BufferedWriter":
|
||||
with open(incomplete_path, "ab") as f:
|
||||
yield f
|
||||
|
||||
temp_file_manager = _resumable_file_manager
|
||||
if os.path.exists(incomplete_path):
|
||||
resume_size = os.stat(incomplete_path).st_size
|
||||
else:
|
||||
resume_size = 0
|
||||
else:
|
||||
temp_file_manager = partial(tempfile.NamedTemporaryFile, mode="wb", dir=cache_dir, delete=False)
|
||||
resume_size = 0
|
||||
|
||||
# Download to temporary file, then copy to cache dir once finished.
|
||||
# Otherwise you get corrupt cache entries if the download gets interrupted.
|
||||
with temp_file_manager() as temp_file:
|
||||
logger.info(f"{url} not found in cache or force_download set to True, downloading to {temp_file.name}")
|
||||
|
||||
http_get(url_to_download, temp_file, proxies=proxies, resume_size=resume_size, headers=headers)
|
||||
|
||||
logger.info(f"storing {url} in cache at {cache_path}")
|
||||
os.replace(temp_file.name, cache_path)
|
||||
|
||||
# NamedTemporaryFile creates a file with hardwired 0600 perms (ignoring umask), so fixing it.
|
||||
umask = os.umask(0o666)
|
||||
os.umask(umask)
|
||||
os.chmod(cache_path, 0o666 & ~umask)
|
||||
|
||||
logger.info(f"creating metadata file for {cache_path}")
|
||||
meta = {"url": url, "etag": etag}
|
||||
meta_path = cache_path + ".json"
|
||||
with open(meta_path, "w") as meta_file:
|
||||
json.dump(meta, meta_file)
|
||||
|
||||
return cache_path
|
||||
|
||||
def is_torch_fx_available():
|
||||
return _TORCH_GREATER_EQUAL_1_8 and _compare_version("torch", operator.lt, "1.9.0")
|
||||
|
||||
def is_torch_fx_proxy(x):
|
||||
if is_torch_fx_available():
|
||||
import torch.fx
|
||||
|
||||
return isinstance(x, torch.fx.Proxy)
|
||||
return False
|
||||
|
||||
def is_sentencepiece_available():
|
||||
return importlib.util.find_spec("sentencepiece") is not None
|
||||
|
||||
def is_tokenizers_available():
|
||||
return importlib.util.find_spec("tokenizers") is not None
|
||||
|
||||
def is_tensor(x):
|
||||
"""
|
||||
Tests if ``x`` is a :obj:`torch.Tensor`, :obj:`tf.Tensor`, obj:`jaxlib.xla_extension.DeviceArray` or
|
||||
:obj:`np.ndarray`.
|
||||
"""
|
||||
if is_torch_fx_proxy(x):
|
||||
return True
|
||||
|
||||
if isinstance(x, torch.Tensor):
|
||||
return True
|
||||
|
||||
return isinstance(x, np.ndarray)
|
||||
|
||||
def to_py_obj(obj):
|
||||
"""
|
||||
Convert a TensorFlow tensor, PyTorch tensor, Numpy array or python list to a python list.
|
||||
"""
|
||||
if isinstance(obj, (dict, UserDict)):
|
||||
return {k: to_py_obj(v) for k, v in obj.items()}
|
||||
elif isinstance(obj, (list, tuple)):
|
||||
return [to_py_obj(o) for o in obj]
|
||||
elif _NEED_IMPORT_TORCH and _is_torch(obj):
|
||||
return obj.detach().cpu().tolist()
|
||||
elif isinstance(obj, np.ndarray):
|
||||
return obj.tolist()
|
||||
else:
|
||||
return obj
|
||||
|
||||
def _is_numpy(x):
|
||||
return isinstance(x, np.ndarray)
|
||||
|
||||
def _is_torch(x):
|
||||
import torch
|
||||
|
||||
return isinstance(x, torch.Tensor)
|
||||
|
||||
|
||||
def _is_torch_device(x):
|
||||
import torch
|
||||
|
||||
return isinstance(x, torch.device)
|
||||
|
||||
class ModelOutput(OrderedDict):
|
||||
"""
|
||||
Base class for all model outputs as dataclass. Has a ``__getitem__`` that allows indexing by integer or slice (like
|
||||
a tuple) or strings (like a dictionary) that will ignore the ``None`` attributes. Otherwise behaves like a regular
|
||||
python dictionary.
|
||||
|
||||
.. warning::
|
||||
You can't unpack a :obj:`ModelOutput` directly. Use the :meth:`~transformers.file_utils.ModelOutput.to_tuple`
|
||||
method to convert it to a tuple before.
|
||||
"""
|
||||
|
||||
def __post_init__(self):
|
||||
class_fields = fields(self)
|
||||
|
||||
# Safety and consistency checks
|
||||
assert len(class_fields), f"{self.__class__.__name__} has no fields."
|
||||
assert all(
|
||||
field.default is None for field in class_fields[1:]
|
||||
), f"{self.__class__.__name__} should not have more than one required field."
|
||||
|
||||
first_field = getattr(self, class_fields[0].name)
|
||||
other_fields_are_none = all(getattr(self, field.name) is None for field in class_fields[1:])
|
||||
|
||||
if other_fields_are_none and not is_tensor(first_field):
|
||||
if isinstance(first_field, dict):
|
||||
iterator = first_field.items()
|
||||
first_field_iterator = True
|
||||
else:
|
||||
try:
|
||||
iterator = iter(first_field)
|
||||
first_field_iterator = True
|
||||
except TypeError:
|
||||
first_field_iterator = False
|
||||
|
||||
# if we provided an iterator as first field and the iterator is a (key, value) iterator
|
||||
# set the associated fields
|
||||
if first_field_iterator:
|
||||
for element in iterator:
|
||||
if (
|
||||
not isinstance(element, (list, tuple))
|
||||
or not len(element) == 2
|
||||
or not isinstance(element[0], str)
|
||||
):
|
||||
break
|
||||
setattr(self, element[0], element[1])
|
||||
if element[1] is not None:
|
||||
self[element[0]] = element[1]
|
||||
elif first_field is not None:
|
||||
self[class_fields[0].name] = first_field
|
||||
else:
|
||||
for field in class_fields:
|
||||
v = getattr(self, field.name)
|
||||
if v is not None:
|
||||
self[field.name] = v
|
||||
|
||||
def __delitem__(self, *args, **kwargs):
|
||||
raise Exception(f"You cannot use ``__delitem__`` on a {self.__class__.__name__} instance.")
|
||||
|
||||
def setdefault(self, *args, **kwargs):
|
||||
raise Exception(f"You cannot use ``setdefault`` on a {self.__class__.__name__} instance.")
|
||||
|
||||
def pop(self, *args, **kwargs):
|
||||
raise Exception(f"You cannot use ``pop`` on a {self.__class__.__name__} instance.")
|
||||
|
||||
def update(self, *args, **kwargs):
|
||||
raise Exception(f"You cannot use ``update`` on a {self.__class__.__name__} instance.")
|
||||
|
||||
def __getitem__(self, k):
|
||||
if isinstance(k, str):
|
||||
inner_dict = {k: v for (k, v) in self.items()}
|
||||
return inner_dict[k]
|
||||
else:
|
||||
return self.to_tuple()[k]
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name in self.keys() and value is not None:
|
||||
# Don't call self.__setitem__ to avoid recursion errors
|
||||
super().__setitem__(name, value)
|
||||
super().__setattr__(name, value)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
# Will raise a KeyException if needed
|
||||
super().__setitem__(key, value)
|
||||
# Don't call self.__setattr__ to avoid recursion errors
|
||||
super().__setattr__(key, value)
|
||||
|
||||
def to_tuple(self) -> Tuple[Any]:
|
||||
"""
|
||||
Convert self to a tuple containing all the attributes/keys that are not ``None``.
|
||||
"""
|
||||
return tuple(self[k] for k in self.keys())
|
||||
|
||||
|
||||
class ExplicitEnum(Enum):
|
||||
"""
|
||||
Enum with more explicit error message for missing values.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _missing_(cls, value):
|
||||
raise ValueError(
|
||||
f"{value} is not a valid {cls.__name__}, please select one of {list(cls._value2member_map_.keys())}"
|
||||
)
|
||||
|
||||
|
||||
class PaddingStrategy(ExplicitEnum):
|
||||
"""
|
||||
Possible values for the ``padding`` argument in :meth:`PreTrainedTokenizerBase.__call__`. Useful for tab-completion
|
||||
in an IDE.
|
||||
"""
|
||||
|
||||
LONGEST = "longest"
|
||||
MAX_LENGTH = "max_length"
|
||||
DO_NOT_PAD = "do_not_pad"
|
||||
|
||||
|
||||
class TensorType(ExplicitEnum):
|
||||
"""
|
||||
Possible values for the ``return_tensors`` argument in :meth:`PreTrainedTokenizerBase.__call__`. Useful for
|
||||
tab-completion in an IDE.
|
||||
"""
|
||||
|
||||
PYTORCH = "pt"
|
||||
NUMPY = "np"
|
393
fastNLP/transformers/torch/generation_beam_search.py
Normal file
393
fastNLP/transformers/torch/generation_beam_search.py
Normal file
@ -0,0 +1,393 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2020 The HuggingFace Inc. team
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from collections import UserDict
|
||||
from typing import Optional, Tuple
|
||||
|
||||
from .file_utils import add_start_docstrings
|
||||
from fastNLP.envs.imports import _NEED_IMPORT_TORCH
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
if _NEED_IMPORT_TORCH:
|
||||
import torch
|
||||
|
||||
|
||||
PROCESS_INPUTS_DOCSTRING = r"""
|
||||
Args:
|
||||
input_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size * num_beams, sequence_length)`):
|
||||
Indices of input sequence tokens in the vocabulary.
|
||||
|
||||
Indices can be obtained using any class inheriting from :class:`~transformers.PreTrainedTokenizer`. See
|
||||
:meth:`transformers.PreTrainedTokenizer.encode` and :meth:`transformers.PreTrainedTokenizer.__call__` for
|
||||
details.
|
||||
|
||||
`What are input IDs? <../glossary.html#input-ids>`__
|
||||
next_scores (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, 2 * num_beams)`):
|
||||
Current scores of the top :obj:`2 * num_beams` non-finished beam hypotheses.
|
||||
next_tokens (:obj:`torch.LongTensor` of shape :obj:`(batch_size, 2 * num_beams)`):
|
||||
:obj:`input_ids` of the tokens corresponding to the top :obj:`2 * num_beams` non-finished beam hypotheses.
|
||||
next_indices (:obj:`torch.LongTensor` of shape :obj:`(batch_size, 2 * num_beams)`):
|
||||
Beam indices indicating to which beam hypothesis the :obj:`next_tokens` correspond.
|
||||
pad_token_id (:obj:`int`, `optional`):
|
||||
The id of the `padding` token.
|
||||
eos_token_id (:obj:`int`, `optional`):
|
||||
The id of the `end-of-sequence` token.
|
||||
|
||||
Return:
|
||||
:obj:`UserDict`: A dictionary composed of the fields as defined above:
|
||||
|
||||
- **next_beam_scores** (:obj:`torch.FloatTensor` of shape :obj:`(batch_size * num_beams)`) -- Updated
|
||||
scores of all non-finished beams.
|
||||
- **next_beam_tokens** (:obj:`torch.FloatTensor` of shape :obj:`(batch_size * num_beams)`) -- Next tokens
|
||||
to be added to the non-finished beam_hypotheses.
|
||||
- **next_beam_indices** (:obj:`torch.FloatTensor` of shape :obj:`(batch_size * num_beams)`) -- Beam indices
|
||||
indicating to which beam the next tokens shall be added.
|
||||
|
||||
"""
|
||||
|
||||
FINALIZE_INPUTS_DOCSTRING = r"""
|
||||
Args:
|
||||
input_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size * num_beams, sequence_length)`):
|
||||
Indices of input sequence tokens in the vocabulary.
|
||||
|
||||
Indices can be obtained using any class inheriting from :class:`~transformers.PreTrainedTokenizer`. See
|
||||
:meth:`transformers.PreTrainedTokenizer.encode` and :meth:`transformers.PreTrainedTokenizer.__call__` for
|
||||
details.
|
||||
|
||||
`What are input IDs? <../glossary.html#input-ids>`__
|
||||
final_beam_scores (:obj:`torch.FloatTensor` of shape :obj:`(batch_size * num_beams)`):
|
||||
The final scores of all non-finished beams.
|
||||
final_beam_tokens (:obj:`torch.FloatTensor` of shape :obj:`(batch_size * num_beams)`):
|
||||
The last tokens to be added to the non-finished beam_hypotheses.
|
||||
final_beam_indices (:obj:`torch.FloatTensor` of shape :obj:`(batch_size * num_beams)`):
|
||||
The beam indices indicating to which beam the :obj:`final_beam_tokens` shall be added.
|
||||
pad_token_id (:obj:`int`, `optional`):
|
||||
The id of the `padding` token.
|
||||
eos_token_id (:obj:`int`, `optional`):
|
||||
The id of the `end-of-sequence` token.
|
||||
|
||||
Return:
|
||||
:obj:`torch.LongTensor` of shape :obj:`(batch_size * num_return_sequences, sequence_length)`: The generated
|
||||
sequences. The second dimension (sequence_length) is either equal to :obj:`max_length` or shorter if all
|
||||
batches finished early due to the :obj:`eos_token_id`.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class BeamScorer(ABC):
|
||||
"""
|
||||
Abstract base class for all beam scorers that are used for :meth:`~transformers.PreTrainedModel.beam_search` and
|
||||
:meth:`~transformers.PreTrainedModel.beam_sample`.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
@add_start_docstrings(PROCESS_INPUTS_DOCSTRING)
|
||||
def process(
|
||||
self,
|
||||
input_ids: "torch.LongTensor",
|
||||
next_scores: "torch.FloatTensor",
|
||||
next_tokens: "torch.LongTensor",
|
||||
next_indices: "torch.LongTensor",
|
||||
**kwargs
|
||||
) -> Tuple["torch.Tensor"]:
|
||||
raise NotImplementedError("This is an abstract method.")
|
||||
|
||||
@abstractmethod
|
||||
@add_start_docstrings(FINALIZE_INPUTS_DOCSTRING)
|
||||
def finalize(
|
||||
self,
|
||||
input_ids: "torch.LongTensor",
|
||||
next_scores: "torch.FloatTensor",
|
||||
next_tokens: "torch.LongTensor",
|
||||
next_indices: "torch.LongTensor",
|
||||
max_length: int,
|
||||
**kwargs
|
||||
) -> "torch.LongTensor":
|
||||
raise NotImplementedError("This is an abstract method.")
|
||||
|
||||
|
||||
class BeamSearchScorer(BeamScorer):
|
||||
r"""
|
||||
:class:`transformers.BeamScorer` implementing standard beam search decoding.
|
||||
|
||||
Adapted in part from `Facebook's XLM beam search code
|
||||
<https://github.com/facebookresearch/XLM/blob/9e6f6814d17be4fe5b15f2e6c43eb2b2d76daeb4/src/model/transformer.py#L529>`__.
|
||||
|
||||
Reference for the diverse beam search algorithm and implementation `Ashwin Kalyan's DBS implementation
|
||||
<https://github.com/ashwinkalyan/dbs/blob/master/dbs/beam_utils.lua>`__
|
||||
|
||||
Args:
|
||||
batch_size (:obj:`int`):
|
||||
Batch Size of :obj:`input_ids` for which standard beam search decoding is run in parallel.
|
||||
max_length (:obj:`int`):
|
||||
The maximum length of the sequence to be generated.
|
||||
num_beams (:obj:`int`):
|
||||
Number of beams for beam search.
|
||||
device (:obj:`torch.device`):
|
||||
Defines the device type (*e.g.*, :obj:`"cpu"` or :obj:`"cuda"`) on which this instance of
|
||||
:obj:`BeamSearchScorer` will be allocated.
|
||||
length_penalty (:obj:`float`, `optional`, defaults to 1.0):
|
||||
Exponential penalty to the length. 1.0 means no penalty. Set to values < 1.0 in order to encourage the
|
||||
model to generate shorter sequences, to a value > 1.0 in order to encourage the model to produce longer
|
||||
sequences.
|
||||
do_early_stopping (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether to stop the beam search when at least ``num_beams`` sentences are finished per batch or not.
|
||||
num_beam_hyps_to_keep (:obj:`int`, `optional`, defaults to 1):
|
||||
The number of beam hypotheses that shall be returned upon calling
|
||||
:meth:`~transformer.BeamSearchScorer.finalize`.
|
||||
num_beam_groups (:obj:`int`):
|
||||
Number of groups to divide :obj:`num_beams` into in order to ensure diversity among different groups of
|
||||
beams. See `this paper <https://arxiv.org/pdf/1610.02424.pdf>`__ for more details.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
batch_size: int,
|
||||
num_beams: int,
|
||||
device: "torch.device",
|
||||
length_penalty: Optional[float] = 1.0,
|
||||
do_early_stopping: Optional[bool] = False,
|
||||
num_beam_hyps_to_keep: Optional[int] = 1,
|
||||
num_beam_groups: Optional[int] = 1,
|
||||
**kwargs,
|
||||
):
|
||||
self.num_beams = num_beams
|
||||
self.device = device
|
||||
self.length_penalty = length_penalty
|
||||
self.do_early_stopping = do_early_stopping
|
||||
self.num_beam_hyps_to_keep = num_beam_hyps_to_keep
|
||||
self.num_beam_groups = num_beam_groups
|
||||
self.group_size = self.num_beams // self.num_beam_groups
|
||||
|
||||
self._is_init = False
|
||||
self._beam_hyps = [
|
||||
BeamHypotheses(
|
||||
num_beams=self.num_beams,
|
||||
length_penalty=self.length_penalty,
|
||||
early_stopping=self.do_early_stopping,
|
||||
)
|
||||
for _ in range(batch_size)
|
||||
]
|
||||
self._done = torch.tensor([False for _ in range(batch_size)], dtype=torch.bool, device=self.device)
|
||||
|
||||
if not isinstance(num_beams, int) or num_beams <= 1:
|
||||
raise ValueError(
|
||||
f"`num_beams` has to be an integer strictly greater than 1, but is {num_beams}. For `num_beams` == 1, one should make use of `greedy_search` instead."
|
||||
)
|
||||
|
||||
if not isinstance(num_beam_groups, int) or (num_beam_groups > num_beams) or (num_beams % num_beam_groups != 0):
|
||||
raise ValueError(
|
||||
f"`num_beam_groups` has to be an integer smaller or equal than `num_beams` and `num_beams` "
|
||||
f"has to be divisible by `num_beam_groups`, but is {num_beam_groups} with `num_beams` being {num_beams}."
|
||||
)
|
||||
|
||||
if "max_length" in kwargs:
|
||||
logger.warn(
|
||||
"Passing `max_length` to BeamSearchScorer is deprecated and has no effect."
|
||||
"`max_length` should be passed directly to `beam_search(...)`, `beam_sample(...)`"
|
||||
",or `group_beam_search(...)`."
|
||||
)
|
||||
|
||||
@property
|
||||
def is_done(self) -> bool:
|
||||
return self._done.all()
|
||||
|
||||
def process(
|
||||
self,
|
||||
input_ids: "torch.LongTensor",
|
||||
next_scores: "torch.FloatTensor",
|
||||
next_tokens: "torch.LongTensor",
|
||||
next_indices: "torch.LongTensor",
|
||||
pad_token_id: Optional[int] = None,
|
||||
eos_token_id: Optional[int] = None,
|
||||
) -> Tuple["torch.Tensor"]:
|
||||
cur_len = input_ids.shape[-1]
|
||||
batch_size = len(self._beam_hyps)
|
||||
assert batch_size == (input_ids.shape[0] // self.group_size)
|
||||
|
||||
device = input_ids.device
|
||||
next_beam_scores = torch.zeros((batch_size, self.group_size), dtype=next_scores.dtype, device=device)
|
||||
next_beam_tokens = torch.zeros((batch_size, self.group_size), dtype=next_tokens.dtype, device=device)
|
||||
next_beam_indices = torch.zeros((batch_size, self.group_size), dtype=next_indices.dtype, device=device)
|
||||
|
||||
for batch_idx, beam_hyp in enumerate(self._beam_hyps):
|
||||
if self._done[batch_idx]:
|
||||
assert (
|
||||
len(beam_hyp) >= self.num_beams
|
||||
), f"Batch can only be done if at least {self.num_beams} beams have been generated"
|
||||
assert (
|
||||
eos_token_id is not None and pad_token_id is not None
|
||||
), "generated beams >= num_beams -> eos_token_id and pad_token have to be defined"
|
||||
# pad the batch
|
||||
next_beam_scores[batch_idx, :] = 0
|
||||
next_beam_tokens[batch_idx, :] = pad_token_id
|
||||
next_beam_indices[batch_idx, :] = 0
|
||||
continue
|
||||
|
||||
# next tokens for this sentence
|
||||
beam_idx = 0
|
||||
for beam_token_rank, (next_token, next_score, next_index) in enumerate(
|
||||
zip(next_tokens[batch_idx], next_scores[batch_idx], next_indices[batch_idx])
|
||||
):
|
||||
batch_beam_idx = batch_idx * self.group_size + next_index
|
||||
# add to generated hypotheses if end of sentence
|
||||
if (eos_token_id is not None) and (next_token.item() == eos_token_id):
|
||||
# if beam_token does not belong to top num_beams tokens, it should not be added
|
||||
is_beam_token_worse_than_top_num_beams = beam_token_rank >= self.group_size
|
||||
if is_beam_token_worse_than_top_num_beams:
|
||||
continue
|
||||
beam_hyp.add(
|
||||
input_ids[batch_beam_idx].clone(),
|
||||
next_score.item(),
|
||||
)
|
||||
else:
|
||||
# add next predicted token since it is not eos_token
|
||||
next_beam_scores[batch_idx, beam_idx] = next_score
|
||||
next_beam_tokens[batch_idx, beam_idx] = next_token
|
||||
next_beam_indices[batch_idx, beam_idx] = batch_beam_idx
|
||||
beam_idx += 1
|
||||
|
||||
# once the beam for next step is full, don't add more tokens to it.
|
||||
if beam_idx == self.group_size:
|
||||
break
|
||||
|
||||
if beam_idx < self.group_size:
|
||||
raise ValueError(
|
||||
f"At most {self.group_size} tokens in {next_tokens[batch_idx]} can be equal to `eos_token_id: {eos_token_id}`. Make sure {next_tokens[batch_idx]} are corrected."
|
||||
)
|
||||
|
||||
# Check if we are done so that we can save a pad step if all(done)
|
||||
self._done[batch_idx] = self._done[batch_idx] or beam_hyp.is_done(
|
||||
next_scores[batch_idx].max().item(), cur_len
|
||||
)
|
||||
|
||||
return UserDict(
|
||||
{
|
||||
"next_beam_scores": next_beam_scores.view(-1),
|
||||
"next_beam_tokens": next_beam_tokens.view(-1),
|
||||
"next_beam_indices": next_beam_indices.view(-1),
|
||||
}
|
||||
)
|
||||
|
||||
def finalize(
|
||||
self,
|
||||
input_ids: "torch.LongTensor",
|
||||
final_beam_scores: "torch.FloatTensor",
|
||||
final_beam_tokens: "torch.LongTensor",
|
||||
final_beam_indices: "torch.LongTensor",
|
||||
max_length: int,
|
||||
pad_token_id: Optional[int] = None,
|
||||
eos_token_id: Optional[int] = None,
|
||||
) -> Tuple["torch.LongTensor"]:
|
||||
batch_size = len(self._beam_hyps)
|
||||
|
||||
# finalize all open beam hypotheses and add to generated hypotheses
|
||||
for batch_idx, beam_hyp in enumerate(self._beam_hyps):
|
||||
if self._done[batch_idx]:
|
||||
continue
|
||||
|
||||
# all open beam hypotheses are added to the beam hypothesis
|
||||
# beam hypothesis class automatically keeps the best beams
|
||||
for beam_id in range(self.num_beams):
|
||||
batch_beam_idx = batch_idx * self.num_beams + beam_id
|
||||
final_score = final_beam_scores[batch_beam_idx].item()
|
||||
final_tokens = input_ids[batch_beam_idx]
|
||||
beam_hyp.add(final_tokens, final_score)
|
||||
|
||||
# select the best hypotheses
|
||||
sent_lengths = input_ids.new(batch_size * self.num_beam_hyps_to_keep)
|
||||
best = []
|
||||
best_scores = torch.zeros(batch_size * self.num_beam_hyps_to_keep, device=self.device, dtype=torch.float32)
|
||||
|
||||
# retrieve best hypotheses
|
||||
for i, beam_hyp in enumerate(self._beam_hyps):
|
||||
sorted_hyps = sorted(beam_hyp.beams, key=lambda x: x[0])
|
||||
for j in range(self.num_beam_hyps_to_keep):
|
||||
best_hyp_tuple = sorted_hyps.pop()
|
||||
best_score = best_hyp_tuple[0]
|
||||
best_hyp = best_hyp_tuple[1]
|
||||
sent_lengths[self.num_beam_hyps_to_keep * i + j] = len(best_hyp)
|
||||
|
||||
# append to lists
|
||||
best.append(best_hyp)
|
||||
best_scores[i * self.num_beam_hyps_to_keep + j] = best_score
|
||||
|
||||
# prepare for adding eos
|
||||
sent_max_len = min(sent_lengths.max().item() + 1, max_length)
|
||||
decoded: "torch.LongTensor" = input_ids.new(batch_size * self.num_beam_hyps_to_keep, sent_max_len)
|
||||
# shorter batches are padded if needed
|
||||
if sent_lengths.min().item() != sent_lengths.max().item():
|
||||
assert pad_token_id is not None, "`pad_token_id` has to be defined"
|
||||
decoded.fill_(pad_token_id)
|
||||
|
||||
# fill with hypotheses and eos_token_id if the latter fits in
|
||||
for i, hypo in enumerate(best):
|
||||
decoded[i, : sent_lengths[i]] = hypo
|
||||
if sent_lengths[i] < max_length:
|
||||
decoded[i, sent_lengths[i]] = eos_token_id
|
||||
return UserDict(
|
||||
{
|
||||
"sequences": decoded,
|
||||
"sequence_scores": best_scores,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class BeamHypotheses:
|
||||
def __init__(self, num_beams: int, length_penalty: float, early_stopping: bool):
|
||||
"""
|
||||
Initialize n-best list of hypotheses.
|
||||
"""
|
||||
self.length_penalty = length_penalty
|
||||
self.early_stopping = early_stopping
|
||||
self.num_beams = num_beams
|
||||
self.beams = []
|
||||
self.worst_score = 1e9
|
||||
|
||||
def __len__(self):
|
||||
"""
|
||||
Number of hypotheses in the list.
|
||||
"""
|
||||
return len(self.beams)
|
||||
|
||||
def add(self, hyp: "torch.LongTensor", sum_logprobs: float):
|
||||
"""
|
||||
Add a new hypothesis to the list.
|
||||
"""
|
||||
score = sum_logprobs / (hyp.shape[-1] ** self.length_penalty)
|
||||
if len(self) < self.num_beams or score > self.worst_score:
|
||||
self.beams.append((score, hyp))
|
||||
if len(self) > self.num_beams:
|
||||
sorted_next_scores = sorted([(s, idx) for idx, (s, _) in enumerate(self.beams)])
|
||||
del self.beams[sorted_next_scores[0][1]]
|
||||
self.worst_score = sorted_next_scores[1][0]
|
||||
else:
|
||||
self.worst_score = min(score, self.worst_score)
|
||||
|
||||
def is_done(self, best_sum_logprobs: float, cur_len: int) -> bool:
|
||||
"""
|
||||
If there are enough hypotheses and that none of the hypotheses being generated can become better than the worst
|
||||
one in the heap, then we are done with this sentence.
|
||||
"""
|
||||
|
||||
if len(self) < self.num_beams:
|
||||
return False
|
||||
elif self.early_stopping:
|
||||
return True
|
||||
else:
|
||||
cur_score = best_sum_logprobs / cur_len ** self.length_penalty
|
||||
ret = self.worst_score >= cur_score
|
||||
return ret
|
618
fastNLP/transformers/torch/generation_logits_process.py
Normal file
618
fastNLP/transformers/torch/generation_logits_process.py
Normal file
@ -0,0 +1,618 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2020 The HuggingFace Inc. team
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import inspect
|
||||
import math
|
||||
from abc import ABC
|
||||
from typing import Callable, Iterable, List, Optional
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .file_utils import add_start_docstrings
|
||||
from fastNLP.envs.imports import _NEED_IMPORT_TORCH
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
if _NEED_IMPORT_TORCH:
|
||||
import torch
|
||||
|
||||
LOGITS_PROCESSOR_INPUTS_DOCSTRING = r"""
|
||||
Args:
|
||||
input_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`):
|
||||
Indices of input sequence tokens in the vocabulary.
|
||||
|
||||
Indices can be obtained using :class:`~transformers.BertTokenizer`. See
|
||||
:meth:`transformers.PreTrainedTokenizer.encode` and :meth:`transformers.PreTrainedTokenizer.__call__` for
|
||||
details.
|
||||
|
||||
`What are input IDs? <../glossary.html#input-ids>`__
|
||||
scores (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, config.vocab_size)`):
|
||||
Prediction scores of a language modeling head. These can be logits for each vocabulary when not using beam
|
||||
search or log softmax for each vocabulary token when using beam search
|
||||
kwargs:
|
||||
Additional logits processor specific kwargs.
|
||||
|
||||
Return:
|
||||
:obj:`torch.FloatTensor` of shape :obj:`(batch_size, config.vocab_size)`: The processed prediction scores.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class LogitsProcessor(ABC):
|
||||
"""Abstract base class for all logit processors that can be applied during generation."""
|
||||
|
||||
@add_start_docstrings(LOGITS_PROCESSOR_INPUTS_DOCSTRING)
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor") -> "torch.FloatTensor":
|
||||
"""Torch method for processing logits."""
|
||||
raise NotImplementedError(
|
||||
f"{self.__class__} is an abstract class. Only classes inheriting this class can be called."
|
||||
)
|
||||
|
||||
|
||||
class LogitsWarper(ABC):
|
||||
"""Abstract base class for all logit warpers that can be applied during generation with multinomial sampling."""
|
||||
|
||||
@add_start_docstrings(LOGITS_PROCESSOR_INPUTS_DOCSTRING)
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor") -> "torch.FloatTensor":
|
||||
"""Torch method for warping logits."""
|
||||
raise NotImplementedError(
|
||||
f"{self.__class__} is an abstract class. Only classes inheriting this class can be called."
|
||||
)
|
||||
|
||||
|
||||
class LogitsProcessorList(list):
|
||||
"""
|
||||
This class can be used to create a list of :class:`~transformers.LogitsProcessor` or
|
||||
:class:`~transformers.LogitsWarper` to subsequently process a :obj:`scores` input tensor. This class inherits from
|
||||
list and adds a specific `__call__` method to apply each :class:`~transformers.LogitsProcessor` or
|
||||
:class:`~transformers.LogitsWarper` to the inputs.
|
||||
"""
|
||||
|
||||
@add_start_docstrings(LOGITS_PROCESSOR_INPUTS_DOCSTRING)
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor", **kwargs) -> "torch.FloatTensor":
|
||||
for processor in self:
|
||||
function_args = inspect.signature(processor.__call__).parameters
|
||||
if len(function_args) > 2:
|
||||
assert all(
|
||||
arg in kwargs for arg in list(function_args.keys())[2:]
|
||||
), f"Make sure that all the required parameters: {list(function_args.keys())} for {processor.__class__} are passed to the logits processor."
|
||||
scores = processor(input_ids, scores, **kwargs)
|
||||
else:
|
||||
scores = processor(input_ids, scores)
|
||||
return scores
|
||||
|
||||
|
||||
class MinLengthLogitsProcessor(LogitsProcessor):
|
||||
r"""
|
||||
:class:`transformers.LogitsProcessor` enforcing a min-length by setting EOS probability to 0.
|
||||
|
||||
Args:
|
||||
min_length (:obj:`int`):
|
||||
The minimum length below which the score of :obj:`eos_token_id` is set to :obj:`-float("Inf")`.
|
||||
eos_token_id (:obj:`int`):
|
||||
The id of the `end-of-sequence` token.
|
||||
"""
|
||||
|
||||
def __init__(self, min_length: int, eos_token_id: int):
|
||||
if not isinstance(min_length, int) or min_length < 0:
|
||||
raise ValueError(f"`min_length` has to be a positive integer, but is {min_length}")
|
||||
|
||||
if not isinstance(eos_token_id, int) or eos_token_id < 0:
|
||||
raise ValueError(f"`eos_token_id` has to be a positive integer, but is {eos_token_id}")
|
||||
|
||||
self.min_length = min_length
|
||||
self.eos_token_id = eos_token_id
|
||||
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor") -> "torch.FloatTensor":
|
||||
cur_len = input_ids.shape[-1]
|
||||
if cur_len < self.min_length:
|
||||
scores[:, self.eos_token_id] = -float("inf")
|
||||
return scores
|
||||
|
||||
|
||||
class TemperatureLogitsWarper(LogitsWarper):
|
||||
r"""
|
||||
:class:`transformers.LogitsWarper` for temperature (exponential scaling output probability distribution).
|
||||
|
||||
Args:
|
||||
temperature (:obj:`float`):
|
||||
The value used to module the logits distribution.
|
||||
"""
|
||||
|
||||
def __init__(self, temperature: float):
|
||||
if not isinstance(temperature, float) or not (temperature > 0):
|
||||
raise ValueError(f"`temperature` has to be a strictly positive float, but is {temperature}")
|
||||
|
||||
self.temperature = temperature
|
||||
|
||||
def __call__(self, input_ids: "torch.Tensor", scores: "torch.Tensor") -> "torch.FloatTensor":
|
||||
scores = scores / self.temperature
|
||||
return scores
|
||||
|
||||
|
||||
class RepetitionPenaltyLogitsProcessor(LogitsProcessor):
|
||||
r"""
|
||||
:class:`transformers.LogitsProcessor` enforcing an exponential penalty on repeated sequences.
|
||||
|
||||
Args:
|
||||
repetition_penalty (:obj:`float`):
|
||||
The parameter for repetition penalty. 1.0 means no penalty. See `this paper
|
||||
<https://arxiv.org/pdf/1909.05858.pdf>`__ for more details.
|
||||
"""
|
||||
|
||||
def __init__(self, penalty: float):
|
||||
if not isinstance(penalty, float) or not (penalty > 0):
|
||||
raise ValueError(f"`penalty` has to be a strictly positive float, but is {penalty}")
|
||||
|
||||
self.penalty = penalty
|
||||
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor") -> "torch.FloatTensor":
|
||||
score = torch.gather(scores, 1, input_ids)
|
||||
|
||||
# if score < 0 then repetition penalty has to be multiplied to reduce the previous token probability
|
||||
score = torch.where(score < 0, score * self.penalty, score / self.penalty)
|
||||
|
||||
scores.scatter_(1, input_ids, score)
|
||||
return scores
|
||||
|
||||
|
||||
class TopPLogitsWarper(LogitsWarper):
|
||||
"""
|
||||
:class:`transformers.LogitsWarper` that performs top-p, i.e. restricting to top tokens summing to prob_cut_off <=
|
||||
prob_cut_off.
|
||||
|
||||
Args:
|
||||
top_p (:obj:`float`):
|
||||
If set to < 1, only the most probable tokens with probabilities that add up to :obj:`top_p` or higher are
|
||||
kept for generation.
|
||||
filter_value (:obj:`float`, `optional`, defaults to :obj:`-float("Inf")`):
|
||||
All filtered values will be set to this float value.
|
||||
min_tokens_to_keep (:obj:`int`, `optional`, defaults to 1):
|
||||
Minimum number of tokens that cannot be filtered.
|
||||
"""
|
||||
|
||||
def __init__(self, top_p: float, filter_value: float = -float("Inf"), min_tokens_to_keep: int = 1):
|
||||
top_p = float(top_p)
|
||||
if top_p < 0 or top_p > 1.0:
|
||||
raise ValueError(f"`top_p` has to be a float > 0 and < 1, but is {top_p}")
|
||||
|
||||
self.top_p = top_p
|
||||
self.filter_value = filter_value
|
||||
self.min_tokens_to_keep = min_tokens_to_keep
|
||||
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor") -> "torch.FloatTensor":
|
||||
sorted_logits, sorted_indices = torch.sort(scores, descending=True)
|
||||
cumulative_probs = sorted_logits.softmax(dim=-1).cumsum(dim=-1)
|
||||
|
||||
# Remove tokens with cumulative top_p above the threshold (token with 0 are kept)
|
||||
sorted_indices_to_remove = cumulative_probs > self.top_p
|
||||
if self.min_tokens_to_keep > 1:
|
||||
# Keep at least min_tokens_to_keep (set to min_tokens_to_keep-1 because we add the first one below)
|
||||
sorted_indices_to_remove[..., : self.min_tokens_to_keep - 1] = 0
|
||||
# Shift the indices to the right to keep also the first token above the threshold
|
||||
sorted_indices_to_remove[..., 1:] = sorted_indices_to_remove[..., :-1].clone()
|
||||
sorted_indices_to_remove[..., 0] = 0
|
||||
|
||||
# scatter sorted tensors to original indexing
|
||||
indices_to_remove = sorted_indices_to_remove.scatter(1, sorted_indices, sorted_indices_to_remove)
|
||||
scores = scores.masked_fill(indices_to_remove, self.filter_value)
|
||||
return scores
|
||||
|
||||
|
||||
class TopKLogitsWarper(LogitsWarper):
|
||||
r"""
|
||||
:class:`transformers.LogitsWarper` that performs top-k, i.e. restricting to the k highest probability elements.
|
||||
|
||||
Args:
|
||||
top_k (:obj:`int`):
|
||||
The number of highest probability vocabulary tokens to keep for top-k-filtering.
|
||||
filter_value (:obj:`float`, `optional`, defaults to :obj:`-float("Inf")`):
|
||||
All filtered values will be set to this float value.
|
||||
min_tokens_to_keep (:obj:`int`, `optional`, defaults to 1):
|
||||
Minimum number of tokens that cannot be filtered.
|
||||
"""
|
||||
|
||||
def __init__(self, top_k: int, filter_value: float = -float("Inf"), min_tokens_to_keep: int = 1):
|
||||
if not isinstance(top_k, int) or top_k <= 0:
|
||||
raise ValueError(f"`top_k` has to be a strictly positive integer, but is {top_k}")
|
||||
|
||||
self.top_k = top_k
|
||||
self.filter_value = filter_value
|
||||
self.min_tokens_to_keep = min_tokens_to_keep
|
||||
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor") -> "torch.FloatTensor":
|
||||
top_k = min(max(self.top_k, self.min_tokens_to_keep), scores.size(-1)) # Safety check
|
||||
# Remove all tokens with a probability less than the last token of the top-k
|
||||
indices_to_remove = scores < torch.topk(scores, top_k)[0][..., -1, None]
|
||||
scores = scores.masked_fill(indices_to_remove, self.filter_value)
|
||||
return scores
|
||||
|
||||
|
||||
def _get_ngrams(ngram_size: int, prev_input_ids: "torch.Tensor", num_hypos: int):
|
||||
generated_ngrams = [{} for _ in range(num_hypos)]
|
||||
for idx in range(num_hypos):
|
||||
gen_tokens = prev_input_ids[idx].tolist()
|
||||
generated_ngram = generated_ngrams[idx]
|
||||
for ngram in zip(*[gen_tokens[i:] for i in range(ngram_size)]):
|
||||
prev_ngram_tuple = tuple(ngram[:-1])
|
||||
generated_ngram[prev_ngram_tuple] = generated_ngram.get(prev_ngram_tuple, []) + [ngram[-1]]
|
||||
return generated_ngrams
|
||||
|
||||
|
||||
def _get_generated_ngrams(banned_ngrams, prev_input_ids, ngram_size, cur_len):
|
||||
# Before decoding the next token, prevent decoding of ngrams that have already appeared
|
||||
start_idx = cur_len + 1 - ngram_size
|
||||
ngram_idx = tuple(prev_input_ids[start_idx:cur_len].tolist())
|
||||
return banned_ngrams.get(ngram_idx, [])
|
||||
|
||||
|
||||
def _calc_banned_ngram_tokens(
|
||||
ngram_size: int, prev_input_ids: "torch.Tensor", num_hypos: int, cur_len: int
|
||||
) -> List[Iterable[int]]:
|
||||
"""Copied from fairseq for no_repeat_ngram in beam_search"""
|
||||
if cur_len + 1 < ngram_size:
|
||||
# return no banned tokens if we haven't generated no_repeat_ngram_size tokens yet
|
||||
return [[] for _ in range(num_hypos)]
|
||||
|
||||
generated_ngrams = _get_ngrams(ngram_size, prev_input_ids, num_hypos)
|
||||
|
||||
banned_tokens = [
|
||||
_get_generated_ngrams(generated_ngrams[hypo_idx], prev_input_ids[hypo_idx], ngram_size, cur_len)
|
||||
for hypo_idx in range(num_hypos)
|
||||
]
|
||||
return banned_tokens
|
||||
|
||||
|
||||
class NoRepeatNGramLogitsProcessor(LogitsProcessor):
|
||||
r"""
|
||||
:class:`transformers.LogitsProcessor` that enforces no repetition of n-grams. See `Fairseq
|
||||
<https://github.com/pytorch/fairseq/blob/a07cb6f40480928c9e0548b737aadd36ee66ac76/fairseq/sequence_generator.py#L345>`__.
|
||||
|
||||
Args:
|
||||
ngram_size (:obj:`int`):
|
||||
All ngrams of size :obj:`ngram_size` can only occur once.
|
||||
"""
|
||||
|
||||
def __init__(self, ngram_size: int):
|
||||
if not isinstance(ngram_size, int) or ngram_size <= 0:
|
||||
raise ValueError(f"`ngram_size` has to be a strictly positive integer, but is {ngram_size}")
|
||||
self.ngram_size = ngram_size
|
||||
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor") -> "torch.FloatTensor":
|
||||
num_batch_hypotheses = scores.shape[0]
|
||||
cur_len = input_ids.shape[-1]
|
||||
banned_batch_tokens = _calc_banned_ngram_tokens(self.ngram_size, input_ids, num_batch_hypotheses, cur_len)
|
||||
|
||||
for i, banned_tokens in enumerate(banned_batch_tokens):
|
||||
scores[i, banned_tokens] = -float("inf")
|
||||
|
||||
return scores
|
||||
|
||||
|
||||
class EncoderNoRepeatNGramLogitsProcessor(LogitsProcessor):
|
||||
r"""
|
||||
:class:`transformers.LogitsProcessor` that enforces no repetition of encoder input ids n-grams for the decoder ids.
|
||||
See `ParlAI <https://github.com/facebookresearch/ParlAI/blob/master/parlai/core/torch_generator_agent.py#L1350>`__.
|
||||
|
||||
Args:
|
||||
encoder_ngram_size (:obj:`int`):
|
||||
All ngrams of size :obj:`ngram_size` can only occur within the encoder input ids.
|
||||
encoder_input_ids (:obj:`int`):
|
||||
The encoder_input_ids that should not be repeated within the decoder ids.
|
||||
"""
|
||||
|
||||
def __init__(self, encoder_ngram_size: int, encoder_input_ids: "torch.LongTensor"):
|
||||
if not isinstance(encoder_ngram_size, int) or encoder_ngram_size <= 0:
|
||||
raise ValueError(
|
||||
f"`encoder_ngram_size` has to be a strictly positive integer, but is {encoder_ngram_size}"
|
||||
)
|
||||
self.ngram_size = encoder_ngram_size
|
||||
if len(encoder_input_ids.shape) == 1:
|
||||
encoder_input_ids = encoder_input_ids.unsqueeze(0)
|
||||
self.batch_size = encoder_input_ids.shape[0]
|
||||
self.generated_ngrams = _get_ngrams(encoder_ngram_size, encoder_input_ids, self.batch_size)
|
||||
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor") -> "torch.FloatTensor":
|
||||
# B x num_beams
|
||||
num_hypos = scores.shape[0]
|
||||
num_beams = num_hypos // self.batch_size
|
||||
cur_len = input_ids.shape[-1]
|
||||
banned_batch_tokens = [
|
||||
_get_generated_ngrams(
|
||||
self.generated_ngrams[hypo_idx // num_beams], input_ids[hypo_idx], self.ngram_size, cur_len
|
||||
)
|
||||
for hypo_idx in range(num_hypos)
|
||||
]
|
||||
|
||||
for i, banned_tokens in enumerate(banned_batch_tokens):
|
||||
scores[i, banned_tokens] = -float("inf")
|
||||
|
||||
return scores
|
||||
|
||||
|
||||
class NoBadWordsLogitsProcessor(LogitsProcessor):
|
||||
"""
|
||||
:class:`transformers.LogitsProcessor` that enforces that specified sequences will never be sampled.
|
||||
|
||||
Args:
|
||||
bad_words_ids (:obj:`List[List[int]]`):
|
||||
List of list of token ids that are not allowed to be generated. In order to get the tokens of the words
|
||||
that should not appear in the generated text, use :obj:`tokenizer(bad_word,
|
||||
add_prefix_space=True).input_ids`.
|
||||
eos_token_id (:obj:`int`):
|
||||
The id of the `end-of-sequence` token.
|
||||
"""
|
||||
|
||||
def __init__(self, bad_words_ids: List[List[int]], eos_token_id: int):
|
||||
|
||||
if not isinstance(bad_words_ids, List) or len(bad_words_ids) == 0:
|
||||
raise ValueError(f"`bad_words_ids` has to be a non-emtpy list, but is {bad_words_ids}.")
|
||||
if any(not isinstance(bad_word_ids, list) for bad_word_ids in bad_words_ids):
|
||||
raise ValueError(f"`bad_words_ids` has to be a list of lists, but is {bad_words_ids}.")
|
||||
if any(
|
||||
any((not isinstance(token_id, (int, np.integer)) or token_id < 0) for token_id in bad_word_ids)
|
||||
for bad_word_ids in bad_words_ids
|
||||
):
|
||||
raise ValueError(
|
||||
f"Each list in `bad_words_ids` has to be a list of positive integers, but is {bad_words_ids}."
|
||||
)
|
||||
|
||||
bad_words_ids = list(filter(lambda bad_token_seq: bad_token_seq != [eos_token_id], bad_words_ids))
|
||||
self.bad_words_id_length_1 = []
|
||||
self.bad_words_id_length_greater_than_1 = []
|
||||
for word in bad_words_ids:
|
||||
if len(word) == 1:
|
||||
self.bad_words_id_length_1.append(word[0])
|
||||
else:
|
||||
self.bad_words_id_length_greater_than_1.append(word)
|
||||
|
||||
self.static_bad_words_mask: Optional[torch.LongTensor] = None
|
||||
|
||||
for banned_token_seq in self.bad_words_id_length_greater_than_1:
|
||||
assert len(banned_token_seq) > 0, f"Banned words token sequences {bad_words_ids} cannot have an empty list"
|
||||
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor") -> "torch.FloatTensor":
|
||||
if self.static_bad_words_mask is None and len(self.bad_words_id_length_1) > 0:
|
||||
self.static_bad_words_mask = self._calc_static_bad_word_mask(scores)
|
||||
|
||||
dynamic_banned_tokens = self._calc_banned_bad_words_ids(input_ids.tolist())
|
||||
scores = self._set_scores_to_inf_for_banned_tokens(scores, dynamic_banned_tokens)
|
||||
|
||||
return scores
|
||||
|
||||
def _calc_static_bad_word_mask(self, scores: "torch.FloatTensor") -> "torch.BoolTensor":
|
||||
static_bad_words_mask = torch.zeros(scores.shape[1])
|
||||
static_bad_words_mask[self.bad_words_id_length_1] = 1
|
||||
return static_bad_words_mask.unsqueeze(0).to(scores.device).bool()
|
||||
|
||||
def _tokens_match(self, prev_tokens: List[int], tokens: List[int]) -> bool:
|
||||
if len(tokens) == 0:
|
||||
# if bad word tokens is just one token always ban it
|
||||
return True
|
||||
elif len(tokens) > len(prev_tokens):
|
||||
# if bad word tokens are longer then prev input_ids they can't be equal
|
||||
return False
|
||||
else:
|
||||
return prev_tokens[-len(tokens) :] == tokens
|
||||
|
||||
def _calc_banned_bad_words_ids(self, prev_input_ids: List[List[int]]) -> Iterable[int]:
|
||||
banned_tokens = []
|
||||
for prev_input_ids_slice in prev_input_ids:
|
||||
banned_tokens_slice = []
|
||||
for banned_token_seq in self.bad_words_id_length_greater_than_1:
|
||||
if self._tokens_match(prev_input_ids_slice, banned_token_seq[:-1]):
|
||||
banned_tokens_slice.append(banned_token_seq[-1])
|
||||
|
||||
banned_tokens.append(banned_tokens_slice)
|
||||
|
||||
return banned_tokens
|
||||
|
||||
def _set_scores_to_inf_for_banned_tokens(
|
||||
self, scores: "torch.Tensor", banned_tokens: List[List[int]]
|
||||
) -> "torch.Tensor":
|
||||
"""
|
||||
Modifies the scores in place by setting the banned token positions to `-inf`. Banned token is expected to be a
|
||||
list of list of banned tokens to ban in the format [[batch index, vocabulary position],...
|
||||
|
||||
Args:
|
||||
scores: logits distribution of shape (batch size, vocabulary size)
|
||||
banned_tokens: list of list of tokens to ban of length (batch_size)
|
||||
"""
|
||||
banned_mask_list = []
|
||||
for idx, batch_banned_tokens in enumerate(banned_tokens):
|
||||
for token in batch_banned_tokens:
|
||||
# Eliminates invalid bad word IDs that are over the vocabulary size.
|
||||
if token <= scores.shape[1]:
|
||||
banned_mask_list.append([idx, token])
|
||||
else:
|
||||
logger.error(
|
||||
f"An invalid bad word ID is defined: {token}. This ID is not contained in the"
|
||||
f"vocabulary, and is therefore ignored."
|
||||
)
|
||||
if not banned_mask_list and self.static_bad_words_mask is None:
|
||||
return scores
|
||||
|
||||
else:
|
||||
if banned_mask_list:
|
||||
banned_mask = torch.LongTensor(banned_mask_list)
|
||||
indices = torch.ones(len(banned_mask))
|
||||
# A sparse tensor is generated from a list of coordinates: [[0, 1], [0, 2], [2, 0]]. A conversion to dense tensor generates:
|
||||
# [ 0 1 1 ]
|
||||
# [ 0 0 0 ]
|
||||
# [ 1 0 0 ]
|
||||
|
||||
banned_mask = (
|
||||
torch.sparse.LongTensor(banned_mask.t(), indices, scores.size())
|
||||
.to(scores.device)
|
||||
.to_dense()
|
||||
.bool()
|
||||
)
|
||||
|
||||
if self.static_bad_words_mask is not None:
|
||||
banned_mask = torch.bitwise_or(banned_mask, self.static_bad_words_mask)
|
||||
else:
|
||||
banned_mask = self.static_bad_words_mask
|
||||
|
||||
scores = scores.masked_fill(banned_mask, -float("inf"))
|
||||
return scores
|
||||
|
||||
|
||||
class PrefixConstrainedLogitsProcessor(LogitsProcessor):
|
||||
r"""
|
||||
:class:`transformers.LogitsProcessor` that enforces constrained generation and is useful for prefix-conditioned
|
||||
constrained generation. See `Autoregressive Entity Retrieval <https://arxiv.org/abs/2010.00904>`__ for more
|
||||
information.
|
||||
|
||||
Args:
|
||||
prefix_allowed_tokens_fn: (:obj:`Callable[[int, torch.Tensor], List[int]]`):
|
||||
This function constraints the beam search to allowed tokens only at each step. This function takes 2
|
||||
arguments :obj:`inputs_ids` and the batch ID :obj:`batch_id`. It has to return a list with the allowed
|
||||
tokens for the next generation step conditioned on the previously generated tokens :obj:`inputs_ids` and
|
||||
the batch ID :obj:`batch_id`.
|
||||
"""
|
||||
|
||||
def __init__(self, prefix_allowed_tokens_fn: Callable[[int, "torch.Tensor"], List[int]], num_beams: int):
|
||||
self._prefix_allowed_tokens_fn = prefix_allowed_tokens_fn
|
||||
self._num_beams = num_beams
|
||||
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor") -> "torch.FloatTensor":
|
||||
mask = torch.full_like(scores, -math.inf)
|
||||
for batch_id, beam_sent in enumerate(input_ids.view(-1, self._num_beams, input_ids.shape[-1])):
|
||||
for beam_id, sent in enumerate(beam_sent):
|
||||
mask[batch_id * self._num_beams + beam_id, self._prefix_allowed_tokens_fn(batch_id, sent)] = 0
|
||||
|
||||
return scores + mask
|
||||
|
||||
|
||||
class HammingDiversityLogitsProcessor(LogitsProcessor):
|
||||
r"""
|
||||
:class:`transformers.LogitsProcessor` that enforces diverse beam search. Note that this logits processor is only
|
||||
effective for :meth:`transformers.PreTrainedModel.group_beam_search`. See `Diverse Beam Search: Decoding Diverse
|
||||
Solutions from Neural Sequence Models <https://arxiv.org/pdf/1610.02424.pdf>`__ for more details.
|
||||
|
||||
Args:
|
||||
diversity_penalty (:obj:`float`):
|
||||
This value is subtracted from a beam's score if it generates a token same as any beam from other group at a
|
||||
particular time. Note that :obj:`diversity_penalty` is only effective if ``group beam search`` is enabled.
|
||||
num_beams (:obj:`int`):
|
||||
Number of beams used for group beam search. See `this paper <https://arxiv.org/pdf/1610.02424.pdf>`__ for
|
||||
more details.
|
||||
num_beam_groups (:obj:`int`):
|
||||
Number of groups to divide :obj:`num_beams` into in order to ensure diversity among different groups of
|
||||
beams. See `this paper <https://arxiv.org/pdf/1610.02424.pdf>`__ for more details.
|
||||
"""
|
||||
|
||||
def __init__(self, diversity_penalty: float, num_beams: int, num_beam_groups: int):
|
||||
if not isinstance(diversity_penalty, float) or (not diversity_penalty > 0.0):
|
||||
raise ValueError("`diversity_penalty` should be a float strictly larger than 0.")
|
||||
self._diversity_penalty = diversity_penalty
|
||||
if not isinstance(num_beams, int) or num_beams < 2:
|
||||
raise ValueError("`num_beams` should be an integer strictly larger than 1.")
|
||||
self._num_beams = num_beams
|
||||
if not isinstance(num_beam_groups, int) or num_beam_groups < 2:
|
||||
raise ValueError("`num_beam_groups` should be an integer strictly larger than 1.")
|
||||
if num_beam_groups > num_beams:
|
||||
raise ValueError("`beam_groups` has to be smaller or equal to `num_beams`.")
|
||||
self._num_sub_beams = num_beams // num_beam_groups
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
input_ids: "torch.LongTensor",
|
||||
scores: "torch.FloatTensor",
|
||||
current_tokens: "torch.LongTensor",
|
||||
beam_group_idx: int,
|
||||
) -> "torch.FloatTensor":
|
||||
# hamming diversity: penalise using same token in current group which was used in previous groups at
|
||||
# the same time step
|
||||
batch_size = current_tokens.shape[0] // self._num_beams
|
||||
group_start_idx = beam_group_idx * self._num_sub_beams
|
||||
group_end_idx = min(group_start_idx + self._num_sub_beams, self._num_beams)
|
||||
group_size = group_end_idx - group_start_idx
|
||||
vocab_size = scores.shape[-1]
|
||||
|
||||
if group_start_idx == 0:
|
||||
return scores
|
||||
|
||||
for batch_idx in range(batch_size):
|
||||
# predicted tokens of last time step of previous groups
|
||||
previous_group_tokens = current_tokens[
|
||||
batch_idx * self._num_beams : batch_idx * self._num_beams + group_start_idx
|
||||
]
|
||||
token_frequency = torch.bincount(previous_group_tokens, minlength=vocab_size).to(scores.device)
|
||||
scores[batch_idx * group_size : (batch_idx + 1) * group_size] -= self._diversity_penalty * token_frequency
|
||||
|
||||
return scores
|
||||
|
||||
|
||||
class ForcedBOSTokenLogitsProcessor(LogitsProcessor):
|
||||
r"""
|
||||
:class:`~transformers.LogitsProcessor` that enforces the specified token as the first generated token.
|
||||
|
||||
Args:
|
||||
bos_token_id (:obj:`int`):
|
||||
The id of the token to force as the first generated token.
|
||||
"""
|
||||
|
||||
def __init__(self, bos_token_id: int):
|
||||
self.bos_token_id = bos_token_id
|
||||
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor") -> "torch.FloatTensor":
|
||||
cur_len = input_ids.shape[-1]
|
||||
if cur_len == 1:
|
||||
num_tokens = scores.shape[1]
|
||||
scores[:, [i for i in range(num_tokens) if i != self.bos_token_id]] = -float("inf")
|
||||
scores[:, self.bos_token_id] = 0
|
||||
return scores
|
||||
|
||||
|
||||
class ForcedEOSTokenLogitsProcessor(LogitsProcessor):
|
||||
r"""
|
||||
:class:`~transformers.LogitsProcessor` that enforces the specified token as the last generated token when
|
||||
:obj:`max_length` is reached.
|
||||
|
||||
Args:
|
||||
max_length (:obj:`int`):
|
||||
The maximum length of the sequence to be generated.
|
||||
eos_token_id (:obj:`int`):
|
||||
The id of the token to force as the last generated token when :obj:`max_length` is reached.
|
||||
"""
|
||||
|
||||
def __init__(self, max_length: int, eos_token_id: int):
|
||||
self.max_length = max_length
|
||||
self.eos_token_id = eos_token_id
|
||||
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor") -> "torch.FloatTensor":
|
||||
cur_len = input_ids.shape[-1]
|
||||
if cur_len == self.max_length - 1:
|
||||
num_tokens = scores.shape[1]
|
||||
scores[:, [i for i in range(num_tokens) if i != self.eos_token_id]] = -float("inf")
|
||||
scores[:, self.eos_token_id] = 0
|
||||
return scores
|
||||
|
||||
|
||||
class InfNanRemoveLogitsProcessor(LogitsProcessor):
|
||||
r"""
|
||||
:class:`~transformers.LogitsProcessor` that removes all :obj:`nan` and :obj:`inf` values to avoid the generation
|
||||
method to fail. Note that using the logits processor should only be used if necessary since it can slow down the
|
||||
generation method. :obj:`max_length` is reached.
|
||||
"""
|
||||
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor") -> "torch.FloatTensor":
|
||||
# set all nan values to 0.0
|
||||
scores[scores != scores] = 0.0
|
||||
|
||||
# set all inf values to max possible value
|
||||
scores[scores == float("inf")] = torch.finfo(scores.dtype).max
|
||||
|
||||
return scores
|
128
fastNLP/transformers/torch/generation_stopping_criteria.py
Normal file
128
fastNLP/transformers/torch/generation_stopping_criteria.py
Normal file
@ -0,0 +1,128 @@
|
||||
import time
|
||||
from abc import ABC
|
||||
from copy import deepcopy
|
||||
from typing import Optional
|
||||
|
||||
from .file_utils import add_start_docstrings
|
||||
from fastNLP.envs.imports import _NEED_IMPORT_TORCH
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
if _NEED_IMPORT_TORCH:
|
||||
import torch
|
||||
|
||||
STOPPING_CRITERIA_INPUTS_DOCSTRING = r"""
|
||||
Args:
|
||||
input_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`):
|
||||
Indices of input sequence tokens in the vocabulary.
|
||||
|
||||
Indices can be obtained using :class:`~transformers.BertTokenizer`. See
|
||||
:meth:`transformers.PreTrainedTokenizer.encode` and :meth:`transformers.PreTrainedTokenizer.__call__` for
|
||||
details.
|
||||
|
||||
`What are input IDs? <../glossary.html#input-ids>`__
|
||||
scores (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, config.vocab_size)`):
|
||||
Prediction scores of a language modeling head. These can be scores for each vocabulary token before SoftMax
|
||||
or scores for each vocabulary token after SoftMax.
|
||||
kwargs:
|
||||
Additional stopping criteria specific kwargs.
|
||||
|
||||
Return:
|
||||
:obj:`bool`. :obj:`False` indicates we should continue, :obj:`True` indicates we should stop.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class StoppingCriteria(ABC):
|
||||
"""Abstract base class for all stopping criteria that can be applied during generation."""
|
||||
|
||||
@add_start_docstrings(STOPPING_CRITERIA_INPUTS_DOCSTRING)
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor", **kwargs) -> bool:
|
||||
raise NotImplementedError("StoppingCriteria needs to be subclassed")
|
||||
|
||||
|
||||
class MaxLengthCriteria(StoppingCriteria):
|
||||
"""
|
||||
This class can be used to stop generation whenever the full generated number of tokens exceeds :obj:`max_length`.
|
||||
Keep in mind for decoder-only type of transformers, this will include the initial prompted tokens.
|
||||
|
||||
Args:
|
||||
max_length (:obj:`int`):
|
||||
The maximum length that the output sequence can have in number of tokens.
|
||||
"""
|
||||
|
||||
def __init__(self, max_length: int):
|
||||
self.max_length = max_length
|
||||
|
||||
@add_start_docstrings(STOPPING_CRITERIA_INPUTS_DOCSTRING)
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor", **kwargs) -> bool:
|
||||
return input_ids.shape[-1] >= self.max_length
|
||||
|
||||
|
||||
class MaxNewTokensCriteria(StoppingCriteria):
|
||||
"""
|
||||
This class can be used to stop generation whenever the generated number of tokens exceeds :obj:`max_new_tokens`.
|
||||
Keep in mind for decoder-only type of transformers, this will **not** include the initial prompted tokens. This is
|
||||
very close to :obj:`MaxLengthCriteria` but ignores the number of initial tokens.
|
||||
|
||||
Args:
|
||||
start_length (:obj:`int`):
|
||||
The number of initial tokens.
|
||||
max_new_tokens (:obj:`int`):
|
||||
The maximum number of tokens to generate.
|
||||
"""
|
||||
|
||||
def __init__(self, start_length: int, max_new_tokens: int):
|
||||
self.start_length = start_length
|
||||
self.max_new_tokens = max_new_tokens
|
||||
self.max_length = start_length + max_new_tokens
|
||||
|
||||
@add_start_docstrings(STOPPING_CRITERIA_INPUTS_DOCSTRING)
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor", **kwargs) -> bool:
|
||||
return input_ids.shape[-1] >= self.max_length
|
||||
|
||||
|
||||
class MaxTimeCriteria(StoppingCriteria):
|
||||
"""
|
||||
This class can be used to stop generation whenever the full generation exceeds some amount of time. By default, the
|
||||
time will start being counted when you initialize this function. You can override this by passing an
|
||||
:obj:`initial_time`.
|
||||
|
||||
Args:
|
||||
max_time (:obj:`float`):
|
||||
The maximum allowed time in seconds for the generation.
|
||||
initial_time (:obj:`float`, `optional`, defaults to :obj:`time.time()`):
|
||||
The start of the generation allowed time.
|
||||
"""
|
||||
|
||||
def __init__(self, max_time: float, initial_timestamp: Optional[float] = None):
|
||||
self.max_time = max_time
|
||||
self.initial_timestamp = time.time() if initial_timestamp is None else initial_timestamp
|
||||
|
||||
@add_start_docstrings(STOPPING_CRITERIA_INPUTS_DOCSTRING)
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor", **kwargs) -> bool:
|
||||
return time.time() - self.initial_timestamp > self.max_time
|
||||
|
||||
|
||||
class StoppingCriteriaList(list):
|
||||
@add_start_docstrings(STOPPING_CRITERIA_INPUTS_DOCSTRING)
|
||||
def __call__(self, input_ids: "torch.LongTensor", scores: "torch.FloatTensor", **kwargs) -> bool:
|
||||
return any(criteria(input_ids, scores) for criteria in self)
|
||||
|
||||
@property
|
||||
def max_length(self) -> Optional[int]:
|
||||
for stopping_criterium in self:
|
||||
if isinstance(stopping_criterium, MaxLengthCriteria):
|
||||
return stopping_criterium.max_length
|
||||
elif isinstance(stopping_criterium, MaxNewTokensCriteria):
|
||||
return stopping_criterium.max_length
|
||||
return None
|
||||
|
||||
|
||||
def validate_stopping_criteria(stopping_criteria: StoppingCriteriaList, max_length: int) -> StoppingCriteriaList:
|
||||
stopping_max_length = stopping_criteria.max_length
|
||||
new_stopping_criteria = deepcopy(stopping_criteria)
|
||||
if stopping_max_length is not None and stopping_max_length != max_length:
|
||||
logger.warn("You set different `max_length` for stopping criteria and `max_length` parameter", UserWarning)
|
||||
elif stopping_max_length is None:
|
||||
new_stopping_criteria.append(MaxLengthCriteria(max_length=max_length))
|
||||
return new_stopping_criteria
|
2579
fastNLP/transformers/torch/generation_utils.py
Normal file
2579
fastNLP/transformers/torch/generation_utils.py
Normal file
File diff suppressed because it is too large
Load Diff
816
fastNLP/transformers/torch/modeling_outputs.py
Normal file
816
fastNLP/transformers/torch/modeling_outputs.py
Normal file
@ -0,0 +1,816 @@
|
||||
# Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, Tuple
|
||||
|
||||
from .file_utils import ModelOutput
|
||||
from fastNLP.envs.imports import _NEED_IMPORT_TORCH
|
||||
|
||||
if _NEED_IMPORT_TORCH:
|
||||
import torch
|
||||
|
||||
|
||||
@dataclass
|
||||
class BaseModelOutput(ModelOutput):
|
||||
"""
|
||||
Base class for model's outputs, with potential hidden states and attentions.
|
||||
|
||||
Args:
|
||||
last_hidden_state (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`):
|
||||
Sequence of hidden-states at the output of the last layer of the model.
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
"""
|
||||
|
||||
last_hidden_state: "torch.FloatTensor" = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BaseModelOutputWithPooling(ModelOutput):
|
||||
"""
|
||||
Base class for model's outputs that also contains a pooling of the last hidden states.
|
||||
|
||||
Args:
|
||||
last_hidden_state (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`):
|
||||
Sequence of hidden-states at the output of the last layer of the model.
|
||||
pooler_output (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, hidden_size)`):
|
||||
Last layer hidden-state of the first token of the sequence (classification token) after further processing
|
||||
through the layers used for the auxiliary pretraining task. E.g. for BERT-family of models, this returns
|
||||
the classification token after processing through a linear layer and a tanh activation function. The linear
|
||||
layer weights are trained from the next sentence prediction (classification) objective during pretraining.
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
"""
|
||||
|
||||
last_hidden_state: "torch.FloatTensor" = None
|
||||
pooler_output: "torch.FloatTensor" = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BaseModelOutputWithPast(ModelOutput):
|
||||
"""
|
||||
Base class for model's outputs that may also contain a past key/values (to speed up sequential decoding).
|
||||
|
||||
Args:
|
||||
last_hidden_state (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`):
|
||||
Sequence of hidden-states at the output of the last layer of the model.
|
||||
|
||||
If :obj:`past_key_values` is used only the last hidden-state of the sequences of shape :obj:`(batch_size,
|
||||
1, hidden_size)` is output.
|
||||
past_key_values (:obj:`tuple(tuple(torch.FloatTensor))`, `optional`, returned when ``use_cache=True`` is passed or when ``config.use_cache=True``):
|
||||
Tuple of :obj:`tuple(torch.FloatTensor)` of length :obj:`config.n_layers`, with each tuple having 2 tensors
|
||||
of shape :obj:`(batch_size, num_heads, sequence_length, embed_size_per_head)`) and optionally if
|
||||
``config.is_encoder_decoder=True`` 2 additional tensors of shape :obj:`(batch_size, num_heads,
|
||||
encoder_sequence_length, embed_size_per_head)`.
|
||||
|
||||
Contains pre-computed hidden-states (key and values in the self-attention blocks and optionally if
|
||||
``config.is_encoder_decoder=True`` in the cross-attention blocks) that can be used (see
|
||||
:obj:`past_key_values` input) to speed up sequential decoding.
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
"""
|
||||
|
||||
last_hidden_state: "torch.FloatTensor" = None
|
||||
past_key_values: Optional[Tuple[Tuple["torch.FloatTensor"]]] = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BaseModelOutputWithCrossAttentions(ModelOutput):
|
||||
"""
|
||||
Base class for model's outputs, with potential hidden states and attentions.
|
||||
|
||||
Args:
|
||||
last_hidden_state (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`):
|
||||
Sequence of hidden-states at the output of the last layer of the model.
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
cross_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` and ``config.add_cross_attention=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the decoder's cross-attention layer, after the attention softmax, used to compute the
|
||||
weighted average in the cross-attention heads.
|
||||
"""
|
||||
|
||||
last_hidden_state: "torch.FloatTensor" = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
cross_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BaseModelOutputWithPoolingAndCrossAttentions(ModelOutput):
|
||||
"""
|
||||
Base class for model's outputs that also contains a pooling of the last hidden states.
|
||||
|
||||
Args:
|
||||
last_hidden_state (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`):
|
||||
Sequence of hidden-states at the output of the last layer of the model.
|
||||
pooler_output (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, hidden_size)`):
|
||||
Last layer hidden-state of the first token of the sequence (classification token) after further processing
|
||||
through the layers used for the auxiliary pretraining task. E.g. for BERT-family of models, this returns
|
||||
the classification token after processing through a linear layer and a tanh activation function. The linear
|
||||
layer weights are trained from the next sentence prediction (classification) objective during pretraining.
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
cross_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` and ``config.add_cross_attention=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the decoder's cross-attention layer, after the attention softmax, used to compute the
|
||||
weighted average in the cross-attention heads.
|
||||
past_key_values (:obj:`tuple(tuple(torch.FloatTensor))`, `optional`, returned when ``use_cache=True`` is passed or when ``config.use_cache=True``):
|
||||
Tuple of :obj:`tuple(torch.FloatTensor)` of length :obj:`config.n_layers`, with each tuple having 2 tensors
|
||||
of shape :obj:`(batch_size, num_heads, sequence_length, embed_size_per_head)`) and optionally if
|
||||
``config.is_encoder_decoder=True`` 2 additional tensors of shape :obj:`(batch_size, num_heads,
|
||||
encoder_sequence_length, embed_size_per_head)`.
|
||||
|
||||
Contains pre-computed hidden-states (key and values in the self-attention blocks and optionally if
|
||||
``config.is_encoder_decoder=True`` in the cross-attention blocks) that can be used (see
|
||||
:obj:`past_key_values` input) to speed up sequential decoding.
|
||||
"""
|
||||
|
||||
last_hidden_state: "torch.FloatTensor" = None
|
||||
pooler_output: "torch.FloatTensor" = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
past_key_values: Optional[Tuple[Tuple["torch.FloatTensor"]]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
cross_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BaseModelOutputWithPastAndCrossAttentions(ModelOutput):
|
||||
"""
|
||||
Base class for model's outputs that may also contain a past key/values (to speed up sequential decoding).
|
||||
|
||||
Args:
|
||||
last_hidden_state (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`):
|
||||
Sequence of hidden-states at the output of the last layer of the model.
|
||||
|
||||
If :obj:`past_key_values` is used only the last hidden-state of the sequences of shape :obj:`(batch_size,
|
||||
1, hidden_size)` is output.
|
||||
past_key_values (:obj:`tuple(tuple(torch.FloatTensor))`, `optional`, returned when ``use_cache=True`` is passed or when ``config.use_cache=True``):
|
||||
Tuple of :obj:`tuple(torch.FloatTensor)` of length :obj:`config.n_layers`, with each tuple having 2 tensors
|
||||
of shape :obj:`(batch_size, num_heads, sequence_length, embed_size_per_head)`) and optionally if
|
||||
``config.is_encoder_decoder=True`` 2 additional tensors of shape :obj:`(batch_size, num_heads,
|
||||
encoder_sequence_length, embed_size_per_head)`.
|
||||
|
||||
Contains pre-computed hidden-states (key and values in the self-attention blocks and optionally if
|
||||
``config.is_encoder_decoder=True`` in the cross-attention blocks) that can be used (see
|
||||
:obj:`past_key_values` input) to speed up sequential decoding.
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
cross_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` and ``config.add_cross_attention=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the decoder's cross-attention layer, after the attention softmax, used to compute the
|
||||
weighted average in the cross-attention heads.
|
||||
"""
|
||||
|
||||
last_hidden_state: "torch.FloatTensor" = None
|
||||
past_key_values: Optional[Tuple[Tuple["torch.FloatTensor"]]] = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
cross_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Seq2SeqModelOutput(ModelOutput):
|
||||
"""
|
||||
Base class for model encoder's outputs that also contains : pre-computed hidden states that can speed up sequential
|
||||
decoding.
|
||||
|
||||
Args:
|
||||
last_hidden_state (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`):
|
||||
Sequence of hidden-states at the output of the last layer of the decoder of the model.
|
||||
|
||||
If :obj:`past_key_values` is used only the last hidden-state of the sequences of shape :obj:`(batch_size,
|
||||
1, hidden_size)` is output.
|
||||
past_key_values (:obj:`tuple(tuple(torch.FloatTensor))`, `optional`, returned when ``use_cache=True`` is passed or when ``config.use_cache=True``):
|
||||
Tuple of :obj:`tuple(torch.FloatTensor)` of length :obj:`config.n_layers`, with each tuple having 2 tensors
|
||||
of shape :obj:`(batch_size, num_heads, sequence_length, embed_size_per_head)`) and 2 additional tensors of
|
||||
shape :obj:`(batch_size, num_heads, encoder_sequence_length, embed_size_per_head)`.
|
||||
|
||||
Contains pre-computed hidden-states (key and values in the self-attention blocks and in the cross-attention
|
||||
blocks) that can be used (see :obj:`past_key_values` input) to speed up sequential decoding.
|
||||
decoder_hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the decoder at the output of each layer plus the initial embedding outputs.
|
||||
decoder_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the decoder, after the attention softmax, used to compute the weighted average in the
|
||||
self-attention heads.
|
||||
cross_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the decoder's cross-attention layer, after the attention softmax, used to compute the
|
||||
weighted average in the cross-attention heads.
|
||||
encoder_last_hidden_state (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`, `optional`):
|
||||
Sequence of hidden-states at the output of the last layer of the encoder of the model.
|
||||
encoder_hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the encoder at the output of each layer plus the initial embedding outputs.
|
||||
encoder_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the encoder, after the attention softmax, used to compute the weighted average in the
|
||||
self-attention heads.
|
||||
"""
|
||||
|
||||
last_hidden_state: "torch.FloatTensor" = None
|
||||
past_key_values: Optional[Tuple[Tuple["torch.FloatTensor"]]] = None
|
||||
decoder_hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
decoder_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
cross_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
encoder_last_hidden_state: Optional["torch.FloatTensor"] = None
|
||||
encoder_hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
encoder_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class CausalLMOutput(ModelOutput):
|
||||
"""
|
||||
Base class for causal language model (or autoregressive) outputs.
|
||||
|
||||
Args:
|
||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`labels` is provided):
|
||||
Language modeling loss (for next-token prediction).
|
||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, config.vocab_size)`):
|
||||
Prediction scores of the language modeling head (scores for each vocabulary token before SoftMax).
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
"""
|
||||
|
||||
loss: Optional["torch.FloatTensor"] = None
|
||||
logits: "torch.FloatTensor" = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class CausalLMOutputWithPast(ModelOutput):
|
||||
"""
|
||||
Base class for causal language model (or autoregressive) outputs.
|
||||
|
||||
Args:
|
||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`labels` is provided):
|
||||
Language modeling loss (for next-token prediction).
|
||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, config.vocab_size)`):
|
||||
Prediction scores of the language modeling head (scores for each vocabulary token before SoftMax).
|
||||
past_key_values (:obj:`tuple(tuple(torch.FloatTensor))`, `optional`, returned when ``use_cache=True`` is passed or when ``config.use_cache=True``):
|
||||
Tuple of :obj:`tuple(torch.FloatTensor)` of length :obj:`config.n_layers`, with each tuple having 2 tensors
|
||||
of shape :obj:`(batch_size, num_heads, sequence_length, embed_size_per_head)`)
|
||||
|
||||
Contains pre-computed hidden-states (key and values in the self-attention blocks) that can be used (see
|
||||
:obj:`past_key_values` input) to speed up sequential decoding.
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
"""
|
||||
|
||||
loss: Optional["torch.FloatTensor"] = None
|
||||
logits: "torch.FloatTensor" = None
|
||||
past_key_values: Optional[Tuple[Tuple["torch.FloatTensor"]]] = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class CausalLMOutputWithCrossAttentions(ModelOutput):
|
||||
"""
|
||||
Base class for causal language model (or autoregressive) outputs.
|
||||
|
||||
Args:
|
||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`labels` is provided):
|
||||
Language modeling loss (for next-token prediction).
|
||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, config.vocab_size)`):
|
||||
Prediction scores of the language modeling head (scores for each vocabulary token before SoftMax).
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
cross_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Cross attentions weights after the attention softmax, used to compute the weighted average in the
|
||||
cross-attention heads.
|
||||
past_key_values (:obj:`tuple(tuple(torch.FloatTensor))`, `optional`, returned when ``use_cache=True`` is passed or when ``config.use_cache=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` tuples of length :obj:`config.n_layers`, with each tuple containing the
|
||||
cached key, value states of the self-attention and the cross-attention layers if model is used in
|
||||
encoder-decoder setting. Only relevant if ``config.is_decoder = True``.
|
||||
|
||||
Contains pre-computed hidden-states (key and values in the attention blocks) that can be used (see
|
||||
:obj:`past_key_values` input) to speed up sequential decoding.
|
||||
"""
|
||||
|
||||
loss: Optional["torch.FloatTensor"] = None
|
||||
logits: "torch.FloatTensor" = None
|
||||
past_key_values: Optional[Tuple[Tuple["torch.FloatTensor"]]] = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
cross_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class SequenceClassifierOutputWithPast(ModelOutput):
|
||||
"""
|
||||
Base class for outputs of sentence classification models.
|
||||
|
||||
Args:
|
||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`labels` is provided):
|
||||
Classification (or regression if config.num_labels==1) loss.
|
||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, config.num_labels)`):
|
||||
Classification (or regression if config.num_labels==1) scores (before SoftMax).
|
||||
past_key_values (:obj:`tuple(tuple(torch.FloatTensor))`, `optional`, returned when ``use_cache=True`` is passed or when ``config.use_cache=True``):
|
||||
Tuple of :obj:`tuple(torch.FloatTensor)` of length :obj:`config.n_layers`, with each tuple having 2 tensors
|
||||
of shape :obj:`(batch_size, num_heads, sequence_length, embed_size_per_head)`)
|
||||
|
||||
Contains pre-computed hidden-states (key and values in the self-attention blocks) that can be used (see
|
||||
:obj:`past_key_values` input) to speed up sequential decoding.
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
"""
|
||||
|
||||
loss: Optional["torch.FloatTensor"] = None
|
||||
logits: "torch.FloatTensor" = None
|
||||
past_key_values: Optional[Tuple[Tuple["torch.FloatTensor"]]] = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class MaskedLMOutput(ModelOutput):
|
||||
"""
|
||||
Base class for masked language models outputs.
|
||||
|
||||
Args:
|
||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`labels` is provided):
|
||||
Masked language modeling (MLM) loss.
|
||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, config.vocab_size)`):
|
||||
Prediction scores of the language modeling head (scores for each vocabulary token before SoftMax).
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
"""
|
||||
|
||||
loss: Optional["torch.FloatTensor"] = None
|
||||
logits: "torch.FloatTensor" = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Seq2SeqLMOutput(ModelOutput):
|
||||
"""
|
||||
Base class for sequence-to-sequence language models outputs.
|
||||
|
||||
Args:
|
||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`labels` is provided):
|
||||
Language modeling loss.
|
||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, config.vocab_size)`):
|
||||
Prediction scores of the language modeling head (scores for each vocabulary token before SoftMax).
|
||||
past_key_values (:obj:`tuple(tuple(torch.FloatTensor))`, `optional`, returned when ``use_cache=True`` is passed or when ``config.use_cache=True``):
|
||||
Tuple of :obj:`tuple(torch.FloatTensor)` of length :obj:`config.n_layers`, with each tuple having 2 tensors
|
||||
of shape :obj:`(batch_size, num_heads, sequence_length, embed_size_per_head)`) and 2 additional tensors of
|
||||
shape :obj:`(batch_size, num_heads, encoder_sequence_length, embed_size_per_head)`.
|
||||
|
||||
Contains pre-computed hidden-states (key and values in the self-attention blocks and in the cross-attention
|
||||
blocks) that can be used (see :obj:`past_key_values` input) to speed up sequential decoding.
|
||||
decoder_hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the decoder at the output of each layer plus the initial embedding outputs.
|
||||
decoder_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the decoder, after the attention softmax, used to compute the weighted average in the
|
||||
self-attention heads.
|
||||
cross_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the decoder's cross-attention layer, after the attention softmax, used to compute the
|
||||
weighted average in the cross-attention heads.
|
||||
encoder_last_hidden_state (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`, `optional`):
|
||||
Sequence of hidden-states at the output of the last layer of the encoder of the model.
|
||||
encoder_hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the encoder at the output of each layer plus the initial embedding outputs.
|
||||
encoder_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the encoder, after the attention softmax, used to compute the weighted average in the
|
||||
self-attention heads.
|
||||
"""
|
||||
|
||||
loss: Optional["torch.FloatTensor"] = None
|
||||
logits: "torch.FloatTensor" = None
|
||||
past_key_values: Optional[Tuple[Tuple["torch.FloatTensor"]]] = None
|
||||
decoder_hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
decoder_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
cross_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
encoder_last_hidden_state: Optional["torch.FloatTensor"] = None
|
||||
encoder_hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
encoder_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class NextSentencePredictorOutput(ModelOutput):
|
||||
"""
|
||||
Base class for outputs of models predicting if two sentences are consecutive or not.
|
||||
|
||||
Args:
|
||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`next_sentence_label` is provided):
|
||||
Next sequence prediction (classification) loss.
|
||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, 2)`):
|
||||
Prediction scores of the next sequence prediction (classification) head (scores of True/False continuation
|
||||
before SoftMax).
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
"""
|
||||
|
||||
loss: Optional["torch.FloatTensor"] = None
|
||||
logits: "torch.FloatTensor" = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class SequenceClassifierOutput(ModelOutput):
|
||||
"""
|
||||
Base class for outputs of sentence classification models.
|
||||
|
||||
Args:
|
||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`labels` is provided):
|
||||
Classification (or regression if config.num_labels==1) loss.
|
||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, config.num_labels)`):
|
||||
Classification (or regression if config.num_labels==1) scores (before SoftMax).
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
"""
|
||||
|
||||
loss: Optional["torch.FloatTensor"] = None
|
||||
logits: "torch.FloatTensor" = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Seq2SeqSequenceClassifierOutput(ModelOutput):
|
||||
"""
|
||||
Base class for outputs of sequence-to-sequence sentence classification models.
|
||||
|
||||
Args:
|
||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`label` is provided):
|
||||
Classification (or regression if config.num_labels==1) loss.
|
||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, config.num_labels)`):
|
||||
Classification (or regression if config.num_labels==1) scores (before SoftMax).
|
||||
past_key_values (:obj:`tuple(tuple(torch.FloatTensor))`, `optional`, returned when ``use_cache=True`` is passed or when ``config.use_cache=True``):
|
||||
Tuple of :obj:`tuple(torch.FloatTensor)` of length :obj:`config.n_layers`, with each tuple having 2 tensors
|
||||
of shape :obj:`(batch_size, num_heads, sequence_length, embed_size_per_head)`) and 2 additional tensors of
|
||||
shape :obj:`(batch_size, num_heads, encoder_sequence_length, embed_size_per_head)`.
|
||||
|
||||
Contains pre-computed hidden-states (key and values in the self-attention blocks and in the cross-attention
|
||||
blocks) that can be used (see :obj:`past_key_values` input) to speed up sequential decoding.
|
||||
decoder_hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the decoder at the output of each layer plus the initial embedding outputs.
|
||||
decoder_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the decoder, after the attention softmax, used to compute the weighted average in the
|
||||
self-attention heads.
|
||||
cross_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the decoder's cross-attention layer, after the attention softmax, used to compute the
|
||||
weighted average in the cross-attention heads.
|
||||
encoder_last_hidden_state (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`, `optional`):
|
||||
Sequence of hidden-states at the output of the last layer of the encoder of the model.
|
||||
encoder_hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the encoder at the output of each layer plus the initial embedding outputs.
|
||||
encoder_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the encoder, after the attention softmax, used to compute the weighted average in the
|
||||
self-attention heads.
|
||||
"""
|
||||
|
||||
loss: Optional["torch.FloatTensor"] = None
|
||||
logits: "torch.FloatTensor" = None
|
||||
past_key_values: Optional[Tuple[Tuple["torch.FloatTensor"]]] = None
|
||||
decoder_hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
decoder_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
cross_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
encoder_last_hidden_state: Optional["torch.FloatTensor"] = None
|
||||
encoder_hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
encoder_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class MultipleChoiceModelOutput(ModelOutput):
|
||||
"""
|
||||
Base class for outputs of multiple choice models.
|
||||
|
||||
Args:
|
||||
loss (:obj:`torch.FloatTensor` of shape `(1,)`, `optional`, returned when :obj:`labels` is provided):
|
||||
Classification loss.
|
||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, num_choices)`):
|
||||
`num_choices` is the second dimension of the input tensors. (see `input_ids` above).
|
||||
|
||||
Classification scores (before SoftMax).
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
"""
|
||||
|
||||
loss: Optional["torch.FloatTensor"] = None
|
||||
logits: "torch.FloatTensor" = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class TokenClassifierOutput(ModelOutput):
|
||||
"""
|
||||
Base class for outputs of token classification models.
|
||||
|
||||
Args:
|
||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when ``labels`` is provided) :
|
||||
Classification loss.
|
||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, config.num_labels)`):
|
||||
Classification scores (before SoftMax).
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
"""
|
||||
|
||||
loss: Optional["torch.FloatTensor"] = None
|
||||
logits: "torch.FloatTensor" = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class QuestionAnsweringModelOutput(ModelOutput):
|
||||
"""
|
||||
Base class for outputs of question answering models.
|
||||
|
||||
Args:
|
||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`labels` is provided):
|
||||
Total span extraction loss is the sum of a Cross-Entropy for the start and end positions.
|
||||
start_logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`):
|
||||
Span-start scores (before SoftMax).
|
||||
end_logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`):
|
||||
Span-end scores (before SoftMax).
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
"""
|
||||
|
||||
loss: Optional["torch.FloatTensor"] = None
|
||||
start_logits: "torch.FloatTensor" = None
|
||||
end_logits: "torch.FloatTensor" = None
|
||||
hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Seq2SeqQuestionAnsweringModelOutput(ModelOutput):
|
||||
"""
|
||||
Base class for outputs of sequence-to-sequence question answering models.
|
||||
|
||||
Args:
|
||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`labels` is provided):
|
||||
Total span extraction loss is the sum of a Cross-Entropy for the start and end positions.
|
||||
start_logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`):
|
||||
Span-start scores (before SoftMax).
|
||||
end_logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`):
|
||||
Span-end scores (before SoftMax).
|
||||
past_key_values (:obj:`tuple(tuple(torch.FloatTensor))`, `optional`, returned when ``use_cache=True`` is passed or when ``config.use_cache=True``):
|
||||
Tuple of :obj:`tuple(torch.FloatTensor)` of length :obj:`config.n_layers`, with each tuple having 2 tensors
|
||||
of shape :obj:`(batch_size, num_heads, sequence_length, embed_size_per_head)`) and 2 additional tensors of
|
||||
shape :obj:`(batch_size, num_heads, encoder_sequence_length, embed_size_per_head)`.
|
||||
|
||||
Contains pre-computed hidden-states (key and values in the self-attention blocks and in the cross-attention
|
||||
blocks) that can be used (see :obj:`past_key_values` input) to speed up sequential decoding.
|
||||
decoder_hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the decoder at the output of each layer plus the initial embedding outputs.
|
||||
decoder_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the decoder, after the attention softmax, used to compute the weighted average in the
|
||||
self-attention heads.
|
||||
cross_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the decoder's cross-attention layer, after the attention softmax, used to compute the
|
||||
weighted average in the cross-attention heads.
|
||||
encoder_last_hidden_state (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`, `optional`):
|
||||
Sequence of hidden-states at the output of the last layer of the encoder of the model.
|
||||
encoder_hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the encoder at the output of each layer plus the initial embedding outputs.
|
||||
encoder_attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||
sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights of the encoder, after the attention softmax, used to compute the weighted average in the
|
||||
self-attention heads.
|
||||
"""
|
||||
|
||||
loss: Optional["torch.FloatTensor"] = None
|
||||
start_logits: "torch.FloatTensor" = None
|
||||
end_logits: "torch.FloatTensor" = None
|
||||
past_key_values: Optional[Tuple[Tuple["torch.FloatTensor"]]] = None
|
||||
decoder_hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
decoder_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
cross_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
encoder_last_hidden_state: Optional["torch.FloatTensor"] = None
|
||||
encoder_hidden_states: Optional[Tuple["torch.FloatTensor"]] = None
|
||||
encoder_attentions: Optional[Tuple["torch.FloatTensor"]] = None
|
1888
fastNLP/transformers/torch/modeling_utils.py
Normal file
1888
fastNLP/transformers/torch/modeling_utils.py
Normal file
File diff suppressed because it is too large
Load Diff
5
fastNLP/transformers/torch/models/__init__.py
Normal file
5
fastNLP/transformers/torch/models/__init__.py
Normal file
@ -0,0 +1,5 @@
|
||||
from .bart import *
|
||||
from .bert import *
|
||||
from .cpt import *
|
||||
from .gpt2 import *
|
||||
from .roberta import *
|
541
fastNLP/transformers/torch/models/auto/configuration_auto.py
Normal file
541
fastNLP/transformers/torch/models/auto/configuration_auto.py
Normal file
@ -0,0 +1,541 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The HuggingFace Inc. team.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
""" Auto Config class. """
|
||||
import importlib
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
from typing import List, Union
|
||||
|
||||
from fastNLP.transformers.torch.configuration_utils import PretrainedConfig
|
||||
from fastNLP.transformers.torch.file_utils import CONFIG_NAME
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
|
||||
CONFIG_MAPPING_NAMES = OrderedDict(
|
||||
[
|
||||
# Add configs here
|
||||
("fnet", "FNetConfig"),
|
||||
("gptj", "GPTJConfig"),
|
||||
("layoutlmv2", "LayoutLMv2Config"),
|
||||
("beit", "BeitConfig"),
|
||||
("rembert", "RemBertConfig"),
|
||||
("visual_bert", "VisualBertConfig"),
|
||||
("canine", "CanineConfig"),
|
||||
("roformer", "RoFormerConfig"),
|
||||
("clip", "CLIPConfig"),
|
||||
("bigbird_pegasus", "BigBirdPegasusConfig"),
|
||||
("deit", "DeiTConfig"),
|
||||
("luke", "LukeConfig"),
|
||||
("detr", "DetrConfig"),
|
||||
("gpt_neo", "GPTNeoConfig"),
|
||||
("big_bird", "BigBirdConfig"),
|
||||
("speech_to_text_2", "Speech2Text2Config"),
|
||||
("speech_to_text", "Speech2TextConfig"),
|
||||
("vit", "ViTConfig"),
|
||||
("wav2vec2", "Wav2Vec2Config"),
|
||||
("m2m_100", "M2M100Config"),
|
||||
("convbert", "ConvBertConfig"),
|
||||
("led", "LEDConfig"),
|
||||
("blenderbot-small", "BlenderbotSmallConfig"),
|
||||
("retribert", "RetriBertConfig"),
|
||||
("ibert", "IBertConfig"),
|
||||
("mt5", "MT5Config"),
|
||||
("t5", "T5Config"),
|
||||
("mobilebert", "MobileBertConfig"),
|
||||
("distilbert", "DistilBertConfig"),
|
||||
("albert", "AlbertConfig"),
|
||||
("bert-generation", "BertGenerationConfig"),
|
||||
("camembert", "CamembertConfig"),
|
||||
("xlm-roberta", "XLMRobertaConfig"),
|
||||
("pegasus", "PegasusConfig"),
|
||||
("marian", "MarianConfig"),
|
||||
("mbart", "MBartConfig"),
|
||||
("megatron-bert", "MegatronBertConfig"),
|
||||
("mpnet", "MPNetConfig"),
|
||||
("bart", "BartConfig"),
|
||||
("blenderbot", "BlenderbotConfig"),
|
||||
("reformer", "ReformerConfig"),
|
||||
("longformer", "LongformerConfig"),
|
||||
("roberta", "RobertaConfig"),
|
||||
("deberta-v2", "DebertaV2Config"),
|
||||
("deberta", "DebertaConfig"),
|
||||
("flaubert", "FlaubertConfig"),
|
||||
("fsmt", "FSMTConfig"),
|
||||
("squeezebert", "SqueezeBertConfig"),
|
||||
("hubert", "HubertConfig"),
|
||||
("bert", "BertConfig"),
|
||||
("openai-gpt", "OpenAIGPTConfig"),
|
||||
("gpt2", "GPT2Config"),
|
||||
("transfo-xl", "TransfoXLConfig"),
|
||||
("xlnet", "XLNetConfig"),
|
||||
("xlm-prophetnet", "XLMProphetNetConfig"),
|
||||
("prophetnet", "ProphetNetConfig"),
|
||||
("xlm", "XLMConfig"),
|
||||
("ctrl", "CTRLConfig"),
|
||||
("electra", "ElectraConfig"),
|
||||
("speech-encoder-decoder", "SpeechEncoderDecoderConfig"),
|
||||
("encoder-decoder", "EncoderDecoderConfig"),
|
||||
("funnel", "FunnelConfig"),
|
||||
("lxmert", "LxmertConfig"),
|
||||
("dpr", "DPRConfig"),
|
||||
("layoutlm", "LayoutLMConfig"),
|
||||
("rag", "RagConfig"),
|
||||
("tapas", "TapasConfig"),
|
||||
("splinter", "SplinterConfig"),
|
||||
]
|
||||
)
|
||||
|
||||
CONFIG_ARCHIVE_MAP_MAPPING_NAMES = OrderedDict(
|
||||
[
|
||||
# Add archive maps here
|
||||
("fnet", "FNET_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("pegasus", "PEGASUS_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("gptj", "GPTJ_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("layoutlmv2", "LAYOUTLMV2_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("beit", "BEIT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("rembert", "REMBERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("visual_bert", "VISUAL_BERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("canine", "CANINE_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("roformer", "ROFORMER_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("clip", "CLIP_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("bigbird_pegasus", "BIGBIRD_PEGASUS_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("deit", "DEIT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("luke", "LUKE_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("detr", "DETR_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("gpt_neo", "GPT_NEO_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("big_bird", "BIG_BIRD_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("megatron-bert", "MEGATRON_BERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("speech_to_text", "SPEECH_TO_TEXT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("speech_to_text_2", "SPEECH_TO_TEXT_2_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("vit", "VIT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("wav2vec2", "WAV_2_VEC_2_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("m2m_100", "M2M_100_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("convbert", "CONVBERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("led", "LED_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("blenderbot-small", "BLENDERBOT_SMALL_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("bert", "BERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("bart", "BART_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("blenderbot", "BLENDERBOT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("mbart", "MBART_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("openai-gpt", "OPENAI_GPT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("transfo-xl", "TRANSFO_XL_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("gpt2", "GPT2_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("ctrl", "CTRL_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("xlnet", "XLNET_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("xlm", "XLM_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("roberta", "ROBERTA_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("distilbert", "DISTILBERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("albert", "ALBERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("camembert", "CAMEMBERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("t5", "T5_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("xlm-roberta", "XLM_ROBERTA_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("flaubert", "FLAUBERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("fsmt", "FSMT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("electra", "ELECTRA_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("longformer", "LONGFORMER_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("retribert", "RETRIBERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("funnel", "FUNNEL_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("lxmert", "LXMERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("layoutlm", "LAYOUTLM_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("dpr", "DPR_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("deberta", "DEBERTA_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("deberta-v2", "DEBERTA_V2_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("squeezebert", "SQUEEZEBERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("xlm-prophetnet", "XLM_PROPHETNET_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("prophetnet", "PROPHETNET_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("mpnet", "MPNET_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("tapas", "TAPAS_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("ibert", "IBERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("hubert", "HUBERT_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
("splinter", "SPLINTER_PRETRAINED_CONFIG_ARCHIVE_MAP"),
|
||||
]
|
||||
)
|
||||
|
||||
MODEL_NAMES_MAPPING = OrderedDict(
|
||||
[
|
||||
# Add full (and cased) model names here
|
||||
("fnet", "FNet"),
|
||||
("gptj", "GPT-J"),
|
||||
("beit", "BeiT"),
|
||||
("rembert", "RemBERT"),
|
||||
("layoutlmv2", "LayoutLMv2"),
|
||||
("visual_bert", "VisualBert"),
|
||||
("canine", "Canine"),
|
||||
("roformer", "RoFormer"),
|
||||
("clip", "CLIP"),
|
||||
("bigbird_pegasus", "BigBirdPegasus"),
|
||||
("deit", "DeiT"),
|
||||
("luke", "LUKE"),
|
||||
("detr", "DETR"),
|
||||
("gpt_neo", "GPT Neo"),
|
||||
("big_bird", "BigBird"),
|
||||
("speech_to_text_2", "Speech2Text2"),
|
||||
("speech_to_text", "Speech2Text"),
|
||||
("vit", "ViT"),
|
||||
("wav2vec2", "Wav2Vec2"),
|
||||
("m2m_100", "M2M100"),
|
||||
("convbert", "ConvBERT"),
|
||||
("led", "LED"),
|
||||
("blenderbot-small", "BlenderbotSmall"),
|
||||
("retribert", "RetriBERT"),
|
||||
("ibert", "I-BERT"),
|
||||
("t5", "T5"),
|
||||
("mobilebert", "MobileBERT"),
|
||||
("distilbert", "DistilBERT"),
|
||||
("albert", "ALBERT"),
|
||||
("bert-generation", "Bert Generation"),
|
||||
("camembert", "CamemBERT"),
|
||||
("xlm-roberta", "XLM-RoBERTa"),
|
||||
("pegasus", "Pegasus"),
|
||||
("blenderbot", "Blenderbot"),
|
||||
("marian", "Marian"),
|
||||
("mbart", "mBART"),
|
||||
("megatron-bert", "MegatronBert"),
|
||||
("bart", "BART"),
|
||||
("reformer", "Reformer"),
|
||||
("longformer", "Longformer"),
|
||||
("roberta", "RoBERTa"),
|
||||
("flaubert", "FlauBERT"),
|
||||
("fsmt", "FairSeq Machine-Translation"),
|
||||
("squeezebert", "SqueezeBERT"),
|
||||
("bert", "BERT"),
|
||||
("openai-gpt", "OpenAI GPT"),
|
||||
("gpt2", "OpenAI GPT-2"),
|
||||
("transfo-xl", "Transformer-XL"),
|
||||
("xlnet", "XLNet"),
|
||||
("xlm", "XLM"),
|
||||
("ctrl", "CTRL"),
|
||||
("electra", "ELECTRA"),
|
||||
("encoder-decoder", "Encoder decoder"),
|
||||
("speech-encoder-decoder", "Speech Encoder decoder"),
|
||||
("funnel", "Funnel Transformer"),
|
||||
("lxmert", "LXMERT"),
|
||||
("deberta-v2", "DeBERTa-v2"),
|
||||
("deberta", "DeBERTa"),
|
||||
("layoutlm", "LayoutLM"),
|
||||
("dpr", "DPR"),
|
||||
("rag", "RAG"),
|
||||
("xlm-prophetnet", "XLMProphetNet"),
|
||||
("prophetnet", "ProphetNet"),
|
||||
("mt5", "mT5"),
|
||||
("mpnet", "MPNet"),
|
||||
("tapas", "TAPAS"),
|
||||
("hubert", "Hubert"),
|
||||
("barthez", "BARThez"),
|
||||
("phobert", "PhoBERT"),
|
||||
("cpm", "CPM"),
|
||||
("bertweet", "Bertweet"),
|
||||
("bert-japanese", "BertJapanese"),
|
||||
("byt5", "ByT5"),
|
||||
("mbart50", "mBART-50"),
|
||||
("splinter", "Splinter"),
|
||||
]
|
||||
)
|
||||
|
||||
SPECIAL_MODEL_TYPE_TO_MODULE_NAME = OrderedDict([("openai-gpt", "openai")])
|
||||
|
||||
|
||||
def model_type_to_module_name(key):
|
||||
"""Converts a config key to the corresponding module."""
|
||||
# Special treatment
|
||||
if key in SPECIAL_MODEL_TYPE_TO_MODULE_NAME:
|
||||
return SPECIAL_MODEL_TYPE_TO_MODULE_NAME[key]
|
||||
|
||||
return key.replace("-", "_")
|
||||
|
||||
|
||||
def config_class_to_model_type(config):
|
||||
"""Converts a config class name to the corresponding model type"""
|
||||
for key, cls in CONFIG_MAPPING_NAMES.items():
|
||||
if cls == config:
|
||||
return key
|
||||
return None
|
||||
|
||||
|
||||
class _LazyConfigMapping(OrderedDict):
|
||||
"""
|
||||
A dictionary that lazily load its values when they are requested.
|
||||
"""
|
||||
|
||||
def __init__(self, mapping):
|
||||
self._mapping = mapping
|
||||
self._modules = {}
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key not in self._mapping:
|
||||
raise KeyError(key)
|
||||
value = self._mapping[key]
|
||||
module_name = model_type_to_module_name(key)
|
||||
if module_name not in self._modules:
|
||||
self._modules[module_name] = importlib.import_module(f".{module_name}", "transformers.models")
|
||||
return getattr(self._modules[module_name], value)
|
||||
|
||||
def keys(self):
|
||||
return self._mapping.keys()
|
||||
|
||||
def values(self):
|
||||
return [self[k] for k in self._mapping.keys()]
|
||||
|
||||
def items(self):
|
||||
return [(k, self[k]) for k in self._mapping.keys()]
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._mapping.keys())
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self._mapping
|
||||
|
||||
|
||||
CONFIG_MAPPING = _LazyConfigMapping(CONFIG_MAPPING_NAMES)
|
||||
|
||||
|
||||
class _LazyLoadAllMappings(OrderedDict):
|
||||
"""
|
||||
A mapping that will load all pairs of key values at the first access (either by indexing, requestions keys, values,
|
||||
etc.)
|
||||
|
||||
Args:
|
||||
mapping: The mapping to load.
|
||||
"""
|
||||
|
||||
def __init__(self, mapping):
|
||||
self._mapping = mapping
|
||||
self._initialized = False
|
||||
self._data = {}
|
||||
|
||||
def _initialize(self):
|
||||
if self._initialized:
|
||||
return
|
||||
logger.warn(
|
||||
"ALL_PRETRAINED_CONFIG_ARCHIVE_MAP is deprecated and will be removed in v5 of Transformers. "
|
||||
"It does not contain all available model checkpoints, far from it. Checkout hf.co/models for that.",
|
||||
FutureWarning,
|
||||
)
|
||||
|
||||
for model_type, map_name in self._mapping.items():
|
||||
module_name = model_type_to_module_name(model_type)
|
||||
module = importlib.import_module(f".{module_name}", "transformers.models")
|
||||
mapping = getattr(module, map_name)
|
||||
self._data.update(mapping)
|
||||
|
||||
self._initialized = True
|
||||
|
||||
def __getitem__(self, key):
|
||||
self._initialize()
|
||||
return self._data[key]
|
||||
|
||||
def keys(self):
|
||||
self._initialize()
|
||||
return self._data.keys()
|
||||
|
||||
def values(self):
|
||||
self._initialize()
|
||||
return self._data.values()
|
||||
|
||||
def items(self):
|
||||
self._initialize()
|
||||
return self._data.keys()
|
||||
|
||||
def __iter__(self):
|
||||
self._initialize()
|
||||
return iter(self._data)
|
||||
|
||||
def __contains__(self, item):
|
||||
self._initialize()
|
||||
return item in self._data
|
||||
|
||||
|
||||
ALL_PRETRAINED_CONFIG_ARCHIVE_MAP = _LazyLoadAllMappings(CONFIG_ARCHIVE_MAP_MAPPING_NAMES)
|
||||
|
||||
|
||||
def _get_class_name(model_class: Union[str, List[str]]):
|
||||
if isinstance(model_class, (list, tuple)):
|
||||
return " or ".join([f":class:`~transformers.{c}`" for c in model_class if c is not None])
|
||||
return f":class:`~transformers.{model_class}`"
|
||||
|
||||
|
||||
def _list_model_options(indent, config_to_class=None, use_model_types=True):
|
||||
if config_to_class is None and not use_model_types:
|
||||
raise ValueError("Using `use_model_types=False` requires a `config_to_class` dictionary.")
|
||||
if use_model_types:
|
||||
if config_to_class is None:
|
||||
model_type_to_name = {
|
||||
model_type: f":class:`~transformers.{config}`" for model_type, config in CONFIG_MAPPING_NAMES.items()
|
||||
}
|
||||
else:
|
||||
model_type_to_name = {
|
||||
model_type: _get_class_name(model_class)
|
||||
for model_type, model_class in config_to_class.items()
|
||||
if model_type in MODEL_NAMES_MAPPING
|
||||
}
|
||||
lines = [
|
||||
f"{indent}- **{model_type}** -- {model_type_to_name[model_type]} ({MODEL_NAMES_MAPPING[model_type]} model)"
|
||||
for model_type in sorted(model_type_to_name.keys())
|
||||
]
|
||||
else:
|
||||
config_to_name = {
|
||||
CONFIG_MAPPING_NAMES[config]: _get_class_name(clas)
|
||||
for config, clas in config_to_class.items()
|
||||
if config in CONFIG_MAPPING_NAMES
|
||||
}
|
||||
config_to_model_name = {
|
||||
config: MODEL_NAMES_MAPPING[model_type] for model_type, config in CONFIG_MAPPING_NAMES.items()
|
||||
}
|
||||
lines = [
|
||||
f"{indent}- :class:`~transformers.{config_name}` configuration class: {config_to_name[config_name]} ({config_to_model_name[config_name]} model)"
|
||||
for config_name in sorted(config_to_name.keys())
|
||||
]
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def replace_list_option_in_docstrings(config_to_class=None, use_model_types=True):
|
||||
def docstring_decorator(fn):
|
||||
docstrings = fn.__doc__
|
||||
lines = docstrings.split("\n")
|
||||
i = 0
|
||||
while i < len(lines) and re.search(r"^(\s*)List options\s*$", lines[i]) is None:
|
||||
i += 1
|
||||
if i < len(lines):
|
||||
indent = re.search(r"^(\s*)List options\s*$", lines[i]).groups()[0]
|
||||
if use_model_types:
|
||||
indent = f"{indent} "
|
||||
lines[i] = _list_model_options(indent, config_to_class=config_to_class, use_model_types=use_model_types)
|
||||
docstrings = "\n".join(lines)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"The function {fn} should have an empty 'List options' in its docstring as placeholder, current docstring is:\n{docstrings}"
|
||||
)
|
||||
fn.__doc__ = docstrings
|
||||
return fn
|
||||
|
||||
return docstring_decorator
|
||||
|
||||
|
||||
class AutoConfig:
|
||||
r"""
|
||||
This is a generic configuration class that will be instantiated as one of the configuration classes of the library
|
||||
when created with the :meth:`~transformers.AutoConfig.from_pretrained` class method.
|
||||
|
||||
This class cannot be instantiated directly using ``__init__()`` (throws an error).
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
raise EnvironmentError(
|
||||
"AutoConfig is designed to be instantiated "
|
||||
"using the `AutoConfig.from_pretrained(pretrained_model_name_or_path)` method."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def for_model(cls, model_type: str, *args, **kwargs):
|
||||
if model_type in CONFIG_MAPPING:
|
||||
config_class = CONFIG_MAPPING[model_type]
|
||||
return config_class(*args, **kwargs)
|
||||
raise ValueError(
|
||||
f"Unrecognized model identifier: {model_type}. Should contain one of {', '.join(CONFIG_MAPPING.keys())}"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@replace_list_option_in_docstrings()
|
||||
def from_pretrained(cls, pretrained_model_name_or_path, **kwargs):
|
||||
r"""
|
||||
Instantiate one of the configuration classes of the library from a pretrained model configuration.
|
||||
|
||||
The configuration class to instantiate is selected based on the :obj:`model_type` property of the config object
|
||||
that is loaded, or when it's missing, by falling back to using pattern matching on
|
||||
:obj:`pretrained_model_name_or_path`:
|
||||
|
||||
List options
|
||||
|
||||
Args:
|
||||
pretrained_model_name_or_path (:obj:`str` or :obj:`os.PathLike`):
|
||||
Can be either:
|
||||
|
||||
- A string, the `model id` of a pretrained model configuration hosted inside a model repo on
|
||||
huggingface.co. Valid model ids can be located at the root-level, like ``bert-base-uncased``, or
|
||||
namespaced under a user or organization name, like ``dbmdz/bert-base-german-cased``.
|
||||
- A path to a `directory` containing a configuration file saved using the
|
||||
:meth:`~transformers.PretrainedConfig.save_pretrained` method, or the
|
||||
:meth:`~transformers.PreTrainedModel.save_pretrained` method, e.g., ``./my_model_directory/``.
|
||||
- A path or url to a saved configuration JSON `file`, e.g.,
|
||||
``./my_model_directory/configuration.json``.
|
||||
cache_dir (:obj:`str` or :obj:`os.PathLike`, `optional`):
|
||||
Path to a directory in which a downloaded pretrained model configuration should be cached if the
|
||||
standard cache should not be used.
|
||||
force_download (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to force the (re-)download the model weights and configuration files and override the
|
||||
cached versions if they exist.
|
||||
resume_download (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to delete incompletely received files. Will attempt to resume the download if such a
|
||||
file exists.
|
||||
proxies (:obj:`Dict[str, str]`, `optional`):
|
||||
A dictionary of proxy servers to use by protocol or endpoint, e.g., :obj:`{'http': 'foo.bar:3128',
|
||||
'http://hostname': 'foo.bar:4012'}`. The proxies are used on each request.
|
||||
revision(:obj:`str`, `optional`, defaults to :obj:`"main"`):
|
||||
The specific model version to use. It can be a branch name, a tag name, or a commit id, since we use a
|
||||
git-based system for storing models and other artifacts on huggingface.co, so ``revision`` can be any
|
||||
identifier allowed by git.
|
||||
return_unused_kwargs (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
If :obj:`False`, then this function returns just the final configuration object.
|
||||
|
||||
If :obj:`True`, then this functions returns a :obj:`Tuple(config, unused_kwargs)` where `unused_kwargs`
|
||||
is a dictionary consisting of the key/value pairs whose keys are not configuration attributes: i.e.,
|
||||
the part of ``kwargs`` which has not been used to update ``config`` and is otherwise ignored.
|
||||
kwargs(additional keyword arguments, `optional`):
|
||||
The values in kwargs of any keys which are configuration attributes will be used to override the loaded
|
||||
values. Behavior concerning key/value pairs whose keys are *not* configuration attributes is controlled
|
||||
by the ``return_unused_kwargs`` keyword parameter.
|
||||
|
||||
Examples::
|
||||
|
||||
>>> from transformers import AutoConfig
|
||||
|
||||
>>> # Download configuration from huggingface.co and cache.
|
||||
>>> config = AutoConfig.from_pretrained('bert-base-uncased')
|
||||
|
||||
>>> # Download configuration from huggingface.co (user-uploaded) and cache.
|
||||
>>> config = AutoConfig.from_pretrained('dbmdz/bert-base-german-cased')
|
||||
|
||||
>>> # If configuration file is in a directory (e.g., was saved using `save_pretrained('./test/saved_model/')`).
|
||||
>>> config = AutoConfig.from_pretrained('./test/bert_saved_model/')
|
||||
|
||||
>>> # Load a specific configuration file.
|
||||
>>> config = AutoConfig.from_pretrained('./test/bert_saved_model/my_configuration.json')
|
||||
|
||||
>>> # Change some config attributes when loading a pretrained config.
|
||||
>>> config = AutoConfig.from_pretrained('bert-base-uncased', output_attentions=True, foo=False)
|
||||
>>> config.output_attentions
|
||||
True
|
||||
>>> config, unused_kwargs = AutoConfig.from_pretrained('bert-base-uncased', output_attentions=True, foo=False, return_unused_kwargs=True)
|
||||
>>> config.output_attentions
|
||||
True
|
||||
>>> config.unused_kwargs
|
||||
{'foo': False}
|
||||
"""
|
||||
kwargs["_from_auto"] = True
|
||||
config_dict, _ = PretrainedConfig.get_config_dict(pretrained_model_name_or_path, **kwargs)
|
||||
if "model_type" in config_dict:
|
||||
config_class = CONFIG_MAPPING[config_dict["model_type"]]
|
||||
return config_class.from_dict(config_dict, **kwargs)
|
||||
else:
|
||||
# Fallback: use pattern matching on the string.
|
||||
for pattern, config_class in CONFIG_MAPPING.items():
|
||||
if pattern in str(pretrained_model_name_or_path):
|
||||
return config_class.from_dict(config_dict, **kwargs)
|
||||
|
||||
raise ValueError(
|
||||
f"Unrecognized model in {pretrained_model_name_or_path}. "
|
||||
f"Should have a `model_type` key in its {CONFIG_NAME}, or contain one of the following strings "
|
||||
f"in its name: {', '.join(CONFIG_MAPPING.keys())}"
|
||||
)
|
199
fastNLP/transformers/torch/models/auto/tokenization_auto.py
Normal file
199
fastNLP/transformers/torch/models/auto/tokenization_auto.py
Normal file
@ -0,0 +1,199 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The HuggingFace Inc. team.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
""" Auto Tokenizer class. """
|
||||
|
||||
from collections import OrderedDict
|
||||
from typing import TYPE_CHECKING, Dict, Optional, Tuple, Union
|
||||
|
||||
from ...file_utils import (
|
||||
is_sentencepiece_available,
|
||||
is_tokenizers_available,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# This significantly improves completion suggestion performance when
|
||||
# the transformers package is used with Microsoft's Pylance language server.
|
||||
TOKENIZER_MAPPING_NAMES: OrderedDict[str, Tuple[Optional[str], Optional[str]]] = OrderedDict()
|
||||
else:
|
||||
TOKENIZER_MAPPING_NAMES = OrderedDict(
|
||||
[
|
||||
("fnet", ("FNetTokenizer", "FNetTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("retribert", ("RetriBertTokenizer", "RetriBertTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("roformer", ("RoFormerTokenizer", "RoFormerTokenizerFast" if is_tokenizers_available() else None)),
|
||||
(
|
||||
"t5",
|
||||
(
|
||||
"T5Tokenizer" if is_sentencepiece_available() else None,
|
||||
"T5TokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
(
|
||||
"mt5",
|
||||
(
|
||||
"MT5Tokenizer" if is_sentencepiece_available() else None,
|
||||
"MT5TokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
("mobilebert", ("MobileBertTokenizer", "MobileBertTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("distilbert", ("DistilBertTokenizer", "DistilBertTokenizerFast" if is_tokenizers_available() else None)),
|
||||
(
|
||||
"albert",
|
||||
(
|
||||
"AlbertTokenizer" if is_sentencepiece_available() else None,
|
||||
"AlbertTokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
(
|
||||
"camembert",
|
||||
(
|
||||
"CamembertTokenizer" if is_sentencepiece_available() else None,
|
||||
"CamembertTokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
(
|
||||
"pegasus",
|
||||
(
|
||||
"PegasusTokenizer" if is_sentencepiece_available() else None,
|
||||
"PegasusTokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
(
|
||||
"mbart",
|
||||
(
|
||||
"MBartTokenizer" if is_sentencepiece_available() else None,
|
||||
"MBartTokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
(
|
||||
"xlm-roberta",
|
||||
(
|
||||
"XLMRobertaTokenizer" if is_sentencepiece_available() else None,
|
||||
"XLMRobertaTokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
("marian", ("MarianTokenizer" if is_sentencepiece_available() else None, None)),
|
||||
("blenderbot-small", ("BlenderbotSmallTokenizer", None)),
|
||||
("blenderbot", ("BlenderbotTokenizer", None)),
|
||||
("bart", ("BartTokenizer", "BartTokenizerFast")),
|
||||
("longformer", ("LongformerTokenizer", "LongformerTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("roberta", ("RobertaTokenizer", "RobertaTokenizerFast" if is_tokenizers_available() else None)),
|
||||
(
|
||||
"reformer",
|
||||
(
|
||||
"ReformerTokenizer" if is_sentencepiece_available() else None,
|
||||
"ReformerTokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
("electra", ("ElectraTokenizer", "ElectraTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("funnel", ("FunnelTokenizer", "FunnelTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("lxmert", ("LxmertTokenizer", "LxmertTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("layoutlm", ("LayoutLMTokenizer", "LayoutLMTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("layoutlmv2", ("LayoutLMv2Tokenizer", "LayoutLMv2TokenizerFast" if is_tokenizers_available() else None)),
|
||||
(
|
||||
"dpr",
|
||||
(
|
||||
"DPRQuestionEncoderTokenizer",
|
||||
"DPRQuestionEncoderTokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
(
|
||||
"squeezebert",
|
||||
("SqueezeBertTokenizer", "SqueezeBertTokenizerFast" if is_tokenizers_available() else None),
|
||||
),
|
||||
("bert", ("BertTokenizer", "BertTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("openai-gpt", ("OpenAIGPTTokenizer", "OpenAIGPTTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("gpt2", ("GPT2Tokenizer", "GPT2TokenizerFast" if is_tokenizers_available() else None)),
|
||||
("transfo-xl", ("TransfoXLTokenizer", None)),
|
||||
(
|
||||
"xlnet",
|
||||
(
|
||||
"XLNetTokenizer" if is_sentencepiece_available() else None,
|
||||
"XLNetTokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
("flaubert", ("FlaubertTokenizer", None)),
|
||||
("xlm", ("XLMTokenizer", None)),
|
||||
("ctrl", ("CTRLTokenizer", None)),
|
||||
("fsmt", ("FSMTTokenizer", None)),
|
||||
("bert-generation", ("BertGenerationTokenizer" if is_sentencepiece_available() else None, None)),
|
||||
("deberta", ("DebertaTokenizer", "DebertaTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("deberta-v2", ("DebertaV2Tokenizer" if is_sentencepiece_available() else None, None)),
|
||||
("rag", ("RagTokenizer", None)),
|
||||
("xlm-prophetnet", ("XLMProphetNetTokenizer" if is_sentencepiece_available() else None, None)),
|
||||
("speech_to_text", ("Speech2TextTokenizer" if is_sentencepiece_available() else None, None)),
|
||||
("speech_to_text_2", ("Speech2Text2Tokenizer", None)),
|
||||
("m2m_100", ("M2M100Tokenizer" if is_sentencepiece_available() else None, None)),
|
||||
("prophetnet", ("ProphetNetTokenizer", None)),
|
||||
("mpnet", ("MPNetTokenizer", "MPNetTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("tapas", ("TapasTokenizer", None)),
|
||||
("led", ("LEDTokenizer", "LEDTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("convbert", ("ConvBertTokenizer", "ConvBertTokenizerFast" if is_tokenizers_available() else None)),
|
||||
(
|
||||
"big_bird",
|
||||
(
|
||||
"BigBirdTokenizer" if is_sentencepiece_available() else None,
|
||||
"BigBirdTokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
("ibert", ("RobertaTokenizer", "RobertaTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("wav2vec2", ("Wav2Vec2CTCTokenizer", None)),
|
||||
("hubert", ("Wav2Vec2CTCTokenizer", None)),
|
||||
("gpt_neo", ("GPT2Tokenizer", "GPT2TokenizerFast" if is_tokenizers_available() else None)),
|
||||
("luke", ("LukeTokenizer", None)),
|
||||
("bigbird_pegasus", ("PegasusTokenizer", "PegasusTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("canine", ("CanineTokenizer", None)),
|
||||
("bertweet", ("BertweetTokenizer", None)),
|
||||
("bert-japanese", ("BertJapaneseTokenizer", None)),
|
||||
("splinter", ("SplinterTokenizer", "SplinterTokenizerFast")),
|
||||
("byt5", ("ByT5Tokenizer", None)),
|
||||
(
|
||||
"cpm",
|
||||
(
|
||||
"CpmTokenizer" if is_sentencepiece_available() else None,
|
||||
"CpmTokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
("herbert", ("HerbertTokenizer", "HerbertTokenizerFast" if is_tokenizers_available() else None)),
|
||||
("phobert", ("PhobertTokenizer", None)),
|
||||
(
|
||||
"barthez",
|
||||
(
|
||||
"BarthezTokenizer" if is_sentencepiece_available() else None,
|
||||
"BarthezTokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
(
|
||||
"mbart50",
|
||||
(
|
||||
"MBart50Tokenizer" if is_sentencepiece_available() else None,
|
||||
"MBart50TokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
(
|
||||
"rembert",
|
||||
(
|
||||
"RemBertTokenizer" if is_sentencepiece_available() else None,
|
||||
"RemBertTokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
(
|
||||
"clip",
|
||||
(
|
||||
"CLIPTokenizer",
|
||||
"CLIPTokenizerFast" if is_tokenizers_available() else None,
|
||||
),
|
||||
),
|
||||
]
|
||||
)
|
20
fastNLP/transformers/torch/models/bart/__init__.py
Normal file
20
fastNLP/transformers/torch/models/bart/__init__.py
Normal file
@ -0,0 +1,20 @@
|
||||
__all__ = [
|
||||
"BartConfig",
|
||||
"BART_PRETRAINED_CONFIG_ARCHIVE_MAP",
|
||||
|
||||
"BART_PRETRAINED_MODEL_ARCHIVE_LIST",
|
||||
"BartForCausalLM",
|
||||
"BartForConditionalGeneration",
|
||||
"BartForQuestionAnswering",
|
||||
"BartForSequenceClassification",
|
||||
"BartModel",
|
||||
"BartPretrainedModel",
|
||||
"PretrainedBartModel",
|
||||
|
||||
"BartTokenizer",
|
||||
]
|
||||
|
||||
from .configuration_bart import BartConfig, BART_PRETRAINED_CONFIG_ARCHIVE_MAP
|
||||
from .tokenization_bart import BartTokenizer
|
||||
from .modeling_bart import BartForCausalLM, BartForConditionalGeneration, BartModel, BartForQuestionAnswering, \
|
||||
BartForSequenceClassification, BartPretrainedModel, PretrainedBartModel, BART_PRETRAINED_MODEL_ARCHIVE_LIST
|
177
fastNLP/transformers/torch/models/bart/configuration_bart.py
Normal file
177
fastNLP/transformers/torch/models/bart/configuration_bart.py
Normal file
@ -0,0 +1,177 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2021 The Fairseq Authors and The HuggingFace Inc. team. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
""" BART model configuration """
|
||||
from fastNLP.transformers.torch.configuration_utils import PretrainedConfig
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
__all__ = [
|
||||
"BartConfig",
|
||||
"BART_PRETRAINED_CONFIG_ARCHIVE_MAP",
|
||||
]
|
||||
|
||||
BART_PRETRAINED_CONFIG_ARCHIVE_MAP = {
|
||||
"facebook/bart-large": "https://huggingface.co/facebook/bart-large/resolve/main/config.json",
|
||||
# See all BART models at https://huggingface.co/models?filter=bart
|
||||
}
|
||||
|
||||
|
||||
class BartConfig(PretrainedConfig):
|
||||
r"""
|
||||
This is the configuration class to store the configuration of a :class:`~transformers.BartModel`. It is used to
|
||||
instantiate a BART model according to the specified arguments, defining the model architecture. Instantiating a
|
||||
configuration with the defaults will yield a similar configuration to that of the BART `facebook/bart-large
|
||||
<https://huggingface.co/facebook/bart-large>`__ architecture.
|
||||
|
||||
Configuration objects inherit from :class:`~transformers.PretrainedConfig` and can be used to control the model
|
||||
outputs. Read the documentation from :class:`~transformers.PretrainedConfig` for more information.
|
||||
|
||||
|
||||
Args:
|
||||
vocab_size (:obj:`int`, `optional`, defaults to 50265):
|
||||
Vocabulary size of the BART model. Defines the number of different tokens that can be represented by the
|
||||
:obj:`inputs_ids` passed when calling :class:`~transformers.BartModel` or
|
||||
:class:`~transformers.TFBartModel`.
|
||||
d_model (:obj:`int`, `optional`, defaults to 1024):
|
||||
Dimensionality of the layers and the pooler layer.
|
||||
encoder_layers (:obj:`int`, `optional`, defaults to 12):
|
||||
Number of encoder layers.
|
||||
decoder_layers (:obj:`int`, `optional`, defaults to 12):
|
||||
Number of decoder layers.
|
||||
encoder_attention_heads (:obj:`int`, `optional`, defaults to 16):
|
||||
Number of attention heads for each attention layer in the Transformer encoder.
|
||||
decoder_attention_heads (:obj:`int`, `optional`, defaults to 16):
|
||||
Number of attention heads for each attention layer in the Transformer decoder.
|
||||
decoder_ffn_dim (:obj:`int`, `optional`, defaults to 4096):
|
||||
Dimensionality of the "intermediate" (often named feed-forward) layer in decoder.
|
||||
encoder_ffn_dim (:obj:`int`, `optional`, defaults to 4096):
|
||||
Dimensionality of the "intermediate" (often named feed-forward) layer in decoder.
|
||||
activation_function (:obj:`str` or :obj:`function`, `optional`, defaults to :obj:`"gelu"`):
|
||||
The non-linear activation function (function or string) in the encoder and pooler. If string,
|
||||
:obj:`"gelu"`, :obj:`"relu"`, :obj:`"silu"` and :obj:`"gelu_new"` are supported.
|
||||
dropout (:obj:`float`, `optional`, defaults to 0.1):
|
||||
The dropout probability for all fully connected layers in the embeddings, encoder, and pooler.
|
||||
attention_dropout (:obj:`float`, `optional`, defaults to 0.0):
|
||||
The dropout ratio for the attention probabilities.
|
||||
activation_dropout (:obj:`float`, `optional`, defaults to 0.0):
|
||||
The dropout ratio for activations inside the fully connected layer.
|
||||
classifier_dropout (:obj:`float`, `optional`, defaults to 0.0):
|
||||
The dropout ratio for classifier.
|
||||
max_position_embeddings (:obj:`int`, `optional`, defaults to 1024):
|
||||
The maximum sequence length that this model might ever be used with. Typically set this to something large
|
||||
just in case (e.g., 512 or 1024 or 2048).
|
||||
init_std (:obj:`float`, `optional`, defaults to 0.02):
|
||||
The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
|
||||
encoder_layerdrop: (:obj:`float`, `optional`, defaults to 0.0):
|
||||
The LayerDrop probability for the encoder. See the `LayerDrop paper <see
|
||||
https://arxiv.org/abs/1909.11556>`__ for more details.
|
||||
decoder_layerdrop: (:obj:`float`, `optional`, defaults to 0.0):
|
||||
The LayerDrop probability for the decoder. See the `LayerDrop paper <see
|
||||
https://arxiv.org/abs/1909.11556>`__ for more details.
|
||||
scale_embedding (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Scale embeddings by diving by sqrt(d_model).
|
||||
use_cache (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Whether or not the model should return the last key/values attentions (not used by all models).
|
||||
num_labels: (:obj:`int`, `optional`, defaults to 3):
|
||||
The number of labels to use in :class:`~transformers.BartForSequenceClassification`.
|
||||
forced_eos_token_id (:obj:`int`, `optional`, defaults to 2):
|
||||
The id of the token to force as the last generated token when :obj:`max_length` is reached. Usually set to
|
||||
:obj:`eos_token_id`.
|
||||
|
||||
Example::
|
||||
|
||||
>>> from transformers import BartModel, BartConfig
|
||||
|
||||
>>> # Initializing a BART facebook/bart-large style configuration
|
||||
>>> configuration = BartConfig()
|
||||
|
||||
>>> # Initializing a model from the facebook/bart-large style configuration
|
||||
>>> model = BartModel(configuration)
|
||||
|
||||
>>> # Accessing the model configuration
|
||||
>>> configuration = model.config
|
||||
"""
|
||||
model_type = "bart"
|
||||
keys_to_ignore_at_inference = ["past_key_values"]
|
||||
attribute_map = {"num_attention_heads": "encoder_attention_heads", "hidden_size": "d_model"}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vocab_size=50265,
|
||||
max_position_embeddings=1024,
|
||||
encoder_layers=12,
|
||||
encoder_ffn_dim=4096,
|
||||
encoder_attention_heads=16,
|
||||
decoder_layers=12,
|
||||
decoder_ffn_dim=4096,
|
||||
decoder_attention_heads=16,
|
||||
encoder_layerdrop=0.0,
|
||||
decoder_layerdrop=0.0,
|
||||
activation_function="gelu",
|
||||
d_model=1024,
|
||||
dropout=0.1,
|
||||
attention_dropout=0.0,
|
||||
activation_dropout=0.0,
|
||||
init_std=0.02,
|
||||
classifier_dropout=0.0,
|
||||
scale_embedding=False,
|
||||
use_cache=True,
|
||||
num_labels=3,
|
||||
pad_token_id=1,
|
||||
bos_token_id=0,
|
||||
eos_token_id=2,
|
||||
is_encoder_decoder=True,
|
||||
decoder_start_token_id=2,
|
||||
forced_eos_token_id=2,
|
||||
**kwargs
|
||||
):
|
||||
self.vocab_size = vocab_size
|
||||
self.max_position_embeddings = max_position_embeddings
|
||||
self.d_model = d_model
|
||||
self.encoder_ffn_dim = encoder_ffn_dim
|
||||
self.encoder_layers = encoder_layers
|
||||
self.encoder_attention_heads = encoder_attention_heads
|
||||
self.decoder_ffn_dim = decoder_ffn_dim
|
||||
self.decoder_layers = decoder_layers
|
||||
self.decoder_attention_heads = decoder_attention_heads
|
||||
self.dropout = dropout
|
||||
self.attention_dropout = attention_dropout
|
||||
self.activation_dropout = activation_dropout
|
||||
self.activation_function = activation_function
|
||||
self.init_std = init_std
|
||||
self.encoder_layerdrop = encoder_layerdrop
|
||||
self.decoder_layerdrop = decoder_layerdrop
|
||||
self.classifier_dropout = classifier_dropout
|
||||
self.use_cache = use_cache
|
||||
self.num_hidden_layers = encoder_layers
|
||||
self.scale_embedding = scale_embedding # scale factor will be sqrt(d_model) if True
|
||||
|
||||
super().__init__(
|
||||
num_labels=num_labels,
|
||||
pad_token_id=pad_token_id,
|
||||
bos_token_id=bos_token_id,
|
||||
eos_token_id=eos_token_id,
|
||||
is_encoder_decoder=is_encoder_decoder,
|
||||
decoder_start_token_id=decoder_start_token_id,
|
||||
forced_eos_token_id=forced_eos_token_id,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
# ensure backward compatibility for BART CNN models
|
||||
if self.forced_bos_token_id is None and kwargs.get("force_bos_token_to_be_generated", False):
|
||||
self.forced_bos_token_id = self.bos_token_id
|
||||
logger.warn(
|
||||
f"Please make sure the config includes `forced_bos_token_id={self.bos_token_id}` in future versions."
|
||||
"The config can simply be saved and uploaded again to be fixed."
|
||||
)
|
1834
fastNLP/transformers/torch/models/bart/modeling_bart.py
Normal file
1834
fastNLP/transformers/torch/models/bart/modeling_bart.py
Normal file
File diff suppressed because it is too large
Load Diff
65
fastNLP/transformers/torch/models/bart/tokenization_bart.py
Normal file
65
fastNLP/transformers/torch/models/bart/tokenization_bart.py
Normal file
@ -0,0 +1,65 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2020 The Facebook AI Research Team Authors and The HuggingFace Inc. team.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ..roberta.tokenization_roberta import RobertaTokenizer
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
__all__ = [
|
||||
"BartTokenizer",
|
||||
]
|
||||
|
||||
VOCAB_FILES_NAMES = {"vocab_file": "vocab.json", "merges_file": "merges.txt"}
|
||||
|
||||
# See all BART models at https://huggingface.co/models?filter=bart
|
||||
PRETRAINED_VOCAB_FILES_MAP = {
|
||||
"vocab_file": {
|
||||
"facebook/bart-base": "https://huggingface.co/facebook/bart-base/resolve/main/vocab.json",
|
||||
"facebook/bart-large": "https://huggingface.co/facebook/bart-large/resolve/main/vocab.json",
|
||||
"facebook/bart-large-mnli": "https://huggingface.co/facebook/bart-large-mnli/resolve/main/vocab.json",
|
||||
"facebook/bart-large-cnn": "https://huggingface.co/facebook/bart-large-cnn/resolve/main/vocab.json",
|
||||
"facebook/bart-large-xsum": "https://huggingface.co/facebook/bart-large-xsum/resolve/main/vocab.json",
|
||||
"yjernite/bart_eli5": "https://huggingface.co/yjernite/bart_eli5/resolve/main/vocab.json",
|
||||
},
|
||||
"merges_file": {
|
||||
"facebook/bart-base": "https://huggingface.co/facebook/bart-base/resolve/main/merges.txt",
|
||||
"facebook/bart-large": "https://huggingface.co/facebook/bart-large/resolve/main/merges.txt",
|
||||
"facebook/bart-large-mnli": "https://huggingface.co/facebook/bart-large-mnli/resolve/main/merges.txt",
|
||||
"facebook/bart-large-cnn": "https://huggingface.co/facebook/bart-large-cnn/resolve/main/merges.txt",
|
||||
"facebook/bart-large-xsum": "https://huggingface.co/facebook/bart-large-xsum/resolve/main/merges.txt",
|
||||
"yjernite/bart_eli5": "https://huggingface.co/yjernite/bart_eli5/resolve/main/merges.txt",
|
||||
},
|
||||
}
|
||||
|
||||
PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES = {
|
||||
"facebook/bart-base": 1024,
|
||||
"facebook/bart-large": 1024,
|
||||
"facebook/bart-large-mnli": 1024,
|
||||
"facebook/bart-large-cnn": 1024,
|
||||
"facebook/bart-large-xsum": 1024,
|
||||
"yjernite/bart_eli5": 1024,
|
||||
}
|
||||
|
||||
|
||||
class BartTokenizer(RobertaTokenizer):
|
||||
r"""
|
||||
Construct a BART tokenizer.
|
||||
|
||||
:class:`~transformers.BartTokenizer` is identical to :class:`~transformers.RobertaTokenizer`. Refer to superclass
|
||||
:class:`~transformers.RobertaTokenizer` for usage examples and documentation concerning the initialization
|
||||
parameters and other methods.
|
||||
"""
|
||||
vocab_files_names = VOCAB_FILES_NAMES
|
||||
pretrained_vocab_files_map = PRETRAINED_VOCAB_FILES_MAP
|
||||
max_model_input_sizes = PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
|
27
fastNLP/transformers/torch/models/bert/__init__.py
Normal file
27
fastNLP/transformers/torch/models/bert/__init__.py
Normal file
@ -0,0 +1,27 @@
|
||||
__all__ = [
|
||||
"BERT_PRETRAINED_CONFIG_ARCHIVE_MAP",
|
||||
"BertConfig",
|
||||
|
||||
"BERT_PRETRAINED_MODEL_ARCHIVE_LIST",
|
||||
"BertForMaskedLM",
|
||||
"BertForMultipleChoice",
|
||||
"BertForNextSentencePrediction",
|
||||
"BertForPreTraining",
|
||||
"BertForQuestionAnswering",
|
||||
"BertForSequenceClassification",
|
||||
"BertForTokenClassification",
|
||||
"BertLayer",
|
||||
"BertLMHeadModel",
|
||||
"BertModel",
|
||||
"BertPreTrainedModel",
|
||||
|
||||
"BasicTokenizer",
|
||||
"BertTokenizer",
|
||||
"WordpieceTokenizer",
|
||||
]
|
||||
|
||||
from .configuration_bert import BertConfig, BERT_PRETRAINED_CONFIG_ARCHIVE_MAP
|
||||
from .tokenization_bert import BasicTokenizer, BertTokenizer, WordpieceTokenizer
|
||||
from .modeling_bert import BERT_PRETRAINED_MODEL_ARCHIVE_LIST, BertForMaskedLM, BertForMultipleChoice, BertForPreTraining, \
|
||||
BertForNextSentencePrediction, BertForQuestionAnswering, BertForSequenceClassification, BertForTokenClassification, \
|
||||
BertLayer, BertLMHeadModel, BertModel, BertPreTrainedModel
|
158
fastNLP/transformers/torch/models/bert/configuration_bert.py
Normal file
158
fastNLP/transformers/torch/models/bert/configuration_bert.py
Normal file
@ -0,0 +1,158 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team.
|
||||
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
""" BERT model configuration """
|
||||
|
||||
from fastNLP.transformers.torch.configuration_utils import PretrainedConfig
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
__all__ = [
|
||||
"BERT_PRETRAINED_CONFIG_ARCHIVE_MAP",
|
||||
"BertConfig",
|
||||
]
|
||||
|
||||
BERT_PRETRAINED_CONFIG_ARCHIVE_MAP = {
|
||||
"bert-base-uncased": "https://huggingface.co/bert-base-uncased/resolve/main/config.json",
|
||||
"bert-large-uncased": "https://huggingface.co/bert-large-uncased/resolve/main/config.json",
|
||||
"bert-base-cased": "https://huggingface.co/bert-base-cased/resolve/main/config.json",
|
||||
"bert-large-cased": "https://huggingface.co/bert-large-cased/resolve/main/config.json",
|
||||
"bert-base-multilingual-uncased": "https://huggingface.co/bert-base-multilingual-uncased/resolve/main/config.json",
|
||||
"bert-base-multilingual-cased": "https://huggingface.co/bert-base-multilingual-cased/resolve/main/config.json",
|
||||
"bert-base-chinese": "https://huggingface.co/bert-base-chinese/resolve/main/config.json",
|
||||
"bert-base-german-cased": "https://huggingface.co/bert-base-german-cased/resolve/main/config.json",
|
||||
"bert-large-uncased-whole-word-masking": "https://huggingface.co/bert-large-uncased-whole-word-masking/resolve/main/config.json",
|
||||
"bert-large-cased-whole-word-masking": "https://huggingface.co/bert-large-cased-whole-word-masking/resolve/main/config.json",
|
||||
"bert-large-uncased-whole-word-masking-finetuned-squad": "https://huggingface.co/bert-large-uncased-whole-word-masking-finetuned-squad/resolve/main/config.json",
|
||||
"bert-large-cased-whole-word-masking-finetuned-squad": "https://huggingface.co/bert-large-cased-whole-word-masking-finetuned-squad/resolve/main/config.json",
|
||||
"bert-base-cased-finetuned-mrpc": "https://huggingface.co/bert-base-cased-finetuned-mrpc/resolve/main/config.json",
|
||||
"bert-base-german-dbmdz-cased": "https://huggingface.co/bert-base-german-dbmdz-cased/resolve/main/config.json",
|
||||
"bert-base-german-dbmdz-uncased": "https://huggingface.co/bert-base-german-dbmdz-uncased/resolve/main/config.json",
|
||||
"cl-tohoku/bert-base-japanese": "https://huggingface.co/cl-tohoku/bert-base-japanese/resolve/main/config.json",
|
||||
"cl-tohoku/bert-base-japanese-whole-word-masking": "https://huggingface.co/cl-tohoku/bert-base-japanese-whole-word-masking/resolve/main/config.json",
|
||||
"cl-tohoku/bert-base-japanese-char": "https://huggingface.co/cl-tohoku/bert-base-japanese-char/resolve/main/config.json",
|
||||
"cl-tohoku/bert-base-japanese-char-whole-word-masking": "https://huggingface.co/cl-tohoku/bert-base-japanese-char-whole-word-masking/resolve/main/config.json",
|
||||
"TurkuNLP/bert-base-finnish-cased-v1": "https://huggingface.co/TurkuNLP/bert-base-finnish-cased-v1/resolve/main/config.json",
|
||||
"TurkuNLP/bert-base-finnish-uncased-v1": "https://huggingface.co/TurkuNLP/bert-base-finnish-uncased-v1/resolve/main/config.json",
|
||||
"wietsedv/bert-base-dutch-cased": "https://huggingface.co/wietsedv/bert-base-dutch-cased/resolve/main/config.json",
|
||||
# See all BERT models at https://huggingface.co/models?filter=bert
|
||||
}
|
||||
|
||||
|
||||
class BertConfig(PretrainedConfig):
|
||||
r"""
|
||||
This is the configuration class to store the configuration of a :class:`~transformers.BertModel` or a
|
||||
:class:`~transformers.TFBertModel`. It is used to instantiate a BERT model according to the specified arguments,
|
||||
defining the model architecture. Instantiating a configuration with the defaults will yield a similar configuration
|
||||
to that of the BERT `bert-base-uncased <https://huggingface.co/bert-base-uncased>`__ architecture.
|
||||
|
||||
Configuration objects inherit from :class:`~transformers.PretrainedConfig` and can be used to control the model
|
||||
outputs. Read the documentation from :class:`~transformers.PretrainedConfig` for more information.
|
||||
|
||||
|
||||
Args:
|
||||
vocab_size (:obj:`int`, `optional`, defaults to 30522):
|
||||
Vocabulary size of the BERT model. Defines the number of different tokens that can be represented by the
|
||||
:obj:`inputs_ids` passed when calling :class:`~transformers.BertModel` or
|
||||
:class:`~transformers.TFBertModel`.
|
||||
hidden_size (:obj:`int`, `optional`, defaults to 768):
|
||||
Dimensionality of the encoder layers and the pooler layer.
|
||||
num_hidden_layers (:obj:`int`, `optional`, defaults to 12):
|
||||
Number of hidden layers in the Transformer encoder.
|
||||
num_attention_heads (:obj:`int`, `optional`, defaults to 12):
|
||||
Number of attention heads for each attention layer in the Transformer encoder.
|
||||
intermediate_size (:obj:`int`, `optional`, defaults to 3072):
|
||||
Dimensionality of the "intermediate" (often named feed-forward) layer in the Transformer encoder.
|
||||
hidden_act (:obj:`str` or :obj:`Callable`, `optional`, defaults to :obj:`"gelu"`):
|
||||
The non-linear activation function (function or string) in the encoder and pooler. If string,
|
||||
:obj:`"gelu"`, :obj:`"relu"`, :obj:`"silu"` and :obj:`"gelu_new"` are supported.
|
||||
hidden_dropout_prob (:obj:`float`, `optional`, defaults to 0.1):
|
||||
The dropout probability for all fully connected layers in the embeddings, encoder, and pooler.
|
||||
attention_probs_dropout_prob (:obj:`float`, `optional`, defaults to 0.1):
|
||||
The dropout ratio for the attention probabilities.
|
||||
max_position_embeddings (:obj:`int`, `optional`, defaults to 512):
|
||||
The maximum sequence length that this model might ever be used with. Typically set this to something large
|
||||
just in case (e.g., 512 or 1024 or 2048).
|
||||
type_vocab_size (:obj:`int`, `optional`, defaults to 2):
|
||||
The vocabulary size of the :obj:`token_type_ids` passed when calling :class:`~transformers.BertModel` or
|
||||
:class:`~transformers.TFBertModel`.
|
||||
initializer_range (:obj:`float`, `optional`, defaults to 0.02):
|
||||
The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
|
||||
layer_norm_eps (:obj:`float`, `optional`, defaults to 1e-12):
|
||||
The epsilon used by the layer normalization layers.
|
||||
position_embedding_type (:obj:`str`, `optional`, defaults to :obj:`"absolute"`):
|
||||
Type of position embedding. Choose one of :obj:`"absolute"`, :obj:`"relative_key"`,
|
||||
:obj:`"relative_key_query"`. For positional embeddings use :obj:`"absolute"`. For more information on
|
||||
:obj:`"relative_key"`, please refer to `Self-Attention with Relative Position Representations (Shaw et al.)
|
||||
<https://arxiv.org/abs/1803.02155>`__. For more information on :obj:`"relative_key_query"`, please refer to
|
||||
`Method 4` in `Improve Transformer Models with Better Relative Position Embeddings (Huang et al.)
|
||||
<https://arxiv.org/abs/2009.13658>`__.
|
||||
use_cache (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Whether or not the model should return the last key/values attentions (not used by all models). Only
|
||||
relevant if ``config.is_decoder=True``.
|
||||
classifier_dropout (:obj:`float`, `optional`):
|
||||
The dropout ratio for the classification head.
|
||||
|
||||
Examples::
|
||||
|
||||
>>> from transformers import BertModel, BertConfig
|
||||
|
||||
>>> # Initializing a BERT bert-base-uncased style configuration
|
||||
>>> configuration = BertConfig()
|
||||
|
||||
>>> # Initializing a model from the bert-base-uncased style configuration
|
||||
>>> model = BertModel(configuration)
|
||||
|
||||
>>> # Accessing the model configuration
|
||||
>>> configuration = model.config
|
||||
"""
|
||||
model_type = "bert"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vocab_size=30522,
|
||||
hidden_size=768,
|
||||
num_hidden_layers=12,
|
||||
num_attention_heads=12,
|
||||
intermediate_size=3072,
|
||||
hidden_act="gelu",
|
||||
hidden_dropout_prob=0.1,
|
||||
attention_probs_dropout_prob=0.1,
|
||||
max_position_embeddings=512,
|
||||
type_vocab_size=2,
|
||||
initializer_range=0.02,
|
||||
layer_norm_eps=1e-12,
|
||||
pad_token_id=0,
|
||||
position_embedding_type="absolute",
|
||||
use_cache=True,
|
||||
classifier_dropout=None,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(pad_token_id=pad_token_id, **kwargs)
|
||||
|
||||
self.vocab_size = vocab_size
|
||||
self.hidden_size = hidden_size
|
||||
self.num_hidden_layers = num_hidden_layers
|
||||
self.num_attention_heads = num_attention_heads
|
||||
self.hidden_act = hidden_act
|
||||
self.intermediate_size = intermediate_size
|
||||
self.hidden_dropout_prob = hidden_dropout_prob
|
||||
self.attention_probs_dropout_prob = attention_probs_dropout_prob
|
||||
self.max_position_embeddings = max_position_embeddings
|
||||
self.type_vocab_size = type_vocab_size
|
||||
self.initializer_range = initializer_range
|
||||
self.layer_norm_eps = layer_norm_eps
|
||||
self.position_embedding_type = position_embedding_type
|
||||
self.use_cache = use_cache
|
||||
self.classifier_dropout = classifier_dropout
|
1806
fastNLP/transformers/torch/models/bert/modeling_bert.py
Normal file
1806
fastNLP/transformers/torch/models/bert/modeling_bert.py
Normal file
File diff suppressed because it is too large
Load Diff
558
fastNLP/transformers/torch/models/bert/tokenization_bert.py
Normal file
558
fastNLP/transformers/torch/models/bert/tokenization_bert.py
Normal file
@ -0,0 +1,558 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Tokenization classes for Bert."""
|
||||
|
||||
|
||||
import collections
|
||||
import os
|
||||
import unicodedata
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from fastNLP.transformers.torch.tokenization_utils import PreTrainedTokenizer, _is_control, _is_punctuation, _is_whitespace
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
__all__ = [
|
||||
"BasicTokenizer",
|
||||
"BertTokenizer",
|
||||
"WordpieceTokenizer",
|
||||
]
|
||||
|
||||
VOCAB_FILES_NAMES = {"vocab_file": "vocab.txt"}
|
||||
|
||||
PRETRAINED_VOCAB_FILES_MAP = {
|
||||
"vocab_file": {
|
||||
"bert-base-uncased": "https://huggingface.co/bert-base-uncased/resolve/main/vocab.txt",
|
||||
"bert-large-uncased": "https://huggingface.co/bert-large-uncased/resolve/main/vocab.txt",
|
||||
"bert-base-cased": "https://huggingface.co/bert-base-cased/resolve/main/vocab.txt",
|
||||
"bert-large-cased": "https://huggingface.co/bert-large-cased/resolve/main/vocab.txt",
|
||||
"bert-base-multilingual-uncased": "https://huggingface.co/bert-base-multilingual-uncased/resolve/main/vocab.txt",
|
||||
"bert-base-multilingual-cased": "https://huggingface.co/bert-base-multilingual-cased/resolve/main/vocab.txt",
|
||||
"bert-base-chinese": "https://huggingface.co/bert-base-chinese/resolve/main/vocab.txt",
|
||||
"bert-base-german-cased": "https://huggingface.co/bert-base-german-cased/resolve/main/vocab.txt",
|
||||
"bert-large-uncased-whole-word-masking": "https://huggingface.co/bert-large-uncased-whole-word-masking/resolve/main/vocab.txt",
|
||||
"bert-large-cased-whole-word-masking": "https://huggingface.co/bert-large-cased-whole-word-masking/resolve/main/vocab.txt",
|
||||
"bert-large-uncased-whole-word-masking-finetuned-squad": "https://huggingface.co/bert-large-uncased-whole-word-masking-finetuned-squad/resolve/main/vocab.txt",
|
||||
"bert-large-cased-whole-word-masking-finetuned-squad": "https://huggingface.co/bert-large-cased-whole-word-masking-finetuned-squad/resolve/main/vocab.txt",
|
||||
"bert-base-cased-finetuned-mrpc": "https://huggingface.co/bert-base-cased-finetuned-mrpc/resolve/main/vocab.txt",
|
||||
"bert-base-german-dbmdz-cased": "https://huggingface.co/bert-base-german-dbmdz-cased/resolve/main/vocab.txt",
|
||||
"bert-base-german-dbmdz-uncased": "https://huggingface.co/bert-base-german-dbmdz-uncased/resolve/main/vocab.txt",
|
||||
"TurkuNLP/bert-base-finnish-cased-v1": "https://huggingface.co/TurkuNLP/bert-base-finnish-cased-v1/resolve/main/vocab.txt",
|
||||
"TurkuNLP/bert-base-finnish-uncased-v1": "https://huggingface.co/TurkuNLP/bert-base-finnish-uncased-v1/resolve/main/vocab.txt",
|
||||
"wietsedv/bert-base-dutch-cased": "https://huggingface.co/wietsedv/bert-base-dutch-cased/resolve/main/vocab.txt",
|
||||
}
|
||||
}
|
||||
|
||||
PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES = {
|
||||
"bert-base-uncased": 512,
|
||||
"bert-large-uncased": 512,
|
||||
"bert-base-cased": 512,
|
||||
"bert-large-cased": 512,
|
||||
"bert-base-multilingual-uncased": 512,
|
||||
"bert-base-multilingual-cased": 512,
|
||||
"bert-base-chinese": 512,
|
||||
"bert-base-german-cased": 512,
|
||||
"bert-large-uncased-whole-word-masking": 512,
|
||||
"bert-large-cased-whole-word-masking": 512,
|
||||
"bert-large-uncased-whole-word-masking-finetuned-squad": 512,
|
||||
"bert-large-cased-whole-word-masking-finetuned-squad": 512,
|
||||
"bert-base-cased-finetuned-mrpc": 512,
|
||||
"bert-base-german-dbmdz-cased": 512,
|
||||
"bert-base-german-dbmdz-uncased": 512,
|
||||
"TurkuNLP/bert-base-finnish-cased-v1": 512,
|
||||
"TurkuNLP/bert-base-finnish-uncased-v1": 512,
|
||||
"wietsedv/bert-base-dutch-cased": 512,
|
||||
}
|
||||
|
||||
PRETRAINED_INIT_CONFIGURATION = {
|
||||
"bert-base-uncased": {"do_lower_case": True},
|
||||
"bert-large-uncased": {"do_lower_case": True},
|
||||
"bert-base-cased": {"do_lower_case": False},
|
||||
"bert-large-cased": {"do_lower_case": False},
|
||||
"bert-base-multilingual-uncased": {"do_lower_case": True},
|
||||
"bert-base-multilingual-cased": {"do_lower_case": False},
|
||||
"bert-base-chinese": {"do_lower_case": False},
|
||||
"bert-base-german-cased": {"do_lower_case": False},
|
||||
"bert-large-uncased-whole-word-masking": {"do_lower_case": True},
|
||||
"bert-large-cased-whole-word-masking": {"do_lower_case": False},
|
||||
"bert-large-uncased-whole-word-masking-finetuned-squad": {"do_lower_case": True},
|
||||
"bert-large-cased-whole-word-masking-finetuned-squad": {"do_lower_case": False},
|
||||
"bert-base-cased-finetuned-mrpc": {"do_lower_case": False},
|
||||
"bert-base-german-dbmdz-cased": {"do_lower_case": False},
|
||||
"bert-base-german-dbmdz-uncased": {"do_lower_case": True},
|
||||
"TurkuNLP/bert-base-finnish-cased-v1": {"do_lower_case": False},
|
||||
"TurkuNLP/bert-base-finnish-uncased-v1": {"do_lower_case": True},
|
||||
"wietsedv/bert-base-dutch-cased": {"do_lower_case": False},
|
||||
}
|
||||
|
||||
|
||||
def load_vocab(vocab_file):
|
||||
"""Loads a vocabulary file into a dictionary."""
|
||||
vocab = collections.OrderedDict()
|
||||
with open(vocab_file, "r", encoding="utf-8") as reader:
|
||||
tokens = reader.readlines()
|
||||
for index, token in enumerate(tokens):
|
||||
token = token.rstrip("\n")
|
||||
vocab[token] = index
|
||||
return vocab
|
||||
|
||||
|
||||
def whitespace_tokenize(text):
|
||||
"""Runs basic whitespace cleaning and splitting on a piece of text."""
|
||||
text = text.strip()
|
||||
if not text:
|
||||
return []
|
||||
tokens = text.split()
|
||||
return tokens
|
||||
|
||||
|
||||
class BertTokenizer(PreTrainedTokenizer):
|
||||
r"""
|
||||
Construct a BERT tokenizer. Based on WordPiece.
|
||||
|
||||
This tokenizer inherits from :class:`~transformers.PreTrainedTokenizer` which contains most of the main methods.
|
||||
Users should refer to this superclass for more information regarding those methods.
|
||||
|
||||
Args:
|
||||
vocab_file (:obj:`str`):
|
||||
File containing the vocabulary.
|
||||
do_lower_case (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Whether or not to lowercase the input when tokenizing.
|
||||
do_basic_tokenize (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Whether or not to do basic tokenization before WordPiece.
|
||||
never_split (:obj:`Iterable`, `optional`):
|
||||
Collection of tokens which will never be split during tokenization. Only has an effect when
|
||||
:obj:`do_basic_tokenize=True`
|
||||
unk_token (:obj:`str`, `optional`, defaults to :obj:`"[UNK]"`):
|
||||
The unknown token. A token that is not in the vocabulary cannot be converted to an ID and is set to be this
|
||||
token instead.
|
||||
sep_token (:obj:`str`, `optional`, defaults to :obj:`"[SEP]"`):
|
||||
The separator token, which is used when building a sequence from multiple sequences, e.g. two sequences for
|
||||
sequence classification or for a text and a question for question answering. It is also used as the last
|
||||
token of a sequence built with special tokens.
|
||||
pad_token (:obj:`str`, `optional`, defaults to :obj:`"[PAD]"`):
|
||||
The token used for padding, for example when batching sequences of different lengths.
|
||||
cls_token (:obj:`str`, `optional`, defaults to :obj:`"[CLS]"`):
|
||||
The classifier token which is used when doing sequence classification (classification of the whole sequence
|
||||
instead of per-token classification). It is the first token of the sequence when built with special tokens.
|
||||
mask_token (:obj:`str`, `optional`, defaults to :obj:`"[MASK]"`):
|
||||
The token used for masking values. This is the token used when training this model with masked language
|
||||
modeling. This is the token which the model will try to predict.
|
||||
tokenize_chinese_chars (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Whether or not to tokenize Chinese characters.
|
||||
|
||||
This should likely be deactivated for Japanese (see this `issue
|
||||
<https://github.com/huggingface/transformers/issues/328>`__).
|
||||
strip_accents: (:obj:`bool`, `optional`):
|
||||
Whether or not to strip all accents. If this option is not specified, then it will be determined by the
|
||||
value for :obj:`lowercase` (as in the original BERT).
|
||||
"""
|
||||
|
||||
vocab_files_names = VOCAB_FILES_NAMES
|
||||
pretrained_vocab_files_map = PRETRAINED_VOCAB_FILES_MAP
|
||||
pretrained_init_configuration = PRETRAINED_INIT_CONFIGURATION
|
||||
max_model_input_sizes = PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vocab_file,
|
||||
do_lower_case=True,
|
||||
do_basic_tokenize=True,
|
||||
never_split=None,
|
||||
unk_token="[UNK]",
|
||||
sep_token="[SEP]",
|
||||
pad_token="[PAD]",
|
||||
cls_token="[CLS]",
|
||||
mask_token="[MASK]",
|
||||
tokenize_chinese_chars=True,
|
||||
strip_accents=None,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
do_lower_case=do_lower_case,
|
||||
do_basic_tokenize=do_basic_tokenize,
|
||||
never_split=never_split,
|
||||
unk_token=unk_token,
|
||||
sep_token=sep_token,
|
||||
pad_token=pad_token,
|
||||
cls_token=cls_token,
|
||||
mask_token=mask_token,
|
||||
tokenize_chinese_chars=tokenize_chinese_chars,
|
||||
strip_accents=strip_accents,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
if not os.path.isfile(vocab_file):
|
||||
raise ValueError(
|
||||
f"Can't find a vocabulary file at path '{vocab_file}'. To load the vocabulary from a Google pretrained "
|
||||
"model use `tokenizer = BertTokenizer.from_pretrained(PRETRAINED_MODEL_NAME)`"
|
||||
)
|
||||
self.vocab = load_vocab(vocab_file)
|
||||
self.ids_to_tokens = collections.OrderedDict([(ids, tok) for tok, ids in self.vocab.items()])
|
||||
self.do_basic_tokenize = do_basic_tokenize
|
||||
if do_basic_tokenize:
|
||||
self.basic_tokenizer = BasicTokenizer(
|
||||
do_lower_case=do_lower_case,
|
||||
never_split=never_split,
|
||||
tokenize_chinese_chars=tokenize_chinese_chars,
|
||||
strip_accents=strip_accents,
|
||||
)
|
||||
self.wordpiece_tokenizer = WordpieceTokenizer(vocab=self.vocab, unk_token=self.unk_token)
|
||||
|
||||
@property
|
||||
def do_lower_case(self):
|
||||
return self.basic_tokenizer.do_lower_case
|
||||
|
||||
@property
|
||||
def vocab_size(self):
|
||||
return len(self.vocab)
|
||||
|
||||
def get_vocab(self):
|
||||
return dict(self.vocab, **self.added_tokens_encoder)
|
||||
|
||||
def _tokenize(self, text):
|
||||
split_tokens = []
|
||||
if self.do_basic_tokenize:
|
||||
for token in self.basic_tokenizer.tokenize(text, never_split=self.all_special_tokens):
|
||||
|
||||
# If the token is part of the never_split set
|
||||
if token in self.basic_tokenizer.never_split:
|
||||
split_tokens.append(token)
|
||||
else:
|
||||
split_tokens += self.wordpiece_tokenizer.tokenize(token)
|
||||
else:
|
||||
split_tokens = self.wordpiece_tokenizer.tokenize(text)
|
||||
return split_tokens
|
||||
|
||||
def _convert_token_to_id(self, token):
|
||||
"""Converts a token (str) in an id using the vocab."""
|
||||
return self.vocab.get(token, self.vocab.get(self.unk_token))
|
||||
|
||||
def _convert_id_to_token(self, index):
|
||||
"""Converts an index (integer) in a token (str) using the vocab."""
|
||||
return self.ids_to_tokens.get(index, self.unk_token)
|
||||
|
||||
def convert_tokens_to_string(self, tokens):
|
||||
"""Converts a sequence of tokens (string) in a single string."""
|
||||
out_string = " ".join(tokens).replace(" ##", "").strip()
|
||||
return out_string
|
||||
|
||||
def build_inputs_with_special_tokens(
|
||||
self, token_ids_0: List[int], token_ids_1: Optional[List[int]] = None
|
||||
) -> List[int]:
|
||||
"""
|
||||
Build model inputs from a sequence or a pair of sequence for sequence classification tasks by concatenating and
|
||||
adding special tokens. A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
- pair of sequences: ``[CLS] A [SEP] B [SEP]``
|
||||
|
||||
Args:
|
||||
token_ids_0 (:obj:`List[int]`):
|
||||
List of IDs to which the special tokens will be added.
|
||||
token_ids_1 (:obj:`List[int]`, `optional`):
|
||||
Optional second list of IDs for sequence pairs.
|
||||
|
||||
Returns:
|
||||
:obj:`List[int]`: List of `input IDs <../glossary.html#input-ids>`__ with the appropriate special tokens.
|
||||
"""
|
||||
if token_ids_1 is None:
|
||||
return [self.cls_token_id] + token_ids_0 + [self.sep_token_id]
|
||||
cls = [self.cls_token_id]
|
||||
sep = [self.sep_token_id]
|
||||
return cls + token_ids_0 + sep + token_ids_1 + sep
|
||||
|
||||
def get_special_tokens_mask(
|
||||
self, token_ids_0: List[int], token_ids_1: Optional[List[int]] = None, already_has_special_tokens: bool = False
|
||||
) -> List[int]:
|
||||
"""
|
||||
Retrieve sequence ids from a token list that has no special tokens added. This method is called when adding
|
||||
special tokens using the tokenizer ``prepare_for_model`` method.
|
||||
|
||||
Args:
|
||||
token_ids_0 (:obj:`List[int]`):
|
||||
List of IDs.
|
||||
token_ids_1 (:obj:`List[int]`, `optional`):
|
||||
Optional second list of IDs for sequence pairs.
|
||||
already_has_special_tokens (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not the token list is already formatted with special tokens for the model.
|
||||
|
||||
Returns:
|
||||
:obj:`List[int]`: A list of integers in the range [0, 1]: 1 for a special token, 0 for a sequence token.
|
||||
"""
|
||||
|
||||
if already_has_special_tokens:
|
||||
return super().get_special_tokens_mask(
|
||||
token_ids_0=token_ids_0, token_ids_1=token_ids_1, already_has_special_tokens=True
|
||||
)
|
||||
|
||||
if token_ids_1 is not None:
|
||||
return [1] + ([0] * len(token_ids_0)) + [1] + ([0] * len(token_ids_1)) + [1]
|
||||
return [1] + ([0] * len(token_ids_0)) + [1]
|
||||
|
||||
def create_token_type_ids_from_sequences(
|
||||
self, token_ids_0: List[int], token_ids_1: Optional[List[int]] = None
|
||||
) -> List[int]:
|
||||
"""
|
||||
Create a mask from the two sequences passed to be used in a sequence-pair classification task. A BERT sequence
|
||||
pair mask has the following format:
|
||||
|
||||
::
|
||||
|
||||
0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1
|
||||
| first sequence | second sequence |
|
||||
|
||||
If :obj:`token_ids_1` is :obj:`None`, this method only returns the first portion of the mask (0s).
|
||||
|
||||
Args:
|
||||
token_ids_0 (:obj:`List[int]`):
|
||||
List of IDs.
|
||||
token_ids_1 (:obj:`List[int]`, `optional`):
|
||||
Optional second list of IDs for sequence pairs.
|
||||
|
||||
Returns:
|
||||
:obj:`List[int]`: List of `token type IDs <../glossary.html#token-type-ids>`_ according to the given
|
||||
sequence(s).
|
||||
"""
|
||||
sep = [self.sep_token_id]
|
||||
cls = [self.cls_token_id]
|
||||
if token_ids_1 is None:
|
||||
return len(cls + token_ids_0 + sep) * [0]
|
||||
return len(cls + token_ids_0 + sep) * [0] + len(token_ids_1 + sep) * [1]
|
||||
|
||||
def save_vocabulary(self, save_directory: str, filename_prefix: Optional[str] = None) -> Tuple[str]:
|
||||
index = 0
|
||||
if os.path.isdir(save_directory):
|
||||
vocab_file = os.path.join(
|
||||
save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"]
|
||||
)
|
||||
else:
|
||||
vocab_file = (filename_prefix + "-" if filename_prefix else "") + save_directory
|
||||
with open(vocab_file, "w", encoding="utf-8") as writer:
|
||||
for token, token_index in sorted(self.vocab.items(), key=lambda kv: kv[1]):
|
||||
if index != token_index:
|
||||
logger.warning(
|
||||
f"Saving vocabulary to {vocab_file}: vocabulary indices are not consecutive."
|
||||
" Please check that the vocabulary is not corrupted!"
|
||||
)
|
||||
index = token_index
|
||||
writer.write(token + "\n")
|
||||
index += 1
|
||||
return (vocab_file,)
|
||||
|
||||
|
||||
class BasicTokenizer(object):
|
||||
"""
|
||||
Constructs a BasicTokenizer that will run basic tokenization (punctuation splitting, lower casing, etc.).
|
||||
|
||||
Args:
|
||||
do_lower_case (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Whether or not to lowercase the input when tokenizing.
|
||||
never_split (:obj:`Iterable`, `optional`):
|
||||
Collection of tokens which will never be split during tokenization. Only has an effect when
|
||||
:obj:`do_basic_tokenize=True`
|
||||
tokenize_chinese_chars (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Whether or not to tokenize Chinese characters.
|
||||
|
||||
This should likely be deactivated for Japanese (see this `issue
|
||||
<https://github.com/huggingface/transformers/issues/328>`__).
|
||||
strip_accents: (:obj:`bool`, `optional`):
|
||||
Whether or not to strip all accents. If this option is not specified, then it will be determined by the
|
||||
value for :obj:`lowercase` (as in the original BERT).
|
||||
"""
|
||||
|
||||
def __init__(self, do_lower_case=True, never_split=None, tokenize_chinese_chars=True, strip_accents=None):
|
||||
if never_split is None:
|
||||
never_split = []
|
||||
self.do_lower_case = do_lower_case
|
||||
self.never_split = set(never_split)
|
||||
self.tokenize_chinese_chars = tokenize_chinese_chars
|
||||
self.strip_accents = strip_accents
|
||||
|
||||
def tokenize(self, text, never_split=None):
|
||||
"""
|
||||
Basic Tokenization of a piece of text. Split on "white spaces" only, for sub-word tokenization, see
|
||||
WordPieceTokenizer.
|
||||
|
||||
Args:
|
||||
**never_split**: (`optional`) list of str
|
||||
Kept for backward compatibility purposes. Now implemented directly at the base class level (see
|
||||
:func:`PreTrainedTokenizer.tokenize`) List of token not to split.
|
||||
"""
|
||||
# union() returns a new set by concatenating the two sets.
|
||||
never_split = self.never_split.union(set(never_split)) if never_split else self.never_split
|
||||
text = self._clean_text(text)
|
||||
|
||||
# This was added on November 1st, 2018 for the multilingual and Chinese
|
||||
# models. This is also applied to the English models now, but it doesn't
|
||||
# matter since the English models were not trained on any Chinese data
|
||||
# and generally don't have any Chinese data in them (there are Chinese
|
||||
# characters in the vocabulary because Wikipedia does have some Chinese
|
||||
# words in the English Wikipedia.).
|
||||
if self.tokenize_chinese_chars:
|
||||
text = self._tokenize_chinese_chars(text)
|
||||
orig_tokens = whitespace_tokenize(text)
|
||||
split_tokens = []
|
||||
for token in orig_tokens:
|
||||
if token not in never_split:
|
||||
if self.do_lower_case:
|
||||
token = token.lower()
|
||||
if self.strip_accents is not False:
|
||||
token = self._run_strip_accents(token)
|
||||
elif self.strip_accents:
|
||||
token = self._run_strip_accents(token)
|
||||
split_tokens.extend(self._run_split_on_punc(token, never_split))
|
||||
|
||||
output_tokens = whitespace_tokenize(" ".join(split_tokens))
|
||||
return output_tokens
|
||||
|
||||
def _run_strip_accents(self, text):
|
||||
"""Strips accents from a piece of text."""
|
||||
text = unicodedata.normalize("NFD", text)
|
||||
output = []
|
||||
for char in text:
|
||||
cat = unicodedata.category(char)
|
||||
if cat == "Mn":
|
||||
continue
|
||||
output.append(char)
|
||||
return "".join(output)
|
||||
|
||||
def _run_split_on_punc(self, text, never_split=None):
|
||||
"""Splits punctuation on a piece of text."""
|
||||
if never_split is not None and text in never_split:
|
||||
return [text]
|
||||
chars = list(text)
|
||||
i = 0
|
||||
start_new_word = True
|
||||
output = []
|
||||
while i < len(chars):
|
||||
char = chars[i]
|
||||
if _is_punctuation(char):
|
||||
output.append([char])
|
||||
start_new_word = True
|
||||
else:
|
||||
if start_new_word:
|
||||
output.append([])
|
||||
start_new_word = False
|
||||
output[-1].append(char)
|
||||
i += 1
|
||||
|
||||
return ["".join(x) for x in output]
|
||||
|
||||
def _tokenize_chinese_chars(self, text):
|
||||
"""Adds whitespace around any CJK character."""
|
||||
output = []
|
||||
for char in text:
|
||||
cp = ord(char)
|
||||
if self._is_chinese_char(cp):
|
||||
output.append(" ")
|
||||
output.append(char)
|
||||
output.append(" ")
|
||||
else:
|
||||
output.append(char)
|
||||
return "".join(output)
|
||||
|
||||
def _is_chinese_char(self, cp):
|
||||
"""Checks whether CP is the codepoint of a CJK character."""
|
||||
# This defines a "chinese character" as anything in the CJK Unicode block:
|
||||
# https://en.wikipedia.org/wiki/CJK_Unified_Ideographs_(Unicode_block)
|
||||
#
|
||||
# Note that the CJK Unicode block is NOT all Japanese and Korean characters,
|
||||
# despite its name. The modern Korean Hangul alphabet is a different block,
|
||||
# as is Japanese Hiragana and Katakana. Those alphabets are used to write
|
||||
# space-separated words, so they are not treated specially and handled
|
||||
# like the all of the other languages.
|
||||
if (
|
||||
(cp >= 0x4E00 and cp <= 0x9FFF)
|
||||
or (cp >= 0x3400 and cp <= 0x4DBF) #
|
||||
or (cp >= 0x20000 and cp <= 0x2A6DF) #
|
||||
or (cp >= 0x2A700 and cp <= 0x2B73F) #
|
||||
or (cp >= 0x2B740 and cp <= 0x2B81F) #
|
||||
or (cp >= 0x2B820 and cp <= 0x2CEAF) #
|
||||
or (cp >= 0xF900 and cp <= 0xFAFF)
|
||||
or (cp >= 0x2F800 and cp <= 0x2FA1F) #
|
||||
): #
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _clean_text(self, text):
|
||||
"""Performs invalid character removal and whitespace cleanup on text."""
|
||||
output = []
|
||||
for char in text:
|
||||
cp = ord(char)
|
||||
if cp == 0 or cp == 0xFFFD or _is_control(char):
|
||||
continue
|
||||
if _is_whitespace(char):
|
||||
output.append(" ")
|
||||
else:
|
||||
output.append(char)
|
||||
return "".join(output)
|
||||
|
||||
|
||||
class WordpieceTokenizer(object):
|
||||
"""Runs WordPiece tokenization."""
|
||||
|
||||
def __init__(self, vocab, unk_token, max_input_chars_per_word=100):
|
||||
self.vocab = vocab
|
||||
self.unk_token = unk_token
|
||||
self.max_input_chars_per_word = max_input_chars_per_word
|
||||
|
||||
def tokenize(self, text):
|
||||
"""
|
||||
Tokenizes a piece of text into its word pieces. This uses a greedy longest-match-first algorithm to perform
|
||||
tokenization using the given vocabulary.
|
||||
|
||||
For example, :obj:`input = "unaffable"` wil return as output :obj:`["un", "##aff", "##able"]`.
|
||||
|
||||
Args:
|
||||
text: A single token or whitespace separated tokens. This should have
|
||||
already been passed through `BasicTokenizer`.
|
||||
|
||||
Returns:
|
||||
A list of wordpiece tokens.
|
||||
"""
|
||||
|
||||
output_tokens = []
|
||||
for token in whitespace_tokenize(text):
|
||||
chars = list(token)
|
||||
if len(chars) > self.max_input_chars_per_word:
|
||||
output_tokens.append(self.unk_token)
|
||||
continue
|
||||
|
||||
is_bad = False
|
||||
start = 0
|
||||
sub_tokens = []
|
||||
while start < len(chars):
|
||||
end = len(chars)
|
||||
cur_substr = None
|
||||
while start < end:
|
||||
substr = "".join(chars[start:end])
|
||||
if start > 0:
|
||||
substr = "##" + substr
|
||||
if substr in self.vocab:
|
||||
cur_substr = substr
|
||||
break
|
||||
end -= 1
|
||||
if cur_substr is None:
|
||||
is_bad = True
|
||||
break
|
||||
sub_tokens.append(cur_substr)
|
||||
start = end
|
||||
|
||||
if is_bad:
|
||||
output_tokens.append(self.unk_token)
|
||||
else:
|
||||
output_tokens.extend(sub_tokens)
|
||||
return output_tokens
|
12
fastNLP/transformers/torch/models/cpt/__init__.py
Normal file
12
fastNLP/transformers/torch/models/cpt/__init__.py
Normal file
@ -0,0 +1,12 @@
|
||||
__all__ = [
|
||||
"CPT_PRETRAINED_MODEL_ARCHIVE_LIST",
|
||||
"CPTForConditionalGeneration",
|
||||
"CPTForSequenceClassification",
|
||||
"CPTForMaskedLM",
|
||||
"CPTForQuestionAnswering",
|
||||
"CPTModel",
|
||||
"CPTPretrainedModel",
|
||||
]
|
||||
|
||||
from .modeling_cpt import CPT_PRETRAINED_MODEL_ARCHIVE_LIST, CPTForConditionalGeneration, CPTForSequenceClassification, \
|
||||
CPTForMaskedLM, CPTForQuestionAnswering, CPTModel, CPTPretrainedModel
|
1489
fastNLP/transformers/torch/models/cpt/modeling_cpt.py
Normal file
1489
fastNLP/transformers/torch/models/cpt/modeling_cpt.py
Normal file
File diff suppressed because it is too large
Load Diff
19
fastNLP/transformers/torch/models/gpt2/__init__.py
Normal file
19
fastNLP/transformers/torch/models/gpt2/__init__.py
Normal file
@ -0,0 +1,19 @@
|
||||
__all__ = [
|
||||
"GPT2_PRETRAINED_CONFIG_ARCHIVE_MAP",
|
||||
"GPT2Config",
|
||||
|
||||
"GPT2_PRETRAINED_MODEL_ARCHIVE_LIST",
|
||||
"GPT2DoubleHeadsModel",
|
||||
"GPT2ForSequenceClassification",
|
||||
"GPT2ForTokenClassification",
|
||||
"GPT2LMHeadModel",
|
||||
"GPT2Model",
|
||||
"GPT2PreTrainedModel",
|
||||
|
||||
"GPT2Tokenizer",
|
||||
]
|
||||
|
||||
from .configuration_gpt2 import GPT2_PRETRAINED_CONFIG_ARCHIVE_MAP, GPT2Config
|
||||
from .tokenization_gpt2 import GPT2Tokenizer
|
||||
from .modeling_gpt2 import GPT2_PRETRAINED_MODEL_ARCHIVE_LIST, GPT2DoubleHeadsModel, GPT2ForSequenceClassification, \
|
||||
GPT2ForTokenClassification, GPT2LMHeadModel, GPT2Model, GPT2PreTrainedModel
|
184
fastNLP/transformers/torch/models/gpt2/configuration_gpt2.py
Normal file
184
fastNLP/transformers/torch/models/gpt2/configuration_gpt2.py
Normal file
@ -0,0 +1,184 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The OpenAI Team Authors and HuggingFace Inc. team.
|
||||
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
""" OpenAI GPT-2 configuration """
|
||||
|
||||
from fastNLP.transformers.torch.configuration_utils import PretrainedConfig
|
||||
|
||||
__all__ = [
|
||||
"GPT2_PRETRAINED_CONFIG_ARCHIVE_MAP",
|
||||
"GPT2Config",
|
||||
]
|
||||
|
||||
GPT2_PRETRAINED_CONFIG_ARCHIVE_MAP = {
|
||||
"gpt2": "https://huggingface.co/gpt2/resolve/main/config.json",
|
||||
"gpt2-medium": "https://huggingface.co/gpt2-medium/resolve/main/config.json",
|
||||
"gpt2-large": "https://huggingface.co/gpt2-large/resolve/main/config.json",
|
||||
"gpt2-xl": "https://huggingface.co/gpt2-xl/resolve/main/config.json",
|
||||
"distilgpt2": "https://huggingface.co/distilgpt2/resolve/main/config.json",
|
||||
}
|
||||
|
||||
|
||||
class GPT2Config(PretrainedConfig):
|
||||
"""
|
||||
This is the configuration class to store the configuration of a :class:`~transformers.GPT2Model` or a
|
||||
:class:`~transformers.TFGPT2Model`. It is used to instantiate a GPT-2 model according to the specified arguments,
|
||||
defining the model architecture. Instantiating a configuration with the defaults will yield a similar configuration
|
||||
to that of the GPT-2 `small <https://huggingface.co/gpt2>`__ architecture.
|
||||
|
||||
Configuration objects inherit from :class:`~transformers.PretrainedConfig` and can be used to control the model
|
||||
outputs. Read the documentation from :class:`~transformers.PretrainedConfig` for more information.
|
||||
|
||||
|
||||
Args:
|
||||
vocab_size (:obj:`int`, `optional`, defaults to 50257):
|
||||
Vocabulary size of the GPT-2 model. Defines the number of different tokens that can be represented by the
|
||||
:obj:`inputs_ids` passed when calling :class:`~transformers.GPT2Model` or
|
||||
:class:`~transformers.TFGPT2Model`.
|
||||
n_positions (:obj:`int`, `optional`, defaults to 1024):
|
||||
The maximum sequence length that this model might ever be used with. Typically set this to something large
|
||||
just in case (e.g., 512 or 1024 or 2048).
|
||||
n_ctx (:obj:`int`, `optional`, defaults to 1024):
|
||||
Dimensionality of the causal mask (usually same as n_positions).
|
||||
n_embd (:obj:`int`, `optional`, defaults to 768):
|
||||
Dimensionality of the embeddings and hidden states.
|
||||
n_layer (:obj:`int`, `optional`, defaults to 12):
|
||||
Number of hidden layers in the Transformer encoder.
|
||||
n_head (:obj:`int`, `optional`, defaults to 12):
|
||||
Number of attention heads for each attention layer in the Transformer encoder.
|
||||
n_inner (:obj:`int`, `optional`, defaults to None):
|
||||
Dimensionality of the inner feed-forward layers. :obj:`None` will set it to 4 times n_embd
|
||||
activation_function (:obj:`str`, `optional`, defaults to :obj:`"gelu"`):
|
||||
Activation function, to be selected in the list :obj:`["relu", "silu", "gelu", "tanh", "gelu_new"]`.
|
||||
resid_pdrop (:obj:`float`, `optional`, defaults to 0.1):
|
||||
The dropout probability for all fully connected layers in the embeddings, encoder, and pooler.
|
||||
embd_pdrop (:obj:`int`, `optional`, defaults to 0.1):
|
||||
The dropout ratio for the embeddings.
|
||||
attn_pdrop (:obj:`float`, `optional`, defaults to 0.1):
|
||||
The dropout ratio for the attention.
|
||||
layer_norm_epsilon (:obj:`float`, `optional`, defaults to 1e-5):
|
||||
The epsilon to use in the layer normalization layers
|
||||
initializer_range (:obj:`float`, `optional`, defaults to 0.02):
|
||||
The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
|
||||
summary_type (:obj:`string`, `optional`, defaults to :obj:`"cls_index"`):
|
||||
Argument used when doing sequence summary, used in the models :class:`~transformers.GPT2DoubleHeadsModel`
|
||||
and :class:`~transformers.TFGPT2DoubleHeadsModel`.
|
||||
|
||||
Has to be one of the following options:
|
||||
|
||||
- :obj:`"last"`: Take the last token hidden state (like XLNet).
|
||||
- :obj:`"first"`: Take the first token hidden state (like BERT).
|
||||
- :obj:`"mean"`: Take the mean of all tokens hidden states.
|
||||
- :obj:`"cls_index"`: Supply a Tensor of classification token position (like GPT/GPT-2).
|
||||
- :obj:`"attn"`: Not implemented now, use multi-head attention.
|
||||
summary_use_proj (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Argument used when doing sequence summary, used in the models :class:`~transformers.GPT2DoubleHeadsModel`
|
||||
and :class:`~transformers.TFGPT2DoubleHeadsModel`.
|
||||
|
||||
Whether or not to add a projection after the vector extraction.
|
||||
summary_activation (:obj:`str`, `optional`):
|
||||
Argument used when doing sequence summary. Used in for the multiple choice head in
|
||||
:class:`~transformers.GPT2DoubleHeadsModel`.
|
||||
|
||||
Pass :obj:`"tanh"` for a tanh activation to the output, any other value will result in no activation.
|
||||
summary_proj_to_labels (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Argument used when doing sequence summary, used in the models :class:`~transformers.GPT2DoubleHeadsModel`
|
||||
and :class:`~transformers.TFGPT2DoubleHeadsModel`.
|
||||
|
||||
Whether the projection outputs should have :obj:`config.num_labels` or :obj:`config.hidden_size` classes.
|
||||
summary_first_dropout (:obj:`float`, `optional`, defaults to 0.1):
|
||||
Argument used when doing sequence summary, used in the models :class:`~transformers.GPT2DoubleHeadsModel`
|
||||
and :class:`~transformers.TFGPT2DoubleHeadsModel`.
|
||||
|
||||
The dropout ratio to be used after the projection and activation.
|
||||
scale_attn_weights (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Scale attention weights by dividing by sqrt(hidden_size)..
|
||||
use_cache (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Whether or not the model should return the last key/values attentions (not used by all models).
|
||||
|
||||
Example::
|
||||
|
||||
>>> from transformers import GPT2Model, GPT2Config
|
||||
|
||||
>>> # Initializing a GPT2 configuration
|
||||
>>> configuration = GPT2Config()
|
||||
|
||||
>>> # Initializing a model from the configuration
|
||||
>>> model = GPT2Model(configuration)
|
||||
|
||||
>>> # Accessing the model configuration
|
||||
>>> configuration = model.config
|
||||
"""
|
||||
|
||||
model_type = "gpt2"
|
||||
keys_to_ignore_at_inference = ["past_key_values"]
|
||||
attribute_map = {
|
||||
"hidden_size": "n_embd",
|
||||
"max_position_embeddings": "n_positions",
|
||||
"num_attention_heads": "n_head",
|
||||
"num_hidden_layers": "n_layer",
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vocab_size=50257,
|
||||
n_positions=1024,
|
||||
n_ctx=1024,
|
||||
n_embd=768,
|
||||
n_layer=12,
|
||||
n_head=12,
|
||||
n_inner=None,
|
||||
activation_function="gelu_new",
|
||||
resid_pdrop=0.1,
|
||||
embd_pdrop=0.1,
|
||||
attn_pdrop=0.1,
|
||||
layer_norm_epsilon=1e-5,
|
||||
initializer_range=0.02,
|
||||
summary_type="cls_index",
|
||||
summary_use_proj=True,
|
||||
summary_activation=None,
|
||||
summary_proj_to_labels=True,
|
||||
summary_first_dropout=0.1,
|
||||
scale_attn_weights=True,
|
||||
use_cache=True,
|
||||
bos_token_id=50256,
|
||||
eos_token_id=50256,
|
||||
**kwargs
|
||||
):
|
||||
self.vocab_size = vocab_size
|
||||
self.n_ctx = n_ctx
|
||||
self.n_positions = n_positions
|
||||
self.n_embd = n_embd
|
||||
self.n_layer = n_layer
|
||||
self.n_head = n_head
|
||||
self.n_inner = n_inner
|
||||
self.activation_function = activation_function
|
||||
self.resid_pdrop = resid_pdrop
|
||||
self.embd_pdrop = embd_pdrop
|
||||
self.attn_pdrop = attn_pdrop
|
||||
self.layer_norm_epsilon = layer_norm_epsilon
|
||||
self.initializer_range = initializer_range
|
||||
self.summary_type = summary_type
|
||||
self.summary_use_proj = summary_use_proj
|
||||
self.summary_activation = summary_activation
|
||||
self.summary_first_dropout = summary_first_dropout
|
||||
self.summary_proj_to_labels = summary_proj_to_labels
|
||||
self.scale_attn_weights = scale_attn_weights
|
||||
self.use_cache = use_cache
|
||||
|
||||
self.bos_token_id = bos_token_id
|
||||
self.eos_token_id = eos_token_id
|
||||
|
||||
super().__init__(bos_token_id=bos_token_id, eos_token_id=eos_token_id, **kwargs)
|
1393
fastNLP/transformers/torch/models/gpt2/modeling_gpt2.py
Normal file
1393
fastNLP/transformers/torch/models/gpt2/modeling_gpt2.py
Normal file
File diff suppressed because it is too large
Load Diff
308
fastNLP/transformers/torch/models/gpt2/tokenization_gpt2.py
Normal file
308
fastNLP/transformers/torch/models/gpt2/tokenization_gpt2.py
Normal file
@ -0,0 +1,308 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The Open AI Team Authors and The HuggingFace Inc. team.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Tokenization classes for OpenAI GPT."""
|
||||
|
||||
import json
|
||||
import os
|
||||
from functools import lru_cache
|
||||
from typing import TYPE_CHECKING, List, Optional, Tuple
|
||||
|
||||
import regex as re
|
||||
|
||||
from fastNLP.transformers.torch.tokenization_utils import AddedToken, PreTrainedTokenizer
|
||||
# if TYPE_CHECKING:
|
||||
# from transformers.pipelines.conversational import Conversation
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
__all__ = [
|
||||
"GPT2Tokenizer",
|
||||
]
|
||||
|
||||
VOCAB_FILES_NAMES = {
|
||||
"vocab_file": "vocab.json",
|
||||
"merges_file": "merges.txt",
|
||||
}
|
||||
|
||||
PRETRAINED_VOCAB_FILES_MAP = {
|
||||
"vocab_file": {
|
||||
"gpt2": "https://huggingface.co/gpt2/resolve/main/vocab.json",
|
||||
"gpt2-medium": "https://huggingface.co/gpt2-medium/resolve/main/vocab.json",
|
||||
"gpt2-large": "https://huggingface.co/gpt2-large/resolve/main/vocab.json",
|
||||
"gpt2-xl": "https://huggingface.co/gpt2-xl/resolve/main/vocab.json",
|
||||
"distilgpt2": "https://huggingface.co/distilgpt2/resolve/main/vocab.json",
|
||||
},
|
||||
"merges_file": {
|
||||
"gpt2": "https://huggingface.co/gpt2/resolve/main/merges.txt",
|
||||
"gpt2-medium": "https://huggingface.co/gpt2-medium/resolve/main/merges.txt",
|
||||
"gpt2-large": "https://huggingface.co/gpt2-large/resolve/main/merges.txt",
|
||||
"gpt2-xl": "https://huggingface.co/gpt2-xl/resolve/main/merges.txt",
|
||||
"distilgpt2": "https://huggingface.co/distilgpt2/resolve/main/merges.txt",
|
||||
},
|
||||
}
|
||||
|
||||
PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES = {
|
||||
"gpt2": 1024,
|
||||
"gpt2-medium": 1024,
|
||||
"gpt2-large": 1024,
|
||||
"gpt2-xl": 1024,
|
||||
"distilgpt2": 1024,
|
||||
}
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def bytes_to_unicode():
|
||||
"""
|
||||
Returns list of utf-8 byte and a mapping to unicode strings. We specifically avoids mapping to whitespace/control
|
||||
characters the bpe code barfs on.
|
||||
|
||||
The reversible bpe codes work on unicode strings. This means you need a large # of unicode characters in your vocab
|
||||
if you want to avoid UNKs. When you're at something like a 10B token dataset you end up needing around 5K for
|
||||
decent coverage. This is a significant percentage of your normal, say, 32K bpe vocab. To avoid that, we want lookup
|
||||
tables between utf-8 bytes and unicode strings.
|
||||
"""
|
||||
bs = (
|
||||
list(range(ord("!"), ord("~") + 1)) + list(range(ord("¡"), ord("¬") + 1)) + list(range(ord("®"), ord("ÿ") + 1))
|
||||
)
|
||||
cs = bs[:]
|
||||
n = 0
|
||||
for b in range(2 ** 8):
|
||||
if b not in bs:
|
||||
bs.append(b)
|
||||
cs.append(2 ** 8 + n)
|
||||
n += 1
|
||||
cs = [chr(n) for n in cs]
|
||||
return dict(zip(bs, cs))
|
||||
|
||||
|
||||
def get_pairs(word):
|
||||
"""
|
||||
Return set of symbol pairs in a word.
|
||||
|
||||
Word is represented as tuple of symbols (symbols being variable-length strings).
|
||||
"""
|
||||
pairs = set()
|
||||
prev_char = word[0]
|
||||
for char in word[1:]:
|
||||
pairs.add((prev_char, char))
|
||||
prev_char = char
|
||||
return pairs
|
||||
|
||||
|
||||
class GPT2Tokenizer(PreTrainedTokenizer):
|
||||
"""
|
||||
Construct a GPT-2 tokenizer. Based on byte-level Byte-Pair-Encoding.
|
||||
|
||||
This tokenizer has been trained to treat spaces like parts of the tokens (a bit like sentencepiece) so a word will
|
||||
be encoded differently whether it is at the beginning of the sentence (without space) or not:
|
||||
|
||||
::
|
||||
|
||||
>>> from transformers import GPT2Tokenizer
|
||||
>>> tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
|
||||
>>> tokenizer("Hello world")['input_ids']
|
||||
[15496, 995]
|
||||
>>> tokenizer(" Hello world")['input_ids']
|
||||
[18435, 995]
|
||||
|
||||
You can get around that behavior by passing ``add_prefix_space=True`` when instantiating this tokenizer or when you
|
||||
call it on some text, but since the model was not pretrained this way, it might yield a decrease in performance.
|
||||
|
||||
.. note::
|
||||
|
||||
When used with ``is_split_into_words=True``, this tokenizer will add a space before each word (even the first
|
||||
one).
|
||||
|
||||
This tokenizer inherits from :class:`~transformers.PreTrainedTokenizer` which contains most of the main methods.
|
||||
Users should refer to this superclass for more information regarding those methods.
|
||||
|
||||
Args:
|
||||
vocab_file (:obj:`str`):
|
||||
Path to the vocabulary file.
|
||||
merges_file (:obj:`str`):
|
||||
Path to the merges file.
|
||||
errors (:obj:`str`, `optional`, defaults to :obj:`"replace"`):
|
||||
Paradigm to follow when decoding bytes to UTF-8. See `bytes.decode
|
||||
<https://docs.python.org/3/library/stdtypes.html#bytes.decode>`__ for more information.
|
||||
unk_token (:obj:`str`, `optional`, defaults to :obj:`<|endoftext|>`):
|
||||
The unknown token. A token that is not in the vocabulary cannot be converted to an ID and is set to be this
|
||||
token instead.
|
||||
bos_token (:obj:`str`, `optional`, defaults to :obj:`<|endoftext|>`):
|
||||
The beginning of sequence token.
|
||||
eos_token (:obj:`str`, `optional`, defaults to :obj:`<|endoftext|>`):
|
||||
The end of sequence token.
|
||||
add_prefix_space (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to add an initial space to the input. This allows to treat the leading word just as any
|
||||
other word. (GPT2 tokenizer detect beginning of words by the preceding space).
|
||||
"""
|
||||
|
||||
vocab_files_names = VOCAB_FILES_NAMES
|
||||
pretrained_vocab_files_map = PRETRAINED_VOCAB_FILES_MAP
|
||||
max_model_input_sizes = PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
|
||||
model_input_names = ["input_ids", "attention_mask"]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vocab_file,
|
||||
merges_file,
|
||||
errors="replace",
|
||||
unk_token="<|endoftext|>",
|
||||
bos_token="<|endoftext|>",
|
||||
eos_token="<|endoftext|>",
|
||||
add_prefix_space=False,
|
||||
**kwargs
|
||||
):
|
||||
bos_token = AddedToken(bos_token, lstrip=False, rstrip=False) if isinstance(bos_token, str) else bos_token
|
||||
eos_token = AddedToken(eos_token, lstrip=False, rstrip=False) if isinstance(eos_token, str) else eos_token
|
||||
unk_token = AddedToken(unk_token, lstrip=False, rstrip=False) if isinstance(unk_token, str) else unk_token
|
||||
super().__init__(
|
||||
errors=errors,
|
||||
unk_token=unk_token,
|
||||
bos_token=bos_token,
|
||||
eos_token=eos_token,
|
||||
add_prefix_space=add_prefix_space,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
with open(vocab_file, encoding="utf-8") as vocab_handle:
|
||||
self.encoder = json.load(vocab_handle)
|
||||
self.decoder = {v: k for k, v in self.encoder.items()}
|
||||
self.errors = errors # how to handle errors in decoding
|
||||
self.byte_encoder = bytes_to_unicode()
|
||||
self.byte_decoder = {v: k for k, v in self.byte_encoder.items()}
|
||||
with open(merges_file, encoding="utf-8") as merges_handle:
|
||||
bpe_merges = merges_handle.read().split("\n")[1:-1]
|
||||
bpe_merges = [tuple(merge.split()) for merge in bpe_merges]
|
||||
self.bpe_ranks = dict(zip(bpe_merges, range(len(bpe_merges))))
|
||||
self.cache = {}
|
||||
self.add_prefix_space = add_prefix_space
|
||||
|
||||
# Should have added re.IGNORECASE so BPE merges can happen for capitalized versions of contractions
|
||||
self.pat = re.compile(r"""'s|'t|'re|'ve|'m|'ll|'d| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+""")
|
||||
|
||||
@property
|
||||
def vocab_size(self):
|
||||
return len(self.encoder)
|
||||
|
||||
def get_vocab(self):
|
||||
return dict(self.encoder, **self.added_tokens_encoder)
|
||||
|
||||
def bpe(self, token):
|
||||
if token in self.cache:
|
||||
return self.cache[token]
|
||||
word = tuple(token)
|
||||
pairs = get_pairs(word)
|
||||
|
||||
if not pairs:
|
||||
return token
|
||||
|
||||
while True:
|
||||
bigram = min(pairs, key=lambda pair: self.bpe_ranks.get(pair, float("inf")))
|
||||
if bigram not in self.bpe_ranks:
|
||||
break
|
||||
first, second = bigram
|
||||
new_word = []
|
||||
i = 0
|
||||
while i < len(word):
|
||||
try:
|
||||
j = word.index(first, i)
|
||||
except ValueError:
|
||||
new_word.extend(word[i:])
|
||||
break
|
||||
else:
|
||||
new_word.extend(word[i:j])
|
||||
i = j
|
||||
|
||||
if word[i] == first and i < len(word) - 1 and word[i + 1] == second:
|
||||
new_word.append(first + second)
|
||||
i += 2
|
||||
else:
|
||||
new_word.append(word[i])
|
||||
i += 1
|
||||
new_word = tuple(new_word)
|
||||
word = new_word
|
||||
if len(word) == 1:
|
||||
break
|
||||
else:
|
||||
pairs = get_pairs(word)
|
||||
word = " ".join(word)
|
||||
self.cache[token] = word
|
||||
return word
|
||||
|
||||
def _tokenize(self, text):
|
||||
"""Tokenize a string."""
|
||||
bpe_tokens = []
|
||||
for token in re.findall(self.pat, text):
|
||||
token = "".join(
|
||||
self.byte_encoder[b] for b in token.encode("utf-8")
|
||||
) # Maps all our bytes to unicode strings, avoiding control tokens of the BPE (spaces in our case)
|
||||
bpe_tokens.extend(bpe_token for bpe_token in self.bpe(token).split(" "))
|
||||
return bpe_tokens
|
||||
|
||||
def _convert_token_to_id(self, token):
|
||||
"""Converts a token (str) in an id using the vocab."""
|
||||
return self.encoder.get(token, self.encoder.get(self.unk_token))
|
||||
|
||||
def _convert_id_to_token(self, index):
|
||||
"""Converts an index (integer) in a token (str) using the vocab."""
|
||||
return self.decoder.get(index)
|
||||
|
||||
def convert_tokens_to_string(self, tokens):
|
||||
"""Converts a sequence of tokens (string) in a single string."""
|
||||
text = "".join(tokens)
|
||||
text = bytearray([self.byte_decoder[c] for c in text]).decode("utf-8", errors=self.errors)
|
||||
return text
|
||||
|
||||
def save_vocabulary(self, save_directory: str, filename_prefix: Optional[str] = None) -> Tuple[str]:
|
||||
if not os.path.isdir(save_directory):
|
||||
logger.error(f"Vocabulary path ({save_directory}) should be a directory")
|
||||
return
|
||||
vocab_file = os.path.join(
|
||||
save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"]
|
||||
)
|
||||
merge_file = os.path.join(
|
||||
save_directory, (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["merges_file"]
|
||||
)
|
||||
|
||||
with open(vocab_file, "w", encoding="utf-8") as f:
|
||||
f.write(json.dumps(self.encoder, ensure_ascii=False))
|
||||
|
||||
index = 0
|
||||
with open(merge_file, "w", encoding="utf-8") as writer:
|
||||
writer.write("#version: 0.2\n")
|
||||
for bpe_tokens, token_index in sorted(self.bpe_ranks.items(), key=lambda kv: kv[1]):
|
||||
if index != token_index:
|
||||
logger.warning(
|
||||
f"Saving vocabulary to {merge_file}: BPE merge indices are not consecutive."
|
||||
" Please check that the tokenizer is not corrupted!"
|
||||
)
|
||||
index = token_index
|
||||
writer.write(" ".join(bpe_tokens) + "\n")
|
||||
index += 1
|
||||
|
||||
return vocab_file, merge_file
|
||||
|
||||
def prepare_for_tokenization(self, text, is_split_into_words=False, **kwargs):
|
||||
add_prefix_space = kwargs.pop("add_prefix_space", self.add_prefix_space)
|
||||
if is_split_into_words or add_prefix_space:
|
||||
text = " " + text
|
||||
return (text, kwargs)
|
||||
|
||||
# def _build_conversation_input_ids(self, conversation: "Conversation") -> List[int]:
|
||||
# input_ids = []
|
||||
# for is_user, text in conversation.iter_texts():
|
||||
# input_ids.extend(self.encode(text, add_special_tokens=False) + [self.eos_token_id])
|
||||
# if len(input_ids) > self.model_max_length:
|
||||
# input_ids = input_ids[-self.model_max_length :]
|
||||
# return input_ids
|
21
fastNLP/transformers/torch/models/roberta/__init__.py
Normal file
21
fastNLP/transformers/torch/models/roberta/__init__.py
Normal file
@ -0,0 +1,21 @@
|
||||
__all__ = [
|
||||
"ROBERTA_PRETRAINED_CONFIG_ARCHIVE_MAP",
|
||||
"RobertaConfig",
|
||||
|
||||
"ROBERTA_PRETRAINED_MODEL_ARCHIVE_LIST",
|
||||
"RobertaForCausalLM",
|
||||
"RobertaForMaskedLM",
|
||||
"RobertaForMultipleChoice",
|
||||
"RobertaForQuestionAnswering",
|
||||
"RobertaForSequenceClassification",
|
||||
"RobertaForTokenClassification",
|
||||
"RobertaModel",
|
||||
"RobertaPreTrainedModel",
|
||||
|
||||
"RobertaTokenizer",
|
||||
]
|
||||
|
||||
from .configuration_roberta import ROBERTA_PRETRAINED_CONFIG_ARCHIVE_MAP, RobertaConfig
|
||||
from .tokenization_roberta import RobertaTokenizer
|
||||
from .modeling_roberta import ROBERTA_PRETRAINED_MODEL_ARCHIVE_LIST, RobertaForCausalLM, RobertaForMaskedLM, RobertaForMultipleChoice, \
|
||||
RobertaForQuestionAnswering, RobertaForSequenceClassification, RobertaForTokenClassification, RobertaModel, RobertaPreTrainedModel
|
@ -0,0 +1,65 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team.
|
||||
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
""" RoBERTa configuration """
|
||||
from ..bert.configuration_bert import BertConfig
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
__all__ = [
|
||||
"ROBERTA_PRETRAINED_CONFIG_ARCHIVE_MAP",
|
||||
"RobertaConfig",
|
||||
]
|
||||
|
||||
ROBERTA_PRETRAINED_CONFIG_ARCHIVE_MAP = {
|
||||
"roberta-base": "https://huggingface.co/roberta-base/resolve/main/config.json",
|
||||
"roberta-large": "https://huggingface.co/roberta-large/resolve/main/config.json",
|
||||
"roberta-large-mnli": "https://huggingface.co/roberta-large-mnli/resolve/main/config.json",
|
||||
"distilroberta-base": "https://huggingface.co/distilroberta-base/resolve/main/config.json",
|
||||
"roberta-base-openai-detector": "https://huggingface.co/roberta-base-openai-detector/resolve/main/config.json",
|
||||
"roberta-large-openai-detector": "https://huggingface.co/roberta-large-openai-detector/resolve/main/config.json",
|
||||
}
|
||||
|
||||
|
||||
class RobertaConfig(BertConfig):
|
||||
r"""
|
||||
This is the configuration class to store the configuration of a :class:`~transformers.RobertaModel` or a
|
||||
:class:`~transformers.TFRobertaModel`. It is used to instantiate a RoBERTa model according to the specified
|
||||
arguments, defining the model architecture.
|
||||
|
||||
|
||||
Configuration objects inherit from :class:`~transformers.PretrainedConfig` and can be used to control the model
|
||||
outputs. Read the documentation from :class:`~transformers.PretrainedConfig` for more information.
|
||||
|
||||
The :class:`~transformers.RobertaConfig` class directly inherits :class:`~transformers.BertConfig`. It reuses the
|
||||
same defaults. Please check the parent class for more information.
|
||||
|
||||
Examples::
|
||||
|
||||
>>> from transformers import RobertaConfig, RobertaModel
|
||||
|
||||
>>> # Initializing a RoBERTa configuration
|
||||
>>> configuration = RobertaConfig()
|
||||
|
||||
>>> # Initializing a model from the configuration
|
||||
>>> model = RobertaModel(configuration)
|
||||
|
||||
>>> # Accessing the model configuration
|
||||
>>> configuration = model.config
|
||||
"""
|
||||
model_type = "roberta"
|
||||
|
||||
def __init__(self, pad_token_id=1, bos_token_id=0, eos_token_id=2, **kwargs):
|
||||
"""Constructs RobertaConfig."""
|
||||
super().__init__(pad_token_id=pad_token_id, bos_token_id=bos_token_id, eos_token_id=eos_token_id, **kwargs)
|
1584
fastNLP/transformers/torch/models/roberta/modeling_roberta.py
Normal file
1584
fastNLP/transformers/torch/models/roberta/modeling_roberta.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,254 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The Open AI Team Authors and The HuggingFace Inc. team.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Tokenization classes for RoBERTa."""
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from fastNLP.transformers.torch.tokenization_utils import AddedToken
|
||||
from ..gpt2.tokenization_gpt2 import GPT2Tokenizer
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
__all__ = [
|
||||
"RobertaTokenizer",
|
||||
]
|
||||
|
||||
VOCAB_FILES_NAMES = {
|
||||
"vocab_file": "vocab.json",
|
||||
"merges_file": "merges.txt",
|
||||
}
|
||||
|
||||
PRETRAINED_VOCAB_FILES_MAP = {
|
||||
"vocab_file": {
|
||||
"roberta-base": "https://huggingface.co/roberta-base/resolve/main/vocab.json",
|
||||
"roberta-large": "https://huggingface.co/roberta-large/resolve/main/vocab.json",
|
||||
"roberta-large-mnli": "https://huggingface.co/roberta-large-mnli/resolve/main/vocab.json",
|
||||
"distilroberta-base": "https://huggingface.co/distilroberta-base/resolve/main/vocab.json",
|
||||
"roberta-base-openai-detector": "https://huggingface.co/roberta-base-openai-detector/resolve/main/vocab.json",
|
||||
"roberta-large-openai-detector": "https://huggingface.co/roberta-large-openai-detector/resolve/main/vocab.json",
|
||||
},
|
||||
"merges_file": {
|
||||
"roberta-base": "https://huggingface.co/roberta-base/resolve/main/merges.txt",
|
||||
"roberta-large": "https://huggingface.co/roberta-large/resolve/main/merges.txt",
|
||||
"roberta-large-mnli": "https://huggingface.co/roberta-large-mnli/resolve/main/merges.txt",
|
||||
"distilroberta-base": "https://huggingface.co/distilroberta-base/resolve/main/merges.txt",
|
||||
"roberta-base-openai-detector": "https://huggingface.co/roberta-base-openai-detector/resolve/main/merges.txt",
|
||||
"roberta-large-openai-detector": "https://huggingface.co/roberta-large-openai-detector/resolve/main/merges.txt",
|
||||
},
|
||||
}
|
||||
|
||||
PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES = {
|
||||
"roberta-base": 512,
|
||||
"roberta-large": 512,
|
||||
"roberta-large-mnli": 512,
|
||||
"distilroberta-base": 512,
|
||||
"roberta-base-openai-detector": 512,
|
||||
"roberta-large-openai-detector": 512,
|
||||
}
|
||||
|
||||
|
||||
class RobertaTokenizer(GPT2Tokenizer):
|
||||
"""
|
||||
Constructs a RoBERTa tokenizer, derived from the GPT-2 tokenizer, using byte-level Byte-Pair-Encoding.
|
||||
|
||||
This tokenizer has been trained to treat spaces like parts of the tokens (a bit like sentencepiece) so a word will
|
||||
be encoded differently whether it is at the beginning of the sentence (without space) or not:
|
||||
|
||||
::
|
||||
|
||||
>>> from transformers import RobertaTokenizer
|
||||
>>> tokenizer = RobertaTokenizer.from_pretrained("roberta-base")
|
||||
>>> tokenizer("Hello world")['input_ids']
|
||||
[0, 31414, 232, 328, 2]
|
||||
>>> tokenizer(" Hello world")['input_ids']
|
||||
[0, 20920, 232, 2]
|
||||
|
||||
You can get around that behavior by passing ``add_prefix_space=True`` when instantiating this tokenizer or when you
|
||||
call it on some text, but since the model was not pretrained this way, it might yield a decrease in performance.
|
||||
|
||||
.. note::
|
||||
|
||||
When used with ``is_split_into_words=True``, this tokenizer will add a space before each word (even the first
|
||||
one).
|
||||
|
||||
This tokenizer inherits from :class:`~transformers.PreTrainedTokenizer` which contains most of the main methods.
|
||||
Users should refer to this superclass for more information regarding those methods.
|
||||
|
||||
Args:
|
||||
vocab_file (:obj:`str`):
|
||||
Path to the vocabulary file.
|
||||
merges_file (:obj:`str`):
|
||||
Path to the merges file.
|
||||
errors (:obj:`str`, `optional`, defaults to :obj:`"replace"`):
|
||||
Paradigm to follow when decoding bytes to UTF-8. See `bytes.decode
|
||||
<https://docs.python.org/3/library/stdtypes.html#bytes.decode>`__ for more information.
|
||||
bos_token (:obj:`str`, `optional`, defaults to :obj:`"<s>"`):
|
||||
The beginning of sequence token that was used during pretraining. Can be used a sequence classifier token.
|
||||
|
||||
.. note::
|
||||
|
||||
When building a sequence using special tokens, this is not the token that is used for the beginning of
|
||||
sequence. The token used is the :obj:`cls_token`.
|
||||
eos_token (:obj:`str`, `optional`, defaults to :obj:`"</s>"`):
|
||||
The end of sequence token.
|
||||
|
||||
.. note::
|
||||
|
||||
When building a sequence using special tokens, this is not the token that is used for the end of
|
||||
sequence. The token used is the :obj:`sep_token`.
|
||||
sep_token (:obj:`str`, `optional`, defaults to :obj:`"</s>"`):
|
||||
The separator token, which is used when building a sequence from multiple sequences, e.g. two sequences for
|
||||
sequence classification or for a text and a question for question answering. It is also used as the last
|
||||
token of a sequence built with special tokens.
|
||||
cls_token (:obj:`str`, `optional`, defaults to :obj:`"<s>"`):
|
||||
The classifier token which is used when doing sequence classification (classification of the whole sequence
|
||||
instead of per-token classification). It is the first token of the sequence when built with special tokens.
|
||||
unk_token (:obj:`str`, `optional`, defaults to :obj:`"<unk>"`):
|
||||
The unknown token. A token that is not in the vocabulary cannot be converted to an ID and is set to be this
|
||||
token instead.
|
||||
pad_token (:obj:`str`, `optional`, defaults to :obj:`"<pad>"`):
|
||||
The token used for padding, for example when batching sequences of different lengths.
|
||||
mask_token (:obj:`str`, `optional`, defaults to :obj:`"<mask>"`):
|
||||
The token used for masking values. This is the token used when training this model with masked language
|
||||
modeling. This is the token which the model will try to predict.
|
||||
add_prefix_space (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to add an initial space to the input. This allows to treat the leading word just as any
|
||||
other word. (RoBERTa tokenizer detect beginning of words by the preceding space).
|
||||
"""
|
||||
|
||||
vocab_files_names = VOCAB_FILES_NAMES
|
||||
pretrained_vocab_files_map = PRETRAINED_VOCAB_FILES_MAP
|
||||
max_model_input_sizes = PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
|
||||
model_input_names = ["input_ids", "attention_mask"]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vocab_file,
|
||||
merges_file,
|
||||
errors="replace",
|
||||
bos_token="<s>",
|
||||
eos_token="</s>",
|
||||
sep_token="</s>",
|
||||
cls_token="<s>",
|
||||
unk_token="<unk>",
|
||||
pad_token="<pad>",
|
||||
mask_token="<mask>",
|
||||
add_prefix_space=False,
|
||||
**kwargs
|
||||
):
|
||||
bos_token = AddedToken(bos_token, lstrip=False, rstrip=False) if isinstance(bos_token, str) else bos_token
|
||||
eos_token = AddedToken(eos_token, lstrip=False, rstrip=False) if isinstance(eos_token, str) else eos_token
|
||||
sep_token = AddedToken(sep_token, lstrip=False, rstrip=False) if isinstance(sep_token, str) else sep_token
|
||||
cls_token = AddedToken(cls_token, lstrip=False, rstrip=False) if isinstance(cls_token, str) else cls_token
|
||||
unk_token = AddedToken(unk_token, lstrip=False, rstrip=False) if isinstance(unk_token, str) else unk_token
|
||||
pad_token = AddedToken(pad_token, lstrip=False, rstrip=False) if isinstance(pad_token, str) else pad_token
|
||||
|
||||
# Mask token behave like a normal word, i.e. include the space before it
|
||||
mask_token = AddedToken(mask_token, lstrip=True, rstrip=False) if isinstance(mask_token, str) else mask_token
|
||||
|
||||
super().__init__(
|
||||
vocab_file=vocab_file,
|
||||
merges_file=merges_file,
|
||||
errors=errors,
|
||||
bos_token=bos_token,
|
||||
eos_token=eos_token,
|
||||
unk_token=unk_token,
|
||||
sep_token=sep_token,
|
||||
cls_token=cls_token,
|
||||
pad_token=pad_token,
|
||||
mask_token=mask_token,
|
||||
add_prefix_space=add_prefix_space,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def build_inputs_with_special_tokens(
|
||||
self, token_ids_0: List[int], token_ids_1: Optional[List[int]] = None
|
||||
) -> List[int]:
|
||||
"""
|
||||
Build model inputs from a sequence or a pair of sequence for sequence classification tasks by concatenating and
|
||||
adding special tokens. A RoBERTa sequence has the following format:
|
||||
|
||||
- single sequence: ``<s> X </s>``
|
||||
- pair of sequences: ``<s> A </s></s> B </s>``
|
||||
|
||||
Args:
|
||||
token_ids_0 (:obj:`List[int]`):
|
||||
List of IDs to which the special tokens will be added.
|
||||
token_ids_1 (:obj:`List[int]`, `optional`):
|
||||
Optional second list of IDs for sequence pairs.
|
||||
|
||||
Returns:
|
||||
:obj:`List[int]`: List of `input IDs <../glossary.html#input-ids>`__ with the appropriate special tokens.
|
||||
"""
|
||||
if token_ids_1 is None:
|
||||
return [self.cls_token_id] + token_ids_0 + [self.sep_token_id]
|
||||
cls = [self.cls_token_id]
|
||||
sep = [self.sep_token_id]
|
||||
return cls + token_ids_0 + sep + sep + token_ids_1 + sep
|
||||
|
||||
def get_special_tokens_mask(
|
||||
self, token_ids_0: List[int], token_ids_1: Optional[List[int]] = None, already_has_special_tokens: bool = False
|
||||
) -> List[int]:
|
||||
"""
|
||||
Retrieve sequence ids from a token list that has no special tokens added. This method is called when adding
|
||||
special tokens using the tokenizer ``prepare_for_model`` method.
|
||||
|
||||
Args:
|
||||
token_ids_0 (:obj:`List[int]`):
|
||||
List of IDs.
|
||||
token_ids_1 (:obj:`List[int]`, `optional`):
|
||||
Optional second list of IDs for sequence pairs.
|
||||
already_has_special_tokens (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not the token list is already formatted with special tokens for the model.
|
||||
|
||||
Returns:
|
||||
:obj:`List[int]`: A list of integers in the range [0, 1]: 1 for a special token, 0 for a sequence token.
|
||||
"""
|
||||
if already_has_special_tokens:
|
||||
return super().get_special_tokens_mask(
|
||||
token_ids_0=token_ids_0, token_ids_1=token_ids_1, already_has_special_tokens=True
|
||||
)
|
||||
|
||||
if token_ids_1 is None:
|
||||
return [1] + ([0] * len(token_ids_0)) + [1]
|
||||
return [1] + ([0] * len(token_ids_0)) + [1, 1] + ([0] * len(token_ids_1)) + [1]
|
||||
|
||||
def create_token_type_ids_from_sequences(
|
||||
self, token_ids_0: List[int], token_ids_1: Optional[List[int]] = None
|
||||
) -> List[int]:
|
||||
"""
|
||||
Create a mask from the two sequences passed to be used in a sequence-pair classification task. RoBERTa does not
|
||||
make use of token type ids, therefore a list of zeros is returned.
|
||||
|
||||
Args:
|
||||
token_ids_0 (:obj:`List[int]`):
|
||||
List of IDs.
|
||||
token_ids_1 (:obj:`List[int]`, `optional`):
|
||||
Optional second list of IDs for sequence pairs.
|
||||
|
||||
Returns:
|
||||
:obj:`List[int]`: List of zeros.
|
||||
"""
|
||||
sep = [self.sep_token_id]
|
||||
cls = [self.cls_token_id]
|
||||
|
||||
if token_ids_1 is None:
|
||||
return len(cls + token_ids_0 + sep) * [0]
|
||||
return len(cls + token_ids_0 + sep + sep + token_ids_1 + sep) * [0]
|
||||
|
||||
def prepare_for_tokenization(self, text, is_split_into_words=False, **kwargs):
|
||||
add_prefix_space = kwargs.pop("add_prefix_space", self.add_prefix_space)
|
||||
if (is_split_into_words or add_prefix_space) and (len(text) > 0 and not text[0].isspace()):
|
||||
text = " " + text
|
||||
return (text, kwargs)
|
915
fastNLP/transformers/torch/tokenization_utils.py
Normal file
915
fastNLP/transformers/torch/tokenization_utils.py
Normal file
@ -0,0 +1,915 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2020 The HuggingFace Inc. team.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
Tokenization classes for python tokenizers. For fast tokenizers (provided by HuggingFace's tokenizers library) see
|
||||
tokenization_utils_fast.py
|
||||
"""
|
||||
import bisect
|
||||
import itertools
|
||||
import re
|
||||
import unicodedata
|
||||
from collections import OrderedDict
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union, overload
|
||||
|
||||
from .file_utils import PaddingStrategy, TensorType, add_end_docstrings
|
||||
from .tokenization_utils_base import (
|
||||
ENCODE_KWARGS_DOCSTRING,
|
||||
ENCODE_PLUS_ADDITIONAL_KWARGS_DOCSTRING,
|
||||
INIT_TOKENIZER_DOCSTRING,
|
||||
AddedToken,
|
||||
BatchEncoding,
|
||||
EncodedInput,
|
||||
EncodedInputPair,
|
||||
PreTokenizedInput,
|
||||
PreTokenizedInputPair,
|
||||
PreTrainedTokenizerBase,
|
||||
TextInput,
|
||||
TextInputPair,
|
||||
TruncationStrategy,
|
||||
)
|
||||
|
||||
from fastNLP.core.log import logger
|
||||
|
||||
# Slow tokenizers are saved in a vocabulary plus three separated files
|
||||
SPECIAL_TOKENS_MAP_FILE = "special_tokens_map.json"
|
||||
ADDED_TOKENS_FILE = "added_tokens.json"
|
||||
TOKENIZER_CONFIG_FILE = "tokenizer_config.json"
|
||||
|
||||
|
||||
class Trie:
|
||||
"""
|
||||
Trie in Python. Creates a Trie out of a list of words. The trie is used to split on `added_tokens` in one pass
|
||||
Loose reference https://en.wikipedia.org/wiki/Trie
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.data = {}
|
||||
|
||||
def add(self, word: str):
|
||||
"""
|
||||
Passes over every char (utf-8 char) on word and recursively adds it to the internal `data` trie representation.
|
||||
The special key `""` is used to represent termination.
|
||||
|
||||
This function is idempotent, adding twice the same word will leave the trie unchanged
|
||||
|
||||
Example::
|
||||
|
||||
>>> trie = Trie()
|
||||
>>> trie.add("Hello 友達")
|
||||
>>> trie.data
|
||||
{"H": {"e": {"l": {"l": {"o": {" ": {"友": {"達": {"": 1}}}}}}}}}
|
||||
>>> trie.add("Hello")
|
||||
>>> trie.data
|
||||
{"H": {"e": {"l": {"l": {"o": {"": 1, " ": {"友": {"達": {"": 1}}}}}}}}}
|
||||
"""
|
||||
if not word:
|
||||
# Prevent empty string
|
||||
return
|
||||
ref = self.data
|
||||
for char in word:
|
||||
ref[char] = char in ref and ref[char] or {}
|
||||
ref = ref[char]
|
||||
ref[""] = 1
|
||||
|
||||
def split(self, text: str) -> List[str]:
|
||||
"""
|
||||
Will look for the words added to the trie within `text`. Output is the original string splitted along the
|
||||
boundaries of the words found.
|
||||
|
||||
This trie will match the longest possible word first !
|
||||
|
||||
Example::
|
||||
|
||||
>>> trie = Trie()
|
||||
>>> trie.split("[CLS] This is a extra_id_100")
|
||||
["[CLS] This is a extra_id_100"]
|
||||
>>> trie.add("[CLS]")
|
||||
>>> trie.add("extra_id_1")
|
||||
>>> trie.add("extra_id_100")
|
||||
>>> trie.split("[CLS] This is a extra_id_100")
|
||||
["[CLS]", " This is a ", "extra_id_100"]
|
||||
"""
|
||||
# indexes are counted left of the chars index.
|
||||
# "hello", index 0, is left of h, index 1 is between h and e.
|
||||
# index 5 is right of the "o".
|
||||
|
||||
# States are going to capture every possible start (indexes as above)
|
||||
# as keys, and have as values, a pointer to the position in the trie
|
||||
# where we're at. This is a partial match for now.
|
||||
# This enables to keep track of multiple matches while we're iterating
|
||||
# the string
|
||||
# If the trie contains, "blowing", and "lower" and we encounter the
|
||||
# string "blower", we need to split into ["b", "lower"].
|
||||
# This is where we need to keep track of multiple possible starts.
|
||||
states = OrderedDict()
|
||||
|
||||
# This will contain every indices where we need
|
||||
# to cut.
|
||||
# We force to cut at offset 0 and len(text) (added later)
|
||||
offsets = [0]
|
||||
|
||||
# This is used by the lookahead which needs to skip over
|
||||
# some text where the full match exceeded the place in the initial
|
||||
# for loop
|
||||
skip = None
|
||||
# Main loop, Giving this algorithm O(n) complexity
|
||||
for current, current_char in enumerate(text):
|
||||
if skip and current < skip:
|
||||
# Prevents the lookahead for matching twice
|
||||
# like extra_id_100 and id_100
|
||||
continue
|
||||
|
||||
# This will track every state
|
||||
# that stop matching, we need to stop tracking them.
|
||||
# If we look at "lowball", we're going to match "l" (add it to states), "o", "w", then
|
||||
# fail on "b", we need to remove 0 from the valid states.
|
||||
to_remove = set()
|
||||
# Whenever we found a match, we need to drop everything
|
||||
# this is a greedy algorithm, it will match on the first found token
|
||||
reset = False
|
||||
|
||||
# In this case, we already have partial matches (But unfinished)
|
||||
for start, trie_pointer in states.items():
|
||||
if "" in trie_pointer:
|
||||
# This is a final match, we need to reset and
|
||||
# store the results in `offsets`.
|
||||
|
||||
# Lookahead to match longest first
|
||||
# Important in case of extra_id_1 vs extra_id_100
|
||||
lookahead_index = current
|
||||
end = current
|
||||
next_char = text[lookahead_index] if lookahead_index < len(text) else None
|
||||
while next_char in trie_pointer:
|
||||
trie_pointer = trie_pointer[next_char]
|
||||
lookahead_index += 1
|
||||
if "" in trie_pointer:
|
||||
end = lookahead_index
|
||||
skip = lookahead_index
|
||||
|
||||
if lookahead_index == len(text):
|
||||
# End of string
|
||||
break
|
||||
next_char = text[lookahead_index]
|
||||
# End lookahead
|
||||
|
||||
# Storing and resetting
|
||||
offsets.append(start)
|
||||
offsets.append(end)
|
||||
reset = True
|
||||
elif current_char in trie_pointer:
|
||||
# The current character being looked at has a match within the trie
|
||||
# update the pointer (it will be stored back into states later).
|
||||
trie_pointer = trie_pointer[current_char]
|
||||
|
||||
# Storing back the new pointer into the states.
|
||||
# Partial matches got longer by one.
|
||||
states[start] = trie_pointer
|
||||
else:
|
||||
# The new character has not match in the trie, we need
|
||||
# to stop keeping track of this partial match.
|
||||
# We can't do it directly within the loop because of how
|
||||
# python iteration works
|
||||
to_remove.add(start)
|
||||
|
||||
# Either clearing the full start (we found a real match)
|
||||
# Or clearing only the partial matches that didn't work.
|
||||
if reset:
|
||||
states = {}
|
||||
else:
|
||||
for start in to_remove:
|
||||
del states[start]
|
||||
|
||||
# If this character is a starting character within the trie
|
||||
# start keeping track of this partial match.
|
||||
if current_char in self.data:
|
||||
states[current] = self.data[current_char]
|
||||
|
||||
# We have a cut at the end with states.
|
||||
for start, trie_pointer in states.items():
|
||||
if "" in trie_pointer:
|
||||
# This is a final match, we need to reset and
|
||||
# store the results in `offsets`.
|
||||
end = len(text)
|
||||
offsets.append(start)
|
||||
offsets.append(end)
|
||||
# Longest cut is always the one with lower start so the first
|
||||
# item so we need to break.
|
||||
break
|
||||
|
||||
# We have all the offsets now, we just need to do the actual splitting.
|
||||
# We need to eventually add the first part of the string and the eventual
|
||||
# last part.
|
||||
offsets.append(len(text))
|
||||
tokens = []
|
||||
start = 0
|
||||
for end in offsets:
|
||||
if start == end:
|
||||
# This might happen if there's a match at index 0
|
||||
# we're also preventing zero-width cuts in case of two
|
||||
# consecutive matches
|
||||
continue
|
||||
tokens.append(text[start:end])
|
||||
start = end
|
||||
|
||||
return tokens
|
||||
|
||||
|
||||
def _is_whitespace(char):
|
||||
"""Checks whether `char` is a whitespace character."""
|
||||
# \t, \n, and \r are technically control characters but we treat them
|
||||
# as whitespace since they are generally considered as such.
|
||||
if char == " " or char == "\t" or char == "\n" or char == "\r":
|
||||
return True
|
||||
cat = unicodedata.category(char)
|
||||
if cat == "Zs":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _is_control(char):
|
||||
"""Checks whether `char` is a control character."""
|
||||
# These are technically control characters but we count them as whitespace
|
||||
# characters.
|
||||
if char == "\t" or char == "\n" or char == "\r":
|
||||
return False
|
||||
cat = unicodedata.category(char)
|
||||
if cat.startswith("C"):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _is_punctuation(char):
|
||||
"""Checks whether `char` is a punctuation character."""
|
||||
cp = ord(char)
|
||||
# We treat all non-letter/number ASCII as punctuation.
|
||||
# Characters such as "^", "$", and "`" are not in the Unicode
|
||||
# Punctuation class but we treat them as punctuation anyways, for
|
||||
# consistency.
|
||||
if (cp >= 33 and cp <= 47) or (cp >= 58 and cp <= 64) or (cp >= 91 and cp <= 96) or (cp >= 123 and cp <= 126):
|
||||
return True
|
||||
cat = unicodedata.category(char)
|
||||
if cat.startswith("P"):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _is_end_of_word(text):
|
||||
"""Checks whether the last character in text is one of a punctuation, control or whitespace character."""
|
||||
last_char = text[-1]
|
||||
return bool(_is_control(last_char) | _is_punctuation(last_char) | _is_whitespace(last_char))
|
||||
|
||||
|
||||
def _is_start_of_word(text):
|
||||
"""Checks whether the first character in text is one of a punctuation, control or whitespace character."""
|
||||
first_char = text[0]
|
||||
return bool(_is_control(first_char) | _is_punctuation(first_char) | _is_whitespace(first_char))
|
||||
|
||||
|
||||
def _insert_one_token_to_ordered_list(token_list: List[str], new_token: str):
|
||||
"""
|
||||
Inserts one token to an ordered list if it does not already exist. Note: token_list must be sorted.
|
||||
"""
|
||||
insertion_idx = bisect.bisect_left(token_list, new_token)
|
||||
# Checks if new_token is already in the ordered token_list
|
||||
if insertion_idx < len(token_list) and token_list[insertion_idx] == new_token:
|
||||
# new_token is in token_list, don't add
|
||||
return
|
||||
else:
|
||||
token_list.insert(insertion_idx, new_token)
|
||||
|
||||
|
||||
@add_end_docstrings(INIT_TOKENIZER_DOCSTRING)
|
||||
class PreTrainedTokenizer(PreTrainedTokenizerBase):
|
||||
"""
|
||||
Base class for all slow tokenizers.
|
||||
|
||||
Inherits from :class:`~transformers.tokenization_utils_base.PreTrainedTokenizerBase`.
|
||||
|
||||
Handle all the shared methods for tokenization and special tokens as well as methods downloading/caching/loading
|
||||
pretrained tokenizers as well as adding tokens to the vocabulary.
|
||||
|
||||
This class also contain the added tokens in a unified way on top of all tokenizers so we don't have to handle the
|
||||
specific vocabulary augmentation methods of the various underlying dictionary structures (BPE, sentencepiece...).
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
# Added tokens - We store this for both slow and fast tokenizers
|
||||
# until the serialization of Fast tokenizers is updated
|
||||
self.added_tokens_encoder: Dict[str, int] = {}
|
||||
self.added_tokens_decoder: Dict[int, str] = {}
|
||||
self.unique_no_split_tokens: List[str] = []
|
||||
self.tokens_trie = Trie()
|
||||
|
||||
self._decode_use_source_tokenizer = False
|
||||
|
||||
@property
|
||||
def is_fast(self) -> bool:
|
||||
return False
|
||||
|
||||
@property
|
||||
def vocab_size(self) -> int:
|
||||
"""
|
||||
:obj:`int`: Size of the base vocabulary (without the added tokens).
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_added_vocab(self) -> Dict[str, int]:
|
||||
"""
|
||||
Returns the added tokens in the vocabulary as a dictionary of token to index.
|
||||
|
||||
Returns:
|
||||
:obj:`Dict[str, int]`: The added tokens.
|
||||
"""
|
||||
return self.added_tokens_encoder
|
||||
|
||||
def __len__(self):
|
||||
"""
|
||||
Size of the full vocabulary with the added tokens.
|
||||
"""
|
||||
return self.vocab_size + len(self.added_tokens_encoder)
|
||||
|
||||
def _add_tokens(self, new_tokens: Union[List[str], List[AddedToken]], special_tokens: bool = False) -> int:
|
||||
"""
|
||||
Add a list of new tokens to the tokenizer class. If the new tokens are not in the vocabulary, they are added to
|
||||
it with indices starting from length of the current vocabulary.
|
||||
|
||||
Args:
|
||||
new_tokens (:obj:`List[str]`or :obj:`List[tokenizers.AddedToken]`):
|
||||
Token(s) to add in vocabulary. A token is only added if it's not already in the vocabulary (tested by
|
||||
checking if the tokenizer assign the index of the ``unk_token`` to them).
|
||||
special_tokens (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not the tokens should be added as special tokens.
|
||||
|
||||
Returns:
|
||||
:obj:`int`: The number of tokens actually added to the vocabulary.
|
||||
|
||||
Examples::
|
||||
|
||||
# Let's see how to increase the vocabulary of Bert model and tokenizer
|
||||
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
|
||||
model = BertModel.from_pretrained('bert-base-uncased')
|
||||
|
||||
num_added_toks = tokenizer.add_tokens(['new_tok1', 'my_new-tok2'])
|
||||
print('We have added', num_added_toks, 'tokens')
|
||||
# Note: resize_token_embeddings expects to receive the full size of the new vocabulary, i.e. the length of the tokenizer.
|
||||
model.resize_token_embeddings(len(tokenizer))
|
||||
"""
|
||||
new_tokens = [str(tok) for tok in new_tokens]
|
||||
|
||||
tokens_to_add = []
|
||||
for token in new_tokens:
|
||||
if not isinstance(token, str):
|
||||
raise TypeError(f"Token {token} is not a string but a {type(token)}.")
|
||||
if not special_tokens and hasattr(self, "do_lower_case") and self.do_lower_case:
|
||||
token = token.lower()
|
||||
if (
|
||||
token != self.unk_token
|
||||
and self.convert_tokens_to_ids(token) == self.convert_tokens_to_ids(self.unk_token)
|
||||
and token not in tokens_to_add
|
||||
):
|
||||
tokens_to_add.append(token)
|
||||
if self.verbose:
|
||||
logger.info(f"Adding {token} to the vocabulary")
|
||||
|
||||
added_tok_encoder = dict((tok, len(self) + i) for i, tok in enumerate(tokens_to_add))
|
||||
added_tok_decoder = {v: k for k, v in added_tok_encoder.items()}
|
||||
self.added_tokens_encoder.update(added_tok_encoder)
|
||||
self.added_tokens_decoder.update(added_tok_decoder)
|
||||
|
||||
# Make sure we don't split on any special tokens (even they were already in the vocab before e.g. for Albert)
|
||||
if special_tokens:
|
||||
if len(new_tokens) == 1:
|
||||
_insert_one_token_to_ordered_list(self.unique_no_split_tokens, new_tokens[0])
|
||||
else:
|
||||
self.unique_no_split_tokens = sorted(set(self.unique_no_split_tokens).union(set(new_tokens)))
|
||||
else:
|
||||
# Or on the newly added tokens
|
||||
if len(tokens_to_add) == 1:
|
||||
_insert_one_token_to_ordered_list(self.unique_no_split_tokens, tokens_to_add[0])
|
||||
else:
|
||||
self.unique_no_split_tokens = sorted(set(self.unique_no_split_tokens).union(set(tokens_to_add)))
|
||||
self._create_trie(self.unique_no_split_tokens)
|
||||
|
||||
return len(tokens_to_add)
|
||||
|
||||
def _create_trie(self, unique_no_split_tokens):
|
||||
trie = Trie()
|
||||
for token in unique_no_split_tokens:
|
||||
if hasattr(self, "do_lower_case") and self.do_lower_case and token not in self.all_special_tokens:
|
||||
trie.add(token.lower())
|
||||
else:
|
||||
trie.add(token)
|
||||
self.tokens_trie = trie
|
||||
|
||||
def num_special_tokens_to_add(self, pair: bool = False) -> int:
|
||||
"""
|
||||
Returns the number of added tokens when encoding a sequence with special tokens.
|
||||
|
||||
.. note::
|
||||
This encodes a dummy input and checks the number of added tokens, and is therefore not efficient. Do not
|
||||
put this inside your training loop.
|
||||
|
||||
Args:
|
||||
pair (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether the number of added tokens should be computed in the case of a sequence pair or a single
|
||||
sequence.
|
||||
|
||||
Returns:
|
||||
:obj:`int`: Number of special tokens added to sequences.
|
||||
"""
|
||||
token_ids_0 = []
|
||||
token_ids_1 = []
|
||||
return len(self.build_inputs_with_special_tokens(token_ids_0, token_ids_1 if pair else None))
|
||||
|
||||
def tokenize(self, text: TextInput, **kwargs) -> List[str]:
|
||||
"""
|
||||
Converts a string in a sequence of tokens, using the tokenizer.
|
||||
|
||||
Split in words for word-based vocabulary or sub-words for sub-word-based vocabularies
|
||||
(BPE/SentencePieces/WordPieces). Takes care of added tokens.
|
||||
|
||||
Args:
|
||||
text (:obj:`str`):
|
||||
The sequence to be encoded.
|
||||
**kwargs (additional keyword arguments):
|
||||
Passed along to the model-specific ``prepare_for_tokenization`` preprocessing method.
|
||||
|
||||
Returns:
|
||||
:obj:`List[str]`: The list of tokens.
|
||||
"""
|
||||
# Simple mapping string => AddedToken for special tokens with specific tokenization behaviors
|
||||
all_special_tokens_extended = dict(
|
||||
(str(t), t) for t in self.all_special_tokens_extended if isinstance(t, AddedToken)
|
||||
)
|
||||
|
||||
text, kwargs = self.prepare_for_tokenization(text, **kwargs)
|
||||
|
||||
if kwargs:
|
||||
logger.warning(f"Keyword arguments {kwargs} not recognized.")
|
||||
|
||||
# TODO: should this be in the base class?
|
||||
if hasattr(self, "do_lower_case") and self.do_lower_case:
|
||||
# convert non-special tokens to lowercase
|
||||
escaped_special_toks = [
|
||||
re.escape(s_tok) for s_tok in (self.unique_no_split_tokens + self.all_special_tokens)
|
||||
]
|
||||
pattern = r"(" + r"|".join(escaped_special_toks) + r")|" + r"(.+?)"
|
||||
text = re.sub(pattern, lambda m: m.groups()[0] or m.groups()[1].lower(), text)
|
||||
|
||||
no_split_token = set(self.unique_no_split_tokens)
|
||||
tokens = self.tokens_trie.split(text)
|
||||
# ["This is something", "<special_token_1>", " else"]
|
||||
for i, token in enumerate(tokens):
|
||||
if token in no_split_token:
|
||||
tok_extended = all_special_tokens_extended.get(token, None)
|
||||
left = tokens[i - 1] if i > 0 else None
|
||||
right = tokens[i + 1] if i < len(tokens) - 1 else None
|
||||
if isinstance(tok_extended, AddedToken):
|
||||
if tok_extended.rstrip and right:
|
||||
# A bit counter-intuitive but we strip the left of the string
|
||||
# since tok_extended.rstrip means the special token is eating all white spaces on its right
|
||||
tokens[i + 1] = right.lstrip()
|
||||
# Strip white spaces on the left
|
||||
if tok_extended.lstrip and left:
|
||||
tokens[i - 1] = left.rstrip() # Opposite here
|
||||
else:
|
||||
# We strip left and right by default
|
||||
if right:
|
||||
tokens[i + 1] = right.lstrip()
|
||||
if left:
|
||||
tokens[i - 1] = left.rstrip()
|
||||
# ["This is something", "<special_token_1>", "else"]
|
||||
tokenized_text = []
|
||||
for token in tokens:
|
||||
# Need to skip eventual empty (fully stripped) tokens
|
||||
if not token:
|
||||
continue
|
||||
if token in no_split_token:
|
||||
tokenized_text.append(token)
|
||||
else:
|
||||
tokenized_text.extend(self._tokenize(token))
|
||||
# ["This", " is", " something", "<special_token_1>", "else"]
|
||||
return tokenized_text
|
||||
|
||||
def _tokenize(self, text, **kwargs):
|
||||
"""
|
||||
Converts a string in a sequence of tokens (string), using the tokenizer. Split in words for word-based
|
||||
vocabulary or sub-words for sub-word-based vocabularies (BPE/SentencePieces/WordPieces).
|
||||
|
||||
Do NOT take care of added tokens.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def convert_tokens_to_ids(self, tokens: Union[str, List[str]]) -> Union[int, List[int]]:
|
||||
"""
|
||||
Converts a token string (or a sequence of tokens) in a single integer id (or a sequence of ids), using the
|
||||
vocabulary.
|
||||
|
||||
Args:
|
||||
tokens (:obj:`str` or :obj:`List[str]`): One or several token(s) to convert to token id(s).
|
||||
|
||||
Returns:
|
||||
:obj:`int` or :obj:`List[int]`: The token id or list of token ids.
|
||||
"""
|
||||
if tokens is None:
|
||||
return None
|
||||
|
||||
if isinstance(tokens, str):
|
||||
return self._convert_token_to_id_with_added_voc(tokens)
|
||||
|
||||
ids = []
|
||||
for token in tokens:
|
||||
ids.append(self._convert_token_to_id_with_added_voc(token))
|
||||
return ids
|
||||
|
||||
def _convert_token_to_id_with_added_voc(self, token):
|
||||
if token is None:
|
||||
return None
|
||||
|
||||
if token in self.added_tokens_encoder:
|
||||
return self.added_tokens_encoder[token]
|
||||
return self._convert_token_to_id(token)
|
||||
|
||||
def _convert_token_to_id(self, token):
|
||||
raise NotImplementedError
|
||||
|
||||
def _encode_plus(
|
||||
self,
|
||||
text: Union[TextInput, PreTokenizedInput, EncodedInput],
|
||||
text_pair: Optional[Union[TextInput, PreTokenizedInput, EncodedInput]] = None,
|
||||
add_special_tokens: bool = True,
|
||||
padding_strategy: PaddingStrategy = PaddingStrategy.DO_NOT_PAD,
|
||||
truncation_strategy: TruncationStrategy = TruncationStrategy.DO_NOT_TRUNCATE,
|
||||
max_length: Optional[int] = None,
|
||||
stride: int = 0,
|
||||
is_split_into_words: bool = False,
|
||||
pad_to_multiple_of: Optional[int] = None,
|
||||
return_tensors: Optional[Union[str, TensorType]] = None,
|
||||
return_token_type_ids: Optional[bool] = None,
|
||||
return_attention_mask: Optional[bool] = None,
|
||||
return_overflowing_tokens: bool = False,
|
||||
return_special_tokens_mask: bool = False,
|
||||
return_offsets_mapping: bool = False,
|
||||
return_length: bool = False,
|
||||
verbose: bool = True,
|
||||
**kwargs
|
||||
) -> BatchEncoding:
|
||||
def get_input_ids(text):
|
||||
if isinstance(text, str):
|
||||
tokens = self.tokenize(text, **kwargs)
|
||||
return self.convert_tokens_to_ids(tokens)
|
||||
elif isinstance(text, (list, tuple)) and len(text) > 0 and isinstance(text[0], str):
|
||||
if is_split_into_words:
|
||||
tokens = list(
|
||||
itertools.chain(*(self.tokenize(t, is_split_into_words=True, **kwargs) for t in text))
|
||||
)
|
||||
return self.convert_tokens_to_ids(tokens)
|
||||
else:
|
||||
return self.convert_tokens_to_ids(text)
|
||||
elif isinstance(text, (list, tuple)) and len(text) > 0 and isinstance(text[0], int):
|
||||
return text
|
||||
else:
|
||||
if is_split_into_words:
|
||||
raise ValueError(
|
||||
f"Input {text} is not valid. Should be a string or a list/tuple of strings when `is_split_into_words=True`."
|
||||
)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Input {text} is not valid. Should be a string, a list/tuple of strings or a list/tuple of integers."
|
||||
)
|
||||
|
||||
if return_offsets_mapping:
|
||||
raise NotImplementedError(
|
||||
"return_offset_mapping is not available when using Python tokenizers."
|
||||
"To use this feature, change your tokenizer to one deriving from "
|
||||
"transformers.PreTrainedTokenizerFast."
|
||||
"More information on available tokenizers at "
|
||||
"https://github.com/huggingface/transformers/pull/2674"
|
||||
)
|
||||
|
||||
first_ids = get_input_ids(text)
|
||||
second_ids = get_input_ids(text_pair) if text_pair is not None else None
|
||||
|
||||
return self.prepare_for_model(
|
||||
first_ids,
|
||||
pair_ids=second_ids,
|
||||
add_special_tokens=add_special_tokens,
|
||||
padding=padding_strategy.value,
|
||||
truncation=truncation_strategy.value,
|
||||
max_length=max_length,
|
||||
stride=stride,
|
||||
pad_to_multiple_of=pad_to_multiple_of,
|
||||
return_tensors=return_tensors,
|
||||
prepend_batch_axis=True,
|
||||
return_attention_mask=return_attention_mask,
|
||||
return_token_type_ids=return_token_type_ids,
|
||||
return_overflowing_tokens=return_overflowing_tokens,
|
||||
return_special_tokens_mask=return_special_tokens_mask,
|
||||
return_length=return_length,
|
||||
verbose=verbose,
|
||||
)
|
||||
|
||||
def _batch_encode_plus(
|
||||
self,
|
||||
batch_text_or_text_pairs: Union[
|
||||
List[TextInput],
|
||||
List[TextInputPair],
|
||||
List[PreTokenizedInput],
|
||||
List[PreTokenizedInputPair],
|
||||
List[EncodedInput],
|
||||
List[EncodedInputPair],
|
||||
],
|
||||
add_special_tokens: bool = True,
|
||||
padding_strategy: PaddingStrategy = PaddingStrategy.DO_NOT_PAD,
|
||||
truncation_strategy: TruncationStrategy = TruncationStrategy.DO_NOT_TRUNCATE,
|
||||
max_length: Optional[int] = None,
|
||||
stride: int = 0,
|
||||
is_split_into_words: bool = False,
|
||||
pad_to_multiple_of: Optional[int] = None,
|
||||
return_tensors: Optional[Union[str, TensorType]] = None,
|
||||
return_token_type_ids: Optional[bool] = None,
|
||||
return_attention_mask: Optional[bool] = None,
|
||||
return_overflowing_tokens: bool = False,
|
||||
return_special_tokens_mask: bool = False,
|
||||
return_offsets_mapping: bool = False,
|
||||
return_length: bool = False,
|
||||
verbose: bool = True,
|
||||
**kwargs
|
||||
) -> BatchEncoding:
|
||||
def get_input_ids(text):
|
||||
if isinstance(text, str):
|
||||
tokens = self.tokenize(text, **kwargs)
|
||||
return self.convert_tokens_to_ids(tokens)
|
||||
elif isinstance(text, (list, tuple)) and len(text) > 0 and isinstance(text[0], str):
|
||||
if is_split_into_words:
|
||||
tokens = list(
|
||||
itertools.chain(*(self.tokenize(t, is_split_into_words=True, **kwargs) for t in text))
|
||||
)
|
||||
return self.convert_tokens_to_ids(tokens)
|
||||
else:
|
||||
return self.convert_tokens_to_ids(text)
|
||||
elif isinstance(text, (list, tuple)) and len(text) > 0 and isinstance(text[0], int):
|
||||
return text
|
||||
else:
|
||||
raise ValueError(
|
||||
"Input is not valid. Should be a string, a list/tuple of strings or a list/tuple of integers."
|
||||
)
|
||||
|
||||
if return_offsets_mapping:
|
||||
raise NotImplementedError(
|
||||
"return_offset_mapping is not available when using Python tokenizers."
|
||||
"To use this feature, change your tokenizer to one deriving from "
|
||||
"transformers.PreTrainedTokenizerFast."
|
||||
)
|
||||
|
||||
input_ids = []
|
||||
for ids_or_pair_ids in batch_text_or_text_pairs:
|
||||
if not isinstance(ids_or_pair_ids, (list, tuple)):
|
||||
ids, pair_ids = ids_or_pair_ids, None
|
||||
elif is_split_into_words and not isinstance(ids_or_pair_ids[0], (list, tuple)):
|
||||
ids, pair_ids = ids_or_pair_ids, None
|
||||
else:
|
||||
ids, pair_ids = ids_or_pair_ids
|
||||
|
||||
first_ids = get_input_ids(ids)
|
||||
second_ids = get_input_ids(pair_ids) if pair_ids is not None else None
|
||||
input_ids.append((first_ids, second_ids))
|
||||
|
||||
batch_outputs = self._batch_prepare_for_model(
|
||||
input_ids,
|
||||
add_special_tokens=add_special_tokens,
|
||||
padding_strategy=padding_strategy,
|
||||
truncation_strategy=truncation_strategy,
|
||||
max_length=max_length,
|
||||
stride=stride,
|
||||
pad_to_multiple_of=pad_to_multiple_of,
|
||||
return_attention_mask=return_attention_mask,
|
||||
return_token_type_ids=return_token_type_ids,
|
||||
return_overflowing_tokens=return_overflowing_tokens,
|
||||
return_special_tokens_mask=return_special_tokens_mask,
|
||||
return_length=return_length,
|
||||
return_tensors=return_tensors,
|
||||
verbose=verbose,
|
||||
)
|
||||
|
||||
return BatchEncoding(batch_outputs)
|
||||
|
||||
@add_end_docstrings(ENCODE_KWARGS_DOCSTRING, ENCODE_PLUS_ADDITIONAL_KWARGS_DOCSTRING)
|
||||
def _batch_prepare_for_model(
|
||||
self,
|
||||
batch_ids_pairs: List[Union[PreTokenizedInputPair, Tuple[List[int], None]]],
|
||||
add_special_tokens: bool = True,
|
||||
padding_strategy: PaddingStrategy = PaddingStrategy.DO_NOT_PAD,
|
||||
truncation_strategy: TruncationStrategy = TruncationStrategy.DO_NOT_TRUNCATE,
|
||||
max_length: Optional[int] = None,
|
||||
stride: int = 0,
|
||||
pad_to_multiple_of: Optional[int] = None,
|
||||
return_tensors: Optional[str] = None,
|
||||
return_token_type_ids: Optional[bool] = None,
|
||||
return_attention_mask: Optional[bool] = None,
|
||||
return_overflowing_tokens: bool = False,
|
||||
return_special_tokens_mask: bool = False,
|
||||
return_length: bool = False,
|
||||
verbose: bool = True,
|
||||
) -> BatchEncoding:
|
||||
"""
|
||||
Prepares a sequence of input id, or a pair of sequences of inputs ids so that it can be used by the model. It
|
||||
adds special tokens, truncates sequences if overflowing while taking into account the special tokens and
|
||||
manages a moving window (with user defined stride) for overflowing tokens
|
||||
|
||||
Args:
|
||||
batch_ids_pairs: list of tokenized input ids or input ids pairs
|
||||
"""
|
||||
|
||||
batch_outputs = {}
|
||||
for first_ids, second_ids in batch_ids_pairs:
|
||||
outputs = self.prepare_for_model(
|
||||
first_ids,
|
||||
second_ids,
|
||||
add_special_tokens=add_special_tokens,
|
||||
padding=PaddingStrategy.DO_NOT_PAD.value, # we pad in batch afterward
|
||||
truncation=truncation_strategy.value,
|
||||
max_length=max_length,
|
||||
stride=stride,
|
||||
pad_to_multiple_of=None, # we pad in batch afterward
|
||||
return_attention_mask=False, # we pad in batch afterward
|
||||
return_token_type_ids=return_token_type_ids,
|
||||
return_overflowing_tokens=return_overflowing_tokens,
|
||||
return_special_tokens_mask=return_special_tokens_mask,
|
||||
return_length=return_length,
|
||||
return_tensors=None, # We convert the whole batch to tensors at the end
|
||||
prepend_batch_axis=False,
|
||||
verbose=verbose,
|
||||
)
|
||||
|
||||
for key, value in outputs.items():
|
||||
if key not in batch_outputs:
|
||||
batch_outputs[key] = []
|
||||
batch_outputs[key].append(value)
|
||||
|
||||
batch_outputs = self.pad(
|
||||
batch_outputs,
|
||||
padding=padding_strategy.value,
|
||||
max_length=max_length,
|
||||
pad_to_multiple_of=pad_to_multiple_of,
|
||||
return_attention_mask=return_attention_mask,
|
||||
)
|
||||
|
||||
batch_outputs = BatchEncoding(batch_outputs, tensor_type=return_tensors)
|
||||
|
||||
return batch_outputs
|
||||
|
||||
def prepare_for_tokenization(
|
||||
self, text: str, is_split_into_words: bool = False, **kwargs
|
||||
) -> Tuple[str, Dict[str, Any]]:
|
||||
"""
|
||||
Performs any necessary transformations before tokenization.
|
||||
|
||||
This method should pop the arguments from kwargs and return the remaining :obj:`kwargs` as well. We test the
|
||||
:obj:`kwargs` at the end of the encoding process to be sure all the arguments have been used.
|
||||
|
||||
Args:
|
||||
text (:obj:`str`):
|
||||
The text to prepare.
|
||||
is_split_into_words (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not the input is already pre-tokenized (e.g., split into words). If set to :obj:`True`, the
|
||||
tokenizer assumes the input is already split into words (for instance, by splitting it on whitespace)
|
||||
which it will tokenize. This is useful for NER or token classification.
|
||||
kwargs:
|
||||
Keyword arguments to use for the tokenization.
|
||||
|
||||
Returns:
|
||||
:obj:`Tuple[str, Dict[str, Any]]`: The prepared text and the unused kwargs.
|
||||
"""
|
||||
return (text, kwargs)
|
||||
|
||||
def get_special_tokens_mask(
|
||||
self, token_ids_0: List, token_ids_1: Optional[List] = None, already_has_special_tokens: bool = False
|
||||
) -> List[int]:
|
||||
"""
|
||||
Retrieves sequence ids from a token list that has no special tokens added. This method is called when adding
|
||||
special tokens using the tokenizer ``prepare_for_model`` or ``encode_plus`` methods.
|
||||
|
||||
Args:
|
||||
token_ids_0 (:obj:`List[int]`):
|
||||
List of ids of the first sequence.
|
||||
token_ids_1 (:obj:`List[int]`, `optional`):
|
||||
List of ids of the second sequence.
|
||||
already_has_special_tokens (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not the token list is already formatted with special tokens for the model.
|
||||
|
||||
Returns:
|
||||
A list of integers in the range [0, 1]: 1 for a special token, 0 for a sequence token.
|
||||
"""
|
||||
if already_has_special_tokens:
|
||||
if token_ids_1 is not None:
|
||||
raise ValueError(
|
||||
"You should not supply a second sequence if the provided sequence of "
|
||||
"ids is already formatted with special tokens for the model."
|
||||
)
|
||||
|
||||
return super().get_special_tokens_mask(
|
||||
token_ids_0=token_ids_0, token_ids_1=token_ids_1, already_has_special_tokens=True
|
||||
)
|
||||
return [0] * ((len(token_ids_1) if token_ids_1 else 0) + len(token_ids_0))
|
||||
|
||||
@overload
|
||||
def convert_ids_to_tokens(self, ids: int, skip_special_tokens: bool = False) -> str:
|
||||
...
|
||||
|
||||
@overload
|
||||
def convert_ids_to_tokens(self, ids: List[int], skip_special_tokens: bool = False) -> List[str]:
|
||||
...
|
||||
|
||||
def convert_ids_to_tokens(
|
||||
self, ids: Union[int, List[int]], skip_special_tokens: bool = False
|
||||
) -> Union[str, List[str]]:
|
||||
"""
|
||||
Converts a single index or a sequence of indices in a token or a sequence of tokens, using the vocabulary and
|
||||
added tokens.
|
||||
|
||||
Args:
|
||||
ids (:obj:`int` or :obj:`List[int]`):
|
||||
The token id (or token ids) to convert to tokens.
|
||||
skip_special_tokens (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to remove special tokens in the decoding.
|
||||
|
||||
Returns:
|
||||
:obj:`str` or :obj:`List[str]`: The decoded token(s).
|
||||
"""
|
||||
if isinstance(ids, int):
|
||||
if ids in self.added_tokens_decoder:
|
||||
return self.added_tokens_decoder[ids]
|
||||
else:
|
||||
return self._convert_id_to_token(ids)
|
||||
tokens = []
|
||||
for index in ids:
|
||||
index = int(index)
|
||||
if skip_special_tokens and index in self.all_special_ids:
|
||||
continue
|
||||
if index in self.added_tokens_decoder:
|
||||
tokens.append(self.added_tokens_decoder[index])
|
||||
else:
|
||||
tokens.append(self._convert_id_to_token(index))
|
||||
return tokens
|
||||
|
||||
def _convert_id_to_token(self, index: int) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
def convert_tokens_to_string(self, tokens: List[str]) -> str:
|
||||
return " ".join(tokens)
|
||||
|
||||
def _decode(
|
||||
self,
|
||||
token_ids: List[int],
|
||||
skip_special_tokens: bool = False,
|
||||
clean_up_tokenization_spaces: bool = True,
|
||||
spaces_between_special_tokens: bool = True,
|
||||
**kwargs
|
||||
) -> str:
|
||||
self._decode_use_source_tokenizer = kwargs.pop("use_source_tokenizer", False)
|
||||
|
||||
filtered_tokens = self.convert_ids_to_tokens(token_ids, skip_special_tokens=skip_special_tokens)
|
||||
|
||||
# To avoid mixing byte-level and unicode for byte-level BPT
|
||||
# we need to build string separately for added tokens and byte-level tokens
|
||||
# cf. https://github.com/huggingface/transformers/issues/1133
|
||||
sub_texts = []
|
||||
current_sub_text = []
|
||||
for token in filtered_tokens:
|
||||
if skip_special_tokens and token in self.all_special_ids:
|
||||
continue
|
||||
if token in self.added_tokens_encoder:
|
||||
if current_sub_text:
|
||||
sub_texts.append(self.convert_tokens_to_string(current_sub_text))
|
||||
current_sub_text = []
|
||||
sub_texts.append(token)
|
||||
else:
|
||||
current_sub_text.append(token)
|
||||
if current_sub_text:
|
||||
sub_texts.append(self.convert_tokens_to_string(current_sub_text))
|
||||
|
||||
if spaces_between_special_tokens:
|
||||
text = " ".join(sub_texts)
|
||||
else:
|
||||
text = "".join(sub_texts)
|
||||
|
||||
if clean_up_tokenization_spaces:
|
||||
clean_text = self.clean_up_tokenization(text)
|
||||
return clean_text
|
||||
else:
|
||||
return text
|
3351
fastNLP/transformers/torch/tokenization_utils_base.py
Normal file
3351
fastNLP/transformers/torch/tokenization_utils_base.py
Normal file
File diff suppressed because it is too large
Load Diff
0
fastNLP/transformers/torch/utils/__init__.py
Normal file
0
fastNLP/transformers/torch/utils/__init__.py
Normal file
54
fastNLP/transformers/torch/utils/model_parallel_utils.py
Normal file
54
fastNLP/transformers/torch/utils/model_parallel_utils.py
Normal file
@ -0,0 +1,54 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from math import ceil
|
||||
|
||||
|
||||
def assert_device_map(device_map, num_blocks):
|
||||
blocks = list(range(0, num_blocks))
|
||||
|
||||
device_map_blocks = [item for sublist in list(device_map.values()) for item in sublist]
|
||||
|
||||
# Duplicate check
|
||||
duplicate_blocks = []
|
||||
for i in device_map_blocks:
|
||||
if device_map_blocks.count(i) > 1 and i not in duplicate_blocks:
|
||||
duplicate_blocks.append(i)
|
||||
# Missing blocks
|
||||
missing_blocks = [i for i in blocks if i not in device_map_blocks]
|
||||
extra_blocks = [i for i in device_map_blocks if i not in blocks]
|
||||
|
||||
assert len(duplicate_blocks) == 0, (
|
||||
"Duplicate attention blocks specified in device_map. Attention blocks must be specified to one device. These "
|
||||
"attention blocks were specified more than once: " + str(duplicate_blocks)
|
||||
)
|
||||
assert len(missing_blocks) == 0, (
|
||||
"There are attention blocks for this model that are not specified in the device_map. Add these attention "
|
||||
"blocks to a device on the device_map: " + str(missing_blocks)
|
||||
)
|
||||
assert (
|
||||
len(extra_blocks) == 0
|
||||
), "The device_map contains more attention blocks than this model has. Remove these from the device_map:" + str(
|
||||
extra_blocks
|
||||
)
|
||||
|
||||
|
||||
def get_device_map(n_layers, devices):
|
||||
"""Returns a dictionary of layers distributed evenly across all devices."""
|
||||
layers = list(range(n_layers))
|
||||
n_blocks = int(ceil(n_layers / len(devices)))
|
||||
layers_list = list(layers[i : i + n_blocks] for i in range(0, n_layers, n_blocks))
|
||||
|
||||
return dict(zip(devices, layers_list))
|
120
fastNLP/transformers/torch/utils/versions.py
Normal file
120
fastNLP/transformers/torch/utils/versions.py
Normal file
@ -0,0 +1,120 @@
|
||||
# Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
Utilities for working with package versions
|
||||
"""
|
||||
|
||||
import operator
|
||||
import re
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
from packaging import version
|
||||
|
||||
|
||||
# The package importlib_metadata is in a different place, depending on the python version.
|
||||
if sys.version_info < (3, 8):
|
||||
import importlib_metadata
|
||||
else:
|
||||
import importlib.metadata as importlib_metadata
|
||||
|
||||
|
||||
ops = {
|
||||
"<": operator.lt,
|
||||
"<=": operator.le,
|
||||
"==": operator.eq,
|
||||
"!=": operator.ne,
|
||||
">=": operator.ge,
|
||||
">": operator.gt,
|
||||
}
|
||||
|
||||
|
||||
def _compare_versions(op, got_ver, want_ver, requirement, pkg, hint):
|
||||
if got_ver is None:
|
||||
raise ValueError("got_ver is None")
|
||||
if want_ver is None:
|
||||
raise ValueError("want_ver is None")
|
||||
if not ops[op](version.parse(got_ver), version.parse(want_ver)):
|
||||
raise ImportError(
|
||||
f"{requirement} is required for a normal functioning of this module, but found {pkg}=={got_ver}.{hint}"
|
||||
)
|
||||
|
||||
|
||||
def require_version(requirement: str, hint: Optional[str] = None) -> None:
|
||||
"""
|
||||
Perform a runtime check of the dependency versions, using the exact same syntax used by pip.
|
||||
|
||||
The installed module version comes from the `site-packages` dir via `importlib_metadata`.
|
||||
|
||||
Args:
|
||||
requirement (:obj:`str`): pip style definition, e.g., "tokenizers==0.9.4", "tqdm>=4.27", "numpy"
|
||||
hint (:obj:`str`, `optional`): what suggestion to print in case of requirements not being met
|
||||
|
||||
Example::
|
||||
|
||||
require_version("pandas>1.1.2")
|
||||
require_version("numpy>1.18.5", "this is important to have for whatever reason")
|
||||
|
||||
"""
|
||||
|
||||
hint = f"\n{hint}" if hint is not None else ""
|
||||
|
||||
# non-versioned check
|
||||
if re.match(r"^[\w_\-\d]+$", requirement):
|
||||
pkg, op, want_ver = requirement, None, None
|
||||
else:
|
||||
match = re.findall(r"^([^!=<>\s]+)([\s!=<>]{1,2}.+)", requirement)
|
||||
if not match:
|
||||
raise ValueError(
|
||||
f"requirement needs to be in the pip package format, .e.g., package_a==1.23, or package_b>=1.23, but got {requirement}"
|
||||
)
|
||||
pkg, want_full = match[0]
|
||||
want_range = want_full.split(",") # there could be multiple requirements
|
||||
wanted = {}
|
||||
for w in want_range:
|
||||
match = re.findall(r"^([\s!=<>]{1,2})(.+)", w)
|
||||
if not match:
|
||||
raise ValueError(
|
||||
f"requirement needs to be in the pip package format, .e.g., package_a==1.23, or package_b>=1.23, but got {requirement}"
|
||||
)
|
||||
op, want_ver = match[0]
|
||||
wanted[op] = want_ver
|
||||
if op not in ops:
|
||||
raise ValueError(f"{requirement}: need one of {list(ops.keys())}, but got {op}")
|
||||
|
||||
# special case
|
||||
if pkg == "python":
|
||||
got_ver = ".".join([str(x) for x in sys.version_info[:3]])
|
||||
for op, want_ver in wanted.items():
|
||||
_compare_versions(op, got_ver, want_ver, requirement, pkg, hint)
|
||||
return
|
||||
|
||||
# check if any version is installed
|
||||
try:
|
||||
got_ver = importlib_metadata.version(pkg)
|
||||
except importlib_metadata.PackageNotFoundError:
|
||||
raise importlib_metadata.PackageNotFoundError(
|
||||
f"The '{requirement}' distribution was not found and is required by this application. {hint}"
|
||||
)
|
||||
|
||||
# check that the right version is installed if version number or a range was provided
|
||||
if want_ver is not None:
|
||||
for op, want_ver in wanted.items():
|
||||
_compare_versions(op, got_ver, want_ver, requirement, pkg, hint)
|
||||
|
||||
|
||||
def require_version_core(requirement):
|
||||
"""require_version wrapper which emits a core-specific hint on failure"""
|
||||
hint = "Try: pip install transformers -U or pip install -e '.[dev]' if you're working with git master"
|
||||
return require_version(requirement, hint)
|
Loading…
Reference in New Issue
Block a user