Compare commits
52
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b55bc33ba0 | ||
|
|
f604cbd0e2 | ||
|
|
30ef0ad019 | ||
|
|
5d9a2273bb | ||
|
|
630adb2b6a | ||
|
|
23bb7b9449 | ||
|
|
2e36f6d3d7 | ||
|
|
3ceb683378 | ||
|
|
5b01621675 | ||
|
|
dd132be1e3 | ||
|
|
3989328ce0 | ||
|
|
252f635e11 | ||
|
|
3e0f062106 | ||
|
|
fc2a4c88ce | ||
|
|
55bda52555 | ||
|
|
ad02c961c6 | ||
|
|
15550ce0d1 | ||
|
|
62427d0815 | ||
|
|
34706ba050 | ||
|
|
edf9ac11d4 | ||
|
|
b908f2e9dd | ||
|
|
af2e6bf87c | ||
|
|
7defc6670f | ||
|
|
84894974bd | ||
|
|
db0076a9df | ||
|
|
2d05480174 | ||
|
|
035678efdb | ||
|
|
b9c9e05381 | ||
|
|
9535bf1977 | ||
|
|
7822cd38a0 | ||
|
|
448c467256 | ||
|
|
c547f15a17 | ||
|
|
015f7812ed | ||
|
|
ef46ccb05c | ||
|
|
94cb73c2d2 | ||
|
|
a0eebdc404 | ||
|
|
7cb203fae4 | ||
|
|
9a687ebb77 | ||
|
|
839bfaedb2 | ||
|
|
2d184cb553 | ||
|
|
ca13618681 | ||
|
|
1e51bb717c | ||
|
|
241759101e | ||
|
|
7d7fe4997f | ||
|
|
0a97f6312a | ||
|
|
15a121fec5 | ||
|
|
15d45211f7 | ||
|
|
8a017cbb5a | ||
|
|
4bf5042240 | ||
|
|
e4512aab3b | ||
|
|
65be574aec | ||
|
|
31e67dd19f |
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
source .env/bin/activate
|
||||
pip install torch==1.4.0
|
||||
pip install torch
|
||||
pip install .[sklearn,testing]
|
||||
|
||||
- name: Are GPUs recognized by our DL frameworks
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ author = u'huggingface'
|
||||
# The short X.Y version
|
||||
version = u''
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = u'2.9.0'
|
||||
release = u'2.9.1'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
@@ -1,28 +1,90 @@
|
||||
MarianMTModel
|
||||
MarianMT
|
||||
----------------------------------------------------
|
||||
**DISCLAIMER:** If you see something strange,
|
||||
file a `Github Issue <https://github.com/huggingface/transformers/issues/new?assignees=&labels=&template=bug-report.md&title>`__ and assign
|
||||
@sshleifer
|
||||
These models are for machine translation. The list of supported language pairs can be found `here <https://huggingface.co/Helsinki-NLP>`__.
|
||||
|
||||
Opus Project
|
||||
~~~~~~~~~~~~
|
||||
The 1,000+ models were originally trained by `Jörg Tiedemann <https://researchportal.helsinki.fi/en/persons/j%C3%B6rg-tiedemann>`__ using the `Marian <https://marian-nmt.github.io/>`_ C++ library, which supports fast training and translation.
|
||||
All models are transformer encoder-decoders with 6 layers in each component. Each model's performance is documented in a model card.
|
||||
@sshleifer. Translations should be similar, but not identical to, output in the test set linked to in each model card.
|
||||
|
||||
Implementation Notes
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
- each model is about 298 MB on disk, there are 1,000+ models.
|
||||
- Models are named with the following patter 'Helsinki-NLP/opus-mt-{src_langs}-{targ_langs}'. If there are multiple source or target languages they are joined by a '+' symbol.
|
||||
- The list of supported language pairs can be found `here <https://huggingface.co/Helsinki-NLP>`__.
|
||||
- The 1,000+ models were originally trained by `Jörg Tiedemann <https://researchportal.helsinki.fi/en/persons/j%C3%B6rg-tiedemann>`__ using the `Marian <https://marian-nmt.github.io/>`_ C++ library, which supports fast training and translation.
|
||||
- All models are transformer encoder-decoders with 6 layers in each component. Each model's performance is documented in a model card.
|
||||
- the 80 opus models that require BPE preprocessing are not supported.
|
||||
- There is an outstanding issue w.r.t multilingual models and language codes.
|
||||
- The modeling code is the same as ``BartModel`` with a few minor modifications:
|
||||
- The modeling code is the same as ``BartForConditionalGeneration`` with a few minor modifications:
|
||||
- static (sinusoid) positional embeddings (``MarianConfig.static_position_embeddings=True``)
|
||||
- a new final_logits_bias (``MarianConfig.add_bias_logits=True``)
|
||||
- no layernorm_embedding (``MarianConfig.normalize_embedding=False``)
|
||||
- the model starts generating with pad_token_id (which has 0 token_embedding) as the prefix. (Bart uses <s/>)
|
||||
- Code to bulk convert models can be found in ``convert_marian_to_pytorch.py``
|
||||
|
||||
Naming
|
||||
~~~~~~
|
||||
- All model names use the following format: ``Helsinki-NLP/opus-mt-{src}-{tgt}``
|
||||
- The language codes used to name models are inconsistent. Two digit codes can usually be found `here <https://developers.google.com/admin-sdk/directory/v1/languages>`_, three digit codes require googling "language code {code}".
|
||||
- Codes formatted like ``es_AR`` are usually ``code_{region}``. That one is spanish documents from Argentina.
|
||||
|
||||
|
||||
Multilingual Models
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
All model names use the following format: ``Helsinki-NLP/opus-mt-{src}-{tgt}``:
|
||||
- if ``src`` is in all caps, the model supports multiple input languages, you can figure out which ones by looking at the model card, or the Group Members `mapping <https://gist.github.com/sshleifer/6d20e7761931b08e73c3219027b97b8a>`_ .
|
||||
- if ``tgt`` is in all caps, the model can output multiple languages, and you should specify a language code by prepending the desired output language to the src_text
|
||||
- You can see a tokenizer's supported language codes in ``tokenizer.supported_language_codes``
|
||||
|
||||
Example of translating english to many romance languages, using language codes:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from transformers import MarianMTModel, MarianTokenizer
|
||||
src_text = [
|
||||
'>>fr<< this is a sentence in english that we want to translate to french',
|
||||
'>>pt<< This should go to portuguese',
|
||||
'>>es<< And this to Spanish'
|
||||
]
|
||||
|
||||
model_name = 'Helsinki-NLP/opus-mt-en-ROMANCE'
|
||||
tokenizer = MarianTokenizer.from_pretrained(model_name)
|
||||
print(tokenizer.supported_language_codes)
|
||||
model = MarianMTModel.from_pretrained(model_name)
|
||||
translated = model.generate(**tokenizer.prepare_translation_batch(src_text))
|
||||
tgt_text = [tokenizer.decode(t, skip_special_tokens=True) for t in translated]
|
||||
# ["c'est une phrase en anglais que nous voulons traduire en français",
|
||||
# 'Isto deve ir para o português.',
|
||||
# 'Y esto al español']
|
||||
|
||||
Sometimes, models were trained on collections of languages that do not resolve to a group. In this case, _ is used as a separator for src or tgt, as in ``'Helsinki-NLP/opus-mt-en_el_es_fi-en_el_es_fi'``. These still require language codes.
|
||||
There are many supported regional language codes, like ``>>es_ES<<`` (Spain) and ``>>es_AR<<`` (Argentina), that do not seem to change translations. I have not found these to provide different results than just using ``>>es<<``.
|
||||
|
||||
For Example:
|
||||
- ``Helsinki-NLP/opus-mt-NORTH_EU-NORTH_EU``: translates from all NORTH_EU languages (see `mapping <https://gist.github.com/sshleifer/6d20e7761931b08e73c3219027b97b8a>`_) to all NORTH_EU languages. Use a special language code like ``>>de<<`` to specify output language.
|
||||
- ``Helsinki-NLP/opus-mt-ROMANCE-en``: translates from many romance languages to english, no codes needed since there is only 1 tgt language.
|
||||
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
GROUP_MEMBERS = {
|
||||
'ZH': ['cmn', 'cn', 'yue', 'ze_zh', 'zh_cn', 'zh_CN', 'zh_HK', 'zh_tw', 'zh_TW', 'zh_yue', 'zhs', 'zht', 'zh'],
|
||||
'ROMANCE': ['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'],
|
||||
'NORTH_EU': ['de', 'nl', 'fy', 'af', 'da', 'fo', 'is', 'no', 'nb', 'nn', 'sv'],
|
||||
'SCANDINAVIA': ['da', 'fo', 'is', 'no', 'nb', 'nn', 'sv'],
|
||||
'SAMI': ['se', 'sma', 'smj', 'smn', 'sms'],
|
||||
'NORWAY': ['nb_NO', 'nb', 'nn_NO', 'nn', 'nog', 'no_nb', 'no'],
|
||||
'CELTIC': ['ga', 'cy', 'br', 'gd', 'kw', 'gv']
|
||||
}
|
||||
|
||||
Code to see available pretrained models:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from transformers.hf_api import HfApi
|
||||
model_list = HfApi().model_list()
|
||||
org = "Helsinki-NLP"
|
||||
model_ids = [x.modelId for x in model_list if x.modelId.startswith(org)]
|
||||
suffix = [x.split('/')[1] for x in model_ids]
|
||||
multi_models = [f'{org}/{s}' for s in suffix if s != s.lower()]
|
||||
|
||||
MarianMTModel
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
+125
-23
@@ -404,48 +404,150 @@ Causal language modeling is the task of predicting the token following a sequenc
|
||||
model only attends to the left context (tokens on the left of the mask). Such a training is particularly interesting
|
||||
for generation tasks.
|
||||
|
||||
There is currently no pipeline to do causal language modeling/generation.
|
||||
Usually, the next token is predicted by sampling from the logits of the last hidden state the model produces from the input sequence.
|
||||
|
||||
Here is an example using the tokenizer and model. leveraging the :func:`~transformers.PreTrainedModel.generate` method
|
||||
to generate the tokens following the initial sequence in PyTorch, and creating a simple loop in TensorFlow.
|
||||
Here is an example using the tokenizer and model and leveraging the :func:`~transformers.PreTrainedModel.top_k_top_p_filtering` method to sample the next token following an input sequence of tokens.
|
||||
|
||||
::
|
||||
|
||||
## PYTORCH CODE
|
||||
from transformers import AutoModelWithLMHead, AutoTokenizer, top_k_top_p_filtering
|
||||
import torch
|
||||
from torch.nn import functional as F
|
||||
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("gpt2")
|
||||
model = AutoModelWithLMHead.from_pretrained("gpt2")
|
||||
|
||||
sequence = f"Hugging Face is based in DUMBO, New York City, and "
|
||||
|
||||
input_ids = tokenizer.encode(sequence, return_tensors="pt")
|
||||
|
||||
# get logits of last hidden state
|
||||
next_token_logits = model(input_ids)[0][:, -1, :]
|
||||
|
||||
# filter
|
||||
filtered_next_token_logits = top_k_top_p_filtering(next_token_logits, top_k=50, top_p=1.0)
|
||||
|
||||
# sample
|
||||
probs = F.softmax(filtered_next_token_logits, dim=-1)
|
||||
next_token = torch.multinomial(probs, num_samples=1)
|
||||
|
||||
generated = torch.cat([input_ids, next_token], dim=-1)
|
||||
|
||||
resulting_string = tokenizer.decode(generated.tolist()[0])
|
||||
print(resulting_string)
|
||||
## TENSORFLOW CODE
|
||||
from transformers import TFAutoModelWithLMHead, AutoTokenizer, tf_top_k_top_p_filtering
|
||||
import tensorflow as tf
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("gpt2")
|
||||
model = TFAutoModelWithLMHead.from_pretrained("gpt2")
|
||||
|
||||
sequence = f"Hugging Face is based in DUMBO, New York City, and "
|
||||
|
||||
input_ids = tokenizer.encode(sequence, return_tensors="tf")
|
||||
|
||||
# get logits of last hidden state
|
||||
next_token_logits = model(input_ids)[0][:, -1, :]
|
||||
|
||||
# filter
|
||||
filtered_next_token_logits = tf_top_k_top_p_filtering(next_token_logits, top_k=50, top_p=1.0)
|
||||
|
||||
# sample
|
||||
next_token = tf.random.categorical(filtered_next_token_logits, dtype=tf.int32, num_samples=1)
|
||||
|
||||
generated = tf.concat([input_ids, next_token], axis=1)
|
||||
|
||||
resulting_string = tokenizer.decode(generated.numpy().tolist()[0])
|
||||
print(resulting_string)
|
||||
|
||||
|
||||
This outputs a (hopefully) coherent next token following the original sequence, which is in our case is the word *has*:
|
||||
|
||||
::
|
||||
|
||||
Hugging Face is based in DUMBO, New York City, and has
|
||||
|
||||
In the next section, we show how this functionality is leveraged in :func:`~transformers.PreTrainedModel.generate` to generate multiple tokens up to a user-defined length.
|
||||
|
||||
Text Generation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In text generation (*a.k.a* *open-ended text generation*) the goal is to create a coherent portion of text that is a continuation from the given context. As an example, is it shown how *GPT-2* can be used in pipelines to generate text. As a default all models apply *Top-K* sampling when used in pipelines as configured in their respective configurations (see `gpt-2 config <https://s3.amazonaws.com/models.huggingface.co/bert/gpt2-config.json>`_ for example).
|
||||
|
||||
::
|
||||
|
||||
from transformers import pipeline
|
||||
|
||||
text_generator = pipeline("text-generation")
|
||||
print(text_generator("As far as I am concerned, I will", max_length=50))
|
||||
|
||||
|
||||
Here the model generates a random text with a total maximal length of *50* tokens from context *"As far as I am concerned, I will"*.
|
||||
The default arguments of ``PreTrainedModel.generate()`` can directly be overriden in the pipeline as is shown above for the argument ``max_length``.
|
||||
|
||||
Here is an example for text generation using XLNet and its tokenzier.
|
||||
|
||||
::
|
||||
|
||||
## PYTORCH CODE
|
||||
from transformers import AutoModelWithLMHead, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("gpt2")
|
||||
model = AutoModelWithLMHead.from_pretrained("gpt2")
|
||||
model = AutoModelWithLMHead.from_pretrained("xlnet-base-cased")
|
||||
tokenizer = AutoTokenizer.from_pretrained("xlnet-base-cased")
|
||||
|
||||
sequence = f"Hugging Face is based in DUMBO, New York City, and is"
|
||||
# Padding text helps XLNet with short prompts - proposed by Aman Rusia in https://github.com/rusiaaman/XLNet-gen#methodology
|
||||
PADDING_TEXT = """In 1991, the remains of Russian Tsar Nicholas II and his family
|
||||
(except for Alexei and Maria) are discovered.
|
||||
The voice of Nicholas's young son, Tsarevich Alexei Nikolaevich, narrates the
|
||||
remainder of the story. 1883 Western Siberia,
|
||||
a young Grigori Rasputin is asked by his father and a group of men to perform magic.
|
||||
Rasputin has a vision and denounces one of the men as a horse thief. Although his
|
||||
father initially slaps him for making such an accusation, Rasputin watches as the
|
||||
man is chased outside and beaten. Twenty years later, Rasputin sees a vision of
|
||||
the Virgin Mary, prompting him to become a priest. Rasputin quickly becomes famous,
|
||||
with people, even a bishop, begging for his blessing. <eod> </s> <eos>"""
|
||||
|
||||
input = tokenizer.encode(sequence, return_tensors="pt")
|
||||
generated = model.generate(input, max_length=50, do_sample=True)
|
||||
prompt = "Today the weather is really nice and I am planning on "
|
||||
inputs = tokenizer.encode(PADDING_TEXT + prompt, add_special_tokens=False, return_tensors="pt")
|
||||
|
||||
prompt_length = len(tokenizer.decode(inputs[0], skip_special_tokens=True, clean_up_tokenization_spaces=True))
|
||||
outputs = model.generate(inputs, max_length=250, do_sample=True, top_p=0.95, top_k=60)
|
||||
generated = prompt + tokenizer.decode(outputs[0])[prompt_length:]
|
||||
|
||||
resulting_string = tokenizer.decode(generated.tolist()[0])
|
||||
print(resulting_string)
|
||||
print(generated)
|
||||
## TENSORFLOW CODE
|
||||
from transformers import TFAutoModelWithLMHead, AutoTokenizer
|
||||
import tensorflow as tf
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("gpt2")
|
||||
model = TFAutoModelWithLMHead.from_pretrained("gpt2")
|
||||
model = TFAutoModelWithLMHead.from_pretrained("xlnet-base-cased")
|
||||
tokenizer = AutoTokenizer.from_pretrained("xlnet-base-cased")
|
||||
|
||||
sequence = f"Hugging Face is based in DUMBO, New York City, and is"
|
||||
input = tokenizer.encode(sequence, return_tensors="tf")
|
||||
generated = model.generate(input, max_length=50, do_sample=True)
|
||||
# Padding text helps XLNet with short prompts - proposed by Aman Rusia in https://github.com/rusiaaman/XLNet-gen#methodology
|
||||
PADDING_TEXT = """In 1991, the remains of Russian Tsar Nicholas II and his family
|
||||
(except for Alexei and Maria) are discovered.
|
||||
The voice of Nicholas's young son, Tsarevich Alexei Nikolaevich, narrates the
|
||||
remainder of the story. 1883 Western Siberia,
|
||||
a young Grigori Rasputin is asked by his father and a group of men to perform magic.
|
||||
Rasputin has a vision and denounces one of the men as a horse thief. Although his
|
||||
father initially slaps him for making such an accusation, Rasputin watches as the
|
||||
man is chased outside and beaten. Twenty years later, Rasputin sees a vision of
|
||||
the Virgin Mary, prompting him to become a priest. Rasputin quickly becomes famous,
|
||||
with people, even a bishop, begging for his blessing. <eod> </s> <eos>"""
|
||||
|
||||
resulting_string = tokenizer.decode(generated.tolist()[0])
|
||||
print(resulting_string)
|
||||
prompt = "Today the weather is really nice and I am planning on "
|
||||
inputs = tokenizer.encode(PADDING_TEXT + prompt, add_special_tokens=False, return_tensors="tf")
|
||||
|
||||
prompt_length = len(tokenizer.decode(inputs[0], skip_special_tokens=True, clean_up_tokenization_spaces=True))
|
||||
outputs = model.generate(inputs, max_length=250, do_sample=True, top_p=0.95, top_k=60)
|
||||
generated = prompt + tokenizer.decode(outputs[0])[prompt_length:]
|
||||
|
||||
This outputs a (hopefully) coherent string from the original sequence, as the
|
||||
:func:`~transformers.PreTrainedModel.generate` samples from a top_p/tok_k distribution:
|
||||
print(generated)
|
||||
|
||||
::
|
||||
Text generation is currently possible with *GPT-2*, *OpenAi-GPT*, *CTRL*, *XLNet*, *Transfo-XL* and *Reformer* in PyTorch and for most models in Tensorflow as well. As can be seen in the example above *XLNet* and *Transfo-xl* often need to be padded to work well.
|
||||
GPT-2 is usually a good choice for *open-ended text generation* because it was trained on millions on webpages with a causal language modeling objective.
|
||||
|
||||
Hugging Face is based in DUMBO, New York City, and is a live-action TV series based on the novel by John
|
||||
Carpenter, and its producers, David Kustlin and Steve Pichar. The film is directed by!
|
||||
For more information on how to apply different decoding strategies for text generation, please also refer to our generation blog post `here <https://huggingface.co/blog/how-to-generate>`_.
|
||||
|
||||
|
||||
Named Entity Recognition
|
||||
|
||||
+23
-24
@@ -1,6 +1,6 @@
|
||||
# Examples
|
||||
## Examples
|
||||
|
||||
Version 2.9 of `transformers` introduces a new `Trainer` class for PyTorch, and its equivalent `TFTrainer` for TF 2.
|
||||
Version 2.9 of `transformers` introduces a new [`Trainer`](https://github.com/huggingface/transformers/blob/master/src/transformers/trainer.py) class for PyTorch, and its equivalent [`TFTrainer`](https://github.com/huggingface/transformers/blob/master/src/transformers/trainer_tf.py) for TF 2.
|
||||
|
||||
Here is the list of all our examples:
|
||||
- **grouped by task** (all official examples work for multiple models)
|
||||
@@ -12,31 +12,24 @@ Here is the list of all our examples:
|
||||
This is still a work-in-progress – in particular documentation is still sparse – so please **contribute improvements/pull requests.**
|
||||
|
||||
|
||||
## Tasks built on Trainer
|
||||
# The Big Table of Tasks
|
||||
|
||||
| Task | Example datasets | Trainer support | TFTrainer support | pytorch-lightning | Colab | One-click Deploy to Azure (wip) |
|
||||
|---|---|:---:|:---:|:---:|:---:|:---:|
|
||||
| [`language-modeling`](./language-modeling) | Raw text | ✅ | - | - | - | - |
|
||||
| [`text-classification`](./text-classification) | GLUE, XNLI | ✅ | ✅ | ✅ | [](https://colab.research.google.com/github/huggingface/blog/blob/master/notebooks/trainer/01_text_classification.ipynb) | [](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2F101-storage-account-create%2Fazuredeploy.json) |
|
||||
| [`token-classification`](./token-classification) | CoNLL NER | ✅ | ✅ | ✅ | - | - |
|
||||
| [`multiple-choice`](./multiple-choice) | SWAG, RACE, ARC | ✅ | - | - | - | - |
|
||||
| Task | Example datasets | Trainer support | TFTrainer support | pytorch-lightning | Colab
|
||||
|---|---|:---:|:---:|:---:|:---:|
|
||||
| [**`language-modeling`**](./language-modeling) | Raw text | ✅ | - | - | [](https://colab.research.google.com/github/huggingface/blog/blob/master/notebooks/01_how_to_train.ipynb)
|
||||
| [**`text-classification`**](./text-classification) | GLUE, XNLI | ✅ | ✅ | ✅ | [](https://colab.research.google.com/github/huggingface/blog/blob/master/notebooks/trainer/01_text_classification.ipynb)
|
||||
| [**`token-classification`**](./token-classification) | CoNLL NER | ✅ | ✅ | ✅ | -
|
||||
| [**`multiple-choice`**](./multiple-choice) | SWAG, RACE, ARC | ✅ | ✅ | - | [](https://colab.research.google.com/github/ViktorAlm/notebooks/blob/master/MPC_GPU_Demo_for_TF_and_PT.ipynb)
|
||||
| [**`question-answering`**](./question-answering) | SQuAD | - | ✅ | - | -
|
||||
| [**`text-generation`**](./text-generation) | - | - | - | - | [](https://colab.research.google.com/github/huggingface/blog/blob/master/notebooks/02_how_to_generate.ipynb)
|
||||
| [**`distillation`**](./distillation) | All | - | - | - | -
|
||||
| [**`summarization`**](./summarization) | CNN/Daily Mail | - | - | - | -
|
||||
| [**`translation`**](./translation) | WMT | - | - | - | -
|
||||
| [**`bertology`**](./bertology) | - | - | - | - | -
|
||||
| [**`adversarial`**](./adversarial) | HANS | - | - | - | -
|
||||
|
||||
|
||||
|
||||
## Other examples and how-to's
|
||||
|
||||
| Section | Description |
|
||||
|---|---|
|
||||
| [TensorFlow 2.0 models on GLUE](./text-classification) | Examples running BERT TensorFlow 2.0 model on the GLUE tasks. |
|
||||
| [Running on TPUs](#running-on-tpus) | Examples on running fine-tuning tasks on Google TPUs to accelerate workloads. |
|
||||
| [Language Model training](./language-modeling) | Fine-tuning (or training from scratch) the library models for language modeling on a text dataset. Causal language modeling for GPT/GPT-2, masked language modeling for BERT/RoBERTa. |
|
||||
| [Language Generation](./text-generation) | Conditional text generation using the auto-regressive models of the library: GPT, GPT-2, Transformer-XL and XLNet. |
|
||||
| [GLUE](./text-classification) | Examples running BERT/XLM/XLNet/RoBERTa on the 9 GLUE tasks. Examples feature distributed training as well as half-precision. |
|
||||
| [SQuAD](./question-answering) | Using BERT/RoBERTa/XLNet/XLM for question answering, examples with distributed training. |
|
||||
| [Multiple Choice](./multiple-choice) | Examples running BERT/XLNet/RoBERTa on the SWAG/RACE/ARC tasks. |
|
||||
| [Named Entity Recognition](./token-classification) | Using BERT for Named Entity Recognition (NER) on the CoNLL 2003 dataset, examples with distributed training. |
|
||||
| [XNLI](./text-classification) | Examples running BERT/XLM on the XNLI benchmark. |
|
||||
| [Adversarial evaluation of model performances](./adversarial) | Testing a model with adversarial evaluation of natural language inference on the Heuristic Analysis for NLI Systems (HANS) dataset (McCoy et al., 2019.) |
|
||||
<br>
|
||||
|
||||
## Important note
|
||||
|
||||
@@ -51,6 +44,12 @@ pip install .
|
||||
pip install -r ./examples/requirements.txt
|
||||
```
|
||||
|
||||
## One-click Deploy to Cloud (wip)
|
||||
|
||||
#### Azure
|
||||
|
||||
[](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2F101-storage-account-create%2Fazuredeploy.json)
|
||||
|
||||
## Running on TPUs
|
||||
|
||||
When using Tensorflow, TPUs are supported out of the box as a `tf.distribute.Strategy`.
|
||||
|
||||
@@ -478,7 +478,7 @@ def _compute_pytorch(
|
||||
dictionary[model_name]["memory"][batch_size][slice_size] = "N/A"
|
||||
|
||||
if not no_speed:
|
||||
print_fn("Going through model with sequence of shape".format(sequence.shape))
|
||||
print_fn("Going through model with sequence of shape {}".format(sequence.shape))
|
||||
runtimes = timeit.repeat(lambda: inference(sequence), repeat=average_over, number=3)
|
||||
average_time = sum(runtimes) / float(len(runtimes)) / 3.0
|
||||
dictionary[model_name]["time"][batch_size][slice_size] = average_time
|
||||
|
||||
@@ -80,7 +80,7 @@ class Distiller:
|
||||
|
||||
self.mlm = params.mlm
|
||||
if self.mlm:
|
||||
logger.info(f"Using MLM loss for LM step.")
|
||||
logger.info("Using MLM loss for LM step.")
|
||||
self.mlm_mask_prop = params.mlm_mask_prop
|
||||
assert 0.0 <= self.mlm_mask_prop <= 1.0
|
||||
assert params.word_mask + params.word_keep + params.word_rand == 1.0
|
||||
@@ -91,7 +91,7 @@ class Distiller:
|
||||
self.pred_probs = self.pred_probs.half()
|
||||
self.token_probs = self.token_probs.half()
|
||||
else:
|
||||
logger.info(f"Using CLM loss for LM step.")
|
||||
logger.info("Using CLM loss for LM step.")
|
||||
|
||||
self.epoch = 0
|
||||
self.n_iter = 0
|
||||
@@ -365,8 +365,8 @@ class Distiller:
|
||||
self.end_epoch()
|
||||
|
||||
if self.is_master:
|
||||
logger.info(f"Save very last checkpoint as `pytorch_model.bin`.")
|
||||
self.save_checkpoint(checkpoint_name=f"pytorch_model.bin")
|
||||
logger.info("Save very last checkpoint as `pytorch_model.bin`.")
|
||||
self.save_checkpoint(checkpoint_name="pytorch_model.bin")
|
||||
logger.info("Training is finished")
|
||||
|
||||
def step(self, input_ids: torch.tensor, attention_mask: torch.tensor, lm_labels: torch.tensor):
|
||||
|
||||
@@ -60,7 +60,7 @@ def main():
|
||||
with open(args.file_path, "r", encoding="utf8") as fp:
|
||||
data = fp.readlines()
|
||||
|
||||
logger.info(f"Start encoding")
|
||||
logger.info("Start encoding")
|
||||
logger.info(f"{len(data)} examples to process.")
|
||||
|
||||
rslt = []
|
||||
|
||||
@@ -93,7 +93,7 @@ if __name__ == "__main__":
|
||||
elif args.model_type == "gpt2":
|
||||
for w in ["weight", "bias"]:
|
||||
compressed_sd[f"{prefix}.ln_f.{w}"] = state_dict[f"{prefix}.ln_f.{w}"]
|
||||
compressed_sd[f"lm_head.weight"] = state_dict[f"lm_head.weight"]
|
||||
compressed_sd["lm_head.weight"] = state_dict["lm_head.weight"]
|
||||
|
||||
print(f"N layers selected for distillation: {std_idx}")
|
||||
print(f"Number of params transfered for distillation: {len(compressed_sd.keys())}")
|
||||
|
||||
@@ -37,7 +37,7 @@ if __name__ == "__main__":
|
||||
model = BertForMaskedLM.from_pretrained(args.model_name)
|
||||
prefix = "bert"
|
||||
else:
|
||||
raise ValueError(f'args.model_type should be "bert".')
|
||||
raise ValueError('args.model_type should be "bert".')
|
||||
|
||||
state_dict = model.state_dict()
|
||||
compressed_sd = {}
|
||||
@@ -78,12 +78,12 @@ if __name__ == "__main__":
|
||||
]
|
||||
std_idx += 1
|
||||
|
||||
compressed_sd[f"vocab_projector.weight"] = state_dict[f"cls.predictions.decoder.weight"]
|
||||
compressed_sd[f"vocab_projector.bias"] = state_dict[f"cls.predictions.bias"]
|
||||
compressed_sd["vocab_projector.weight"] = state_dict["cls.predictions.decoder.weight"]
|
||||
compressed_sd["vocab_projector.bias"] = state_dict["cls.predictions.bias"]
|
||||
if args.vocab_transform:
|
||||
for w in ["weight", "bias"]:
|
||||
compressed_sd[f"vocab_transform.{w}"] = state_dict[f"cls.predictions.transform.dense.{w}"]
|
||||
compressed_sd[f"vocab_layer_norm.{w}"] = state_dict[f"cls.predictions.transform.LayerNorm.{w}"]
|
||||
compressed_sd[f"vocab_transform.{w}"] = state_dict["cls.predictions.transform.dense.{w}"]
|
||||
compressed_sd[f"vocab_layer_norm.{w}"] = state_dict["cls.predictions.transform.LayerNorm.{w}"]
|
||||
|
||||
print(f"N layers selected for distillation: {std_idx}")
|
||||
print(f"Number of params transfered for distillation: {len(compressed_sd.keys())}")
|
||||
|
||||
@@ -273,7 +273,7 @@ def main():
|
||||
token_probs = None
|
||||
|
||||
train_lm_seq_dataset = LmSeqsDataset(params=args, data=data)
|
||||
logger.info(f"Data loader created.")
|
||||
logger.info("Data loader created.")
|
||||
|
||||
# STUDENT #
|
||||
logger.info(f"Loading student config from {args.student_config}")
|
||||
@@ -288,7 +288,7 @@ def main():
|
||||
|
||||
if args.n_gpu > 0:
|
||||
student.to(f"cuda:{args.local_rank}")
|
||||
logger.info(f"Student loaded.")
|
||||
logger.info("Student loaded.")
|
||||
|
||||
# TEACHER #
|
||||
teacher = teacher_model_class.from_pretrained(args.teacher_name, output_hidden_states=True)
|
||||
|
||||
@@ -115,16 +115,12 @@ class DataTrainingArguments:
|
||||
)
|
||||
|
||||
|
||||
def get_dataset(args: DataTrainingArguments, tokenizer: PreTrainedTokenizer, evaluate=False, local_rank=-1):
|
||||
def get_dataset(args: DataTrainingArguments, tokenizer: PreTrainedTokenizer, evaluate=False):
|
||||
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, local_rank=local_rank
|
||||
)
|
||||
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, local_rank=local_rank,
|
||||
)
|
||||
return TextDataset(tokenizer=tokenizer, file_path=file_path, block_size=args.block_size)
|
||||
|
||||
|
||||
def main():
|
||||
@@ -220,16 +216,8 @@ def main():
|
||||
data_args.block_size = min(data_args.block_size, tokenizer.max_len)
|
||||
|
||||
# Get datasets
|
||||
train_dataset = (
|
||||
get_dataset(data_args, tokenizer=tokenizer, local_rank=training_args.local_rank)
|
||||
if training_args.do_train
|
||||
else None
|
||||
)
|
||||
eval_dataset = (
|
||||
get_dataset(data_args, tokenizer=tokenizer, local_rank=training_args.local_rank, evaluate=True)
|
||||
if training_args.do_eval
|
||||
else None
|
||||
)
|
||||
train_dataset = get_dataset(data_args, tokenizer=tokenizer) if training_args.do_train else None
|
||||
eval_dataset = get_dataset(data_args, tokenizer=tokenizer, evaluate=True) if training_args.do_eval else None
|
||||
data_collator = DataCollatorForLanguageModeling(
|
||||
tokenizer=tokenizer, mlm=data_args.mlm, mlm_probability=data_args.mlm_probability
|
||||
)
|
||||
@@ -265,7 +253,7 @@ def main():
|
||||
|
||||
eval_output = trainer.evaluate()
|
||||
|
||||
perplexity = math.exp(eval_output["loss"])
|
||||
perplexity = math.exp(eval_output["eval_loss"])
|
||||
result = {"perplexity": perplexity}
|
||||
|
||||
output_eval_file = os.path.join(training_args.output_dir, "eval_results_lm.txt")
|
||||
|
||||
@@ -29,3 +29,28 @@ Training with the defined hyper-parameters yields the following results:
|
||||
eval_acc = 0.8338998300509847
|
||||
eval_loss = 0.44457291918821606
|
||||
```
|
||||
|
||||
|
||||
## Tensorflow
|
||||
|
||||
```bash
|
||||
export SWAG_DIR=/path/to/swag_data_dir
|
||||
python ./examples/multiple-choice/run_tf_multiple_choice.py \
|
||||
--task_name swag \
|
||||
--model_name_or_path bert-base-cased \
|
||||
--do_train \
|
||||
--do_eval \
|
||||
--data_dir $SWAG_DIR \
|
||||
--learning_rate 5e-5 \
|
||||
--num_train_epochs 3 \
|
||||
--max_seq_length 80 \
|
||||
--output_dir models_bert/swag_base \
|
||||
--per_gpu_eval_batch_size=16 \
|
||||
--per_gpu_train_batch_size=16 \
|
||||
--logging-dir logs \
|
||||
--gradient_accumulation_steps 2 \
|
||||
--overwrite_output
|
||||
```
|
||||
|
||||
# Run it in colab
|
||||
[](https://colab.research.google.com/github/ViktorAlm/notebooks/blob/master/MPC_GPU_Demo_for_TF_and_PT.ipynb)
|
||||
|
||||
@@ -159,7 +159,6 @@ def main():
|
||||
max_seq_length=data_args.max_seq_length,
|
||||
overwrite_cache=data_args.overwrite_cache,
|
||||
mode=Split.train,
|
||||
local_rank=training_args.local_rank,
|
||||
)
|
||||
if training_args.do_train
|
||||
else None
|
||||
@@ -172,7 +171,6 @@ def main():
|
||||
max_seq_length=data_args.max_seq_length,
|
||||
overwrite_cache=data_args.overwrite_cache,
|
||||
mode=Split.dev,
|
||||
local_rank=training_args.local_rank,
|
||||
)
|
||||
if training_args.do_eval
|
||||
else None
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team.
|
||||
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
""" Finetuning the library models for multiple choice (Bert, Roberta, XLNet)."""
|
||||
|
||||
|
||||
import logging
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Dict, Optional
|
||||
|
||||
import numpy as np
|
||||
|
||||
from transformers import (
|
||||
AutoConfig,
|
||||
AutoTokenizer,
|
||||
EvalPrediction,
|
||||
HfArgumentParser,
|
||||
TFAutoModelForMultipleChoice,
|
||||
TFTrainer,
|
||||
TFTrainingArguments,
|
||||
set_seed,
|
||||
)
|
||||
from utils_multiple_choice import Split, TFMultipleChoiceDataset, processors
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def simple_accuracy(preds, labels):
|
||||
return (preds == labels).mean()
|
||||
|
||||
|
||||
@dataclass
|
||||
class ModelArguments:
|
||||
"""
|
||||
Arguments pertaining to which model/config/tokenizer we are going to fine-tune from.
|
||||
"""
|
||||
|
||||
model_name_or_path: str = field(
|
||||
metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"}
|
||||
)
|
||||
config_name: Optional[str] = field(
|
||||
default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"}
|
||||
)
|
||||
tokenizer_name: Optional[str] = field(
|
||||
default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"}
|
||||
)
|
||||
cache_dir: Optional[str] = field(
|
||||
default=None, metadata={"help": "Where do you want to store the pretrained models downloaded from s3"}
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class DataTrainingArguments:
|
||||
"""
|
||||
Arguments pertaining to what data we are going to input our model for training and eval.
|
||||
"""
|
||||
|
||||
task_name: str = field(metadata={"help": "The name of the task to train on: " + ", ".join(processors.keys())})
|
||||
data_dir: str = field(metadata={"help": "Should contain the data files for the task."})
|
||||
max_seq_length: int = field(
|
||||
default=128,
|
||||
metadata={
|
||||
"help": "The maximum total input sequence length after tokenization. Sequences longer "
|
||||
"than this will be truncated, sequences shorter will be padded."
|
||||
},
|
||||
)
|
||||
overwrite_cache: bool = field(
|
||||
default=False, metadata={"help": "Overwrite the cached training and evaluation sets"}
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
# See all possible arguments in src/transformers/training_args.py
|
||||
# or by passing the --help flag to this script.
|
||||
# We now keep distinct sets of args, for a cleaner separation of concerns.
|
||||
|
||||
parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TFTrainingArguments))
|
||||
model_args, data_args, training_args = parser.parse_args_into_dataclasses()
|
||||
|
||||
if (
|
||||
os.path.exists(training_args.output_dir)
|
||||
and os.listdir(training_args.output_dir)
|
||||
and training_args.do_train
|
||||
and not training_args.overwrite_output_dir
|
||||
):
|
||||
raise ValueError(
|
||||
f"Output directory ({training_args.output_dir}) already exists and is not empty. Use --overwrite_output_dir to overcome."
|
||||
)
|
||||
|
||||
# Setup logging
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
|
||||
datefmt="%m/%d/%Y %H:%M:%S",
|
||||
level=logging.INFO,
|
||||
)
|
||||
logger.warning(
|
||||
"device: %s, n_gpu: %s, 16-bits training: %s", training_args.device, training_args.n_gpu, training_args.fp16,
|
||||
)
|
||||
logger.info("Training/evaluation parameters %s", training_args)
|
||||
|
||||
# Set seed
|
||||
set_seed(training_args.seed)
|
||||
|
||||
try:
|
||||
processor = processors[data_args.task_name]()
|
||||
label_list = processor.get_labels()
|
||||
num_labels = len(label_list)
|
||||
except KeyError:
|
||||
raise ValueError("Task not found: %s" % (data_args.task_name))
|
||||
|
||||
# Load pretrained model and tokenizer
|
||||
#
|
||||
# Distributed training:
|
||||
# The .from_pretrained methods guarantee that only one local process can concurrently
|
||||
# download model & vocab.
|
||||
config = AutoConfig.from_pretrained(
|
||||
model_args.config_name if model_args.config_name else model_args.model_name_or_path,
|
||||
num_labels=num_labels,
|
||||
finetuning_task=data_args.task_name,
|
||||
cache_dir=model_args.cache_dir,
|
||||
)
|
||||
tokenizer = AutoTokenizer.from_pretrained(
|
||||
model_args.tokenizer_name if model_args.tokenizer_name else model_args.model_name_or_path,
|
||||
cache_dir=model_args.cache_dir,
|
||||
)
|
||||
with training_args.strategy.scope():
|
||||
model = TFAutoModelForMultipleChoice.from_pretrained(
|
||||
model_args.model_name_or_path,
|
||||
from_pt=bool(".bin" in model_args.model_name_or_path),
|
||||
config=config,
|
||||
cache_dir=model_args.cache_dir,
|
||||
)
|
||||
# Get datasets
|
||||
train_dataset = (
|
||||
TFMultipleChoiceDataset(
|
||||
data_dir=data_args.data_dir,
|
||||
tokenizer=tokenizer,
|
||||
task=data_args.task_name,
|
||||
max_seq_length=data_args.max_seq_length,
|
||||
overwrite_cache=data_args.overwrite_cache,
|
||||
mode=Split.train,
|
||||
)
|
||||
if training_args.do_train
|
||||
else None
|
||||
)
|
||||
eval_dataset = (
|
||||
TFMultipleChoiceDataset(
|
||||
data_dir=data_args.data_dir,
|
||||
tokenizer=tokenizer,
|
||||
task=data_args.task_name,
|
||||
max_seq_length=data_args.max_seq_length,
|
||||
overwrite_cache=data_args.overwrite_cache,
|
||||
mode=Split.dev,
|
||||
)
|
||||
if training_args.do_eval
|
||||
else None
|
||||
)
|
||||
|
||||
def compute_metrics(p: EvalPrediction) -> Dict:
|
||||
preds = np.argmax(p.predictions, axis=1)
|
||||
return {"acc": simple_accuracy(preds, p.label_ids)}
|
||||
|
||||
# Initialize our Trainer
|
||||
trainer = TFTrainer(
|
||||
model=model,
|
||||
args=training_args,
|
||||
train_dataset=train_dataset.get_dataset() if train_dataset else None,
|
||||
eval_dataset=eval_dataset.get_dataset() if eval_dataset else None,
|
||||
compute_metrics=compute_metrics,
|
||||
)
|
||||
|
||||
# Training
|
||||
if training_args.do_train:
|
||||
trainer.train()
|
||||
trainer.save_model()
|
||||
tokenizer.save_pretrained(training_args.output_dir)
|
||||
# Evaluation
|
||||
results = {}
|
||||
if training_args.do_eval:
|
||||
logger.info("*** Evaluate ***")
|
||||
|
||||
result = trainer.evaluate()
|
||||
|
||||
output_eval_file = os.path.join(training_args.output_dir, "eval_results.txt")
|
||||
with open(output_eval_file, "w") as writer:
|
||||
logger.info("***** Eval results *****")
|
||||
for key, value in result.items():
|
||||
logger.info(" %s = %s", key, value)
|
||||
writer.write("%s = %s\n" % (key, value))
|
||||
|
||||
results.update(result)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -25,11 +25,10 @@ from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from typing import List, Optional
|
||||
|
||||
import torch
|
||||
import tqdm
|
||||
from torch.utils.data.dataset import Dataset
|
||||
from filelock import FileLock
|
||||
|
||||
from transformers import PreTrainedTokenizer, torch_distributed_zero_first
|
||||
from transformers import PreTrainedTokenizer, is_tf_available, is_torch_available
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -76,66 +75,159 @@ class Split(Enum):
|
||||
test = "test"
|
||||
|
||||
|
||||
class MultipleChoiceDataset(Dataset):
|
||||
"""
|
||||
This will be superseded by a framework-agnostic approach
|
||||
soon.
|
||||
"""
|
||||
if is_torch_available():
|
||||
import torch
|
||||
from torch.utils.data.dataset import Dataset
|
||||
|
||||
features: List[InputFeatures]
|
||||
class MultipleChoiceDataset(Dataset):
|
||||
"""
|
||||
This will be superseded by a framework-agnostic approach
|
||||
soon.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data_dir: str,
|
||||
tokenizer: PreTrainedTokenizer,
|
||||
task: str,
|
||||
max_seq_length: Optional[int] = None,
|
||||
overwrite_cache=False,
|
||||
mode: Split = Split.train,
|
||||
local_rank=-1,
|
||||
):
|
||||
processor = processors[task]()
|
||||
features: List[InputFeatures]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data_dir: str,
|
||||
tokenizer: PreTrainedTokenizer,
|
||||
task: str,
|
||||
max_seq_length: Optional[int] = None,
|
||||
overwrite_cache=False,
|
||||
mode: Split = Split.train,
|
||||
):
|
||||
processor = processors[task]()
|
||||
|
||||
cached_features_file = os.path.join(
|
||||
data_dir,
|
||||
"cached_{}_{}_{}_{}".format(mode.value, tokenizer.__class__.__name__, str(max_seq_length), task,),
|
||||
)
|
||||
|
||||
cached_features_file = os.path.join(
|
||||
data_dir,
|
||||
"cached_{}_{}_{}_{}".format(mode.value, tokenizer.__class__.__name__, str(max_seq_length), task,),
|
||||
)
|
||||
with torch_distributed_zero_first(local_rank):
|
||||
# Make sure only the first process in distributed training processes the dataset,
|
||||
# and the others will use the cache.
|
||||
lock_path = cached_features_file + ".lock"
|
||||
with FileLock(lock_path):
|
||||
|
||||
if os.path.exists(cached_features_file) and not overwrite_cache:
|
||||
logger.info(f"Loading features from cached file {cached_features_file}")
|
||||
self.features = torch.load(cached_features_file)
|
||||
else:
|
||||
logger.info(f"Creating features from dataset file at {data_dir}")
|
||||
label_list = processor.get_labels()
|
||||
if mode == Split.dev:
|
||||
examples = processor.get_dev_examples(data_dir)
|
||||
elif mode == Split.test:
|
||||
examples = processor.get_test_examples(data_dir)
|
||||
if os.path.exists(cached_features_file) and not overwrite_cache:
|
||||
logger.info(f"Loading features from cached file {cached_features_file}")
|
||||
self.features = torch.load(cached_features_file)
|
||||
else:
|
||||
examples = processor.get_train_examples(data_dir)
|
||||
logger.info("Training examples: %s", len(examples))
|
||||
# TODO clean up all this to leverage built-in features of tokenizers
|
||||
self.features = convert_examples_to_features(
|
||||
examples,
|
||||
label_list,
|
||||
max_seq_length,
|
||||
tokenizer,
|
||||
pad_on_left=bool(tokenizer.padding_side == "left"),
|
||||
pad_token=tokenizer.pad_token_id,
|
||||
pad_token_segment_id=tokenizer.pad_token_type_id,
|
||||
)
|
||||
if local_rank in [-1, 0]:
|
||||
logger.info(f"Creating features from dataset file at {data_dir}")
|
||||
label_list = processor.get_labels()
|
||||
if mode == Split.dev:
|
||||
examples = processor.get_dev_examples(data_dir)
|
||||
elif mode == Split.test:
|
||||
examples = processor.get_test_examples(data_dir)
|
||||
else:
|
||||
examples = processor.get_train_examples(data_dir)
|
||||
logger.info("Training examples: %s", len(examples))
|
||||
# TODO clean up all this to leverage built-in features of tokenizers
|
||||
self.features = convert_examples_to_features(
|
||||
examples,
|
||||
label_list,
|
||||
max_seq_length,
|
||||
tokenizer,
|
||||
pad_on_left=bool(tokenizer.padding_side == "left"),
|
||||
pad_token=tokenizer.pad_token_id,
|
||||
pad_token_segment_id=tokenizer.pad_token_type_id,
|
||||
)
|
||||
logger.info("Saving features into cached file %s", cached_features_file)
|
||||
torch.save(self.features, cached_features_file)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.features)
|
||||
def __len__(self):
|
||||
return len(self.features)
|
||||
|
||||
def __getitem__(self, i) -> InputFeatures:
|
||||
return self.features[i]
|
||||
def __getitem__(self, i) -> InputFeatures:
|
||||
return self.features[i]
|
||||
|
||||
|
||||
if is_tf_available():
|
||||
import tensorflow as tf
|
||||
|
||||
class TFMultipleChoiceDataset:
|
||||
"""
|
||||
This will be superseded by a framework-agnostic approach
|
||||
soon.
|
||||
"""
|
||||
|
||||
features: List[InputFeatures]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data_dir: str,
|
||||
tokenizer: PreTrainedTokenizer,
|
||||
task: str,
|
||||
max_seq_length: Optional[int] = 128,
|
||||
overwrite_cache=False,
|
||||
mode: Split = Split.train,
|
||||
):
|
||||
processor = processors[task]()
|
||||
|
||||
logger.info(f"Creating features from dataset file at {data_dir}")
|
||||
label_list = processor.get_labels()
|
||||
if mode == Split.dev:
|
||||
examples = processor.get_dev_examples(data_dir)
|
||||
elif mode == Split.test:
|
||||
examples = processor.get_test_examples(data_dir)
|
||||
else:
|
||||
examples = processor.get_train_examples(data_dir)
|
||||
logger.info("Training examples: %s", len(examples))
|
||||
# TODO clean up all this to leverage built-in features of tokenizers
|
||||
self.features = convert_examples_to_features(
|
||||
examples,
|
||||
label_list,
|
||||
max_seq_length,
|
||||
tokenizer,
|
||||
pad_on_left=bool(tokenizer.padding_side == "left"),
|
||||
pad_token=tokenizer.pad_token_id,
|
||||
pad_token_segment_id=tokenizer.pad_token_type_id,
|
||||
)
|
||||
|
||||
def gen():
|
||||
for (ex_index, ex) in tqdm.tqdm(enumerate(self.features), desc="convert examples to features"):
|
||||
if ex_index % 10000 == 0:
|
||||
logger.info("Writing example %d of %d" % (ex_index, len(examples)))
|
||||
|
||||
yield (
|
||||
{
|
||||
"example_id": 0,
|
||||
"input_ids": ex.input_ids,
|
||||
"attention_mask": ex.attention_mask,
|
||||
"token_type_ids": ex.token_type_ids,
|
||||
},
|
||||
ex.label,
|
||||
)
|
||||
|
||||
self.dataset = tf.data.Dataset.from_generator(
|
||||
gen,
|
||||
(
|
||||
{
|
||||
"example_id": tf.int32,
|
||||
"input_ids": tf.int32,
|
||||
"attention_mask": tf.int32,
|
||||
"token_type_ids": tf.int32,
|
||||
},
|
||||
tf.int64,
|
||||
),
|
||||
(
|
||||
{
|
||||
"example_id": tf.TensorShape([]),
|
||||
"input_ids": tf.TensorShape([None, None]),
|
||||
"attention_mask": tf.TensorShape([None, None]),
|
||||
"token_type_ids": tf.TensorShape([None, None]),
|
||||
},
|
||||
tf.TensorShape([]),
|
||||
),
|
||||
)
|
||||
|
||||
def get_dataset(self):
|
||||
return self.dataset
|
||||
|
||||
def __len__(self):
|
||||
return len(self.features)
|
||||
|
||||
def __getitem__(self, i) -> InputFeatures:
|
||||
return self.features[i]
|
||||
|
||||
|
||||
class DataProcessor:
|
||||
@@ -225,6 +317,52 @@ class RaceProcessor(DataProcessor):
|
||||
return examples
|
||||
|
||||
|
||||
class SynonymProcessor(DataProcessor):
|
||||
"""Processor for the Synonym data set."""
|
||||
|
||||
def get_train_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
logger.info("LOOKING AT {} train".format(data_dir))
|
||||
return self._create_examples(self._read_csv(os.path.join(data_dir, "mctrain.csv")), "train")
|
||||
|
||||
def get_dev_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
logger.info("LOOKING AT {} dev".format(data_dir))
|
||||
return self._create_examples(self._read_csv(os.path.join(data_dir, "mchp.csv")), "dev")
|
||||
|
||||
def get_test_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
logger.info("LOOKING AT {} dev".format(data_dir))
|
||||
|
||||
return self._create_examples(self._read_csv(os.path.join(data_dir, "mctest.csv")), "test")
|
||||
|
||||
def get_labels(self):
|
||||
"""See base class."""
|
||||
return ["0", "1", "2", "3", "4"]
|
||||
|
||||
def _read_csv(self, input_file):
|
||||
with open(input_file, "r", encoding="utf-8") as f:
|
||||
return list(csv.reader(f))
|
||||
|
||||
def _create_examples(self, lines: List[List[str]], type: str):
|
||||
"""Creates examples for the training and dev sets."""
|
||||
|
||||
examples = [
|
||||
InputExample(
|
||||
example_id=line[0],
|
||||
question="", # in the swag dataset, the
|
||||
# common beginning of each
|
||||
# choice is stored in "sent2".
|
||||
contexts=[line[1], line[1], line[1], line[1], line[1]],
|
||||
endings=[line[2], line[3], line[4], line[5], line[6]],
|
||||
label=line[7],
|
||||
)
|
||||
for line in lines # we skip the line with the column names
|
||||
]
|
||||
|
||||
return examples
|
||||
|
||||
|
||||
class SwagProcessor(DataProcessor):
|
||||
"""Processor for the SWAG data set."""
|
||||
|
||||
@@ -397,7 +535,12 @@ def convert_examples_to_features(
|
||||
text_b = example.question + " " + ending
|
||||
|
||||
inputs = tokenizer.encode_plus(
|
||||
text_a, text_b, add_special_tokens=True, max_length=max_length, pad_to_max_length=True,
|
||||
text_a,
|
||||
text_b,
|
||||
add_special_tokens=True,
|
||||
max_length=max_length,
|
||||
pad_to_max_length=True,
|
||||
return_overflowing_tokens=True,
|
||||
)
|
||||
if "num_truncated_tokens" in inputs and inputs["num_truncated_tokens"] > 0:
|
||||
logger.info(
|
||||
@@ -435,7 +578,5 @@ def convert_examples_to_features(
|
||||
return features
|
||||
|
||||
|
||||
processors = {"race": RaceProcessor, "swag": SwagProcessor, "arc": ArcProcessor}
|
||||
|
||||
|
||||
MULTIPLE_CHOICE_TASKS_NUM_LABELS = {"race", 4, "swag", 4, "arc", 4}
|
||||
processors = {"race": RaceProcessor, "swag": SwagProcessor, "arc": ArcProcessor, "syn": SynonymProcessor}
|
||||
MULTIPLE_CHOICE_TASKS_NUM_LABELS = {"race", 4, "swag", 4, "arc", 4, "syn", 5}
|
||||
|
||||
@@ -157,3 +157,23 @@ Larger batch size may improve the performance while costing more memory.
|
||||
}
|
||||
```
|
||||
|
||||
## SQuAD with the Tensorflow Trainer
|
||||
|
||||
```bash
|
||||
python run_tf_squad.py \
|
||||
--model_name_or_path bert-base-uncased \
|
||||
--output_dir model \
|
||||
--max-seq-length 384 \
|
||||
--num_train_epochs 2 \
|
||||
--per_gpu_train_batch_size 8 \
|
||||
--per_gpu_eval_batch_size 16 \
|
||||
--do_train \
|
||||
--logging_dir logs \
|
||||
--mode question-answering \
|
||||
--logging_steps 10 \
|
||||
--learning_rate 3e-5 \
|
||||
--doc_stride 128 \
|
||||
--optimizer_name adamw
|
||||
```
|
||||
|
||||
For the moment the evaluation is not available in the Tensorflow Trainer only the training.
|
||||
@@ -0,0 +1,237 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team.
|
||||
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
""" Fine-tuning the library models for question-answering."""
|
||||
|
||||
|
||||
import logging
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
|
||||
from transformers import (
|
||||
AutoConfig,
|
||||
AutoTokenizer,
|
||||
HfArgumentParser,
|
||||
TFAutoModelForQuestionAnswering,
|
||||
TFTrainer,
|
||||
TFTrainingArguments,
|
||||
squad_convert_examples_to_features,
|
||||
)
|
||||
from transformers.data.processors.squad import SquadV1Processor, SquadV2Processor
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ModelArguments:
|
||||
"""
|
||||
Arguments pertaining to which model/config/tokenizer we are going to fine-tune from.
|
||||
"""
|
||||
|
||||
model_name_or_path: str = field(
|
||||
metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"}
|
||||
)
|
||||
config_name: Optional[str] = field(
|
||||
default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"}
|
||||
)
|
||||
tokenizer_name: Optional[str] = field(
|
||||
default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"}
|
||||
)
|
||||
use_fast: bool = field(default=False, metadata={"help": "Set this flag to use fast tokenization."})
|
||||
# If you want to tweak more attributes on your tokenizer, you should do it in a distinct script,
|
||||
# or just modify its tokenizer_config.json.
|
||||
cache_dir: Optional[str] = field(
|
||||
default=None, metadata={"help": "Where do you want to store the pretrained models downloaded from s3"}
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class DataTrainingArguments:
|
||||
"""
|
||||
Arguments pertaining to what data we are going to input our model for training and eval.
|
||||
"""
|
||||
|
||||
data_dir: Optional[str] = field(
|
||||
default=None, metadata={"help": "The input data dir. Should contain the .json files for the SQuAD task."}
|
||||
)
|
||||
max_seq_length: int = field(
|
||||
default=128,
|
||||
metadata={
|
||||
"help": "The maximum total input sequence length after tokenization. Sequences longer "
|
||||
"than this will be truncated, sequences shorter will be padded."
|
||||
},
|
||||
)
|
||||
doc_stride: int = field(
|
||||
default=128,
|
||||
metadata={"help": "When splitting up a long document into chunks, how much stride to take between chunks."},
|
||||
)
|
||||
max_query_length: int = field(
|
||||
default=64,
|
||||
metadata={
|
||||
"help": "The maximum number of tokens for the question. Questions longer than this will "
|
||||
"be truncated to this length."
|
||||
},
|
||||
)
|
||||
max_answer_length: int = field(
|
||||
default=30,
|
||||
metadata={
|
||||
"help": "The maximum length of an answer that can be generated. This is needed because the start "
|
||||
"and end predictions are not conditioned on one another."
|
||||
},
|
||||
)
|
||||
overwrite_cache: bool = field(
|
||||
default=False, metadata={"help": "Overwrite the cached training and evaluation sets"}
|
||||
)
|
||||
version_2_with_negative: bool = field(
|
||||
default=False, metadata={"help": "If true, the SQuAD examples contain some that do not have an answer."}
|
||||
)
|
||||
null_score_diff_threshold: float = field(
|
||||
default=0.0, metadata={"help": "If null_score - best_non_null is greater than the threshold predict null."}
|
||||
)
|
||||
n_best_size: int = field(
|
||||
default=20, metadata={"help": "If null_score - best_non_null is greater than the threshold predict null."}
|
||||
)
|
||||
lang_id: int = field(
|
||||
default=0,
|
||||
metadata={
|
||||
"help": "language id of input for language-specific xlm models (see tokenization_xlm.PRETRAINED_INIT_CONFIGURATION)"
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
# See all possible arguments in src/transformers/training_args.py
|
||||
# or by passing the --help flag to this script.
|
||||
# We now keep distinct sets of args, for a cleaner separation of concerns.
|
||||
parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TFTrainingArguments))
|
||||
model_args, data_args, training_args = parser.parse_args_into_dataclasses()
|
||||
|
||||
if (
|
||||
os.path.exists(training_args.output_dir)
|
||||
and os.listdir(training_args.output_dir)
|
||||
and training_args.do_train
|
||||
and not training_args.overwrite_output_dir
|
||||
):
|
||||
raise ValueError(
|
||||
f"Output directory ({training_args.output_dir}) already exists and is not empty. Use --overwrite_output_dir to overcome."
|
||||
)
|
||||
|
||||
# Setup logging
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
|
||||
datefmt="%m/%d/%Y %H:%M:%S",
|
||||
level=logging.INFO,
|
||||
)
|
||||
logger.info(
|
||||
"n_gpu: %s, distributed training: %s, 16-bits training: %s",
|
||||
training_args.n_gpu,
|
||||
bool(training_args.n_gpu > 1),
|
||||
training_args.fp16,
|
||||
)
|
||||
logger.info("Training/evaluation parameters %s", training_args)
|
||||
|
||||
# Prepare Question-Answering task
|
||||
# Load pretrained model and tokenizer
|
||||
#
|
||||
# Distributed training:
|
||||
# The .from_pretrained methods guarantee that only one local process can concurrently
|
||||
# download model & vocab.
|
||||
|
||||
config = AutoConfig.from_pretrained(
|
||||
model_args.config_name if model_args.config_name else model_args.model_name_or_path,
|
||||
cache_dir=model_args.cache_dir,
|
||||
)
|
||||
tokenizer = AutoTokenizer.from_pretrained(
|
||||
model_args.tokenizer_name if model_args.tokenizer_name else model_args.model_name_or_path,
|
||||
cache_dir=model_args.cache_dir,
|
||||
use_fast=model_args.use_fast,
|
||||
)
|
||||
|
||||
with training_args.strategy.scope():
|
||||
model = TFAutoModelForQuestionAnswering.from_pretrained(
|
||||
model_args.model_name_or_path,
|
||||
from_pt=bool(".bin" in model_args.model_name_or_path),
|
||||
config=config,
|
||||
cache_dir=model_args.cache_dir,
|
||||
)
|
||||
|
||||
# Get datasets
|
||||
if not data_args.data_dir:
|
||||
if data_args.version_2_with_negative:
|
||||
logger.warn("tensorflow_datasets does not handle version 2 of SQuAD. Switch to version 1 automatically")
|
||||
|
||||
try:
|
||||
import tensorflow_datasets as tfds
|
||||
except ImportError:
|
||||
raise ImportError("If not data_dir is specified, tensorflow_datasets needs to be installed.")
|
||||
|
||||
tfds_examples = tfds.load("squad")
|
||||
train_examples = (
|
||||
SquadV1Processor().get_examples_from_dataset(tfds_examples, evaluate=False)
|
||||
if training_args.do_train
|
||||
else None
|
||||
)
|
||||
eval_examples = (
|
||||
SquadV1Processor().get_examples_from_dataset(tfds_examples, evaluate=True)
|
||||
if training_args.do_eval
|
||||
else None
|
||||
)
|
||||
else:
|
||||
processor = SquadV2Processor() if data_args.version_2_with_negative else SquadV1Processor()
|
||||
train_examples = processor.get_train_examples(data_args.data_dir) if training_args.do_train else None
|
||||
eval_examples = processor.get_dev_examples(data_args.data_dir) if training_args.do_eval else None
|
||||
|
||||
train_dataset = (
|
||||
squad_convert_examples_to_features(
|
||||
examples=train_examples,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=data_args.max_seq_length,
|
||||
doc_stride=data_args.doc_stride,
|
||||
max_query_length=data_args.max_query_length,
|
||||
is_training=True,
|
||||
return_dataset="tf",
|
||||
)
|
||||
if training_args.do_train
|
||||
else None
|
||||
)
|
||||
|
||||
eval_dataset = (
|
||||
squad_convert_examples_to_features(
|
||||
examples=eval_examples,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=data_args.max_seq_length,
|
||||
doc_stride=data_args.doc_stride,
|
||||
max_query_length=data_args.max_query_length,
|
||||
is_training=False,
|
||||
return_dataset="tf",
|
||||
)
|
||||
if training_args.do_eval
|
||||
else None
|
||||
)
|
||||
|
||||
# Initialize our Trainer
|
||||
trainer = TFTrainer(model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset,)
|
||||
|
||||
# Training
|
||||
if training_args.do_train:
|
||||
trainer.train()
|
||||
trainer.save_model()
|
||||
tokenizer.save_pretrained(training_args.output_dir)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -72,7 +72,7 @@ class ExamplesTests(unittest.TestCase):
|
||||
""".split()
|
||||
with patch.object(sys, "argv", testargs):
|
||||
result = run_glue.main()
|
||||
del result["loss"]
|
||||
del result["eval_loss"]
|
||||
for value in result.values():
|
||||
self.assertGreaterEqual(value, 0.75)
|
||||
|
||||
|
||||
@@ -171,7 +171,6 @@ def main():
|
||||
max_seq_length=data_args.max_seq_length,
|
||||
overwrite_cache=data_args.overwrite_cache,
|
||||
mode=Split.train,
|
||||
local_rank=training_args.local_rank,
|
||||
)
|
||||
if training_args.do_train
|
||||
else None
|
||||
@@ -185,7 +184,6 @@ def main():
|
||||
max_seq_length=data_args.max_seq_length,
|
||||
overwrite_cache=data_args.overwrite_cache,
|
||||
mode=Split.dev,
|
||||
local_rank=training_args.local_rank,
|
||||
)
|
||||
if training_args.do_eval
|
||||
else None
|
||||
@@ -261,7 +259,6 @@ def main():
|
||||
max_seq_length=data_args.max_seq_length,
|
||||
overwrite_cache=data_args.overwrite_cache,
|
||||
mode=Split.test,
|
||||
local_rank=training_args.local_rank,
|
||||
)
|
||||
|
||||
predictions, label_ids, metrics = trainer.predict(test_dataset)
|
||||
|
||||
@@ -6,7 +6,7 @@ from unittest.mock import patch
|
||||
import run_ner
|
||||
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
@@ -30,4 +30,4 @@ class ExamplesTests(unittest.TestCase):
|
||||
""".split()
|
||||
with patch.object(sys, "argv", ["run.py"] + testargs):
|
||||
result = run_ner.main()
|
||||
self.assertLess(result["loss"], 1.5)
|
||||
self.assertLess(result["eval_loss"], 1.5)
|
||||
|
||||
@@ -22,6 +22,8 @@ from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from filelock import FileLock
|
||||
|
||||
from transformers import PreTrainedTokenizer, is_tf_available, is_torch_available
|
||||
|
||||
|
||||
@@ -68,7 +70,6 @@ if is_torch_available():
|
||||
import torch
|
||||
from torch import nn
|
||||
from torch.utils.data.dataset import Dataset
|
||||
from transformers import torch_distributed_zero_first
|
||||
|
||||
class NerDataset(Dataset):
|
||||
"""
|
||||
@@ -90,16 +91,16 @@ if is_torch_available():
|
||||
max_seq_length: Optional[int] = None,
|
||||
overwrite_cache=False,
|
||||
mode: Split = Split.train,
|
||||
local_rank=-1,
|
||||
):
|
||||
# Load data features from cache or dataset file
|
||||
cached_features_file = os.path.join(
|
||||
data_dir, "cached_{}_{}_{}".format(mode.value, tokenizer.__class__.__name__, str(max_seq_length)),
|
||||
)
|
||||
|
||||
with torch_distributed_zero_first(local_rank):
|
||||
# Make sure only the first process in distributed training processes the dataset,
|
||||
# and the others will use the cache.
|
||||
# Make sure only the first process in distributed training processes the dataset,
|
||||
# and the others will use the cache.
|
||||
lock_path = cached_features_file + ".lock"
|
||||
with FileLock(lock_path):
|
||||
|
||||
if os.path.exists(cached_features_file) and not overwrite_cache:
|
||||
logger.info(f"Loading features from cached file {cached_features_file}")
|
||||
@@ -125,9 +126,8 @@ if is_torch_available():
|
||||
pad_token_segment_id=tokenizer.pad_token_type_id,
|
||||
pad_token_label_id=self.pad_token_label_id,
|
||||
)
|
||||
if local_rank in [-1, 0]:
|
||||
logger.info(f"Saving features into cached file {cached_features_file}")
|
||||
torch.save(self.features, cached_features_file)
|
||||
logger.info(f"Saving features into cached file {cached_features_file}")
|
||||
torch.save(self.features, cached_features_file)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.features)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
language: norwegian
|
||||
thumbnail: https://i.imgur.com/QqSEC5I.png
|
||||
---
|
||||
|
||||
# Norwegian Electra
|
||||

