Compare commits
52
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4114a96831 | ||
|
|
fa6a4414bb | ||
|
|
1b073be34e | ||
|
|
4abf78f2b1 | ||
|
|
bf5819f6f4 | ||
|
|
8fd0275066 | ||
|
|
daf2a4a37e | ||
|
|
8202330d24 | ||
|
|
995c47b1fe | ||
|
|
e36a51ed58 | ||
|
|
d0be398f50 | ||
|
|
896f8aaefc | ||
|
|
520b558a6a | ||
|
|
4ee2f6f4d8 | ||
|
|
0ca151b168 | ||
|
|
6fc3849dce | ||
|
|
ba4c3a9a07 | ||
|
|
342db2aaf6 | ||
|
|
1108ec9bfd | ||
|
|
7968051aba | ||
|
|
2977bd528f | ||
|
|
2d6e2ad4fa | ||
|
|
7e73c12805 | ||
|
|
8cb4ecca25 | ||
|
|
52f7d74398 | ||
|
|
82b09a8481 | ||
|
|
2d4e928d97 | ||
|
|
dcba9ee03b | ||
|
|
f34b4cd1bd | ||
|
|
9c2b2db2cd | ||
|
|
aacac8f708 | ||
|
|
1f1d950b28 | ||
|
|
d9ffb87efb | ||
|
|
d6175a4268 | ||
|
|
1d5ea34f6a | ||
|
|
f176e70723 | ||
|
|
34fcfb44e3 | ||
|
|
2f34bcf3e7 | ||
|
|
13c1857718 | ||
|
|
83086858f8 | ||
|
|
03ec02a667 | ||
|
|
827c519494 | ||
|
|
ba4bbd92bc | ||
|
|
26d5475d4b | ||
|
|
c6e18de9f8 | ||
|
|
2c9e83f7b8 | ||
|
|
9618cd6964 | ||
|
|
4dcc424de3 | ||
|
|
a3cea6a8cc | ||
|
|
0af53b1ef9 | ||
|
|
b0f05e0c4c | ||
|
|
bc00b37a0d |
@@ -37,25 +37,27 @@ members/contributors which may be interested in your PR.
|
||||
If you know how to use git blame, that is the easiest way, otherwise, here is a rough guide of **who to tag**.
|
||||
Please tag fewer than 3 people.
|
||||
|
||||
albert, bert, GPT2, XLM: @LysandreJik
|
||||
albert, bert, XLM: @LysandreJik
|
||||
GPT2: @LysandreJik, @patrickvonplaten
|
||||
tokenizers: @mfuntowicz
|
||||
Trainer: @sgugger
|
||||
Speed and Memory Benchmarks: @patrickvonplaten
|
||||
Benchmarks: @patrickvonplaten
|
||||
Model Cards: @julien-c
|
||||
Translation: @sshleifer
|
||||
Summarization: @sshleifer
|
||||
TextGeneration: @TevenLeScao
|
||||
examples/distillation: @VictorSanh
|
||||
nlp datasets: [different repo](https://github.com/huggingface/nlp)
|
||||
rust tokenizers: [different repo](https://github.com/huggingface/tokenizers)
|
||||
Text Generation: @TevenLeScao
|
||||
Text Generation: @patrickvonplaten, @TevenLeScao
|
||||
Blenderbot, Bart, Marian, Pegasus: @sshleifer
|
||||
T5: @patrickvonplaten
|
||||
Longformer/Reformer: @patrickvonplaten
|
||||
TransfoXL/XLNet: @TevenLeScao
|
||||
Rag: @patrickvonplaten, @lhoestq
|
||||
EncoderDecoder: @patrickvonplaten
|
||||
Longformer, Reformer: @patrickvonplaten
|
||||
TransfoXL, XLNet: @TevenLeScao, @patrickvonplaten
|
||||
examples/seq2seq: @sshleifer
|
||||
examples/bert-loses-patience: @JetRunner
|
||||
tensorflow: @jplu
|
||||
examples/token-classification: @stefan-it
|
||||
documentation: @sgugger
|
||||
-->
|
||||
-->
|
||||
|
||||
@@ -12,6 +12,7 @@ __pycache__/
|
||||
tests/fixtures
|
||||
logs/
|
||||
lightning_logs/
|
||||
lang_code_data/
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
|
||||
@@ -12,7 +12,7 @@ subclass :class:`~transformers.Trainer` and override the methods you need (see :
|
||||
|
||||
By default a :class:`~transformers.Trainer` will use the following callbacks:
|
||||
|
||||
- :class:`~transformers.DefaultFlowCallback` which handles the default beahvior for logging, saving and evaluation.
|
||||
- :class:`~transformers.DefaultFlowCallback` which handles the default behavior for logging, saving and evaluation.
|
||||
- :class:`~transformers.PrinterCallback` or :class:`~transformers.ProrgressCallback` to display progress and print the
|
||||
logs (the first one is used if you deactivate tqdm through the :class:`~transformers.TrainingArguments`, otherwise
|
||||
it's the second one).
|
||||
|
||||
@@ -15,7 +15,7 @@ Both :class:`~transformers.Trainer` and :class:`~transformers.TFTrainer` contain
|
||||
previous features. To inject custom behavior you can subclass them and override the following methods:
|
||||
|
||||
- **get_train_dataloader**/**get_train_tfdataset** -- Creates the training DataLoader (PyTorch) or TF Dataset.
|
||||
- **get_eval_dataloader**/**get_eval_tfdataset** -- Creates the evaulation DataLoader (PyTorch) or TF Dataset.
|
||||
- **get_eval_dataloader**/**get_eval_tfdataset** -- Creates the evaluation DataLoader (PyTorch) or TF Dataset.
|
||||
- **get_test_dataloader**/**get_test_tfdataset** -- Creates the test DataLoader (PyTorch) or TF Dataset.
|
||||
- **log** -- Logs information on the various objects watching training.
|
||||
- **create_optimizer_and_scheduler** -- Setups the optimizer and learning rate scheduler if they were not passed at
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Blenderbot
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
**DISCLAIMER:** If you see something strange,
|
||||
file a `Github Issue <https://github.com/huggingface/transformers/issues/new?assignees=&labels=&template=bug-report.md&title>`__ .
|
||||
|
||||
|
||||
@@ -104,6 +104,13 @@ OpenAIGPTDoubleHeadsModel
|
||||
:members: forward
|
||||
|
||||
|
||||
OpenAIGPTForSequenceClassification
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.OpenAIGPTForSequenceClassification
|
||||
:members: forward
|
||||
|
||||
|
||||
TFOpenAIGPTModel
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ The library is built around three types of classes for each model:
|
||||
All these classes can be instantiated from pretrained instances and saved locally using two methods:
|
||||
|
||||
- :obj:`from_pretrained()` lets you instantiate a model/configuration/tokenizer from a pretrained version either
|
||||
provided by the library itself (the suported models are provided in the list :doc:`here <pretrained_models>`
|
||||
provided by the library itself (the supported models are provided in the list :doc:`here <pretrained_models>`
|
||||
or stored locally (or on a server) by the user,
|
||||
- :obj:`save_pretrained()` lets you save a model/configuration/tokenizer locally so that it can be reloaded using
|
||||
:obj:`from_pretrained()`.
|
||||
|
||||
@@ -24,8 +24,11 @@ import logging
|
||||
import math
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
from glob import glob
|
||||
from typing import Optional
|
||||
|
||||
from torch.utils.data import ConcatDataset
|
||||
|
||||
from transformers import (
|
||||
CONFIG_MAPPING,
|
||||
MODEL_WITH_LM_HEAD_MAPPING,
|
||||
@@ -87,6 +90,13 @@ class DataTrainingArguments:
|
||||
train_data_file: Optional[str] = field(
|
||||
default=None, metadata={"help": "The input training data file (a text file)."}
|
||||
)
|
||||
train_data_files: Optional[str] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"help": "The input training data files (multiple files in glob format). "
|
||||
"Very often splitting large files to smaller files can prevent tokenizer going out of memory"
|
||||
},
|
||||
)
|
||||
eval_data_file: Optional[str] = field(
|
||||
default=None,
|
||||
metadata={"help": "An optional input evaluation data file to evaluate the perplexity on (a text file)."},
|
||||
@@ -131,17 +141,24 @@ def get_dataset(
|
||||
evaluate: bool = False,
|
||||
cache_dir: Optional[str] = None,
|
||||
):
|
||||
file_path = args.eval_data_file if evaluate else args.train_data_file
|
||||
if args.line_by_line:
|
||||
return LineByLineTextDataset(tokenizer=tokenizer, file_path=file_path, block_size=args.block_size)
|
||||
def _dataset(file_path):
|
||||
if args.line_by_line:
|
||||
return LineByLineTextDataset(tokenizer=tokenizer, file_path=file_path, block_size=args.block_size)
|
||||
else:
|
||||
return TextDataset(
|
||||
tokenizer=tokenizer,
|
||||
file_path=file_path,
|
||||
block_size=args.block_size,
|
||||
overwrite_cache=args.overwrite_cache,
|
||||
cache_dir=cache_dir,
|
||||
)
|
||||
|
||||
if evaluate:
|
||||
return _dataset(args.eval_data_file)
|
||||
elif args.train_data_files:
|
||||
return ConcatDataset([_dataset(f) for f in glob(args.train_data_files)])
|
||||
else:
|
||||
return TextDataset(
|
||||
tokenizer=tokenizer,
|
||||
file_path=file_path,
|
||||
block_size=args.block_size,
|
||||
overwrite_cache=args.overwrite_cache,
|
||||
cache_dir=cache_dir,
|
||||
)
|
||||
return _dataset(args.train_data_file)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -119,7 +119,7 @@ class BaseTransformer(pl.LightningModule):
|
||||
def get_lr_scheduler(self):
|
||||
get_schedule_func = arg_to_scheduler[self.hparams.lr_scheduler]
|
||||
scheduler = get_schedule_func(
|
||||
self.opt, num_warmup_steps=self.hparams.warmup_steps, num_training_steps=self.total_steps
|
||||
self.opt, num_warmup_steps=self.hparams.warmup_steps, num_training_steps=self.total_steps()
|
||||
)
|
||||
scheduler = {"scheduler": scheduler, "interval": "step", "frequency": 1}
|
||||
return scheduler
|
||||
@@ -159,19 +159,20 @@ class BaseTransformer(pl.LightningModule):
|
||||
def test_epoch_end(self, outputs):
|
||||
return self.validation_end(outputs)
|
||||
|
||||
@property
|
||||
def total_steps(self) -> int:
|
||||
"""The number of total training steps that will be run. Used for lr scheduler purposes."""
|
||||
num_devices = max(1, self.hparams.gpus) # TODO: consider num_tpu_cores
|
||||
effective_batch_size = self.hparams.train_batch_size * self.hparams.accumulate_grad_batches * num_devices
|
||||
dataset_size = len(self.train_loader.dataset)
|
||||
return (dataset_size / effective_batch_size) * self.hparams.max_epochs
|
||||
return (self.dataset_size / effective_batch_size) * self.hparams.max_epochs
|
||||
|
||||
def setup(self, mode):
|
||||
if mode == "fit":
|
||||
if mode == "test":
|
||||
self.dataset_size = len(self.test_dataloader().dataset)
|
||||
else:
|
||||
self.train_loader = self.get_dataloader("train", self.hparams.train_batch_size, shuffle=True)
|
||||
self.dataset_size = len(self.train_loader.dataset)
|
||||
|
||||
def get_dataloader(self, type_path, batch_size, shuffle=False):
|
||||
def get_dataloader(self, type_path: str, batch_size: int, shuffle: bool = False):
|
||||
raise NotImplementedError("You must implement this for your task")
|
||||
|
||||
def train_dataloader(self):
|
||||
|
||||
@@ -5,7 +5,7 @@ psutil
|
||||
sacrebleu
|
||||
rouge-score
|
||||
tensorflow_datasets
|
||||
pytorch-lightning==0.8.5
|
||||
pytorch-lightning==0.9.0
|
||||
matplotlib
|
||||
git-python==1.0.3
|
||||
faiss-cpu
|
||||
|
||||
@@ -12,7 +12,6 @@ For `bertabs` instructions, see [`bertabs/README.md`](bertabs/README.md).
|
||||
- `MBartForConditionalGeneration`
|
||||
- `FSMTForConditionalGeneration`
|
||||
- `T5ForConditionalGeneration`
|
||||
|
||||
|
||||
## Datasets
|
||||
|
||||
@@ -100,7 +99,7 @@ All finetuning bash scripts call finetune.py (or distillation.py) with reasonabl
|
||||
To see all the possible command line options, run:
|
||||
|
||||
```bash
|
||||
./finetune.py --help
|
||||
./finetune.py --help
|
||||
```
|
||||
|
||||
### Finetuning Training Params
|
||||
@@ -192,7 +191,7 @@ model = AutoModelForSeq2SeqLM.from_pretrained(f'{output_dir}/best_tfmr')
|
||||
### Fine-tuning using Seq2SeqTrainer
|
||||
To use `Seq2SeqTrainer` for fine-tuning you should use the `finetune_trainer.py` script. It subclasses `Trainer` to extend it for seq2seq training. Except the `Trainer` releated `TrainingArguments`, it shares the same argument names as that of `finetune.py` file. One notable difference is that, calculating generative metrics (BLEU, ROUGE) is optional and is controlled using the `--predict_with_generate` argument, set this argument to calculate BLEU and ROUGE metrics.
|
||||
|
||||
With PyTorch 1.6+ it'll automatically use `native AMP` when `--fp16` is set.
|
||||
With PyTorch 1.6+ it'll automatically use `native AMP` when `--fp16` is set.
|
||||
|
||||
To see all the possible command line options, run:
|
||||
|
||||
@@ -265,6 +264,7 @@ export DATA_DIR=cnn_dm
|
||||
--fp16 \
|
||||
--bs 32
|
||||
```
|
||||
|
||||
### Multi-GPU Evaluation
|
||||
here is a command to run xsum evaluation on 8 GPUS. It is more than linearly faster than run_eval.py in some cases
|
||||
because it uses SortishSampler to minimize padding. You can also use it on 1 GPU. `data_dir` must have
|
||||
@@ -391,6 +391,17 @@ runtime: 13H on V-100 16GB GPU.
|
||||
pytest examples/seq2seq/
|
||||
```
|
||||
|
||||
### Converting pytorch-lightning checkpoints
|
||||
pytorch lightning ``-do_predict`` often fails, after you are done training, the best way to evaluate your model is to convert it.
|
||||
|
||||
This should be done for you, with a file called `{save_dir}/best_tfmr`.
|
||||
|
||||
If that file doesn't exist but you have a lightning `.ckpt` file, you can run
|
||||
```bash
|
||||
python convert_pl_checkpoint_to_hf.py PATH_TO_CKPT randomly_initialized_hf_model_path save_dir/best_tfmr
|
||||
```
|
||||
Then either `run_eval` or `run_distributed_eval` with `save_dir/best_tfmr` (see previous sections)
|
||||
|
||||
|
||||
## Experimental Features
|
||||
These features are harder to use and not always useful.
|
||||
@@ -419,4 +430,3 @@ uses 12,723 batches of length 48 and takes slightly more time 9.5 minutes.
|
||||
The feature is still experimental, because:
|
||||
+ we can make it much more robust if we have memory mapped/preprocessed datasets.
|
||||
+ The speedup over sortish sampler is not that large at the moment.
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ python run_summarization.py \
|
||||
--compute_rouge true
|
||||
```
|
||||
|
||||
The scripts executes on GPU if one is available and if `no_cuda` is not set to `true`. Inference on multiple GPUs is not suported yet. The ROUGE scores will be displayed in the console at the end of evaluation and written in a `rouge_scores.txt` file. The script takes 30 hours to compute with a single Tesla V100 GPU and a batch size of 10 (300,000 texts to summarize).
|
||||
The scripts executes on GPU if one is available and if `no_cuda` is not set to `true`. Inference on multiple GPUs is not supported yet. The ROUGE scores will be displayed in the console at the end of evaluation and written in a `rouge_scores.txt` file. The script takes 30 hours to compute with a single Tesla V100 GPU and a batch size of 10 (300,000 texts to summarize).
|
||||
|
||||
## Summarize any text
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ from finetune import main as ft_main
|
||||
from make_student import create_student_by_copying_alternating_layers, get_layers_to_supervise
|
||||
from transformers import AutoModelForSeq2SeqLM, MBartTokenizer, T5ForConditionalGeneration
|
||||
from transformers.modeling_bart import shift_tokens_right
|
||||
from utils import calculate_bleu, freeze_params, label_smoothed_nll_loss, pickle_load, use_task_specific_params
|
||||
from utils import calculate_bleu, freeze_params, label_smoothed_nll_loss, use_task_specific_params
|
||||
|
||||
|
||||
# need the parent dir module
|
||||
@@ -264,30 +264,6 @@ def create_module(args):
|
||||
return model
|
||||
|
||||
|
||||
def evaluate_checkpoint(ckpt_path: Path, dest_dir=None):
|
||||
# TODO(SS): DELETE? Better to convert_pl_ckpt_to_hf and run_eval.py
|
||||
exp_dir = ckpt_path.parent
|
||||
if dest_dir is None:
|
||||
dest_dir = exp_dir
|
||||
clash = list(dest_dir.glob("test_generations*"))
|
||||
if clash:
|
||||
print(f"SKIPPING to avoid overwriting {clash}")
|
||||
ckpt = torch.load(ckpt_path, map_location="cpu")
|
||||
if "hparams" in ckpt:
|
||||
args = argparse.Namespace(**ckpt["hparams"])
|
||||
else:
|
||||
args = argparse.Namespace(**pickle_load(exp_dir / "hparams.pkl"))
|
||||
args.resume_from_checkpoint = str(ckpt_path)
|
||||
args.do_train = False
|
||||
args.output_dir = str(dest_dir)
|
||||
args.n_gpu = 1
|
||||
args.eval_batch_size = 16
|
||||
Path(args.output_dir).mkdir(exist_ok=True)
|
||||
model = create_module(args)
|
||||
trainer: pl.Trainer = generic_train(model, args, early_stopping_callback=False)
|
||||
trainer.test(model)
|
||||
|
||||
|
||||
def distill_main(args):
|
||||
Path(args.output_dir).mkdir(exist_ok=True)
|
||||
if len(os.listdir(args.output_dir)) > 3 and args.do_train:
|
||||
|
||||
@@ -181,6 +181,7 @@ class SummarizationModule(BaseTransformer):
|
||||
return self._generative_step(batch)
|
||||
|
||||
def validation_epoch_end(self, outputs, prefix="val") -> Dict:
|
||||
|
||||
self.step_count += 1
|
||||
losses = {k: torch.stack([x[k] for x in outputs]).mean() for k in self.loss_names}
|
||||
loss = losses["loss"]
|
||||
|
||||
@@ -13,7 +13,7 @@ import torch
|
||||
|
||||
import lightning_base
|
||||
from convert_pl_checkpoint_to_hf import convert_pl_to_hf
|
||||
from distillation import distill_main, evaluate_checkpoint
|
||||
from distillation import distill_main
|
||||
from finetune import SummarizationModule, main
|
||||
from run_eval import generate_summaries_or_translations, run_generate
|
||||
from run_eval_search import run_search
|
||||
@@ -178,7 +178,6 @@ class TestSummarizationDistiller(unittest.TestCase):
|
||||
generate_summaries_or_translations(examples, out_path, str(model.output_dir / "best_tfmr"))
|
||||
self.assertTrue(Path(out_path).exists())
|
||||
|
||||
evaluate_checkpoint(ckpts[0], dest_dir=Path(tempfile.mkdtemp()))
|
||||
out_path_new = tempfile.mkdtemp()
|
||||
convert_pl_to_hf(ckpts[0], transformer_ckpts[0].parent, out_path_new)
|
||||
assert os.path.exists(os.path.join(out_path_new, "pytorch_model.bin"))
|
||||
@@ -227,8 +226,6 @@ class TestSummarizationDistiller(unittest.TestCase):
|
||||
assert len(all_files) > 2
|
||||
self.assertEqual(len(transformer_ckpts), 2)
|
||||
|
||||
evaluate_checkpoint(ckpts[0], dest_dir=Path(tempfile.mkdtemp()))
|
||||
|
||||
def test_distill_t5(self):
|
||||
updates = dict(
|
||||
student_encoder_layers=1,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
from transformers.convert_marian_tatoeba_to_pytorch import TatoebaConverter
|
||||
from transformers.file_utils import cached_property
|
||||
from transformers.testing_utils import slow
|
||||
|
||||
|
||||
class TatoebaConversionTester(unittest.TestCase):
|
||||
@cached_property
|
||||
def resolver(self):
|
||||
tmp_dir = tempfile.mkdtemp()
|
||||
return TatoebaConverter(save_dir=tmp_dir)
|
||||
|
||||
@slow
|
||||
def test_resolver(self):
|
||||
self.resolver.convert_models(["heb-eng"])
|
||||
|
||||
@slow
|
||||
def test_model_card(self):
|
||||
content, mmeta = self.resolver.write_model_card("opus-mt-he-en", dry_run=True)
|
||||
assert mmeta["long_pair"] == "heb-eng"
|
||||
@@ -116,8 +116,8 @@ class ExamplesTests(TestCasePlus):
|
||||
testargs.append("--fp16")
|
||||
|
||||
with patch.object(sys, "argv", testargs):
|
||||
result = run_pl_glue.main()
|
||||
# for now just testing that the script can run to a completion
|
||||
result = run_pl_glue.main()[0]
|
||||
# for now just testing that the script can run to completion
|
||||
self.assertGreater(result["acc"], 0.25)
|
||||
#
|
||||
# TODO: this fails on CI - doesn't get acc/f1>=0.75:
|
||||
|
||||
@@ -60,7 +60,7 @@ def get_tfds(
|
||||
for k in files.keys():
|
||||
transformed_ds[k] = ds[k].map(
|
||||
lambda example: tokenizer.batch_encode_plus(
|
||||
(example[features_name[0]], features_name[1]),
|
||||
(example[features_name[0]], example[features_name[1]]),
|
||||
truncation=True,
|
||||
max_length=max_seq_length,
|
||||
padding="max_length",
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
license: apache-2.0
|
||||
---
|
||||
@@ -4,4 +4,5 @@ datasets:
|
||||
- squad
|
||||
metrics:
|
||||
- squad
|
||||
license: apache-2.0
|
||||
---
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
language: de
|
||||
license: apache-2.0
|
||||
---
|
||||
## distilbert-base-german-cased
|
||||
|
||||
@@ -6,4 +6,5 @@ widget:
|
||||
context: "The Amazon rainforest (Portuguese: Floresta Amazônica or Amazônia; Spanish: Selva Amazónica, Amazonía or usually Amazonia; French: Forêt amazonienne; Dutch: Amazoneregenwoud), also known in English as Amazonia or the Amazon Jungle, is a moist broadleaf forest that covers most of the Amazon basin of South America. This basin encompasses 7,000,000 square kilometres (2,700,000 sq mi), of which 5,500,000 square kilometres (2,100,000 sq mi) are covered by the rainforest. This region includes territory belonging to nine nations. The majority of the forest is contained within Brazil, with 60% of the rainforest, followed by Peru with 13%, Colombia with 10%, and with minor amounts in Venezuela, Ecuador, Bolivia, Guyana, Suriname and French Guiana. States or departments in four nations contain \"Amazonas\" in their names. The Amazon represents over half of the planet's remaining rainforests, and comprises the largest and most biodiverse tract of tropical rainforest in the world, with an estimated 390 billion individual trees divided into 16,000 species."
|
||||
- text: "How many square kilometers of rainforest is covered in the basin?"
|
||||
context: "The Amazon rainforest (Portuguese: Floresta Amazônica or Amazônia; Spanish: Selva Amazónica, Amazonía or usually Amazonia; French: Forêt amazonienne; Dutch: Amazoneregenwoud), also known in English as Amazonia or the Amazon Jungle, is a moist broadleaf forest that covers most of the Amazon basin of South America. This basin encompasses 7,000,000 square kilometres (2,700,000 sq mi), of which 5,500,000 square kilometres (2,100,000 sq mi) are covered by the rainforest. This region includes territory belonging to nine nations. The majority of the forest is contained within Brazil, with 60% of the rainforest, followed by Peru with 13%, Colombia with 10%, and with minor amounts in Venezuela, Ecuador, Bolivia, Guyana, Suriname and French Guiana. States or departments in four nations contain \"Amazonas\" in their names. The Amazon represents over half of the planet's remaining rainforests, and comprises the largest and most biodiverse tract of tropical rainforest in the world, with an estimated 390 billion individual trees divided into 16,000 species."
|
||||
license: apache-2.0
|
||||
---
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
license: apache-2.0
|
||||
---
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
license: mit
|
||||
---
|
||||
@@ -6,6 +6,8 @@ language:
|
||||
- fr
|
||||
- it
|
||||
- es
|
||||
|
||||
license: mit
|
||||
---
|
||||
|
||||
# bert-base-multilingual-uncased-sentiment
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# this script builds a small sample spm file tests/fixtures/test_sentencepiece_no_bos.model, with features needed by pegasus
|
||||
|
||||
# 1. pip install sentencepiece
|
||||
#
|
||||
# 2. wget https://raw.githubusercontent.com/google/sentencepiece/master/data/botchan.txt
|
||||
|
||||
# 3. build
|
||||
import sentencepiece as spm
|
||||
|
||||
# pegasus:
|
||||
# 1. no bos
|
||||
# 2. eos_id is 1
|
||||
# 3. unk_id is 2
|
||||
# build a sample spm file accordingly
|
||||
spm.SentencePieceTrainer.train('--input=botchan.txt --model_prefix=test_sentencepiece_no_bos --bos_id=-1 --unk_id=2 --eos_id=1 --vocab_size=1000')
|
||||
|
||||
# 4. now update the fixture
|
||||
# mv test_sentencepiece_no_bos.model ../../tests/fixtures/
|
||||
@@ -0,0 +1,44 @@
|
||||
Setup transformers following instructions in README.md, (I would fork first).
|
||||
```bash
|
||||
git clone git@github.com:huggingface/transformers.git
|
||||
cd transformers
|
||||
pip install -e .
|
||||
pip install pandas
|
||||
```
|
||||
|
||||
Get required metadata
|
||||
```
|
||||
curl https://cdn-datasets.huggingface.co/language_codes/language-codes-3b2.csv > language-codes-3b2.csv
|
||||
curl https://cdn-datasets.huggingface.co/language_codes/iso-639-3.csv > iso-639-3.csv
|
||||
```
|
||||
|
||||
Install Tatoeba-Challenge repo inside transformers
|
||||
```bash
|
||||
git clone git@github.com:Helsinki-NLP/Tatoeba-Challenge.git
|
||||
```
|
||||
|
||||
To convert a few models, call the conversion script from command line:
|
||||
```bash
|
||||
python src/transformers/convert_marian_tatoeba_to_pytorch.py --models heb-eng eng-heb --save_dir converted
|
||||
```
|
||||
|
||||
To convert lots of models you can pass your list of Tatoeba model names to `resolver.convert_models` in a python client or script.
|
||||
|
||||
```python
|
||||
from transformers.convert_marian_tatoeba_to_pytorch import TatoebaConverter
|
||||
resolver = TatoebaConverter(save_dir='converted')
|
||||
resolver.convert_models(['heb-eng', 'eng-heb'])
|
||||
```
|
||||
|
||||
|
||||
### Upload converted models
|
||||
```bash
|
||||
cd converted
|
||||
transformers-cli login
|
||||
for FILE in *; do transformers-cli upload $FILE; done
|
||||
```
|
||||
|
||||
|
||||
### Modifications
|
||||
- To change naming logic, change the code near `os.rename`. The model card creation code may also need to change.
|
||||
- To change model card content, you must modify `TatoebaCodeResolver.write_model_card`
|
||||
@@ -6,6 +6,7 @@ To create the package for pypi.
|
||||
1. Change the version in __init__.py, setup.py as well as docs/source/conf.py. Remove the master from the links in
|
||||
the new models of the README:
|
||||
(https://huggingface.co/transformers/master/model_doc/ -> https://huggingface.co/transformers/model_doc/)
|
||||
then run `make fix-copies` to fix the index of the documentation.
|
||||
|
||||
2. Unpin specific versions from setup.py that use a git install.
|
||||
|
||||
@@ -133,9 +134,7 @@ setup(
|
||||
"sacremoses",
|
||||
],
|
||||
extras_require=extras,
|
||||
entry_points={
|
||||
"console_scripts": ["transformers-cli=transformers.commands.transformers_cli:main"]
|
||||
},
|
||||
entry_points={"console_scripts": ["transformers-cli=transformers.commands.transformers_cli:main"]},
|
||||
python_requires=">=3.6.0",
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
|
||||
@@ -437,6 +437,7 @@ if is_torch_available():
|
||||
from .modeling_openai import (
|
||||
OPENAI_GPT_PRETRAINED_MODEL_ARCHIVE_LIST,
|
||||
OpenAIGPTDoubleHeadsModel,
|
||||
OpenAIGPTForSequenceClassification,
|
||||
OpenAIGPTLMHeadModel,
|
||||
OpenAIGPTModel,
|
||||
OpenAIGPTPreTrainedModel,
|
||||
|
||||
@@ -31,7 +31,7 @@ class MMBTConfig(object):
|
||||
Config of the underlying Transformer models. Its values are copied over to use a single config.
|
||||
num_labels (:obj:`int`, `optional`):
|
||||
Size of final Linear layer for classification.
|
||||
modal_hidden_size (:obj:`int`, `optional`, defautls to 2048):
|
||||
modal_hidden_size (:obj:`int`, `optional`, defaults to 2048):
|
||||
Embedding dimension of the non-text modality encoder.
|
||||
"""
|
||||
|
||||
|
||||
@@ -274,7 +274,7 @@ class PretrainedConfig(object):
|
||||
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`):
|
||||
Wheter or not to force to (re-)download the configuration files and override the cached versions if they
|
||||
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
|
||||
|
||||
@@ -204,7 +204,7 @@ class XLNetConfig(PretrainedConfig):
|
||||
if mem_len is None or mem_len == 0:
|
||||
warnings.warn(
|
||||
"This config doesn't use attention memories, a core feature of XLNet."
|
||||
" Consider setting `men_len` to a non-zero value, for example "
|
||||
" Consider setting `mem_len` to a non-zero value, for example "
|
||||
"`xlnet = XLNetLMHeadModel.from_pretrained('xlnet-base-cased'', mem_len=1024)`,"
|
||||
" for accurate training performance as well as an order of magnitude faster inference."
|
||||
" Starting from version 3.5.0, the default parameter will be 1024, following"
|
||||
|
||||
@@ -211,7 +211,7 @@ def load_graph_from_args(pipeline_name: str, framework: str, model: str, tokeniz
|
||||
pipeline_name: The kind of pipeline to use (ner, question-answering, etc.)
|
||||
framework: The actual model to convert the pipeline from ("pt" or "tf")
|
||||
model: The model name which will be loaded by the pipeline
|
||||
tokenizer: The tokenizer name which will be loaded by the pipeline, defaut to the model's value
|
||||
tokenizer: The tokenizer name which will be loaded by the pipeline, default to the model's value
|
||||
|
||||
Returns: Pipeline object
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,11 @@
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
import time
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Tuple, Union
|
||||
from typing import Dict, List, Union
|
||||
from zipfile import ZipFile
|
||||
|
||||
import numpy as np
|
||||
@@ -23,85 +22,6 @@ def remove_suffix(text: str, suffix: str):
|
||||
return text # or whatever
|
||||
|
||||
|
||||
def _process_benchmark_table_row(x):
|
||||
fields = lmap(str.strip, x.replace("\t", "").split("|")[1:-1])
|
||||
assert len(fields) == 3
|
||||
return (fields[0], float(fields[1]), float(fields[2]))
|
||||
|
||||
|
||||
def process_last_benchmark_table(readme_path) -> List[Tuple[str, float, float]]:
|
||||
md_content = Path(readme_path).open().read()
|
||||
entries = md_content.split("## Benchmarks")[-1].strip().split("\n")[2:]
|
||||
data = lmap(_process_benchmark_table_row, entries)
|
||||
return data
|
||||
|
||||
|
||||
def check_if_models_are_dominated(old_repo_path="OPUS-MT-train/models", new_repo_path="Tatoeba-Challenge/models/"):
|
||||
"""Make a blacklist for models where we have already ported the same language pair, and the ported model has higher BLEU score."""
|
||||
import pandas as pd
|
||||
|
||||
newest_released, old_reg, released = get_released_df(new_repo_path, old_repo_path)
|
||||
|
||||
short_to_new_bleu = newest_released.set_index("short_pair").bleu
|
||||
|
||||
assert released.groupby("short_pair").pair.nunique().max() == 1
|
||||
|
||||
short_to_long = released.groupby("short_pair").pair.first().to_dict()
|
||||
|
||||
overlap_short = old_reg.index.intersection(released.short_pair.unique())
|
||||
overlap_long = [short_to_long[o] for o in overlap_short]
|
||||
new_reported_bleu = [short_to_new_bleu[o] for o in overlap_short]
|
||||
|
||||
def get_old_bleu(o) -> float:
|
||||
pat = old_repo_path + "/{}/README.md"
|
||||
bm_data = process_last_benchmark_table(pat.format(o))
|
||||
tab = pd.DataFrame(bm_data, columns=["testset", "bleu", "chr-f"])
|
||||
tato_bleu = tab.loc[lambda x: x.testset.str.startswith("Tato")].bleu
|
||||
if tato_bleu.shape[0] > 0:
|
||||
return tato_bleu.iloc[0]
|
||||
else:
|
||||
return np.nan
|
||||
|
||||
old_bleu = [get_old_bleu(o) for o in overlap_short]
|
||||
cmp_df = pd.DataFrame(
|
||||
dict(short=overlap_short, long=overlap_long, old_bleu=old_bleu, new_bleu=new_reported_bleu)
|
||||
).fillna(-1)
|
||||
|
||||
dominated = cmp_df[cmp_df.old_bleu > cmp_df.new_bleu]
|
||||
whitelist_df = cmp_df[cmp_df.old_bleu <= cmp_df.new_bleu]
|
||||
blacklist = dominated.long.unique().tolist() # 3 letter codes
|
||||
return whitelist_df, dominated, blacklist
|
||||
|
||||
|
||||
def get_released_df(new_repo_path, old_repo_path):
|
||||
import pandas as pd
|
||||
|
||||
released_cols = [
|
||||
"url_base",
|
||||
"pair", # (ISO639-3/ISO639-5 codes),
|
||||
"short_pair", # (reduced codes),
|
||||
"chrF2_score",
|
||||
"bleu",
|
||||
"brevity_penalty",
|
||||
"ref_len",
|
||||
"src_name",
|
||||
"tgt_name",
|
||||
]
|
||||
released = pd.read_csv(f"{new_repo_path}/released-models.txt", sep="\t", header=None).iloc[:-1]
|
||||
released.columns = released_cols
|
||||
old_reg = make_registry(repo_path=old_repo_path)
|
||||
old_reg = pd.DataFrame(old_reg, columns=["id", "prepro", "url_model", "url_test_set"])
|
||||
assert old_reg.id.value_counts().max() == 1
|
||||
old_reg = old_reg.set_index("id")
|
||||
released["fname"] = released["url_base"].apply(
|
||||
lambda x: remove_suffix(remove_prefix(x, "https://object.pouta.csc.fi/Tatoeba-Challenge/opus"), ".zip")
|
||||
)
|
||||
released["2m"] = released.fname.str.startswith("2m")
|
||||
released["date"] = pd.to_datetime(released["fname"].apply(lambda x: remove_prefix(remove_prefix(x, "2m-"), "-")))
|
||||
newest_released = released.dsort("date").drop_duplicates(["short_pair"], keep="first")
|
||||
return newest_released, old_reg, released
|
||||
|
||||
|
||||
def remove_prefix(text: str, prefix: str):
|
||||
if text.startswith(prefix):
|
||||
return text[len(prefix) :]
|
||||
@@ -183,7 +103,11 @@ def find_model_file(dest_dir): # this one better
|
||||
|
||||
|
||||
# Group Names Logic: change long opus model names to something shorter, like opus-mt-en-ROMANCE
|
||||
ROM_GROUP = "fr+fr_BE+fr_CA+fr_FR+wa+frp+oc+ca+rm+lld+fur+lij+lmo+es+es_AR+es_CL+es_CO+es_CR+es_DO+es_EC+es_ES+es_GT+es_HN+es_MX+es_NI+es_PA+es_PE+es_PR+es_SV+es_UY+es_VE+pt+pt_br+pt_BR+pt_PT+gl+lad+an+mwl+it+it_IT+co+nap+scn+vec+sc+ro+la"
|
||||
ROM_GROUP = (
|
||||
"fr+fr_BE+fr_CA+fr_FR+wa+frp+oc+ca+rm+lld+fur+lij+lmo+es+es_AR+es_CL+es_CO+es_CR+es_DO+es_EC+es_ES+es_GT"
|
||||
"+es_HN+es_MX+es_NI+es_PA+es_PE+es_PR+es_SV+es_UY+es_VE+pt+pt_br+pt_BR+pt_PT+gl+lad+an+mwl+it+it_IT+co"
|
||||
"+nap+scn+vec+sc+ro+la"
|
||||
)
|
||||
GROUPS = [
|
||||
("cmn+cn+yue+ze_zh+zh_cn+zh_CN+zh_HK+zh_tw+zh_TW+zh_yue+zhs+zht+zh", "ZH"),
|
||||
(ROM_GROUP, "ROMANCE"),
|
||||
@@ -221,13 +145,15 @@ ORG_NAME = "Helsinki-NLP/"
|
||||
|
||||
|
||||
def convert_opus_name_to_hf_name(x):
|
||||
"""For OPUS-MT-Train/ DEPRECATED"""
|
||||
for substr, grp_name in GROUPS:
|
||||
x = x.replace(substr, grp_name)
|
||||
return x.replace("+", "_")
|
||||
|
||||
|
||||
def convert_hf_name_to_opus_name(hf_model_name):
|
||||
"""Relies on the assumption that there are no language codes like pt_br in models that are not in GROUP_TO_OPUS_NAME."""
|
||||
"""Relies on the assumption that there are no language codes like pt_br in models that are not in
|
||||
GROUP_TO_OPUS_NAME."""
|
||||
hf_model_name = remove_prefix(hf_model_name, ORG_NAME)
|
||||
if hf_model_name in GROUP_TO_OPUS_NAME:
|
||||
opus_w_prefix = GROUP_TO_OPUS_NAME[hf_model_name]
|
||||
@@ -247,8 +173,9 @@ def get_system_metadata(repo_root):
|
||||
)
|
||||
|
||||
|
||||
front_matter = """---
|
||||
language: {}
|
||||
FRONT_MATTER_TEMPLATE = """---
|
||||
language:
|
||||
{}
|
||||
tags:
|
||||
- translation
|
||||
|
||||
@@ -256,11 +183,13 @@ license: apache-2.0
|
||||
---
|
||||
|
||||
"""
|
||||
DEFAULT_REPO = "Tatoeba-Challenge"
|
||||
DEFAULT_MODEL_DIR = os.path.join(DEFAULT_REPO, "models")
|
||||
|
||||
|
||||
def write_model_card(
|
||||
hf_model_name: str,
|
||||
repo_root="OPUS-MT-train",
|
||||
repo_root=DEFAULT_REPO,
|
||||
save_dir=Path("marian_converted"),
|
||||
dry_run=False,
|
||||
extra_metadata={},
|
||||
@@ -294,7 +223,10 @@ def write_model_card(
|
||||
|
||||
# combine with opus markdown
|
||||
|
||||
extra_markdown = f"### {hf_model_name}\n\n* source group: {metadata['src_name']} \n* target group: {metadata['tgt_name']} \n* OPUS readme: [{opus_name}]({readme_url})\n"
|
||||
extra_markdown = (
|
||||
f"### {hf_model_name}\n\n* source group: {metadata['src_name']} \n* target group: "
|
||||
f"{metadata['tgt_name']} \n* OPUS readme: [{opus_name}]({readme_url})\n"
|
||||
)
|
||||
|
||||
content = opus_readme_path.open().read()
|
||||
content = content.split("\n# ")[-1] # Get the lowest level 1 header in the README -- the most recent model.
|
||||
@@ -302,7 +234,7 @@ def write_model_card(
|
||||
print(splat[3])
|
||||
content = "*".join(splat)
|
||||
content = (
|
||||
front_matter.format(metadata["src_alpha2"])
|
||||
FRONT_MATTER_TEMPLATE.format(metadata["src_alpha2"])
|
||||
+ extra_markdown
|
||||
+ "\n* "
|
||||
+ content.replace("download", "download original weights")
|
||||
@@ -323,48 +255,6 @@ def write_model_card(
|
||||
return content, metadata
|
||||
|
||||
|
||||
def get_clean_model_id_mapping(multiling_model_ids):
|
||||
return {x: convert_opus_name_to_hf_name(x) for x in multiling_model_ids}
|
||||
|
||||
|
||||
def expand_group_to_two_letter_codes(grp_name):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def get_two_letter_code(three_letter_code):
|
||||
raise NotImplementedError()
|
||||
# return two_letter_code
|
||||
|
||||
|
||||
def get_tags(code, ref_name):
|
||||
if len(code) == 2:
|
||||
assert "languages" not in ref_name, f"{code}: {ref_name}"
|
||||
return [code], False
|
||||
elif "languages" in ref_name:
|
||||
group = expand_group_to_two_letter_codes(code)
|
||||
group.append(code)
|
||||
return group, True
|
||||
else: # zho-> zh
|
||||
raise ValueError(f"Three letter monolingual code: {code}")
|
||||
|
||||
|
||||
def resolve_lang_code(r):
|
||||
"""R is a row in ported"""
|
||||
short_pair = r.short_pair
|
||||
src, tgt = short_pair.split("-")
|
||||
src_tags, src_multilingual = get_tags(src, r.src_name)
|
||||
assert isinstance(src_tags, list)
|
||||
tgt_tags, tgt_multilingual = get_tags(src, r.tgt_name)
|
||||
assert isinstance(tgt_tags, list)
|
||||
if src_multilingual:
|
||||
src_tags.append("multilingual_src")
|
||||
if tgt_multilingual:
|
||||
tgt_tags.append("multilingual_tgt")
|
||||
return src_tags + tgt_tags
|
||||
|
||||
# process target
|
||||
|
||||
|
||||
def make_registry(repo_path="Opus-MT-train/models"):
|
||||
if not (Path(repo_path) / "fr-en" / "README.md").exists():
|
||||
raise ValueError(
|
||||
@@ -382,36 +272,25 @@ def make_registry(repo_path="Opus-MT-train/models"):
|
||||
return [(k, v["pre-processing"], v["download"], v["download"][:-4] + ".test.txt") for k, v in results.items()]
|
||||
|
||||
|
||||
def make_tatoeba_registry(repo_path="Tatoeba-Challenge/models"):
|
||||
if not (Path(repo_path) / "zho-eng" / "README.md").exists():
|
||||
raise ValueError(
|
||||
f"repo_path:{repo_path} does not exist: "
|
||||
"You must run: git clone git@github.com:Helsinki-NLP/Tatoeba-Challenge.git before calling."
|
||||
)
|
||||
results = {}
|
||||
for p in Path(repo_path).iterdir():
|
||||
if len(p.name) != 7:
|
||||
continue
|
||||
lns = list(open(p / "README.md").readlines())
|
||||
results[p.name] = _parse_readme(lns)
|
||||
return [(k, v["pre-processing"], v["download"], v["download"][:-4] + ".test.txt") for k, v in results.items()]
|
||||
|
||||
|
||||
def convert_all_sentencepiece_models(model_list=None, repo_path=None):
|
||||
def convert_all_sentencepiece_models(model_list=None, repo_path=None, dest_dir=Path("marian_converted")):
|
||||
"""Requires 300GB"""
|
||||
save_dir = Path("marian_ckpt")
|
||||
dest_dir = Path("marian_converted")
|
||||
dest_dir = Path(dest_dir)
|
||||
dest_dir.mkdir(exist_ok=True)
|
||||
save_paths = []
|
||||
if model_list is None:
|
||||
model_list: list = make_registry(repo_path=repo_path)
|
||||
for k, prepro, download, test_set_url in tqdm(model_list):
|
||||
if "SentencePiece" not in prepro: # dont convert BPE models.
|
||||
continue
|
||||
if not os.path.exists(save_dir / k / "pytorch_model.bin"):
|
||||
if not os.path.exists(save_dir / k):
|
||||
download_and_unzip(download, save_dir / k)
|
||||
pair_name = convert_opus_name_to_hf_name(k)
|
||||
convert(save_dir / k, dest_dir / f"opus-mt-{pair_name}")
|
||||
|
||||
save_paths.append(dest_dir / f"opus-mt-{pair_name}")
|
||||
return save_paths
|
||||
|
||||
|
||||
def lmap(f, x) -> List:
|
||||
return list(map(f, x))
|
||||
@@ -493,15 +372,6 @@ def add_special_tokens_to_vocab(model_dir: Path) -> None:
|
||||
save_tokenizer_config(model_dir)
|
||||
|
||||
|
||||
def save_tokenizer(self, save_directory):
|
||||
dest = Path(save_directory)
|
||||
src_path = Path(self.init_kwargs["source_spm"])
|
||||
|
||||
for dest_name in {"source.spm", "target.spm", "tokenizer_config.json"}:
|
||||
shutil.copyfile(src_path.parent / dest_name, dest / dest_name)
|
||||
save_json(self.encoder, dest / "vocab.json")
|
||||
|
||||
|
||||
def check_equal(marian_cfg, k1, k2):
|
||||
v1, v2 = marian_cfg[k1], marian_cfg[k2]
|
||||
assert v1 == v2, f"hparams {k1},{k2} differ: {v1} != {v2}"
|
||||
@@ -698,14 +568,14 @@ def convert(source_dir: Path, dest_dir):
|
||||
|
||||
add_special_tokens_to_vocab(source_dir)
|
||||
tokenizer = MarianTokenizer.from_pretrained(str(source_dir))
|
||||
save_tokenizer(tokenizer, dest_dir)
|
||||
tokenizer.save_pretrained(dest_dir)
|
||||
|
||||
opus_state = OpusState(source_dir)
|
||||
assert opus_state.cfg["vocab_size"] == len(
|
||||
tokenizer.encoder
|
||||
), f"Original vocab size {opus_state.cfg['vocab_size']} and new vocab size {len(tokenizer.encoder)} mismatched"
|
||||
# save_json(opus_state.cfg, dest_dir / "marian_original_config.json")
|
||||
# ^^ Save human readable marian config for debugging
|
||||
# ^^ Uncomment to save human readable marian config for debugging
|
||||
|
||||
model = opus_state.load_marian_model()
|
||||
model = model.half()
|
||||
@@ -732,15 +602,11 @@ def unzip(zip_path: str, dest_dir: str) -> None:
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""
|
||||
To bulk convert, run
|
||||
>>> from transformers.convert_marian_to_pytorch import make_tatoeba_registry, convert_all_sentencepiece_models
|
||||
>>> reg = make_tatoeba_registry()
|
||||
>>> convert_all_sentencepiece_models(model_list=reg) # saves to marian_converted
|
||||
(bash) aws s3 sync marian_converted s3://models.huggingface.co/bert/Helsinki-NLP/ --dryrun
|
||||
Tatoeba conversion instructions in scripts/tatoeba/README.md
|
||||
"""
|
||||
parser = argparse.ArgumentParser()
|
||||
# Required parameters
|
||||
parser.add_argument("--src", type=str, help="path to marian model dir", default="en-de")
|
||||
parser.add_argument("--src", type=str, help="path to marian model sub dir", default="en-de")
|
||||
parser.add_argument("--dest", type=str, default=None, help="Path to the output PyTorch model.")
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
@@ -547,6 +547,7 @@ CONVERTERS = {
|
||||
"DPRReaderTokenizer": BertConverter,
|
||||
"DPRQuestionEncoderTokenizer": BertConverter,
|
||||
"DPRContextEncoderTokenizer": BertConverter,
|
||||
"ElectraTokenizer": BertConverter,
|
||||
"FunnelTokenizer": FunnelConverter,
|
||||
"GPT2Tokenizer": GPT2Converter,
|
||||
"LxmertTokenizer": BertConverter,
|
||||
|
||||
@@ -560,7 +560,7 @@ class SquadProcessor(DataProcessor):
|
||||
|
||||
Args:
|
||||
dataset: The tfds dataset loaded from `tensorflow_datasets.load("squad")`
|
||||
evaluate: boolean specifying if in evaluation mode or in training mode
|
||||
evaluate: Boolean specifying if in evaluation mode or in training mode
|
||||
|
||||
Returns:
|
||||
List of SquadExample
|
||||
|
||||
@@ -1093,7 +1093,7 @@ def is_tensor(x):
|
||||
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 dictionnary) that will ignore the ``None`` attributes. Otherwise behaves like a
|
||||
a tuple) or strings (like a dictionary) that will ignore the ``None`` attributes. Otherwise behaves like a
|
||||
regular python dictionary.
|
||||
|
||||
.. warning::
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
import math
|
||||
import os
|
||||
|
||||
from .file_utils import is_torch_tpu_available
|
||||
from .trainer_callback import TrainerCallback
|
||||
from .trainer_utils import PREFIX_CHECKPOINT_DIR, BestRun
|
||||
from .utils import logging
|
||||
|
||||
# Import 3rd-party integrations first:
|
||||
|
||||
try:
|
||||
# Comet needs to be imported before any ML frameworks
|
||||
import comet_ml # noqa: F401
|
||||
|
||||
_has_comet = True
|
||||
@@ -53,6 +51,14 @@ except ImportError:
|
||||
except ImportError:
|
||||
_has_tensorboard = False
|
||||
|
||||
# No transformer imports above this point
|
||||
|
||||
from .file_utils import is_torch_tpu_available
|
||||
from .trainer_callback import TrainerCallback
|
||||
from .trainer_utils import PREFIX_CHECKPOINT_DIR, BestRun
|
||||
from .utils import logging
|
||||
|
||||
|
||||
logger = logging.get_logger(__name__)
|
||||
|
||||
|
||||
@@ -191,7 +197,7 @@ class TensorBoardCallback(TrainerCallback):
|
||||
|
||||
Args:
|
||||
tb_writer (:obj:`SummaryWriter`, `optional`):
|
||||
The writer to use. Will instatiate one if not set.
|
||||
The writer to use. Will instantiate one if not set.
|
||||
"""
|
||||
|
||||
def __init__(self, tb_writer=None):
|
||||
|
||||
@@ -539,7 +539,7 @@ ALBERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -153,7 +153,7 @@ from .modeling_mobilebert import (
|
||||
MobileBertForTokenClassification,
|
||||
MobileBertModel,
|
||||
)
|
||||
from .modeling_openai import OpenAIGPTLMHeadModel, OpenAIGPTModel
|
||||
from .modeling_openai import OpenAIGPTForSequenceClassification, OpenAIGPTLMHeadModel, OpenAIGPTModel
|
||||
from .modeling_pegasus import PegasusForConditionalGeneration
|
||||
from .modeling_rag import ( # noqa: F401 - need to import all RagModels to be in globals() function
|
||||
RagModel,
|
||||
@@ -381,6 +381,7 @@ MODEL_FOR_SEQUENCE_CLASSIFICATION_MAPPING = OrderedDict(
|
||||
(FunnelConfig, FunnelForSequenceClassification),
|
||||
(DebertaConfig, DebertaForSequenceClassification),
|
||||
(GPT2Config, GPT2ForSequenceClassification),
|
||||
(OpenAIGPTConfig, OpenAIGPTForSequenceClassification),
|
||||
]
|
||||
)
|
||||
|
||||
@@ -506,7 +507,7 @@ AUTO_MODEL_PRETRAINED_DOCSTRING = r"""
|
||||
:obj:`{'http': 'foo.bar:3128', 'http://hostname': 'foo.bar:4012'}`. The proxies are used on each
|
||||
request.
|
||||
output_loading_info(:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether ot not to also return a dictionnary containing missing keys, unexpected keys and error
|
||||
Whether ot not to also return a dictionary containing missing keys, unexpected keys and error
|
||||
messages.
|
||||
local_files_only(:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to only look at local files (e.g., not try doanloading the model).
|
||||
@@ -532,7 +533,7 @@ AUTO_MODEL_PRETRAINED_DOCSTRING = r"""
|
||||
class AutoModel:
|
||||
r"""
|
||||
This is a generic model class that will be instantiated as one of the base model classes of the library
|
||||
when created with the when created with the :meth:`~transformers.AutoModel.from_pretrained` class method or the
|
||||
when created with the :meth:`~transformers.AutoModel.from_pretrained` class method or the
|
||||
:meth:`~transformers.AutoModel.from_config` class methods.
|
||||
|
||||
This class cannot be instantiated directly using ``__init__()`` (throws an error).
|
||||
|
||||
@@ -113,7 +113,7 @@ BART_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
decoder_input_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, target_sequence_length)`, `optional`):
|
||||
|
||||
@@ -667,7 +667,7 @@ BERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`({0})`, `optional`):
|
||||
@@ -781,7 +781,7 @@ class BertModel(BertPreTrainedModel):
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
"""
|
||||
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
||||
output_hidden_states = (
|
||||
@@ -1012,7 +1012,7 @@ class BertLMHeadModel(BertPreTrainedModel):
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||
Labels for computing the left-to-right language modeling loss (next word prediction).
|
||||
Indices should be in ``[-100, 0, ..., config.vocab_size]`` (see ``input_ids`` docstring)
|
||||
|
||||
@@ -218,7 +218,7 @@ BERT_GENERATION_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
position_ids (:obj:`torch.LongTensor` of shape :obj:`({0})`, `optional`):
|
||||
@@ -450,7 +450,7 @@ class BertGenerationDecoder(BertGenerationPreTrainedModel):
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||
Labels for computing the left-to-right language modeling loss (next word prediction).
|
||||
Indices should be in ``[-100, 0, ..., config.vocab_size]`` (see ``input_ids`` docstring)
|
||||
|
||||
@@ -273,7 +273,7 @@ CTRL_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||
|
||||
@@ -401,7 +401,7 @@ DISTILBERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
head_mask (:obj:`torch.FloatTensor` of shape :obj:`(num_heads,)` or :obj:`(num_layers, num_heads)`, `optional`):
|
||||
|
||||
@@ -358,7 +358,7 @@ DPR_ENCODERS_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||
@@ -403,7 +403,7 @@ DPR_READER_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
inputs_embeds (:obj:`torch.FloatTensor` of shape :obj:`(n_passages, sequence_length, hidden_size)`, `optional`):
|
||||
|
||||
@@ -611,7 +611,7 @@ ELECTRA_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -74,7 +74,7 @@ ENCODER_DECODER_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
decoder_input_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, target_sequence_length)`, `optional`):
|
||||
|
||||
@@ -81,7 +81,7 @@ FLAUBERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||
|
||||
@@ -224,7 +224,7 @@ FSMT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
decoder_input_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, target_sequence_length)`, `optional`):
|
||||
|
||||
@@ -857,7 +857,7 @@ FUNNEL_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -33,7 +33,11 @@ from .file_utils import (
|
||||
add_start_docstrings_to_callable,
|
||||
replace_return_docstrings,
|
||||
)
|
||||
from .modeling_outputs import BaseModelOutputWithPast, CausalLMOutputWithPast, SequenceClassifierOutputWithPast
|
||||
from .modeling_outputs import (
|
||||
BaseModelOutputWithPast,
|
||||
CausalLMOutputWithPast,
|
||||
SequenceClassifierOutputWithPast,
|
||||
)
|
||||
from .modeling_utils import (
|
||||
Conv1D,
|
||||
PreTrainedModel,
|
||||
@@ -42,6 +46,7 @@ from .modeling_utils import (
|
||||
prune_conv1d_layer,
|
||||
)
|
||||
from .utils import logging
|
||||
from .utils.model_parallel_utils import assert_device_map, get_device_map
|
||||
|
||||
|
||||
logger = logging.get_logger(__name__)
|
||||
@@ -124,7 +129,10 @@ class Attention(nn.Module):
|
||||
# [switch nx => n_state from Block to Attention to keep identical to TF implem]
|
||||
assert n_state % config.n_head == 0
|
||||
self.register_buffer(
|
||||
"bias", torch.tril(torch.ones((n_ctx, n_ctx), dtype=torch.uint8)).view(1, 1, n_ctx, n_ctx)
|
||||
"bias",
|
||||
torch.tril(torch.ones((n_ctx, n_ctx), dtype=torch.uint8)).view(
|
||||
1, 1, n_ctx, n_ctx
|
||||
),
|
||||
)
|
||||
self.register_buffer("masked_bias", torch.tensor(-1e4))
|
||||
self.n_head = config.n_head
|
||||
@@ -147,7 +155,9 @@ class Attention(nn.Module):
|
||||
heads, index = find_pruneable_heads_and_indices(
|
||||
heads, self.n_head, self.split_size // self.n_head, self.pruned_heads
|
||||
)
|
||||
index_attn = torch.cat([index, index + self.split_size, index + (2 * self.split_size)])
|
||||
index_attn = torch.cat(
|
||||
[index, index + self.split_size, index + (2 * self.split_size)]
|
||||
)
|
||||
|
||||
# Prune conv1d layers
|
||||
self.c_attn = prune_conv1d_layer(self.c_attn, index_attn, dim=1)
|
||||
@@ -158,7 +168,9 @@ class Attention(nn.Module):
|
||||
self.n_head = self.n_head - len(heads)
|
||||
self.pruned_heads = self.pruned_heads.union(heads)
|
||||
|
||||
def _attn(self, q, k, v, attention_mask=None, head_mask=None, output_attentions=False):
|
||||
def _attn(
|
||||
self, q, k, v, attention_mask=None, head_mask=None, output_attentions=False
|
||||
):
|
||||
w = torch.matmul(q, k)
|
||||
if self.scale:
|
||||
w = w / (float(v.size(-1)) ** 0.5)
|
||||
@@ -214,7 +226,9 @@ class Attention(nn.Module):
|
||||
self, "q_attn"
|
||||
), "If class is used as cross attention, the weights `q_attn` have to be defined. Please make sure to instantiate class with `Attention(..., is_cross_attention=True)`."
|
||||
query = self.q_attn(hidden_states)
|
||||
key, value = self.c_attn(encoder_hidden_states).split(self.split_size, dim=2)
|
||||
key, value = self.c_attn(encoder_hidden_states).split(
|
||||
self.split_size, dim=2
|
||||
)
|
||||
attention_mask = encoder_attention_mask
|
||||
else:
|
||||
query, key, value = self.c_attn(hidden_states).split(self.split_size, dim=2)
|
||||
@@ -223,16 +237,23 @@ class Attention(nn.Module):
|
||||
key = self.split_heads(key, k=True)
|
||||
value = self.split_heads(value)
|
||||
if layer_past is not None:
|
||||
past_key, past_value = layer_past[0].transpose(-2, -1), layer_past[1] # transpose back cf below
|
||||
past_key, past_value = (
|
||||
layer_past[0].transpose(-2, -1),
|
||||
layer_past[1],
|
||||
) # transpose back cf below
|
||||
key = torch.cat((past_key, key), dim=-1)
|
||||
value = torch.cat((past_value, value), dim=-2)
|
||||
|
||||
if use_cache is True:
|
||||
present = torch.stack((key.transpose(-2, -1), value)) # transpose to have same shapes for stacking
|
||||
present = torch.stack(
|
||||
(key.transpose(-2, -1), value)
|
||||
) # transpose to have same shapes for stacking
|
||||
else:
|
||||
present = (None,)
|
||||
|
||||
attn_outputs = self._attn(query, key, value, attention_mask, head_mask, output_attentions)
|
||||
attn_outputs = self._attn(
|
||||
query, key, value, attention_mask, head_mask, output_attentions
|
||||
)
|
||||
a = attn_outputs[0]
|
||||
|
||||
a = self.merge_heads(a)
|
||||
@@ -267,8 +288,12 @@ class Block(nn.Module):
|
||||
self.attn = Attention(hidden_size, n_ctx, config, scale)
|
||||
self.ln_2 = nn.LayerNorm(hidden_size, eps=config.layer_norm_epsilon)
|
||||
if config.add_cross_attention:
|
||||
self.crossattention = Attention(hidden_size, n_ctx, config, scale, is_cross_attention=True)
|
||||
self.ln_cross_attn = nn.LayerNorm(hidden_size, eps=config.layer_norm_epsilon)
|
||||
self.crossattention = Attention(
|
||||
hidden_size, n_ctx, config, scale, is_cross_attention=True
|
||||
)
|
||||
self.ln_cross_attn = nn.LayerNorm(
|
||||
hidden_size, eps=config.layer_norm_epsilon
|
||||
)
|
||||
self.mlp = MLP(inner_dim, config)
|
||||
|
||||
def forward(
|
||||
@@ -311,7 +336,9 @@ class Block(nn.Module):
|
||||
attn_output = cross_attn_outputs[0]
|
||||
# residual connection
|
||||
hidden_states = hidden_states + attn_output
|
||||
outputs = outputs + cross_attn_outputs[1:] # add cross attentions if we output attention weights
|
||||
outputs = (
|
||||
outputs + cross_attn_outputs[1:]
|
||||
) # add cross attentions if we output attention weights
|
||||
|
||||
feed_forward_hidden_states = self.mlp(self.ln_2(hidden_states))
|
||||
# residual connection
|
||||
@@ -429,7 +456,7 @@ GPT2_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, input_ids_length)`, `optional`):
|
||||
@@ -472,6 +499,48 @@ GPT2_INPUTS_DOCSTRING = r"""
|
||||
Whether or not to return a :class:`~transformers.file_utils.ModelOutput` instead of a plain tuple.
|
||||
"""
|
||||
|
||||
PARALLELIZE_DOCSTRING = r"""
|
||||
Uses a device map to distribute attention modules of the model across several devices. If no device map is given, it
|
||||
will evenly distribute blocks across all devices.
|
||||
Args:
|
||||
device_map (:obj:`Dict[int, list]`, optional, defaults to None):
|
||||
A dictionary that maps attention modules to devices. Note that the embedding module and LMHead are
|
||||
always automatically mapped to the first device (for esoteric reasons). That means that the first
|
||||
device should have fewer attention modules mapped to it than other devices.
|
||||
|
||||
For reference, the gpt2 models have the following number of attention modules:
|
||||
|
||||
- gpt2: 12
|
||||
- gpt2-medium: 24
|
||||
- gpt2-large: 36
|
||||
- gpt2-xl: 48
|
||||
|
||||
Example::
|
||||
Here is an example of a device map on a machine with 4 GPUs using gpt2-xl, which has a total of 48 attention modules:
|
||||
|
||||
model = GPT2LMHeadModel.from_pretrained('gpt2-xl')
|
||||
device_map = {0: [0, 1, 2, 3, 4, 5, 6, 7, 8],
|
||||
1: [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21],
|
||||
2: [22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34],
|
||||
3: [35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]}
|
||||
model.parallelize(device_map)
|
||||
"""
|
||||
|
||||
DEPARALLELIZE_DOCSTRING = r"""
|
||||
Moves the model to cpu from a model parallel state.
|
||||
|
||||
Example::
|
||||
On a 4 GPU machine with gpt2-large:
|
||||
|
||||
model = GPT2LMHeadModel.from_pretrained('gpt2-large')
|
||||
device_map = {0: [0, 1, 2, 3, 4, 5, 6, 7],
|
||||
1: [8, 9, 10, 11, 12, 13, 14, 15],
|
||||
2: [16, 17, 18, 19, 20, 21, 22, 23],
|
||||
3: [24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35]}
|
||||
model.parallelize(device_map) # Splits the model across several devices
|
||||
model.deparallelize() # Put the model back on cpu and cleans memory by calling torch.cuda.empty_cache()
|
||||
"""
|
||||
|
||||
|
||||
@add_start_docstrings(
|
||||
"The bare GPT2 Model transformer outputting raw hidden-states without any specific head on top.",
|
||||
@@ -484,11 +553,58 @@ class GPT2Model(GPT2PreTrainedModel):
|
||||
self.wte = nn.Embedding(config.vocab_size, config.n_embd)
|
||||
self.wpe = nn.Embedding(config.n_positions, config.n_embd)
|
||||
self.drop = nn.Dropout(config.embd_pdrop)
|
||||
self.h = nn.ModuleList([Block(config.n_ctx, config, scale=True) for _ in range(config.n_layer)])
|
||||
self.h = nn.ModuleList(
|
||||
[Block(config.n_ctx, config, scale=True) for _ in range(config.n_layer)]
|
||||
)
|
||||
self.ln_f = nn.LayerNorm(config.n_embd, eps=config.layer_norm_epsilon)
|
||||
|
||||
self.init_weights()
|
||||
|
||||
# Model parallel
|
||||
self.model_parallel = False
|
||||
self.device_map = None
|
||||
|
||||
@add_start_docstrings(PARALLELIZE_DOCSTRING)
|
||||
def parallelize(self, device_map=None):
|
||||
# Check validity of device_map
|
||||
self.device_map = (
|
||||
get_device_map(len(self.h), range(torch.cuda.device_count()))
|
||||
if device_map is None
|
||||
else device_map
|
||||
)
|
||||
assert_device_map(self.device_map, len(self.h))
|
||||
|
||||
self.model_parallel = True
|
||||
self.first_device = (
|
||||
"cpu"
|
||||
if "cpu" in self.device_map.keys()
|
||||
else "cuda:" + str(min(self.device_map.keys()))
|
||||
)
|
||||
self.last_device = "cuda:" + str(max(self.device_map.keys()))
|
||||
self.wte = self.wte.to(self.first_device)
|
||||
self.wpe = self.wpe.to(self.first_device)
|
||||
# Load onto devices
|
||||
for k, v in self.device_map.items():
|
||||
for block in v:
|
||||
cuda_device = "cuda:" + str(k)
|
||||
self.h[block] = self.h[block].to(cuda_device)
|
||||
# ln_f to last
|
||||
self.ln_f = self.ln_f.to(self.last_device)
|
||||
|
||||
@add_start_docstrings(DEPARALLELIZE_DOCSTRING)
|
||||
def deparallelize(self):
|
||||
self.model_parallel = False
|
||||
self.device_map = None
|
||||
self.first_device = "cpu"
|
||||
self.last_device = "cpu"
|
||||
self.wte = self.wte.to("cpu")
|
||||
self.wpe = self.wpe.to("cpu")
|
||||
for index in range(len(self.h)):
|
||||
self.h[index] = self.h[index].to("cpu")
|
||||
|
||||
self.ln_f = self.ln_f.to("cpu")
|
||||
torch.cuda.empty_cache()
|
||||
|
||||
def get_input_embeddings(self):
|
||||
return self.wte
|
||||
|
||||
@@ -534,15 +650,25 @@ class GPT2Model(GPT2PreTrainedModel):
|
||||
past_key_values = kwargs.pop("past")
|
||||
assert kwargs == {}, f"Unexpected keyword arguments: {list(kwargs.keys())}."
|
||||
|
||||
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
||||
output_attentions = (
|
||||
output_attentions
|
||||
if output_attentions is not None
|
||||
else self.config.output_attentions
|
||||
)
|
||||
output_hidden_states = (
|
||||
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
||||
output_hidden_states
|
||||
if output_hidden_states is not None
|
||||
else self.config.output_hidden_states
|
||||
)
|
||||
use_cache = use_cache if use_cache is not None else self.config.use_cache
|
||||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||||
return_dict = (
|
||||
return_dict if return_dict is not None else self.config.use_return_dict
|
||||
)
|
||||
|
||||
if input_ids is not None and inputs_embeds is not None:
|
||||
raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
|
||||
raise ValueError(
|
||||
"You cannot specify both input_ids and inputs_embeds at the same time"
|
||||
)
|
||||
elif input_ids is not None:
|
||||
input_shape = input_ids.size()
|
||||
input_ids = input_ids.view(-1, input_shape[-1])
|
||||
@@ -565,7 +691,12 @@ class GPT2Model(GPT2PreTrainedModel):
|
||||
past_length = past_key_values[0][0].size(-2)
|
||||
if position_ids is None:
|
||||
device = input_ids.device if input_ids is not None else inputs_embeds.device
|
||||
position_ids = torch.arange(past_length, input_shape[-1] + past_length, dtype=torch.long, device=device)
|
||||
position_ids = torch.arange(
|
||||
past_length,
|
||||
input_shape[-1] + past_length,
|
||||
dtype=torch.long,
|
||||
device=device,
|
||||
)
|
||||
position_ids = position_ids.unsqueeze(0).view(-1, input_shape[-1])
|
||||
|
||||
# Attention mask.
|
||||
@@ -584,13 +715,17 @@ class GPT2Model(GPT2PreTrainedModel):
|
||||
# positions we want to attend and -10000.0 for masked positions.
|
||||
# Since we are adding it to the raw scores before the softmax, this is
|
||||
# effectively the same as removing these entirely.
|
||||
attention_mask = attention_mask.to(dtype=next(self.parameters()).dtype) # fp16 compatibility
|
||||
attention_mask = attention_mask.to(dtype=self.dtype) # fp16 compatibility
|
||||
attention_mask = (1.0 - attention_mask) * -10000.0
|
||||
|
||||
# If a 2D ou 3D attention mask is provided for the cross-attention
|
||||
# we need to make broadcastabe to [batch_size, num_heads, seq_length, seq_length]
|
||||
if self.config.add_cross_attention and encoder_hidden_states is not None:
|
||||
encoder_batch_size, encoder_sequence_length, _ = encoder_hidden_states.size()
|
||||
(
|
||||
encoder_batch_size,
|
||||
encoder_sequence_length,
|
||||
_,
|
||||
) = encoder_hidden_states.size()
|
||||
encoder_hidden_shape = (encoder_batch_size, encoder_sequence_length)
|
||||
if encoder_attention_mask is None:
|
||||
encoder_attention_mask = torch.ones(encoder_hidden_shape, device=device)
|
||||
@@ -620,15 +755,33 @@ class GPT2Model(GPT2PreTrainedModel):
|
||||
all_attentions = () if output_attentions else None
|
||||
all_hidden_states = () if output_hidden_states else None
|
||||
for i, (block, layer_past) in enumerate(zip(self.h, past_key_values)):
|
||||
# Model parallel
|
||||
if self.model_parallel:
|
||||
torch.cuda.set_device(hidden_states.device)
|
||||
# Ensure layer_past is on same device as hidden_states (might not be correct)
|
||||
if layer_past is not None:
|
||||
layer_past = layer_past.to(hidden_states.device)
|
||||
# Ensure that attention_mask is always on the same device as hidden_states
|
||||
if attention_mask is not None:
|
||||
attention_mask = attention_mask.to(hidden_states.device)
|
||||
|
||||
if isinstance(head_mask, torch.Tensor):
|
||||
head_mask = head_mask.to(hidden_states.device)
|
||||
|
||||
if output_hidden_states:
|
||||
all_hidden_states = all_hidden_states + (hidden_states.view(*output_shape),)
|
||||
all_hidden_states = all_hidden_states + (
|
||||
hidden_states.view(*output_shape),
|
||||
)
|
||||
|
||||
if getattr(self.config, "gradient_checkpointing", False):
|
||||
|
||||
def create_custom_forward(module):
|
||||
def custom_forward(*inputs):
|
||||
# checkpointing only works with tuple returns, not with lists
|
||||
return tuple(output for output in module(*inputs, use_cache, output_attentions))
|
||||
return tuple(
|
||||
output
|
||||
for output in module(*inputs, use_cache, output_attentions)
|
||||
)
|
||||
|
||||
return custom_forward
|
||||
|
||||
@@ -660,6 +813,12 @@ class GPT2Model(GPT2PreTrainedModel):
|
||||
if output_attentions:
|
||||
all_attentions = all_attentions + (outputs[2],)
|
||||
|
||||
# Model Parallel: If it's the last layer for that device, put things on the next device
|
||||
if self.model_parallel:
|
||||
for k, v in self.device_map.items():
|
||||
if i == v[-1] and "cuda:" + str(k) != self.last_device:
|
||||
hidden_states = hidden_states.to("cuda:" + str(k + 1))
|
||||
|
||||
hidden_states = self.ln_f(hidden_states)
|
||||
|
||||
hidden_states = hidden_states.view(*output_shape)
|
||||
@@ -668,7 +827,11 @@ class GPT2Model(GPT2PreTrainedModel):
|
||||
all_hidden_states = all_hidden_states + (hidden_states,)
|
||||
|
||||
if not return_dict:
|
||||
return tuple(v for v in [hidden_states, presents, all_hidden_states, all_attentions] if v is not None)
|
||||
return tuple(
|
||||
v
|
||||
for v in [hidden_states, presents, all_hidden_states, all_attentions]
|
||||
if v is not None
|
||||
)
|
||||
|
||||
return BaseModelOutputWithPast(
|
||||
last_hidden_state=hidden_states,
|
||||
@@ -693,6 +856,29 @@ class GPT2LMHeadModel(GPT2PreTrainedModel):
|
||||
|
||||
self.init_weights()
|
||||
|
||||
self.model_parallel = False
|
||||
|
||||
@add_start_docstrings(PARALLELIZE_DOCSTRING)
|
||||
def parallelize(self, device_map=None):
|
||||
self.device_map = (
|
||||
get_device_map(len(self.transformer.h), range(torch.cuda.device_count()))
|
||||
if device_map is None
|
||||
else device_map
|
||||
)
|
||||
assert_device_map(self.device_map, len(self.transformer.h))
|
||||
|
||||
self.transformer.parallelize(self.device_map)
|
||||
self.lm_head = self.lm_head.to(self.transformer.first_device)
|
||||
self.model_parallel = True
|
||||
|
||||
@add_start_docstrings(DEPARALLELIZE_DOCSTRING)
|
||||
def deparallelize(self):
|
||||
self.transformer.deparallelize()
|
||||
self.transformer = self.transformer.to("cpu")
|
||||
self.lm_head = self.lm_head.to("cpu")
|
||||
self.model_parallel = False
|
||||
torch.cuda.empty_cache()
|
||||
|
||||
def get_output_embeddings(self):
|
||||
return self.lm_head
|
||||
|
||||
@@ -747,7 +933,9 @@ class GPT2LMHeadModel(GPT2PreTrainedModel):
|
||||
)
|
||||
past_key_values = kwargs.pop("past")
|
||||
assert kwargs == {}, f"Unexpected keyword arguments: {list(kwargs.keys())}."
|
||||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||||
return_dict = (
|
||||
return_dict if return_dict is not None else self.config.use_return_dict
|
||||
)
|
||||
|
||||
transformer_outputs = self.transformer(
|
||||
input_ids,
|
||||
@@ -766,6 +954,11 @@ class GPT2LMHeadModel(GPT2PreTrainedModel):
|
||||
)
|
||||
hidden_states = transformer_outputs[0]
|
||||
|
||||
# Set device for model parallelism
|
||||
if self.model_parallel:
|
||||
torch.cuda.set_device(self.transformer.first_device)
|
||||
hidden_states = hidden_states.to(self.lm_head.weight.device)
|
||||
|
||||
lm_logits = self.lm_head(hidden_states)
|
||||
|
||||
loss = None
|
||||
@@ -775,7 +968,9 @@ class GPT2LMHeadModel(GPT2PreTrainedModel):
|
||||
shift_labels = labels[..., 1:].contiguous()
|
||||
# Flatten the tokens
|
||||
loss_fct = CrossEntropyLoss()
|
||||
loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1))
|
||||
loss = loss_fct(
|
||||
shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1)
|
||||
)
|
||||
|
||||
if not return_dict:
|
||||
output = (lm_logits,) + transformer_outputs[1:]
|
||||
@@ -823,7 +1018,9 @@ class GPT2DoubleHeadsModel(GPT2PreTrainedModel):
|
||||
}
|
||||
|
||||
@add_start_docstrings_to_callable(GPT2_INPUTS_DOCSTRING)
|
||||
@replace_return_docstrings(output_type=GPT2DoubleHeadsModelOutput, config_class=_CONFIG_FOR_DOC)
|
||||
@replace_return_docstrings(
|
||||
output_type=GPT2DoubleHeadsModelOutput, config_class=_CONFIG_FOR_DOC
|
||||
)
|
||||
def forward(
|
||||
self,
|
||||
input_ids=None,
|
||||
@@ -899,7 +1096,9 @@ class GPT2DoubleHeadsModel(GPT2PreTrainedModel):
|
||||
)
|
||||
past_key_values = kwargs.pop("past")
|
||||
assert kwargs == {}, f"Unexpected keyword arguments: {list(kwargs.keys())}."
|
||||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||||
return_dict = (
|
||||
return_dict if return_dict is not None else self.config.use_return_dict
|
||||
)
|
||||
|
||||
transformer_outputs = self.transformer(
|
||||
input_ids,
|
||||
@@ -923,13 +1122,17 @@ class GPT2DoubleHeadsModel(GPT2PreTrainedModel):
|
||||
mc_loss = None
|
||||
if mc_labels is not None:
|
||||
loss_fct = CrossEntropyLoss()
|
||||
mc_loss = loss_fct(mc_logits.view(-1, mc_logits.size(-1)), mc_labels.view(-1))
|
||||
mc_loss = loss_fct(
|
||||
mc_logits.view(-1, mc_logits.size(-1)), mc_labels.view(-1)
|
||||
)
|
||||
lm_loss = None
|
||||
if labels is not None:
|
||||
shift_logits = lm_logits[..., :-1, :].contiguous()
|
||||
shift_labels = labels[..., 1:].contiguous()
|
||||
loss_fct = CrossEntropyLoss()
|
||||
lm_loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1))
|
||||
lm_loss = loss_fct(
|
||||
shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1)
|
||||
)
|
||||
|
||||
if not return_dict:
|
||||
output = (lm_logits, mc_logits) + transformer_outputs[1:]
|
||||
@@ -1003,7 +1206,9 @@ class GPT2ForSequenceClassification(GPT2PreTrainedModel):
|
||||
If :obj:`config.num_labels == 1` a regression loss is computed (Mean-Square loss),
|
||||
If :obj:`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
||||
"""
|
||||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||||
return_dict = (
|
||||
return_dict if return_dict is not None else self.config.use_return_dict
|
||||
)
|
||||
|
||||
transformer_outputs = self.transformer(
|
||||
input_ids,
|
||||
@@ -1033,7 +1238,9 @@ class GPT2ForSequenceClassification(GPT2PreTrainedModel):
|
||||
sequence_lengths = -1
|
||||
else:
|
||||
if input_ids is not None:
|
||||
sequence_lengths = torch.ne(input_ids, self.config.pad_token_id).sum(-1) - 1
|
||||
sequence_lengths = (
|
||||
torch.ne(input_ids, self.config.pad_token_id).sum(-1) - 1
|
||||
)
|
||||
else:
|
||||
sequence_lengths = -1
|
||||
logger.warning(
|
||||
@@ -1051,7 +1258,9 @@ class GPT2ForSequenceClassification(GPT2PreTrainedModel):
|
||||
loss = loss_fct(pooled_logits.view(-1), labels.view(-1))
|
||||
else:
|
||||
loss_fct = CrossEntropyLoss()
|
||||
loss = loss_fct(pooled_logits.view(-1, self.num_labels), labels.view(-1))
|
||||
loss = loss_fct(
|
||||
pooled_logits.view(-1, self.num_labels), labels.view(-1)
|
||||
)
|
||||
|
||||
if not return_dict:
|
||||
output = (pooled_logits,) + transformer_outputs[1:]
|
||||
|
||||
@@ -1018,7 +1018,7 @@ LONGFORMER_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
global_attention_mask (:obj:`torch.FloatTensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -848,7 +848,7 @@ LXMERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
visual_attention_mask (:obj:`torch.FloatTensor` of shape :obj:`({0})`, `optional`):
|
||||
@@ -856,7 +856,7 @@ LXMERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -123,7 +123,7 @@ MMBT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (`optional`) ``torch.LongTensor`` of shape ``(batch_size, sequence_length)``:
|
||||
@@ -167,7 +167,7 @@ MMBT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
output_attentions (:obj:`bool`, `optional`):
|
||||
Whether or not to return the attentions tensors of all attention layers. See ``attentions`` under returned
|
||||
|
||||
@@ -756,7 +756,7 @@ MOBILEBERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`({0})`, `optional`):
|
||||
@@ -792,7 +792,7 @@ MOBILEBERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
output_attentions (:obj:`bool`, `optional`):
|
||||
Whether or not to return the attentions tensors of all attention layers. See ``attentions`` under returned
|
||||
|
||||
@@ -25,7 +25,7 @@ from typing import Optional, Tuple
|
||||
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
from torch.nn import CrossEntropyLoss
|
||||
from torch.nn import CrossEntropyLoss, MSELoss
|
||||
|
||||
from .activations import gelu_new, swish
|
||||
from .configuration_openai import OpenAIGPTConfig
|
||||
@@ -36,7 +36,7 @@ from .file_utils import (
|
||||
add_start_docstrings_to_callable,
|
||||
replace_return_docstrings,
|
||||
)
|
||||
from .modeling_outputs import BaseModelOutput, CausalLMOutput
|
||||
from .modeling_outputs import BaseModelOutput, CausalLMOutput, SequenceClassifierOutput
|
||||
from .modeling_utils import (
|
||||
Conv1D,
|
||||
PreTrainedModel,
|
||||
@@ -360,7 +360,7 @@ OPENAI_GPT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||
@@ -732,3 +732,113 @@ class OpenAIGPTDoubleHeadsModel(OpenAIGPTPreTrainedModel):
|
||||
hidden_states=transformer_outputs.hidden_states,
|
||||
attentions=transformer_outputs.attentions,
|
||||
)
|
||||
|
||||
|
||||
@add_start_docstrings(
|
||||
"""The Original OpenAI GPT Model transformer with a sequence classification head on top
|
||||
(linear layer).
|
||||
:class:`~transformers.OpenAIGPTForSequenceClassification` uses the last token in order to do the classification, as
|
||||
other causal models (e.g. GPT-2) do.
|
||||
Since it does classification on the last token, it requires to know the position of the last token.
|
||||
If a :obj:`pad_token_id` is defined in the configuration, it finds the last token that is not a padding token
|
||||
in each row. If no :obj:`pad_token_id` is defined, it simply takes the last value in each row of the batch.
|
||||
Since it cannot guess the padding tokens when :obj:`inputs_embeds` are passed instead of :obj:`input_ids`, it
|
||||
does the same (take the last value in each row of the batch).
|
||||
""",
|
||||
OPENAI_GPT_START_DOCSTRING,
|
||||
)
|
||||
class OpenAIGPTForSequenceClassification(OpenAIGPTPreTrainedModel):
|
||||
def __init__(self, config):
|
||||
super().__init__(config)
|
||||
self.num_labels = config.num_labels
|
||||
self.transformer = OpenAIGPTModel(config)
|
||||
self.score = nn.Linear(config.n_embd, self.num_labels, bias=False)
|
||||
|
||||
self.init_weights()
|
||||
|
||||
@add_start_docstrings_to_callable(OPENAI_GPT_INPUTS_DOCSTRING)
|
||||
@add_code_sample_docstrings(
|
||||
tokenizer_class=_TOKENIZER_FOR_DOC,
|
||||
checkpoint="openai-gpt",
|
||||
output_type=SequenceClassifierOutput,
|
||||
config_class=_CONFIG_FOR_DOC,
|
||||
)
|
||||
def forward(
|
||||
self,
|
||||
input_ids=None,
|
||||
attention_mask=None,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
head_mask=None,
|
||||
inputs_embeds=None,
|
||||
labels=None,
|
||||
output_attentions=None,
|
||||
output_hidden_states=None,
|
||||
return_dict=None,
|
||||
):
|
||||
r"""
|
||||
labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size,)`, `optional`):
|
||||
Labels for computing the sequence classification/regression loss.
|
||||
Indices should be in :obj:`[0, ..., config.num_labels - 1]`.
|
||||
If :obj:`config.num_labels == 1` a regression loss is computed (Mean-Square loss),
|
||||
If :obj:`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
||||
"""
|
||||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||||
|
||||
transformer_outputs = self.transformer(
|
||||
input_ids,
|
||||
attention_mask=attention_mask,
|
||||
token_type_ids=token_type_ids,
|
||||
position_ids=position_ids,
|
||||
head_mask=head_mask,
|
||||
inputs_embeds=inputs_embeds,
|
||||
output_attentions=output_attentions,
|
||||
output_hidden_states=output_hidden_states,
|
||||
return_dict=return_dict,
|
||||
)
|
||||
|
||||
hidden_states = transformer_outputs[0]
|
||||
logits = self.score(hidden_states)
|
||||
|
||||
if input_ids is not None:
|
||||
batch_size, sequence_length = input_ids.shape[:2]
|
||||
else:
|
||||
batch_size, sequence_length = inputs_embeds.shape[:2]
|
||||
|
||||
assert (
|
||||
self.config.pad_token_id is not None or batch_size == 1
|
||||
), "Cannot handle batch sizes > 1 if no padding token is defined."
|
||||
if self.config.pad_token_id is None:
|
||||
sequence_lengths = -1
|
||||
else:
|
||||
if input_ids is not None:
|
||||
sequence_lengths = torch.ne(input_ids, self.config.pad_token_id).sum(-1) - 1
|
||||
else:
|
||||
sequence_lengths = -1
|
||||
logger.warning(
|
||||
f"{self.__class__.__name__} will not detect padding tokens in `inputs_embeds`. Results may be "
|
||||
f"unexpected if using padding tokens in conjuction with `inputs_embeds.`"
|
||||
)
|
||||
|
||||
pooled_logits = logits[range(batch_size), sequence_lengths]
|
||||
|
||||
loss = None
|
||||
if labels is not None:
|
||||
if self.num_labels == 1:
|
||||
# We are doing regression
|
||||
loss_fct = MSELoss()
|
||||
loss = loss_fct(pooled_logits.view(-1), labels.view(-1))
|
||||
else:
|
||||
loss_fct = CrossEntropyLoss()
|
||||
loss = loss_fct(pooled_logits.view(-1, self.num_labels), labels.view(-1))
|
||||
|
||||
if not return_dict:
|
||||
output = (pooled_logits,) + transformer_outputs[1:]
|
||||
return ((loss,) + output) if loss is not None else output
|
||||
|
||||
return SequenceClassifierOutput(
|
||||
loss=loss,
|
||||
logits=pooled_logits,
|
||||
hidden_states=transformer_outputs.hidden_states,
|
||||
attentions=transformer_outputs.attentions,
|
||||
)
|
||||
|
||||
@@ -406,7 +406,7 @@ RAG_FORWARD_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
encoder_outputs (:obj:`tuple(tuple(torch.FloatTensor)`, `optional`)
|
||||
@@ -836,7 +836,7 @@ class RagSequenceForGeneration(RagPreTrainedModel):
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
context_input_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size * config.n_docs, config.max_combined_length)`, `optional`, returned when `output_retrieved=True`):
|
||||
@@ -1221,7 +1221,7 @@ class RagTokenForGeneration(RagPreTrainedModel):
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
context_input_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size * config.n_docs, config.max_combined_length)`, `optional`, returned when `output_retrieved=True`):
|
||||
|
||||
@@ -1926,7 +1926,7 @@ REFORMER_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
position_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||
|
||||
@@ -185,7 +185,7 @@ class RetriBertModel(RetriBertPreTrainedModel):
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
input_ids_doc (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`):
|
||||
|
||||
@@ -506,7 +506,7 @@ ROBERTA_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -461,7 +461,7 @@ SQUEEZEBERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -36,6 +36,7 @@ from .file_utils import (
|
||||
from .modeling_outputs import BaseModelOutput, BaseModelOutputWithPast, Seq2SeqLMOutput, Seq2SeqModelOutput
|
||||
from .modeling_utils import PreTrainedModel, find_pruneable_heads_and_indices, prune_linear_layer
|
||||
from .utils import logging
|
||||
from .utils.model_parallel_utils import assert_device_map, get_device_map
|
||||
|
||||
|
||||
logger = logging.get_logger(__name__)
|
||||
@@ -151,7 +152,48 @@ def load_tf_weights_in_t5(model, config, tf_checkpoint_path):
|
||||
# - torch.nn.Module for the layers and
|
||||
# - PreTrainedModel for the models (it-self a sub-class of torch.nn.Module)
|
||||
####################################################
|
||||
PARALLELIZE_DOCSTRING = r"""
|
||||
Uses a device map to distribute attention modules of the model across several devices. If no device map is given, it
|
||||
will evenly distribute blocks across all devices.
|
||||
Args:
|
||||
device_map (:obj:`Dict[int, list]`, optional, defaults to None):
|
||||
A dictionary that maps attention modules to devices. Note that the embedding module and LMHead are
|
||||
always automatically mapped to the first device (for esoteric reasons). That means that the first
|
||||
device should have fewer attention modules mapped to it than other devices.
|
||||
|
||||
For reference, the t5 models have the following number of attention modules:
|
||||
|
||||
- t5-small: 6
|
||||
- t5-base: 12
|
||||
- t5-large: 24
|
||||
- t5-3b: 24
|
||||
- t5-11b: 24
|
||||
|
||||
Example::
|
||||
Here is an example of a device map on a machine with 4 GPUs using t5-3b, which has a total of 24 attention modules:
|
||||
|
||||
model = T5ForConditionalGeneration.from_pretrained('t5-3b')
|
||||
device_map = {0: [0, 1, 2],
|
||||
1: [3, 4, 5, 6, 7, 8, 9],
|
||||
2: [10, 11, 12, 13, 14, 15, 16],
|
||||
3: [17, 18, 19, 20, 21, 22, 23]}
|
||||
model.parallelize(device_map)
|
||||
"""
|
||||
|
||||
DEPARALLELIZE_DOCSTRING = r"""
|
||||
Moves the model to cpu from a model parallel state.
|
||||
|
||||
Example::
|
||||
On a 4 GPU machine with t5-3b:
|
||||
|
||||
model = T5ForConditionalGeneration.from_pretrained('t5-3b')
|
||||
device_map = {0: [0, 1, 2],
|
||||
1: [3, 4, 5, 6, 7, 8, 9],
|
||||
2: [10, 11, 12, 13, 14, 15, 16],
|
||||
3: [17, 18, 19, 20, 21, 22, 23]}
|
||||
model.parallelize(device_map) # Splits the model across several devices
|
||||
model.deparallelize() # Put the model back on cpu and cleans memory by calling torch.cuda.empty_cache()
|
||||
"""
|
||||
|
||||
class T5LayerNorm(nn.Module):
|
||||
def __init__(self, hidden_size, eps=1e-6):
|
||||
@@ -661,6 +703,43 @@ class T5Stack(T5PreTrainedModel):
|
||||
|
||||
self.init_weights()
|
||||
|
||||
# Model parallel
|
||||
self.model_parallel = False
|
||||
self.device_map = None
|
||||
|
||||
@add_start_docstrings(PARALLELIZE_DOCSTRING)
|
||||
def parallelize(self, device_map=None):
|
||||
# Check validity of device_map
|
||||
self.device_map = get_device_map(len(self.block), torch.cuda.device_count()) if device_map is None else device_map
|
||||
assert_device_map(self.device_map, len(self.block))
|
||||
|
||||
self.model_parallel = True
|
||||
self.first_device = "cpu" if "cpu" in self.device_map.keys() else "cuda:" + str(min(self.device_map.keys()))
|
||||
self.last_device = "cuda:" + str(max(self.device_map.keys()))
|
||||
# Load onto devices
|
||||
for k, v in self.device_map.items():
|
||||
for layer in v:
|
||||
cuda_device = "cuda:" + str(k)
|
||||
self.block[layer] = self.block[layer].to(cuda_device)
|
||||
|
||||
# Set embed_tokens to first layer
|
||||
self.embed_tokens = self.embed_tokens.to(self.first_device)
|
||||
|
||||
# Set final layer norm to last device
|
||||
self.final_layer_norm = self.final_layer_norm.to(self.last_device)
|
||||
|
||||
@add_start_docstrings(PARALLELIZE_DOCSTRING)
|
||||
def deparallelize(self):
|
||||
self.model_parallel = False
|
||||
self.device_map = None
|
||||
self.first_device = "cpu"
|
||||
self.last_device = "cpu"
|
||||
for i in range(len(self.block)):
|
||||
self.block[i] = self.block[i].to("cpu")
|
||||
self.embed_tokens = self.embed_tokens.to("cpu")
|
||||
self.final_layer_norm = self.final_layer_norm.to("cpu")
|
||||
torch.cuda.empty_cache()
|
||||
|
||||
def get_input_embeddings(self):
|
||||
return self.embed_tokens
|
||||
|
||||
@@ -684,15 +763,19 @@ class T5Stack(T5PreTrainedModel):
|
||||
output_hidden_states=None,
|
||||
return_dict=None,
|
||||
):
|
||||
|
||||
# # Model parallel
|
||||
if self.model_parallel:
|
||||
torch.cuda.set_device(self.first_device)
|
||||
self.embed_tokens = self.embed_tokens.to(self.first_device)
|
||||
use_cache = use_cache if use_cache is not None else self.config.use_cache
|
||||
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
||||
output_hidden_states = (
|
||||
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
||||
)
|
||||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||||
|
||||
|
||||
if input_ids is not None and inputs_embeds is not None:
|
||||
|
||||
err_msg_prefix = "decoder_" if self.is_decoder else ""
|
||||
raise ValueError(
|
||||
f"You cannot specify both {err_msg_prefix}inputs and {err_msg_prefix}inputs_embeds at the same time"
|
||||
@@ -705,7 +788,6 @@ class T5Stack(T5PreTrainedModel):
|
||||
else:
|
||||
err_msg_prefix = "decoder_" if self.is_decoder else ""
|
||||
raise ValueError(f"You have to specify either {err_msg_prefix}inputs or {err_msg_prefix}inputs_embeds")
|
||||
|
||||
if inputs_embeds is None:
|
||||
assert self.embed_tokens is not None, "You have to intialize the model with valid token embeddings"
|
||||
inputs_embeds = self.embed_tokens(input_ids)
|
||||
@@ -719,7 +801,6 @@ class T5Stack(T5PreTrainedModel):
|
||||
assert self.is_decoder, ":obj:`use_cache` can only be set to `True` if {} is used as a decoder".format(
|
||||
self
|
||||
)
|
||||
|
||||
if attention_mask is None:
|
||||
attention_mask = torch.ones(batch_size, mask_seq_length).to(inputs_embeds.device)
|
||||
if self.is_decoder and encoder_attention_mask is None and encoder_hidden_states is not None:
|
||||
@@ -727,7 +808,6 @@ class T5Stack(T5PreTrainedModel):
|
||||
encoder_attention_mask = torch.ones(
|
||||
batch_size, encoder_seq_length, device=inputs_embeds.device, dtype=torch.long
|
||||
)
|
||||
|
||||
# initialize past_key_values with `None` if past does not exist
|
||||
if past_key_values is None:
|
||||
past_key_values = [None] * len(self.block)
|
||||
@@ -751,6 +831,21 @@ class T5Stack(T5PreTrainedModel):
|
||||
hidden_states = self.dropout(inputs_embeds)
|
||||
|
||||
for i, (layer_module, past_key_value) in enumerate(zip(self.block, past_key_values)):
|
||||
# Model parallel
|
||||
if self.model_parallel:
|
||||
torch.cuda.set_device(hidden_states.device)
|
||||
# Ensure that attention_mask is always on the same device as hidden_states
|
||||
if attention_mask is not None:
|
||||
attention_mask = attention_mask.to(hidden_states.device)
|
||||
if position_bias is not None:
|
||||
position_bias = position_bias.to(hidden_states.device)
|
||||
if encoder_hidden_states is not None:
|
||||
encoder_hidden_states = encoder_hidden_states.to(hidden_states.device)
|
||||
if encoder_extended_attention_mask is not None:
|
||||
encoder_extended_attention_mask = encoder_extended_attention_mask.to(hidden_states.device)
|
||||
if encoder_decoder_position_bias is not None:
|
||||
encoder_decoder_position_bias = encoder_decoder_position_bias.to(hidden_states.device)
|
||||
|
||||
if output_hidden_states:
|
||||
all_hidden_states = all_hidden_states + (hidden_states,)
|
||||
|
||||
@@ -782,6 +877,11 @@ class T5Stack(T5PreTrainedModel):
|
||||
|
||||
if output_attentions:
|
||||
all_attentions = all_attentions + (layer_outputs[2],) # We keep only self-attention weights for now
|
||||
# Model Parallel: If it's the last layer for that device, put things on the next device
|
||||
if self.model_parallel:
|
||||
for k, v in self.device_map.items():
|
||||
if i == v[-1] and "cuda:" + str(k) != self.last_device:
|
||||
hidden_states = hidden_states.to("cuda:" + str(k + 1))
|
||||
|
||||
hidden_states = self.final_layer_norm(hidden_states)
|
||||
hidden_states = self.dropout(hidden_states)
|
||||
@@ -843,7 +943,7 @@ T5_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
decoder_input_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, target_sequence_length)`, `optional`):
|
||||
@@ -904,7 +1004,6 @@ T5_INPUTS_DOCSTRING = r"""
|
||||
Whether or not to return a :class:`~transformers.file_utils.ModelOutput` instead of a plain tuple.
|
||||
"""
|
||||
|
||||
|
||||
@add_start_docstrings(
|
||||
"The bare T5 Model transformer outputting raw hidden-states" "without any specific head on top.",
|
||||
T5_START_DOCSTRING,
|
||||
@@ -927,6 +1026,32 @@ class T5Model(T5PreTrainedModel):
|
||||
|
||||
self.init_weights()
|
||||
|
||||
# Model parallel
|
||||
self.model_parallel = False
|
||||
self.device_map = None
|
||||
|
||||
@add_start_docstrings(PARALLELIZE_DOCSTRING)
|
||||
def parallelize(self, device_map=None):
|
||||
|
||||
self.device_map = (
|
||||
get_device_map(len(self.encoder.block), range(torch.cuda.device_count())) if device_map is None else device_map
|
||||
)
|
||||
assert_device_map(self.device_map, len(self.encoder.block))
|
||||
|
||||
self.encoder.parallelize(self.device_map)
|
||||
self.decoder.parallelize(self.device_map)
|
||||
self.model_parallel = True
|
||||
|
||||
@add_start_docstrings(DEPARALLELIZE_DOCSTRING)
|
||||
def deparallelize(self):
|
||||
self.encoder.deparallelize()
|
||||
self.decoder.deparallelize()
|
||||
self.encoder = self.encoder.to("cpu")
|
||||
self.decoder = self.decoder.to("cpu")
|
||||
self.model_parallel = False
|
||||
self.device_map = None
|
||||
torch.cuda.empty_cache()
|
||||
|
||||
def get_input_embeddings(self):
|
||||
return self.shared
|
||||
|
||||
@@ -1020,6 +1145,19 @@ class T5Model(T5PreTrainedModel):
|
||||
)
|
||||
|
||||
hidden_states = encoder_outputs[0]
|
||||
if self.model_parallel:
|
||||
torch.cuda.set_device(self.decoder.first_device)
|
||||
|
||||
# Set device for model parallelism
|
||||
if self.model_parallel:
|
||||
torch.cuda.set_device(self.decoder.first_device)
|
||||
hidden_states = hidden_states.to(self.decoder.first_device)
|
||||
if decoder_input_ids is not None:
|
||||
decoder_input_ids = decoder_input_ids.to(self.decoder.first_device)
|
||||
if attention_mask is not None:
|
||||
attention_mask = attention_mask.to(self.decoder.first_device)
|
||||
if decoder_attention_mask is not None:
|
||||
decoder_attention_mask = decoder_attention_mask.to(self.decoder.first_device)
|
||||
|
||||
# Decode
|
||||
decoder_outputs = self.decoder(
|
||||
@@ -1075,6 +1213,34 @@ class T5ForConditionalGeneration(T5PreTrainedModel):
|
||||
|
||||
self.init_weights()
|
||||
|
||||
# Model parallel
|
||||
self.model_parallel = False
|
||||
self.device_map = None
|
||||
|
||||
@add_start_docstrings(PARALLELIZE_DOCSTRING)
|
||||
def parallelize(self, device_map=None):
|
||||
|
||||
self.device_map = (
|
||||
get_device_map(len(self.encoder.block), range(torch.cuda.device_count())) if device_map is None else device_map
|
||||
)
|
||||
assert_device_map(self.device_map, len(self.encoder.block))
|
||||
|
||||
self.encoder.parallelize(self.device_map)
|
||||
self.decoder.parallelize(self.device_map)
|
||||
self.lm_head = self.lm_head.to(self.decoder.first_device)
|
||||
self.model_parallel = True
|
||||
|
||||
@add_start_docstrings(DEPARALLELIZE_DOCSTRING)
|
||||
def deparallelize(self):
|
||||
self.encoder.deparallelize()
|
||||
self.decoder.deparallelize()
|
||||
self.encoder = self.encoder.to("cpu")
|
||||
self.decoder = self.decoder.to("cpu")
|
||||
self.lm_head = self.lm_head.to("cpu")
|
||||
self.model_parallel = False
|
||||
self.device_map = None
|
||||
torch.cuda.empty_cache()
|
||||
|
||||
def get_input_embeddings(self):
|
||||
return self.shared
|
||||
|
||||
@@ -1139,7 +1305,6 @@ class T5ForConditionalGeneration(T5PreTrainedModel):
|
||||
>>> input_ids = tokenizer("summarize: studies have shown that owning a dog is good for you ", return_tensors="pt").input_ids # Batch size 1
|
||||
>>> outputs = model.generate(input_ids)
|
||||
"""
|
||||
|
||||
if "lm_labels" in kwargs:
|
||||
warnings.warn(
|
||||
"The `lm_labels` argument is deprecated and will be removed in a future version, use `labels` instead.",
|
||||
@@ -1175,6 +1340,7 @@ class T5ForConditionalGeneration(T5PreTrainedModel):
|
||||
output_hidden_states=output_hidden_states,
|
||||
return_dict=return_dict,
|
||||
)
|
||||
|
||||
elif return_dict and not isinstance(encoder_outputs, BaseModelOutput):
|
||||
encoder_outputs = BaseModelOutput(
|
||||
last_hidden_state=encoder_outputs[0],
|
||||
@@ -1184,6 +1350,9 @@ class T5ForConditionalGeneration(T5PreTrainedModel):
|
||||
|
||||
hidden_states = encoder_outputs[0]
|
||||
|
||||
if self.model_parallel:
|
||||
torch.cuda.set_device(self.decoder.first_device)
|
||||
|
||||
if labels is not None and decoder_input_ids is None and decoder_inputs_embeds is None:
|
||||
# get decoder inputs from shifting lm labels to the right
|
||||
decoder_input_ids = self._shift_right(labels)
|
||||
@@ -1197,6 +1366,17 @@ class T5ForConditionalGeneration(T5PreTrainedModel):
|
||||
if decoder_inputs_embeds is not None:
|
||||
decoder_inputs_embeds = decoder_inputs_embeds[:, -1:]
|
||||
|
||||
# Set device for model parallelism
|
||||
if self.model_parallel:
|
||||
torch.cuda.set_device(self.decoder.first_device)
|
||||
hidden_states = hidden_states.to(self.decoder.first_device)
|
||||
if decoder_input_ids is not None:
|
||||
decoder_input_ids = decoder_input_ids.to(self.decoder.first_device)
|
||||
if attention_mask is not None:
|
||||
attention_mask = attention_mask.to(self.decoder.first_device)
|
||||
if decoder_attention_mask is not None:
|
||||
decoder_attention_mask = decoder_attention_mask.to(self.decoder.first_device)
|
||||
|
||||
# Decode
|
||||
decoder_outputs = self.decoder(
|
||||
input_ids=decoder_input_ids,
|
||||
@@ -1213,6 +1393,11 @@ class T5ForConditionalGeneration(T5PreTrainedModel):
|
||||
)
|
||||
|
||||
sequence_output = decoder_outputs[0]
|
||||
# Set device for model parallelism
|
||||
if self.model_parallel:
|
||||
torch.cuda.set_device(self.encoder.first_device)
|
||||
self.lm_head = self.lm_head.to(self.encoder.first_device)
|
||||
sequence_output = sequence_output.to(self.lm_head.weight.device)
|
||||
# Rescale output before projecting on vocab
|
||||
# See https://github.com/tensorflow/mesh/blob/fa19d69eafc9a482aff0b59ddd96b025c0cb207d/mesh_tensorflow/transformer/transformer.py#L586
|
||||
sequence_output = sequence_output * (self.model_dim ** -0.5)
|
||||
|
||||
@@ -690,7 +690,7 @@ ALBERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`Numpy array` or :obj:`tf.Tensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -390,7 +390,7 @@ TF_AUTO_MODEL_PRETRAINED_DOCSTRING = r"""
|
||||
:obj:`{'http': 'foo.bar:3128', 'http://hostname': 'foo.bar:4012'}`. The proxies are used on each
|
||||
request.
|
||||
output_loading_info(:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether ot not to also return a dictionnary containing missing keys, unexpected keys and error
|
||||
Whether ot not to also return a dictionary containing missing keys, unexpected keys and error
|
||||
messages.
|
||||
local_files_only(:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to only look at local files (e.g., not try doanloading the model).
|
||||
|
||||
@@ -735,7 +735,7 @@ BERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`Numpy array` or :obj:`tf.Tensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -495,7 +495,7 @@ CTRL_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`tf.Tensor` or :obj:`Numpy array` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||
|
||||
@@ -550,7 +550,7 @@ DISTILBERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
head_mask (:obj:`Numpy array` or :obj:`tf.Tensor` of shape :obj:`(num_heads,)` or :obj:`(num_layers, num_heads)`, `optional`):
|
||||
|
||||
@@ -665,7 +665,7 @@ ELECTRA_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
position_ids (:obj:`Numpy array` or :obj:`tf.Tensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -96,7 +96,7 @@ FLAUBERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- ``1`` for tokens that are **not masked**,
|
||||
- ``0`` for tokens that are **maked**.
|
||||
- ``0`` for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
langs (:obj:`tf.Tensor` or :obj:`Numpy array` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||
|
||||
@@ -1099,7 +1099,7 @@ FUNNEL_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`Numpy array` or :obj:`tf.Tensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -508,7 +508,7 @@ GPT2_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`tf.Tensor` or :obj:`Numpy array` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||
|
||||
@@ -1534,7 +1534,7 @@ LONGFORMER_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
global_attention_mask (:obj:`tf.Tensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -921,7 +921,7 @@ LXMERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
visual_attention_mask (:obj:`tf.Tensor` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||
@@ -929,7 +929,7 @@ LXMERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`tf.Tensor` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||
|
||||
@@ -903,7 +903,7 @@ MOBILEBERT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`Numpy array` or :obj:`tf.Tensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -444,7 +444,7 @@ OPENAI_GPT_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`tf.Tensor` or :obj:`Numpy array` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||
|
||||
@@ -654,7 +654,7 @@ ROBERTA_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`Numpy array` or :obj:`tf.Tensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -913,7 +913,7 @@ T5_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
decoder_attention_mask (:obj:`tf.Tensor` of shape :obj:`(batch_size, tgt_seq_len)`, `optional`):
|
||||
|
||||
@@ -569,7 +569,7 @@ class TFPreTrainedModel(tf.keras.Model, TFModelUtilsMixin, TFGenerationMixin):
|
||||
:obj:`{'http': 'foo.bar:3128', 'http://hostname': 'foo.bar:4012'}`. The proxies are used on each
|
||||
request.
|
||||
output_loading_info(:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether ot not to also return a dictionnary containing missing keys, unexpected keys and error
|
||||
Whether ot not to also return a dictionary containing missing keys, unexpected keys and error
|
||||
messages.
|
||||
local_files_only(:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to only look at local files (e.g., not try doanloading the model).
|
||||
|
||||
@@ -626,7 +626,7 @@ XLM_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
langs (:obj:`tf.Tensor` or :obj:`Numpy array` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -1057,7 +1057,7 @@ XLNET_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
mems (:obj:`List[torch.FloatTensor]` of length :obj:`config.n_layers`):
|
||||
|
||||
@@ -716,7 +716,7 @@ class PreTrainedModel(nn.Module, ModuleUtilsMixin, GenerationMixin):
|
||||
# If we save using the predefined names, we can load using `from_pretrained`
|
||||
output_model_file = os.path.join(save_directory, WEIGHTS_NAME)
|
||||
|
||||
if getattr(self.config, "xla_device", False):
|
||||
if getattr(self.config, "xla_device", False) and is_torch_tpu_available():
|
||||
import torch_xla.core.xla_model as xm
|
||||
|
||||
if xm.is_master_ordinal():
|
||||
@@ -802,7 +802,7 @@ class PreTrainedModel(nn.Module, ModuleUtilsMixin, GenerationMixin):
|
||||
:obj:`{'http': 'foo.bar:3128', 'http://hostname': 'foo.bar:4012'}`. The proxies are used on each
|
||||
request.
|
||||
output_loading_info(:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether ot not to also return a dictionnary containing missing keys, unexpected keys and error
|
||||
Whether ot not to also return a dictionary containing missing keys, unexpected keys and error
|
||||
messages.
|
||||
local_files_only(:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to only look at local files (e.g., not try doanloading the model).
|
||||
|
||||
@@ -337,7 +337,7 @@ XLM_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
langs (:obj:`torch.LongTensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
@@ -866,7 +866,7 @@ XLNET_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
mems (:obj:`List[torch.FloatTensor]` of length :obj:`config.n_layers`):
|
||||
|
||||
@@ -169,7 +169,7 @@ class AdamWeightDecay(tf.keras.optimizers.Adam):
|
||||
epsilon (:obj:`float`, `optional`, defaults to 1e-7):
|
||||
The epsilon paramenter in Adam, which is a small constant for numerical stability.
|
||||
amsgrad (:obj:`bool`, `optional`, default to `False`):
|
||||
Wheter to apply AMSGrad varient of this algorithm or not, see
|
||||
Whether to apply AMSGrad varient of this algorithm or not, see
|
||||
`On the Convergence of Adam and Beyond <https://arxiv.org/abs/1904.09237>`__.
|
||||
weight_decay_rate (:obj:`float`, `optional`, defaults to 0):
|
||||
The weight decay to apply.
|
||||
|
||||
@@ -943,6 +943,9 @@ class TextClassificationPipeline(Pipeline):
|
||||
task identifier: :obj:`"sentiment-analysis"` (for classifying sequences according to positive or negative
|
||||
sentiments).
|
||||
|
||||
If multiple classification labels are available (:obj:`model.config.num_labels >= 2`), the pipeline will run
|
||||
a softmax over the results. If there is a single label, the pipeline will run a sigmoid over the result.
|
||||
|
||||
The models that this pipeline can use are models that have been fine-tuned on a sequence classification task.
|
||||
See the up-to-date list of available models on
|
||||
`huggingface.co/models <https://huggingface.co/models?filter=text-classification>`__.
|
||||
@@ -977,7 +980,11 @@ class TextClassificationPipeline(Pipeline):
|
||||
If ``self.return_all_scores=True``, one such dictionary is returned per label.
|
||||
"""
|
||||
outputs = super().__call__(*args, **kwargs)
|
||||
scores = np.exp(outputs) / np.exp(outputs).sum(-1, keepdims=True)
|
||||
|
||||
if self.model.config.num_labels == 1:
|
||||
scores = 1.0 / (1.0 + np.exp(-outputs))
|
||||
else:
|
||||
scores = np.exp(outputs) / np.exp(outputs).sum(-1, keepdims=True)
|
||||
if self.return_all_scores:
|
||||
return [
|
||||
[{"label": self.model.config.id2label[i], "score": score.item()} for i, score in enumerate(item)]
|
||||
@@ -1759,7 +1766,7 @@ class QuestionAnsweringPipeline(Pipeline):
|
||||
|
||||
def decode(self, start: np.ndarray, end: np.ndarray, topk: int, max_answer_len: int) -> Tuple:
|
||||
"""
|
||||
Take the output of any :obj:`ModelForQuestionAnswering` and will generate probalities for each span to be
|
||||
Take the output of any :obj:`ModelForQuestionAnswering` and will generate probabilities for each span to be
|
||||
the actual answer.
|
||||
|
||||
In addition, it filters out some unwanted/impossible cases like answer len being greater than
|
||||
@@ -1800,7 +1807,7 @@ class QuestionAnsweringPipeline(Pipeline):
|
||||
|
||||
def span_to_answer(self, text: str, start: int, end: int) -> Dict[str, Union[str, int]]:
|
||||
"""
|
||||
When decoding from token probalities, this method maps token indexes to actual word in
|
||||
When decoding from token probabilities, this method maps token indexes to actual word in
|
||||
the initial context.
|
||||
|
||||
Args:
|
||||
|
||||
@@ -184,13 +184,23 @@ def require_faiss(test_case):
|
||||
return test_case
|
||||
|
||||
|
||||
def get_tests_dir():
|
||||
def get_tests_dir(append_path=None):
|
||||
"""
|
||||
returns the full path to the `tests` dir, so that the tests can be invoked from anywhere
|
||||
Args:
|
||||
append_path: optional path to append to the tests dir path
|
||||
|
||||
Return:
|
||||
The full path to the `tests` dir, so that the tests can be invoked from anywhere.
|
||||
Optionally `append_path` is joined after the `tests` dir the former is provided.
|
||||
|
||||
"""
|
||||
# this function caller's __file__
|
||||
caller__file__ = inspect.stack()[1][1]
|
||||
return os.path.abspath(os.path.dirname(caller__file__))
|
||||
tests_dir = os.path.abspath(os.path.dirname(caller__file__))
|
||||
if append_path:
|
||||
return os.path.join(tests_dir, append_path)
|
||||
else:
|
||||
return tests_dir
|
||||
|
||||
|
||||
#
|
||||
|
||||
@@ -49,7 +49,7 @@ class PegasusTokenizer(ReformerTokenizer):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# Dont use reserved words added_token_encoder, added_tokens_decoder because of
|
||||
# Don't use reserved words added_token_encoder, added_tokens_decoder because of
|
||||
# AssertionError: Non-consecutive added token '1' found. in from_pretrained
|
||||
assert len(self.added_tokens_decoder) == 0
|
||||
self.encoder: Dict[int, str] = {0: self.pad_token, 1: self.eos_token}
|
||||
@@ -58,7 +58,7 @@ class PegasusTokenizer(ReformerTokenizer):
|
||||
self.decoder: Dict[str, int] = {v: k for k, v in self.encoder.items()}
|
||||
|
||||
def _convert_token_to_id(self, token: str) -> int:
|
||||
""" Converts a token (str) in an id using the vocab. """
|
||||
""" Converts a token (str) to an id using the vocab. """
|
||||
if token in self.decoder:
|
||||
return self.decoder[token]
|
||||
elif token in self.added_tokens_decoder:
|
||||
@@ -67,7 +67,7 @@ class PegasusTokenizer(ReformerTokenizer):
|
||||
return sp_id + self.offset
|
||||
|
||||
def _convert_id_to_token(self, index: int) -> str:
|
||||
"""Converts an index (integer) in a token (str) using the vocab."""
|
||||
"""Converts an index (integer) to a token (str) using the vocab."""
|
||||
if index in self.encoder:
|
||||
return self.encoder[index]
|
||||
elif index in self.added_tokens_encoder:
|
||||
@@ -81,11 +81,6 @@ class PegasusTokenizer(ReformerTokenizer):
|
||||
def vocab_size(self) -> int:
|
||||
return len(self.sp_model) + self.offset
|
||||
|
||||
def get_vocab(self) -> Dict[str, int]:
|
||||
vocab = {self.convert_ids_to_tokens(i): i for i in range(self.vocab_size)}
|
||||
vocab.update(self.added_tokens_encoder)
|
||||
return vocab
|
||||
|
||||
def num_special_tokens_to_add(self, pair=False):
|
||||
"""Just EOS"""
|
||||
return 1
|
||||
@@ -109,12 +104,12 @@ class PegasusTokenizer(ReformerTokenizer):
|
||||
|
||||
def build_inputs_with_special_tokens(self, token_ids_0, token_ids_1=None) -> List[int]:
|
||||
"""
|
||||
Build model inputs from a sequence or a pair of sequence for sequence classification tasks
|
||||
Build model inputs from a sequence or a pair of sequences for sequence classification tasks
|
||||
by concatenating and adding special tokens.
|
||||
A Pegasus sequence has the following format, where ``X`` represents the sequence:
|
||||
|
||||
- single sequence: ``X </s>``
|
||||
- pair of sequences: ``A B </s>`` (not intended use)
|
||||
- pair of sequences: ``A B </s>`` (not intended use)
|
||||
|
||||
BOS is never used.
|
||||
Pairs of sequences are not the expected use case, but they will be handled without a separator.
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
import os
|
||||
from shutil import copyfile
|
||||
from typing import Dict
|
||||
|
||||
from .tokenization_utils import PreTrainedTokenizer
|
||||
from .tokenization_utils_fast import PreTrainedTokenizerFast
|
||||
@@ -119,7 +120,7 @@ class ReformerTokenizer(PreTrainedTokenizer):
|
||||
def vocab_size(self):
|
||||
return self.sp_model.get_piece_size()
|
||||
|
||||
def get_vocab(self):
|
||||
def get_vocab(self) -> Dict[str, int]:
|
||||
vocab = {self.convert_ids_to_tokens(i): i for i in range(self.vocab_size)}
|
||||
vocab.update(self.added_tokens_encoder)
|
||||
return vocab
|
||||
|
||||
@@ -186,7 +186,7 @@ class PreTrainedTokenizer(PreTrainedTokenizerBase):
|
||||
|
||||
num_added_toks = tokenizer.add_tokens(['new_tok1', 'my_new-tok2'])
|
||||
print('We have added', num_added_toks, 'tokens')
|
||||
# Notice: resize_token_embeddings expect to receive the full size of the new vocabulary, i.e. the length of the tokenizer.
|
||||
# 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]
|
||||
@@ -682,7 +682,7 @@ class PreTrainedTokenizer(PreTrainedTokenizerBase):
|
||||
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`):
|
||||
Wheter or not the token list is already formated with special tokens for the model.
|
||||
Whether or not the token list is already formated 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.
|
||||
@@ -815,7 +815,7 @@ class PreTrainedTokenizer(PreTrainedTokenizerBase):
|
||||
you want to reload it using the :meth:`~transformers.PreTrainedTokenizer.from_pretrained` class method.
|
||||
|
||||
Args:
|
||||
save_directory (:obj:`str`): The path to adirectory where the tokenizer will be saved.
|
||||
save_directory (:obj:`str`): The path to a directory where the tokenizer will be saved.
|
||||
|
||||
Returns:
|
||||
A tuple of :obj:`str`: The files saved.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
""" Base classes common to both the slow and the fast tokenization classes:
|
||||
PreTrainedTokenizerBase (host all the user fronting encoding methodes)
|
||||
Special token mixing (host the special tokens logic) and
|
||||
BatchEncoding (wrap the dictionnary of output with special method for the Fast tokenizers)
|
||||
BatchEncoding (wrap the dictionary of output with special method for the Fast tokenizers)
|
||||
"""
|
||||
|
||||
import copy
|
||||
@@ -159,9 +159,9 @@ class BatchEncoding(UserDict):
|
||||
Dictionary of lists/arrays/tensors returned by the encode/batch_encode methods ('input_ids',
|
||||
'attention_mask', etc.).
|
||||
encoding (:obj:`tokenizers.Encoding` or :obj:`Sequence[tokenizers.Encoding]`, `optional`):
|
||||
If the tokenizer is a fast tokenizer which outputs additional informations like mapping from word/character
|
||||
space to token space the :obj:`tokenizers.Encoding` instance or list of instance (for batches) hold these
|
||||
informations.
|
||||
If the tokenizer is a fast tokenizer which outputs additional information like mapping from word/character
|
||||
space to token space the :obj:`tokenizers.Encoding` instance or list of instance (for batches) hold this
|
||||
information.
|
||||
tensor_type (:obj:`Union[None, str, TensorType]`, `optional`):
|
||||
You can give a tensor_type here to convert the lists of integers in PyTorch/TensorFlow/Numpy Tensors at
|
||||
initialization.
|
||||
@@ -249,7 +249,7 @@ class BatchEncoding(UserDict):
|
||||
|
||||
def tokens(self, batch_index: int = 0) -> List[str]:
|
||||
"""
|
||||
Return the list of tokens (sub-parts of the input strings after word/subword splitting and before converstion
|
||||
Return the list of tokens (sub-parts of the input strings after word/subword splitting and before conversion
|
||||
to integer indices) at a given batch index (only works for the output of a fast tokenizer).
|
||||
|
||||
Args:
|
||||
@@ -1121,7 +1121,7 @@ ENCODE_PLUS_ADDITIONAL_KWARGS_DOCSTRING = r"""
|
||||
return_overflowing_tokens (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to return overflowing token sequences.
|
||||
return_special_tokens_mask (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Wheter or not to return special tokens mask information.
|
||||
Whether or not to return special tokens mask information.
|
||||
return_offsets_mapping (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to return :obj:`(char_start, char_end)` for each token.
|
||||
|
||||
@@ -1131,7 +1131,7 @@ ENCODE_PLUS_ADDITIONAL_KWARGS_DOCSTRING = r"""
|
||||
return_length (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether or not to return the lengths of the encoded inputs.
|
||||
verbose (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Whether or not to print informations and warnings.
|
||||
Whether or not to print more information and warnings.
|
||||
**kwargs: passed to the :obj:`self.tokenize()` method
|
||||
|
||||
Return:
|
||||
@@ -1153,13 +1153,13 @@ ENCODE_PLUS_ADDITIONAL_KWARGS_DOCSTRING = r"""
|
||||
- **num_truncated_tokens** -- Number of tokens truncated (when a :obj:`max_length` is specified and
|
||||
:obj:`return_overflowing_tokens=True`).
|
||||
- **special_tokens_mask** -- List of 0s and 1s, with 0 specifying added special tokens and 1 specifying
|
||||
regual sequence tokens (when :obj:`add_special_tokens=True` and :obj:`return_special_tokens_mask=True`).
|
||||
regular sequence tokens (when :obj:`add_special_tokens=True` and :obj:`return_special_tokens_mask=True`).
|
||||
- **length** -- The length of the inputs (when :obj:`return_length=True`)
|
||||
"""
|
||||
|
||||
INIT_TOKENIZER_DOCSTRING = r"""
|
||||
Class attributes (overridden by derived classes)
|
||||
- **vocab_files_names** (:obj:`Dict[str, str]`) -- A ditionary with, as keys, the ``__init__`` keyword name of
|
||||
- **vocab_files_names** (:obj:`Dict[str, str]`) -- A dictionary with, as keys, the ``__init__`` keyword name of
|
||||
each vocabulary file required by the model, and as associated values, the filename for saving the associated
|
||||
file (string).
|
||||
- **pretrained_vocab_files_map** (:obj:`Dict[str, Dict[str, str]]`) -- A dictionary of dictionaries, with the
|
||||
@@ -1170,7 +1170,7 @@ INIT_TOKENIZER_DOCSTRING = r"""
|
||||
:obj:`short-cut-names` of the pretrained models, and as associated values, the maximum length of the sequence
|
||||
inputs of this model, or :obj:`None` if the model has no maximum input size.
|
||||
- **pretrained_init_configuration** (:obj:`Dict[str, Dict[str, Any]]`) -- A dictionary with, as keys, the
|
||||
:obj:`short-cut-names` of the pretrained models, and as associated values, a dictionnary of specific
|
||||
:obj:`short-cut-names` of the pretrained models, and as associated values, a dictionary of specific
|
||||
arguments to pass to the ``__init__`` method of the tokenizer class for this pretrained model when loading the
|
||||
tokenizer with the :meth:`~transformers.tokenization_utils_base.PreTrainedTokenizerBase.from_pretrained`
|
||||
method.
|
||||
@@ -1637,9 +1637,11 @@ class PreTrainedTokenizerBase(SpecialTokensMixin):
|
||||
if special_tokens_map_file is not None:
|
||||
with open(special_tokens_map_file, encoding="utf-8") as special_tokens_map_handle:
|
||||
special_tokens_map = json.load(special_tokens_map_handle)
|
||||
|
||||
special_tokens_map = convert_added_tokens(special_tokens_map)
|
||||
for key, value in special_tokens_map.items():
|
||||
if isinstance(value, dict):
|
||||
value = AddedToken(**value)
|
||||
elif isinstance(value, list):
|
||||
value = [AddedToken(**token) if isinstance(token, dict) else token for token in value]
|
||||
setattr(tokenizer, key, value)
|
||||
|
||||
# Add supplementary tokens.
|
||||
@@ -1686,7 +1688,7 @@ class PreTrainedTokenizerBase(SpecialTokensMixin):
|
||||
modifying :obj:`tokenizer.do_lower_case` after creation).
|
||||
|
||||
Args:
|
||||
save_directory (:obj:`str`): The path to adirectory where the tokenizer will be saved.
|
||||
save_directory (:obj:`str`): The path to a directory where the tokenizer will be saved.
|
||||
|
||||
Returns:
|
||||
A tuple of :obj:`str`: The files saved.
|
||||
@@ -1706,23 +1708,25 @@ class PreTrainedTokenizerBase(SpecialTokensMixin):
|
||||
tokenizer_config.pop(file_id, None)
|
||||
|
||||
# Sanitize AddedTokens
|
||||
def convert_added_tokens(obj: Union[AddedToken, Any]):
|
||||
def convert_added_tokens(obj: Union[AddedToken, Any], add_type_field=True):
|
||||
if isinstance(obj, AddedToken):
|
||||
out = obj.__getstate__()
|
||||
out["__type"] = "AddedToken"
|
||||
if add_type_field:
|
||||
out["__type"] = "AddedToken"
|
||||
return out
|
||||
elif isinstance(obj, (list, tuple)):
|
||||
return list(convert_added_tokens(o) for o in obj)
|
||||
return list(convert_added_tokens(o, add_type_field=add_type_field) for o in obj)
|
||||
elif isinstance(obj, dict):
|
||||
return {k: convert_added_tokens(v) for k, v in obj.items()}
|
||||
return {k: convert_added_tokens(v, add_type_field=add_type_field) for k, v in obj.items()}
|
||||
return obj
|
||||
|
||||
tokenizer_config = convert_added_tokens(tokenizer_config)
|
||||
# add_type_field=True to allow dicts in the kwargs / differentiate from AddedToken serialization
|
||||
tokenizer_config = convert_added_tokens(tokenizer_config, add_type_field=True)
|
||||
with open(tokenizer_config_file, "w", encoding="utf-8") as f:
|
||||
f.write(json.dumps(tokenizer_config, ensure_ascii=False))
|
||||
|
||||
# Sanitize AddedTokens in special_tokens_map
|
||||
write_dict = convert_added_tokens(self.special_tokens_map_extended)
|
||||
write_dict = convert_added_tokens(self.special_tokens_map_extended, add_type_field=False)
|
||||
with open(special_tokens_map_file, "w", encoding="utf-8") as f:
|
||||
f.write(json.dumps(write_dict, ensure_ascii=False))
|
||||
|
||||
@@ -2309,7 +2313,7 @@ class PreTrainedTokenizerBase(SpecialTokensMixin):
|
||||
* :obj:`'pt'`: Return PyTorch :obj:`torch.Tensor` objects.
|
||||
* :obj:`'np'`: Return Numpy :obj:`np.ndarray` objects.
|
||||
verbose (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Whether or not to print informations and warnings.
|
||||
Whether or not to print more information and warnings.
|
||||
"""
|
||||
# If we have a list of dicts, let's convert it in a dict of lists
|
||||
# We do this to allow using this method as a collate_fn function in PyTorch Dataloader
|
||||
@@ -2379,7 +2383,7 @@ class PreTrainedTokenizerBase(SpecialTokensMixin):
|
||||
batch_size = len(encoded_inputs["input_ids"])
|
||||
assert all(
|
||||
len(v) == batch_size for v in encoded_inputs.values()
|
||||
), "Some items in the output dictionnary have a different batch size than others."
|
||||
), "Some items in the output dictionary have a different batch size than others."
|
||||
|
||||
if padding_strategy == PaddingStrategy.LONGEST:
|
||||
max_length = max(len(inputs) for inputs in encoded_inputs["input_ids"])
|
||||
@@ -2543,7 +2547,7 @@ class PreTrainedTokenizerBase(SpecialTokensMixin):
|
||||
sequence = ids + pair_ids if pair else ids
|
||||
token_type_ids = [0] * len(ids) + ([0] * len(pair_ids) if pair else [])
|
||||
|
||||
# Build output dictionnary
|
||||
# Build output dictionary
|
||||
encoded_inputs["input_ids"] = sequence
|
||||
if return_token_type_ids:
|
||||
encoded_inputs["token_type_ids"] = token_type_ids
|
||||
@@ -2815,7 +2819,7 @@ class PreTrainedTokenizerBase(SpecialTokensMixin):
|
||||
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`):
|
||||
Wheter or not the token list is already formated with special tokens for the model.
|
||||
Whether or not the token list is already formated 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.
|
||||
|
||||
@@ -552,7 +552,7 @@ class PreTrainedTokenizerFast(PreTrainedTokenizerBase):
|
||||
you want to reload it using the :meth:`~transformers.PreTrainedTokenizerFast.from_pretrained` class method.
|
||||
|
||||
Args:
|
||||
save_directory (:obj:`str`): The path to adirectory where the tokenizer will be saved.
|
||||
save_directory (:obj:`str`): The path to a directory where the tokenizer will be saved.
|
||||
|
||||
Returns:
|
||||
A tuple of :obj:`str`: The files saved.
|
||||
|
||||
+405
-116
@@ -33,7 +33,11 @@ from torch.utils.data.dataset import Dataset
|
||||
from torch.utils.data.distributed import DistributedSampler
|
||||
from torch.utils.data.sampler import RandomSampler, SequentialSampler
|
||||
|
||||
from .data.data_collator import DataCollator, DataCollatorWithPadding, default_data_collator
|
||||
from .data.data_collator import (
|
||||
DataCollator,
|
||||
DataCollatorWithPadding,
|
||||
default_data_collator,
|
||||
)
|
||||
from .file_utils import WEIGHTS_NAME, is_datasets_available, is_torch_tpu_available
|
||||
from .integrations import (
|
||||
default_hp_search_backend,
|
||||
@@ -101,6 +105,11 @@ else:
|
||||
_use_native_amp = True
|
||||
from torch.cuda.amp import autocast
|
||||
|
||||
if version.parse(torch.__version__) < version.parse("1.2"):
|
||||
_use_ddp_no_sync = False
|
||||
else:
|
||||
_use_ddp_no_sync = True
|
||||
|
||||
if is_datasets_available():
|
||||
import datasets
|
||||
|
||||
@@ -168,6 +177,9 @@ class Trainer:
|
||||
model_init (:obj:`Callable[[], PreTrainedModel]`, `optional`):
|
||||
A function that instantiates the model to be used. If provided, each call to
|
||||
:meth:`~transformers.Trainer.train` will start from a new instance of the model as given by this function.
|
||||
|
||||
The function may have zero argument, or a single one containing the optuna/Ray Tune trial object, to be able to choose
|
||||
different architectures according to hyper parameters (such as layer count, sizes of inner layers, dropout probabilities etc).
|
||||
compute_metrics (:obj:`Callable[[EvalPrediction], Dict]`, `optional`):
|
||||
The function that will be used to compute metrics at evaluation. Must take a
|
||||
:class:`~transformers.EvalPrediction` and return a dictionary string to metric values.
|
||||
@@ -195,11 +207,16 @@ class Trainer:
|
||||
model_init: Callable[[], PreTrainedModel] = None,
|
||||
compute_metrics: Optional[Callable[[EvalPrediction], Dict]] = None,
|
||||
callbacks: Optional[List[TrainerCallback]] = None,
|
||||
optimizers: Tuple[torch.optim.Optimizer, torch.optim.lr_scheduler.LambdaLR] = (None, None),
|
||||
optimizers: Tuple[torch.optim.Optimizer, torch.optim.lr_scheduler.LambdaLR] = (
|
||||
None,
|
||||
None,
|
||||
),
|
||||
**kwargs,
|
||||
):
|
||||
if args is None:
|
||||
logger.info("No `TrainingArguments` passed, using the current path as `output_dir`.")
|
||||
logger.info(
|
||||
"No `TrainingArguments` passed, using the current path as `output_dir`."
|
||||
)
|
||||
args = TrainingArguments("tmp_trainer")
|
||||
self.args = args
|
||||
# Seed must be set before instantiating the model when using model
|
||||
@@ -207,25 +224,46 @@ class Trainer:
|
||||
assert (
|
||||
model is not None or model_init is not None
|
||||
), "You must provide a model to use `Trainer`, either by using the `model` argument or the `model_init` argument."
|
||||
self.model_init = model_init
|
||||
|
||||
if model is None and model_init is not None:
|
||||
model = model_init()
|
||||
self.model = model.to(args.device) if model is not None else None
|
||||
default_collator = default_data_collator if tokenizer is None else DataCollatorWithPadding(tokenizer)
|
||||
self.data_collator = data_collator if data_collator is not None else default_collator
|
||||
model = self.call_model_init()
|
||||
|
||||
# Model parallel
|
||||
self.model = model if model else None
|
||||
if not self.args.model_parallel and self.model is not None:
|
||||
self.model = self.model.to(args.device)
|
||||
|
||||
default_collator = (
|
||||
default_data_collator
|
||||
if tokenizer is None
|
||||
else DataCollatorWithPadding(tokenizer)
|
||||
)
|
||||
self.data_collator = (
|
||||
data_collator if data_collator is not None else default_collator
|
||||
)
|
||||
self.train_dataset = train_dataset
|
||||
self.eval_dataset = eval_dataset
|
||||
self.tokenizer = tokenizer
|
||||
self.model_init = model_init
|
||||
|
||||
self.compute_metrics = compute_metrics
|
||||
self.optimizer, self.lr_scheduler = optimizers
|
||||
if model_init is not None and (self.optimizer is not None or self.lr_scheduler is not None):
|
||||
if model_init is not None and (
|
||||
self.optimizer is not None or self.lr_scheduler is not None
|
||||
):
|
||||
raise RuntimeError(
|
||||
"Passing a `model_init` is incompatible with providing the `optimizers` argument."
|
||||
"You should subclass `Trainer` and override the `create_optimizer_and_scheduler` method."
|
||||
)
|
||||
callbacks = DEFAULT_CALLBACKS if callbacks is None else DEFAULT_CALLBACKS + callbacks
|
||||
self.callback_handler = CallbackHandler(callbacks, self.model, self.optimizer, self.lr_scheduler)
|
||||
self.add_callback(PrinterCallback if self.args.disable_tqdm else ProgressCallback)
|
||||
callbacks = (
|
||||
DEFAULT_CALLBACKS if callbacks is None else DEFAULT_CALLBACKS + callbacks
|
||||
)
|
||||
self.callback_handler = CallbackHandler(
|
||||
callbacks, self.model, self.optimizer, self.lr_scheduler
|
||||
)
|
||||
self.add_callback(
|
||||
PrinterCallback if self.args.disable_tqdm else ProgressCallback
|
||||
)
|
||||
|
||||
# Deprecated arguments
|
||||
if "tb_writer" in kwargs:
|
||||
@@ -258,7 +296,9 @@ class Trainer:
|
||||
# Set an xla_device flag on the model's config.
|
||||
# We'll find a more elegant and not need to do this in the future.
|
||||
self.model.config.xla_device = True
|
||||
if not callable(self.data_collator) and callable(getattr(self.data_collator, "collate_batch", None)):
|
||||
if not callable(self.data_collator) and callable(
|
||||
getattr(self.data_collator, "collate_batch", None)
|
||||
):
|
||||
self.data_collator = self.data_collator.collate_batch
|
||||
warnings.warn(
|
||||
(
|
||||
@@ -288,8 +328,14 @@ class Trainer:
|
||||
if type(self.model) in MODEL_FOR_QUESTION_ANSWERING_MAPPING.values()
|
||||
else ["labels"]
|
||||
)
|
||||
self.label_names = default_label_names if self.args.label_names is None else self.args.label_names
|
||||
self.control = self.callback_handler.on_init_end(self.args, self.state, self.control)
|
||||
self.label_names = (
|
||||
default_label_names
|
||||
if self.args.label_names is None
|
||||
else self.args.label_names
|
||||
)
|
||||
self.control = self.callback_handler.on_init_end(
|
||||
self.args, self.state, self.control
|
||||
)
|
||||
|
||||
def add_callback(self, callback):
|
||||
"""
|
||||
@@ -329,7 +375,9 @@ class Trainer:
|
||||
"""
|
||||
self.callback_handler.remove_callback(callback)
|
||||
|
||||
def _remove_unused_columns(self, dataset: "datasets.Dataset", description: Optional[str] = None):
|
||||
def _remove_unused_columns(
|
||||
self, dataset: "datasets.Dataset", description: Optional[str] = None
|
||||
):
|
||||
if not self.args.remove_unused_columns:
|
||||
return
|
||||
# Inspect model forward signature to keep only the arguments it accepts.
|
||||
@@ -379,11 +427,15 @@ class Trainer:
|
||||
num_workers=self.args.dataloader_num_workers,
|
||||
)
|
||||
|
||||
def _get_eval_sampler(self, eval_dataset: Dataset) -> Optional[torch.utils.data.sampler.Sampler]:
|
||||
def _get_eval_sampler(
|
||||
self, eval_dataset: Dataset
|
||||
) -> Optional[torch.utils.data.sampler.Sampler]:
|
||||
if isinstance(eval_dataset, torch.utils.data.IterableDataset):
|
||||
return None
|
||||
elif is_torch_tpu_available():
|
||||
return SequentialDistributedSampler(eval_dataset, num_replicas=xm.xrt_world_size(), rank=xm.get_ordinal())
|
||||
return SequentialDistributedSampler(
|
||||
eval_dataset, num_replicas=xm.xrt_world_size(), rank=xm.get_ordinal()
|
||||
)
|
||||
elif self.args.local_rank != -1:
|
||||
return SequentialDistributedSampler(eval_dataset)
|
||||
else:
|
||||
@@ -405,7 +457,11 @@ class Trainer:
|
||||
"""
|
||||
if eval_dataset is None and self.eval_dataset is None:
|
||||
raise ValueError("Trainer: evaluation requires an eval_dataset.")
|
||||
elif eval_dataset is not None and is_datasets_available() and isinstance(eval_dataset, datasets.Dataset):
|
||||
elif (
|
||||
eval_dataset is not None
|
||||
and is_datasets_available()
|
||||
and isinstance(eval_dataset, datasets.Dataset)
|
||||
):
|
||||
self._remove_unused_columns(eval_dataset, description="evaluation")
|
||||
eval_dataset = eval_dataset if eval_dataset is not None else self.eval_dataset
|
||||
eval_sampler = self._get_eval_sampler(eval_dataset)
|
||||
@@ -457,11 +513,19 @@ class Trainer:
|
||||
no_decay = ["bias", "LayerNorm.weight"]
|
||||
optimizer_grouped_parameters = [
|
||||
{
|
||||
"params": [p for n, p in self.model.named_parameters() if not any(nd in n for nd in no_decay)],
|
||||
"params": [
|
||||
p
|
||||
for n, p in self.model.named_parameters()
|
||||
if not any(nd in n for nd in no_decay)
|
||||
],
|
||||
"weight_decay": self.args.weight_decay,
|
||||
},
|
||||
{
|
||||
"params": [p for n, p in self.model.named_parameters() if any(nd in n for nd in no_decay)],
|
||||
"params": [
|
||||
p
|
||||
for n, p in self.model.named_parameters()
|
||||
if any(nd in n for nd in no_decay)
|
||||
],
|
||||
"weight_decay": 0.0,
|
||||
},
|
||||
]
|
||||
@@ -473,7 +537,9 @@ class Trainer:
|
||||
)
|
||||
if self.lr_scheduler is None:
|
||||
self.lr_scheduler = get_linear_schedule_with_warmup(
|
||||
self.optimizer, num_warmup_steps=self.args.warmup_steps, num_training_steps=num_training_steps
|
||||
self.optimizer,
|
||||
num_warmup_steps=self.args.warmup_steps,
|
||||
num_training_steps=num_training_steps,
|
||||
)
|
||||
|
||||
def num_examples(self, dataloader: DataLoader) -> int:
|
||||
@@ -486,7 +552,11 @@ class Trainer:
|
||||
""" HP search setup code """
|
||||
if self.hp_search_backend is None or trial is None:
|
||||
return
|
||||
params = self.hp_space(trial) if self.hp_search_backend == HPSearchBackend.OPTUNA else trial
|
||||
params = (
|
||||
self.hp_space(trial)
|
||||
if self.hp_search_backend == HPSearchBackend.OPTUNA
|
||||
else trial
|
||||
)
|
||||
for key, value in params.items():
|
||||
if not hasattr(self.args, key):
|
||||
raise AttributeError(
|
||||
@@ -501,7 +571,10 @@ class Trainer:
|
||||
logger.info("Trial:", trial.params)
|
||||
|
||||
def _report_to_hp_search(
|
||||
self, trial: Union["optuna.Trial", Dict[str, Any]], epoch: int, metrics: Dict[str, float]
|
||||
self,
|
||||
trial: Union["optuna.Trial", Dict[str, Any]],
|
||||
epoch: int,
|
||||
metrics: Dict[str, float],
|
||||
):
|
||||
if self.hp_search_backend is None or trial is None:
|
||||
return
|
||||
@@ -520,14 +593,38 @@ class Trainer:
|
||||
return
|
||||
with tune.checkpoint_dir(step=self.state.global_step) as checkpoint_dir:
|
||||
self.args.output_dir = checkpoint_dir
|
||||
output_dir = os.path.join(self.args.output_dir, f"{PREFIX_CHECKPOINT_DIR}-{self.state.global_step}")
|
||||
output_dir = os.path.join(
|
||||
self.args.output_dir,
|
||||
f"{PREFIX_CHECKPOINT_DIR}-{self.state.global_step}",
|
||||
)
|
||||
self.save_model(output_dir)
|
||||
if self.is_world_master():
|
||||
self.state.save_to_json(os.path.join(output_dir, "trainer_state.json"))
|
||||
torch.save(self.optimizer.state_dict(), os.path.join(output_dir, "optimizer.pt"))
|
||||
torch.save(self.lr_scheduler.state_dict(), os.path.join(output_dir, "scheduler.pt"))
|
||||
torch.save(
|
||||
self.optimizer.state_dict(),
|
||||
os.path.join(output_dir, "optimizer.pt"),
|
||||
)
|
||||
torch.save(
|
||||
self.lr_scheduler.state_dict(),
|
||||
os.path.join(output_dir, "scheduler.pt"),
|
||||
)
|
||||
|
||||
def train(self, model_path: Optional[str] = None, trial: Union["optuna.Trial", Dict[str, Any]] = None):
|
||||
def call_model_init(self, trial=None):
|
||||
model_init_argcount = len(inspect.signature(self.model_init).parameters)
|
||||
if model_init_argcount == 0:
|
||||
model = self.model_init()
|
||||
elif model_init_argcount == 1:
|
||||
model = self.model_init(trial)
|
||||
else:
|
||||
raise Exception("model_init should have 0 or 1 argument.")
|
||||
|
||||
return model
|
||||
|
||||
def train(
|
||||
self,
|
||||
model_path: Optional[str] = None,
|
||||
trial: Union["optuna.Trial", Dict[str, Any]] = None,
|
||||
):
|
||||
"""
|
||||
Main training entry point.
|
||||
|
||||
@@ -545,15 +642,21 @@ class Trainer:
|
||||
if self.model_init is not None:
|
||||
# Seed must be set before instantiating the model when using model_init.
|
||||
set_seed(self.args.seed)
|
||||
model = self.model_init()
|
||||
self.model = model.to(self.args.device)
|
||||
|
||||
model = self.call_model_init(trial)
|
||||
|
||||
# Model parallel
|
||||
if not self.args.model_parallel:
|
||||
self.model = model.to(self.args.device)
|
||||
|
||||
# Reinitializes optimizer and scheduler
|
||||
self.optimizer, self.lr_scheduler = None, None
|
||||
|
||||
# Data loader and number of training steps
|
||||
train_dataloader = self.get_train_dataloader()
|
||||
num_update_steps_per_epoch = len(train_dataloader) // self.args.gradient_accumulation_steps
|
||||
num_update_steps_per_epoch = (
|
||||
len(train_dataloader) // self.args.gradient_accumulation_steps
|
||||
)
|
||||
num_update_steps_per_epoch = max(num_update_steps_per_epoch, 1)
|
||||
if self.args.max_steps > 0:
|
||||
max_steps = self.args.max_steps
|
||||
@@ -576,21 +679,30 @@ class Trainer:
|
||||
):
|
||||
# Load in optimizer and scheduler states
|
||||
self.optimizer.load_state_dict(
|
||||
torch.load(os.path.join(model_path, "optimizer.pt"), map_location=self.args.device)
|
||||
torch.load(
|
||||
os.path.join(model_path, "optimizer.pt"),
|
||||
map_location=self.args.device,
|
||||
)
|
||||
)
|
||||
with warnings.catch_warnings(record=True) as caught_warnings:
|
||||
self.lr_scheduler.load_state_dict(torch.load(os.path.join(model_path, "scheduler.pt")))
|
||||
self.lr_scheduler.load_state_dict(
|
||||
torch.load(os.path.join(model_path, "scheduler.pt"))
|
||||
)
|
||||
reissue_pt_warnings(caught_warnings)
|
||||
|
||||
# Mixed precision training with apex (torch < 1.6)
|
||||
model = self.model
|
||||
if self.args.fp16 and _use_apex:
|
||||
if not is_apex_available():
|
||||
raise ImportError("Please install apex from https://www.github.com/nvidia/apex to use fp16 training.")
|
||||
model, self.optimizer = amp.initialize(model, self.optimizer, opt_level=self.args.fp16_opt_level)
|
||||
raise ImportError(
|
||||
"Please install apex from https://www.github.com/nvidia/apex to use fp16 training."
|
||||
)
|
||||
model, self.optimizer = amp.initialize(
|
||||
model, self.optimizer, opt_level=self.args.fp16_opt_level
|
||||
)
|
||||
|
||||
# Multi-gpu training (should be after apex fp16 initialization)
|
||||
if self.args.n_gpu > 1:
|
||||
if self.args.n_gpu > 1 and not self.args.model_parallel:
|
||||
model = torch.nn.DataParallel(model)
|
||||
|
||||
# Distributed training (should be after apex fp16 initialization)
|
||||
@@ -615,14 +727,26 @@ class Trainer:
|
||||
total_train_batch_size = (
|
||||
self.args.train_batch_size
|
||||
* self.args.gradient_accumulation_steps
|
||||
* (torch.distributed.get_world_size() if self.args.local_rank != -1 else 1)
|
||||
* (
|
||||
torch.distributed.get_world_size()
|
||||
if self.args.local_rank != -1
|
||||
else 1
|
||||
)
|
||||
)
|
||||
logger.info("***** Running training *****")
|
||||
logger.info(" Num examples = %d", self.num_examples(train_dataloader))
|
||||
logger.info(" Num Epochs = %d", num_train_epochs)
|
||||
logger.info(" Instantaneous batch size per device = %d", self.args.per_device_train_batch_size)
|
||||
logger.info(" Total train batch size (w. parallel, distributed & accumulation) = %d", total_train_batch_size)
|
||||
logger.info(" Gradient Accumulation steps = %d", self.args.gradient_accumulation_steps)
|
||||
logger.info(
|
||||
" Instantaneous batch size per device = %d",
|
||||
self.args.per_device_train_batch_size,
|
||||
)
|
||||
logger.info(
|
||||
" Total train batch size (w. parallel, distributed & accumulation) = %d",
|
||||
total_train_batch_size,
|
||||
)
|
||||
logger.info(
|
||||
" Gradient Accumulation steps = %d", self.args.gradient_accumulation_steps
|
||||
)
|
||||
logger.info(" Total optimization steps = %d", max_steps)
|
||||
|
||||
self.state.epoch = 0
|
||||
@@ -630,15 +754,28 @@ class Trainer:
|
||||
steps_trained_in_current_epoch = 0
|
||||
|
||||
# Check if continuing training from a checkpoint
|
||||
if model_path and os.path.isfile(os.path.join(model_path, "trainer_state.json")):
|
||||
self.state = TrainerState.load_from_json(os.path.join(model_path, "trainer_state.json"))
|
||||
if model_path and os.path.isfile(
|
||||
os.path.join(model_path, "trainer_state.json")
|
||||
):
|
||||
self.state = TrainerState.load_from_json(
|
||||
os.path.join(model_path, "trainer_state.json")
|
||||
)
|
||||
epochs_trained = self.state.global_step // num_update_steps_per_epoch
|
||||
steps_trained_in_current_epoch = self.state.global_step % (num_update_steps_per_epoch)
|
||||
steps_trained_in_current_epoch = self.state.global_step % (
|
||||
num_update_steps_per_epoch
|
||||
)
|
||||
|
||||
logger.info(" Continuing training from checkpoint, will skip to saved global_step")
|
||||
logger.info(
|
||||
" Continuing training from checkpoint, will skip to saved global_step"
|
||||
)
|
||||
logger.info(" Continuing training from epoch %d", epochs_trained)
|
||||
logger.info(" Continuing training from global step %d", self.state.global_step)
|
||||
logger.info(" Will skip the first %d steps in the first epoch", steps_trained_in_current_epoch)
|
||||
logger.info(
|
||||
" Continuing training from global step %d", self.state.global_step
|
||||
)
|
||||
logger.info(
|
||||
" Will skip the first %d steps in the first epoch",
|
||||
steps_trained_in_current_epoch,
|
||||
)
|
||||
|
||||
# Update the references
|
||||
self.callback_handler.model = self.model
|
||||
@@ -657,16 +794,20 @@ class Trainer:
|
||||
self._total_flos = self.state.total_flos
|
||||
model.zero_grad()
|
||||
|
||||
self.control = self.callback_handler.on_train_begin(self.args, self.state, self.control)
|
||||
self.control = self.callback_handler.on_train_begin(
|
||||
self.args, self.state, self.control
|
||||
)
|
||||
|
||||
for epoch in range(epochs_trained, num_train_epochs):
|
||||
if isinstance(train_dataloader, DataLoader) and isinstance(train_dataloader.sampler, DistributedSampler):
|
||||
if isinstance(train_dataloader, DataLoader) and isinstance(
|
||||
train_dataloader.sampler, DistributedSampler
|
||||
):
|
||||
train_dataloader.sampler.set_epoch(epoch)
|
||||
|
||||
if is_torch_tpu_available():
|
||||
parallel_loader = pl.ParallelLoader(train_dataloader, [self.args.device]).per_device_loader(
|
||||
self.args.device
|
||||
)
|
||||
parallel_loader = pl.ParallelLoader(
|
||||
train_dataloader, [self.args.device]
|
||||
).per_device_loader(self.args.device)
|
||||
epoch_iterator = parallel_loader
|
||||
else:
|
||||
epoch_iterator = train_dataloader
|
||||
@@ -675,7 +816,9 @@ class Trainer:
|
||||
if self.args.past_index >= 0:
|
||||
self._past = None
|
||||
|
||||
self.control = self.callback_handler.on_epoch_begin(self.args, self.state, self.control)
|
||||
self.control = self.callback_handler.on_epoch_begin(
|
||||
self.args, self.state, self.control
|
||||
)
|
||||
|
||||
for step, inputs in enumerate(epoch_iterator):
|
||||
|
||||
@@ -685,9 +828,19 @@ class Trainer:
|
||||
continue
|
||||
|
||||
if (step + 1) % self.args.gradient_accumulation_steps == 0:
|
||||
self.control = self.callback_handler.on_step_begin(self.args, self.state, self.control)
|
||||
self.control = self.callback_handler.on_step_begin(
|
||||
self.args, self.state, self.control
|
||||
)
|
||||
|
||||
tr_loss += self.training_step(model, inputs)
|
||||
if (
|
||||
((step + 1) % self.args.gradient_accumulation_steps != 0)
|
||||
and self.args.local_rank != -1
|
||||
and _use_ddp_no_sync
|
||||
):
|
||||
with model.no_sync():
|
||||
tr_loss += self.training_step(model, inputs)
|
||||
else:
|
||||
tr_loss += self.training_step(model, inputs)
|
||||
self._total_flos += self.floating_point_ops(inputs)
|
||||
|
||||
if (step + 1) % self.args.gradient_accumulation_steps == 0 or (
|
||||
@@ -697,11 +850,17 @@ class Trainer:
|
||||
):
|
||||
if self.args.fp16 and _use_native_amp:
|
||||
self.scaler.unscale_(self.optimizer)
|
||||
torch.nn.utils.clip_grad_norm_(model.parameters(), self.args.max_grad_norm)
|
||||
torch.nn.utils.clip_grad_norm_(
|
||||
model.parameters(), self.args.max_grad_norm
|
||||
)
|
||||
elif self.args.fp16 and _use_apex:
|
||||
torch.nn.utils.clip_grad_norm_(amp.master_params(self.optimizer), self.args.max_grad_norm)
|
||||
torch.nn.utils.clip_grad_norm_(
|
||||
amp.master_params(self.optimizer), self.args.max_grad_norm
|
||||
)
|
||||
else:
|
||||
torch.nn.utils.clip_grad_norm_(model.parameters(), self.args.max_grad_norm)
|
||||
torch.nn.utils.clip_grad_norm_(
|
||||
model.parameters(), self.args.max_grad_norm
|
||||
)
|
||||
|
||||
if is_torch_tpu_available():
|
||||
xm.optimizer_step(self.optimizer)
|
||||
@@ -715,14 +874,18 @@ class Trainer:
|
||||
model.zero_grad()
|
||||
self.state.global_step += 1
|
||||
self.state.epoch = epoch + (step + 1) / len(epoch_iterator)
|
||||
self.control = self.callback_handler.on_step_end(self.args, self.state, self.control)
|
||||
self.control = self.callback_handler.on_step_end(
|
||||
self.args, self.state, self.control
|
||||
)
|
||||
|
||||
self._maybe_log_save_evalute(tr_loss, model, trial, epoch)
|
||||
|
||||
if self.control.should_epoch_stop or self.control.should_training_stop:
|
||||
break
|
||||
|
||||
self.control = self.callback_handler.on_epoch_end(self.args, self.state, self.control)
|
||||
self.control = self.callback_handler.on_epoch_end(
|
||||
self.args, self.state, self.control
|
||||
)
|
||||
self._maybe_log_save_evalute(tr_loss, model, trial, epoch)
|
||||
|
||||
if self.args.tpu_metrics_debug or self.args.debug:
|
||||
@@ -741,27 +904,42 @@ class Trainer:
|
||||
# Clean the state at the end of training
|
||||
delattr(self, "_past")
|
||||
|
||||
logger.info("\n\nTraining completed. Do not forget to share your model on huggingface.co/models =)\n\n")
|
||||
if self.args.load_best_model_at_end and self.state.best_model_checkpoint is not None:
|
||||
logger.info(
|
||||
"\n\nTraining completed. Do not forget to share your model on huggingface.co/models =)\n\n"
|
||||
)
|
||||
if (
|
||||
self.args.load_best_model_at_end
|
||||
and self.state.best_model_checkpoint is not None
|
||||
):
|
||||
logger.info(
|
||||
f"Loading best model from {self.state.best_model_checkpoint} (score: {self.state.best_metric})."
|
||||
)
|
||||
if isinstance(model, PreTrainedModel):
|
||||
self.model = model.from_pretrained(self.state.best_model_checkpoint)
|
||||
self.model = self.model.to(self.args.device)
|
||||
if not self.args.model_parallel:
|
||||
self.model = model.to(self.args.device)
|
||||
|
||||
else:
|
||||
state_dict = torch.load(os.path.join(self.state.best_model_checkpoint, WEIGHTS_NAME))
|
||||
state_dict = torch.load(
|
||||
os.path.join(self.state.best_model_checkpoint, WEIGHTS_NAME)
|
||||
)
|
||||
self.model.load_state_dict(state_dict)
|
||||
|
||||
self.control = self.callback_handler.on_train_end(self.args, self.state, self.control)
|
||||
self.control = self.callback_handler.on_train_end(
|
||||
self.args, self.state, self.control
|
||||
)
|
||||
|
||||
return TrainOutput(self.state.global_step, tr_loss.item() / self.state.global_step)
|
||||
return TrainOutput(
|
||||
self.state.global_step, tr_loss.item() / self.state.global_step
|
||||
)
|
||||
|
||||
def _maybe_log_save_evalute(self, tr_loss, model, trial, epoch):
|
||||
if self.control.should_log:
|
||||
logs: Dict[str, float] = {}
|
||||
tr_loss_scalar = tr_loss.item()
|
||||
logs["loss"] = (tr_loss_scalar - self._logging_loss_scalar) / self.args.logging_steps
|
||||
logs["loss"] = (
|
||||
tr_loss_scalar - self._logging_loss_scalar
|
||||
) / self.args.logging_steps
|
||||
# backward compatibility for pytorch schedulers
|
||||
logs["learning_rate"] = (
|
||||
self.lr_scheduler.get_last_lr()[0]
|
||||
@@ -776,23 +954,35 @@ class Trainer:
|
||||
if self.control.should_evaluate:
|
||||
metrics = self.evaluate()
|
||||
self._report_to_hp_search(trial, epoch, metrics)
|
||||
self.control = self.callback_handler.on_evaluate(self.args, self.state, self.control, metrics)
|
||||
self.control = self.callback_handler.on_evaluate(
|
||||
self.args, self.state, self.control, metrics
|
||||
)
|
||||
|
||||
if self.control.should_save:
|
||||
self._save_checkpoint(model, trial, metrics=metrics)
|
||||
self.control = self.callback_handler.on_save(self.args, self.state, self.control)
|
||||
self.control = self.callback_handler.on_save(
|
||||
self.args, self.state, self.control
|
||||
)
|
||||
|
||||
def _save_checkpoint(self, model, trial, metrics=None):
|
||||
# In all cases (even distributed/parallel), self.model is always a reference
|
||||
# to the model we want to save.
|
||||
if hasattr(model, "module"):
|
||||
assert model.module is self.model, f"Module {model.module} should be a reference to self.model"
|
||||
assert (
|
||||
model.module is self.model
|
||||
), f"Module {model.module} should be a reference to self.model"
|
||||
else:
|
||||
assert model is self.model, f"Model {model} should be a reference to self.model"
|
||||
assert (
|
||||
model is self.model
|
||||
), f"Model {model} should be a reference to self.model"
|
||||
# Save model checkpoint
|
||||
checkpoint_folder = f"{PREFIX_CHECKPOINT_DIR}-{self.state.global_step}"
|
||||
if self.hp_search_backend is not None and trial is not None:
|
||||
run_id = trial.number if self.hp_search_backend == HPSearchBackend.OPTUNA else tune.get_trial_id()
|
||||
run_id = (
|
||||
trial.number
|
||||
if self.hp_search_backend == HPSearchBackend.OPTUNA
|
||||
else tune.get_trial_id()
|
||||
)
|
||||
checkpoint_folder += f"-run-{run_id}"
|
||||
output_dir = os.path.join(self.args.output_dir, checkpoint_folder)
|
||||
|
||||
@@ -802,14 +992,24 @@ class Trainer:
|
||||
# Save optimizer and scheduler
|
||||
if is_torch_tpu_available():
|
||||
xm.rendezvous("saving_optimizer_states")
|
||||
xm.save(self.optimizer.state_dict(), os.path.join(output_dir, "optimizer.pt"))
|
||||
xm.save(
|
||||
self.optimizer.state_dict(), os.path.join(output_dir, "optimizer.pt")
|
||||
)
|
||||
with warnings.catch_warnings(record=True) as caught_warnings:
|
||||
xm.save(self.lr_scheduler.state_dict(), os.path.join(output_dir, "scheduler.pt"))
|
||||
xm.save(
|
||||
self.lr_scheduler.state_dict(),
|
||||
os.path.join(output_dir, "scheduler.pt"),
|
||||
)
|
||||
reissue_pt_warnings(caught_warnings)
|
||||
elif self.is_world_process_zero():
|
||||
torch.save(self.optimizer.state_dict(), os.path.join(output_dir, "optimizer.pt"))
|
||||
torch.save(
|
||||
self.optimizer.state_dict(), os.path.join(output_dir, "optimizer.pt")
|
||||
)
|
||||
with warnings.catch_warnings(record=True) as caught_warnings:
|
||||
torch.save(self.lr_scheduler.state_dict(), os.path.join(output_dir, "scheduler.pt"))
|
||||
torch.save(
|
||||
self.lr_scheduler.state_dict(),
|
||||
os.path.join(output_dir, "scheduler.pt"),
|
||||
)
|
||||
reissue_pt_warnings(caught_warnings)
|
||||
|
||||
# Determine the new best metric / best model checkpoint
|
||||
@@ -843,7 +1043,7 @@ class Trainer:
|
||||
n_trials: int = 20,
|
||||
direction: str = "minimize",
|
||||
backend: Optional[Union["str", HPSearchBackend]] = None,
|
||||
**kwargs
|
||||
**kwargs,
|
||||
) -> BestRun:
|
||||
"""
|
||||
Launch an hyperparameter search using ``optuna`` or ``Ray Tune``. The optimized quantity is determined by
|
||||
@@ -882,7 +1082,7 @@ class Trainer:
|
||||
- the documentation of `tune.run <https://docs.ray.io/en/latest/tune/api_docs/execution.html#tune-run>`__
|
||||
|
||||
Returns:
|
||||
:class:`transformers.trainer_utils.BestRun`: All the informations about the best run.
|
||||
:class:`transformers.trainer_utils.BestRun`: All the information about the best run.
|
||||
"""
|
||||
if backend is None:
|
||||
backend = default_hp_search_backend()
|
||||
@@ -894,7 +1094,9 @@ class Trainer:
|
||||
)
|
||||
backend = HPSearchBackend(backend)
|
||||
if backend == HPSearchBackend.OPTUNA and not is_optuna_available():
|
||||
raise RuntimeError("You picked the optuna backend, but it is not installed. Use `pip install optuna`.")
|
||||
raise RuntimeError(
|
||||
"You picked the optuna backend, but it is not installed. Use `pip install optuna`."
|
||||
)
|
||||
if backend == HPSearchBackend.RAY and not is_ray_available():
|
||||
raise RuntimeError(
|
||||
"You picked the Ray Tune backend, but it is not installed. Use `pip install 'ray[tune]'`."
|
||||
@@ -907,9 +1109,17 @@ class Trainer:
|
||||
)
|
||||
|
||||
self.hp_space = default_hp_space[backend] if hp_space is None else hp_space
|
||||
self.compute_objective = default_compute_objective if compute_objective is None else compute_objective
|
||||
self.compute_objective = (
|
||||
default_compute_objective
|
||||
if compute_objective is None
|
||||
else compute_objective
|
||||
)
|
||||
|
||||
run_hp_search = run_hp_search_optuna if backend == HPSearchBackend.OPTUNA else run_hp_search_ray
|
||||
run_hp_search = (
|
||||
run_hp_search_optuna
|
||||
if backend == HPSearchBackend.OPTUNA
|
||||
else run_hp_search_ray
|
||||
)
|
||||
best_run = run_hp_search(self, n_trials, direction, **kwargs)
|
||||
|
||||
self.hp_search_backend = None
|
||||
@@ -937,11 +1147,15 @@ class Trainer:
|
||||
if self._total_flos is not None:
|
||||
self.store_flos()
|
||||
logs["total_flos"] = self.state.total_flos
|
||||
self.control = self.callback_handler.on_log(self.args, self.state, self.control, logs)
|
||||
self.control = self.callback_handler.on_log(
|
||||
self.args, self.state, self.control, logs
|
||||
)
|
||||
output = {**logs, **{"step": self.state.global_step}}
|
||||
self.state.log_history.append(output)
|
||||
|
||||
def _prepare_inputs(self, inputs: Dict[str, Union[torch.Tensor, Any]]) -> Dict[str, Union[torch.Tensor, Any]]:
|
||||
def _prepare_inputs(
|
||||
self, inputs: Dict[str, Union[torch.Tensor, Any]]
|
||||
) -> Dict[str, Union[torch.Tensor, Any]]:
|
||||
"""
|
||||
Prepare :obj:`inputs` before feeding them to the model, converting them to tensors if they are not already and
|
||||
handling potential state.
|
||||
@@ -955,7 +1169,9 @@ class Trainer:
|
||||
|
||||
return inputs
|
||||
|
||||
def training_step(self, model: nn.Module, inputs: Dict[str, Union[torch.Tensor, Any]]) -> torch.Tensor:
|
||||
def training_step(
|
||||
self, model: nn.Module, inputs: Dict[str, Union[torch.Tensor, Any]]
|
||||
) -> torch.Tensor:
|
||||
"""
|
||||
Perform a training step on a batch of inputs.
|
||||
|
||||
@@ -989,7 +1205,7 @@ class Trainer:
|
||||
else:
|
||||
loss = self.compute_loss(model, inputs)
|
||||
|
||||
if self.args.n_gpu > 1:
|
||||
if self.args.n_gpu > 1 and not self.args.model_parallel:
|
||||
loss = loss.mean() # mean() to average on multi-gpu parallel training
|
||||
|
||||
if self.args.gradient_accumulation_steps > 1:
|
||||
@@ -1027,7 +1243,10 @@ class Trainer:
|
||||
|
||||
This method is deprecated, use :meth:`~transformers.Trainer.is_local_process_zero` instead.
|
||||
"""
|
||||
warnings.warn("This method is deprecated, use `Trainer.is_local_process_zero()` instead.", FutureWarning)
|
||||
warnings.warn(
|
||||
"This method is deprecated, use `Trainer.is_local_process_zero()` instead.",
|
||||
FutureWarning,
|
||||
)
|
||||
return self.is_local_process_zero()
|
||||
|
||||
def is_local_process_zero(self) -> bool:
|
||||
@@ -1049,7 +1268,10 @@ class Trainer:
|
||||
|
||||
This method is deprecated, use :meth:`~transformers.Trainer.is_world_process_zero` instead.
|
||||
"""
|
||||
warnings.warn("This method is deprecated, use `Trainer.is_world_process_zero()` instead.", FutureWarning)
|
||||
warnings.warn(
|
||||
"This method is deprecated, use `Trainer.is_world_process_zero()` instead.",
|
||||
FutureWarning,
|
||||
)
|
||||
return self.is_world_process_zero()
|
||||
|
||||
def is_world_process_zero(self) -> bool:
|
||||
@@ -1086,7 +1308,9 @@ class Trainer:
|
||||
# They can then be reloaded using `from_pretrained()`
|
||||
xm.rendezvous("saving_checkpoint")
|
||||
if not isinstance(self.model, PreTrainedModel):
|
||||
logger.info("Trainer.model is not a `PreTrainedModel`, only saving its state dict.")
|
||||
logger.info(
|
||||
"Trainer.model is not a `PreTrainedModel`, only saving its state dict."
|
||||
)
|
||||
state_dict = self.model.state_dict()
|
||||
xm.save(state_dict, os.path.join(output_dir, WEIGHTS_NAME))
|
||||
else:
|
||||
@@ -1101,7 +1325,9 @@ class Trainer:
|
||||
# Save a trained model and configuration using `save_pretrained()`.
|
||||
# They can then be reloaded using `from_pretrained()`
|
||||
if not isinstance(self.model, PreTrainedModel):
|
||||
logger.info("Trainer.model is not a `PreTrainedModel`, only saving its state dict.")
|
||||
logger.info(
|
||||
"Trainer.model is not a `PreTrainedModel`, only saving its state dict."
|
||||
)
|
||||
state_dict = self.model.state_dict()
|
||||
torch.save(state_dict, os.path.join(output_dir, WEIGHTS_NAME))
|
||||
else:
|
||||
@@ -1116,14 +1342,20 @@ class Trainer:
|
||||
# Storing the number of floating-point operations that went into the model
|
||||
if self._total_flos is not None:
|
||||
if self.args.local_rank != -1:
|
||||
self.state.total_flos = distributed_broadcast_scalars([self._total_flos]).sum().item()
|
||||
self.state.total_flos = (
|
||||
distributed_broadcast_scalars([self._total_flos]).sum().item()
|
||||
)
|
||||
else:
|
||||
self.state.total_flos = self._total_flos
|
||||
|
||||
def _sorted_checkpoints(self, checkpoint_prefix=PREFIX_CHECKPOINT_DIR, use_mtime=False) -> List[str]:
|
||||
def _sorted_checkpoints(
|
||||
self, checkpoint_prefix=PREFIX_CHECKPOINT_DIR, use_mtime=False
|
||||
) -> List[str]:
|
||||
ordering_and_checkpoint_path = []
|
||||
|
||||
glob_checkpoints = [str(x) for x in Path(self.args.output_dir).glob(f"{checkpoint_prefix}-*")]
|
||||
glob_checkpoints = [
|
||||
str(x) for x in Path(self.args.output_dir).glob(f"{checkpoint_prefix}-*")
|
||||
]
|
||||
|
||||
for path in glob_checkpoints:
|
||||
if use_mtime:
|
||||
@@ -1131,14 +1363,21 @@ class Trainer:
|
||||
else:
|
||||
regex_match = re.match(f".*{checkpoint_prefix}-([0-9]+)", path)
|
||||
if regex_match and regex_match.groups():
|
||||
ordering_and_checkpoint_path.append((int(regex_match.groups()[0]), path))
|
||||
ordering_and_checkpoint_path.append(
|
||||
(int(regex_match.groups()[0]), path)
|
||||
)
|
||||
|
||||
checkpoints_sorted = sorted(ordering_and_checkpoint_path)
|
||||
checkpoints_sorted = [checkpoint[1] for checkpoint in checkpoints_sorted]
|
||||
# Make sure we don't delete the best model.
|
||||
if self.state.best_model_checkpoint is not None:
|
||||
best_model_index = checkpoints_sorted.index(self.state.best_model_checkpoint)
|
||||
checkpoints_sorted[best_model_index], checkpoints_sorted[best_model_index][-1] = (
|
||||
best_model_index = checkpoints_sorted.index(
|
||||
self.state.best_model_checkpoint
|
||||
)
|
||||
(
|
||||
checkpoints_sorted[best_model_index],
|
||||
checkpoints_sorted[best_model_index][-1],
|
||||
) = (
|
||||
checkpoints_sorted[-1],
|
||||
checkpoints_sorted[best_model_index],
|
||||
)
|
||||
@@ -1153,10 +1392,16 @@ class Trainer:
|
||||
if len(checkpoints_sorted) <= self.args.save_total_limit:
|
||||
return
|
||||
|
||||
number_of_checkpoints_to_delete = max(0, len(checkpoints_sorted) - self.args.save_total_limit)
|
||||
number_of_checkpoints_to_delete = max(
|
||||
0, len(checkpoints_sorted) - self.args.save_total_limit
|
||||
)
|
||||
checkpoints_to_be_deleted = checkpoints_sorted[:number_of_checkpoints_to_delete]
|
||||
for checkpoint in checkpoints_to_be_deleted:
|
||||
logger.info("Deleting older checkpoint [{}] due to args.save_total_limit".format(checkpoint))
|
||||
logger.info(
|
||||
"Deleting older checkpoint [{}] due to args.save_total_limit".format(
|
||||
checkpoint
|
||||
)
|
||||
)
|
||||
shutil.rmtree(checkpoint)
|
||||
|
||||
def evaluate(self, eval_dataset: Optional[Dataset] = None) -> Dict[str, float]:
|
||||
@@ -1214,7 +1459,10 @@ class Trainer:
|
||||
return self.prediction_loop(test_dataloader, description="Prediction")
|
||||
|
||||
def prediction_loop(
|
||||
self, dataloader: DataLoader, description: str, prediction_loss_only: Optional[bool] = None
|
||||
self,
|
||||
dataloader: DataLoader,
|
||||
description: str,
|
||||
prediction_loss_only: Optional[bool] = None,
|
||||
) -> PredictionOutput:
|
||||
"""
|
||||
Prediction/evaluation loop, shared by :obj:`Trainer.evaluate()` and :obj:`Trainer.predict()`.
|
||||
@@ -1226,15 +1474,19 @@ class Trainer:
|
||||
"The `_prediction_loop` method is deprecated and won't be called in a future version, define `prediction_loop` in your subclass.",
|
||||
FutureWarning,
|
||||
)
|
||||
return self._prediction_loop(dataloader, description, prediction_loss_only=prediction_loss_only)
|
||||
return self._prediction_loop(
|
||||
dataloader, description, prediction_loss_only=prediction_loss_only
|
||||
)
|
||||
|
||||
prediction_loss_only = (
|
||||
prediction_loss_only if prediction_loss_only is not None else self.args.prediction_loss_only
|
||||
prediction_loss_only
|
||||
if prediction_loss_only is not None
|
||||
else self.args.prediction_loss_only
|
||||
)
|
||||
|
||||
model = self.model
|
||||
# multi-gpu eval
|
||||
if self.args.n_gpu > 1:
|
||||
# multi-gpu eval without model parallel
|
||||
if self.args.n_gpu > 1 and not self.args.model_parallel:
|
||||
model = torch.nn.DataParallel(model)
|
||||
else:
|
||||
model = self.model
|
||||
@@ -1251,7 +1503,9 @@ class Trainer:
|
||||
model.eval()
|
||||
|
||||
if is_torch_tpu_available():
|
||||
dataloader = pl.ParallelLoader(dataloader, [self.args.device]).per_device_loader(self.args.device)
|
||||
dataloader = pl.ParallelLoader(
|
||||
dataloader, [self.args.device]
|
||||
).per_device_loader(self.args.device)
|
||||
|
||||
if self.args.past_index >= 0:
|
||||
self._past = None
|
||||
@@ -1259,15 +1513,23 @@ class Trainer:
|
||||
self.callback_handler.eval_dataloader = dataloader
|
||||
|
||||
for inputs in dataloader:
|
||||
loss, logits, labels = self.prediction_step(model, inputs, prediction_loss_only)
|
||||
loss, logits, labels = self.prediction_step(
|
||||
model, inputs, prediction_loss_only
|
||||
)
|
||||
batch_size = inputs[list(inputs.keys())[0]].shape[0]
|
||||
if loss is not None:
|
||||
eval_losses.extend([loss] * batch_size)
|
||||
if logits is not None:
|
||||
preds = logits if preds is None else nested_concat(preds, logits, dim=0)
|
||||
if labels is not None:
|
||||
label_ids = labels if label_ids is None else nested_concat(label_ids, labels, dim=0)
|
||||
self.control = self.callback_handler.on_prediction_step(self.args, self.state, self.control)
|
||||
label_ids = (
|
||||
labels
|
||||
if label_ids is None
|
||||
else nested_concat(label_ids, labels, dim=0)
|
||||
)
|
||||
self.control = self.callback_handler.on_prediction_step(
|
||||
self.args, self.state, self.control
|
||||
)
|
||||
|
||||
if self.args.past_index and hasattr(self, "_past"):
|
||||
# Clean the state at the end of the evaluation loop
|
||||
@@ -1276,9 +1538,13 @@ class Trainer:
|
||||
if self.args.local_rank != -1:
|
||||
# In distributed mode, concatenate all results from all nodes:
|
||||
if preds is not None:
|
||||
preds = distributed_concat(preds, num_total_examples=self.num_examples(dataloader))
|
||||
preds = distributed_concat(
|
||||
preds, num_total_examples=self.num_examples(dataloader)
|
||||
)
|
||||
if label_ids is not None:
|
||||
label_ids = distributed_concat(label_ids, num_total_examples=self.num_examples(dataloader))
|
||||
label_ids = distributed_concat(
|
||||
label_ids, num_total_examples=self.num_examples(dataloader)
|
||||
)
|
||||
elif is_torch_tpu_available():
|
||||
# tpu-comment: Get all predictions and labels from all worker shards of eval dataset
|
||||
if preds is not None:
|
||||
@@ -1286,7 +1552,9 @@ class Trainer:
|
||||
if label_ids is not None:
|
||||
label_ids = nested_xla_mesh_reduce(label_ids, "eval_label_ids")
|
||||
if eval_losses is not None:
|
||||
eval_losses = xm.mesh_reduce("eval_losses", torch.tensor(eval_losses), torch.cat).tolist()
|
||||
eval_losses = xm.mesh_reduce(
|
||||
"eval_losses", torch.tensor(eval_losses), torch.cat
|
||||
).tolist()
|
||||
|
||||
# Finally, turn the aggregated tensors into numpy arrays.
|
||||
if preds is not None:
|
||||
@@ -1294,14 +1562,22 @@ class Trainer:
|
||||
if label_ids is not None:
|
||||
label_ids = nested_numpify(label_ids)
|
||||
|
||||
if self.compute_metrics is not None and preds is not None and label_ids is not None:
|
||||
metrics = self.compute_metrics(EvalPrediction(predictions=preds, label_ids=label_ids))
|
||||
if (
|
||||
self.compute_metrics is not None
|
||||
and preds is not None
|
||||
and label_ids is not None
|
||||
):
|
||||
metrics = self.compute_metrics(
|
||||
EvalPrediction(predictions=preds, label_ids=label_ids)
|
||||
)
|
||||
else:
|
||||
metrics = {}
|
||||
if len(eval_losses) > 0:
|
||||
if self.args.local_rank != -1:
|
||||
metrics["eval_loss"] = (
|
||||
distributed_broadcast_scalars(eval_losses, num_total_examples=self.num_examples(dataloader))
|
||||
distributed_broadcast_scalars(
|
||||
eval_losses, num_total_examples=self.num_examples(dataloader)
|
||||
)
|
||||
.mean()
|
||||
.item()
|
||||
)
|
||||
@@ -1316,7 +1592,10 @@ class Trainer:
|
||||
return PredictionOutput(predictions=preds, label_ids=label_ids, metrics=metrics)
|
||||
|
||||
def prediction_step(
|
||||
self, model: nn.Module, inputs: Dict[str, Union[torch.Tensor, Any]], prediction_loss_only: bool
|
||||
self,
|
||||
model: nn.Module,
|
||||
inputs: Dict[str, Union[torch.Tensor, Any]],
|
||||
prediction_loss_only: bool,
|
||||
) -> Tuple[Optional[float], Optional[torch.Tensor], Optional[torch.Tensor]]:
|
||||
"""
|
||||
Perform an evaluation step on :obj:`model` using obj:`inputs`.
|
||||
@@ -1352,9 +1631,13 @@ class Trainer:
|
||||
# Slicing so we get a tuple even if `outputs` is a `ModelOutput`.
|
||||
logits = outputs[:]
|
||||
if self.args.past_index >= 0:
|
||||
self._past = outputs[self.args.past_index if has_labels else self.args.past_index - 1]
|
||||
self._past = outputs[
|
||||
self.args.past_index if has_labels else self.args.past_index - 1
|
||||
]
|
||||
# Remove the past from the logits.
|
||||
logits = logits[: self.args.past_index - 1] + logits[self.args.past_index :]
|
||||
logits = (
|
||||
logits[: self.args.past_index - 1] + logits[self.args.past_index :]
|
||||
)
|
||||
|
||||
if prediction_loss_only:
|
||||
return (loss, None, None)
|
||||
@@ -1398,7 +1681,11 @@ class Trainer:
|
||||
|
||||
@staticmethod
|
||||
def _actual_model(
|
||||
model: Union[torch.nn.DataParallel, torch.nn.parallel.DistributedDataParallel, torch.nn.modules.Module]
|
||||
model: Union[
|
||||
torch.nn.DataParallel,
|
||||
torch.nn.parallel.DistributedDataParallel,
|
||||
torch.nn.modules.Module,
|
||||
]
|
||||
) -> torch.nn.modules.Module:
|
||||
"""
|
||||
|
||||
@@ -1409,7 +1696,9 @@ class Trainer:
|
||||
Returns:
|
||||
:obj:`torch.nn.modules.Module`: unwrapped module
|
||||
"""
|
||||
if isinstance(model, torch.nn.DataParallel) or isinstance(model, torch.nn.parallel.DistributedDataParallel):
|
||||
if isinstance(model, torch.nn.DataParallel) or isinstance(
|
||||
model, torch.nn.parallel.DistributedDataParallel
|
||||
):
|
||||
model = model.module
|
||||
else:
|
||||
model = model
|
||||
|
||||
@@ -443,7 +443,8 @@ class ProgressCallback(TrainerCallback):
|
||||
|
||||
def on_evaluate(self, args, state, control, **kwargs):
|
||||
if state.is_local_process_zero:
|
||||
self.prediction_bar.close()
|
||||
if self.prediction_bar is not None:
|
||||
self.prediction_bar.close()
|
||||
self.prediction_bar = None
|
||||
|
||||
def on_log(self, args, state, control, logs=None, **kwargs):
|
||||
|
||||
@@ -54,6 +54,8 @@ class TrainingArguments:
|
||||
:obj:`"no"`.
|
||||
do_predict (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether to run predictions on the test set or not.
|
||||
model_parallel (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
If there is more than one device, whether to distribute the model's modules across devices.
|
||||
evaluation_strategy (:obj:`str` or :class:`~transformers.trainer_utils.EvaluationStrategy`, `optional`, defaults to :obj:`"no"`):
|
||||
The evaluation strategy to adopt during training. Possible values are:
|
||||
|
||||
@@ -94,7 +96,7 @@ class TrainingArguments:
|
||||
logging_dir (:obj:`str`, `optional`):
|
||||
Tensorboard log directory. Will default to `runs/**CURRENT_DATETIME_HOSTNAME**`.
|
||||
logging_first_step (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Wheter to log and evalulate the first :obj:`global_step` or not.
|
||||
Whether to log and evaluate the first :obj:`global_step` or not.
|
||||
logging_steps (:obj:`int`, `optional`, defaults to 500):
|
||||
Number of update steps between two logs.
|
||||
save_steps (:obj:`int`, `optional`, defaults to 500):
|
||||
@@ -114,7 +116,7 @@ class TrainingArguments:
|
||||
local_rank (:obj:`int`, `optional`, defaults to -1):
|
||||
During distributed training, the rank of the process.
|
||||
tpu_num_cores (:obj:`int`, `optional`):
|
||||
When training on TPU, the mumber of TPU cores (automatically passed by launcher script).
|
||||
When training on TPU, the number of TPU cores (automatically passed by launcher script).
|
||||
debug (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
When training on TPU, whether to print debug metrics or not.
|
||||
dataloader_drop_last (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
@@ -159,7 +161,7 @@ class TrainingArguments:
|
||||
Will default to :obj:`"loss"` if unspecified and :obj:`load_best_model_at_end=True` (to use the evaluation
|
||||
loss).
|
||||
|
||||
If you set this value, :obj:`greater_is_better` will defaut to :obj:`True`. Don't forget to set it to
|
||||
If you set this value, :obj:`greater_is_better` will default to :obj:`True`. Don't forget to set it to
|
||||
:obj:`False` if your metric is better when lower.
|
||||
greater_is_better (:obj:`bool`, `optional`)
|
||||
Use in conjunction with :obj:`load_best_model_at_end` and :obj:`metric_for_best_model` to specify if better
|
||||
@@ -186,6 +188,12 @@ class TrainingArguments:
|
||||
do_train: bool = field(default=False, metadata={"help": "Whether to run training."})
|
||||
do_eval: bool = field(default=None, metadata={"help": "Whether to run eval on the dev set."})
|
||||
do_predict: bool = field(default=False, metadata={"help": "Whether to run predictions on the test set."})
|
||||
model_parallel: bool = field(
|
||||
default=False,
|
||||
metadata={
|
||||
"help": "If there are more than one devices, whether to use model parallelism to distribute the model's modules across devices."
|
||||
},
|
||||
)
|
||||
evaluate_during_training: bool = field(
|
||||
default=None,
|
||||
metadata={"help": "Run evaluation during training at each logging step."},
|
||||
@@ -354,7 +362,11 @@ class TrainingArguments:
|
||||
"version. Using `--per_device_train_batch_size` is preferred."
|
||||
)
|
||||
per_device_batch_size = self.per_gpu_train_batch_size or self.per_device_train_batch_size
|
||||
return per_device_batch_size * max(1, self.n_gpu)
|
||||
if not self.model_parallel:
|
||||
train_batch_size = per_device_batch_size * max(1, self.n_gpu)
|
||||
else:
|
||||
train_batch_size = per_device_batch_size
|
||||
return train_batch_size
|
||||
|
||||
@property
|
||||
def eval_batch_size(self) -> int:
|
||||
@@ -367,7 +379,11 @@ class TrainingArguments:
|
||||
"version. Using `--per_device_eval_batch_size` is preferred."
|
||||
)
|
||||
per_device_batch_size = self.per_gpu_eval_batch_size or self.per_device_eval_batch_size
|
||||
return per_device_batch_size * max(1, self.n_gpu)
|
||||
if not self.model_parallel:
|
||||
eval_batch_size = per_device_batch_size * max(1, self.n_gpu)
|
||||
else:
|
||||
eval_batch_size = per_device_batch_size
|
||||
return eval_batch_size
|
||||
|
||||
@cached_property
|
||||
@torch_required
|
||||
|
||||
@@ -66,7 +66,7 @@ class TFTrainingArguments(TrainingArguments):
|
||||
logging_dir (:obj:`str`, `optional`):
|
||||
Tensorboard log directory. Will default to `runs/**CURRENT_DATETIME_HOSTNAME**`.
|
||||
logging_first_step (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Wheter to log and evalulate the first :obj:`global_step` or not.
|
||||
Whether to log and evaluate the first :obj:`global_step` or not.
|
||||
logging_steps (:obj:`int`, `optional`, defaults to 500):
|
||||
Number of update steps between two logs.
|
||||
save_steps (:obj:`int`, `optional`, defaults to 500):
|
||||
@@ -86,7 +86,7 @@ class TFTrainingArguments(TrainingArguments):
|
||||
local_rank (:obj:`int`, `optional`, defaults to -1):
|
||||
During distributed training, the rank of the process.
|
||||
tpu_num_cores (:obj:`int`, `optional`):
|
||||
When training on TPU, the mumber of TPU cores (automatically passed by launcher script).
|
||||
When training on TPU, the number of TPU cores (automatically passed by launcher script).
|
||||
debug (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
Whether to activate the trace to record computation graphs and profiling information or not.
|
||||
dataloader_drop_last (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||
|
||||
@@ -1256,6 +1256,15 @@ class OpenAIGPTDoubleHeadsModel:
|
||||
requires_pytorch(self)
|
||||
|
||||
|
||||
class OpenAIGPTForSequenceClassification:
|
||||
def __init__(self, *args, **kwargs):
|
||||
requires_pytorch(self)
|
||||
|
||||
@classmethod
|
||||
def from_pretrained(self, *args, **kwargs):
|
||||
requires_pytorch(self)
|
||||
|
||||
|
||||
class OpenAIGPTLMHeadModel:
|
||||
def __init__(self, *args, **kwargs):
|
||||
requires_pytorch(self)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# coding=utf-8
|
||||
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: int, devices: list):
|
||||
"""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))
|
||||
@@ -310,7 +310,7 @@ XXX_INPUTS_DOCSTRING = r"""
|
||||
Mask values selected in ``[0, 1]``:
|
||||
|
||||
- 1 for tokens that are **not masked**,
|
||||
- 0 for tokens that are **maked**.
|
||||
- 0 for tokens that are **masked**.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`Numpy array` or :obj:`tf.Tensor` of shape :obj:`({0})`, `optional`):
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user