|
||||
|
||||
Trained on Oscar + wikipedia + opensubtitles + some other data I had with the awesome power of TPUs(V3-8)
|
||||
|
||||
Use with caution. I have no downstream tasks in Norwegian to test on so I have no idea of its performance yet.
|
||||
# Model
|
||||
## Electra: Pre-training Text Encoders as Discriminators Rather Than Generators
|
||||
Kevin Clark and Minh-Thang Luong and Quoc V. Le and Christopher D. Manning
|
||||
- https://openreview.net/pdf?id=r1xMH1BtvB
|
||||
- https://github.com/google-research/electra
|
||||
# Acknowledgments
|
||||
### TensorFlow Research Cloud
|
||||
Research supported with Cloud TPUs from Google's TensorFlow Research Cloud (TFRC). Thanks for providing access to the TFRC ❤️
|
||||
- https://www.tensorflow.org/tfrc
|
||||
#### OSCAR corpus
|
||||
- https://oscar-corpus.com/
|
||||
#### OPUS
|
||||
- http://opus.nlpl.eu/
|
||||
- http://www.opensubtitles.org/
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
language: turkish
|
||||
license: mit
|
||||
---
|
||||
|
||||
# 🤗 + 📚 dbmdz Turkish ELECTRA model
|
||||
|
||||
In this repository the MDZ Digital Library team (dbmdz) at the Bavarian State
|
||||
Library open sources a cased ELECTRA base model for Turkish 🎉
|
||||
|
||||
# Turkish ELECTRA model
|
||||
|
||||
We release a base ELEC**TR**A model for Turkish, that was trained on the same data as *BERTurk*.
|
||||
|
||||
> ELECTRA is a new method for self-supervised language representation learning. It can be used to
|
||||
> pre-train transformer networks using relatively little compute. ELECTRA models are trained to
|
||||
> distinguish "real" input tokens vs "fake" input tokens generated by another neural network, similar to
|
||||
> the discriminator of a GAN.
|
||||
|
||||
More details about ELECTRA can be found in the [ICLR paper](https://openreview.net/forum?id=r1xMH1BtvB)
|
||||
or in the [official ELECTRA repository](https://github.com/google-research/electra) on GitHub.
|
||||
|
||||
## Stats
|
||||
|
||||
The current version of the model is trained on a filtered and sentence
|
||||
segmented version of the Turkish [OSCAR corpus](https://traces1.inria.fr/oscar/),
|
||||
a recent Wikipedia dump, various [OPUS corpora](http://opus.nlpl.eu/) and a
|
||||
special corpus provided by [Kemal Oflazer](http://www.andrew.cmu.edu/user/ko/).
|
||||
|
||||
The final training corpus has a size of 35GB and 44,04,976,662 tokens.
|
||||
|
||||
Thanks to Google's TensorFlow Research Cloud (TFRC) we could train a cased model
|
||||
on a TPU v3-8 for 1M steps.
|
||||
|
||||
## Model weights
|
||||
|
||||
[Transformers](https://github.com/huggingface/transformers)
|
||||
compatible weights for both PyTorch and TensorFlow are available.
|
||||
|
||||
| Model | Downloads
|
||||
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------
|
||||
| `dbmdz/electra-base-turkish-cased-discriminator` | [`config.json`](https://cdn.huggingface.co/dbmdz/electra-base-turkish-cased-discriminator/config.json) • [`pytorch_model.bin`](https://cdn.huggingface.co/dbmdz/electra-base-turkish-cased-discriminator/pytorch_model.bin) • [`vocab.txt`](https://cdn.huggingface.co/dbmdz/electra-base-turkish-cased-discriminator/vocab.txt)
|
||||
|
||||
## Usage
|
||||
|
||||
With Transformers >= 2.8 our ELECTRA base cased model can be loaded like:
|
||||
|
||||
```python
|
||||
from transformers import AutoModelWithLMHead, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("dbmdz/electra-base-turkish-cased-discriminator")
|
||||
model = AutoModelWithLMHead.from_pretrained("dbmdz/electra-base-turkish-cased-discriminator")
|
||||
```
|
||||
|
||||
## Results
|
||||
|
||||
For results on PoS tagging or NER tasks, please refer to
|
||||
[this repository](https://github.com/stefan-it/turkish-bert/electra).
|
||||
|
||||
# Huggingface model hub
|
||||
|
||||
All models are available on the [Huggingface model hub](https://huggingface.co/dbmdz).
|
||||
|
||||
# Contact (Bugs, Feedback, Contribution and more)
|
||||
|
||||
For questions about our ELECTRA models just open an issue
|
||||
[here](https://github.com/dbmdz/berts/issues/new) 🤗
|
||||
|
||||
# Acknowledgments
|
||||
|
||||
Thanks to [Kemal Oflazer](http://www.andrew.cmu.edu/user/ko/) for providing us
|
||||
additional large corpora for Turkish. Many thanks to Reyyan Yeniterzi for providing
|
||||
us the Turkish NER dataset for evaluation.
|
||||
|
||||
Research supported with Cloud TPUs from Google's TensorFlow Research Cloud (TFRC).
|
||||
Thanks for providing access to the TFRC ❤️
|
||||
|
||||
Thanks to the generous support from the [Hugging Face](https://huggingface.co/) team,
|
||||
it is possible to download both cased and uncased models from their S3 storage 🤗
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
language: turkish
|
||||
license: mit
|
||||
---
|
||||
|
||||
# 🤗 + 📚 dbmdz Turkish ELECTRA model
|
||||
|
||||
In this repository the MDZ Digital Library team (dbmdz) at the Bavarian State
|
||||
Library open sources a cased ELECTRA small model for Turkish 🎉
|
||||
|
||||
# Turkish ELECTRA model
|
||||
|
||||
We release a small ELEC**TR**A model for Turkish, that was trained on the same data as *BERTurk*.
|
||||
|
||||
> ELECTRA is a new method for self-supervised language representation learning. It can be used to
|
||||
> pre-train transformer networks using relatively little compute. ELECTRA models are trained to
|
||||
> distinguish "real" input tokens vs "fake" input tokens generated by another neural network, similar to
|
||||
> the discriminator of a GAN.
|
||||
|
||||
More details about ELECTRA can be found in the [ICLR paper](https://openreview.net/forum?id=r1xMH1BtvB)
|
||||
or in the [official ELECTRA repository](https://github.com/google-research/electra) on GitHub.
|
||||
|
||||
## Stats
|
||||
|
||||
The current version of the model is trained on a filtered and sentence
|
||||
segmented version of the Turkish [OSCAR corpus](https://traces1.inria.fr/oscar/),
|
||||
a recent Wikipedia dump, various [OPUS corpora](http://opus.nlpl.eu/) and a
|
||||
special corpus provided by [Kemal Oflazer](http://www.andrew.cmu.edu/user/ko/).
|
||||
|
||||
The final training corpus has a size of 35GB and 44,04,976,662 tokens.
|
||||
|
||||
Thanks to Google's TensorFlow Research Cloud (TFRC) we could train a cased model
|
||||
on a TPU v3-8 for 1M steps.
|
||||
|
||||
## Model weights
|
||||
|
||||
[Transformers](https://github.com/huggingface/transformers)
|
||||
compatible weights for both PyTorch and TensorFlow are available.
|
||||
|
||||
| Model | Downloads
|
||||
| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------
|
||||
| `dbmdz/electra-small-turkish-cased-discriminator` | [`config.json`](https://cdn.huggingface.co/dbmdz/electra-small-turkish-cased-discriminator/config.json) • [`pytorch_model.bin`](https://cdn.huggingface.co/dbmdz/electra-small-turkish-cased-discriminator/pytorch_model.bin) • [`vocab.txt`](https://cdn.huggingface.co/dbmdz/electra-small-turkish-cased-discriminator/vocab.txt)
|
||||
|
||||
## Usage
|
||||
|
||||
With Transformers >= 2.8 our ELECTRA small cased model can be loaded like:
|
||||
|
||||
```python
|
||||
from transformers import AutoModelWithLMHead, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("dbmdz/electra-small-turkish-cased-discriminator")
|
||||
model = AutoModelWithLMHead.from_pretrained("dbmdz/electra-small-turkish-cased-discriminator")
|
||||
```
|
||||
|
||||
## Results
|
||||
|
||||
For results on PoS tagging or NER tasks, please refer to
|
||||
[this repository](https://github.com/stefan-it/turkish-bert/electra).
|
||||
|
||||
# Huggingface model hub
|
||||
|
||||
All models are available on the [Huggingface model hub](https://huggingface.co/dbmdz).
|
||||
|
||||
# Contact (Bugs, Feedback, Contribution and more)
|
||||
|
||||
For questions about our ELECTRA models just open an issue
|
||||
[here](https://github.com/dbmdz/berts/issues/new) 🤗
|
||||
|
||||
# Acknowledgments
|
||||
|
||||
Thanks to [Kemal Oflazer](http://www.andrew.cmu.edu/user/ko/) for providing us
|
||||
additional large corpora for Turkish. Many thanks to Reyyan Yeniterzi for providing
|
||||
us the Turkish NER dataset for evaluation.
|
||||
|
||||
Research supported with Cloud TPUs from Google's TensorFlow Research Cloud (TFRC).
|
||||
Thanks for providing access to the TFRC ❤️
|
||||
|
||||
Thanks to the generous support from the [Hugging Face](https://huggingface.co/) team,
|
||||
it is possible to download both cased and uncased models from their S3 storage 🤗
|
||||
@@ -25,7 +25,7 @@ fill_mask = pipeline(
|
||||
)
|
||||
|
||||
print(
|
||||
fill_mask(f"HuggingFace is creating a {nlp.tokenizer.mask_token} that the community uses to solve NLP tasks.")
|
||||
fill_mask(f"HuggingFace is creating a {fill_mask.tokenizer.mask_token} that the community uses to solve NLP tasks.")
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
@@ -17,6 +17,7 @@ nlp({
|
||||
|
||||
```python
|
||||
from transformers import AutoTokenizer, AutoModelForQuestionAnswering
|
||||
import torch
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("lserinol/bert-turkish-question-answering")
|
||||
model = AutoModelForQuestionAnswering.from_pretrained("lserinol/bert-turkish-question-answering")
|
||||
|
||||
@@ -20,6 +20,9 @@ A few examples of the model response to a query before and after optimisation:
|
||||
|I have watched 3 episodes |with this guy and he is such a talented actor...| but the show is just plain awful and there ne...| 2.681171| -4.512792|
|
||||
|We know that firefighters and| police officers are forced to become populari...| other chains have going to get this disaster ...| 1.367811| -3.34017|
|
||||
|
||||
## Training logs and metrics <img src="https://gblobscdn.gitbook.com/spaces%2F-Lqya5RvLedGEWPhtkjU%2Favatar.png?alt=media" width="25" height="25">
|
||||
Watch the whole training logs and metrics on [W&B](https://app.wandb.ai/mrm8488/gpt2-sentiment-negative?workspace=user-mrm8488)
|
||||
|
||||
|
||||
|
||||
> Created by [Manuel Romero/@mrm8488](https://twitter.com/mrm8488)
|
||||
|
||||
@@ -38,7 +38,7 @@ The dataset is used by following papers
|
||||
* 1 Yildirim, Savaş. (2020). Comparing Deep Neural Networks to Traditional Models for Sentiment Analysis in Turkish Language. 10.1007/978-981-15-1216-2_12.
|
||||
* 2 Demirtas, Erkin and Mykola Pechenizkiy. 2013. Cross-lingual polarity detection with machine translation. In Proceedings of the Second International Workshop on Issues of Sentiment
|
||||
Discovery and Opinion Mining (WISDOM ’13)
|
||||
* Hayran, A., Sert, M. (2017), "Sentiment Analysis on Microblog Data based on Word Embedding and Fusion Techniques", IEEE 25th Signal Processing and Communications Applications Conference (SIU 2017), Belek, Turkey
|
||||
* [3] Hayran, A., Sert, M. (2017), "Sentiment Analysis on Microblog Data based on Word Embedding and Fusion Techniques", IEEE 25th Signal Processing and Communications Applications Conference (SIU 2017), Belek, Turkey
|
||||
|
||||
# Training
|
||||
|
||||
@@ -121,8 +121,8 @@ Suppose your file has lots of lines of comment and label (1 or 0) at the end (t
|
||||
from transformers import AutoModelForSequenceClassification, AutoTokenizer, pipeline
|
||||
|
||||
f="/path/to/your/file/yourfile.tsv"
|
||||
model = AutoModelForSequenceClassification.from_pretrained(folder)
|
||||
tokenizer = AutoTokenizer.from_pretrained(folder)
|
||||
model = AutoModelForSequenceClassification.from_pretrained("savasy/bert-base-turkish-sentiment-cased")
|
||||
tokenizer = AutoTokenizer.from_pretrained("savasy/bert-base-turkish-sentiment-cased")
|
||||
sa= pipeline("sentiment-analysis", tokenizer=tokenizer, model=model)
|
||||
|
||||
i,crr=0,0
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
language: turkish
|
||||
---
|
||||
# Turkish SQuAD Model : Question Answering
|
||||
|
||||
I fine-tuned Turkish-Bert-Model for Question-Answering problem with Turkish version of SQuAD; TQuAD
|
||||
* BERT-base: https://huggingface.co/dbmdz/bert-base-turkish-uncased
|
||||
* TQuAD dataset: https://github.com/TQuad/turkish-nlp-qa-dataset
|
||||
|
||||
|
||||
# Training Code
|
||||
|
||||
```
|
||||
!python3 run_squad.py \
|
||||
--model_type bert \
|
||||
--model_name_or_path dbmdz/bert-base-turkish-uncased\
|
||||
--do_train \
|
||||
--do_eval \
|
||||
--train_file trainQ.json \
|
||||
--predict_file dev1.json \
|
||||
--per_gpu_train_batch_size 12 \
|
||||
--learning_rate 3e-5 \
|
||||
--num_train_epochs 5.0 \
|
||||
--max_seq_length 384 \
|
||||
--doc_stride 128 \
|
||||
--output_dir "./model"
|
||||
```
|
||||
|
||||
|
||||
# Example Usage
|
||||
|
||||
> Load Model
|
||||
```
|
||||
from transformers import AutoTokenizer, AutoModelForQuestionAnswering, pipeline
|
||||
import torch
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("./model")
|
||||
model = AutoModelForQuestionAnswering.from_pretrained("./model")
|
||||
nlp=pipeline("question-answering", model=model, tokenizer=tokenizer)
|
||||
```
|
||||
|
||||
> Apply the model
|
||||
```
|
||||
|
||||
sait="ABASIYANIK, Sait Faik. Hikayeci (Adapazarı 23 Kasım 1906-İstanbul 11 Mayıs 1954). \
|
||||
İlk öğrenimine Adapazarı’nda Rehber-i Terakki Mektebi’nde başladı. İki yıl kadar Adapazarı İdadisi’nde okudu.\
|
||||
İstanbul Erkek Lisesi’nde devam ettiği orta öğrenimini Bursa Lisesi’nde tamamladı (1928). İstanbul Edebiyat \
|
||||
Fakültesi’ne iki yıl devam ettikten sonra babasının isteği üzerine iktisat öğrenimi için İsviçre’ye gitti. \
|
||||
Kısa süre sonra iktisat öğrenimini bırakarak Lozan’dan Grenoble’a geçti. Üç yıl başıboş bir edebiyat öğrenimi \
|
||||
gördükten sonra babası tarafından geri çağrıldı (1933). Bir müddet Halıcıoğlu Ermeni Yetim Mektebi'nde Türkçe \
|
||||
gurup dersleri öğretmenliği yaptı. Ticarete atıldıysa da tutunamadı. Bir ay Haber gazetesinde adliye muhabirliği\
|
||||
yaptı (1942). Babasının ölümü üzerine aileden kalan emlakin geliri ile avare bir hayata başladı. Evlenemedi.\
|
||||
Yazları Burgaz adasındaki köşklerinde, kışları Şişli’deki apartmanlarında annesi ile beraber geçen bu fazla \
|
||||
içkili bohem hayatı ömrünün sonuna kadar sürdü."
|
||||
|
||||
print(nlp(question="Ne zaman avare bir hayata başladı?", context=sait))
|
||||
print(nlp(question="Sait Faik hangi Lisede orta öğrenimini tamamladı?", context=sait))
|
||||
|
||||
```
|
||||
```
|
||||
# Ask your self ! type your question
|
||||
print(nlp(question="...?", context=sait))
|
||||
```
|
||||
|
||||
|
||||
Check My other Model
|
||||
https://huggingface.co/savasy
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
tags:
|
||||
- pytorch
|
||||
- exbert
|
||||
license: apache-2.0
|
||||
---
|
||||
# ouBioBERT-Base, Uncased
|
||||
Bidirectional Encoder Representations from Transformers for Biomedical Text Mining by Osaka University (ouBioBERT) is a language model based on the BERT-Base (Devlin, et al., 2019) architecture. We pre-trained ouBioBERT on PubMed abstracts from the PubMed baseline (ftp://ftp.ncbi.nlm.nih.gov/pubmed/baseline) via our method.
|
||||
|
||||
The details of the pre-training procedure can be found in Wada, et al. (2020).
|
||||
|
||||
## Evaluation
|
||||
We evaluated the performance of ouBioBERT in terms of the biomedical language understanding evaluation (BLUE) benchmark (Peng, et al., 2019). The numbers are mean (standard deviation) on five different random seeds.
|
||||
| Dataset | Task Type | Score |
|
||||
|:----------------|:--------------------------|-------------:|
|
||||
| MedSTS | Sentence similarity | 84.9 (0.6) |
|
||||
| BIOSSES | Sentence similarity | 92.3 (0.8) |
|
||||
| BC5CDR-disease | Named-entity recognition | 87.4 (0.1) |
|
||||
| BC5CDR-chemical | Named-entity recognition | 93.7 (0.2) |
|
||||
| ShARe/CLEFE | Named-entity recognition | 80.1 (0.4) |
|
||||
| DDI | Relation extraction | 81.1 (1.5) |
|
||||
| ChemProt | Relation extraction | 75.0 (0.3) |
|
||||
| i2b2 2010 | Relation extraction | 74.0 (0.8) |
|
||||
| HoC | Document classification | 86.4 (0.5) |
|
||||
| MedNLI | Inference | 83.6 (0.7) |
|
||||
| **Total** | - |**83.8 (0.3)**|
|
||||
|
||||
## Code for Fine-tuning
|
||||
We made the source code for fine-tuning freely available at [our repository](https://github.com/sy-wada/blue_benchmark_with_transformers).
|
||||
|
||||
## Citation
|
||||
If you use our work in your research, please kindly cite the following paper:
|
||||
```bibtex
|
||||
now preparing...
|
||||
```
|
||||
|
||||
<a href="https://huggingface.co/exbert/?model=seiya/oubiobert-base-uncased&sentence=Coronavirus%20disease%20(COVID-19)%20is%20caused%20by%20SARS-COV2%20and%20represents%20the%20causative%20agent%20of%20a%20potentially%20fatal%20disease%20that%20is%20of%20great%20global%20public%20health%20concern.">
|
||||
<img width="300px" src="https://hf-dinosaur.huggingface.co/exbert/button.png">
|
||||
</a>
|
||||
@@ -3,7 +3,6 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"pycharm": {
|
||||
"is_executing": false,
|
||||
"name": "#%% md\n"
|
||||
@@ -77,7 +76,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"pycharm": {
|
||||
"is_executing": false,
|
||||
@@ -85,77 +84,7 @@
|
||||
},
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Requirement already satisfied: transformers in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (2.5.1)\n",
|
||||
"Requirement already satisfied: filelock in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from transformers) (3.0.12)\n",
|
||||
"Requirement already satisfied: sentencepiece in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from transformers) (0.1.83)\n",
|
||||
"Requirement already satisfied: boto3 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from transformers) (1.12.0)\n",
|
||||
"Requirement already satisfied: requests in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from transformers) (2.22.0)\n",
|
||||
"Requirement already satisfied: numpy in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from transformers) (1.18.1)\n",
|
||||
"Requirement already satisfied: sacremoses in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from transformers) (0.0.35)\n",
|
||||
"Requirement already satisfied: tokenizers==0.5.2 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from transformers) (0.5.2)\n",
|
||||
"Requirement already satisfied: regex!=2019.12.17 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from transformers) (2020.1.8)\n",
|
||||
"Requirement already satisfied: tqdm>=4.27 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from transformers) (4.42.1)\n",
|
||||
"Requirement already satisfied: s3transfer<0.4.0,>=0.3.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from boto3->transformers) (0.3.3)\n",
|
||||
"Requirement already satisfied: botocore<1.16.0,>=1.15.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from boto3->transformers) (1.15.0)\n",
|
||||
"Requirement already satisfied: jmespath<1.0.0,>=0.7.1 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from boto3->transformers) (0.9.4)\n",
|
||||
"Requirement already satisfied: certifi>=2017.4.17 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from requests->transformers) (2019.11.28)\n",
|
||||
"Requirement already satisfied: idna<2.9,>=2.5 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from requests->transformers) (2.8)\n",
|
||||
"Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from requests->transformers) (1.25.8)\n",
|
||||
"Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from requests->transformers) (3.0.4)\n",
|
||||
"Requirement already satisfied: joblib in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from sacremoses->transformers) (0.14.0)\n",
|
||||
"Requirement already satisfied: click in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from sacremoses->transformers) (7.0)\n",
|
||||
"Requirement already satisfied: six in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from sacremoses->transformers) (1.14.0)\n",
|
||||
"Requirement already satisfied: docutils<0.16,>=0.10 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from botocore<1.16.0,>=1.15.0->boto3->transformers) (0.15.2)\n",
|
||||
"Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from botocore<1.16.0,>=1.15.0->boto3->transformers) (2.8.1)\n",
|
||||
"Requirement already satisfied: tensorflow==2.1.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (2.1.0)\n",
|
||||
"Requirement already satisfied: termcolor>=1.1.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (1.1.0)\n",
|
||||
"Requirement already satisfied: keras-preprocessing>=1.1.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (1.1.0)\n",
|
||||
"Requirement already satisfied: opt-einsum>=2.3.2 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (3.1.0)\n",
|
||||
"Requirement already satisfied: protobuf>=3.8.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (3.11.4)\n",
|
||||
"Requirement already satisfied: numpy<2.0,>=1.16.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (1.18.1)\n",
|
||||
"Requirement already satisfied: tensorboard<2.2.0,>=2.1.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (2.1.0)\n",
|
||||
"Requirement already satisfied: keras-applications>=1.0.8 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (1.0.8)\n",
|
||||
"Requirement already satisfied: wrapt>=1.11.1 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (1.11.2)\n",
|
||||
"Requirement already satisfied: six>=1.12.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (1.14.0)\n",
|
||||
"Requirement already satisfied: tensorflow-estimator<2.2.0,>=2.1.0rc0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (2.1.0)\n",
|
||||
"Requirement already satisfied: scipy==1.4.1; python_version >= \"3\" in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (1.4.1)\n",
|
||||
"Requirement already satisfied: google-pasta>=0.1.6 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (0.1.8)\n",
|
||||
"Requirement already satisfied: wheel>=0.26; python_version >= \"3\" in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (0.34.2)\n",
|
||||
"Requirement already satisfied: grpcio>=1.8.6 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (1.16.1)\n",
|
||||
"Requirement already satisfied: absl-py>=0.7.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (0.9.0)\n",
|
||||
"Requirement already satisfied: gast==0.2.2 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (0.2.2)\n",
|
||||
"Requirement already satisfied: astor>=0.6.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorflow==2.1.0) (0.8.0)\n",
|
||||
"Requirement already satisfied: setuptools in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from protobuf>=3.8.0->tensorflow==2.1.0) (45.2.0.post20200210)\n",
|
||||
"Requirement already satisfied: google-auth<2,>=1.6.3 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (1.11.2)\n",
|
||||
"Requirement already satisfied: google-auth-oauthlib<0.5,>=0.4.1 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (0.4.1)\n",
|
||||
"Requirement already satisfied: markdown>=2.6.8 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (3.1.1)\n",
|
||||
"Requirement already satisfied: werkzeug>=0.11.15 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (1.0.0)\n",
|
||||
"Requirement already satisfied: requests<3,>=2.21.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (2.22.0)\n",
|
||||
"Requirement already satisfied: h5py in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from keras-applications>=1.0.8->tensorflow==2.1.0) (2.10.0)\n",
|
||||
"Requirement already satisfied: rsa<4.1,>=3.1.4 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from google-auth<2,>=1.6.3->tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (4.0)\n",
|
||||
"Requirement already satisfied: cachetools<5.0,>=2.0.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from google-auth<2,>=1.6.3->tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (4.0.0)\n",
|
||||
"Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from google-auth<2,>=1.6.3->tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (0.2.8)\n",
|
||||
"Requirement already satisfied: requests-oauthlib>=0.7.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from google-auth-oauthlib<0.5,>=0.4.1->tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (1.3.0)\n",
|
||||
"Requirement already satisfied: idna<2.9,>=2.5 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from requests<3,>=2.21.0->tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (2.8)\n",
|
||||
"Requirement already satisfied: certifi>=2017.4.17 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from requests<3,>=2.21.0->tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (2019.11.28)\n",
|
||||
"Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from requests<3,>=2.21.0->tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (3.0.4)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from requests<3,>=2.21.0->tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (1.25.8)\r\n",
|
||||
"Requirement already satisfied: pyasn1>=0.1.3 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from rsa<4.1,>=3.1.4->google-auth<2,>=1.6.3->tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (0.4.8)\r\n",
|
||||
"Requirement already satisfied: oauthlib>=3.0.0 in /usr/local/Caskroom/miniconda/base/envs/huggingface/lib/python3.7/site-packages (from requests-oauthlib>=0.7.0->google-auth-oauthlib<0.5,>=0.4.1->tensorboard<2.2.0,>=2.1.0->tensorflow==2.1.0) (3.1.0)\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install transformers\n",
|
||||
"!pip install tensorflow==2.1.0"
|
||||
@@ -174,7 +103,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"<torch.autograd.grad_mode.set_grad_enabled at 0x102c0ce10>"
|
||||
"<torch.autograd.grad_mode.set_grad_enabled at 0x7f10b441e890>"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
@@ -441,7 +370,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 8,
|
||||
"metadata": {
|
||||
"pycharm": {
|
||||
"is_executing": false
|
||||
@@ -458,13 +387,22 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"pycharm": {
|
||||
"is_executing": false
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"output differences: 1.6236e-05\n",
|
||||
"pooled differences: -1.3039e-08\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# transformers generates a ready to use dictionary with all the required parameters for the specific framework.\n",
|
||||
"input_tf = tokenizer.encode_plus(\"This is a sample input\", return_tensors=\"tf\")\n",
|
||||
@@ -476,7 +414,7 @@
|
||||
"# Models outputs 2 values (The value for each tokens, the pooled representation of the input sentence)\n",
|
||||
"# Here we compare the output differences between PyTorch and TensorFlow.\n",
|
||||
"for name, o_tf, o_pt in zip([\"output\", \"pooled\"], output_tf, output_pt):\n",
|
||||
" print(\"{} differences: {}\".format(name, (o_tf.numpy() - o_pt.numpy()).sum()))"
|
||||
" print(\"{} differences: {:.5}\".format(name, (o_tf.numpy() - o_pt.numpy()).sum()))"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -504,13 +442,24 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 10,
|
||||
"metadata": {
|
||||
"pycharm": {
|
||||
"is_executing": false
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"CPU times: user 232 ms, sys: 0 ns, total: 232 ms\n",
|
||||
"Wall time: 21.1 ms\n",
|
||||
"CPU times: user 511 ms, sys: 0 ns, total: 511 ms\n",
|
||||
"Wall time: 43.9 ms\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from transformers import DistilBertModel\n",
|
||||
"\n",
|
||||
@@ -541,13 +490,25 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 11,
|
||||
"metadata": {
|
||||
"pycharm": {
|
||||
"is_executing": false
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Tokens (int) : [102, 12272, 9355, 5746, 30881, 215, 261, 5945, 4118, 212, 2414, 153, 1942, 232, 3532, 566, 103]\n",
|
||||
"Tokens (str) : ['[CLS]', 'Hug', '##ging', 'Fac', '##e', 'ist', 'eine', 'französische', 'Firma', 'mit', 'Sitz', 'in', 'New', '-', 'York', '.', '[SEP]']\n",
|
||||
"Tokens (attn_mask): [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n",
|
||||
"\n",
|
||||
"Token wise output: torch.Size([1, 7, 768]), Pooled output: torch.Size([1, 768])\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Let's load German BERT from the Bavarian State Library\n",
|
||||
"de_bert = BertModel.from_pretrained(\"dbmdz/bert-base-german-cased\")\n",
|
||||
@@ -557,7 +518,14 @@
|
||||
" \"Hugging Face ist eine französische Firma mit Sitz in New-York.\",\n",
|
||||
" return_tensors=\"pt\"\n",
|
||||
")\n",
|
||||
"output_de, pooled_de = de_bert(**de_input)"
|
||||
"print(\"Tokens (int) : {}\".format(de_input['input_ids'].tolist()[0]))\n",
|
||||
"print(\"Tokens (str) : {}\".format([de_tokenizer.convert_ids_to_tokens(s) for s in de_input['input_ids'].tolist()[0]]))\n",
|
||||
"print(\"Tokens (attn_mask): {}\".format(de_input['attention_mask'].tolist()[0]))\n",
|
||||
"print()\n",
|
||||
"\n",
|
||||
"output_de, pooled_de = de_bert(**de_input)\n",
|
||||
"\n",
|
||||
"print(\"Token wise output: {}, Pooled output: {}\".format(outputs.shape, pooled.shape))"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -577,7 +545,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.6"
|
||||
"version": "3.7.4"
|
||||
},
|
||||
"pycharm": {
|
||||
"stem_cell": {
|
||||
@@ -590,5 +558,5 @@
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 1
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
|
||||
+390
-35
@@ -30,7 +30,8 @@
|
||||
},
|
||||
"colab": {
|
||||
"name": "03-pipelines.ipynb",
|
||||
"provenance": []
|
||||
"provenance": [],
|
||||
"include_colab_link": true
|
||||
},
|
||||
"widgets": {
|
||||
"application/vnd.jupyter.widget-state+json": {
|
||||
@@ -1504,6 +1505,251 @@
|
||||
"left": null
|
||||
}
|
||||
},
|
||||
"3c86415352574190b71e1fe5a15d36f1": {
|
||||
"model_module": "@jupyter-widgets/controls",
|
||||
"model_name": "HBoxModel",
|
||||
"state": {
|
||||
"_view_name": "HBoxView",
|
||||
"_dom_classes": [],
|
||||
"_model_name": "HBoxModel",
|
||||
"_view_module": "@jupyter-widgets/controls",
|
||||
"_model_module_version": "1.5.0",
|
||||
"_view_count": null,
|
||||
"_view_module_version": "1.5.0",
|
||||
"box_style": "",
|
||||
"layout": "IPY_MODEL_dd2c9dd935754cf2802233053554c21c",
|
||||
"_model_module": "@jupyter-widgets/controls",
|
||||
"children": [
|
||||
"IPY_MODEL_8ae3be32d9c845e59fdb1c47884d48aa",
|
||||
"IPY_MODEL_4dea0031f3554752ad5aad01fe516a60"
|
||||
]
|
||||
}
|
||||
},
|
||||
"dd2c9dd935754cf2802233053554c21c": {
|
||||
"model_module": "@jupyter-widgets/base",
|
||||
"model_name": "LayoutModel",
|
||||
"state": {
|
||||
"_view_name": "LayoutView",
|
||||
"grid_template_rows": null,
|
||||
"right": null,
|
||||
"justify_content": null,
|
||||
"_view_module": "@jupyter-widgets/base",
|
||||
"overflow": null,
|
||||
"_model_module_version": "1.2.0",
|
||||
"_view_count": null,
|
||||
"flex_flow": null,
|
||||
"width": null,
|
||||
"min_width": null,
|
||||
"border": null,
|
||||
"align_items": null,
|
||||
"bottom": null,
|
||||
"_model_module": "@jupyter-widgets/base",
|
||||
"top": null,
|
||||
"grid_column": null,
|
||||
"overflow_y": null,
|
||||
"overflow_x": null,
|
||||
"grid_auto_flow": null,
|
||||
"grid_area": null,
|
||||
"grid_template_columns": null,
|
||||
"flex": null,
|
||||
"_model_name": "LayoutModel",
|
||||
"justify_items": null,
|
||||
"grid_row": null,
|
||||
"max_height": null,
|
||||
"align_content": null,
|
||||
"visibility": null,
|
||||
"align_self": null,
|
||||
"height": null,
|
||||
"min_height": null,
|
||||
"padding": null,
|
||||
"grid_auto_rows": null,
|
||||
"grid_gap": null,
|
||||
"max_width": null,
|
||||
"order": null,
|
||||
"_view_module_version": "1.2.0",
|
||||
"grid_template_areas": null,
|
||||
"object_position": null,
|
||||
"object_fit": null,
|
||||
"grid_auto_columns": null,
|
||||
"margin": null,
|
||||
"display": null,
|
||||
"left": null
|
||||
}
|
||||
},
|
||||
"8ae3be32d9c845e59fdb1c47884d48aa": {
|
||||
"model_module": "@jupyter-widgets/controls",
|
||||
"model_name": "FloatProgressModel",
|
||||
"state": {
|
||||
"_view_name": "ProgressView",
|
||||
"style": "IPY_MODEL_1efb96d931a446de92f1930b973ae846",
|
||||
"_dom_classes": [],
|
||||
"description": "Downloading: 100%",
|
||||
"_model_name": "FloatProgressModel",
|
||||
"bar_style": "success",
|
||||
"max": 230,
|
||||
"_view_module": "@jupyter-widgets/controls",
|
||||
"_model_module_version": "1.5.0",
|
||||
"value": 230,
|
||||
"_view_count": null,
|
||||
"_view_module_version": "1.5.0",
|
||||
"orientation": "horizontal",
|
||||
"min": 0,
|
||||
"description_tooltip": null,
|
||||
"_model_module": "@jupyter-widgets/controls",
|
||||
"layout": "IPY_MODEL_6a4f5aab5ba949fd860b5a35bba7db9c"
|
||||
}
|
||||
},
|
||||
"4dea0031f3554752ad5aad01fe516a60": {
|
||||
"model_module": "@jupyter-widgets/controls",
|
||||
"model_name": "HTMLModel",
|
||||
"state": {
|
||||
"_view_name": "HTMLView",
|
||||
"style": "IPY_MODEL_4b02b2e964ad49af9f7ce7023131ceb8",
|
||||
"_dom_classes": [],
|
||||
"description": "",
|
||||
"_model_name": "HTMLModel",
|
||||
"placeholder": "",
|
||||
"_view_module": "@jupyter-widgets/controls",
|
||||
"_model_module_version": "1.5.0",
|
||||
"value": " 230/230 [00:00<00:00, 8.69kB/s]",
|
||||
"_view_count": null,
|
||||
"_view_module_version": "1.5.0",
|
||||
"description_tooltip": null,
|
||||
"_model_module": "@jupyter-widgets/controls",
|
||||
"layout": "IPY_MODEL_0ae8a68c3668401da8d8a6d5ec9cac8f"
|
||||
}
|
||||
},
|
||||
"1efb96d931a446de92f1930b973ae846": {
|
||||
"model_module": "@jupyter-widgets/controls",
|
||||
"model_name": "ProgressStyleModel",
|
||||
"state": {
|
||||
"_view_name": "StyleView",
|
||||
"_model_name": "ProgressStyleModel",
|
||||
"description_width": "initial",
|
||||
"_view_module": "@jupyter-widgets/base",
|
||||
"_model_module_version": "1.5.0",
|
||||
"_view_count": null,
|
||||
"_view_module_version": "1.2.0",
|
||||
"bar_color": null,
|
||||
"_model_module": "@jupyter-widgets/controls"
|
||||
}
|
||||
},
|
||||
"6a4f5aab5ba949fd860b5a35bba7db9c": {
|
||||
"model_module": "@jupyter-widgets/base",
|
||||
"model_name": "LayoutModel",
|
||||
"state": {
|
||||
"_view_name": "LayoutView",
|
||||
"grid_template_rows": null,
|
||||
"right": null,
|
||||
"justify_content": null,
|
||||
"_view_module": "@jupyter-widgets/base",
|
||||
"overflow": null,
|
||||
"_model_module_version": "1.2.0",
|
||||
"_view_count": null,
|
||||
"flex_flow": null,
|
||||
"width": null,
|
||||
"min_width": null,
|
||||
"border": null,
|
||||
"align_items": null,
|
||||
"bottom": null,
|
||||
"_model_module": "@jupyter-widgets/base",
|
||||
"top": null,
|
||||
"grid_column": null,
|
||||
"overflow_y": null,
|
||||
"overflow_x": null,
|
||||
"grid_auto_flow": null,
|
||||
"grid_area": null,
|
||||
"grid_template_columns": null,
|
||||
"flex": null,
|
||||
"_model_name": "LayoutModel",
|
||||
"justify_items": null,
|
||||
"grid_row": null,
|
||||
"max_height": null,
|
||||
"align_content": null,
|
||||
"visibility": null,
|
||||
"align_self": null,
|
||||
"height": null,
|
||||
"min_height": null,
|
||||
"padding": null,
|
||||
"grid_auto_rows": null,
|
||||
"grid_gap": null,
|
||||
"max_width": null,
|
||||
"order": null,
|
||||
"_view_module_version": "1.2.0",
|
||||
"grid_template_areas": null,
|
||||
"object_position": null,
|
||||
"object_fit": null,
|
||||
"grid_auto_columns": null,
|
||||
"margin": null,
|
||||
"display": null,
|
||||
"left": null
|
||||
}
|
||||
},
|
||||
"4b02b2e964ad49af9f7ce7023131ceb8": {
|
||||
"model_module": "@jupyter-widgets/controls",
|
||||
"model_name": "DescriptionStyleModel",
|
||||
"state": {
|
||||
"_view_name": "StyleView",
|
||||
"_model_name": "DescriptionStyleModel",
|
||||
"description_width": "",
|
||||
"_view_module": "@jupyter-widgets/base",
|
||||
"_model_module_version": "1.5.0",
|
||||
"_view_count": null,
|
||||
"_view_module_version": "1.2.0",
|
||||
"_model_module": "@jupyter-widgets/controls"
|
||||
}
|
||||
},
|
||||
"0ae8a68c3668401da8d8a6d5ec9cac8f": {
|
||||
"model_module": "@jupyter-widgets/base",
|
||||
"model_name": "LayoutModel",
|
||||
"state": {
|
||||
"_view_name": "LayoutView",
|
||||
"grid_template_rows": null,
|
||||
"right": null,
|
||||
"justify_content": null,
|
||||
"_view_module": "@jupyter-widgets/base",
|
||||
"overflow": null,
|
||||
"_model_module_version": "1.2.0",
|
||||
"_view_count": null,
|
||||
"flex_flow": null,
|
||||
"width": null,
|
||||
"min_width": null,
|
||||
"border": null,
|
||||
"align_items": null,
|
||||
"bottom": null,
|
||||
"_model_module": "@jupyter-widgets/base",
|
||||
"top": null,
|
||||
"grid_column": null,
|
||||
"overflow_y": null,
|
||||
"overflow_x": null,
|
||||
"grid_auto_flow": null,
|
||||
"grid_area": null,
|
||||
"grid_template_columns": null,
|
||||
"flex": null,
|
||||
"_model_name": "LayoutModel",
|
||||
"justify_items": null,
|
||||
"grid_row": null,
|
||||
"max_height": null,
|
||||
"align_content": null,
|
||||
"visibility": null,
|
||||
"align_self": null,
|
||||
"height": null,
|
||||
"min_height": null,
|
||||
"padding": null,
|
||||
"grid_auto_rows": null,
|
||||
"grid_gap": null,
|
||||
"max_width": null,
|
||||
"order": null,
|
||||
"_view_module_version": "1.2.0",
|
||||
"grid_template_areas": null,
|
||||
"object_position": null,
|
||||
"object_fit": null,
|
||||
"grid_auto_columns": null,
|
||||
"margin": null,
|
||||
"display": null,
|
||||
"left": null
|
||||
}
|
||||
},
|
||||
"fd44cf6ab17e4b768b2e1d5cb8ce5af9": {
|
||||
"model_module": "@jupyter-widgets/controls",
|
||||
"model_name": "HBoxModel",
|
||||
@@ -2105,6 +2351,16 @@
|
||||
}
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "view-in-github",
|
||||
"colab_type": "text"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/huggingface/transformers/blob/generation_pipeline_docs/notebooks/03-pipelines.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -2170,13 +2426,29 @@
|
||||
},
|
||||
"id": "4maAknWNrl_N",
|
||||
"colab_type": "code",
|
||||
"colab": {}
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 102
|
||||
},
|
||||
"outputId": "467e3cc8-a069-47da-8029-86e4142c7dde"
|
||||
},
|
||||
"source": [
|
||||
"!pip install -q transformers"
|
||||
],
|
||||
"execution_count": 0,
|
||||
"outputs": []
|
||||
"execution_count": 2,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\u001b[K |████████████████████████████████| 645kB 4.4MB/s \n",
|
||||
"\u001b[K |████████████████████████████████| 3.8MB 11.7MB/s \n",
|
||||
"\u001b[K |████████████████████████████████| 890kB 51.5MB/s \n",
|
||||
"\u001b[K |████████████████████████████████| 1.0MB 46.0MB/s \n",
|
||||
"\u001b[?25h Building wheel for sacremoses (setup.py) ... \u001b[?25l\u001b[?25hdone\n"
|
||||
],
|
||||
"name": "stdout"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -2219,6 +2491,7 @@
|
||||
},
|
||||
"id": "AMRXHQw9rl_d",
|
||||
"colab_type": "code",
|
||||
"outputId": "a7a10851-b71e-4553-9afc-04066120410d",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 83,
|
||||
@@ -2232,14 +2505,13 @@
|
||||
"ad84da685cf44abb90d17d9d2e023b48",
|
||||
"a246f9eea2d7440cb979e728741d2e32"
|
||||
]
|
||||
},
|
||||
"outputId": "a7a10851-b71e-4553-9afc-04066120410d"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"nlp_sentence_classif = pipeline('sentiment-analysis')\n",
|
||||
"nlp_sentence_classif('Such a nice weather outside !')"
|
||||
],
|
||||
"execution_count": 3,
|
||||
"execution_count": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "display_data",
|
||||
@@ -2300,6 +2572,7 @@
|
||||
},
|
||||
"id": "B3BDRX_Krl_n",
|
||||
"colab_type": "code",
|
||||
"outputId": "a6b90b11-a272-4ecb-960d-4c682551b399",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 185,
|
||||
@@ -2313,14 +2586,13 @@
|
||||
"405afa5bb8b840d8bc0850e02f593ce4",
|
||||
"78c718e3d5fa4cb892217260bea6d540"
|
||||
]
|
||||
},
|
||||
"outputId": "a6b90b11-a272-4ecb-960d-4c682551b399"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"nlp_token_class = pipeline('ner')\n",
|
||||
"nlp_token_class('Hugging Face is a French company based in New-York.')"
|
||||
],
|
||||
"execution_count": 4,
|
||||
"execution_count": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "display_data",
|
||||
@@ -2384,6 +2656,7 @@
|
||||
},
|
||||
"id": "ND_8LzQKrl_u",
|
||||
"colab_type": "code",
|
||||
"outputId": "c59ae695-c465-4de6-fa6e-181d8f1a3992",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 117,
|
||||
@@ -2397,14 +2670,13 @@
|
||||
"cd64e3f20b23483daa79712bde6622ea",
|
||||
"67cbaa1f55d24e62ad6b022af36bca56"
|
||||
]
|
||||
},
|
||||
"outputId": "c59ae695-c465-4de6-fa6e-181d8f1a3992"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"nlp_qa = pipeline('question-answering')\n",
|
||||
"nlp_qa(context='Hugging Face is a French company based in New-York.', question='Where is based Hugging Face ?')"
|
||||
],
|
||||
"execution_count": 5,
|
||||
"execution_count": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "display_data",
|
||||
@@ -2470,6 +2742,7 @@
|
||||
},
|
||||
"id": "zpJQ2HXNrl_4",
|
||||
"colab_type": "code",
|
||||
"outputId": "3fb62e7a-25a6-4b06-ced8-51eb8aa6bf33",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 321,
|
||||
@@ -2483,14 +2756,13 @@
|
||||
"a35703cc8ff44e93a8c0eb413caddc40",
|
||||
"9df7014c99b343f3b178fa020ff56010"
|
||||
]
|
||||
},
|
||||
"outputId": "3fb62e7a-25a6-4b06-ced8-51eb8aa6bf33"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"nlp_fill = pipeline('fill-mask')\n",
|
||||
"nlp_fill('Hugging Face is a French company based in ' + nlp_fill.tokenizer.mask_token)"
|
||||
],
|
||||
"execution_count": 6,
|
||||
"execution_count": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "display_data",
|
||||
@@ -2560,11 +2832,11 @@
|
||||
"metadata": {
|
||||
"id": "8BaOgzi1u1Yc",
|
||||
"colab_type": "code",
|
||||
"outputId": "2168e437-cfba-4247-a38c-07f02f555c6e",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 88
|
||||
},
|
||||
"outputId": "2168e437-cfba-4247-a38c-07f02f555c6e"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"TEXT_TO_SUMMARIZE = \"\"\" \n",
|
||||
@@ -2590,7 +2862,7 @@
|
||||
"summarizer = pipeline('summarization')\n",
|
||||
"summarizer(TEXT_TO_SUMMARIZE)"
|
||||
],
|
||||
"execution_count": 7,
|
||||
"execution_count": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -2631,6 +2903,7 @@
|
||||
"metadata": {
|
||||
"id": "8FwayP4nwV3Z",
|
||||
"colab_type": "code",
|
||||
"outputId": "66956816-c924-4718-fe58-cabef7d51974",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 83,
|
||||
@@ -2644,15 +2917,14 @@
|
||||
"ad78042ee71a41fd989e4b4ce9d2e3c1",
|
||||
"40c8d2617f3d4c84b923b140456fa5da"
|
||||
]
|
||||
},
|
||||
"outputId": "66956816-c924-4718-fe58-cabef7d51974"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"# English to French\n",
|
||||
"translator = pipeline('translation_en_to_fr')\n",
|
||||
"translator(\"HuggingFace is a French company that is based in New York City. HuggingFace's mission is to solve NLP one commit at a time\")"
|
||||
],
|
||||
"execution_count": 8,
|
||||
"execution_count": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "display_data",
|
||||
@@ -2696,6 +2968,7 @@
|
||||
"metadata": {
|
||||
"colab_type": "code",
|
||||
"id": "ra0-WfznwoIW",
|
||||
"outputId": "278a3d5f-cc42-40bc-a9db-c92ec5a3a2f0",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 83,
|
||||
@@ -2709,15 +2982,14 @@
|
||||
"4486f8a2efc34b9aab3864eb5ad2ba48",
|
||||
"d6228324f3444aa6bd1323d65ae4ff75"
|
||||
]
|
||||
},
|
||||
"outputId": "278a3d5f-cc42-40bc-a9db-c92ec5a3a2f0"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"# English to German\n",
|
||||
"translator = pipeline('translation_en_to_de')\n",
|
||||
"translator(\"The history of natural language processing (NLP) generally started in the 1950s, although work can be found from earlier periods.\")"
|
||||
],
|
||||
"execution_count": 9,
|
||||
"execution_count": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "display_data",
|
||||
@@ -2756,6 +3028,89 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "qPUpg0M8hCtB",
|
||||
"colab_type": "text"
|
||||
},
|
||||
"source": [
|
||||
"## 7. Text Generation\n",
|
||||
"\n",
|
||||
"Text generation is currently supported by GPT-2, OpenAi-GPT, TransfoXL, XLNet, CTRL and Reformer."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "5pKfxTxohXuZ",
|
||||
"colab_type": "code",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 120,
|
||||
"referenced_widgets": [
|
||||
"3c86415352574190b71e1fe5a15d36f1",
|
||||
"dd2c9dd935754cf2802233053554c21c",
|
||||
"8ae3be32d9c845e59fdb1c47884d48aa",
|
||||
"4dea0031f3554752ad5aad01fe516a60",
|
||||
"1efb96d931a446de92f1930b973ae846",
|
||||
"6a4f5aab5ba949fd860b5a35bba7db9c",
|
||||
"4b02b2e964ad49af9f7ce7023131ceb8",
|
||||
"0ae8a68c3668401da8d8a6d5ec9cac8f"
|
||||
]
|
||||
},
|
||||
"outputId": "8705f6b4-2413-4ac6-f72d-e5ecce160662"
|
||||
},
|
||||
"source": [
|
||||
"text_generator = pipeline(\"text-generation\")\n",
|
||||
"text_generator(\"Today is a beautiful day and I will\")"
|
||||
],
|
||||
"execution_count": 5,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "display_data",
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "3c86415352574190b71e1fe5a15d36f1",
|
||||
"version_minor": 0,
|
||||
"version_major": 2
|
||||
},
|
||||
"text/plain": [
|
||||
"HBox(children=(FloatProgress(value=0.0, description='Downloading', max=230.0, style=ProgressStyle(description_…"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"tags": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n"
|
||||
],
|
||||
"name": "stdout"
|
||||
},
|
||||
{
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Setting `pad_token_id` to 50256 (first `eos_token_id`) to generate sequence\n"
|
||||
],
|
||||
"name": "stderr"
|
||||
},
|
||||
{
|
||||
"output_type": "execute_result",
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[{'generated_text': 'Today is a beautiful day and I will celebrate my birthday!\"\\n\\nThe mother told CNN the two had planned their meal together. After dinner, she added that she and I walked down the street and stopped at a diner near her home. \"He'}]"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"execution_count": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -2763,7 +3118,7 @@
|
||||
"colab_type": "text"
|
||||
},
|
||||
"source": [
|
||||
"## 7. Projection - Features Extraction "
|
||||
"## 8. Projection - Features Extraction "
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2775,6 +3130,7 @@
|
||||
},
|
||||
"id": "O4SjR1QQrl__",
|
||||
"colab_type": "code",
|
||||
"outputId": "2ce966d5-7a89-4488-d48f-626d1c2a8222",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 83,
|
||||
@@ -2788,8 +3144,7 @@
|
||||
"31d97ecf78fa412c99e6659196d82828",
|
||||
"c6be5d48ec3c4c799d1445607e5f1ac6"
|
||||
]
|
||||
},
|
||||
"outputId": "2ce966d5-7a89-4488-d48f-626d1c2a8222"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
@@ -2797,7 +3152,7 @@
|
||||
"output = nlp_features('Hugging Face is a French company based in Paris')\n",
|
||||
"np.array(output).shape # (Samples, Tokens, Vector Size)\n"
|
||||
],
|
||||
"execution_count": 10,
|
||||
"execution_count": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "display_data",
|
||||
@@ -2861,6 +3216,7 @@
|
||||
},
|
||||
"id": "yFlBPQHtrmAH",
|
||||
"colab_type": "code",
|
||||
"outputId": "03cc3207-a7e8-49fd-904a-63a7a1d0eb7a",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 116,
|
||||
@@ -2872,8 +3228,7 @@
|
||||
"62b10ca525cc4ac68f3a006434eb7416",
|
||||
"211109537fbe4e60b89a238c89db1346"
|
||||
]
|
||||
},
|
||||
"outputId": "03cc3207-a7e8-49fd-904a-63a7a1d0eb7a"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"task = widgets.Dropdown(\n",
|
||||
@@ -2906,7 +3261,7 @@
|
||||
"input.on_submit(forward)\n",
|
||||
"display(task, input)"
|
||||
],
|
||||
"execution_count": 11,
|
||||
"execution_count": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "display_data",
|
||||
@@ -2958,6 +3313,7 @@
|
||||
},
|
||||
"id": "GCoKbBTYrmAN",
|
||||
"colab_type": "code",
|
||||
"outputId": "57c3a647-160a-4b3a-e852-e7a1daf1294a",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 143,
|
||||
@@ -2969,8 +3325,7 @@
|
||||
"d305ba1662e3466c93ab5cca7ebf8f33",
|
||||
"879f7a3747ad455d810c7a29918648ee"
|
||||
]
|
||||
},
|
||||
"outputId": "57c3a647-160a-4b3a-e852-e7a1daf1294a"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"context = widgets.Textarea(\n",
|
||||
@@ -2995,7 +3350,7 @@
|
||||
"query.on_submit(forward)\n",
|
||||
"display(context, query)"
|
||||
],
|
||||
"execution_count": 12,
|
||||
"execution_count": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "display_data",
|
||||
|
||||
File diff suppressed because one or more lines are too long
+2
-1
@@ -10,9 +10,10 @@ Pull Request and we'll review it so it can be included here.
|
||||
## Hugging Face's notebooks :hugs:
|
||||
|
||||
| Notebook | Description | |
|
||||
|:----------|:-------------:|------:|
|
||||
|:----------|:-------------|------:|
|
||||
| [Getting Started Tokenizers](https://github.com/huggingface/transformers/blob/master/notebooks/01-training-tokenizers.ipynb) | How to train and use your very own tokenizer |[](https://colab.research.google.com/github/huggingface/transformers/blob/master/notebooks/01-training-tokenizers.ipynb) |
|
||||
| [Getting Started Transformers](https://github.com/huggingface/transformers/blob/master/notebooks/02-transformers.ipynb) | How to easily start using transformers | [](https://colab.research.google.com/github/huggingface/transformers/blob/master/notebooks/02-transformers.ipynb) |
|
||||
| [How to use Pipelines](https://github.com/huggingface/transformers/blob/master/notebooks/03-pipelines.ipynb) | Simple and efficient way to use State-of-the-Art models on downstream tasks through transformers | [](https://colab.research.google.com/github/huggingface/transformers/blob/master/notebooks/03-pipelines.ipynb) |
|
||||
| [How to train a language model](https://github.com/huggingface/blog/blob/master/notebooks/01_how_to_train.ipynb)| Highlight all the steps to effectively train Transformer model on custom data | [](https://colab.research.google.com/github/huggingface/blog/blob/master/notebooks/01_how_to_train.ipynb)|
|
||||
| [How to generate text](https://github.com/huggingface/blog/blob/master/notebooks/02_how_to_generate.ipynb)| How to use different decoding methods for language generation with transformers | [](https://colab.research.google.com/github/huggingface/blog/blob/master/notebooks/02_how_to_generate.ipynb)|
|
||||
| [How to export model to ONNX](https://github.com/huggingface/transformers/blob/master/notebooks/04-onnx-export.ipynb) | Highlight how to export and run inference workloads through ONNX |
|
||||
@@ -36,5 +36,5 @@ multi_line_output = 3
|
||||
use_parentheses = True
|
||||
|
||||
[flake8]
|
||||
ignore = E203, E501, W503
|
||||
ignore = E203, E501, E741, W503
|
||||
max-line-length = 119
|
||||
|
||||
@@ -67,8 +67,18 @@ extras = {}
|
||||
|
||||
extras["mecab"] = ["mecab-python3"]
|
||||
extras["sklearn"] = ["scikit-learn"]
|
||||
extras["tf"] = ["tensorflow <= 2.1"]
|
||||
extras["tf-cpu"] = ["tensorflow-cpu <= 2.1"]
|
||||
|
||||
# keras2onnx and onnxconverter-common version is specific through a commit until 1.7.0 lands on pypi
|
||||
extras["tf"] = [
|
||||
"tensorflow",
|
||||
"onnxconverter-common @ git+git://github.com/microsoft/onnxconverter-common.git@f64ca15989b6dc95a1f3507ff6e4c395ba12dff5#egg=onnxconverter-common",
|
||||
"keras2onnx @ git+git://github.com/onnx/keras-onnx.git@cbdc75cb950b16db7f0a67be96a278f8d2953b48#egg=keras2onnx"
|
||||
]
|
||||
extras["tf-cpu"] = [
|
||||
"tensorflow-cpu",
|
||||
"onnxconverter-common @ git+git://github.com/microsoft/onnxconverter-common.git@f64ca15989b6dc95a1f3507ff6e4c395ba12dff5#egg=onnxconverter-common",
|
||||
"keras2onnx @ git+git://github.com/onnx/keras-onnx.git@cbdc75cb950b16db7f0a67be96a278f8d2953b48#egg=keras2onnx"
|
||||
]
|
||||
extras["torch"] = ["torch"]
|
||||
|
||||
extras["serving"] = ["pydantic", "uvicorn", "fastapi", "starlette"]
|
||||
@@ -79,13 +89,13 @@ extras["docs"] = ["recommonmark", "sphinx", "sphinx-markdown-tables", "sphinx-rt
|
||||
extras["quality"] = [
|
||||
"black",
|
||||
"isort @ git+git://github.com/timothycrosley/isort.git@e63ae06ec7d70b06df9e528357650281a3d3ec22#egg=isort",
|
||||
"flake8==3.7.9",
|
||||
"flake8",
|
||||
]
|
||||
extras["dev"] = extras["testing"] + extras["quality"] + ["mecab-python3", "scikit-learn", "tensorflow <= 2.1", "torch"]
|
||||
extras["dev"] = extras["testing"] + extras["quality"] + ["mecab-python3", "scikit-learn", "tensorflow", "torch"]
|
||||
|
||||
setup(
|
||||
name="transformers",
|
||||
version="2.9.0",
|
||||
version="2.9.1",
|
||||
author="Thomas Wolf, Lysandre Debut, Victor Sanh, Julien Chaumond, Sam Shleifer, Google AI Language Team Authors, Open AI team Authors, Facebook AI Authors, Carnegie Mellon University Authors",
|
||||
author_email="thomas@huggingface.co",
|
||||
description="State-of-the-art Natural Language Processing for TensorFlow 2.0 and PyTorch",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# There's no way to ignore "F401 '...' imported but unused" warnings in this
|
||||
# module, but to preserve other warnings. So, don't check this module at all.
|
||||
|
||||
__version__ = "2.9.0"
|
||||
__version__ = "2.9.1"
|
||||
|
||||
# Work around to update TensorFlow's absl.logging threshold which alters the
|
||||
# default Python logging output behavior when present.
|
||||
@@ -359,6 +359,7 @@ if is_tf_available():
|
||||
from .modeling_tf_auto import (
|
||||
TFAutoModel,
|
||||
TFAutoModelForPreTraining,
|
||||
TFAutoModelForMultipleChoice,
|
||||
TFAutoModelForSequenceClassification,
|
||||
TFAutoModelForQuestionAnswering,
|
||||
TFAutoModelWithLMHead,
|
||||
@@ -493,6 +494,7 @@ if is_tf_available():
|
||||
TFAlbertModel,
|
||||
TFAlbertForPreTraining,
|
||||
TFAlbertForMaskedLM,
|
||||
TFAlbertForMultipleChoice,
|
||||
TFAlbertForSequenceClassification,
|
||||
TFAlbertForQuestionAnswering,
|
||||
TF_ALBERT_PRETRAINED_MODEL_ARCHIVE_MAP,
|
||||
|
||||
@@ -26,7 +26,8 @@ def gelu_new(x):
|
||||
""" Implementation of the gelu activation function currently in Google Bert repo (identical to OpenAI GPT).
|
||||
Also see https://arxiv.org/abs/1606.08415
|
||||
"""
|
||||
return 0.5 * x * (1.0 + torch.tanh(math.sqrt(2.0 / math.pi) * (x + 0.044715 * torch.pow(x, 3.0))))
|
||||
# math.sqrt(2.0 / math.pi) = 0.7978845608
|
||||
return 0.5 * x * (1.0 + torch.tanh(0.7978845608 * (x + 0.044715 * torch.pow(x, 3.0))))
|
||||
|
||||
|
||||
if torch.__version__ < "1.4.0":
|
||||
@@ -53,4 +54,4 @@ def get_activation(activation_string):
|
||||
if activation_string in ACT2FN:
|
||||
return ACT2FN[activation_string]
|
||||
else:
|
||||
raise KeyError("function {} not found in ACT2FN mapping {}".format(activation_string, list(ACT2FN.keys())))
|
||||
raise KeyError("function {} not found in ACT2FN mapping {}".format(activation_string, list(ACT2FN.keys())))
|
||||
@@ -68,6 +68,6 @@ class RobertaConfig(BertConfig):
|
||||
model_type = "roberta"
|
||||
|
||||
def __init__(self, pad_token_id=1, bos_token_id=0, eos_token_id=2, **kwargs):
|
||||
"""Constructs FlaubertConfig.
|
||||
"""Constructs RobertaConfig.
|
||||
"""
|
||||
super().__init__(pad_token_id=pad_token_id, bos_token_id=bos_token_id, eos_token_id=eos_token_id, **kwargs)
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
from argparse import ArgumentParser
|
||||
from itertools import takewhile
|
||||
from os import listdir, makedirs
|
||||
from os.path import abspath, dirname, exists
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from transformers import is_tf_available, is_torch_available
|
||||
from transformers.pipelines import Pipeline, pipeline
|
||||
from transformers.tokenization_utils import BatchEncoding
|
||||
|
||||
|
||||
class OnnxConverterArgumentParser(ArgumentParser):
|
||||
"""
|
||||
Wraps all the script arguments supported to export transformers models to ONNX IR
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(OnnxConverterArgumentParser, self).__init__("ONNX Converter")
|
||||
|
||||
self.add_argument("--model", type=str, required=True, help="Model's id or path (ex: bert-base-cased)")
|
||||
self.add_argument("--tokenizer", type=str, help="Tokenizer's id or path (ex: bert-base-cased)")
|
||||
self.add_argument("--framework", type=str, choices=["pt", "tf"], help="Framework for loading the model")
|
||||
self.add_argument("--opset", type=int, default=11, help="ONNX opset to use")
|
||||
self.add_argument("--check-loading", action="store_true", help="Check ONNX is able to load the model")
|
||||
self.add_argument("output")
|
||||
|
||||
|
||||
def ensure_valid_input(model, tokens, input_names):
|
||||
"""
|
||||
Ensure input are presented in the correct order, without any None
|
||||
Args:
|
||||
model: The model used to forward the input data
|
||||
tokens: BatchEncoding holding the input data
|
||||
input_names: The name of the inputs
|
||||
|
||||
Returns: Tuple
|
||||
|
||||
"""
|
||||
model_args_name = model.forward.__code__.co_varnames
|
||||
model_args_pos = [(model_args_name.index(name) - 1, name) for name in input_names]
|
||||
model_args = [None] * (max(map(lambda x: x[0], model_args_pos)) + 1)
|
||||
|
||||
for arg_pos, arg_name in model_args_pos:
|
||||
model_args[arg_pos] = tokens[arg_name]
|
||||
|
||||
model_args = tuple(model_args) # Need to be ordered
|
||||
return tuple(takewhile(lambda arg: arg is not None, model_args))
|
||||
|
||||
|
||||
def infer_shapes(nlp: Pipeline, framework: str) -> Tuple[List[str], List[str], Dict, BatchEncoding]:
|
||||
def build_shape_dict(tensor, is_input: bool, seq_len: int):
|
||||
if isinstance(tensor, (tuple, list)):
|
||||
return [build_shape_dict(t, is_input, seq_len) for t in tensor]
|
||||
|
||||
else:
|
||||
# Let's assume batch is the first axis with only 1 element (~~ might not be always true ...)
|
||||
axes = {[axis for axis, numel in enumerate(tensor.shape) if numel == 1][0]: "batch"}
|
||||
if is_input:
|
||||
if len(tensor.shape) == 2:
|
||||
axes[1] = "sequence"
|
||||
else:
|
||||
raise ValueError("Unable to infer tensor axes ({})".format(len(tensor.shape)))
|
||||
else:
|
||||
seq_axes = [dim for dim, shape in enumerate(tensor.shape) if shape == seq_len]
|
||||
axes.update({dim: "sequence" for dim in seq_axes})
|
||||
|
||||
return axes
|
||||
|
||||
tokens = nlp.tokenizer.encode_plus("This is a sample output", return_tensors=framework)
|
||||
seq_len = tokens.input_ids.shape[-1]
|
||||
outputs = nlp.model(**tokens) if framework == "pt" else nlp.model(tokens)
|
||||
|
||||
if not isinstance(outputs, (list, tuple)):
|
||||
outputs = (outputs,)
|
||||
|
||||
# Generate input names & axes
|
||||
input_vars = list(tokens.keys())
|
||||
input_dynamic_axes = {k: build_shape_dict(v, True, seq_len) for k, v in tokens.items()}
|
||||
|
||||
# flatten potentially grouped outputs (past for gpt2, attentions)
|
||||
outputs_flat = []
|
||||
for output in outputs:
|
||||
if isinstance(output, (tuple, list)):
|
||||
outputs_flat.extend(output)
|
||||
else:
|
||||
outputs_flat.append(output)
|
||||
|
||||
# Generate output names & axes
|
||||
output_names = ["output_{}".format(i) for i in range(len(outputs_flat))]
|
||||
output_dynamic_axes = {k: build_shape_dict(v, False, seq_len) for k, v in zip(output_names, outputs_flat)}
|
||||
|
||||
# Create the aggregated axes representation
|
||||
dynamic_axes = dict(input_dynamic_axes, **output_dynamic_axes)
|
||||
return input_vars, output_names, dynamic_axes, tokens
|
||||
|
||||
|
||||
def load_graph_from_args(framework: str, model: str, tokenizer: Optional[str] = None) -> Pipeline:
|
||||
# If no tokenizer provided
|
||||
if tokenizer is None:
|
||||
tokenizer = model
|
||||
|
||||
print("Loading pipeline (model: {}, tokenizer: {})".format(model, tokenizer))
|
||||
|
||||
# Allocate tokenizer and model
|
||||
return pipeline("feature-extraction", model=model, framework=framework)
|
||||
|
||||
|
||||
def convert_pytorch(nlp: Pipeline, opset: int, output: str):
|
||||
if not is_torch_available():
|
||||
raise Exception("Cannot convert because PyTorch is not installed. Please install torch first.")
|
||||
|
||||
import torch
|
||||
from torch.onnx import export
|
||||
|
||||
print("PyTorch: {}".format(torch.__version__))
|
||||
|
||||
with torch.no_grad():
|
||||
input_names, output_names, dynamic_axes, tokens = infer_shapes(nlp, "pt")
|
||||
model_args = ensure_valid_input(nlp.model, tokens, input_names)
|
||||
|
||||
export(
|
||||
nlp.model,
|
||||
model_args,
|
||||
f=output,
|
||||
input_names=input_names,
|
||||
output_names=output_names,
|
||||
dynamic_axes=dynamic_axes,
|
||||
do_constant_folding=True,
|
||||
use_external_data_format=True,
|
||||
enable_onnx_checker=True,
|
||||
opset_version=opset,
|
||||
)
|
||||
|
||||
|
||||
def convert_tensorflow(nlp: Pipeline, opset: int, output: str):
|
||||
if not is_tf_available():
|
||||
raise Exception(
|
||||
"Cannot convert {} because TF is not installed. Please install torch first.".format(args.model)
|
||||
)
|
||||
|
||||
print("/!\\ Please note TensorFlow doesn't support exporting model > 2Gb /!\\")
|
||||
|
||||
try:
|
||||
import tensorflow as tf
|
||||
from keras2onnx import convert_keras, save_model, __version__ as k2ov
|
||||
|
||||
print("TensorFlow: {}, keras2onnx: {}".format(tf.version.VERSION, k2ov))
|
||||
|
||||
# Build
|
||||
input_names, output_names, dynamic_axes, tokens = infer_shapes(nlp, "tf")
|
||||
|
||||
# Forward
|
||||
nlp.model.predict(tokens.data)
|
||||
onnx_model = convert_keras(nlp.model, nlp.model.name, target_opset=opset)
|
||||
save_model(onnx_model, output)
|
||||
|
||||
except ImportError as e:
|
||||
raise Exception(
|
||||
"Cannot import {} required to convert TF model to ONNX. Please install {} first.".format(e.name, e.name)
|
||||
)
|
||||
|
||||
|
||||
def convert(framework: str, model: str, output: str, opset: int, tokenizer: Optional[str] = None):
|
||||
print("ONNX opset version set to: {}".format(opset))
|
||||
|
||||
# Load the pipeline
|
||||
nlp = load_graph_from_args(framework, model, tokenizer)
|
||||
|
||||
parent = dirname(output)
|
||||
if not exists(parent):
|
||||
print("Creating folder {}".format(parent))
|
||||
makedirs(parent)
|
||||
elif len(listdir(parent)) > 0:
|
||||
raise Exception("Folder {} is not empty, aborting conversion".format(parent))
|
||||
|
||||
# Export the graph
|
||||
if framework == "pt":
|
||||
convert_pytorch(nlp, opset, output)
|
||||
else:
|
||||
convert_tensorflow(nlp, opset, output)
|
||||
|
||||
|
||||
def verify(path: str):
|
||||
from onnxruntime import InferenceSession, SessionOptions
|
||||
from onnxruntime.capi.onnxruntime_pybind11_state import RuntimeException
|
||||
|
||||
print("Checking ONNX model loading from: {}".format(path))
|
||||
try:
|
||||
onnx_options = SessionOptions()
|
||||
_ = InferenceSession(path, onnx_options, providers=["CPUExecutionProvider"])
|
||||
print("Model correctly loaded")
|
||||
except RuntimeException as re:
|
||||
print("Error while loading the model: {}".format(re))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = OnnxConverterArgumentParser()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Make sure output is absolute path
|
||||
args.output = abspath(args.output)
|
||||
|
||||
try:
|
||||
# Convert
|
||||
convert(args.framework, args.model, args.output, args.opset, args.tokenizer)
|
||||
|
||||
# And verify
|
||||
if args.check_loading:
|
||||
verify(args.output)
|
||||
except Exception as e:
|
||||
print("Error while converting the model: {}".format(e))
|
||||
exit(1)
|
||||
@@ -95,6 +95,97 @@ def find_model_file(dest_dir): # this one better
|
||||
return model_file
|
||||
|
||||
|
||||
# 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"
|
||||
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"),
|
||||
("de+nl+fy+af+da+fo+is+no+nb+nn+sv", "NORTH_EU"),
|
||||
("da+fo+is+no+nb+nn+sv", "SCANDINAVIA"),
|
||||
("se+sma+smj+smn+sms", "SAMI"),
|
||||
("nb_NO+nb+nn_NO+nn+nog+no_nb+no", "NORWAY"),
|
||||
("ga+cy+br+gd+kw+gv", "CELTIC"), # https://en.wikipedia.org/wiki/Insular_Celtic_languages
|
||||
]
|
||||
GROUP_TO_OPUS_NAME = {
|
||||
"opus-mt-ZH-de": "cmn+cn+yue+ze_zh+zh_cn+zh_CN+zh_HK+zh_tw+zh_TW+zh_yue+zhs+zht+zh-de",
|
||||
"opus-mt-ZH-fi": "cmn+cn+yue+ze_zh+zh_cn+zh_CN+zh_HK+zh_tw+zh_TW+zh_yue+zhs+zht+zh-fi",
|
||||
"opus-mt-ZH-sv": "cmn+cn+yue+ze_zh+zh_cn+zh_CN+zh_HK+zh_tw+zh_TW+zh_yue+zhs+zht+zh-sv",
|
||||
"opus-mt-SCANDINAVIA-SCANDINAVIA": "da+fo+is+no+nb+nn+sv-da+fo+is+no+nb+nn+sv",
|
||||
"opus-mt-NORTH_EU-NORTH_EU": "de+nl+fy+af+da+fo+is+no+nb+nn+sv-de+nl+fy+af+da+fo+is+no+nb+nn+sv",
|
||||
"opus-mt-de-ZH": "de-cmn+cn+yue+ze_zh+zh_cn+zh_CN+zh_HK+zh_tw+zh_TW+zh_yue+zhs+zht+zh",
|
||||
"opus-mt-en_el_es_fi-en_el_es_fi": "en+el+es+fi-en+el+es+fi",
|
||||
"opus-mt-en-ROMANCE": "en-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",
|
||||
"opus-mt-en-CELTIC": "en-ga+cy+br+gd+kw+gv",
|
||||
"opus-mt-es-NORWAY": "es-nb_NO+nb+nn_NO+nn+nog+no_nb+no",
|
||||
"opus-mt-fi_nb_no_nn_ru_sv_en-SAMI": "fi+nb+no+nn+ru+sv+en-se+sma+smj+smn+sms",
|
||||
"opus-mt-fi-ZH": "fi-cmn+cn+yue+ze_zh+zh_cn+zh_CN+zh_HK+zh_tw+zh_TW+zh_yue+zhs+zht+zh",
|
||||
"opus-mt-fi-NORWAY": "fi-nb_NO+nb+nn_NO+nn+nog+no_nb+no",
|
||||
"opus-mt-ROMANCE-en": "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-en",
|
||||
"opus-mt-CELTIC-en": "ga+cy+br+gd+kw+gv-en",
|
||||
"opus-mt-sv-ZH": "sv-cmn+cn+yue+ze_zh+zh_cn+zh_CN+zh_HK+zh_tw+zh_TW+zh_yue+zhs+zht+zh",
|
||||
"opus-mt-sv-NORWAY": "sv-nb_NO+nb+nn_NO+nn+nog+no_nb+no",
|
||||
}
|
||||
OPUS_GITHUB_URL = "https://github.com/Helsinki-NLP/OPUS-MT-train/blob/master/models/"
|
||||
ORG_NAME = "Helsinki-NLP/"
|
||||
|
||||
|
||||
def convert_opus_name_to_hf_name(x):
|
||||
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."""
|
||||
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]
|
||||
else:
|
||||
opus_w_prefix = hf_model_name.replace("_", "+")
|
||||
return remove_prefix(opus_w_prefix, "opus-mt-")
|
||||
|
||||
|
||||
def write_model_card(
|
||||
hf_model_name: str,
|
||||
repo_path="OPUS-MT-train/models/",
|
||||
dry_run=False,
|
||||
model_card_dir=Path("marian_converted/model_cards/Helsinki-NLP/"),
|
||||
) -> str:
|
||||
"""Copy the most recent model's readme section from opus, and add metadata.
|
||||
upload command: s3cmd sync --recursive model_card_dir s3://models.huggingface.co/bert/Helsinki-NLP/
|
||||
"""
|
||||
hf_model_name = remove_prefix(hf_model_name, ORG_NAME)
|
||||
opus_name: str = convert_hf_name_to_opus_name(hf_model_name)
|
||||
opus_src, opus_tgt = [x.split("+") for x in opus_name.split("-")]
|
||||
readme_url = OPUS_GITHUB_URL + f"{opus_name}/README.md"
|
||||
s, t = ",".join(opus_src), ",".join(opus_tgt)
|
||||
extra_markdown = f"### {hf_model_name}\n\n* source languages: {s}\n* target languages: {t}\n* OPUS readme: [{opus_name}]({readme_url})\n"
|
||||
# combine with opus markdown
|
||||
opus_readme_path = Path(f"{repo_path}{opus_name}/README.md")
|
||||
assert opus_readme_path.exists(), opus_readme_path
|
||||
content = opus_readme_path.open().read()
|
||||
content = content.split("\n# ")[-1] # Get the lowest level 1 header in the README -- the most recent model.
|
||||
content = "*".join(content.split("*")[1:])
|
||||
content = extra_markdown + "\n* " + content.replace("download", "download original weights")
|
||||
if dry_run:
|
||||
return content
|
||||
# Save string to model_cards/hf_model_name/readme.md
|
||||
model_card_dir.mkdir(exist_ok=True)
|
||||
sub_dir = model_card_dir / hf_model_name
|
||||
sub_dir.mkdir(exist_ok=True)
|
||||
dest = sub_dir / "README.md"
|
||||
dest.open("w").write(content)
|
||||
return content
|
||||
|
||||
|
||||
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 make_registry(repo_path="Opus-MT-train/models"):
|
||||
if not (Path(repo_path) / "fr-en" / "README.md").exists():
|
||||
raise ValueError(
|
||||
@@ -109,10 +200,7 @@ def make_registry(repo_path="Opus-MT-train/models"):
|
||||
else:
|
||||
lns = list(open(p / "README.md").readlines())
|
||||
results[p.name] = _parse_readme(lns)
|
||||
return [(k, v["pre-processing"], v["download"]) for k, v in results.items()]
|
||||
|
||||
|
||||
CH_GROUP = "cmn+cn+yue+ze_zh+zh_cn+zh_CN+zh_HK+zh_tw+zh_TW+zh_yue+zhs+zht+zh"
|
||||
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):
|
||||
@@ -122,12 +210,12 @@ def convert_all_sentencepiece_models(model_list=None, repo_path=None):
|
||||
dest_dir.mkdir(exist_ok=True)
|
||||
if model_list is None:
|
||||
model_list: list = make_registry(repo_path=repo_path)
|
||||
for k, prepro, download in tqdm(model_list):
|
||||
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"):
|
||||
download_and_unzip(download, save_dir / k)
|
||||
pair_name = k.replace(CH_GROUP, "ch_group")
|
||||
pair_name = convert_opus_name_to_hf_name(k)
|
||||
convert(save_dir / k, dest_dir / f"opus-mt-{pair_name}")
|
||||
|
||||
|
||||
@@ -135,12 +223,10 @@ def lmap(f, x) -> List:
|
||||
return list(map(f, x))
|
||||
|
||||
|
||||
def fetch_test_set(readmes_raw, pair):
|
||||
def fetch_test_set(test_set_url):
|
||||
import wget
|
||||
|
||||
download_url = readmes_raw[pair]["download"]
|
||||
test_set_url = download_url[:-4] + ".test.txt"
|
||||
fname = wget.download(test_set_url, f"opus_test_{pair}.txt")
|
||||
fname = wget.download(test_set_url, "opus_test.txt")
|
||||
lns = Path(fname).open().readlines()
|
||||
src = lmap(str.strip, lns[::4])
|
||||
gold = lmap(str.strip, lns[1::4])
|
||||
|
||||
@@ -114,7 +114,7 @@ class GlueDataset(Dataset):
|
||||
torch.save(self.features, cached_features_file)
|
||||
# ^ This seems to take a lot of time so I want to investigate why and how we can improve.
|
||||
logger.info(
|
||||
f"Saving features into cached file %s [took %.3f s]", cached_features_file, time.time() - start
|
||||
"Saving features into cached file %s [took %.3f s]", cached_features_file, time.time() - start
|
||||
)
|
||||
|
||||
def __len__(self):
|
||||
|
||||
@@ -4,10 +4,10 @@ import pickle
|
||||
import time
|
||||
|
||||
import torch
|
||||
from filelock import FileLock
|
||||
from torch.utils.data.dataset import Dataset
|
||||
|
||||
from ...tokenization_utils import PreTrainedTokenizer
|
||||
from ...trainer import torch_distributed_zero_first
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -20,7 +20,7 @@ class TextDataset(Dataset):
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, tokenizer: PreTrainedTokenizer, file_path: str, block_size: int, overwrite_cache=False, local_rank=-1,
|
||||
self, tokenizer: PreTrainedTokenizer, file_path: str, block_size: int, overwrite_cache=False,
|
||||
):
|
||||
assert os.path.isfile(file_path)
|
||||
|
||||
@@ -31,9 +31,10 @@ class TextDataset(Dataset):
|
||||
directory, "cached_lm_{}_{}_{}".format(tokenizer.__class__.__name__, str(block_size), filename,),
|
||||
)
|
||||
|
||||
with torch_distributed_zero_first(local_rank):
|
||||
# Make sure only the first process in distributed training processes the dataset,
|
||||
# and the others will use the cache.
|
||||
# Make sure only the first process in distributed training processes the dataset,
|
||||
# and the others will use the cache.
|
||||
lock_path = cached_features_file + ".lock"
|
||||
with FileLock(lock_path):
|
||||
|
||||
if os.path.exists(cached_features_file) and not overwrite_cache:
|
||||
start = time.time()
|
||||
@@ -64,7 +65,7 @@ class TextDataset(Dataset):
|
||||
with open(cached_features_file, "wb") as handle:
|
||||
pickle.dump(self.examples, handle, protocol=pickle.HIGHEST_PROTOCOL)
|
||||
logger.info(
|
||||
f"Saving features into cached file %s [took %.3f s]", cached_features_file, time.time() - start
|
||||
"Saving features into cached file %s [took %.3f s]", cached_features_file, time.time() - start
|
||||
)
|
||||
|
||||
def __len__(self):
|
||||
@@ -80,7 +81,7 @@ class LineByLineTextDataset(Dataset):
|
||||
soon.
|
||||
"""
|
||||
|
||||
def __init__(self, tokenizer: PreTrainedTokenizer, file_path: str, block_size: int, local_rank=-1):
|
||||
def __init__(self, tokenizer: PreTrainedTokenizer, file_path: str, block_size: int):
|
||||
assert os.path.isfile(file_path)
|
||||
# Here, we do not cache the features, operating under the assumption
|
||||
# that we will soon use fast multithreaded tokenizers from the
|
||||
|
||||
@@ -195,18 +195,22 @@ def squad_convert_example_to_features(example, max_seq_length, doc_stride, max_q
|
||||
cls_index = span["input_ids"].index(tokenizer.cls_token_id)
|
||||
|
||||
# p_mask: mask with 1 for token than cannot be in the answer (0 for token which can be in an answer)
|
||||
# Original TF implem also keep the classification token (set to 0) (not sure why...)
|
||||
p_mask = np.array(span["token_type_ids"])
|
||||
|
||||
p_mask = np.minimum(p_mask, 1)
|
||||
|
||||
# Original TF implem also keep the classification token (set to 0)
|
||||
p_mask = np.ones_like(span["token_type_ids"])
|
||||
if tokenizer.padding_side == "right":
|
||||
# Limit positive values to one
|
||||
p_mask = 1 - p_mask
|
||||
p_mask[len(truncated_query) + sequence_added_tokens :] = 0
|
||||
else:
|
||||
p_mask[-len(span["tokens"]) : -(len(truncated_query) + sequence_added_tokens)] = 0
|
||||
|
||||
p_mask[np.where(np.array(span["input_ids"]) == tokenizer.sep_token_id)[0]] = 1
|
||||
pad_token_indices = np.where(span["input_ids"] == tokenizer.pad_token_id)
|
||||
special_token_indices = np.asarray(
|
||||
tokenizer.get_special_tokens_mask(span["input_ids"], already_has_special_tokens=True)
|
||||
).nonzero()
|
||||
|
||||
# Set the CLS index to '0'
|
||||
p_mask[pad_token_indices] = 1
|
||||
p_mask[special_token_indices] = 1
|
||||
|
||||
# Set the cls index to 0: the CLS index can be used for impossible answers
|
||||
p_mask[cls_index] = 0
|
||||
|
||||
span_is_impossible = example.is_impossible
|
||||
|
||||
@@ -175,7 +175,7 @@ class AlbertEmbeddings(BertEmbeddings):
|
||||
def __init__(self, config):
|
||||
super().__init__(config)
|
||||
|
||||
self.word_embeddings = nn.Embedding(config.vocab_size, config.embedding_size, padding_idx=0)
|
||||
self.word_embeddings = nn.Embedding(config.vocab_size, config.embedding_size, padding_idx=config.pad_token_id)
|
||||
self.position_embeddings = nn.Embedding(config.max_position_embeddings, config.embedding_size)
|
||||
self.token_type_embeddings = nn.Embedding(config.type_vocab_size, config.embedding_size)
|
||||
self.LayerNorm = torch.nn.LayerNorm(config.embedding_size, eps=config.layer_norm_eps)
|
||||
|
||||
@@ -886,7 +886,7 @@ class BartForConditionalGeneration(PretrainedBartModel):
|
||||
if new_num_tokens <= old_num_tokens:
|
||||
new_bias = self.final_logits_bias[:, :new_num_tokens]
|
||||
else:
|
||||
extra_bias = torch.zeros((1, new_num_tokens - old_num_tokens))
|
||||
extra_bias = torch.zeros((1, new_num_tokens - old_num_tokens), device=self.final_logits_bias.device)
|
||||
new_bias = torch.cat([self.final_logits_bias, extra_bias], dim=1)
|
||||
self.register_buffer("final_logits_bias", new_bias)
|
||||
|
||||
@@ -980,12 +980,12 @@ class BartForConditionalGeneration(PretrainedBartModel):
|
||||
"use_cache": use_cache, # change this to avoid caching (presumably for debugging)
|
||||
}
|
||||
|
||||
def prepare_scores_for_generation(self, scores, cur_len, max_length):
|
||||
def prepare_logits_for_generation(self, logits, cur_len, max_length):
|
||||
if cur_len == 1:
|
||||
self._force_token_ids_generation(scores, self.config.bos_token_id)
|
||||
self._force_token_ids_generation(logits, self.config.bos_token_id)
|
||||
if cur_len == max_length - 1 and self.config.eos_token_id is not None:
|
||||
self._force_token_ids_generation(scores, self.config.eos_token_id)
|
||||
return scores
|
||||
self._force_token_ids_generation(logits, self.config.eos_token_id)
|
||||
return logits
|
||||
|
||||
def _force_token_ids_generation(self, scores, token_ids) -> None:
|
||||
"""force one of token_ids to be generated by setting prob of all other tokens to 0"""
|
||||
|
||||
@@ -61,7 +61,7 @@ def create_sinusoidal_embeddings(n_pos, dim, out):
|
||||
class Embeddings(nn.Module):
|
||||
def __init__(self, config):
|
||||
super().__init__()
|
||||
self.word_embeddings = nn.Embedding(config.vocab_size, config.dim, padding_idx=0)
|
||||
self.word_embeddings = nn.Embedding(config.vocab_size, config.dim, padding_idx=config.pad_token_id)
|
||||
self.position_embeddings = nn.Embedding(config.max_position_embeddings, config.dim)
|
||||
if config.sinusoidal_pos_embds:
|
||||
create_sinusoidal_embeddings(
|
||||
|
||||
@@ -104,7 +104,7 @@ 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.bool)).view(1, 1, n_ctx, n_ctx)
|
||||
)
|
||||
self.register_buffer("masked_bias", torch.tensor(-1e4))
|
||||
self.n_head = config.n_head
|
||||
@@ -143,6 +143,7 @@ class Attention(nn.Module):
|
||||
w = torch.matmul(q, k)
|
||||
if self.scale:
|
||||
w = w / (float(v.size(-1)) ** 0.5)
|
||||
|
||||
nd, ns = w.size(-2), w.size(-1)
|
||||
mask = self.bias[:, :, ns - nd : ns, :ns]
|
||||
w = torch.where(mask.bool(), w, self.masked_bias.to(w.dtype))
|
||||
@@ -151,22 +152,22 @@ class Attention(nn.Module):
|
||||
# Apply the attention mask
|
||||
w = w + attention_mask
|
||||
|
||||
w = nn.Softmax(dim=-1)(w)
|
||||
w = torch.softmax(w, dim=-1)
|
||||
w = self.attn_dropout(w)
|
||||
|
||||
# Mask heads if we want to
|
||||
if head_mask is not None:
|
||||
w = w * head_mask
|
||||
|
||||
outputs = [torch.matmul(w, v)]
|
||||
wv = torch.matmul(w, v)
|
||||
if self.output_attentions:
|
||||
outputs.append(w)
|
||||
return outputs
|
||||
return wv, w
|
||||
else:
|
||||
return (wv, )
|
||||
|
||||
def merge_heads(self, x):
|
||||
x = x.permute(0, 2, 1, 3).contiguous()
|
||||
new_x_shape = x.size()[:-2] + (x.size(-2) * x.size(-1),)
|
||||
return x.view(*new_x_shape) # in Tensorflow implem: fct merge_states
|
||||
x = x.transpose(2, 1).contiguous()
|
||||
return x.flatten(2) # in Tensorflow implem: fct merge_states
|
||||
|
||||
def split_heads(self, x, k=False):
|
||||
new_x_shape = x.size()[:-1] + (self.n_head, x.size(-1) // self.n_head)
|
||||
@@ -174,11 +175,11 @@ class Attention(nn.Module):
|
||||
if k:
|
||||
return x.permute(0, 2, 3, 1) # (batch, head, head_features, seq_length)
|
||||
else:
|
||||
return x.permute(0, 2, 1, 3) # (batch, head, seq_length, head_features)
|
||||
return x.transpose(2, 1) # (batch, head, seq_length, head_features)
|
||||
|
||||
def forward(self, x, layer_past=None, attention_mask=None, head_mask=None, use_cache=False):
|
||||
x = self.c_attn(x)
|
||||
query, key, value = x.split(self.split_size, dim=2)
|
||||
query, key, value = x.chunk(3, dim=2)
|
||||
query = self.split_heads(query)
|
||||
key = self.split_heads(key, k=True)
|
||||
value = self.split_heads(value)
|
||||
@@ -199,8 +200,7 @@ class Attention(nn.Module):
|
||||
a = self.c_proj(a)
|
||||
a = self.resid_dropout(a)
|
||||
|
||||
outputs = [a, present] + attn_outputs[1:]
|
||||
return outputs # a, present, (attentions)
|
||||
return a, present, attn_outputs[1:]
|
||||
|
||||
|
||||
class MLP(nn.Module):
|
||||
@@ -241,8 +241,7 @@ class Block(nn.Module):
|
||||
m = self.mlp(self.ln_2(x))
|
||||
x = x + m
|
||||
|
||||
outputs = [x] + output_attn[1:]
|
||||
return outputs # x, present, (attentions)
|
||||
return x, output_attn[1:]
|
||||
|
||||
|
||||
class GPT2PreTrainedModel(PreTrainedModel):
|
||||
@@ -425,17 +424,17 @@ class GPT2Model(GPT2PreTrainedModel):
|
||||
elif input_ids is not None:
|
||||
input_shape = input_ids.size()
|
||||
input_ids = input_ids.view(-1, input_shape[-1])
|
||||
batch_size = input_ids.shape[0]
|
||||
batch_size = input_ids.size(0)
|
||||
elif inputs_embeds is not None:
|
||||
input_shape = inputs_embeds.size()[:-1]
|
||||
batch_size = inputs_embeds.shape[0]
|
||||
batch_size = inputs_embeds.size(0)
|
||||
else:
|
||||
raise ValueError("You have to specify either input_ids or inputs_embeds")
|
||||
|
||||
if token_type_ids is not None:
|
||||
token_type_ids = token_type_ids.view(-1, input_shape[-1])
|
||||
token_type_ids = token_type_ids.view_as(input_ids)
|
||||
if position_ids is not None:
|
||||
position_ids = position_ids.view(-1, input_shape[-1])
|
||||
position_ids = position_ids.view_as(input_ids)
|
||||
|
||||
if past is None:
|
||||
past_length = 0
|
||||
@@ -450,22 +449,25 @@ class GPT2Model(GPT2PreTrainedModel):
|
||||
# Attention mask.
|
||||
if attention_mask is not None:
|
||||
assert batch_size > 0, "batch_size has to be defined and > 0"
|
||||
attention_mask = attention_mask.view(batch_size, -1)
|
||||
# We create a 3D attention mask from a 2D tensor mask.
|
||||
# Sizes are [batch_size, 1, 1, to_seq_length]
|
||||
# So we can broadcast to [batch_size, num_heads, from_seq_length, to_seq_length]
|
||||
# this attention mask is more simple than the triangular masking of causal attention
|
||||
# used in OpenAI GPT, we just need to prepare the broadcast dimension here.
|
||||
attention_mask = attention_mask.unsqueeze(1).unsqueeze(2)
|
||||
|
||||
# Since attention_mask is 1.0 for positions we want to attend and 0.0 for
|
||||
# masked positions, this operation will create a tensor which is 0.0 for
|
||||
# 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
|
||||
|
||||
# Computation is done over contiguous tensor (no view / unsqueeze) so probably faster
|
||||
# Do the shaping ops afterwards
|
||||
attention_mask = attention_mask.to(self.dtype) # fp16 compatibility
|
||||
attention_mask = (1.0 - attention_mask) * -10000.0
|
||||
|
||||
# We create a 3D attention mask from a 2D tensor mask.
|
||||
# Sizes are [batch_size, 1, 1, to_seq_length]
|
||||
# So we can broadcast to [batch_size, num_heads, from_seq_length, to_seq_length]
|
||||
# this attention mask is more simple than the triangular masking of causal attention
|
||||
# used in OpenAI GPT, we just need to prepare the broadcast dimension here.
|
||||
attention_mask = attention_mask.view(batch_size, 1, 1, -1)
|
||||
|
||||
# Prepare head mask if needed
|
||||
# 1.0 in head_mask indicate we keep the head
|
||||
# attention_probs has shape bsz x n_heads x N x N
|
||||
@@ -478,7 +480,7 @@ class GPT2Model(GPT2PreTrainedModel):
|
||||
if token_type_ids is not None:
|
||||
token_type_embeds = self.wte(token_type_ids)
|
||||
else:
|
||||
token_type_embeds = 0
|
||||
token_type_embeds = 0.
|
||||
hidden_states = inputs_embeds + position_embeds + token_type_embeds
|
||||
hidden_states = self.drop(hidden_states)
|
||||
|
||||
@@ -521,7 +523,7 @@ class GPT2Model(GPT2PreTrainedModel):
|
||||
if self.output_attentions:
|
||||
# let the number of heads free (-1) so we can extract attention even after head pruning
|
||||
attention_output_shape = input_shape[:-1] + (-1,) + all_attentions[0].shape[-2:]
|
||||
all_attentions = tuple(t.view(*attention_output_shape) for t in all_attentions)
|
||||
all_attentions = tuple([t.view(*attention_output_shape) for t in all_attentions])
|
||||
outputs = outputs + (all_attentions,)
|
||||
return outputs # last hidden state, (presents), (all hidden_states), (attentions)
|
||||
|
||||
@@ -752,6 +754,7 @@ class GPT2DoubleHeadsModel(GPT2PreTrainedModel):
|
||||
loss_fct = CrossEntropyLoss()
|
||||
loss = loss_fct(mc_logits.view(-1, mc_logits.size(-1)), mc_labels.view(-1))
|
||||
outputs = (loss,) + outputs
|
||||
|
||||
if lm_labels is not None:
|
||||
shift_logits = lm_logits[..., :-1, :].contiguous()
|
||||
shift_labels = lm_labels[..., 1:].contiguous()
|
||||
|
||||
@@ -31,7 +31,7 @@ class MarianMTModel(BartForConditionalGeneration):
|
||||
src = 'fr' # source language
|
||||
trg = 'en' # target language
|
||||
sample_text = "où est l'arrêt de bus ?"
|
||||
mname = f'Helsinki-NLP/opus-mt-{src}-{trg}' # `Model List`__
|
||||
mname = f'Helsinki-NLP/opus-mt-{src}-{trg}'
|
||||
|
||||
model = MarianMTModel.from_pretrained(mname)
|
||||
tok = MarianTokenizer.from_pretrained(mname)
|
||||
@@ -43,7 +43,8 @@ class MarianMTModel(BartForConditionalGeneration):
|
||||
|
||||
pretrained_model_archive_map = {} # see https://huggingface.co/models?search=Helsinki-NLP
|
||||
|
||||
def prepare_scores_for_generation(self, scores, cur_len, max_length):
|
||||
def prepare_logits_for_generation(self, logits, cur_len, max_length):
|
||||
logits[:, self.config.pad_token_id] = float("-inf")
|
||||
if cur_len == max_length - 1 and self.config.eos_token_id is not None:
|
||||
self._force_token_ids_generation(scores, self.config.eos_token_id)
|
||||
return scores
|
||||
self._force_token_ids_generation(logits, self.config.eos_token_id)
|
||||
return logits
|
||||
|
||||
@@ -21,7 +21,7 @@ import logging
|
||||
import tensorflow as tf
|
||||
|
||||
from .configuration_albert import AlbertConfig
|
||||
from .file_utils import add_start_docstrings, add_start_docstrings_to_callable
|
||||
from .file_utils import MULTIPLE_CHOICE_DUMMY_INPUTS, add_start_docstrings, add_start_docstrings_to_callable
|
||||
from .modeling_tf_bert import ACT2FN, TFBertSelfAttention
|
||||
from .modeling_tf_utils import TFPreTrainedModel, get_initializer, keras_serializable, shape_list
|
||||
from .tokenization_utils import BatchEncoding
|
||||
@@ -957,3 +957,127 @@ class TFAlbertForQuestionAnswering(TFAlbertPreTrainedModel):
|
||||
outputs = (start_logits, end_logits,) + outputs[2:]
|
||||
|
||||
return outputs # start_logits, end_logits, (hidden_states), (attentions)
|
||||
|
||||
|
||||
@add_start_docstrings(
|
||||
"""Albert Model with a multiple choice classification head on top (a linear layer on top of
|
||||
the pooled output and a softmax) e.g. for RocStories/SWAG tasks. """,
|
||||
ALBERT_START_DOCSTRING,
|
||||
)
|
||||
class TFAlbertForMultipleChoice(TFAlbertPreTrainedModel):
|
||||
def __init__(self, config, *inputs, **kwargs):
|
||||
super().__init__(config, *inputs, **kwargs)
|
||||
|
||||
self.albert = TFAlbertMainLayer(config, name="albert")
|
||||
self.dropout = tf.keras.layers.Dropout(config.hidden_dropout_prob)
|
||||
self.classifier = tf.keras.layers.Dense(
|
||||
1, kernel_initializer=get_initializer(config.initializer_range), name="classifier"
|
||||
)
|
||||
|
||||
@property
|
||||
def dummy_inputs(self):
|
||||
""" Dummy inputs to build the network.
|
||||
|
||||
Returns:
|
||||
tf.Tensor with dummy inputs
|
||||
"""
|
||||
return {"input_ids": tf.constant(MULTIPLE_CHOICE_DUMMY_INPUTS)}
|
||||
|
||||
@add_start_docstrings_to_callable(ALBERT_INPUTS_DOCSTRING)
|
||||
def call(
|
||||
self,
|
||||
inputs,
|
||||
attention_mask=None,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
head_mask=None,
|
||||
inputs_embeds=None,
|
||||
training=False,
|
||||
):
|
||||
r"""
|
||||
Return:
|
||||
:obj:`tuple(tf.Tensor)` comprising various elements depending on the configuration (:class:`~transformers.BertConfig`) and inputs:
|
||||
classification_scores (:obj:`Numpy array` or :obj:`tf.Tensor` of shape :obj:`(batch_size, num_choices)`:
|
||||
`num_choices` is the size of the second dimension of the input tensors. (see `input_ids` above).
|
||||
|
||||
Classification scores (before SoftMax).
|
||||
hidden_states (:obj:`tuple(tf.Tensor)`, `optional`, returned when :obj:`config.output_hidden_states=True`):
|
||||
tuple of :obj:`tf.Tensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(tf.Tensor)`, `optional`, returned when ``config.output_attentions=True``):
|
||||
tuple of :obj:`tf.Tensor` (one for each layer) of shape
|
||||
:obj:`(batch_size, num_heads, sequence_length, sequence_length)`:
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention heads.
|
||||
|
||||
Examples::
|
||||
|
||||
import tensorflow as tf
|
||||
from transformers import AlbertTokenizer, TFAlbertForMultipleChoice
|
||||
|
||||
tokenizer = AlbertTokenizer.from_pretrained('albert-base-v2')
|
||||
model = TFAlbertForMultipleChoice.from_pretrained('albert-base-v2')
|
||||
|
||||
example1 = ["This is a context", "Is it a context? Yes"]
|
||||
example2 = ["This is a context", "Is it a context? No"]
|
||||
encoding = tokenizer.batch_encode_plus([example1, example2], return_tensors='tf', truncation_strategy="only_first", pad_to_max_length=True, max_length=128)
|
||||
outputs = model(encoding["input_ids"][None, :])
|
||||
logits = outputs[0]
|
||||
|
||||
"""
|
||||
if isinstance(inputs, (tuple, list)):
|
||||
input_ids = inputs[0]
|
||||
attention_mask = inputs[1] if len(inputs) > 1 else attention_mask
|
||||
token_type_ids = inputs[2] if len(inputs) > 2 else token_type_ids
|
||||
position_ids = inputs[3] if len(inputs) > 3 else position_ids
|
||||
head_mask = inputs[4] if len(inputs) > 4 else head_mask
|
||||
inputs_embeds = inputs[5] if len(inputs) > 5 else inputs_embeds
|
||||
assert len(inputs) <= 6, "Too many inputs."
|
||||
elif isinstance(inputs, dict):
|
||||
print("isdict(1)")
|
||||
input_ids = inputs.get("input_ids")
|
||||
print(input_ids)
|
||||
|
||||
attention_mask = inputs.get("attention_mask", attention_mask)
|
||||
token_type_ids = inputs.get("token_type_ids", token_type_ids)
|
||||
position_ids = inputs.get("position_ids", position_ids)
|
||||
head_mask = inputs.get("head_mask", head_mask)
|
||||
inputs_embeds = inputs.get("inputs_embeds", inputs_embeds)
|
||||
assert len(inputs) <= 6, "Too many inputs."
|
||||
else:
|
||||
input_ids = inputs
|
||||
|
||||
if input_ids is not None:
|
||||
num_choices = shape_list(input_ids)[1]
|
||||
seq_length = shape_list(input_ids)[2]
|
||||
else:
|
||||
num_choices = shape_list(inputs_embeds)[1]
|
||||
seq_length = shape_list(inputs_embeds)[2]
|
||||
|
||||
flat_input_ids = tf.reshape(input_ids, (-1, seq_length)) if input_ids is not None else None
|
||||
flat_attention_mask = tf.reshape(attention_mask, (-1, seq_length)) if attention_mask is not None else None
|
||||
flat_token_type_ids = tf.reshape(token_type_ids, (-1, seq_length)) if token_type_ids is not None else None
|
||||
flat_position_ids = tf.reshape(position_ids, (-1, seq_length)) if position_ids is not None else None
|
||||
|
||||
flat_inputs = [
|
||||
flat_input_ids,
|
||||
flat_attention_mask,
|
||||
flat_token_type_ids,
|
||||
flat_position_ids,
|
||||
head_mask,
|
||||
inputs_embeds,
|
||||
]
|
||||
|
||||
outputs = self.albert(flat_inputs, training=training)
|
||||
|
||||
pooled_output = outputs[1]
|
||||
|
||||
pooled_output = self.dropout(pooled_output, training=training)
|
||||
logits = self.classifier(pooled_output)
|
||||
reshaped_logits = tf.reshape(logits, (-1, num_choices))
|
||||
|
||||
outputs = (reshaped_logits,) + outputs[2:] # add hidden states and attention if they are here
|
||||
|
||||
return outputs # reshaped_logits, (hidden_states), (attentions)
|
||||
|
||||
@@ -36,6 +36,7 @@ from .configuration_utils import PretrainedConfig
|
||||
from .modeling_tf_albert import (
|
||||
TF_ALBERT_PRETRAINED_MODEL_ARCHIVE_MAP,
|
||||
TFAlbertForMaskedLM,
|
||||
TFAlbertForMultipleChoice,
|
||||
TFAlbertForPreTraining,
|
||||
TFAlbertForQuestionAnswering,
|
||||
TFAlbertForSequenceClassification,
|
||||
@@ -44,6 +45,7 @@ from .modeling_tf_albert import (
|
||||
from .modeling_tf_bert import (
|
||||
TF_BERT_PRETRAINED_MODEL_ARCHIVE_MAP,
|
||||
TFBertForMaskedLM,
|
||||
TFBertForMultipleChoice,
|
||||
TFBertForPreTraining,
|
||||
TFBertForQuestionAnswering,
|
||||
TFBertForSequenceClassification,
|
||||
@@ -172,6 +174,10 @@ TF_MODEL_FOR_SEQUENCE_CLASSIFICATION_MAPPING = OrderedDict(
|
||||
]
|
||||
)
|
||||
|
||||
TF_MODEL_FOR_MULTIPLE_CHOICE_MAPPING = OrderedDict(
|
||||
[(BertConfig, TFBertForMultipleChoice), (AlbertConfig, TFAlbertForMultipleChoice)]
|
||||
)
|
||||
|
||||
TF_MODEL_FOR_QUESTION_ANSWERING_MAPPING = OrderedDict(
|
||||
[
|
||||
(DistilBertConfig, TFDistilBertForQuestionAnswering),
|
||||
@@ -662,6 +668,153 @@ class TFAutoModelWithLMHead(object):
|
||||
)
|
||||
|
||||
|
||||
class TFAutoModelForMultipleChoice:
|
||||
r"""
|
||||
:class:`~transformers.TFAutoModelForMultipleChoice` is a generic model class
|
||||
that will be instantiated as one of the multiple choice model classes of the library
|
||||
when created with the `TFAutoModelForMultipleChoice.from_pretrained(pretrained_model_name_or_path)`
|
||||
class method.
|
||||
|
||||
The `from_pretrained()` method takes care of returning the correct model class instance
|
||||
based on the `model_type` property of the config object, or when it's missing,
|
||||
falling back to using pattern matching on the `pretrained_model_name_or_path` string.
|
||||
|
||||
The model class to instantiate is selected as the first pattern matching
|
||||
in the `pretrained_model_name_or_path` string (in the following order):
|
||||
- contains `albert`: TFAlbertForMultipleChoice (Albert model)
|
||||
- contains `bert`: TFBertForMultipleChoice (Bert model)
|
||||
|
||||
This class cannot be instantiated using `__init__()` (throws an error).
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
raise EnvironmentError(
|
||||
"TFAutoModelForMultipleChoice is designed to be instantiated "
|
||||
"using the `TFAutoModelForMultipleChoice.from_pretrained(pretrained_model_name_or_path)` or "
|
||||
"`TFAutoModelForMultipleChoice.from_config(config)` methods."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, config):
|
||||
r""" Instantiates one of the base model classes of the library
|
||||
from a configuration.
|
||||
|
||||
config: (`optional`) instance of a class derived from :class:`~transformers.PretrainedConfig`:
|
||||
The model class to instantiate is selected based on the configuration class:
|
||||
- isInstance of `albert` configuration class: AlbertModel (Albert model)
|
||||
- isInstance of `bert` configuration class: BertModel (Bert model)
|
||||
|
||||
Examples::
|
||||
|
||||
config = BertConfig.from_pretrained('bert-base-uncased') # Download configuration from S3 and cache.
|
||||
model = AutoModelForMulitpleChoice.from_config(config) # E.g. model was saved using `save_pretrained('./test/saved_model/')`
|
||||
"""
|
||||
for config_class, model_class in TF_MODEL_FOR_MULTIPLE_CHOICE_MAPPING.items():
|
||||
if isinstance(config, config_class):
|
||||
return model_class(config)
|
||||
raise ValueError(
|
||||
"Unrecognized configuration class {} for this kind of TFAutoModel: {}.\n"
|
||||
"Model type should be one of {}.".format(
|
||||
config.__class__,
|
||||
cls.__name__,
|
||||
", ".join(c.__name__ for c in TF_MODEL_FOR_MULTIPLE_CHOICE_MAPPING.keys()),
|
||||
)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_pretrained(cls, pretrained_model_name_or_path, *model_args, **kwargs):
|
||||
r""" Instantiates one of the multiple choice model classes of the library
|
||||
from a pre-trained model configuration.
|
||||
|
||||
The `from_pretrained()` method takes care of returning the correct model class instance
|
||||
based on the `model_type` property of the config object, or when it's missing,
|
||||
falling back to using pattern matching on the `pretrained_model_name_or_path` string.
|
||||
|
||||
The model class to instantiate is selected as the first pattern matching
|
||||
in the `pretrained_model_name_or_path` string (in the following order):
|
||||
- contains `albert`: TFRobertaForMultiple (Albert model)
|
||||
- contains `bert`: TFBertForMultipleChoice (Bert model)
|
||||
|
||||
The model is set in evaluation mode by default using `model.eval()` (Dropout modules are deactivated)
|
||||
To train the model, you should first set it back in training mode with `model.train()`
|
||||
|
||||
Params:
|
||||
pretrained_model_name_or_path: either:
|
||||
|
||||
- a string with the `shortcut name` of a pre-trained model to load from cache or download, e.g.: ``bert-base-uncased``.
|
||||
- a string with the `identifier name` of a pre-trained model that was user-uploaded to our S3, e.g.: ``dbmdz/bert-base-german-cased``.
|
||||
- a path to a `directory` containing model weights saved using :func:`~transformers.PreTrainedModel.save_pretrained`, e.g.: ``./my_model_directory/``.
|
||||
- a path or url to a `PyTorch, TF 1.X or TF 2.0 checkpoint file` (e.g. `./tf_model/model.ckpt.index`). In the case of a PyTorch checkpoint, ``from_pt`` should be set to True and a configuration object should be provided as ``config`` argument.
|
||||
|
||||
from_pt: (`Optional`) Boolean
|
||||
Set to True if the Checkpoint is a PyTorch checkpoint.
|
||||
|
||||
model_args: (`optional`) Sequence of positional arguments:
|
||||
All remaning positional arguments will be passed to the underlying model's ``__init__`` method
|
||||
|
||||
config: (`optional`) instance of a class derived from :class:`~transformers.PretrainedConfig`:
|
||||
Configuration for the model to use instead of an automatically loaded configuation. Configuration can be automatically loaded when:
|
||||
|
||||
- the model is a model provided by the library (loaded with the ``shortcut-name`` string of a pretrained model), or
|
||||
- the model was saved using :func:`~transformers.PreTrainedModel.save_pretrained` and is reloaded by suppling the save directory.
|
||||
- the model is loaded by suppling a local directory as ``pretrained_model_name_or_path`` and a configuration JSON file named `config.json` is found in the directory.
|
||||
|
||||
state_dict: (`optional`) dict:
|
||||
an optional state dictionnary for the model to use instead of a state dictionary loaded from saved weights file.
|
||||
This option can be used if you want to create a model from a pretrained configuration but load your own weights.
|
||||
In this case though, you should check if using :func:`~transformers.PreTrainedModel.save_pretrained` and :func:`~transformers.PreTrainedModel.from_pretrained` is not a simpler option.
|
||||
|
||||
cache_dir: (`optional`) string:
|
||||
Path to a directory in which a downloaded pre-trained model
|
||||
configuration should be cached if the standard cache should not be used.
|
||||
|
||||
force_download: (`optional`) boolean, default False:
|
||||
Force to (re-)download the model weights and configuration files and override the cached versions if they exists.
|
||||
|
||||
resume_download: (`optional`) boolean, default False:
|
||||
Do not delete incompletely recieved file. Attempt to resume the download if such a file exists.
|
||||
|
||||
proxies: (`optional`) dict, default None:
|
||||
A dictionary of proxy servers to use by protocol or endpoint, e.g.: {'http': 'foo.bar:3128', 'http://hostname': 'foo.bar:4012'}.
|
||||
The proxies are used on each request.
|
||||
|
||||
output_loading_info: (`optional`) boolean:
|
||||
Set to ``True`` to also return a dictionnary containing missing keys, unexpected keys and error messages.
|
||||
|
||||
kwargs: (`optional`) Remaining dictionary of keyword arguments:
|
||||
Can be used to update the configuration object (after it being loaded) and initiate the model. (e.g. ``output_attention=True``). Behave differently depending on whether a `config` is provided or automatically loaded:
|
||||
|
||||
- If a configuration is provided with ``config``, ``**kwargs`` will be directly passed to the underlying model's ``__init__`` method (we assume all relevant updates to the configuration have already been done)
|
||||
- If a configuration is not provided, ``kwargs`` will be first passed to the configuration class initialization function (:func:`~transformers.PretrainedConfig.from_pretrained`). Each key of ``kwargs`` that corresponds to a configuration attribute will be used to override said attribute with the supplied ``kwargs`` value. Remaining keys that do not correspond to any configuration attribute will be passed to the underlying model's ``__init__`` function.
|
||||
|
||||
Examples::
|
||||
|
||||
model = TFAutoModelFormultipleChoice.from_pretrained('bert-base-uncased') # Download model and configuration from S3 and cache.
|
||||
model = TFAutoModelFormultipleChoice.from_pretrained('./test/bert_model/') # E.g. model was saved using `save_pretrained('./test/saved_model/')`
|
||||
model = TFAutoModelFormultipleChoice.from_pretrained('bert-base-uncased', output_attention=True) # Update configuration during loading
|
||||
assert model.config.output_attention == True
|
||||
# Loading from a TF checkpoint file instead of a PyTorch model (slower)
|
||||
config = AutoConfig.from_json_file('./tf_model/bert_tf_model_config.json')
|
||||
model = TFAutoModelFormultipleChoice.from_pretrained('./pt_model/bert_pytorch_model.bin', from_pt=True, config=config)
|
||||
|
||||
"""
|
||||
config = kwargs.pop("config", None)
|
||||
if not isinstance(config, PretrainedConfig):
|
||||
config = AutoConfig.from_pretrained(pretrained_model_name_or_path, **kwargs)
|
||||
|
||||
for config_class, model_class in TF_MODEL_FOR_MULTIPLE_CHOICE_MAPPING.items():
|
||||
if isinstance(config, config_class):
|
||||
return model_class.from_pretrained(pretrained_model_name_or_path, *model_args, config=config, **kwargs)
|
||||
raise ValueError(
|
||||
"Unrecognized configuration class {} for this kind of TFAutoModel: {}.\n"
|
||||
"Model type should be one of {}.".format(
|
||||
config.__class__,
|
||||
cls.__name__,
|
||||
", ".join(c.__name__ for c in TF_MODEL_FOR_MULTIPLE_CHOICE_MAPPING.keys()),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class TFAutoModelForSequenceClassification(object):
|
||||
r"""
|
||||
:class:`~transformers.TFAutoModelForSequenceClassification` is a generic model class
|
||||
|
||||
@@ -744,8 +744,8 @@ class PreTrainedModel(nn.Module, ModuleUtilsMixin):
|
||||
def prepare_inputs_for_generation(self, input_ids, **kwargs):
|
||||
return {"input_ids": input_ids}
|
||||
|
||||
def prepare_scores_for_generation(self, scores, **kwargs):
|
||||
return scores
|
||||
def prepare_logits_for_generation(self, logits, **kwargs):
|
||||
return logits
|
||||
|
||||
def _use_cache(self, outputs, use_cache):
|
||||
"""During generation, decide whether to pass the `past` variable to the next forward pass."""
|
||||
@@ -857,7 +857,7 @@ class PreTrainedModel(nn.Module, ModuleUtilsMixin):
|
||||
``1`` for tokens that are NOT MASKED, ``0`` for MASKED tokens.
|
||||
Defaults to `None`.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
|
||||
decoder_start_token_id=None: (`optional`) int
|
||||
If an encoder-decoder model starts decoding with a different token than BOS.
|
||||
@@ -1342,10 +1342,13 @@ class PreTrainedModel(nn.Module, ModuleUtilsMixin):
|
||||
if temperature != 1.0:
|
||||
next_token_logits = next_token_logits / temperature
|
||||
|
||||
scores = F.log_softmax(next_token_logits, dim=-1) # (batch_size * num_beams, vocab_size)
|
||||
if self.config.is_encoder_decoder and do_sample is False:
|
||||
# TODO (PVP) still a bit hacky here - there might be a better solutino
|
||||
scores = self.prepare_scores_for_generation(scores, cur_len=cur_len, max_length=max_length)
|
||||
# TODO (PVP) still a bit hacky here - there might be a better solution
|
||||
next_token_logits = self.prepare_logits_for_generation(
|
||||
next_token_logits, cur_len=cur_len, max_length=max_length
|
||||
)
|
||||
|
||||
scores = F.log_softmax(next_token_logits, dim=-1) # (batch_size * num_beams, vocab_size)
|
||||
|
||||
# set eos token prob to zero if min_length is not reached
|
||||
if eos_token_id is not None and cur_len < min_length:
|
||||
@@ -1705,10 +1708,7 @@ class Conv1D(nn.Module):
|
||||
self.bias = nn.Parameter(torch.zeros(nf))
|
||||
|
||||
def forward(self, x):
|
||||
size_out = x.size()[:-1] + (self.nf,)
|
||||
x = torch.addmm(self.bias, x.view(-1, x.size(-1)), self.weight)
|
||||
x = x.view(*size_out)
|
||||
return x
|
||||
return torch.baddbmm(self.bias[None, None], x, self.weight[None])
|
||||
|
||||
|
||||
class PoolerStartLogits(nn.Module):
|
||||
|
||||
@@ -152,8 +152,8 @@ class AdamW(Optimizer):
|
||||
|
||||
# Decay the first and second moment running average coefficient
|
||||
# In-place operations to update the averages at the same time
|
||||
exp_avg.mul_(beta1).add_(1.0 - beta1, grad)
|
||||
exp_avg_sq.mul_(beta2).addcmul_(1.0 - beta2, grad, grad)
|
||||
exp_avg.mul_(beta1).add_(grad, alpha=1.0 - beta1)
|
||||
exp_avg_sq.mul_(beta2).addcmul_(grad, grad, value=1.0 - beta2)
|
||||
denom = exp_avg_sq.sqrt().add_(group["eps"])
|
||||
|
||||
step_size = group["lr"]
|
||||
@@ -173,6 +173,6 @@ class AdamW(Optimizer):
|
||||
# of the weights to the loss with plain (non-momentum) SGD.
|
||||
# Add weight decay at the end (fixed version)
|
||||
if group["weight_decay"] > 0.0:
|
||||
p.data.add_(-group["lr"] * group["weight_decay"], p.data)
|
||||
p.data.add_(p.data, alpha=-group["lr"] * group["weight_decay"])
|
||||
|
||||
return loss
|
||||
|
||||
@@ -217,7 +217,7 @@ class GradientAccumulator(object):
|
||||
"""The accumulated gradients on the current replica."""
|
||||
if not self._gradients:
|
||||
raise ValueError("The accumulator should be called first to initialize the gradients")
|
||||
return list(gradient.value() for gradient in self._gradients)
|
||||
return list(gradient.value() if gradient is not None else gradient for gradient in self._gradients)
|
||||
|
||||
def __call__(self, gradients):
|
||||
"""Accumulates :obj:`gradients` on the current replica."""
|
||||
@@ -231,6 +231,8 @@ class GradientAccumulator(object):
|
||||
synchronization=tf.VariableSynchronization.ON_READ,
|
||||
aggregation=tf.VariableAggregation.ONLY_FIRST_REPLICA,
|
||||
)
|
||||
if gradient is not None
|
||||
else gradient
|
||||
for gradient in gradients
|
||||
]
|
||||
)
|
||||
@@ -238,7 +240,8 @@ class GradientAccumulator(object):
|
||||
raise ValueError("Expected %s gradients, but got %d" % (len(self._gradients), len(gradients)))
|
||||
|
||||
for accum_gradient, gradient in zip(self._gradients, gradients):
|
||||
accum_gradient.assign_add(gradient)
|
||||
if accum_gradient is not None and gradient is not None:
|
||||
accum_gradient.assign_add(gradient)
|
||||
|
||||
self._accum_steps.assign_add(1)
|
||||
|
||||
@@ -248,4 +251,5 @@ class GradientAccumulator(object):
|
||||
return
|
||||
self._accum_steps.assign(0)
|
||||
for gradient in self._gradients:
|
||||
gradient.assign(tf.zeros_like(gradient))
|
||||
if gradient is not None:
|
||||
gradient.assign(tf.zeros_like(gradient))
|
||||
|
||||
@@ -24,7 +24,7 @@ from abc import ABC, abstractmethod
|
||||
from contextlib import contextmanager
|
||||
from itertools import chain
|
||||
from os.path import abspath, exists
|
||||
from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, Union
|
||||
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Sequence, Tuple, Union
|
||||
|
||||
import numpy as np
|
||||
|
||||
@@ -58,6 +58,10 @@ if is_torch_available():
|
||||
AutoModelWithLMHead,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .modeling_utils import PreTrainedModel
|
||||
from .modeling_tf_utils import TFPreTrainedModel
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -1509,7 +1513,7 @@ class TranslationPipeline(Pipeline):
|
||||
return results
|
||||
|
||||
|
||||
# Register all the supported task here
|
||||
# Register all the supported tasks here
|
||||
SUPPORTED_TASKS = {
|
||||
"feature-extraction": {
|
||||
"impl": FeatureExtractionPipeline,
|
||||
@@ -1572,9 +1576,9 @@ SUPPORTED_TASKS = {
|
||||
"tf": TFAutoModelWithLMHead if is_tf_available() else None,
|
||||
"pt": AutoModelWithLMHead if is_torch_available() else None,
|
||||
"default": {
|
||||
"model": {"pt": "bart-large-cnn", "tf": None},
|
||||
"model": {"pt": "bart-large-cnn", "tf": "t5-small"},
|
||||
"config": None,
|
||||
"tokenizer": ("bart-large-cnn", {"use_fast": False}),
|
||||
"tokenizer": {"pt": ("bart-large-cnn", {"use_fast": False}), "tf": "t5-small"},
|
||||
},
|
||||
},
|
||||
"translation_en_to_fr": {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import json
|
||||
import re
|
||||
import warnings
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
@@ -14,7 +15,7 @@ vocab_files_names = {
|
||||
"vocab": "vocab.json",
|
||||
"tokenizer_config_file": "tokenizer_config.json",
|
||||
}
|
||||
MODEL_NAMES = ("opus-mt-en-de",)
|
||||
MODEL_NAMES = ("opus-mt-en-de",) # TODO(SS): the only required constant is vocab_files_names
|
||||
PRETRAINED_VOCAB_FILES_MAP = {
|
||||
k: {m: f"{S3_BUCKET_PREFIX}/Helsinki-NLP/{m}/{fname}" for m in MODEL_NAMES}
|
||||
for k, fname in vocab_files_names.items()
|
||||
@@ -41,6 +42,7 @@ class MarianTokenizer(PreTrainedTokenizer):
|
||||
pretrained_vocab_files_map = PRETRAINED_VOCAB_FILES_MAP
|
||||
max_model_input_sizes = {m: 512 for m in MODEL_NAMES}
|
||||
model_input_names = ["attention_mask"] # actually attention_mask, decoder_attention_mask
|
||||
language_code_re = re.compile(">>.+<<") # type: re.Pattern
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -72,8 +74,6 @@ class MarianTokenizer(PreTrainedTokenizer):
|
||||
self.target_lang = target_lang
|
||||
|
||||
# load SentencePiece model for pre-processing
|
||||
self.paths = {}
|
||||
|
||||
self.spm_source = sentencepiece.SentencePieceProcessor()
|
||||
self.spm_source.Load(source_spm)
|
||||
|
||||
@@ -82,9 +82,7 @@ class MarianTokenizer(PreTrainedTokenizer):
|
||||
|
||||
# Multilingual target side: default to using first supported language code.
|
||||
self.supported_language_codes: list = [k for k in self.encoder if k.startswith(">>") and k.endswith("<<")]
|
||||
self.tgt_lang_id = None # will not be used unless it is set through prepare_translation_batch
|
||||
|
||||
# Note(SS): sentence_splitter would require lots of book-keeping.
|
||||
try:
|
||||
from mosestokenizer import MosesPunctuationNormalizer
|
||||
|
||||
@@ -93,11 +91,23 @@ class MarianTokenizer(PreTrainedTokenizer):
|
||||
warnings.warn("Recommended: pip install mosestokenizer")
|
||||
self.punc_normalizer = lambda x: x
|
||||
|
||||
def normalize(self, x: str) -> str:
|
||||
"""Cover moses empty string edge case. They return empty list for '' input!"""
|
||||
return self.punc_normalizer(x) if x else ""
|
||||
|
||||
def _convert_token_to_id(self, token):
|
||||
return self.encoder.get(token, self.encoder[self.unk_token])
|
||||
|
||||
def remove_language_code(self, text: str):
|
||||
"""Remove language codes like <<fr>> before sentencepiece"""
|
||||
match = self.language_code_re.match(text)
|
||||
code: list = [match.group(0)] if match else []
|
||||
return code, self.language_code_re.sub("", text)
|
||||
|
||||
def _tokenize(self, text: str) -> List[str]:
|
||||
return self.current_spm.EncodeAsPieces(text)
|
||||
code, text = self.remove_language_code(text)
|
||||
pieces = self.current_spm.EncodeAsPieces(text)
|
||||
return code + pieces
|
||||
|
||||
def _convert_id_to_token(self, index: int) -> str:
|
||||
"""Converts an index (integer) in a token (str) using the encoder."""
|
||||
@@ -114,9 +124,6 @@ class MarianTokenizer(PreTrainedTokenizer):
|
||||
# We don't expect to process pairs, but leave the pair logic for API consistency
|
||||
return token_ids_0 + token_ids_1 + [self.eos_token_id]
|
||||
|
||||
def batch_decode(self, token_ids, **kwargs) -> List[str]:
|
||||
return [self.decode(ids, **kwargs) for ids in token_ids]
|
||||
|
||||
def prepare_translation_batch(
|
||||
self,
|
||||
src_texts: List[str],
|
||||
@@ -125,7 +132,7 @@ class MarianTokenizer(PreTrainedTokenizer):
|
||||
pad_to_max_length: bool = True,
|
||||
return_tensors: str = "pt",
|
||||
) -> BatchEncoding:
|
||||
"""
|
||||
"""Prepare model inputs for translation. For best performance, translate one sentence at a time.
|
||||
Arguments:
|
||||
src_texts: list of src language texts
|
||||
tgt_texts: list of tgt language texts
|
||||
@@ -138,7 +145,10 @@ class MarianTokenizer(PreTrainedTokenizer):
|
||||
all shaped bs, seq_len. (BatchEncoding is a dict of string -> tensor or lists).
|
||||
If no tgt_text is specified, the only keys will be input_ids and attention_mask.
|
||||
"""
|
||||
if "" in src_texts:
|
||||
raise ValueError(f"found empty string in src_texts: {src_texts}")
|
||||
self.current_spm = self.spm_source
|
||||
src_texts = [self.normalize(t) for t in src_texts] # this does not appear to do much
|
||||
model_inputs: BatchEncoding = self.batch_encode_plus(
|
||||
src_texts,
|
||||
add_special_tokens=True,
|
||||
|
||||
@@ -173,7 +173,11 @@ class BatchEncoding(UserDict):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, data: Dict[str, Any], encoding: Optional[Union[EncodingFast, Sequence[EncodingFast]]] = None):
|
||||
def __init__(
|
||||
self,
|
||||
data: Optional[Dict[str, Any]] = None,
|
||||
encoding: Optional[Union[EncodingFast, Sequence[EncodingFast]]] = None,
|
||||
):
|
||||
super().__init__(data)
|
||||
|
||||
if isinstance(encoding, EncodingFast):
|
||||
@@ -2179,6 +2183,9 @@ class PreTrainedTokenizer(SpecialTokensMixin):
|
||||
else:
|
||||
return text
|
||||
|
||||
def batch_decode(self, sequences: List[List[int]], **kwargs) -> List[str]:
|
||||
return [self.decode(seq, **kwargs) for seq in sequences]
|
||||
|
||||
@staticmethod
|
||||
def clean_up_tokenization(out_string: str) -> str:
|
||||
""" Clean up a list of simple English tokenization artifacts like spaces before punctuations and abreviated forms.
|
||||
@@ -2191,7 +2198,6 @@ class PreTrainedTokenizer(SpecialTokensMixin):
|
||||
.replace(" ' ", "'")
|
||||
.replace(" n't", "n't")
|
||||
.replace(" 'm", "'m")
|
||||
.replace(" do not", " don't")
|
||||
.replace(" 's", "'s")
|
||||
.replace(" 've", "'ve")
|
||||
.replace(" 're", "'re")
|
||||
|
||||
+98
-43
@@ -61,7 +61,12 @@ def is_tensorboard_available():
|
||||
try:
|
||||
import wandb
|
||||
|
||||
_has_wandb = True
|
||||
wandb.ensure_configured()
|
||||
if wandb.api.api_key is None:
|
||||
_has_wandb = False
|
||||
wandb.termwarn("W&B installed but not logged in. Run `wandb login` or set the WANDB_API_KEY env variable.")
|
||||
else:
|
||||
_has_wandb = False if os.getenv("WANDB_DISABLED") else True
|
||||
except ImportError:
|
||||
_has_wandb = False
|
||||
|
||||
@@ -114,6 +119,8 @@ class Trainer:
|
||||
prediction_loss_only: bool
|
||||
tb_writer: Optional["SummaryWriter"] = None
|
||||
optimizers: Tuple[torch.optim.Optimizer, torch.optim.lr_scheduler.LambdaLR] = None
|
||||
global_step: Optional[int] = None
|
||||
epoch: Optional[float] = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -154,9 +161,12 @@ class Trainer:
|
||||
logger.warning(
|
||||
"You are instantiating a Trainer but Tensorboard is not installed. You should consider installing it."
|
||||
)
|
||||
if not is_wandb_available():
|
||||
if is_wandb_available():
|
||||
self._setup_wandb()
|
||||
else:
|
||||
logger.info(
|
||||
"You are instantiating a Trainer but wandb is not installed. Install it to use Weights & Biases logging."
|
||||
"You are instantiating a Trainer but W&B is not installed. To use wandb logging, "
|
||||
"run `pip install wandb; wandb login` see https://docs.wandb.com/huggingface."
|
||||
)
|
||||
set_seed(self.args.seed)
|
||||
# Create output directory if needed
|
||||
@@ -263,11 +273,25 @@ class Trainer:
|
||||
"""
|
||||
Setup the optional Weights & Biases (`wandb`) integration.
|
||||
|
||||
One can override this method to customize the setup if needed.
|
||||
One can override this method to customize the setup if needed. Find more information at https://docs.wandb.com/huggingface
|
||||
You can also override the following environment variables:
|
||||
|
||||
Environment:
|
||||
WANDB_WATCH:
|
||||
(Optional, ["gradients", "all", "false"]) "gradients" by default, set to "false" to disable gradient logging
|
||||
or "all" to log gradients and parameters
|
||||
WANDB_PROJECT:
|
||||
(Optional): str - "huggingface" by default, set this to a custom string to store results in a different project
|
||||
WANDB_DISABLED:
|
||||
(Optional): boolean - defaults to false, set to "true" to disable wandb entirely
|
||||
"""
|
||||
wandb.init(name=self.args.logging_dir, config=vars(self.args))
|
||||
logger.info('Automatic Weights & Biases logging enabled, to disable set os.environ["WANDB_DISABLED"] = "true"')
|
||||
wandb.init(project=os.getenv("WANDB_PROJECT", "huggingface"), config=vars(self.args))
|
||||
# keep track of model topology and gradients
|
||||
wandb.watch(self.model)
|
||||
if os.getenv("WANDB_WATCH") != "false":
|
||||
wandb.watch(
|
||||
self.model, log=os.getenv("WANDB_WATCH", "gradients"), log_freq=max(100, self.args.logging_steps)
|
||||
)
|
||||
|
||||
def num_examples(self, dataloader: Union[DataLoader, "pl.PerDeviceLoader"]) -> int:
|
||||
"""
|
||||
@@ -333,8 +357,6 @@ class Trainer:
|
||||
if self.tb_writer is not None:
|
||||
self.tb_writer.add_text("args", self.args.to_json_string())
|
||||
self.tb_writer.add_hparams(self.args.to_sanitized_dict(), metric_dict={})
|
||||
if is_wandb_available():
|
||||
self._setup_wandb()
|
||||
|
||||
# Train!
|
||||
if is_tpu_available():
|
||||
@@ -353,25 +375,26 @@ class Trainer:
|
||||
logger.info(" Gradient Accumulation steps = %d", self.args.gradient_accumulation_steps)
|
||||
logger.info(" Total optimization steps = %d", t_total)
|
||||
|
||||
global_step = 0
|
||||
self.global_step = 0
|
||||
self.epoch = 0
|
||||
epochs_trained = 0
|
||||
steps_trained_in_current_epoch = 0
|
||||
# Check if continuing training from a checkpoint
|
||||
if model_path is not None:
|
||||
# set global_step to global_step of last saved checkpoint from model path
|
||||
try:
|
||||
global_step = int(model_path.split("-")[-1].split("/")[0])
|
||||
epochs_trained = global_step // (len(train_dataloader) // self.args.gradient_accumulation_steps)
|
||||
steps_trained_in_current_epoch = global_step % (
|
||||
self.global_step = int(model_path.split("-")[-1].split("/")[0])
|
||||
epochs_trained = self.global_step // (len(train_dataloader) // self.args.gradient_accumulation_steps)
|
||||
steps_trained_in_current_epoch = self.global_step % (
|
||||
len(train_dataloader) // self.args.gradient_accumulation_steps
|
||||
)
|
||||
|
||||
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", global_step)
|
||||
logger.info(" Continuing training from global step %d", self.global_step)
|
||||
logger.info(" Will skip the first %d steps in the first epoch", steps_trained_in_current_epoch)
|
||||
except ValueError:
|
||||
global_step = 0
|
||||
self.global_step = 0
|
||||
logger.info(" Starting fine-tuning.")
|
||||
|
||||
tr_loss = 0.0
|
||||
@@ -408,34 +431,24 @@ class Trainer:
|
||||
|
||||
scheduler.step()
|
||||
model.zero_grad()
|
||||
global_step += 1
|
||||
self.global_step += 1
|
||||
self.epoch = epoch + (step + 1) / len(epoch_iterator)
|
||||
|
||||
if self.is_local_master():
|
||||
if (self.args.logging_steps > 0 and global_step % self.args.logging_steps == 0) or (
|
||||
global_step == 1 and self.args.logging_first_step
|
||||
if (self.args.logging_steps > 0 and self.global_step % self.args.logging_steps == 0) or (
|
||||
self.global_step == 1 and self.args.logging_first_step
|
||||
):
|
||||
logs = {}
|
||||
if self.args.evaluate_during_training:
|
||||
results = self.evaluate()
|
||||
for key, value in results.items():
|
||||
eval_key = "eval_{}".format(key)
|
||||
logs[eval_key] = value
|
||||
|
||||
loss_scalar = (tr_loss - logging_loss) / self.args.logging_steps
|
||||
learning_rate_scalar = scheduler.get_last_lr()[0]
|
||||
logs["learning_rate"] = learning_rate_scalar
|
||||
logs["loss"] = loss_scalar
|
||||
logs: Dict[str, float] = {}
|
||||
logs["loss"] = (tr_loss - logging_loss) / self.args.logging_steps
|
||||
logs["learning_rate"] = scheduler.get_last_lr()[0]
|
||||
logging_loss = tr_loss
|
||||
|
||||
if self.tb_writer:
|
||||
for k, v in logs.items():
|
||||
self.tb_writer.add_scalar(k, v, global_step)
|
||||
if is_wandb_available():
|
||||
wandb.log(logs, step=global_step)
|
||||
self._log(logs)
|
||||
|
||||
epoch_iterator.write(json.dumps({**logs, **{"step": global_step}}))
|
||||
if self.args.evaluate_during_training:
|
||||
self.evaluate()
|
||||
|
||||
if self.args.save_steps > 0 and global_step % self.args.save_steps == 0:
|
||||
if self.args.save_steps > 0 and self.global_step % self.args.save_steps == 0:
|
||||
# In all cases (even distributed/parallel), self.model is always a reference
|
||||
# to the model we want to save.
|
||||
if hasattr(model, "module"):
|
||||
@@ -443,7 +456,9 @@ class Trainer:
|
||||
else:
|
||||
assert model is self.model
|
||||
# Save model checkpoint
|
||||
output_dir = os.path.join(self.args.output_dir, f"{PREFIX_CHECKPOINT_DIR}-{global_step}")
|
||||
output_dir = os.path.join(
|
||||
self.args.output_dir, f"{PREFIX_CHECKPOINT_DIR}-{self.global_step}"
|
||||
)
|
||||
|
||||
self.save_model(output_dir)
|
||||
self._rotate_checkpoints()
|
||||
@@ -451,10 +466,10 @@ class Trainer:
|
||||
torch.save(scheduler.state_dict(), os.path.join(output_dir, "scheduler.pt"))
|
||||
logger.info("Saving optimizer and scheduler states to %s", output_dir)
|
||||
|
||||
if self.args.max_steps > 0 and global_step > self.args.max_steps:
|
||||
if self.args.max_steps > 0 and self.global_step > self.args.max_steps:
|
||||
epoch_iterator.close()
|
||||
break
|
||||
if self.args.max_steps > 0 and global_step > self.args.max_steps:
|
||||
if self.args.max_steps > 0 and self.global_step > self.args.max_steps:
|
||||
train_iterator.close()
|
||||
break
|
||||
if self.args.tpu_metrics_debug:
|
||||
@@ -465,7 +480,21 @@ class Trainer:
|
||||
self.tb_writer.close()
|
||||
|
||||
logger.info("\n\nTraining completed. Do not forget to share your model on huggingface.co/models =)\n\n")
|
||||
return TrainOutput(global_step, tr_loss / global_step)
|
||||
return TrainOutput(self.global_step, tr_loss / self.global_step)
|
||||
|
||||
def _log(self, logs: Dict[str, float], iterator: Optional[tqdm] = None) -> None:
|
||||
if self.epoch is not None:
|
||||
logs["epoch"] = self.epoch
|
||||
if self.tb_writer:
|
||||
for k, v in logs.items():
|
||||
self.tb_writer.add_scalar(k, v, self.global_step)
|
||||
if is_wandb_available():
|
||||
wandb.log(logs, step=self.global_step)
|
||||
output = json.dumps({**logs, **{"step": self.global_step}})
|
||||
if iterator is not None:
|
||||
iterator.write(output)
|
||||
else:
|
||||
print(output)
|
||||
|
||||
def _training_step(
|
||||
self, model: nn.Module, inputs: Dict[str, torch.Tensor], optimizer: torch.optim.Optimizer
|
||||
@@ -513,9 +542,28 @@ class Trainer:
|
||||
|
||||
Will only save from the master process.
|
||||
"""
|
||||
if self.is_world_master():
|
||||
|
||||
if is_tpu_available():
|
||||
self._save_tpu(output_dir)
|
||||
elif self.is_world_master():
|
||||
self._save(output_dir)
|
||||
|
||||
def _save_tpu(self, output_dir: Optional[str] = None):
|
||||
output_dir = output_dir if output_dir is not None else self.args.output_dir
|
||||
logger.info("Saving model checkpoint to %s", output_dir)
|
||||
|
||||
if xm.is_master_ordinal():
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
torch.save(self.args, os.path.join(output_dir, "training_args.bin"))
|
||||
|
||||
# Save a trained model and configuration using `save_pretrained()`.
|
||||
# They can then be reloaded using `from_pretrained()`
|
||||
if not isinstance(self.model, PreTrainedModel):
|
||||
raise ValueError("Trainer.model appears to not be a PreTrainedModel")
|
||||
|
||||
xm.rendezvous("saving_checkpoint")
|
||||
self.model.save_pretrained(output_dir)
|
||||
|
||||
def _save(self, output_dir: Optional[str] = None):
|
||||
output_dir = output_dir if output_dir is not None else self.args.output_dir
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
@@ -582,6 +630,8 @@ class Trainer:
|
||||
|
||||
output = self._prediction_loop(eval_dataloader, description="Evaluation")
|
||||
|
||||
self._log(output.metrics)
|
||||
|
||||
if self.args.tpu_metrics_debug:
|
||||
# tpu-comment: Logging debug metrics for PyTorch/XLA (compile, execute times, ops, etc.)
|
||||
xm.master_print(met.metrics_report())
|
||||
@@ -629,7 +679,7 @@ class Trainer:
|
||||
model.eval()
|
||||
|
||||
for inputs in tqdm(dataloader, desc=description):
|
||||
has_labels = any(inputs.get(k) is not None for k in ["labels", "masked_lm_labels"])
|
||||
has_labels = any(inputs.get(k) is not None for k in ["labels", "lm_labels", "masked_lm_labels"])
|
||||
|
||||
for k, v in inputs.items():
|
||||
inputs[k] = v.to(self.args.device)
|
||||
@@ -653,7 +703,7 @@ class Trainer:
|
||||
else:
|
||||
label_ids = np.append(label_ids, inputs["labels"].detach().cpu().numpy(), axis=0)
|
||||
|
||||
if is_tpu_available():
|
||||
if is_tpu_available() and preds is not None and label_ids is not None:
|
||||
# tpu-comment: Get all predictions and labels from all worker shards of eval dataset
|
||||
preds = xm.mesh_reduce("eval_preds", preds, np.concatenate)
|
||||
label_ids = xm.mesh_reduce("eval_out_label_ids", label_ids, np.concatenate)
|
||||
@@ -663,6 +713,11 @@ class Trainer:
|
||||
else:
|
||||
metrics = {}
|
||||
if len(eval_losses) > 0:
|
||||
metrics["loss"] = np.mean(eval_losses)
|
||||
metrics["eval_loss"] = np.mean(eval_losses)
|
||||
|
||||
# Prefix all keys with eval_
|
||||
for key in list(metrics.keys()):
|
||||
if not key.startswith("eval_"):
|
||||
metrics[f"eval_{key}"] = metrics.pop(key)
|
||||
|
||||
return PredictionOutput(predictions=preds, label_ids=label_ids, metrics=metrics)
|
||||
|
||||
@@ -125,7 +125,9 @@ class TFTrainer:
|
||||
in the Tensorflow documentation and those contained in the transformers library.
|
||||
"""
|
||||
if self.args.optimizer_name == "adamw":
|
||||
self.optimizer = create_optimizer(self.args.learning_rate, self.train_steps, self.args.warmup_steps)
|
||||
self.optimizer = create_optimizer(
|
||||
self.args.learning_rate, self.train_steps, self.args.warmup_steps, self.args.end_lr
|
||||
)
|
||||
else:
|
||||
try:
|
||||
self.optimizer = tf.keras.optimizers.get(
|
||||
@@ -139,6 +141,7 @@ class TFTrainer:
|
||||
self.optimizer = tf.keras.optimizers.get(
|
||||
{"class_name": self.args.optimizer_name, "config": {"learning_rate": self.args.learning_rate}}
|
||||
)
|
||||
logger.info("Created an/a {} optimizer".format(self.optimizer))
|
||||
|
||||
def _create_checkpoint_manager(self, max_to_keep: int = 5, load_model: bool = True) -> None:
|
||||
"""
|
||||
@@ -149,6 +152,7 @@ class TFTrainer:
|
||||
load_model: if we want to start the training from the latest checkpoint.
|
||||
"""
|
||||
ckpt = tf.train.Checkpoint(optimizer=self.optimizer, model=self.model)
|
||||
|
||||
self.model.ckpt_manager = tf.train.CheckpointManager(ckpt, PREFIX_CHECKPOINT_DIR, max_to_keep=max_to_keep)
|
||||
|
||||
if load_model:
|
||||
@@ -222,7 +226,11 @@ class TFTrainer:
|
||||
else:
|
||||
metrics = {}
|
||||
|
||||
metrics["loss"] = loss.numpy()
|
||||
metrics["eval_loss"] = loss.numpy()
|
||||
|
||||
for key in list(metrics.keys()):
|
||||
if not key.startswith("eval_"):
|
||||
metrics[f"eval_{key}"] = metrics.pop(key)
|
||||
|
||||
return PredictionOutput(predictions=preds, label_ids=label_ids, metrics=metrics)
|
||||
|
||||
@@ -329,7 +337,7 @@ class TFTrainer:
|
||||
gradients = [(tf.clip_by_value(grad, -self.args.max_grad_norm, self.args.max_grad_norm)) for grad in gradients]
|
||||
vars = self.model.trainable_variables
|
||||
|
||||
if self.args.mode == "token-classification":
|
||||
if self.args.mode in ["token-classification", "question-answering"]:
|
||||
vars = [var for var in self.model.trainable_variables if "pooler" not in var.name]
|
||||
|
||||
self.optimizer.apply_gradients(list(zip(gradients, vars)))
|
||||
@@ -369,7 +377,7 @@ class TFTrainer:
|
||||
per_example_loss, _ = self._run_model(features, labels, True)
|
||||
vars = self.model.trainable_variables
|
||||
|
||||
if self.args.mode == "token-classification":
|
||||
if self.args.mode in ["token-classification", "question-answering"]:
|
||||
vars = [var for var in self.model.trainable_variables if "pooler" not in var.name]
|
||||
|
||||
gradients = self.optimizer.get_gradients(per_example_loss, vars)
|
||||
@@ -386,7 +394,7 @@ class TFTrainer:
|
||||
labels: the batched labels.
|
||||
training: run the model in training mode or not
|
||||
"""
|
||||
if self.args.mode == "sequence-classification" or self.args.mode == "token-classification":
|
||||
if self.args.mode == "text-classification" or self.args.mode == "token-classification":
|
||||
logits = self.model(features, training=training)[0]
|
||||
else:
|
||||
logits = self.model(features, training=training)
|
||||
@@ -396,6 +404,10 @@ class TFTrainer:
|
||||
reduced_logits = tf.boolean_mask(tf.reshape(logits, (-1, shape_list(logits)[2])), active_loss)
|
||||
labels = tf.boolean_mask(tf.reshape(labels, (-1,)), active_loss)
|
||||
loss = self.loss(labels, reduced_logits)
|
||||
elif self.args.mode == "question-answering":
|
||||
start_loss = self.loss(labels["start_position"], logits[0])
|
||||
end_loss = self.loss(labels["end_position"], logits[1])
|
||||
loss = (start_loss + end_loss) / 2.0
|
||||
else:
|
||||
loss = self.loss(labels, logits)
|
||||
|
||||
@@ -425,5 +437,6 @@ class TFTrainer:
|
||||
|
||||
path = os.path.join(self.args.output_dir, "saved_model")
|
||||
|
||||
logger.info("Saving model in {}".format(path))
|
||||
os.makedirs(path, exist_ok=True)
|
||||
self.model.save_pretrained(self.args.output_dir)
|
||||
|
||||
@@ -21,8 +21,8 @@ class TFTrainingArguments(TrainingArguments):
|
||||
},
|
||||
)
|
||||
mode: str = field(
|
||||
default="sequence-classification",
|
||||
metadata={"help": 'Type of task, one of "sequence-classification", "token-classification" '},
|
||||
default="text-classification",
|
||||
metadata={"help": 'Type of task, one of "text-classification", "token-classification", "question-answering"'},
|
||||
)
|
||||
loss_name: str = field(
|
||||
default="SparseCategoricalCrossentropy",
|
||||
@@ -30,6 +30,12 @@ class TFTrainingArguments(TrainingArguments):
|
||||
"help": "Name of a Tensorflow loss. For the list see: https://www.tensorflow.org/api_docs/python/tf/keras/losses"
|
||||
},
|
||||
)
|
||||
tpu_name: str = field(
|
||||
default=None, metadata={"help": "Name of TPU"},
|
||||
)
|
||||
end_lr: float = field(
|
||||
default=0, metadata={"help": "End learning rate for optimizer"},
|
||||
)
|
||||
eval_steps: int = field(default=1000, metadata={"help": "Run an evaluation every X steps."})
|
||||
debug: bool = field(
|
||||
default=False, metadata={"help": "Activate the trace to record computation graphs and profiling information"}
|
||||
@@ -45,7 +51,10 @@ class TFTrainingArguments(TrainingArguments):
|
||||
strategy = tf.distribute.OneDeviceStrategy(device="/cpu:0")
|
||||
else:
|
||||
try:
|
||||
tpu = tf.distribute.cluster_resolver.TPUClusterResolver()
|
||||
if self.tpu_name:
|
||||
tpu = tf.distribute.cluster_resolver.TPUClusterResolver(self.tpu_name)
|
||||
else:
|
||||
tpu = tf.distribute.cluster_resolver.TPUClusterResolver()
|
||||
except ValueError:
|
||||
tpu = None
|
||||
|
||||
|
||||
@@ -690,4 +690,8 @@ class TestSinusoidalPositionalEmbeddings(unittest.TestCase):
|
||||
# test that forward pass is just a lookup, there is no ignore padding logic
|
||||
input_ids = torch.tensor([[4, 10, pad, pad, pad]], dtype=torch.long, device=torch_device)
|
||||
no_cache_pad_zero = emb1(input_ids)
|
||||
self.assertTrue(torch.allclose(torch.Tensor(self.desired_weights), no_cache_pad_zero[:3, :5], atol=1e-3))
|
||||
self.assertTrue(
|
||||
torch.allclose(
|
||||
torch.tensor(self.desired_weights, device=torch_device), no_cache_pad_zero[:3, :5], atol=1e-3
|
||||
)
|
||||
)
|
||||
|
||||
@@ -33,15 +33,21 @@ if is_torch_available():
|
||||
MarianTokenizer,
|
||||
MarianMTModel,
|
||||
)
|
||||
from transformers.convert_marian_to_pytorch import (
|
||||
convert_hf_name_to_opus_name,
|
||||
convert_opus_name_to_hf_name,
|
||||
ORG_NAME,
|
||||
)
|
||||
|
||||
|
||||
class ModelManagementTests(unittest.TestCase):
|
||||
@slow
|
||||
def test_model_count(self):
|
||||
def test_model_names(self):
|
||||
model_list = HfApi().model_list()
|
||||
expected_num_models = 1011
|
||||
actual_num_models = len([x for x in model_list if x.modelId.startswith("Helsinki-NLP")])
|
||||
self.assertEqual(expected_num_models, actual_num_models)
|
||||
model_ids = [x.modelId for x in model_list if x.modelId.startswith(ORG_NAME)]
|
||||
bad_model_ids = [mid for mid in model_ids if "+" in model_ids]
|
||||
self.assertListEqual([], bad_model_ids)
|
||||
self.assertGreater(len(model_ids), 500)
|
||||
|
||||
|
||||
@require_torch
|
||||
@@ -91,12 +97,12 @@ class MarianIntegrationTest(unittest.TestCase):
|
||||
self.assertListEqual(self.expected_text, generated_words)
|
||||
|
||||
def translate_src_text(self, **tokenizer_kwargs):
|
||||
model_inputs: dict = self.tokenizer.prepare_translation_batch(src_texts=self.src_text, **tokenizer_kwargs).to(
|
||||
model_inputs = self.tokenizer.prepare_translation_batch(src_texts=self.src_text, **tokenizer_kwargs).to(
|
||||
torch_device
|
||||
)
|
||||
self.assertEqual(self.model.device, model_inputs["input_ids"].device)
|
||||
self.assertEqual(self.model.device, model_inputs.input_ids.device)
|
||||
generated_ids = self.model.generate(
|
||||
model_inputs["input_ids"], attention_mask=model_inputs["attention_mask"], num_beams=2
|
||||
model_inputs.input_ids, attention_mask=model_inputs.attention_mask, num_beams=2
|
||||
)
|
||||
generated_words = self.tokenizer.batch_decode(generated_ids, skip_special_tokens=True)
|
||||
return generated_words
|
||||
@@ -106,10 +112,10 @@ class TestMarian_EN_DE_More(MarianIntegrationTest):
|
||||
@slow
|
||||
def test_forward(self):
|
||||
src, tgt = ["I am a small frog"], ["Ich bin ein kleiner Frosch."]
|
||||
expected = [38, 121, 14, 697, 38848, 0]
|
||||
expected_ids = [38, 121, 14, 697, 38848, 0]
|
||||
|
||||
model_inputs: dict = self.tokenizer.prepare_translation_batch(src, tgt_texts=tgt).to(torch_device)
|
||||
self.assertListEqual(expected, model_inputs["input_ids"][0].tolist())
|
||||
self.assertListEqual(expected_ids, model_inputs.input_ids[0].tolist())
|
||||
|
||||
desired_keys = {
|
||||
"input_ids",
|
||||
@@ -125,20 +131,19 @@ class TestMarian_EN_DE_More(MarianIntegrationTest):
|
||||
|
||||
def test_tokenizer_equivalence(self):
|
||||
batch = self.tokenizer.prepare_translation_batch(["I am a small frog"]).to(torch_device)
|
||||
input_ids = batch["input_ids"][0]
|
||||
expected = [38, 121, 14, 697, 38848, 0]
|
||||
self.assertListEqual(expected, input_ids.tolist())
|
||||
self.assertListEqual(expected, batch.input_ids[0].tolist())
|
||||
|
||||
def test_unk_support(self):
|
||||
t = self.tokenizer
|
||||
ids = t.prepare_translation_batch(["||"]).to(torch_device)["input_ids"][0].tolist()
|
||||
ids = t.prepare_translation_batch(["||"]).to(torch_device).input_ids[0].tolist()
|
||||
expected = [t.unk_token_id, t.unk_token_id, t.eos_token_id]
|
||||
self.assertEqual(expected, ids)
|
||||
|
||||
def test_pad_not_split(self):
|
||||
input_ids_w_pad = self.tokenizer.prepare_translation_batch(["I am a small frog <pad>"])["input_ids"][0]
|
||||
input_ids_w_pad = self.tokenizer.prepare_translation_batch(["I am a small frog <pad>"]).input_ids[0].tolist()
|
||||
expected_w_pad = [38, 121, 14, 697, 38848, self.tokenizer.pad_token_id, 0] # pad
|
||||
self.assertListEqual(expected_w_pad, input_ids_w_pad.tolist())
|
||||
self.assertListEqual(expected_w_pad, input_ids_w_pad)
|
||||
|
||||
@slow
|
||||
def test_batch_generation_en_de(self):
|
||||
@@ -187,9 +192,8 @@ class TestMarian_RU_FR(MarianIntegrationTest):
|
||||
src = "ru"
|
||||
tgt = "fr"
|
||||
src_text = ["Он показал мне рукопись своей новой пьесы."]
|
||||
expected_text = ["Il me montre un manuscrit de sa nouvelle pièce."]
|
||||
expected_text = ["Il m'a montré le manuscrit de sa nouvelle pièce."]
|
||||
|
||||
@slow
|
||||
def test_batch_generation_ru_fr(self):
|
||||
self._assert_generated_batch_equal_expected()
|
||||
|
||||
@@ -197,36 +201,59 @@ class TestMarian_RU_FR(MarianIntegrationTest):
|
||||
class TestMarian_MT_EN(MarianIntegrationTest):
|
||||
src = "mt"
|
||||
tgt = "en"
|
||||
src_text = ["Il - Babiloniżi b'mod żbaljat ikkonkludew li l - Alla l - veru kien dgħajjef."]
|
||||
expected_text = ["The Babylonians wrongly concluded that the true God was weak."]
|
||||
src_text = ["Billi messu b'mod ġentili, Ġesù fejjaq raġel li kien milqut bil - marda kerha tal - ġdiem."]
|
||||
expected_text = ["Touching gently, Jesus healed a man who was affected by the sad disease of leprosy."]
|
||||
|
||||
@unittest.skip("") # Known Issue: This model generates a string of .... at the end of the translation.
|
||||
def test_batch_generation_mt_en(self):
|
||||
self._assert_generated_batch_equal_expected()
|
||||
|
||||
|
||||
class TestMarian_DE_Multi(MarianIntegrationTest):
|
||||
src = "de"
|
||||
tgt = "ch_group"
|
||||
src_text = ["Er aber sprach: Das ist die Gottlosigkeit."]
|
||||
class TestMarian_en_ROMANCE(MarianIntegrationTest):
|
||||
"""Multilingual on target side."""
|
||||
|
||||
src = "en"
|
||||
tgt = "ROMANCE"
|
||||
src_text = [
|
||||
">>fr<< Don't spend so much time watching TV.",
|
||||
">>pt<< Your message has been sent.",
|
||||
">>es<< He's two years older than me.",
|
||||
]
|
||||
expected_text = [
|
||||
"Ne passez pas autant de temps à regarder la télé.",
|
||||
"A sua mensagem foi enviada.",
|
||||
"Es dos años más viejo que yo.",
|
||||
]
|
||||
|
||||
@slow
|
||||
def test_translation_de_multi_does_not_error(self):
|
||||
self.translate_src_text()
|
||||
|
||||
@unittest.skip("") # "Language codes are not yet supported."
|
||||
def test_batch_generation_de_multi_tgt(self):
|
||||
def test_batch_generation_en_ROMANCE_multi(self):
|
||||
self._assert_generated_batch_equal_expected()
|
||||
|
||||
@unittest.skip("") # "Language codes are not yet supported."
|
||||
def test_lang_code(self):
|
||||
t = "Er aber sprach"
|
||||
zh_code = self.code
|
||||
tok_fn = self.tokenizer.prepare_translation_batch
|
||||
pass_code = tok_fn(src_texts=[t], tgt_lang_code=zh_code)["input_ids"][0]
|
||||
preprocess_with_code = tok_fn(src_texts=[zh_code + " " + t])["input_ids"][0]
|
||||
self.assertListEqual(pass_code.tolist(), preprocess_with_code.tolist())
|
||||
for code in self.tokenizer.supported_language_codes:
|
||||
self.assertIn(code, self.tokenizer.encoder)
|
||||
pass_only_code = tok_fn(src_texts=[""], tgt_lang_code=zh_code)["input_ids"][0].tolist()
|
||||
self.assertListEqual(pass_only_code, [self.tokenizer.encoder[zh_code], self.tokenizer.eos_token_id])
|
||||
def test_tokenizer_handles_empty(self):
|
||||
normalized = self.tokenizer.normalize("")
|
||||
self.assertIsInstance(normalized, str)
|
||||
with self.assertRaises(ValueError):
|
||||
self.tokenizer.prepare_translation_batch([""])
|
||||
|
||||
|
||||
@require_torch
|
||||
class TestConversionUtils(unittest.TestCase):
|
||||
def test_renaming_multilingual(self):
|
||||
old_names = [
|
||||
"opus-mt-cmn+cn+yue+ze_zh+zh_cn+zh_CN+zh_HK+zh_tw+zh_TW+zh_yue+zhs+zht+zh-fi",
|
||||
"opus-mt-cmn+cn-fi", # no group
|
||||
"opus-mt-en-de", # standard name
|
||||
"opus-mt-en-de", # standard name
|
||||
]
|
||||
expected = ["opus-mt-ZH-fi", "opus-mt-cmn_cn-fi", "opus-mt-en-de", "opus-mt-en-de"]
|
||||
self.assertListEqual(expected, [convert_opus_name_to_hf_name(x) for x in old_names])
|
||||
|
||||
def test_undoing_renaming(self):
|
||||
hf_names = ["opus-mt-ZH-fi", "opus-mt-cmn_cn-fi", "opus-mt-en-de", "opus-mt-en-de"]
|
||||
converted_opus_names = [convert_hf_name_to_opus_name(x) for x in hf_names]
|
||||
expected_opus_names = [
|
||||
"cmn+cn+yue+ze_zh+zh_cn+zh_CN+zh_HK+zh_tw+zh_TW+zh_yue+zhs+zht+zh-fi",
|
||||
"cmn+cn-fi",
|
||||
"en-de", # standard name
|
||||
"en-de",
|
||||
]
|
||||
self.assertListEqual(expected_opus_names, converted_opus_names)
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import unittest
|
||||
from os import sep
|
||||
from os.path import dirname, exists
|
||||
from shutil import rmtree
|
||||
|
||||
from tests.utils import require_tf, require_torch
|
||||
from transformers import BertConfig, BertTokenizerFast, FeatureExtractionPipeline
|
||||
from transformers.convert_graph_to_onnx import convert, ensure_valid_input, infer_shapes
|
||||
|
||||
|
||||
class FuncContiguousArgs:
|
||||
def forward(self, input_ids, token_type_ids, attention_mask):
|
||||
return None
|
||||
|
||||
|
||||
class FuncNonContiguousArgs:
|
||||
def forward(self, input_ids, some_other_args, token_type_ids, attention_mask):
|
||||
return None
|
||||
|
||||
|
||||
class OnnxExportTestCase(unittest.TestCase):
|
||||
MODEL_TO_TEST = ["bert-base-cased", "gpt2", "roberta-base"]
|
||||
|
||||
@require_tf
|
||||
def test_export_tensorflow(self):
|
||||
for model in OnnxExportTestCase.MODEL_TO_TEST:
|
||||
self._test_export(model, "tf", 11)
|
||||
|
||||
@require_torch
|
||||
def test_export_pytorch(self):
|
||||
for model in OnnxExportTestCase.MODEL_TO_TEST:
|
||||
self._test_export(model, "pt", 11)
|
||||
|
||||
def _test_export(self, model, framework, opset):
|
||||
try:
|
||||
# Compute path
|
||||
path = "onnx" + sep + model + ".onnx"
|
||||
|
||||
# Remove folder if exists
|
||||
if exists(dirname(path)):
|
||||
rmtree(dirname(path))
|
||||
|
||||
# Export
|
||||
convert(framework, model, path, opset)
|
||||
except Exception as e:
|
||||
self.fail(e)
|
||||
|
||||
@require_torch
|
||||
def test_infer_dynamic_axis_pytorch(self):
|
||||
"""
|
||||
Validate the dynamic axis generated for each parameters are correct
|
||||
"""
|
||||
from transformers import BertModel
|
||||
|
||||
model = BertModel(BertConfig.from_pretrained("bert-base-cased"))
|
||||
tokenizer = BertTokenizerFast.from_pretrained("bert-base-cased")
|
||||
self._test_infer_dynamic_axis(model, tokenizer, "pt")
|
||||
|
||||
@require_tf
|
||||
def test_infer_dynamic_axis_tf(self):
|
||||
"""
|
||||
Validate the dynamic axis generated for each parameters are correct
|
||||
"""
|
||||
from transformers import TFBertModel
|
||||
|
||||
model = TFBertModel(BertConfig.from_pretrained("bert-base-cased"))
|
||||
tokenizer = BertTokenizerFast.from_pretrained("bert-base-cased")
|
||||
self._test_infer_dynamic_axis(model, tokenizer, "tf")
|
||||
|
||||
def _test_infer_dynamic_axis(self, model, tokenizer, framework):
|
||||
nlp = FeatureExtractionPipeline(model, tokenizer)
|
||||
|
||||
variable_names = ["input_ids", "token_type_ids", "attention_mask", "output_0", "output_1"]
|
||||
input_vars, output_vars, shapes, tokens = infer_shapes(nlp, framework)
|
||||
|
||||
# Assert all variables are present
|
||||
self.assertEqual(len(shapes), len(variable_names))
|
||||
self.assertTrue(all([var_name in shapes for var_name in variable_names]))
|
||||
self.assertSequenceEqual(variable_names[:3], input_vars)
|
||||
self.assertSequenceEqual(variable_names[3:], output_vars)
|
||||
|
||||
# Assert inputs are {0: batch, 1: sequence}
|
||||
for var_name in ["input_ids", "token_type_ids", "attention_mask"]:
|
||||
self.assertDictEqual(shapes[var_name], {0: "batch", 1: "sequence"})
|
||||
|
||||
# Assert outputs are {0: batch, 1: sequence} and {0: batch}
|
||||
self.assertDictEqual(shapes["output_0"], {0: "batch", 1: "sequence"})
|
||||
self.assertDictEqual(shapes["output_1"], {0: "batch"})
|
||||
|
||||
def test_ensure_valid_input(self):
|
||||
"""
|
||||
Validate parameters are correctly exported
|
||||
GPT2 has "past" parameter in the middle of input_ids, token_type_ids and attention_mask.
|
||||
ONNX doesn't support export with a dictionary, only a tuple. Thus we need to ensure we remove
|
||||
token_type_ids and attention_mask for now to not having a None tensor in the middle
|
||||
"""
|
||||
# All generated args are valid
|
||||
input_names = ["input_ids", "attention_mask", "token_type_ids"]
|
||||
tokens = {"input_ids": [1, 2, 3, 4], "attention_mask": [0, 0, 0, 0], "token_type_ids": [1, 1, 1, 1]}
|
||||
inputs_args = ensure_valid_input(FuncContiguousArgs(), tokens, input_names)
|
||||
|
||||
# Should have exactly the same number of args (all are valid)
|
||||
self.assertEqual(len(inputs_args), 3)
|
||||
|
||||
# Parameter should be reordered according to their respective place in the function:
|
||||
# (input_ids, token_type_ids, attention_mask)
|
||||
self.assertEqual(inputs_args, (tokens["input_ids"], tokens["token_type_ids"], tokens["attention_mask"]))
|
||||
|
||||
# Generated args are interleaved with another args (for instance parameter "past" in GPT2)
|
||||
inputs_args = ensure_valid_input(FuncNonContiguousArgs(), tokens, input_names)
|
||||
|
||||
# Should have exactly the one arg (all before the one not provided "some_other_args")
|
||||
self.assertEqual(len(inputs_args), 1)
|
||||
|
||||
# Should have only "input_ids"
|
||||
self.assertEqual(inputs_args[0], tokens["input_ids"])
|
||||
+137
-250
@@ -2,94 +2,41 @@ import unittest
|
||||
from typing import Iterable, List, Optional
|
||||
|
||||
from transformers import pipeline
|
||||
from transformers.pipelines import DefaultArgumentHandler, Pipeline
|
||||
from transformers.pipelines import SUPPORTED_TASKS, DefaultArgumentHandler, Pipeline
|
||||
|
||||
from .utils import require_tf, require_torch, slow
|
||||
|
||||
|
||||
QA_FINETUNED_MODELS = [
|
||||
(("bert-base-uncased", {"use_fast": False}), "bert-large-uncased-whole-word-masking-finetuned-squad", None),
|
||||
(("distilbert-base-cased-distilled-squad", {"use_fast": False}), "distilbert-base-cased-distilled-squad", None),
|
||||
NER_FINETUNED_MODELS = ["sshleifer/tiny-dbmdz-bert-large-cased-finetuned-conll03-english"]
|
||||
|
||||
# xlnet-base-cased disabled for now, since it crashes TF2
|
||||
FEATURE_EXTRACT_FINETUNED_MODELS = ["sshleifer/tiny-distilbert-base-cased"]
|
||||
TEXT_CLASSIF_FINETUNED_MODELS = ["sshleifer/tiny-distilbert-base-uncased-finetuned-sst-2-english"]
|
||||
TEXT_GENERATION_FINETUNED_MODELS = ["sshleifer/tiny-ctrl"]
|
||||
|
||||
FILL_MASK_FINETUNED_MODELS = ["sshleifer/tiny-distilroberta-base"]
|
||||
LARGE_FILL_MASK_FINETUNED_MODELS = ["distilroberta-base"] # @slow
|
||||
|
||||
SUMMARIZATION_FINETUNED_MODELS = ["sshleifer/bart-tiny-random", "patrickvonplaten/t5-tiny-random"]
|
||||
TF_SUMMARIZATION_FINETUNED_MODELS = ["patrickvonplaten/t5-tiny-random"]
|
||||
|
||||
TRANSLATION_FINETUNED_MODELS = [
|
||||
("patrickvonplaten/t5-tiny-random", "translation_en_to_de"),
|
||||
("patrickvonplaten/t5-tiny-random", "translation_en_to_ro"),
|
||||
]
|
||||
TF_TRANSLATION_FINETUNED_MODELS = [("patrickvonplaten/t5-tiny-random", "translation_en_to_fr")]
|
||||
|
||||
TF_QA_FINETUNED_MODELS = [
|
||||
(("bert-base-uncased", {"use_fast": False}), "bert-large-uncased-whole-word-masking-finetuned-squad", None),
|
||||
(("distilbert-base-cased-distilled-squad", {"use_fast": False}), "distilbert-base-cased-distilled-squad", None),
|
||||
expected_fill_mask_result = [
|
||||
[
|
||||
{"sequence": "<s> My name is:</s>", "score": 0.009954338893294334, "token": 35},
|
||||
{"sequence": "<s> My name is John</s>", "score": 0.0080940006300807, "token": 610},
|
||||
],
|
||||
[
|
||||
{"sequence": "<s> The largest city in France is Paris</s>", "score": 0.3185044229030609, "token": 2201},
|
||||
{"sequence": "<s> The largest city in France is Lyon</s>", "score": 0.21112334728240967, "token": 12790},
|
||||
],
|
||||
]
|
||||
|
||||
TF_NER_FINETUNED_MODELS = {
|
||||
(
|
||||
"bert-base-cased",
|
||||
"dbmdz/bert-large-cased-finetuned-conll03-english",
|
||||
"dbmdz/bert-large-cased-finetuned-conll03-english",
|
||||
)
|
||||
}
|
||||
|
||||
NER_FINETUNED_MODELS = {
|
||||
(
|
||||
"bert-base-cased",
|
||||
"dbmdz/bert-large-cased-finetuned-conll03-english",
|
||||
"dbmdz/bert-large-cased-finetuned-conll03-english",
|
||||
)
|
||||
}
|
||||
|
||||
FEATURE_EXTRACT_FINETUNED_MODELS = {
|
||||
("bert-base-cased", "bert-base-cased", None),
|
||||
# ('xlnet-base-cased', 'xlnet-base-cased', None), # Disabled for now as it crash for TF2
|
||||
("distilbert-base-cased", "distilbert-base-cased", None),
|
||||
}
|
||||
|
||||
TF_FEATURE_EXTRACT_FINETUNED_MODELS = {
|
||||
# ('xlnet-base-cased', 'xlnet-base-cased', None), # Disabled for now as it crash for TF2
|
||||
("distilbert-base-cased", "distilbert-base-cased", None),
|
||||
}
|
||||
|
||||
TF_TEXT_CLASSIF_FINETUNED_MODELS = {
|
||||
(
|
||||
"bert-base-uncased",
|
||||
"distilbert-base-uncased-finetuned-sst-2-english",
|
||||
"distilbert-base-uncased-finetuned-sst-2-english",
|
||||
)
|
||||
}
|
||||
|
||||
TEXT_CLASSIF_FINETUNED_MODELS = {
|
||||
(
|
||||
"distilbert-base-cased",
|
||||
"distilbert-base-uncased-finetuned-sst-2-english",
|
||||
"distilbert-base-uncased-finetuned-sst-2-english",
|
||||
)
|
||||
}
|
||||
|
||||
TEXT_GENERATION_FINETUNED_MODELS = {
|
||||
("gpt2", "gpt2"),
|
||||
("xlnet-base-cased", "xlnet-base-cased"),
|
||||
}
|
||||
|
||||
TF_TEXT_GENERATION_FINETUNED_MODELS = {
|
||||
("gpt2", "gpt2"),
|
||||
("xlnet-base-cased", "xlnet-base-cased"),
|
||||
}
|
||||
|
||||
FILL_MASK_FINETUNED_MODELS = [
|
||||
(("distilroberta-base", {"use_fast": False}), "distilroberta-base", None),
|
||||
]
|
||||
|
||||
TF_FILL_MASK_FINETUNED_MODELS = [
|
||||
(("distilroberta-base", {"use_fast": False}), "distilroberta-base", None),
|
||||
]
|
||||
|
||||
SUMMARIZATION_FINETUNED_MODELS = {
|
||||
("sshleifer/bart-tiny-random", "bart-large-cnn"),
|
||||
("patrickvonplaten/t5-tiny-random", "t5-small"),
|
||||
}
|
||||
TF_SUMMARIZATION_FINETUNED_MODELS = {("patrickvonplaten/t5-tiny-random", "t5-small")}
|
||||
|
||||
TRANSLATION_FINETUNED_MODELS = {
|
||||
("patrickvonplaten/t5-tiny-random", "t5-small", "translation_en_to_de"),
|
||||
("patrickvonplaten/t5-tiny-random", "t5-small", "translation_en_to_ro"),
|
||||
}
|
||||
TF_TRANSLATION_FINETUNED_MODELS = {("patrickvonplaten/t5-tiny-random", "t5-small", "translation_en_to_fr")}
|
||||
|
||||
|
||||
class DefaultArgumentHandlerTestCase(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
@@ -168,8 +115,8 @@ class MonoColumnInputTestCase(unittest.TestCase):
|
||||
self,
|
||||
nlp: Pipeline,
|
||||
valid_inputs: List,
|
||||
invalid_inputs: List,
|
||||
output_keys: Iterable[str],
|
||||
invalid_inputs: List = [None],
|
||||
expected_multi_result: Optional[List] = None,
|
||||
expected_check_keys: Optional[List[str]] = None,
|
||||
):
|
||||
@@ -206,93 +153,61 @@ class MonoColumnInputTestCase(unittest.TestCase):
|
||||
self.assertRaises(Exception, nlp, invalid_inputs)
|
||||
|
||||
@require_torch
|
||||
def test_ner(self):
|
||||
def test_torch_ner(self):
|
||||
mandatory_keys = {"entity", "word", "score"}
|
||||
valid_inputs = ["HuggingFace is solving NLP one commit at a time.", "HuggingFace is based in New-York & Paris"]
|
||||
invalid_inputs = [None]
|
||||
for tokenizer, model, config in NER_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="ner", model=model, config=config, tokenizer=tokenizer)
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, invalid_inputs, mandatory_keys)
|
||||
for model_name in NER_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="ner", model=model_name, tokenizer=model_name)
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, mandatory_keys)
|
||||
|
||||
@require_tf
|
||||
def test_tf_ner(self):
|
||||
mandatory_keys = {"entity", "word", "score"}
|
||||
valid_inputs = ["HuggingFace is solving NLP one commit at a time.", "HuggingFace is based in New-York & Paris"]
|
||||
invalid_inputs = [None]
|
||||
for tokenizer, model, config in TF_NER_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="ner", model=model, config=config, tokenizer=tokenizer, framework="tf")
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, invalid_inputs, mandatory_keys)
|
||||
for model_name in NER_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="ner", model=model_name, tokenizer=model_name, framework="tf")
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, mandatory_keys)
|
||||
|
||||
@require_torch
|
||||
def test_sentiment_analysis(self):
|
||||
def test_torch_sentiment_analysis(self):
|
||||
mandatory_keys = {"label", "score"}
|
||||
valid_inputs = ["HuggingFace is solving NLP one commit at a time.", "HuggingFace is based in New-York & Paris"]
|
||||
invalid_inputs = [None]
|
||||
for tokenizer, model, config in TEXT_CLASSIF_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="sentiment-analysis", model=model, config=config, tokenizer=tokenizer)
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, invalid_inputs, mandatory_keys)
|
||||
for model_name in TEXT_CLASSIF_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="sentiment-analysis", model=model_name, tokenizer=model_name)
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, mandatory_keys)
|
||||
|
||||
@require_tf
|
||||
def test_tf_sentiment_analysis(self):
|
||||
mandatory_keys = {"label", "score"}
|
||||
valid_inputs = ["HuggingFace is solving NLP one commit at a time.", "HuggingFace is based in New-York & Paris"]
|
||||
invalid_inputs = [None]
|
||||
for tokenizer, model, config in TF_TEXT_CLASSIF_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="sentiment-analysis", model=model, config=config, tokenizer=tokenizer, framework="tf")
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, invalid_inputs, mandatory_keys)
|
||||
for model_name in TEXT_CLASSIF_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="sentiment-analysis", model=model_name, tokenizer=model_name, framework="tf")
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, mandatory_keys)
|
||||
|
||||
@require_torch
|
||||
def test_feature_extraction(self):
|
||||
def test_torch_feature_extraction(self):
|
||||
valid_inputs = ["HuggingFace is solving NLP one commit at a time.", "HuggingFace is based in New-York & Paris"]
|
||||
invalid_inputs = [None]
|
||||
for tokenizer, model, config in FEATURE_EXTRACT_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="feature-extraction", model=model, config=config, tokenizer=tokenizer)
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, invalid_inputs, {})
|
||||
for model_name in FEATURE_EXTRACT_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="feature-extraction", model=model_name, tokenizer=model_name)
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, {})
|
||||
|
||||
@require_tf
|
||||
def test_tf_feature_extraction(self):
|
||||
valid_inputs = ["HuggingFace is solving NLP one commit at a time.", "HuggingFace is based in New-York & Paris"]
|
||||
invalid_inputs = [None]
|
||||
for tokenizer, model, config in TF_FEATURE_EXTRACT_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="feature-extraction", model=model, config=config, tokenizer=tokenizer, framework="tf")
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, invalid_inputs, {})
|
||||
for model_name in FEATURE_EXTRACT_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="feature-extraction", model=model_name, tokenizer=model_name, framework="tf")
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, {})
|
||||
|
||||
@require_torch
|
||||
def test_fill_mask(self):
|
||||
def test_torch_fill_mask(self):
|
||||
mandatory_keys = {"sequence", "score", "token"}
|
||||
valid_inputs = [
|
||||
"My name is <mask>",
|
||||
"The largest city in France is <mask>",
|
||||
]
|
||||
invalid_inputs = [None]
|
||||
expected_multi_result = [
|
||||
[
|
||||
{"sequence": "<s> My name is:</s>", "score": 0.009954338893294334, "token": 35},
|
||||
{"sequence": "<s> My name is John</s>", "score": 0.0080940006300807, "token": 610},
|
||||
],
|
||||
[
|
||||
{
|
||||
"sequence": "<s> The largest city in France is Paris</s>",
|
||||
"score": 0.3185044229030609,
|
||||
"token": 2201,
|
||||
},
|
||||
{
|
||||
"sequence": "<s> The largest city in France is Lyon</s>",
|
||||
"score": 0.21112334728240967,
|
||||
"token": 12790,
|
||||
},
|
||||
],
|
||||
]
|
||||
for tokenizer, model, config in FILL_MASK_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="fill-mask", model=model, config=config, tokenizer=tokenizer, topk=2)
|
||||
self._test_mono_column_pipeline(
|
||||
nlp,
|
||||
valid_inputs,
|
||||
invalid_inputs,
|
||||
mandatory_keys,
|
||||
expected_multi_result=expected_multi_result,
|
||||
expected_check_keys=["sequence"],
|
||||
)
|
||||
for model_name in FILL_MASK_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="fill-mask", model=model_name, tokenizer=model_name, framework="pt", topk=2,)
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, mandatory_keys, expected_check_keys=["sequence"])
|
||||
|
||||
@require_tf
|
||||
def test_tf_fill_mask(self):
|
||||
@@ -301,103 +216,117 @@ class MonoColumnInputTestCase(unittest.TestCase):
|
||||
"My name is <mask>",
|
||||
"The largest city in France is <mask>",
|
||||
]
|
||||
invalid_inputs = [None]
|
||||
expected_multi_result = [
|
||||
[
|
||||
{"sequence": "<s> My name is:</s>", "score": 0.009954338893294334, "token": 35},
|
||||
{"sequence": "<s> My name is John</s>", "score": 0.0080940006300807, "token": 610},
|
||||
],
|
||||
[
|
||||
{
|
||||
"sequence": "<s> The largest city in France is Paris</s>",
|
||||
"score": 0.3185044229030609,
|
||||
"token": 2201,
|
||||
},
|
||||
{
|
||||
"sequence": "<s> The largest city in France is Lyon</s>",
|
||||
"score": 0.21112334728240967,
|
||||
"token": 12790,
|
||||
},
|
||||
],
|
||||
for model_name in FILL_MASK_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="fill-mask", model=model_name, tokenizer=model_name, framework="tf", topk=2,)
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, mandatory_keys, expected_check_keys=["sequence"])
|
||||
|
||||
@require_torch
|
||||
@slow
|
||||
def test_torch_fill_mask_results(self):
|
||||
mandatory_keys = {"sequence", "score", "token"}
|
||||
valid_inputs = [
|
||||
"My name is <mask>",
|
||||
"The largest city in France is <mask>",
|
||||
]
|
||||
for tokenizer, model, config in TF_FILL_MASK_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="fill-mask", model=model, config=config, tokenizer=tokenizer, framework="tf", topk=2)
|
||||
for model_name in LARGE_FILL_MASK_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="fill-mask", model=model_name, tokenizer=model_name, framework="pt", topk=2,)
|
||||
self._test_mono_column_pipeline(
|
||||
nlp,
|
||||
valid_inputs,
|
||||
invalid_inputs,
|
||||
mandatory_keys,
|
||||
expected_multi_result=expected_multi_result,
|
||||
expected_multi_result=expected_fill_mask_result,
|
||||
expected_check_keys=["sequence"],
|
||||
)
|
||||
|
||||
@require_tf
|
||||
@slow
|
||||
def test_tf_fill_mask_results(self):
|
||||
mandatory_keys = {"sequence", "score", "token"}
|
||||
valid_inputs = [
|
||||
"My name is <mask>",
|
||||
"The largest city in France is <mask>",
|
||||
]
|
||||
for model_name in LARGE_FILL_MASK_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="fill-mask", model=model_name, tokenizer=model_name, framework="tf", topk=2)
|
||||
self._test_mono_column_pipeline(
|
||||
nlp,
|
||||
valid_inputs,
|
||||
mandatory_keys,
|
||||
expected_multi_result=expected_fill_mask_result,
|
||||
expected_check_keys=["sequence"],
|
||||
)
|
||||
|
||||
@require_torch
|
||||
def test_summarization(self):
|
||||
def test_torch_summarization(self):
|
||||
valid_inputs = ["A string like this", ["list of strings entry 1", "list of strings v2"]]
|
||||
invalid_inputs = [4, "<mask>"]
|
||||
mandatory_keys = ["summary_text"]
|
||||
for model, tokenizer in SUMMARIZATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="summarization", model=model, tokenizer=tokenizer)
|
||||
self._test_mono_column_pipeline(
|
||||
nlp, valid_inputs, invalid_inputs, mandatory_keys,
|
||||
)
|
||||
for model in SUMMARIZATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="summarization", model=model, tokenizer=model)
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, mandatory_keys, invalid_inputs=invalid_inputs)
|
||||
|
||||
@require_tf
|
||||
def test_tf_summarization(self):
|
||||
valid_inputs = ["A string like this", ["list of strings entry 1", "list of strings v2"]]
|
||||
invalid_inputs = [4, "<mask>"]
|
||||
mandatory_keys = ["summary_text"]
|
||||
for model, tokenizer in TF_SUMMARIZATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="summarization", model=model, tokenizer=tokenizer, framework="tf")
|
||||
self._test_mono_column_pipeline(
|
||||
nlp, valid_inputs, invalid_inputs, mandatory_keys,
|
||||
)
|
||||
for model_name in TF_SUMMARIZATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="summarization", model=model_name, tokenizer=model_name, framework="tf",)
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, mandatory_keys, invalid_inputs=invalid_inputs)
|
||||
|
||||
@require_torch
|
||||
def test_translation(self):
|
||||
def test_torch_translation(self):
|
||||
valid_inputs = ["A string like this", ["list of strings entry 1", "list of strings v2"]]
|
||||
invalid_inputs = [4, "<mask>"]
|
||||
mandatory_keys = ["translation_text"]
|
||||
for model, tokenizer, task in TRANSLATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task=task, model=model, tokenizer=tokenizer)
|
||||
self._test_mono_column_pipeline(
|
||||
nlp, valid_inputs, invalid_inputs, mandatory_keys,
|
||||
)
|
||||
for model_name, task in TRANSLATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task=task, model=model_name, tokenizer=model_name)
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, mandatory_keys, invalid_inputs)
|
||||
|
||||
@require_tf
|
||||
@slow
|
||||
def test_tf_translation(self):
|
||||
valid_inputs = ["A string like this", ["list of strings entry 1", "list of strings v2"]]
|
||||
invalid_inputs = [4, "<mask>"]
|
||||
mandatory_keys = ["translation_text"]
|
||||
for model, tokenizer, task in TF_TRANSLATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task=task, model=model, tokenizer=tokenizer, framework="tf")
|
||||
self._test_mono_column_pipeline(
|
||||
nlp, valid_inputs, invalid_inputs, mandatory_keys,
|
||||
)
|
||||
for model, task in TF_TRANSLATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task=task, model=model, tokenizer=model, framework="tf")
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, mandatory_keys, invalid_inputs=invalid_inputs)
|
||||
|
||||
@require_torch
|
||||
def test_text_generation(self):
|
||||
def test_torch_text_generation(self):
|
||||
valid_inputs = ["A string like this", ["list of strings entry 1", "list of strings v2"]]
|
||||
invalid_inputs = [None]
|
||||
for model, tokenizer in TEXT_GENERATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="text-generation", model=model, tokenizer=tokenizer, framework="pt")
|
||||
self._test_mono_column_pipeline(
|
||||
nlp, valid_inputs, invalid_inputs, {},
|
||||
)
|
||||
for model_name in TEXT_GENERATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="text-generation", model=model_name, tokenizer=model_name, framework="pt")
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, {})
|
||||
|
||||
@require_tf
|
||||
def test_tf_text_generation(self):
|
||||
valid_inputs = ["A string like this", ["list of strings entry 1", "list of strings v2"]]
|
||||
invalid_inputs = [None]
|
||||
for model, tokenizer in TF_TEXT_GENERATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="text-generation", model=model, tokenizer=tokenizer, framework="tf")
|
||||
self._test_mono_column_pipeline(
|
||||
nlp, valid_inputs, invalid_inputs, {},
|
||||
)
|
||||
for model_name in TEXT_GENERATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="text-generation", model=model_name, tokenizer=model_name, framework="tf")
|
||||
self._test_mono_column_pipeline(nlp, valid_inputs, {})
|
||||
|
||||
|
||||
class MultiColumnInputTestCase(unittest.TestCase):
|
||||
def _test_multicolumn_pipeline(self, nlp, valid_inputs: list, invalid_inputs: list, output_keys: Iterable[str]):
|
||||
QA_FINETUNED_MODELS = ["sshleifer/tiny-distilbert-base-cased-distilled-squad"]
|
||||
|
||||
|
||||
class QAPipelineTests(unittest.TestCase):
|
||||
def _test_qa_pipeline(self, nlp):
|
||||
output_keys = {"score", "answer", "start", "end"}
|
||||
valid_inputs = [
|
||||
{"question": "Where was HuggingFace founded ?", "context": "HuggingFace was founded in Paris."},
|
||||
{
|
||||
"question": "In what field is HuggingFace working ?",
|
||||
"context": "HuggingFace is a startup based in New-York founded in Paris which is trying to solve NLP.",
|
||||
},
|
||||
]
|
||||
invalid_inputs = [
|
||||
{"question": "", "context": "This is a test to try empty question edge case"},
|
||||
{"question": None, "context": "This is a test to try empty question edge case"},
|
||||
{"question": "What is does with empty context ?", "context": ""},
|
||||
{"question": "What is does with empty context ?", "context": None},
|
||||
]
|
||||
self.assertIsNotNone(nlp)
|
||||
|
||||
mono_result = nlp(valid_inputs[0])
|
||||
@@ -413,75 +342,33 @@ class MultiColumnInputTestCase(unittest.TestCase):
|
||||
for result in multi_result:
|
||||
for key in output_keys:
|
||||
self.assertIn(key, result)
|
||||
|
||||
self.assertRaises(Exception, nlp, invalid_inputs[0])
|
||||
for bad_input in invalid_inputs:
|
||||
self.assertRaises(Exception, nlp, bad_input)
|
||||
self.assertRaises(Exception, nlp, invalid_inputs)
|
||||
|
||||
@require_torch
|
||||
def test_question_answering(self):
|
||||
mandatory_output_keys = {"score", "answer", "start", "end"}
|
||||
valid_samples = [
|
||||
{"question": "Where was HuggingFace founded ?", "context": "HuggingFace was founded in Paris."},
|
||||
{
|
||||
"question": "In what field is HuggingFace working ?",
|
||||
"context": "HuggingFace is a startup based in New-York founded in Paris which is trying to solve NLP.",
|
||||
},
|
||||
]
|
||||
invalid_samples = [
|
||||
{"question": "", "context": "This is a test to try empty question edge case"},
|
||||
{"question": None, "context": "This is a test to try empty question edge case"},
|
||||
{"question": "What is does with empty context ?", "context": ""},
|
||||
{"question": "What is does with empty context ?", "context": None},
|
||||
]
|
||||
|
||||
for tokenizer, model, config in QA_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="question-answering", model=model, config=config, tokenizer=tokenizer)
|
||||
self._test_multicolumn_pipeline(nlp, valid_samples, invalid_samples, mandatory_output_keys)
|
||||
def test_torch_question_answering(self):
|
||||
for model_name in QA_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="question-answering", model=model_name, tokenizer=model_name)
|
||||
self._test_qa_pipeline(nlp)
|
||||
|
||||
@require_tf
|
||||
@slow
|
||||
def test_tf_question_answering(self):
|
||||
mandatory_output_keys = {"score", "answer", "start", "end"}
|
||||
valid_samples = [
|
||||
{"question": "Where was HuggingFace founded ?", "context": "HuggingFace was founded in Paris."},
|
||||
{
|
||||
"question": "In what field is HuggingFace working ?",
|
||||
"context": "HuggingFace is a startup based in New-York founded in Paris which is trying to solve NLP.",
|
||||
},
|
||||
]
|
||||
invalid_samples = [
|
||||
{"question": "", "context": "This is a test to try empty question edge case"},
|
||||
{"question": None, "context": "This is a test to try empty question edge case"},
|
||||
{"question": "What is does with empty context ?", "context": ""},
|
||||
{"question": "What is does with empty context ?", "context": None},
|
||||
]
|
||||
|
||||
for tokenizer, model, config in TF_QA_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="question-answering", model=model, config=config, tokenizer=tokenizer, framework="tf")
|
||||
self._test_multicolumn_pipeline(nlp, valid_samples, invalid_samples, mandatory_output_keys)
|
||||
for model_name in QA_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="question-answering", model=model_name, tokenizer=model_name, framework="tf")
|
||||
self._test_qa_pipeline(nlp)
|
||||
|
||||
|
||||
class PipelineCommonTests(unittest.TestCase):
|
||||
|
||||
pipelines = (
|
||||
"ner",
|
||||
"feature-extraction",
|
||||
"question-answering",
|
||||
"fill-mask",
|
||||
"summarization",
|
||||
"sentiment-analysis",
|
||||
"translation_en_to_fr",
|
||||
"translation_en_to_de",
|
||||
"translation_en_to_ro",
|
||||
"text-generation",
|
||||
)
|
||||
pipelines = SUPPORTED_TASKS.keys()
|
||||
|
||||
@slow
|
||||
@require_tf
|
||||
def test_tf_defaults(self):
|
||||
# Test that pipelines can be correctly loaded without any argument
|
||||
for task in self.pipelines:
|
||||
with self.subTest(msg="Testing Torch defaults with PyTorch and {}".format(task)):
|
||||
with self.subTest(msg="Testing TF defaults with TF and {}".format(task)):
|
||||
pipeline(task, framework="tf")
|
||||
|
||||
@slow
|
||||
|
||||
@@ -19,11 +19,21 @@ import pickle
|
||||
import shutil
|
||||
import tempfile
|
||||
from collections import OrderedDict
|
||||
from typing import Dict, Tuple, Union
|
||||
from typing import TYPE_CHECKING, Dict, Tuple, Union
|
||||
|
||||
from tests.utils import require_tf, require_torch
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from transformers import (
|
||||
PretrainedConfig,
|
||||
PreTrainedTokenizer,
|
||||
PreTrainedTokenizerFast,
|
||||
PreTrainedModel,
|
||||
TFPreTrainedModel,
|
||||
)
|
||||
|
||||
|
||||
def merge_model_tokenizer_mappings(
|
||||
model_mapping: Dict["PretrainedConfig", Union["PreTrainedModel", "TFPreTrainedModel"]],
|
||||
tokenizer_mapping: Dict["PretrainedConfig", Tuple["PreTrainedTokenizer", "PreTrainedTokenizerFast"]],
|
||||
|
||||
@@ -98,7 +98,7 @@ class TrainerIntegrationTest(unittest.TestCase):
|
||||
training_args = TrainingArguments(output_dir="./examples", no_cuda=True)
|
||||
trainer = Trainer(model=model, args=training_args, eval_dataset=eval_dataset)
|
||||
result = trainer.evaluate()
|
||||
self.assertLess(result["loss"], 0.2)
|
||||
self.assertLess(result["eval_loss"], 0.2)
|
||||
|
||||
def test_trainer_eval_lm(self):
|
||||
MODEL_ID = "distilroberta-base"
|
||||
|
||||
Reference in New Issue
Block a user