Compare commits
28
Commits
bert-optim
...
v2.10.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10d72390c0 | ||
|
|
e0db6bbd65 | ||
|
|
bd6e301832 | ||
|
|
a086527727 | ||
|
|
9d2ce253de | ||
|
|
49296533ca | ||
|
|
271bedb485 | ||
|
|
865d4d595e | ||
|
|
a3af8e86cb | ||
|
|
eacea530c1 | ||
|
|
fa2fbed3e5 | ||
|
|
e708bb75bf | ||
|
|
49c06132df | ||
|
|
cacb654c7f | ||
|
|
30a09f3827 | ||
|
|
14cb5b35fa | ||
|
|
6dc52c78d8 | ||
|
|
ed5456daf4 | ||
|
|
c76450e20c | ||
|
|
9907dc523a | ||
|
|
efbc1c5a9d | ||
|
|
956c4c4eb4 | ||
|
|
48c3a70b4e | ||
|
|
aa925a52fa | ||
|
|
5856999a9f | ||
|
|
07dd7c2fd8 | ||
|
|
8f1d047148 | ||
|
|
31eedff5a0 |
No files matched your search
+3
-2
@@ -198,11 +198,12 @@ Follow these steps to start contributing:
|
||||
are useful to avoid duplicated work, and to differentiate it from PRs ready
|
||||
to be merged;
|
||||
4. Make sure existing tests pass;
|
||||
5. Add high-coverage tests. No quality test, no merge.
|
||||
5. Add high-coverage tests. No quality testing = no merge.
|
||||
- If you are adding a new model, make sure that you use `ModelTester.all_model_classes = (MyModel, MyModelWithLMHead,...)`, which triggers the common tests.
|
||||
- If you are adding new `@slow` tests, make sure they pass using `RUN_SLOW=1 python -m pytest tests/test_my_new_model.py`.
|
||||
- If you are adding a new tokenizer, write tests, and make sure `RUN_SLOW=1 python -m pytest tests/test_tokenization_{your_model_name}.py` passes.
|
||||
CircleCI does not run them.
|
||||
6. All public methods must have informative docstrings;
|
||||
6. All public methods must have informative docstrings that work nicely with sphinx. See `modeling_ctrl.py` for an example.
|
||||
|
||||
### Tests
|
||||
|
||||
|
||||
@@ -165,8 +165,9 @@ At some point in the future, you'll be able to seamlessly move from pre-training
|
||||
18. **[DialoGPT](https://huggingface.co/transformers/model_doc/dialogpt.html)** (from Microsoft Research) released with the paper [DialoGPT: Large-Scale Generative Pre-training for Conversational Response Generation](https://arxiv.org/abs/1911.00536) by Yizhe Zhang, Siqi Sun, Michel Galley, Yen-Chun Chen, Chris Brockett, Xiang Gao, Jianfeng Gao, Jingjing Liu, Bill Dolan.
|
||||
19. **[Reformer](https://huggingface.co/transformers/model_doc/reformer.html)** (from Google Research) released with the paper [Reformer: The Efficient Transformer](https://arxiv.org/abs/2001.04451) by Nikita Kitaev, Łukasz Kaiser, Anselm Levskaya.
|
||||
20. **[MarianMT](https://huggingface.co/transformers/model_doc/marian.html)** Machine translation models trained using [OPUS](http://opus.nlpl.eu/) data by Jörg Tiedemann. The [Marian Framework](https://marian-nmt.github.io/) is being developed by the Microsoft Translator Team.
|
||||
21. **[Other community models](https://huggingface.co/models)**, contributed by the [community](https://huggingface.co/users).
|
||||
22. Want to contribute a new model? We have added a **detailed guide and templates** to guide you in the process of adding a new model. You can find them in the [`templates`](./templates) folder of the repository. Be sure to check the [contributing guidelines](./CONTRIBUTING.md) and contact the maintainers or open an issue to collect feedbacks before starting your PR.
|
||||
21. **[Longformer](https://huggingface.co/transformers/model_doc/longformer.html)** (from AllenAI) released with the paper [Longformer: The Long-Document Transformer](https://arxiv.org/abs/2004.05150) by Iz Beltagy, Matthew E. Peters, Arman Cohan.
|
||||
22. **[Other community models](https://huggingface.co/models)**, contributed by the [community](https://huggingface.co/users).
|
||||
23. Want to contribute a new model? We have added a **detailed guide and templates** to guide you in the process of adding a new model. You can find them in the [`templates`](./templates) folder of the repository. Be sure to check the [contributing guidelines](./CONTRIBUTING.md) and contact the maintainers or open an issue to collect feedbacks before starting your PR.
|
||||
|
||||
These implementations have been tested on several datasets (see the example scripts) and should match the performances of the original implementations (e.g. ~93 F1 on SQuAD for BERT Whole-Word-Masking, ~88 F1 on RocStories for OpenAI GPT, ~18.3 perplexity on WikiText 103 for Transformer-XL, ~0.916 Peason R coefficient on STS-B for XLNet). You can find more details on the performances in the Examples section of the [documentation](https://huggingface.co/transformers/examples.html).
|
||||
|
||||
|
||||
+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.1'
|
||||
release = u'2.10.0'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
@@ -109,3 +109,4 @@ The library currently contains PyTorch and Tensorflow implementations, pre-train
|
||||
model_doc/dialogpt
|
||||
model_doc/reformer
|
||||
model_doc/marian
|
||||
model_doc/longformer
|
||||
@@ -0,0 +1,69 @@
|
||||
Longformer
|
||||
----------------------------------------------------
|
||||
**DISCLAIMER:** This model is still a work in progress, if you see something strange,
|
||||
file a `Github Issue <https://github.com/huggingface/transformers/issues/new?assignees=&labels=&template=bug-report.md&title>`_
|
||||
|
||||
Overview
|
||||
~~~~~
|
||||
The Longformer model was presented in `Longformer: The Long-Document Transformer <https://arxiv.org/pdf/2004.05150.pdf>`_ by Iz Beltagy, Matthew E. Peters, Arman Cohan.
|
||||
Here the abstract:
|
||||
|
||||
*Transformer-based models are unable to process long sequences due to their self-attention operation, which scales quadratically with the sequence length. To address this limitation, we introduce the Longformer with an attention mechanism that scales linearly with sequence length, making it easy to process documents of thousands of tokens or longer. Longformer's attention mechanism is a drop-in replacement for the standard self-attention and combines a local windowed attention with a task motivated global attention. Following prior work on long-sequence transformers, we evaluate Longformer on character-level language modeling and achieve state-of-the-art results on text8 and enwik8. In contrast to most prior work, we also pretrain Longformer and finetune it on a variety of downstream tasks. Our pretrained Longformer consistently outperforms RoBERTa on long document tasks and sets new state-of-the-art results on WikiHop and TriviaQA.*
|
||||
|
||||
The Authors' code can be found `here <https://github.com/allenai/longformer>`_ .
|
||||
|
||||
Longformer Self Attention
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
Longformer self attention employs self attention on both a "local" context and a "global" context.
|
||||
Most tokens only attend "locally" to each other meaning that each token attends to its :math:`\frac{1}{2} w` previous tokens and :math:`\frac{1}{2} w` succeding tokens with :math:`w` being the window length as defined in `config.attention_window`. Note that `config.attention_window` can be of type ``list`` to define a different :math:`w` for each layer.
|
||||
A selecetd few tokens attend "globally" to all other tokens, as it is conventionally done for all tokens in *e.g.* `BertSelfAttention`.
|
||||
|
||||
Note that "locally" and "globally" attending tokens are projected by different query, key and value matrices.
|
||||
Also note that every "locally" attending token not only attends to tokens within its window :math:`w`, but also to all "globally" attending tokens so that global attention is *symmetric*.
|
||||
|
||||
The user can define which tokens are masked, which tokens attend "locally" and which tokens attend "globally" by setting the `config.attention_mask` `torch.Tensor` appropriately. In contrast to other models `Longformer` accepts the following values in `config.attention_mask`: `0` - the token is masked and not attended at all (as is done in other models), `1` - the token attends "locally", `2` - token attends "globally". For more information please also refer to :func:`~transformers.LongformerModel.forward` method.
|
||||
|
||||
Using Longformer self attention, the memory and time complexity of the query-key matmul operation, which usually represents the memory and time bottleneck, can be reduced from :math:`\mathcal{O}(n_s \times n_s)` to :math:`\mathcal{O}(n_s \times w)`, with :math:`n_s` being the sequence length and :math:`w` being the average window size. It is assumed that the number of "globally" attending tokens is insignificant as compared to the number of "locally" attending tokens.
|
||||
|
||||
For more information, please refer to the official `paper <https://arxiv.org/pdf/2004.05150.pdf>`_ .
|
||||
|
||||
|
||||
Training
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
``LongformerForMaskedLM`` is trained the exact same way, ``RobertaForMaskedLM`` is trained and
|
||||
should be used as follows:
|
||||
|
||||
::
|
||||
|
||||
input_ids = tokenizer.encode('This is a sentence from [MASK] training data', return_tensors='pt')
|
||||
mlm_labels = tokenizer.encode('This is a sentence from the training data', return_tensors='pt')
|
||||
|
||||
loss = model(input_ids, labels=input_ids, masked_lm_labels=mlm_labels)[0]
|
||||
|
||||
|
||||
LongformerConfig
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.LongformerConfig
|
||||
:members:
|
||||
|
||||
|
||||
LongformerTokenizer
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.LongformerTokenizer
|
||||
:members:
|
||||
|
||||
|
||||
LongformerModel
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.LongformerModel
|
||||
:members:
|
||||
|
||||
|
||||
LongformerForMaskedLM
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.LongformerForMaskedLM
|
||||
:members:
|
||||
@@ -305,3 +305,9 @@ For a list that includes community-uploaded models, refer to `https://huggingfac
|
||||
| MarianMT | ``Helsinki-NLP/opus-mt-{src}-{tgt}`` | | 12-layer, 512-hidden, 8-heads, ~74M parameter Machine translation models. Parameter counts vary depending on vocab size. |
|
||||
| | | | (see `model list <https://huggingface.co/Helsinki-NLP>`_) |
|
||||
+-------------------+------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Longformer | ``longformer-base-4096`` | | 12-layer, 768-hidden, 12-heads, ~149M parameters |
|
||||
| | | | Starting from RoBERTa-base checkpoint, trained on documents of max length 4,096 |
|
||||
| +------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| | ``longformer-large-4096`` | | 24-layer, 1024-hidden, 16-heads, ~435M parameters |
|
||||
| | | | Starting from RoBERTa-large checkpoint, trained on documents of max length 4,096 |
|
||||
+-------------------+------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------+
|
||||
@@ -64,7 +64,7 @@ def print_2d_tensor(tensor):
|
||||
|
||||
|
||||
def compute_heads_importance(
|
||||
args, model, eval_dataloader, compute_entropy=True, compute_importance=True, head_mask=None
|
||||
args, model, eval_dataloader, compute_entropy=True, compute_importance=True, head_mask=None, actually_pruned=False
|
||||
):
|
||||
""" This method shows how to compute:
|
||||
- head attention entropy
|
||||
@@ -77,7 +77,12 @@ def compute_heads_importance(
|
||||
|
||||
if head_mask is None:
|
||||
head_mask = torch.ones(n_layers, n_heads).to(args.device)
|
||||
|
||||
head_mask.requires_grad_(requires_grad=True)
|
||||
# If actually pruned attention multi-head, set head mask to None to avoid shape mismatch
|
||||
if actually_pruned:
|
||||
head_mask = None
|
||||
|
||||
preds = None
|
||||
labels = None
|
||||
tot_tokens = 0.0
|
||||
@@ -172,6 +177,7 @@ def mask_heads(args, model, eval_dataloader):
|
||||
new_head_mask = new_head_mask.view(-1)
|
||||
new_head_mask[current_heads_to_mask] = 0.0
|
||||
new_head_mask = new_head_mask.view_as(head_mask)
|
||||
new_head_mask = new_head_mask.clone().detach()
|
||||
print_2d_tensor(new_head_mask)
|
||||
|
||||
# Compute metric and head importance again
|
||||
@@ -181,7 +187,7 @@ def mask_heads(args, model, eval_dataloader):
|
||||
preds = np.argmax(preds, axis=1) if args.output_mode == "classification" else np.squeeze(preds)
|
||||
current_score = glue_compute_metrics(args.task_name, preds, labels)[args.metric_name]
|
||||
logger.info(
|
||||
"Masking: current score: %f, remaning heads %d (%.1f percents)",
|
||||
"Masking: current score: %f, remaining heads %d (%.1f percents)",
|
||||
current_score,
|
||||
new_head_mask.sum(),
|
||||
new_head_mask.sum() / new_head_mask.numel() * 100,
|
||||
@@ -209,14 +215,23 @@ def prune_heads(args, model, eval_dataloader, head_mask):
|
||||
original_time = datetime.now() - before_time
|
||||
|
||||
original_num_params = sum(p.numel() for p in model.parameters())
|
||||
heads_to_prune = dict((layer, (1 - head_mask[layer].long()).nonzero().tolist()) for layer in range(len(head_mask)))
|
||||
heads_to_prune = dict(
|
||||
(layer, (1 - head_mask[layer].long()).nonzero().squeeze().tolist()) for layer in range(len(head_mask))
|
||||
)
|
||||
|
||||
assert sum(len(h) for h in heads_to_prune.values()) == (1 - head_mask.long()).sum().item()
|
||||
model.prune_heads(heads_to_prune)
|
||||
pruned_num_params = sum(p.numel() for p in model.parameters())
|
||||
|
||||
before_time = datetime.now()
|
||||
_, _, preds, labels = compute_heads_importance(
|
||||
args, model, eval_dataloader, compute_entropy=False, compute_importance=False, head_mask=None
|
||||
args,
|
||||
model,
|
||||
eval_dataloader,
|
||||
compute_entropy=False,
|
||||
compute_importance=False,
|
||||
head_mask=None,
|
||||
actually_pruned=True,
|
||||
)
|
||||
preds = np.argmax(preds, axis=1) if args.output_mode == "classification" else np.squeeze(preds)
|
||||
score_pruning = glue_compute_metrics(args.task_name, preds, labels)[args.metric_name]
|
||||
@@ -404,7 +419,7 @@ def main():
|
||||
logger.info("Training/evaluation parameters %s", args)
|
||||
|
||||
# Prepare dataset for the GLUE task
|
||||
eval_dataset = GlueDataset(args, tokenizer=tokenizer, evaluate=True)
|
||||
eval_dataset = GlueDataset(args, tokenizer=tokenizer, mode="dev")
|
||||
if args.data_subset > 0:
|
||||
eval_dataset = Subset(eval_dataset, list(range(min(args.data_subset, len(eval_dataset)))))
|
||||
eval_sampler = SequentialSampler(eval_dataset) if args.local_rank == -1 else DistributedSampler(eval_dataset)
|
||||
|
||||
@@ -80,7 +80,7 @@ def main():
|
||||
|
||||
# Load a pre-trained model
|
||||
model = TransfoXLLMHeadModel.from_pretrained(args.model_name)
|
||||
model = model.to(device)
|
||||
model.to(device)
|
||||
|
||||
logger.info(
|
||||
"Evaluating with bsz {} tgt_len {} ext_len {} mem_len {} clamp_len {}".format(
|
||||
|
||||
@@ -135,7 +135,8 @@ def main():
|
||||
|
||||
# Get datasets
|
||||
train_dataset = GlueDataset(data_args, tokenizer=tokenizer) if training_args.do_train else None
|
||||
eval_dataset = GlueDataset(data_args, tokenizer=tokenizer, evaluate=True) if training_args.do_eval else None
|
||||
eval_dataset = GlueDataset(data_args, tokenizer=tokenizer, mode="dev") if training_args.do_eval else None
|
||||
test_dataset = GlueDataset(data_args, tokenizer=tokenizer, mode="test") if training_args.do_predict else None
|
||||
|
||||
def compute_metrics(p: EvalPrediction) -> Dict:
|
||||
if output_mode == "classification":
|
||||
@@ -165,7 +166,7 @@ def main():
|
||||
tokenizer.save_pretrained(training_args.output_dir)
|
||||
|
||||
# Evaluation
|
||||
results = {}
|
||||
eval_results = {}
|
||||
if training_args.do_eval:
|
||||
logger.info("*** Evaluate ***")
|
||||
|
||||
@@ -173,10 +174,10 @@ def main():
|
||||
eval_datasets = [eval_dataset]
|
||||
if data_args.task_name == "mnli":
|
||||
mnli_mm_data_args = dataclasses.replace(data_args, task_name="mnli-mm")
|
||||
eval_datasets.append(GlueDataset(mnli_mm_data_args, tokenizer=tokenizer, evaluate=True))
|
||||
eval_datasets.append(GlueDataset(mnli_mm_data_args, tokenizer=tokenizer, mode="dev"))
|
||||
|
||||
for eval_dataset in eval_datasets:
|
||||
result = trainer.evaluate(eval_dataset=eval_dataset)
|
||||
eval_result = trainer.evaluate(eval_dataset=eval_dataset)
|
||||
|
||||
output_eval_file = os.path.join(
|
||||
training_args.output_dir, f"eval_results_{eval_dataset.args.task_name}.txt"
|
||||
@@ -184,13 +185,38 @@ def main():
|
||||
if trainer.is_world_master():
|
||||
with open(output_eval_file, "w") as writer:
|
||||
logger.info("***** Eval results {} *****".format(eval_dataset.args.task_name))
|
||||
for key, value in result.items():
|
||||
for key, value in eval_result.items():
|
||||
logger.info(" %s = %s", key, value)
|
||||
writer.write("%s = %s\n" % (key, value))
|
||||
|
||||
results.update(result)
|
||||
eval_results.update(eval_result)
|
||||
|
||||
return results
|
||||
if training_args.do_predict:
|
||||
logging.info("*** Test ***")
|
||||
test_datasets = [test_dataset]
|
||||
if data_args.task_name == "mnli":
|
||||
mnli_mm_data_args = dataclasses.replace(data_args, task_name="mnli-mm")
|
||||
test_datasets.append(GlueDataset(mnli_mm_data_args, tokenizer=tokenizer, mode="test"))
|
||||
|
||||
for test_dataset in test_datasets:
|
||||
predictions = trainer.predict(test_dataset=test_dataset).predictions
|
||||
if output_mode == "classification":
|
||||
predictions = np.argmax(predictions, axis=1)
|
||||
|
||||
output_test_file = os.path.join(
|
||||
training_args.output_dir, f"test_results_{test_dataset.args.task_name}.txt"
|
||||
)
|
||||
if trainer.is_world_master():
|
||||
with open(output_test_file, "w") as writer:
|
||||
logger.info("***** Test results {} *****".format(test_dataset.args.task_name))
|
||||
writer.write("index\tprediction\n")
|
||||
for index, item in enumerate(predictions):
|
||||
if output_mode == "regression":
|
||||
writer.write("%d\t%3.3f\n" % (index, item))
|
||||
else:
|
||||
item = test_dataset.get_labels()[item]
|
||||
writer.write("%d\t%s\n" % (index, item))
|
||||
return eval_results
|
||||
|
||||
|
||||
def _mp_fn(index):
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
Note: **default code snippet above won't work** because we are using `AlbertTokenizer` with `GPT2LMHeadModel`, see [issue](https://github.com/huggingface/transformers/issues/4285).
|
||||
|
||||
## GPT2 124M Trained on Ukranian Fiction
|
||||
|
||||
Example usage:
|
||||
```python
|
||||
from transformers import AlbertTokenizer, GPT2LMHeadModel
|
||||
|
||||
tokenizer = AlbertTokenizer.from_pretrained("Tereveni-AI/gpt2-124M-uk-fiction")
|
||||
model = GPT2LMHeadModel.from_pretrained("Tereveni-AI/gpt2-124M-uk-fiction")
|
||||
|
||||
input_ids = tokenizer.encode('Но зла Юнона, суча дочка,', add_special_tokens=False, return_tensors='pt')
|
||||
|
||||
outputs = model.generate(
|
||||
input_ids,
|
||||
do_sample=True,
|
||||
num_return_sequences=3,
|
||||
max_length=50
|
||||
)
|
||||
|
||||
for i, out in enumerate(outputs):
|
||||
print('{}: {}'.format(i, tokenizer.decode(out)))
|
||||
```
|
||||
@@ -0,0 +1,43 @@
|
||||
# ReviewBERT
|
||||
|
||||
BERT (post-)trained from review corpus to understand sentiment, options and various e-commence aspects.
|
||||
|
||||
`BERT-DK_laptop` is trained from 100MB laptop corpus under `Electronics/Computers & Accessories/Laptops`.
|
||||
|
||||
|
||||
## Model Description
|
||||
|
||||
The original model is from `BERT-base-uncased` trained from Wikipedia+BookCorpus.
|
||||
Models are post-trained from [Amazon Dataset](http://jmcauley.ucsd.edu/data/amazon/) and [Yelp Dataset](https://www.yelp.com/dataset/challenge/).
|
||||
|
||||
`BERT-DK_laptop` is trained from 100MB laptop corpus under `Electronics/Computers & Accessories/Laptops`.
|
||||
|
||||
## Instructions
|
||||
Loading the post-trained weights are as simple as, e.g.,
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModel, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("activebus/BERT-DK_laptop")
|
||||
model = AutoModel.from_pretrained("activebus/BERT-DK_laptop")
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Evaluation Results
|
||||
|
||||
Check our [NAACL paper](https://www.aclweb.org/anthology/N19-1242.pdf)
|
||||
|
||||
|
||||
## Citation
|
||||
If you find this work useful, please cite as following.
|
||||
```
|
||||
@inproceedings{xu_bert2019,
|
||||
title = "BERT Post-Training for Review Reading Comprehension and Aspect-based Sentiment Analysis",
|
||||
author = "Xu, Hu and Liu, Bing and Shu, Lei and Yu, Philip S.",
|
||||
booktitle = "Proceedings of the 2019 Conference of the North American Chapter of the Association for Computational Linguistics",
|
||||
month = "jun",
|
||||
year = "2019",
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,41 @@
|
||||
# ReviewBERT
|
||||
|
||||
BERT (post-)trained from review corpus to understand sentiment, options and various e-commence aspects.
|
||||
|
||||
`BERT-DK_rest` is trained from 1G (19 types) restaurants from Yelp.
|
||||
|
||||
## Model Description
|
||||
|
||||
The original model is from `BERT-base-uncased` trained from Wikipedia+BookCorpus.
|
||||
Models are post-trained from [Amazon Dataset](http://jmcauley.ucsd.edu/data/amazon/) and [Yelp Dataset](https://www.yelp.com/dataset/challenge/).
|
||||
|
||||
|
||||
## Instructions
|
||||
Loading the post-trained weights are as simple as, e.g.,
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModel, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("activebus/BERT-DK_rest")
|
||||
model = AutoModel.from_pretrained("activebus/BERT-DK_rest")
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Evaluation Results
|
||||
|
||||
Check our [NAACL paper](https://www.aclweb.org/anthology/N19-1242.pdf)
|
||||
|
||||
|
||||
## Citation
|
||||
If you find this work useful, please cite as following.
|
||||
```
|
||||
@inproceedings{xu_bert2019,
|
||||
title = "BERT Post-Training for Review Reading Comprehension and Aspect-based Sentiment Analysis",
|
||||
author = "Xu, Hu and Liu, Bing and Shu, Lei and Yu, Philip S.",
|
||||
booktitle = "Proceedings of the 2019 Conference of the North American Chapter of the Association for Computational Linguistics",
|
||||
month = "jun",
|
||||
year = "2019",
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,41 @@
|
||||
# ReviewBERT
|
||||
|
||||
BERT (post-)trained from review corpus to understand sentiment, options and various e-commence aspects.
|
||||
|
||||
`BERT-DK_laptop` is trained from 100MB laptop corpus under `Electronics/Computers & Accessories/Laptops`.
|
||||
`BERT-PT_*` addtionally uses SQuAD 1.1.
|
||||
|
||||
## Model Description
|
||||
|
||||
The original model is from `BERT-base-uncased` trained from Wikipedia+BookCorpus.
|
||||
Models are post-trained from [Amazon Dataset](http://jmcauley.ucsd.edu/data/amazon/) and [Yelp Dataset](https://www.yelp.com/dataset/challenge/).
|
||||
|
||||
|
||||
## Instructions
|
||||
Loading the post-trained weights are as simple as, e.g.,
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModel, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("activebus/BERT-PT_laptop")
|
||||
model = AutoModel.from_pretrained("activebus/BERT-PT_laptop")
|
||||
|
||||
```
|
||||
|
||||
## Evaluation Results
|
||||
|
||||
Check our [NAACL paper](https://www.aclweb.org/anthology/N19-1242.pdf)
|
||||
|
||||
|
||||
## Citation
|
||||
If you find this work useful, please cite as following.
|
||||
```
|
||||
@inproceedings{xu_bert2019,
|
||||
title = "BERT Post-Training for Review Reading Comprehension and Aspect-based Sentiment Analysis",
|
||||
author = "Xu, Hu and Liu, Bing and Shu, Lei and Yu, Philip S.",
|
||||
booktitle = "Proceedings of the 2019 Conference of the North American Chapter of the Association for Computational Linguistics",
|
||||
month = "jun",
|
||||
year = "2019",
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,42 @@
|
||||
# ReviewBERT
|
||||
|
||||
BERT (post-)trained from review corpus to understand sentiment, options and various e-commence aspects.
|
||||
|
||||
`BERT-DK_rest` is trained from 1G (19 types) restaurants from Yelp.
|
||||
`BERT-PT_*` addtionally uses SQuAD 1.1.
|
||||
|
||||
## Model Description
|
||||
|
||||
The original model is from `BERT-base-uncased` trained from Wikipedia+BookCorpus.
|
||||
Models are post-trained from [Amazon Dataset](http://jmcauley.ucsd.edu/data/amazon/) and [Yelp Dataset](https://www.yelp.com/dataset/challenge/).
|
||||
|
||||
|
||||
## Instructions
|
||||
Loading the post-trained weights are as simple as, e.g.,
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModel, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("activebus/BERT-PT_rest")
|
||||
model = AutoModel.from_pretrained("activebus/BERT-PT_rest")
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Evaluation Results
|
||||
|
||||
Check our [NAACL paper](https://www.aclweb.org/anthology/N19-1242.pdf)
|
||||
|
||||
|
||||
## Citation
|
||||
If you find this work useful, please cite as following.
|
||||
```
|
||||
@inproceedings{xu_bert2019,
|
||||
title = "BERT Post-Training for Review Reading Comprehension and Aspect-based Sentiment Analysis",
|
||||
author = "Xu, Hu and Liu, Bing and Shu, Lei and Yu, Philip S.",
|
||||
booktitle = "Proceedings of the 2019 Conference of the North American Chapter of the Association for Computational Linguistics",
|
||||
month = "jun",
|
||||
year = "2019",
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
# ReviewBERT
|
||||
|
||||
BERT (post-)trained from review corpus to understand sentiment, options and various e-commence aspects.
|
||||
Please visit https://github.com/howardhsu/BERT-for-RRC-ABSA for details.
|
||||
|
||||
`BERT-XD_Review` is a cross-domain (beyond just `laptop` and `restaurant`) language model, where each example is from a single product / restaurant with the same rating, post-trained (fine-tuned) on a combination of 5-core Amazon reviews and all Yelp data, expected to be 22 G in total. It is trained for 4 epochs on `bert-base-uncased`.
|
||||
The preprocessing code [here](https://github.com/howardhsu/BERT-for-RRC-ABSA/transformers).
|
||||
|
||||
## Model Description
|
||||
|
||||
The original model is from `BERT-base-uncased`.
|
||||
Models are post-trained from [Amazon Dataset](http://jmcauley.ucsd.edu/data/amazon/) and [Yelp Dataset](https://www.yelp.com/dataset/challenge/).
|
||||
|
||||
|
||||
## Instructions
|
||||
Loading the post-trained weights are as simple as, e.g.,
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModel, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("activebus/BERT-XD_Review")
|
||||
model = AutoModel.from_pretrained("activebus/BERT-XD_Review")
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Evaluation Results
|
||||
|
||||
Check our [NAACL paper](https://www.aclweb.org/anthology/N19-1242.pdf)
|
||||
`BERT_Review` is expected to have similar performance on domain-specific tasks (such as aspect extraction) as `BERT-DK`, but much better on general tasks such as aspect sentiment classification (different domains mostly share similar sentiment words).
|
||||
|
||||
|
||||
## Citation
|
||||
If you find this work useful, please cite as following.
|
||||
```
|
||||
@inproceedings{xu_bert2019,
|
||||
title = "BERT Post-Training for Review Reading Comprehension and Aspect-based Sentiment Analysis",
|
||||
author = "Xu, Hu and Liu, Bing and Shu, Lei and Yu, Philip S.",
|
||||
booktitle = "Proceedings of the 2019 Conference of the North American Chapter of the Association for Computational Linguistics",
|
||||
month = "jun",
|
||||
year = "2019",
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
# ReviewBERT
|
||||
|
||||
BERT (post-)trained from review corpus to understand sentiment, options and various e-commence aspects.
|
||||
|
||||
`BERT_Review` is cross-domain (beyond just `laptop` and `restaurant`) language model with one example from randomly mixed domains, post-trained (fine-tuned) on a combination of 5-core Amazon reviews and all Yelp data, expected to be 22 G in total. It is trained for 4 epochs on `bert-base-uncased`.
|
||||
The preprocessing code [here](https://github.com/howardhsu/BERT-for-RRC-ABSA/transformers).
|
||||
|
||||
|
||||
## Model Description
|
||||
|
||||
The original model is from `BERT-base-uncased` trained from Wikipedia+BookCorpus.
|
||||
Models are post-trained from [Amazon Dataset](http://jmcauley.ucsd.edu/data/amazon/) and [Yelp Dataset](https://www.yelp.com/dataset/challenge/).
|
||||
|
||||
|
||||
## Instructions
|
||||
Loading the post-trained weights are as simple as, e.g.,
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModel, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("activebus/BERT_Review")
|
||||
model = AutoModel.from_pretrained("activebus/BERT_Review")
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Evaluation Results
|
||||
|
||||
Check our [NAACL paper](https://www.aclweb.org/anthology/N19-1242.pdf)
|
||||
`BERT_Review` is expected to have similar performance on domain-specific tasks (such as aspect extraction) as `BERT-DK`, but much better on general tasks such as aspect sentiment classification (different domains mostly share similar sentiment words).
|
||||
|
||||
|
||||
## Citation
|
||||
If you find this work useful, please cite as following.
|
||||
```
|
||||
@inproceedings{xu_bert2019,
|
||||
title = "BERT Post-Training for Review Reading Comprehension and Aspect-based Sentiment Analysis",
|
||||
author = "Xu, Hu and Liu, Bing and Shu, Lei and Yu, Philip S.",
|
||||
booktitle = "Proceedings of the 2019 Conference of the North American Chapter of the Association for Computational Linguistics",
|
||||
month = "jun",
|
||||
year = "2019",
|
||||
}
|
||||
```
|
||||
@@ -18,13 +18,16 @@ tags:
|
||||
**Eval data:** Conll03 (NER), GermEval14 (NER), GermEval18 (Classification), GNAD (Classification)
|
||||
**Infrastructure**: 1x TPU v2
|
||||
**Published**: Jun 14th, 2019
|
||||
|
||||
**Update April 3rd, 2020**: we updated the vocabulary file on deepset's s3 to conform with the default tokenization of punctuation tokens.
|
||||
For details see the related [FARM issue](https://github.com/deepset-ai/FARM/issues/60). If you want to use the old vocab we have also uploaded a ["deepset/bert-base-german-cased-oldvocab"](https://huggingface.co/deepset/bert-base-german-cased-oldvocab) model.
|
||||
|
||||
## Details
|
||||
- We trained using Google's Tensorflow code on a single cloud TPU v2 with standard settings.
|
||||
- We trained 810k steps with a batch size of 1024 for sequence length 128 and 30k steps with sequence length 512. Training took about 9 days.
|
||||
- As training data we used the latest German Wikipedia dump (6GB of raw txt files), the OpenLegalData dump (2.4 GB) and news articles (3.6 GB).
|
||||
- We cleaned the data dumps with tailored scripts and segmented sentences with spacy v2.1. To create tensorflow records we used the recommended sentencepiece library for creating the word piece vocabulary and tensorflow scripts to convert the text to data usable by BERT.
|
||||
- Update April 3rd, 2020: updated the vocab file on deepset s3 to adjust tokenization of punctuation.
|
||||
|
||||
|
||||
See https://deepset.ai/german-bert for more details
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
language: german
|
||||
thumbnail: https://static.tildacdn.com/tild6438-3730-4164-b266-613634323466/german_bert.png
|
||||
tags:
|
||||
- exbert
|
||||
---
|
||||
|
||||
<a href="https://huggingface.co/exbert/?model=bert-base-german-cased">
|
||||
<img width="300px" src="https://hf-dinosaur.huggingface.co/exbert/button.png">
|
||||
</a>
|
||||
|
||||
# German BERT with old vocabulary
|
||||
For details see the related [FARM issue](https://github.com/deepset-ai/FARM/issues/60).
|
||||
|
||||
|
||||
## About us
|
||||

|
||||
|
||||
We bring NLP to the industry via open source!
|
||||
Our focus: Industry specific language models & large scale QA systems.
|
||||
|
||||
Some of our work:
|
||||
- [German BERT (aka "bert-base-german-cased")](https://deepset.ai/german-bert)
|
||||
- [FARM](https://github.com/deepset-ai/FARM)
|
||||
- [Haystack](https://github.com/deepset-ai/haystack/)
|
||||
|
||||
Get in touch:
|
||||
[Twitter](https://twitter.com/deepset_ai) | [LinkedIn](https://www.linkedin.com/company/deepset-ai/) | [Website](https://deepset.ai)
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
language: spanish
|
||||
thumbnail:
|
||||
---
|
||||
|
||||
# RuPERTa-base (Spanish RoBERTa) + NER 🎃🏷
|
||||
|
||||
This model is a fine-tuned on [NER-C](https://www.kaggle.com/nltkdata/conll-corpora) version of [RuPERTa-base](https://huggingface.co/mrm8488/RuPERTa-base) for **NER** downstream task.
|
||||
|
||||
## Details of the downstream task (NER) - Dataset
|
||||
|
||||
- [Dataset: CONLL Corpora ES](https://www.kaggle.com/nltkdata/conll-corpora) 📚
|
||||
|
||||
| Dataset | # Examples |
|
||||
| ---------------------- | ----- |
|
||||
| Train | 329 K |
|
||||
| Dev | 40 K |
|
||||
|
||||
|
||||
- [Fine-tune on NER script provided by Huggingface](https://github.com/huggingface/transformers/blob/master/examples/token-classification/run_ner.py)
|
||||
|
||||
- Labels covered:
|
||||
|
||||
```
|
||||
B-LOC
|
||||
B-MISC
|
||||
B-ORG
|
||||
B-PER
|
||||
I-LOC
|
||||
I-MISC
|
||||
I-ORG
|
||||
I-PER
|
||||
O
|
||||
```
|
||||
|
||||
## Metrics on evaluation set 🧾
|
||||
|
||||
| Metric | # score |
|
||||
| :------------------------------------------------------------------------------------: | :-------: |
|
||||
| F1 | **77.55**
|
||||
| Precision | **75.53** |
|
||||
| Recall | **79.68** |
|
||||
|
||||
## Model in action 🔨
|
||||
|
||||
|
||||
Example of usage:
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModelForTokenClassification, AutoTokenizer
|
||||
|
||||
id2label = {
|
||||
"0": "B-LOC",
|
||||
"1": "B-MISC",
|
||||
"2": "B-ORG",
|
||||
"3": "B-PER",
|
||||
"4": "I-LOC",
|
||||
"5": "I-MISC",
|
||||
"6": "I-ORG",
|
||||
"7": "I-PER",
|
||||
"8": "O"
|
||||
}
|
||||
|
||||
text ="Julien, CEO de HF, nació en Francia."
|
||||
input_ids = torch.tensor(tokenizer.encode(text)).unsqueeze(0)
|
||||
|
||||
outputs = model(input_ids)
|
||||
last_hidden_states = outputs[0]
|
||||
|
||||
for m in last_hidden_states:
|
||||
for index, n in enumerate(m):
|
||||
if(index > 0 and index <= len(text.split(" "))):
|
||||
print(text.split(" ")[index-1] + ": " + id2label[str(torch.argmax(n).item())])
|
||||
|
||||
'''
|
||||
Output:
|
||||
--------
|
||||
Julien,: I-PER
|
||||
CEO: O
|
||||
de: O
|
||||
HF,: B-ORG
|
||||
nació: I-PER
|
||||
en: I-PER
|
||||
Francia.: I-LOC
|
||||
'''
|
||||
```
|
||||
Yeah! Not too bad 🎉
|
||||
|
||||
> Created by [Manuel Romero/@mrm8488](https://twitter.com/mrm8488)
|
||||
|
||||
> Made with <span style="color: #e25555;">♥</span> in Spain
|
||||
@@ -0,0 +1,111 @@
|
||||
---
|
||||
language: spanish
|
||||
thumbnail:
|
||||
---
|
||||
|
||||
# RuPERTa-base (Spanish RoBERTa) + POS 🎃🏷
|
||||
|
||||
This model is a fine-tuned on [CONLL CORPORA](https://www.kaggle.com/nltkdata/conll-corpora) version of [RuPERTa-base](https://huggingface.co/mrm8488/RuPERTa-base) for **POS** downstream task.
|
||||
|
||||
## Details of the downstream task (POS) - Dataset
|
||||
|
||||
- [Dataset: CONLL Corpora ES](https://www.kaggle.com/nltkdata/conll-corpora) 📚
|
||||
|
||||
| Dataset | # Examples |
|
||||
| ---------------------- | ----- |
|
||||
| Train | 445 K |
|
||||
| Dev | 55 K |
|
||||
|
||||
- [Fine-tune on NER script provided by Huggingface](https://github.com/huggingface/transformers/blob/master/examples/token-classification/run_ner.py)
|
||||
|
||||
- Labels covered:
|
||||
|
||||
```
|
||||
ADJ
|
||||
ADP
|
||||
ADV
|
||||
AUX
|
||||
CCONJ
|
||||
DET
|
||||
INTJ
|
||||
NOUN
|
||||
NUM
|
||||
PART
|
||||
PRON
|
||||
PROPN
|
||||
PUNCT
|
||||
SCONJ
|
||||
SYM
|
||||
VERB
|
||||
```
|
||||
|
||||
## Metrics on evaluation set 🧾
|
||||
|
||||
| Metric | # score |
|
||||
| :------------------------------------------------------------------------------------: | :-------: |
|
||||
| F1 | **97.39**
|
||||
| Precision | **97.47** |
|
||||
| Recall | **9732** |
|
||||
|
||||
## Model in action 🔨
|
||||
|
||||
|
||||
Example of usage
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModelForTokenClassification, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained('mrm8488/RuPERTa-base-finetuned-pos')
|
||||
model = AutoModelForTokenClassification.from_pretrained('mrm8488/RuPERTa-base-finetuned-pos')
|
||||
|
||||
id2label = {
|
||||
"0": "O",
|
||||
"1": "ADJ",
|
||||
"2": "ADP",
|
||||
"3": "ADV",
|
||||
"4": "AUX",
|
||||
"5": "CCONJ",
|
||||
"6": "DET",
|
||||
"7": "INTJ",
|
||||
"8": "NOUN",
|
||||
"9": "NUM",
|
||||
"10": "PART",
|
||||
"11": "PRON",
|
||||
"12": "PROPN",
|
||||
"13": "PUNCT",
|
||||
"14": "SCONJ",
|
||||
"15": "SYM",
|
||||
"16": "VERB"
|
||||
}
|
||||
|
||||
text ="Mis amigos están pensando viajar a Londres este verano."
|
||||
input_ids = torch.tensor(tokenizer.encode(text)).unsqueeze(0)
|
||||
|
||||
outputs = model(input_ids)
|
||||
last_hidden_states = outputs[0]
|
||||
|
||||
for m in last_hidden_states:
|
||||
for index, n in enumerate(m):
|
||||
if(index > 0 and index <= len(text.split(" "))):
|
||||
print(text.split(" ")[index-1] + ": " + id2label[str(torch.argmax(n).item())])
|
||||
|
||||
'''
|
||||
Output:
|
||||
--------
|
||||
Mis: NUM
|
||||
amigos: PRON
|
||||
están: AUX
|
||||
pensando: ADV
|
||||
viajar: VERB
|
||||
a: ADP
|
||||
Londres: PROPN
|
||||
este: DET
|
||||
verano..: NOUN
|
||||
'''
|
||||
```
|
||||
Yeah! Not too bad 🎉
|
||||
|
||||
> Created by [Manuel Romero/@mrm8488](https://twitter.com/mrm8488) | [LinkedIn](https://www.linkedin.com/in/manuel-romero-cs/)
|
||||
|
||||
> Made with <span style="color: #e25555;">♥</span> in Spain
|
||||
@@ -5,12 +5,12 @@ https://huggingface.co/savasy/bert-base-turkish-sentiment-cased
|
||||
This model is used for Sentiment Analysis, which is based on BERTurk for Turkish Language https://huggingface.co/dbmdz/bert-base-turkish-cased
|
||||
|
||||
|
||||
# Dataset
|
||||
## Dataset
|
||||
|
||||
The dataset is taken from the studies [2] and [3] and merged.
|
||||
The dataset is taken from the studies [[2]](#paper-2) and [[3]](#paper-3), and merged.
|
||||
|
||||
* The study [2] gathered movie and product reviews. The products are book, DVD, electronics, and kitchen.
|
||||
The movie dataset is taken from a cinema Web page (www.beyazperde.com) with
|
||||
The movie dataset is taken from a cinema Web page ([Beyazperde](www.beyazperde.com)) with
|
||||
5331 positive and 5331 negative sentences. Reviews in the Web page are marked in
|
||||
scale from 0 to 5 by the users who made the reviews. The study considered a review
|
||||
sentiment positive if the rating is equal to or bigger than 4, and negative if it is less
|
||||
@@ -19,9 +19,9 @@ Web page. They constructed benchmark dataset consisting of reviews regarding som
|
||||
products (book, DVD, etc.). Likewise, reviews are marked in the range from 1 to 5,
|
||||
and majority class of reviews are 5. Each category has 700 positive and 700 negative
|
||||
reviews in which average rating of negative reviews is 2.27 and of positive reviews
|
||||
is 4.5. This dataset is also used the study [1]
|
||||
is 4.5. This dataset is also used by the study [[1]](#paper-1).
|
||||
|
||||
* The study[3] collected tweet dataset. They proposed a new approach for automatically classifying the sentiment of microblog messages. The proposed approach is based on utilizing robust feature representation and fusion.
|
||||
* The study [[3]](#paper-3) collected tweet dataset. They proposed a new approach for automatically classifying the sentiment of microblog messages. The proposed approach is based on utilizing robust feature representation and fusion.
|
||||
|
||||
*Merged Dataset*
|
||||
|
||||
@@ -32,20 +32,21 @@ is 4.5. This dataset is also used the study [1]
|
||||
| 32000 |train.tsv|
|
||||
| *48290* |*total*|
|
||||
|
||||
### The dataset is used by following papers
|
||||
|
||||
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
|
||||
<a id="paper-1">[1]</a> Yildirim, Savaş. (2020). Comparing Deep Neural Networks to Traditional Models for Sentiment Analysis in Turkish Language. 10.1007/978-981-15-1216-2_12.
|
||||
|
||||
<a id="paper-2">[2]</a> 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)
|
||||
* [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
|
||||
<a id="paper-3">[3]</a> 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
|
||||
|
||||
```shell
|
||||
export GLUE_DIR="./sst-2-newall"
|
||||
export TASK_NAME=SST-2
|
||||
|
||||
|
||||
python3 run_glue.py \
|
||||
--model_type bert \
|
||||
@@ -59,88 +60,79 @@ python3 run_glue.py \
|
||||
--learning_rate 2e-5 \
|
||||
--num_train_epochs 3.0 \
|
||||
--output_dir "./model"
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Results
|
||||
|
||||
> 05/10/2020 17:00:43 - INFO - transformers.trainer - \*\*\*\*\* Running Evaluation \*\*\*\*\*
|
||||
> 05/10/2020 17:00:43 - INFO - transformers.trainer - Num examples = 7999
|
||||
> 05/10/2020 17:00:43 - INFO - transformers.trainer - Batch size = 8
|
||||
> Evaluation: 100% 1000/1000 [00:34<00:00, 29.04it/s]
|
||||
> 05/10/2020 17:01:17 - INFO - \_\_main__ - \*\*\*\*\* Eval results sst-2 \*\*\*\*\*
|
||||
> 05/10/2020 17:01:17 - INFO - \_\_main__ - acc = 0.9539942492811602
|
||||
> 05/10/2020 17:01:17 - INFO - \_\_main__ - loss = 0.16348013816401363
|
||||
|
||||
Accuracy is about **95.4%**
|
||||
|
||||
|
||||
# Results
|
||||
## Code Usage
|
||||
|
||||
> 05/10/2020 17:00:43 - INFO - transformers.trainer - ***** Running Evaluation *****
|
||||
|
||||
> 05/10/2020 17:00:43 - INFO - transformers.trainer - Num examples = 7999
|
||||
|
||||
> 05/10/2020 17:00:43 - INFO - transformers.trainer - Batch size = 8
|
||||
|
||||
>Evaluation: 100% 1000/1000 [00:34<00:00, 29.04it/s]
|
||||
|
||||
>05/10/2020 17:01:17 - INFO - __main__ - ***** Eval results sst-2 *****
|
||||
|
||||
>05/10/2020 17:01:17 - INFO - __main__ - acc = 0.9539942492811602
|
||||
|
||||
>05/10/2020 17:01:17 - INFO - __main__ - loss = 0.16348013816401363
|
||||
|
||||
|
||||
Accuracy is about *%95.4*
|
||||
# Code Usage
|
||||
|
||||
```
|
||||
```python
|
||||
from transformers import AutoModelForSequenceClassification, AutoTokenizer, pipeline
|
||||
|
||||
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)
|
||||
|
||||
p= sa("bu telefon modelleri çok kaliteli , her parçası çok özel bence")
|
||||
p = sa("bu telefon modelleri çok kaliteli , her parçası çok özel bence")
|
||||
print(p)
|
||||
#[{'label': 'LABEL_1', 'score': 0.9871089}]
|
||||
print (p[0]['label']=='LABEL_1')
|
||||
#True
|
||||
# [{'label': 'LABEL_1', 'score': 0.9871089}]
|
||||
print(p[0]['label'] == 'LABEL_1')
|
||||
# True
|
||||
|
||||
|
||||
p= sa("Film çok kötü ve çok sahteydi")
|
||||
p = sa("Film çok kötü ve çok sahteydi")
|
||||
print(p)
|
||||
#[{'label': 'LABEL_0', 'score': 0.9975505}]
|
||||
print (p[0]['label']=='LABEL_1')
|
||||
#False
|
||||
# [{'label': 'LABEL_0', 'score': 0.9975505}]
|
||||
print(p[0]['label'] == 'LABEL_1')
|
||||
# False
|
||||
```
|
||||
|
||||
# Test your data
|
||||
|
||||
## Test
|
||||
### Data
|
||||
|
||||
Suppose your file has lots of lines of comment and label (1 or 0) at the end (tab seperated)
|
||||
|
||||
> comment1 ... \t label
|
||||
|
||||
> comment2 ... \t label
|
||||
|
||||
> comment1 ... \t label
|
||||
> comment2 ... \t label
|
||||
> ...
|
||||
|
||||
### Code
|
||||
|
||||
|
||||
```
|
||||
```python
|
||||
from transformers import AutoModelForSequenceClassification, AutoTokenizer, pipeline
|
||||
|
||||
f="/path/to/your/file/yourfile.tsv"
|
||||
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)
|
||||
sa = pipeline("sentiment-analysis", tokenizer=tokenizer, model=model)
|
||||
|
||||
i,crr=0,0
|
||||
for line in open(f):
|
||||
lines=line.strip().split("\t")
|
||||
if len(lines)==2:
|
||||
i=i+1
|
||||
if i%100==0:
|
||||
print(i)
|
||||
pred= sa(lines[0])
|
||||
pred=pred[0]["label"].split("_")[1]
|
||||
if pred== lines[1]:
|
||||
crr=crr+1
|
||||
input_file = "/path/to/your/file/yourfile.tsv"
|
||||
|
||||
i, crr = 0, 0
|
||||
for line in open(input_file):
|
||||
lines = line.strip().split("\t")
|
||||
if len(lines) == 2:
|
||||
|
||||
i = i + 1
|
||||
if i%100 == 0:
|
||||
print(i)
|
||||
|
||||
pred = sa(lines[0])
|
||||
pred = pred[0]["label"].split("_")[1]
|
||||
|
||||
if pred == lines[1]:
|
||||
crr = crr + 1
|
||||
|
||||
print(crr, i, crr/i)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+3
-1
@@ -23,4 +23,6 @@ Pull Request so it can be included under the Community notebooks.
|
||||
|
||||
| Notebook | Description | Author | |
|
||||
|:----------|:-------------|:-------------|------:|
|
||||
| [Train T5 on TPU](https://github.com/patil-suraj/exploring-T5/blob/master/T5_on_TPU.ipynb) | How to train T5 on SQUAD with transformers and nlp | [Suraj Patil](https://github.com/patil-suraj) |[](https://colab.research.google.com/github/patil-suraj/exploring-T5/blob/master/T5_on_TPU.ipynb#scrollTo=QLGiFCDqvuil) |
|
||||
| [Train T5 on TPU](https://github.com/patil-suraj/exploring-T5/blob/master/T5_on_TPU.ipynb) | How to train T5 on SQUAD with Transformers and Nlp | [Suraj Patil](https://github.com/patil-suraj) |[](https://colab.research.google.com/github/patil-suraj/exploring-T5/blob/master/T5_on_TPU.ipynb#scrollTo=QLGiFCDqvuil) |
|
||||
| [Fine-tune T5 for Classification and Multiple Choice](https://github.com/patil-suraj/exploring-T5/blob/master/t5_fine_tuning.ipynb) | How to fine-tune T5 for classification and multiple choice tasks using a text-to-text format with PyTorch Lightning | [Suraj Patil](https://github.com/patil-suraj) | [](https://colab.research.google.com/github/patil-suraj/exploring-T5/blob/master/t5_fine_tuning.ipynb) |
|
||||
| [Fine-tune DialoGPT on New Datasets and Languages](https://github.com/ncoop57/i-am-a-nerd/blob/master/_notebooks/2020-05-12-chatbot-part-1.ipynb) | How to fine-tune the DialoGPT model on a new dataset for open-dialog conversational chatbots | [Nathan Cooper](https://github.com/ncoop57) | [](https://colab.research.google.com/github/ncoop57/i-am-a-nerd/blob/master/_notebooks/2020-05-12-chatbot-part-1.ipynb)
|
||||
@@ -71,13 +71,13 @@ extras["sklearn"] = ["scikit-learn"]
|
||||
# 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"
|
||||
"onnxconverter-common",
|
||||
"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"
|
||||
"onnxconverter-common",
|
||||
"keras2onnx"
|
||||
]
|
||||
extras["torch"] = ["torch"]
|
||||
|
||||
@@ -88,15 +88,15 @@ extras["testing"] = ["pytest", "pytest-xdist", "timeout-decorator"]
|
||||
extras["docs"] = ["recommonmark", "sphinx", "sphinx-markdown-tables", "sphinx-rtd-theme"]
|
||||
extras["quality"] = [
|
||||
"black",
|
||||
"isort @ git+git://github.com/timothycrosley/isort.git@e63ae06ec7d70b06df9e528357650281a3d3ec22#egg=isort",
|
||||
"isort",
|
||||
"flake8",
|
||||
]
|
||||
extras["dev"] = extras["testing"] + extras["quality"] + ["mecab-python3", "scikit-learn", "tensorflow", "torch"]
|
||||
|
||||
setup(
|
||||
name="transformers",
|
||||
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",
|
||||
version="2.10.0",
|
||||
author="Thomas Wolf, Lysandre Debut, Victor Sanh, Julien Chaumond, Sam Shleifer, Patrick von Platen, 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",
|
||||
long_description=open("README.md", "r", encoding="utf-8").read(),
|
||||
|
||||
@@ -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.1"
|
||||
__version__ = "2.10.0"
|
||||
|
||||
# Work around to update TensorFlow's absl.logging threshold which alters the
|
||||
# default Python logging output behavior when present.
|
||||
@@ -44,6 +44,7 @@ from .configuration_electra import ELECTRA_PRETRAINED_CONFIG_ARCHIVE_MAP, Electr
|
||||
from .configuration_encoder_decoder import EncoderDecoderConfig
|
||||
from .configuration_flaubert import FLAUBERT_PRETRAINED_CONFIG_ARCHIVE_MAP, FlaubertConfig
|
||||
from .configuration_gpt2 import GPT2_PRETRAINED_CONFIG_ARCHIVE_MAP, GPT2Config
|
||||
from .configuration_longformer import LONGFORMER_PRETRAINED_CONFIG_ARCHIVE_MAP, LongformerConfig
|
||||
from .configuration_marian import MarianConfig
|
||||
from .configuration_mmbt import MMBTConfig
|
||||
from .configuration_openai import OPENAI_GPT_PRETRAINED_CONFIG_ARCHIVE_MAP, OpenAIGPTConfig
|
||||
@@ -138,6 +139,7 @@ from .tokenization_distilbert import DistilBertTokenizer, DistilBertTokenizerFas
|
||||
from .tokenization_electra import ElectraTokenizer, ElectraTokenizerFast
|
||||
from .tokenization_flaubert import FlaubertTokenizer
|
||||
from .tokenization_gpt2 import GPT2Tokenizer, GPT2TokenizerFast
|
||||
from .tokenization_longformer import LongformerTokenizer
|
||||
from .tokenization_openai import OpenAIGPTTokenizer, OpenAIGPTTokenizerFast
|
||||
from .tokenization_reformer import ReformerTokenizer
|
||||
from .tokenization_roberta import RobertaTokenizer, RobertaTokenizerFast
|
||||
@@ -319,6 +321,7 @@ if is_torch_available():
|
||||
ElectraForMaskedLM,
|
||||
ElectraForTokenClassification,
|
||||
ElectraPreTrainedModel,
|
||||
ElectraForSequenceClassification,
|
||||
ElectraModel,
|
||||
load_tf_weights_in_electra,
|
||||
ELECTRA_PRETRAINED_MODEL_ARCHIVE_MAP,
|
||||
@@ -332,6 +335,8 @@ if is_torch_available():
|
||||
REFORMER_PRETRAINED_MODEL_ARCHIVE_MAP,
|
||||
)
|
||||
|
||||
from .modeling_longformer import LONGFORMER_PRETRAINED_MODEL_ARCHIVE_MAP, LongformerModel, LongformerForMaskedLM
|
||||
|
||||
# Optimization
|
||||
from .optimization import (
|
||||
AdamW,
|
||||
|
||||
@@ -28,6 +28,7 @@ from .configuration_electra import ELECTRA_PRETRAINED_CONFIG_ARCHIVE_MAP, Electr
|
||||
from .configuration_encoder_decoder import EncoderDecoderConfig
|
||||
from .configuration_flaubert import FLAUBERT_PRETRAINED_CONFIG_ARCHIVE_MAP, FlaubertConfig
|
||||
from .configuration_gpt2 import GPT2_PRETRAINED_CONFIG_ARCHIVE_MAP, GPT2Config
|
||||
from .configuration_longformer import LONGFORMER_PRETRAINED_CONFIG_ARCHIVE_MAP, LongformerConfig
|
||||
from .configuration_marian import MarianConfig
|
||||
from .configuration_openai import OPENAI_GPT_PRETRAINED_CONFIG_ARCHIVE_MAP, OpenAIGPTConfig
|
||||
from .configuration_reformer import ReformerConfig
|
||||
@@ -62,6 +63,7 @@ ALL_PRETRAINED_CONFIG_ARCHIVE_MAP = dict(
|
||||
XLM_ROBERTA_PRETRAINED_CONFIG_ARCHIVE_MAP,
|
||||
FLAUBERT_PRETRAINED_CONFIG_ARCHIVE_MAP,
|
||||
ELECTRA_PRETRAINED_CONFIG_ARCHIVE_MAP,
|
||||
LONGFORMER_PRETRAINED_CONFIG_ARCHIVE_MAP,
|
||||
]
|
||||
for key, value, in pretrained_map.items()
|
||||
)
|
||||
@@ -77,6 +79,7 @@ CONFIG_MAPPING = OrderedDict(
|
||||
("marian", MarianConfig,),
|
||||
("bart", BartConfig,),
|
||||
("reformer", ReformerConfig,),
|
||||
("longformer", LongformerConfig,),
|
||||
("roberta", RobertaConfig,),
|
||||
("flaubert", FlaubertConfig,),
|
||||
("bert", BertConfig,),
|
||||
@@ -133,6 +136,7 @@ class AutoConfig:
|
||||
- contains `albert`: :class:`~transformers.AlbertConfig` (ALBERT model)
|
||||
- contains `camembert`: :class:`~transformers.CamembertConfig` (CamemBERT model)
|
||||
- contains `xlm-roberta`: :class:`~transformers.XLMRobertaConfig` (XLM-RoBERTa model)
|
||||
- contains `longformer`: :class:`~transformers.LongformerConfig` (Longformer model)
|
||||
- contains `roberta`: :class:`~transformers.RobertaConfig` (RoBERTa model)
|
||||
- contains `reformer`: :class:`~transformers.ReformerConfig` (Reformer model)
|
||||
- contains `bert`: :class:`~transformers.BertConfig` (Bert model)
|
||||
@@ -145,7 +149,6 @@ class AutoConfig:
|
||||
- contains `flaubert` : :class:`~transformers.FlaubertConfig` (Flaubert model)
|
||||
- contains `electra` : :class:`~transformers.ElectraConfig` (ELECTRA model)
|
||||
|
||||
|
||||
Args:
|
||||
pretrained_model_name_or_path (:obj:`string`):
|
||||
Is either: \
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2020 The Allen Institute for AI team and The HuggingFace Inc. team.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
""" Longformer configuration """
|
||||
|
||||
import logging
|
||||
from typing import List, Union
|
||||
|
||||
from .configuration_roberta import RobertaConfig
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
LONGFORMER_PRETRAINED_CONFIG_ARCHIVE_MAP = {
|
||||
"longformer-base-4096": "https://s3.amazonaws.com/models.huggingface.co/bert/allenai/longformer-base-4096/config.json",
|
||||
"longformer-large-4096": "https://s3.amazonaws.com/models.huggingface.co/bert/allenai/longformer-large-4096/config.json",
|
||||
}
|
||||
|
||||
|
||||
class LongformerConfig(RobertaConfig):
|
||||
r"""
|
||||
This is the configuration class to store the configuration of an :class:`~transformers.LongformerModel`.
|
||||
It is used to instantiate an Longformer model according to the specified arguments, defining the model
|
||||
architecture. Instantiating a configuration with the defaults will yield a similar configuration to that of
|
||||
the RoBERTa `roberta-base <https://huggingface.co/roberta-base>`__ architecture with a sequence length 4,096.
|
||||
|
||||
The :class:`~transformers.LongformerConfig` class directly inherits :class:`~transformers.RobertaConfig`.
|
||||
It reuses the same defaults. Please check the parent class for more information.
|
||||
|
||||
Args:
|
||||
attention_window (:obj:`int` or :obj:`List[int]`, optional, defaults to 512):
|
||||
Size of an attention window around each token. If :obj:`int`, use the same size for all layers.
|
||||
To specify a different window size for each layer, use a :obj:`List[int]` where
|
||||
``len(attention_window) == num_hidden_layers``.
|
||||
|
||||
Example::
|
||||
|
||||
from transformers import LongformerConfig, LongformerModel
|
||||
|
||||
# Initializing a Longformer configuration
|
||||
configuration = LongformerConfig()
|
||||
|
||||
# Initializing a model from the configuration
|
||||
model = LongformerModel(configuration)
|
||||
|
||||
# Accessing the model configuration
|
||||
configuration = model.config
|
||||
|
||||
Attributes:
|
||||
pretrained_config_archive_map (Dict[str, str]):
|
||||
A dictionary containing all the available pre-trained checkpoints.
|
||||
"""
|
||||
pretrained_config_archive_map = LONGFORMER_PRETRAINED_CONFIG_ARCHIVE_MAP
|
||||
model_type = "longformer"
|
||||
|
||||
def __init__(self, attention_window: Union[List[int], int] = 512, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.attention_window = attention_window
|
||||
@@ -103,7 +103,7 @@ def load_graph_from_args(framework: str, model: str, tokenizer: Optional[str] =
|
||||
print("Loading pipeline (model: {}, tokenizer: {})".format(model, tokenizer))
|
||||
|
||||
# Allocate tokenizer and model
|
||||
return pipeline("feature-extraction", model=model, framework=framework)
|
||||
return pipeline("feature-extraction", model=model, tokenizer=tokenizer, framework=framework)
|
||||
|
||||
|
||||
def convert_pytorch(nlp: Pipeline, opset: int, output: str, use_external_format: bool):
|
||||
|
||||
@@ -2,7 +2,8 @@ import logging
|
||||
import os
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from typing import List, Optional
|
||||
from enum import Enum
|
||||
from typing import List, Optional, Union
|
||||
|
||||
import torch
|
||||
from filelock import FileLock
|
||||
@@ -47,6 +48,12 @@ class GlueDataTrainingArguments:
|
||||
self.task_name = self.task_name.lower()
|
||||
|
||||
|
||||
class Split(Enum):
|
||||
train = "train"
|
||||
dev = "dev"
|
||||
test = "test"
|
||||
|
||||
|
||||
class GlueDataset(Dataset):
|
||||
"""
|
||||
This will be superseded by a framework-agnostic approach
|
||||
@@ -62,16 +69,21 @@ class GlueDataset(Dataset):
|
||||
args: GlueDataTrainingArguments,
|
||||
tokenizer: PreTrainedTokenizer,
|
||||
limit_length: Optional[int] = None,
|
||||
evaluate=False,
|
||||
mode: Union[str, Split] = Split.train,
|
||||
):
|
||||
self.args = args
|
||||
processor = glue_processors[args.task_name]()
|
||||
self.processor = glue_processors[args.task_name]()
|
||||
self.output_mode = glue_output_modes[args.task_name]
|
||||
if isinstance(mode, str):
|
||||
try:
|
||||
mode = Split[mode]
|
||||
except KeyError:
|
||||
raise KeyError("mode is not a valid split name")
|
||||
# Load data features from cache or dataset file
|
||||
cached_features_file = os.path.join(
|
||||
args.data_dir,
|
||||
"cached_{}_{}_{}_{}".format(
|
||||
"dev" if evaluate else "train", tokenizer.__class__.__name__, str(args.max_seq_length), args.task_name,
|
||||
mode.value, tokenizer.__class__.__name__, str(args.max_seq_length), args.task_name,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -88,7 +100,7 @@ class GlueDataset(Dataset):
|
||||
)
|
||||
else:
|
||||
logger.info(f"Creating features from dataset file at {args.data_dir}")
|
||||
label_list = processor.get_labels()
|
||||
label_list = self.processor.get_labels()
|
||||
if args.task_name in ["mnli", "mnli-mm"] and tokenizer.__class__ in (
|
||||
RobertaTokenizer,
|
||||
RobertaTokenizerFast,
|
||||
@@ -96,11 +108,12 @@ class GlueDataset(Dataset):
|
||||
):
|
||||
# HACK(label indices are swapped in RoBERTa pretrained model)
|
||||
label_list[1], label_list[2] = label_list[2], label_list[1]
|
||||
examples = (
|
||||
processor.get_dev_examples(args.data_dir)
|
||||
if evaluate
|
||||
else processor.get_train_examples(args.data_dir)
|
||||
)
|
||||
if mode == Split.dev:
|
||||
examples = self.processor.get_dev_examples(args.data_dir)
|
||||
elif mode == Split.test:
|
||||
examples = self.processor.get_test_examples(args.data_dir)
|
||||
else:
|
||||
examples = self.processor.get_train_examples(args.data_dir)
|
||||
if limit_length is not None:
|
||||
examples = examples[:limit_length]
|
||||
self.features = glue_convert_examples_to_features(
|
||||
@@ -122,3 +135,6 @@ class GlueDataset(Dataset):
|
||||
|
||||
def __getitem__(self, i) -> InputFeatures:
|
||||
return self.features[i]
|
||||
|
||||
def get_labels(self):
|
||||
return self.processor.get_labels()
|
||||
@@ -126,7 +126,9 @@ def _glue_convert_examples_to_features(
|
||||
|
||||
label_map = {label: i for i, label in enumerate(label_list)}
|
||||
|
||||
def label_from_example(example: InputExample) -> Union[int, float]:
|
||||
def label_from_example(example: InputExample) -> Union[int, float, None]:
|
||||
if example.label is None:
|
||||
return None
|
||||
if output_mode == "classification":
|
||||
return label_map[example.label]
|
||||
elif output_mode == "regression":
|
||||
@@ -180,12 +182,16 @@ class MrpcProcessor(DataProcessor):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")
|
||||
|
||||
def get_test_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")
|
||||
|
||||
def get_labels(self):
|
||||
"""See base class."""
|
||||
return ["0", "1"]
|
||||
|
||||
def _create_examples(self, lines, set_type):
|
||||
"""Creates examples for the training and dev sets."""
|
||||
"""Creates examples for the training, dev and test sets."""
|
||||
examples = []
|
||||
for (i, line) in enumerate(lines):
|
||||
if i == 0:
|
||||
@@ -193,7 +199,7 @@ class MrpcProcessor(DataProcessor):
|
||||
guid = "%s-%s" % (set_type, i)
|
||||
text_a = line[3]
|
||||
text_b = line[4]
|
||||
label = line[0]
|
||||
label = None if set_type == "test" else line[0]
|
||||
examples.append(InputExample(guid=guid, text_a=text_a, text_b=text_b, label=label))
|
||||
return examples
|
||||
|
||||
@@ -218,12 +224,16 @@ class MnliProcessor(DataProcessor):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "dev_matched.tsv")), "dev_matched")
|
||||
|
||||
def get_test_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "test_matched.tsv")), "test_matched")
|
||||
|
||||
def get_labels(self):
|
||||
"""See base class."""
|
||||
return ["contradiction", "entailment", "neutral"]
|
||||
|
||||
def _create_examples(self, lines, set_type):
|
||||
"""Creates examples for the training and dev sets."""
|
||||
"""Creates examples for the training, dev and test sets."""
|
||||
examples = []
|
||||
for (i, line) in enumerate(lines):
|
||||
if i == 0:
|
||||
@@ -231,7 +241,7 @@ class MnliProcessor(DataProcessor):
|
||||
guid = "%s-%s" % (set_type, line[0])
|
||||
text_a = line[8]
|
||||
text_b = line[9]
|
||||
label = line[-1]
|
||||
label = None if set_type.startswith("test") else line[-1]
|
||||
examples.append(InputExample(guid=guid, text_a=text_a, text_b=text_b, label=label))
|
||||
return examples
|
||||
|
||||
@@ -241,7 +251,11 @@ class MnliMismatchedProcessor(MnliProcessor):
|
||||
|
||||
def get_dev_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "dev_mismatched.tsv")), "dev_matched")
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "dev_mismatched.tsv")), "dev_mismatched")
|
||||
|
||||
def get_test_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "test_mismatched.tsv")), "test_mismatched")
|
||||
|
||||
|
||||
class ColaProcessor(DataProcessor):
|
||||
@@ -264,17 +278,25 @@ class ColaProcessor(DataProcessor):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")
|
||||
|
||||
def get_test_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")
|
||||
|
||||
def get_labels(self):
|
||||
"""See base class."""
|
||||
return ["0", "1"]
|
||||
|
||||
def _create_examples(self, lines, set_type):
|
||||
"""Creates examples for the training and dev sets."""
|
||||
"""Creates examples for the training, dev and test sets."""
|
||||
test_mode = set_type == "test"
|
||||
if test_mode:
|
||||
lines = lines[1:]
|
||||
text_index = 1 if test_mode else 3
|
||||
examples = []
|
||||
for (i, line) in enumerate(lines):
|
||||
guid = "%s-%s" % (set_type, i)
|
||||
text_a = line[3]
|
||||
label = line[1]
|
||||
text_a = line[text_index]
|
||||
label = None if test_mode else line[1]
|
||||
examples.append(InputExample(guid=guid, text_a=text_a, text_b=None, label=label))
|
||||
return examples
|
||||
|
||||
@@ -299,19 +321,23 @@ class Sst2Processor(DataProcessor):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")
|
||||
|
||||
def get_test_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")
|
||||
|
||||
def get_labels(self):
|
||||
"""See base class."""
|
||||
return ["0", "1"]
|
||||
|
||||
def _create_examples(self, lines, set_type):
|
||||
"""Creates examples for the training and dev sets."""
|
||||
"""Creates examples for the training, dev and test sets."""
|
||||
examples = []
|
||||
for (i, line) in enumerate(lines):
|
||||
if i == 0:
|
||||
continue
|
||||
guid = "%s-%s" % (set_type, i)
|
||||
text_a = line[0]
|
||||
label = line[1]
|
||||
label = None if set_type == "test" else line[1]
|
||||
examples.append(InputExample(guid=guid, text_a=text_a, text_b=None, label=label))
|
||||
return examples
|
||||
|
||||
@@ -336,12 +362,16 @@ class StsbProcessor(DataProcessor):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")
|
||||
|
||||
def get_test_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")
|
||||
|
||||
def get_labels(self):
|
||||
"""See base class."""
|
||||
return [None]
|
||||
|
||||
def _create_examples(self, lines, set_type):
|
||||
"""Creates examples for the training and dev sets."""
|
||||
"""Creates examples for the training, dev and test sets."""
|
||||
examples = []
|
||||
for (i, line) in enumerate(lines):
|
||||
if i == 0:
|
||||
@@ -349,7 +379,7 @@ class StsbProcessor(DataProcessor):
|
||||
guid = "%s-%s" % (set_type, line[0])
|
||||
text_a = line[7]
|
||||
text_b = line[8]
|
||||
label = line[-1]
|
||||
label = None if set_type == "test" else line[-1]
|
||||
examples.append(InputExample(guid=guid, text_a=text_a, text_b=text_b, label=label))
|
||||
return examples
|
||||
|
||||
@@ -374,21 +404,28 @@ class QqpProcessor(DataProcessor):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")
|
||||
|
||||
def get_test_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")
|
||||
|
||||
def get_labels(self):
|
||||
"""See base class."""
|
||||
return ["0", "1"]
|
||||
|
||||
def _create_examples(self, lines, set_type):
|
||||
"""Creates examples for the training and dev sets."""
|
||||
"""Creates examples for the training, dev and test sets."""
|
||||
test_mode = set_type == "test"
|
||||
q1_index = 1 if test_mode else 3
|
||||
q2_index = 2 if test_mode else 4
|
||||
examples = []
|
||||
for (i, line) in enumerate(lines):
|
||||
if i == 0:
|
||||
continue
|
||||
guid = "%s-%s" % (set_type, line[0])
|
||||
try:
|
||||
text_a = line[3]
|
||||
text_b = line[4]
|
||||
label = line[5]
|
||||
text_a = line[q1_index]
|
||||
text_b = line[q2_index]
|
||||
label = None if test_mode else line[5]
|
||||
except IndexError:
|
||||
continue
|
||||
examples.append(InputExample(guid=guid, text_a=text_a, text_b=text_b, label=label))
|
||||
@@ -413,14 +450,18 @@ class QnliProcessor(DataProcessor):
|
||||
|
||||
def get_dev_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev_matched")
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")
|
||||
|
||||
def get_test_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")
|
||||
|
||||
def get_labels(self):
|
||||
"""See base class."""
|
||||
return ["entailment", "not_entailment"]
|
||||
|
||||
def _create_examples(self, lines, set_type):
|
||||
"""Creates examples for the training and dev sets."""
|
||||
"""Creates examples for the training, dev and test sets."""
|
||||
examples = []
|
||||
for (i, line) in enumerate(lines):
|
||||
if i == 0:
|
||||
@@ -428,7 +469,7 @@ class QnliProcessor(DataProcessor):
|
||||
guid = "%s-%s" % (set_type, line[0])
|
||||
text_a = line[1]
|
||||
text_b = line[2]
|
||||
label = line[-1]
|
||||
label = None if set_type == "test" else line[-1]
|
||||
examples.append(InputExample(guid=guid, text_a=text_a, text_b=text_b, label=label))
|
||||
return examples
|
||||
|
||||
@@ -453,12 +494,16 @@ class RteProcessor(DataProcessor):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")
|
||||
|
||||
def get_test_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")
|
||||
|
||||
def get_labels(self):
|
||||
"""See base class."""
|
||||
return ["entailment", "not_entailment"]
|
||||
|
||||
def _create_examples(self, lines, set_type):
|
||||
"""Creates examples for the training and dev sets."""
|
||||
"""Creates examples for the training, dev and test sets."""
|
||||
examples = []
|
||||
for (i, line) in enumerate(lines):
|
||||
if i == 0:
|
||||
@@ -466,7 +511,7 @@ class RteProcessor(DataProcessor):
|
||||
guid = "%s-%s" % (set_type, line[0])
|
||||
text_a = line[1]
|
||||
text_b = line[2]
|
||||
label = line[-1]
|
||||
label = None if set_type == "test" else line[-1]
|
||||
examples.append(InputExample(guid=guid, text_a=text_a, text_b=text_b, label=label))
|
||||
return examples
|
||||
|
||||
@@ -491,12 +536,16 @@ class WnliProcessor(DataProcessor):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")
|
||||
|
||||
def get_test_examples(self, data_dir):
|
||||
"""See base class."""
|
||||
return self._create_examples(self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")
|
||||
|
||||
def get_labels(self):
|
||||
"""See base class."""
|
||||
return ["0", "1"]
|
||||
|
||||
def _create_examples(self, lines, set_type):
|
||||
"""Creates examples for the training and dev sets."""
|
||||
"""Creates examples for the training, dev and test sets."""
|
||||
examples = []
|
||||
for (i, line) in enumerate(lines):
|
||||
if i == 0:
|
||||
@@ -504,7 +553,7 @@ class WnliProcessor(DataProcessor):
|
||||
guid = "%s-%s" % (set_type, line[0])
|
||||
text_a = line[1]
|
||||
text_b = line[2]
|
||||
label = line[-1]
|
||||
label = None if set_type == "test" else line[-1]
|
||||
examples.append(InputExample(guid=guid, text_a=text_a, text_b=text_b, label=label))
|
||||
return examples
|
||||
|
||||
|
||||
@@ -98,6 +98,10 @@ class DataProcessor:
|
||||
"""Gets a collection of `InputExample`s for the dev set."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_test_examples(self, data_dir):
|
||||
"""Gets a collection of `InputExample`s for the test set."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_labels(self):
|
||||
"""Gets the list of labels for this data set."""
|
||||
raise NotImplementedError()
|
||||
|
||||
@@ -30,6 +30,7 @@ from .configuration_auto import (
|
||||
EncoderDecoderConfig,
|
||||
FlaubertConfig,
|
||||
GPT2Config,
|
||||
LongformerConfig,
|
||||
OpenAIGPTConfig,
|
||||
ReformerConfig,
|
||||
RobertaConfig,
|
||||
@@ -87,6 +88,7 @@ from .modeling_electra import (
|
||||
ELECTRA_PRETRAINED_MODEL_ARCHIVE_MAP,
|
||||
ElectraForMaskedLM,
|
||||
ElectraForPreTraining,
|
||||
ElectraForSequenceClassification,
|
||||
ElectraForTokenClassification,
|
||||
ElectraModel,
|
||||
)
|
||||
@@ -99,6 +101,7 @@ from .modeling_flaubert import (
|
||||
FlaubertWithLMHeadModel,
|
||||
)
|
||||
from .modeling_gpt2 import GPT2_PRETRAINED_MODEL_ARCHIVE_MAP, GPT2LMHeadModel, GPT2Model
|
||||
from .modeling_longformer import LONGFORMER_PRETRAINED_MODEL_ARCHIVE_MAP, LongformerForMaskedLM, LongformerModel
|
||||
from .modeling_marian import MarianMTModel
|
||||
from .modeling_openai import OPENAI_GPT_PRETRAINED_MODEL_ARCHIVE_MAP, OpenAIGPTLMHeadModel, OpenAIGPTModel
|
||||
from .modeling_reformer import ReformerModel, ReformerModelWithLMHead
|
||||
@@ -162,6 +165,7 @@ ALL_PRETRAINED_MODEL_ARCHIVE_MAP = dict(
|
||||
FLAUBERT_PRETRAINED_MODEL_ARCHIVE_MAP,
|
||||
XLM_ROBERTA_PRETRAINED_MODEL_ARCHIVE_MAP,
|
||||
ELECTRA_PRETRAINED_MODEL_ARCHIVE_MAP,
|
||||
LONGFORMER_PRETRAINED_MODEL_ARCHIVE_MAP,
|
||||
]
|
||||
for key, value, in pretrained_map.items()
|
||||
)
|
||||
@@ -174,6 +178,7 @@ MODEL_MAPPING = OrderedDict(
|
||||
(CamembertConfig, CamembertModel),
|
||||
(XLMRobertaConfig, XLMRobertaModel),
|
||||
(BartConfig, BartModel),
|
||||
(LongformerConfig, LongformerModel),
|
||||
(RobertaConfig, RobertaModel),
|
||||
(BertConfig, BertModel),
|
||||
(OpenAIGPTConfig, OpenAIGPTModel),
|
||||
@@ -196,6 +201,7 @@ MODEL_FOR_PRETRAINING_MAPPING = OrderedDict(
|
||||
(CamembertConfig, CamembertForMaskedLM),
|
||||
(XLMRobertaConfig, XLMRobertaForMaskedLM),
|
||||
(BartConfig, BartForConditionalGeneration),
|
||||
(LongformerConfig, LongformerForMaskedLM),
|
||||
(RobertaConfig, RobertaForMaskedLM),
|
||||
(BertConfig, BertForPreTraining),
|
||||
(OpenAIGPTConfig, OpenAIGPTLMHeadModel),
|
||||
@@ -218,6 +224,7 @@ MODEL_WITH_LM_HEAD_MAPPING = OrderedDict(
|
||||
(XLMRobertaConfig, XLMRobertaForMaskedLM),
|
||||
(MarianConfig, MarianMTModel),
|
||||
(BartConfig, BartForConditionalGeneration),
|
||||
(LongformerConfig, LongformerForMaskedLM),
|
||||
(RobertaConfig, RobertaForMaskedLM),
|
||||
(BertConfig, BertForMaskedLM),
|
||||
(OpenAIGPTConfig, OpenAIGPTLMHeadModel),
|
||||
@@ -245,6 +252,7 @@ MODEL_FOR_SEQUENCE_CLASSIFICATION_MAPPING = OrderedDict(
|
||||
(XLNetConfig, XLNetForSequenceClassification),
|
||||
(FlaubertConfig, FlaubertForSequenceClassification),
|
||||
(XLMConfig, XLMForSequenceClassification),
|
||||
(ElectraConfig, ElectraForSequenceClassification),
|
||||
]
|
||||
)
|
||||
|
||||
@@ -313,6 +321,7 @@ class AutoModel:
|
||||
The model class to instantiate is selected based on the configuration class:
|
||||
|
||||
- isInstance of `distilbert` configuration class: :class:`~transformers.DistilBertModel` (DistilBERT model)
|
||||
- isInstance of `longformer` configuration class: :class:`~transformers.LongformerModel` (Longformer model)
|
||||
- isInstance of `roberta` configuration class: :class:`~transformers.RobertaModel` (RoBERTa model)
|
||||
- isInstance of `bert` configuration class: :class:`~transformers.BertModel` (Bert model)
|
||||
- isInstance of `openai-gpt` configuration class: :class:`~transformers.OpenAIGPTModel` (OpenAI GPT model)
|
||||
@@ -355,6 +364,7 @@ class AutoModel:
|
||||
- contains `albert`: :class:`~transformers.AlbertModel` (ALBERT model)
|
||||
- contains `camembert`: :class:`~transformers.CamembertModel` (CamemBERT model)
|
||||
- contains `xlm-roberta`: :class:`~transformers.XLMRobertaModel` (XLM-RoBERTa model)
|
||||
- contains `longformer` :class:`~transformers.LongformerModel` (Longformer model)
|
||||
- contains `roberta`: :class:`~transformers.RobertaModel` (RoBERTa model)
|
||||
- contains `bert`: :class:`~transformers.BertModel` (Bert model)
|
||||
- contains `openai-gpt`: :class:`~transformers.OpenAIGPTModel` (OpenAI GPT model)
|
||||
@@ -463,6 +473,7 @@ class AutoModelForPreTraining:
|
||||
The model class to instantiate is selected based on the configuration class:
|
||||
|
||||
- isInstance of `distilbert` configuration class: :class:`~transformers.DistilBertForMaskedLM` (DistilBERT model)
|
||||
- isInstance of `longformer` configuration class: :class:`~transformers.LongformerForMaskedLM` (Longformer model)
|
||||
- isInstance of `roberta` configuration class: :class:`~transformers.RobertaForMaskedLM` (RoBERTa model)
|
||||
- isInstance of `bert` configuration class: :class:`~transformers.BertForPreTraining` (Bert model)
|
||||
- isInstance of `openai-gpt` configuration class: :class:`~transformers.OpenAIGPTLMHeadModel` (OpenAI GPT model)
|
||||
@@ -504,6 +515,7 @@ class AutoModelForPreTraining:
|
||||
- contains `albert`: :class:`~transformers.AlbertForMaskedLM` (ALBERT model)
|
||||
- contains `camembert`: :class:`~transformers.CamembertForMaskedLM` (CamemBERT model)
|
||||
- contains `xlm-roberta`: :class:`~transformers.XLMRobertaForMaskedLM` (XLM-RoBERTa model)
|
||||
- contains `longformer`: :class:`~transformers.LongformerForMaskedLM` (Longformer model)
|
||||
- contains `roberta`: :class:`~transformers.RobertaForMaskedLM` (RoBERTa model)
|
||||
- contains `bert`: :class:`~transformers.BertForPreTraining` (Bert model)
|
||||
- contains `openai-gpt`: :class:`~transformers.OpenAIGPTLMHeadModel` (OpenAI GPT model)
|
||||
@@ -606,6 +618,7 @@ class AutoModelWithLMHead:
|
||||
The model class to instantiate is selected based on the configuration class:
|
||||
|
||||
- isInstance of `distilbert` configuration class: :class:`~transformers.DistilBertForMaskedLM` (DistilBERT model)
|
||||
- isInstance of `longformer` configuration class: :class:`~transformers.LongformerForMaskedLM` (Longformer model)
|
||||
- isInstance of `roberta` configuration class: :class:`~transformers.RobertaForMaskedLM` (RoBERTa model)
|
||||
- isInstance of `bert` configuration class: :class:`~transformers.BertForMaskedLM` (Bert model)
|
||||
- isInstance of `openai-gpt` configuration class: :class:`~transformers.OpenAIGPTLMHeadModel` (OpenAI GPT model)
|
||||
@@ -648,6 +661,7 @@ class AutoModelWithLMHead:
|
||||
- contains `albert`: :class:`~transformers.AlbertForMaskedLM` (ALBERT model)
|
||||
- contains `camembert`: :class:`~transformers.CamembertForMaskedLM` (CamemBERT model)
|
||||
- contains `xlm-roberta`: :class:`~transformers.XLMRobertaForMaskedLM` (XLM-RoBERTa model)
|
||||
- contains `longformer`: :class:`~transformers.LongformerForMaskedLM` (Longformer model)
|
||||
- contains `roberta`: :class:`~transformers.RobertaForMaskedLM` (RoBERTa model)
|
||||
- contains `bert`: :class:`~transformers.BertForMaskedLM` (Bert model)
|
||||
- contains `openai-gpt`: :class:`~transformers.OpenAIGPTLMHeadModel` (OpenAI GPT model)
|
||||
|
||||
@@ -3,6 +3,7 @@ import os
|
||||
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
from torch.nn import CrossEntropyLoss, MSELoss
|
||||
|
||||
from .activations import get_activation
|
||||
from .configuration_electra import ElectraConfig
|
||||
@@ -330,6 +331,112 @@ class ElectraModel(ElectraPreTrainedModel):
|
||||
return hidden_states
|
||||
|
||||
|
||||
class ElectraClassificationHead(nn.Module):
|
||||
"""Head for sentence-level classification tasks."""
|
||||
|
||||
def __init__(self, config):
|
||||
super().__init__()
|
||||
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
|
||||
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
||||
self.out_proj = nn.Linear(config.hidden_size, config.num_labels)
|
||||
|
||||
def forward(self, features, **kwargs):
|
||||
x = features[:, 0, :] # take <s> token (equiv. to [CLS])
|
||||
x = self.dropout(x)
|
||||
x = self.dense(x)
|
||||
x = get_activation("gelu")(x) # although BERT uses tanh here, it seems Electra authors used gelu here
|
||||
x = self.dropout(x)
|
||||
x = self.out_proj(x)
|
||||
return x
|
||||
|
||||
|
||||
@add_start_docstrings(
|
||||
"""ELECTRA Model transformer with a sequence classification/regression head on top (a linear layer on top of
|
||||
the pooled output) e.g. for GLUE tasks. """,
|
||||
ELECTRA_START_DOCSTRING,
|
||||
)
|
||||
class ElectraForSequenceClassification(ElectraPreTrainedModel):
|
||||
def __init__(self, config):
|
||||
super().__init__(config)
|
||||
self.num_labels = config.num_labels
|
||||
self.electra = ElectraModel(config)
|
||||
self.classifier = ElectraClassificationHead(config)
|
||||
|
||||
self.init_weights()
|
||||
|
||||
@add_start_docstrings_to_callable(ELECTRA_INPUTS_DOCSTRING)
|
||||
def forward(
|
||||
self,
|
||||
input_ids=None,
|
||||
attention_mask=None,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
head_mask=None,
|
||||
inputs_embeds=None,
|
||||
labels=None,
|
||||
):
|
||||
r"""
|
||||
labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size,)`, `optional`, defaults to :obj:`None`):
|
||||
Labels for computing the sequence classification/regression loss.
|
||||
Indices should be in :obj:`[0, ..., config.num_labels - 1]`.
|
||||
If :obj:`config.num_labels == 1` a regression loss is computed (Mean-Square loss),
|
||||
If :obj:`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
||||
|
||||
Returns:
|
||||
:obj:`tuple(torch.FloatTensor)` comprising various elements depending on the configuration (:class:`~transformers.BertConfig`) and inputs:
|
||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`label` is provided):
|
||||
Classification (or regression if config.num_labels==1) loss.
|
||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, config.num_labels)`):
|
||||
Classification (or regression if config.num_labels==1) scores (before SoftMax).
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape
|
||||
:obj:`(batch_size, num_heads, sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
|
||||
Examples::
|
||||
|
||||
from transformers import BertTokenizer, BertForSequenceClassification
|
||||
import torch
|
||||
|
||||
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
|
||||
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
|
||||
|
||||
input_ids = torch.tensor(tokenizer.encode("Hello, my dog is cute", add_special_tokens=True)).unsqueeze(0) # Batch size 1
|
||||
labels = torch.tensor([1]).unsqueeze(0) # Batch size 1
|
||||
outputs = model(input_ids, labels=labels)
|
||||
|
||||
loss, logits = outputs[:2]
|
||||
|
||||
"""
|
||||
discriminator_hidden_states = self.electra(
|
||||
input_ids, attention_mask, token_type_ids, position_ids, head_mask, inputs_embeds
|
||||
)
|
||||
|
||||
sequence_output = discriminator_hidden_states[0]
|
||||
logits = self.classifier(sequence_output)
|
||||
|
||||
outputs = (logits,) + discriminator_hidden_states[2:] # add hidden states and attention if they are here
|
||||
|
||||
if labels is not None:
|
||||
if self.num_labels == 1:
|
||||
# We are doing regression
|
||||
loss_fct = MSELoss()
|
||||
loss = loss_fct(logits.view(-1), labels.view(-1))
|
||||
else:
|
||||
loss_fct = CrossEntropyLoss()
|
||||
loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
|
||||
outputs = (loss,) + outputs
|
||||
|
||||
return outputs # (loss), logits, (hidden_states), (attentions)
|
||||
|
||||
|
||||
@add_start_docstrings(
|
||||
"""
|
||||
Electra model with a binary classification head on top as used during pre-training for identifying generated
|
||||
|
||||
@@ -0,0 +1,709 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2020 The Allen Institute for AI team and The HuggingFace Inc. team.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""PyTorch Longformer model. """
|
||||
|
||||
import logging
|
||||
import math
|
||||
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
from torch.nn import CrossEntropyLoss
|
||||
from torch.nn import functional as F
|
||||
|
||||
from .configuration_longformer import LongformerConfig
|
||||
from .file_utils import add_start_docstrings, add_start_docstrings_to_callable
|
||||
from .modeling_bert import BertPreTrainedModel
|
||||
from .modeling_roberta import RobertaLMHead, RobertaModel
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
LONGFORMER_PRETRAINED_MODEL_ARCHIVE_MAP = {
|
||||
"longformer-base-4096": "https://s3.amazonaws.com/models.huggingface.co/bert/allenai/longformer-base-4096/pytorch_model.bin",
|
||||
"longformer-large-4096": "https://s3.amazonaws.com/models.huggingface.co/bert/allenai/longformer-large-4096/pytorch_model.bin",
|
||||
}
|
||||
|
||||
|
||||
class LongformerSelfAttention(nn.Module):
|
||||
def __init__(self, config, layer_id):
|
||||
super().__init__()
|
||||
if config.hidden_size % config.num_attention_heads != 0:
|
||||
raise ValueError(
|
||||
"The hidden size (%d) is not a multiple of the number of attention "
|
||||
"heads (%d)" % (config.hidden_size, config.num_attention_heads)
|
||||
)
|
||||
self.output_attentions = config.output_attentions
|
||||
self.num_heads = config.num_attention_heads
|
||||
self.head_dim = int(config.hidden_size / config.num_attention_heads)
|
||||
self.embed_dim = config.hidden_size
|
||||
|
||||
self.query = nn.Linear(config.hidden_size, self.embed_dim)
|
||||
self.key = nn.Linear(config.hidden_size, self.embed_dim)
|
||||
self.value = nn.Linear(config.hidden_size, self.embed_dim)
|
||||
|
||||
# separate projection layers for tokens with global attention
|
||||
self.query_global = nn.Linear(config.hidden_size, self.embed_dim)
|
||||
self.key_global = nn.Linear(config.hidden_size, self.embed_dim)
|
||||
self.value_global = nn.Linear(config.hidden_size, self.embed_dim)
|
||||
|
||||
self.dropout = config.attention_probs_dropout_prob
|
||||
|
||||
self.layer_id = layer_id
|
||||
attention_window = config.attention_window[self.layer_id]
|
||||
assert (
|
||||
attention_window % 2 == 0
|
||||
), f"`attention_window` for layer {self.layer_id} has to be an even value. Given {attention_window}"
|
||||
assert (
|
||||
attention_window > 0
|
||||
), f"`attention_window` for layer {self.layer_id} has to be positive. Given {attention_window}"
|
||||
|
||||
self.one_sided_attention_window_size = attention_window // 2
|
||||
|
||||
@staticmethod
|
||||
def _skew(x, direction):
|
||||
"""Convert diagonals into columns (or columns into diagonals depending on `direction`"""
|
||||
x_padded = F.pad(x, direction) # padding value is not important because it will be overwritten
|
||||
x_padded = x_padded.view(*x_padded.size()[:-2], x_padded.size(-1), x_padded.size(-2))
|
||||
return x_padded
|
||||
|
||||
@staticmethod
|
||||
def _skew2(x):
|
||||
"""shift every row 1 step to right converting columns into diagonals"""
|
||||
# X = B x C x M x L
|
||||
B, C, M, L = x.size()
|
||||
x = F.pad(x, (0, M + 1)) # B x C x M x (L+M+1). Padding value is not important because it'll be overwritten
|
||||
x = x.view(B, C, -1) # B x C x ML+MM+M
|
||||
x = x[:, :, :-M] # B x C x ML+MM
|
||||
x = x.view(B, C, M, M + L) # B x C, M x L+M
|
||||
x = x[:, :, :, :-1]
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
def _chunk(x, w):
|
||||
"""convert into overlapping chunkings. Chunk size = 2w, overlap size = w"""
|
||||
|
||||
# non-overlapping chunks of size = 2w
|
||||
x = x.view(x.size(0), x.size(1) // (w * 2), w * 2, x.size(2))
|
||||
|
||||
# use `as_strided` to make the chunks overlap with an overlap size = w
|
||||
chunk_size = list(x.size())
|
||||
chunk_size[1] = chunk_size[1] * 2 - 1
|
||||
|
||||
chunk_stride = list(x.stride())
|
||||
chunk_stride[1] = chunk_stride[1] // 2
|
||||
return x.as_strided(size=chunk_size, stride=chunk_stride)
|
||||
|
||||
def _mask_invalid_locations(self, input_tensor, w) -> torch.Tensor:
|
||||
affected_seqlen = w
|
||||
beginning_mask_2d = input_tensor.new_ones(w, w + 1).tril().flip(dims=[0])
|
||||
beginning_mask = beginning_mask_2d[None, :, None, :]
|
||||
ending_mask = beginning_mask.flip(dims=(1, 3))
|
||||
seqlen = input_tensor.size(1)
|
||||
beginning_input = input_tensor[:, :affected_seqlen, :, : w + 1]
|
||||
beginning_mask = beginning_mask[:, :seqlen].expand(beginning_input.size())
|
||||
beginning_input.masked_fill_(beginning_mask == 1, -float("inf")) # `== 1` converts to bool or uint8
|
||||
ending_input = input_tensor[:, -affected_seqlen:, :, -(w + 1) :]
|
||||
ending_mask = ending_mask[:, -seqlen:].expand(ending_input.size())
|
||||
ending_input.masked_fill_(ending_mask == 1, -float("inf")) # `== 1` converts to bool or uint8
|
||||
|
||||
def _sliding_chunks_matmul_qk(self, q: torch.Tensor, k: torch.Tensor, w: int):
|
||||
"""Matrix multiplicatio of query x key tensors using with a sliding window attention pattern.
|
||||
This implementation splits the input into overlapping chunks of size 2w (e.g. 512 for pretrained Longformer)
|
||||
with an overlap of size w"""
|
||||
batch_size, seqlen, num_heads, head_dim = q.size()
|
||||
assert seqlen % (w * 2) == 0, f"Sequence length should be multiple of {w * 2}. Given {seqlen}"
|
||||
assert q.size() == k.size()
|
||||
|
||||
chunks_count = seqlen // w - 1
|
||||
|
||||
# group batch_size and num_heads dimensions into one, then chunk seqlen into chunks of size w * 2
|
||||
q = q.transpose(1, 2).reshape(batch_size * num_heads, seqlen, head_dim)
|
||||
k = k.transpose(1, 2).reshape(batch_size * num_heads, seqlen, head_dim)
|
||||
|
||||
chunk_q = self._chunk(q, w)
|
||||
chunk_k = self._chunk(k, w)
|
||||
|
||||
# matrix multipication
|
||||
# bcxd: batch_size * num_heads x chunks x 2w x head_dim
|
||||
# bcyd: batch_size * num_heads x chunks x 2w x head_dim
|
||||
# bcxy: batch_size * num_heads x chunks x 2w x 2w
|
||||
chunk_attn = torch.einsum("bcxd,bcyd->bcxy", (chunk_q, chunk_k)) # multiply
|
||||
|
||||
# convert diagonals into columns
|
||||
diagonal_chunk_attn = self._skew(chunk_attn, direction=(0, 0, 0, 1))
|
||||
|
||||
# allocate space for the overall attention matrix where the chunks are compined. The last dimension
|
||||
# has (w * 2 + 1) columns. The first (w) columns are the w lower triangles (attention from a word to
|
||||
# w previous words). The following column is attention score from each word to itself, then
|
||||
# followed by w columns for the upper triangle.
|
||||
|
||||
diagonal_attn = diagonal_chunk_attn.new_empty((batch_size * num_heads, chunks_count + 1, w, w * 2 + 1))
|
||||
|
||||
# copy parts from diagonal_chunk_attn into the compined matrix of attentions
|
||||
# - copying the main diagonal and the upper triangle
|
||||
diagonal_attn[:, :-1, :, w:] = diagonal_chunk_attn[:, :, :w, : w + 1]
|
||||
diagonal_attn[:, -1, :, w:] = diagonal_chunk_attn[:, -1, w:, : w + 1]
|
||||
# - copying the lower triangle
|
||||
diagonal_attn[:, 1:, :, :w] = diagonal_chunk_attn[:, :, -(w + 1) : -1, w + 1 :]
|
||||
diagonal_attn[:, 0, 1:w, 1:w] = diagonal_chunk_attn[:, 0, : w - 1, 1 - w :]
|
||||
|
||||
# separate batch_size and num_heads dimensions again
|
||||
diagonal_attn = diagonal_attn.view(batch_size, num_heads, seqlen, 2 * w + 1).transpose(2, 1)
|
||||
|
||||
self._mask_invalid_locations(diagonal_attn, w)
|
||||
return diagonal_attn
|
||||
|
||||
def _sliding_chunks_matmul_pv(self, prob: torch.Tensor, v: torch.Tensor, w: int):
|
||||
"""Same as _sliding_chunks_matmul_qk but for prob and value tensors. It is expecting the same output
|
||||
format from _sliding_chunks_matmul_qk"""
|
||||
batch_size, seqlen, num_heads, head_dim = v.size()
|
||||
assert seqlen % (w * 2) == 0
|
||||
assert prob.size()[:3] == v.size()[:3]
|
||||
assert prob.size(3) == 2 * w + 1
|
||||
chunks_count = seqlen // w - 1
|
||||
# group batch_size and num_heads dimensions into one, then chunk seqlen into chunks of size 2w
|
||||
chunk_prob = prob.transpose(1, 2).reshape(batch_size * num_heads, seqlen // w, w, 2 * w + 1)
|
||||
|
||||
# group batch_size and num_heads dimensions into one
|
||||
v = v.transpose(1, 2).reshape(batch_size * num_heads, seqlen, head_dim)
|
||||
|
||||
# pad seqlen with w at the beginning of the sequence and another w at the end
|
||||
padded_v = F.pad(v, (0, 0, w, w), value=-1)
|
||||
|
||||
# chunk padded_v into chunks of size 3w and an overlap of size w
|
||||
chunk_v_size = (batch_size * num_heads, chunks_count + 1, 3 * w, head_dim)
|
||||
chunk_v_stride = padded_v.stride()
|
||||
chunk_v_stride = chunk_v_stride[0], w * chunk_v_stride[1], chunk_v_stride[1], chunk_v_stride[2]
|
||||
chunk_v = padded_v.as_strided(size=chunk_v_size, stride=chunk_v_stride)
|
||||
|
||||
skewed_prob = self._skew2(chunk_prob)
|
||||
|
||||
context = torch.einsum("bcwd,bcdh->bcwh", (skewed_prob, chunk_v))
|
||||
return context.view(batch_size, num_heads, seqlen, head_dim).transpose(1, 2)
|
||||
|
||||
def forward(
|
||||
self,
|
||||
hidden_states,
|
||||
attention_mask=None,
|
||||
head_mask=None,
|
||||
encoder_hidden_states=None,
|
||||
encoder_attention_mask=None,
|
||||
):
|
||||
"""
|
||||
LongformerSelfAttention expects `len(hidden_states)` to be multiple of `attention_window`.
|
||||
Padding to `attention_window` happens in LongformerModel.forward to avoid redoing the padding on each layer.
|
||||
|
||||
The `attention_mask` is changed in `BertModel.forward` from 0, 1, 2 to
|
||||
-ve: no attention
|
||||
0: local attention
|
||||
+ve: global attention
|
||||
|
||||
`encoder_hidden_states` and `encoder_attention_mask` are not supported and should be None
|
||||
"""
|
||||
# TODO: add support for `encoder_hidden_states` and `encoder_attention_mask`
|
||||
assert encoder_hidden_states is None, "`encoder_hidden_states` is not supported and should be None"
|
||||
assert encoder_attention_mask is None, "`encoder_attention_mask` is not supported and shiould be None"
|
||||
|
||||
if attention_mask is not None:
|
||||
attention_mask = attention_mask.squeeze(dim=2).squeeze(dim=1)
|
||||
key_padding_mask = attention_mask < 0
|
||||
extra_attention_mask = attention_mask > 0
|
||||
remove_from_windowed_attention_mask = attention_mask != 0
|
||||
|
||||
num_extra_indices_per_batch = extra_attention_mask.long().sum(dim=1)
|
||||
max_num_extra_indices_per_batch = num_extra_indices_per_batch.max()
|
||||
if max_num_extra_indices_per_batch <= 0:
|
||||
extra_attention_mask = None
|
||||
else:
|
||||
# To support the case of variable number of global attention in the rows of a batch,
|
||||
# we use the following three selection masks to select global attention embeddings
|
||||
# in a 3d tensor and pad it to `max_num_extra_indices_per_batch`
|
||||
# 1) selecting embeddings that correspond to global attention
|
||||
extra_attention_mask_nonzeros = extra_attention_mask.nonzero(as_tuple=True)
|
||||
zero_to_max_range = torch.arange(
|
||||
0, max_num_extra_indices_per_batch, device=num_extra_indices_per_batch.device
|
||||
)
|
||||
# mask indicating which values are actually going to be padding
|
||||
selection_padding_mask = zero_to_max_range < num_extra_indices_per_batch.unsqueeze(dim=-1)
|
||||
# 2) location of the non-padding values in the selected global attention
|
||||
selection_padding_mask_nonzeros = selection_padding_mask.nonzero(as_tuple=True)
|
||||
# 3) location of the padding values in the selected global attention
|
||||
selection_padding_mask_zeros = (selection_padding_mask == 0).nonzero(as_tuple=True)
|
||||
else:
|
||||
remove_from_windowed_attention_mask = None
|
||||
extra_attention_mask = None
|
||||
key_padding_mask = None
|
||||
|
||||
hidden_states = hidden_states.transpose(0, 1)
|
||||
seqlen, batch_size, embed_dim = hidden_states.size()
|
||||
assert embed_dim == self.embed_dim
|
||||
q = self.query(hidden_states)
|
||||
k = self.key(hidden_states)
|
||||
v = self.value(hidden_states)
|
||||
q /= math.sqrt(self.head_dim)
|
||||
|
||||
q = q.view(seqlen, batch_size, self.num_heads, self.head_dim).transpose(0, 1)
|
||||
k = k.view(seqlen, batch_size, self.num_heads, self.head_dim).transpose(0, 1)
|
||||
# attn_weights = (batch_size, seqlen, num_heads, window*2+1)
|
||||
attn_weights = self._sliding_chunks_matmul_qk(q, k, self.one_sided_attention_window_size)
|
||||
self._mask_invalid_locations(attn_weights, self.one_sided_attention_window_size)
|
||||
if remove_from_windowed_attention_mask is not None:
|
||||
# This implementation is fast and takes very little memory because num_heads x hidden_size = 1
|
||||
# from (batch_size x seqlen) to (batch_size x seqlen x num_heads x hidden_size)
|
||||
remove_from_windowed_attention_mask = remove_from_windowed_attention_mask.unsqueeze(dim=-1).unsqueeze(
|
||||
dim=-1
|
||||
)
|
||||
# cast to fp32/fp16 then replace 1's with -inf
|
||||
float_mask = remove_from_windowed_attention_mask.type_as(q).masked_fill(
|
||||
remove_from_windowed_attention_mask, -10000.0
|
||||
)
|
||||
ones = float_mask.new_ones(size=float_mask.size()) # tensor of ones
|
||||
# diagonal mask with zeros everywhere and -inf inplace of padding
|
||||
d_mask = self._sliding_chunks_matmul_qk(ones, float_mask, self.one_sided_attention_window_size)
|
||||
attn_weights += d_mask
|
||||
assert list(attn_weights.size()) == [
|
||||
batch_size,
|
||||
seqlen,
|
||||
self.num_heads,
|
||||
self.one_sided_attention_window_size * 2 + 1,
|
||||
]
|
||||
|
||||
# the extra attention
|
||||
if extra_attention_mask is not None:
|
||||
selected_k = k.new_zeros(batch_size, max_num_extra_indices_per_batch, self.num_heads, self.head_dim)
|
||||
selected_k[selection_padding_mask_nonzeros] = k[extra_attention_mask_nonzeros]
|
||||
# (batch_size, seqlen, num_heads, max_num_extra_indices_per_batch)
|
||||
selected_attn_weights = torch.einsum("blhd,bshd->blhs", (q, selected_k))
|
||||
selected_attn_weights[selection_padding_mask_zeros[0], :, :, selection_padding_mask_zeros[1]] = -10000
|
||||
# concat to attn_weights
|
||||
# (batch_size, seqlen, num_heads, extra attention count + 2*window+1)
|
||||
attn_weights = torch.cat((selected_attn_weights, attn_weights), dim=-1)
|
||||
|
||||
attn_weights_fp32 = F.softmax(attn_weights, dim=-1, dtype=torch.float32) # use fp32 for numerical stability
|
||||
attn_weights = attn_weights_fp32.type_as(attn_weights)
|
||||
|
||||
if key_padding_mask is not None:
|
||||
# softmax sometimes inserts NaN if all positions are masked, replace them with 0
|
||||
attn_weights = torch.masked_fill(attn_weights, key_padding_mask.unsqueeze(-1).unsqueeze(-1), 0.0)
|
||||
|
||||
attn_probs = F.dropout(attn_weights, p=self.dropout, training=self.training)
|
||||
v = v.view(seqlen, batch_size, self.num_heads, self.head_dim).transpose(0, 1)
|
||||
attn = None
|
||||
if extra_attention_mask is not None:
|
||||
selected_attn_probs = attn_probs.narrow(-1, 0, max_num_extra_indices_per_batch)
|
||||
selected_v = v.new_zeros(batch_size, max_num_extra_indices_per_batch, self.num_heads, self.head_dim)
|
||||
selected_v[selection_padding_mask_nonzeros] = v[extra_attention_mask_nonzeros]
|
||||
# use `matmul` because `einsum` crashes sometimes with fp16
|
||||
# attn = torch.einsum('blhs,bshd->blhd', (selected_attn_probs, selected_v))
|
||||
attn = torch.matmul(
|
||||
selected_attn_probs.transpose(1, 2), selected_v.transpose(1, 2).type_as(selected_attn_probs)
|
||||
).transpose(1, 2)
|
||||
attn_probs = attn_probs.narrow(
|
||||
-1, max_num_extra_indices_per_batch, attn_probs.size(-1) - max_num_extra_indices_per_batch
|
||||
).contiguous()
|
||||
if attn is None:
|
||||
attn = self._sliding_chunks_matmul_pv(attn_probs, v, self.one_sided_attention_window_size)
|
||||
else:
|
||||
attn += self._sliding_chunks_matmul_pv(attn_probs, v, self.one_sided_attention_window_size)
|
||||
|
||||
assert attn.size() == (batch_size, seqlen, self.num_heads, self.head_dim), "Unexpected size"
|
||||
attn = attn.transpose(0, 1).reshape(seqlen, batch_size, embed_dim).contiguous()
|
||||
|
||||
# For this case, we'll just recompute the attention for these indices
|
||||
# and overwrite the attn tensor.
|
||||
# TODO: remove the redundant computation
|
||||
if extra_attention_mask is not None:
|
||||
selected_hidden_states = hidden_states.new_zeros(max_num_extra_indices_per_batch, batch_size, embed_dim)
|
||||
selected_hidden_states[selection_padding_mask_nonzeros[::-1]] = hidden_states[
|
||||
extra_attention_mask_nonzeros[::-1]
|
||||
]
|
||||
|
||||
q = self.query_global(selected_hidden_states)
|
||||
k = self.key_global(hidden_states)
|
||||
v = self.value_global(hidden_states)
|
||||
q /= math.sqrt(self.head_dim)
|
||||
|
||||
q = (
|
||||
q.contiguous()
|
||||
.view(max_num_extra_indices_per_batch, batch_size * self.num_heads, self.head_dim)
|
||||
.transpose(0, 1)
|
||||
) # (batch_size * self.num_heads, max_num_extra_indices_per_batch, head_dim)
|
||||
k = (
|
||||
k.contiguous().view(-1, batch_size * self.num_heads, self.head_dim).transpose(0, 1)
|
||||
) # batch_size * self.num_heads, seqlen, head_dim)
|
||||
v = (
|
||||
v.contiguous().view(-1, batch_size * self.num_heads, self.head_dim).transpose(0, 1)
|
||||
) # batch_size * self.num_heads, seqlen, head_dim)
|
||||
attn_weights = torch.bmm(q, k.transpose(1, 2))
|
||||
assert list(attn_weights.size()) == [batch_size * self.num_heads, max_num_extra_indices_per_batch, seqlen]
|
||||
|
||||
attn_weights = attn_weights.view(batch_size, self.num_heads, max_num_extra_indices_per_batch, seqlen)
|
||||
attn_weights[selection_padding_mask_zeros[0], :, selection_padding_mask_zeros[1], :] = -10000.0
|
||||
if key_padding_mask is not None:
|
||||
attn_weights = attn_weights.masked_fill(key_padding_mask.unsqueeze(1).unsqueeze(2), -10000.0,)
|
||||
attn_weights = attn_weights.view(batch_size * self.num_heads, max_num_extra_indices_per_batch, seqlen)
|
||||
attn_weights_float = F.softmax(
|
||||
attn_weights, dim=-1, dtype=torch.float32
|
||||
) # use fp32 for numerical stability
|
||||
attn_probs = F.dropout(attn_weights_float.type_as(attn_weights), p=self.dropout, training=self.training)
|
||||
selected_attn = torch.bmm(attn_probs, v)
|
||||
assert list(selected_attn.size()) == [
|
||||
batch_size * self.num_heads,
|
||||
max_num_extra_indices_per_batch,
|
||||
self.head_dim,
|
||||
]
|
||||
|
||||
selected_attn_4d = selected_attn.view(
|
||||
batch_size, self.num_heads, max_num_extra_indices_per_batch, self.head_dim
|
||||
)
|
||||
nonzero_selected_attn = selected_attn_4d[
|
||||
selection_padding_mask_nonzeros[0], :, selection_padding_mask_nonzeros[1]
|
||||
]
|
||||
attn[extra_attention_mask_nonzeros[::-1]] = nonzero_selected_attn.view(
|
||||
len(selection_padding_mask_nonzeros[0]), -1
|
||||
).type_as(hidden_states)
|
||||
|
||||
context_layer = attn.transpose(0, 1)
|
||||
if self.output_attentions:
|
||||
if extra_attention_mask is not None:
|
||||
# With global attention, return global attention probabilities only
|
||||
# batch_size x num_heads x max_num_global_attention_tokens x sequence_length
|
||||
# which is the attention weights from tokens with global attention to all tokens
|
||||
# It doesn't not return local attention
|
||||
# In case of variable number of global attantion in the rows of a batch,
|
||||
# attn_weights are padded with -10000.0 attention scores
|
||||
attn_weights = attn_weights.view(batch_size, self.num_heads, max_num_extra_indices_per_batch, seqlen)
|
||||
else:
|
||||
# without global attention, return local attention probabilities
|
||||
# batch_size x num_heads x sequence_length x window_size
|
||||
# which is the attention weights of every token attending to its neighbours
|
||||
attn_weights = attn_weights.permute(0, 2, 1, 3)
|
||||
outputs = (context_layer, attn_weights) if self.output_attentions else (context_layer,)
|
||||
return outputs
|
||||
|
||||
|
||||
LONGFORMER_START_DOCSTRING = r"""
|
||||
|
||||
This model is a PyTorch `torch.nn.Module <https://pytorch.org/docs/stable/nn.html#torch.nn.Module>`_ sub-class.
|
||||
Use it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general
|
||||
usage and behavior.
|
||||
|
||||
Parameters:
|
||||
config (:class:`~transformers.LongformerConfig`): Model configuration class with all the parameters of the
|
||||
model. Initializing with a config file does not load the weights associated with the model, only the configuration.
|
||||
Check out the :meth:`~transformers.PreTrainedModel.from_pretrained` method to load the model weights.
|
||||
"""
|
||||
|
||||
LONGFORMER_INPUTS_DOCSTRING = r"""
|
||||
Args:
|
||||
input_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`):
|
||||
Indices of input sequence tokens in the vocabulary.
|
||||
|
||||
Indices can be obtained using :class:`transformers.LonmgformerTokenizer`.
|
||||
See :func:`transformers.PreTrainedTokenizer.encode` and
|
||||
:func:`transformers.PreTrainedTokenizer.encode_plus` for details.
|
||||
|
||||
`What are input IDs? <../glossary.html#input-ids>`__
|
||||
attention_mask (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`, defaults to :obj:`None`):
|
||||
Mask to decide the attention given on each token, local attention, global attenion, or no attention (for padding tokens).
|
||||
Tokens with global attention attends to all other tokens, and all other tokens attend to them. This is important for
|
||||
task-specific finetuning because it makes the model more flexible at representing the task. For example,
|
||||
for classification, the <s> token should be given global attention. For QA, all question tokens should also have
|
||||
global attention. Please refer to the Longformer paper https://arxiv.org/abs/2004.05150 for more details.
|
||||
Mask values selected in ``[0, 1, 2]``:
|
||||
``0`` for no attention (padding tokens),
|
||||
``1`` for local attention (a sliding window attention),
|
||||
``2`` for global attention (tokens that attend to all other tokens, and all other tokens attend to them).
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`, defaults to :obj:`None`):
|
||||
Segment token indices to indicate first and second portions of the inputs.
|
||||
Indices are selected in ``[0, 1]``: ``0`` corresponds to a `sentence A` token, ``1``
|
||||
corresponds to a `sentence B` token
|
||||
|
||||
`What are token type IDs? <../glossary.html#token-type-ids>`_
|
||||
position_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`, defaults to :obj:`None`):
|
||||
Indices of positions of each input sequence tokens in the position embeddings.
|
||||
Selected in the range ``[0, config.max_position_embeddings - 1]``.
|
||||
|
||||
`What are position IDs? <../glossary.html#position-ids>`_
|
||||
inputs_embeds (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`, `optional`, defaults to :obj:`None`):
|
||||
Optionally, instead of passing :obj:`input_ids` you can choose to directly pass an embedded representation.
|
||||
This is useful if you want more control over how to convert `input_ids` indices into associated vectors
|
||||
than the model's internal embedding lookup matrix.
|
||||
"""
|
||||
|
||||
|
||||
@add_start_docstrings(
|
||||
"The bare Longformer Model outputting raw hidden-states without any specific head on top.",
|
||||
LONGFORMER_START_DOCSTRING,
|
||||
)
|
||||
class LongformerModel(RobertaModel):
|
||||
"""
|
||||
This class overrides :class:`~transformers.RobertaModel` to provide the ability to process
|
||||
long sequences following the selfattention approach described in `Longformer: the Long-Document Transformer`_by
|
||||
Iz Beltagy, Matthew E. Peters, and Arman Cohan. Longformer selfattention combines a local (sliding window)
|
||||
and global attention to extend to long documents without the O(n^2) increase in memory and compute.
|
||||
|
||||
The selfattention module `LongformerSelfAttention` implemented here supports the combination of local and
|
||||
global attention but it lacks support for autoregressive attention and dilated attention. Autoregressive
|
||||
and dilated attention are more relevant for autoregressive language modeling than finetuning on downstream
|
||||
tasks. Future release will add support for autoregressive attention, but the support for dilated attention
|
||||
requires a custom CUDA kernel to be memory and compute efficient.
|
||||
|
||||
.. _`Longformer: the Long-Document Transformer`:
|
||||
https://arxiv.org/abs/2004.05150
|
||||
|
||||
"""
|
||||
|
||||
config_class = LongformerConfig
|
||||
pretrained_model_archive_map = LONGFORMER_PRETRAINED_MODEL_ARCHIVE_MAP
|
||||
base_model_prefix = "longformer"
|
||||
|
||||
def __init__(self, config):
|
||||
super().__init__(config)
|
||||
|
||||
if isinstance(config.attention_window, int):
|
||||
assert config.attention_window % 2 == 0, "`config.attention_window` has to be an even value"
|
||||
assert config.attention_window > 0, "`config.attention_window` has to be positive"
|
||||
config.attention_window = [config.attention_window] * config.num_hidden_layers # one value per layer
|
||||
else:
|
||||
assert len(config.attention_window) == config.num_hidden_layers, (
|
||||
"`len(config.attention_window)` should equal `config.num_hidden_layers`. "
|
||||
f"Expected {config.num_hidden_layers}, given {len(config.attention_window)}"
|
||||
)
|
||||
|
||||
for i, layer in enumerate(self.encoder.layer):
|
||||
# replace the `modeling_bert.BertSelfAttention` object with `LongformerSelfAttention`
|
||||
layer.attention.self = LongformerSelfAttention(config, layer_id=i)
|
||||
|
||||
self.init_weights()
|
||||
|
||||
def _pad_to_window_size(
|
||||
self,
|
||||
input_ids: torch.Tensor,
|
||||
attention_mask: torch.Tensor,
|
||||
token_type_ids: torch.Tensor,
|
||||
position_ids: torch.Tensor,
|
||||
inputs_embeds: torch.Tensor,
|
||||
attention_window: int,
|
||||
pad_token_id: int,
|
||||
):
|
||||
"""A helper function to pad tokens and mask to work with implementation of Longformer selfattention."""
|
||||
|
||||
assert attention_window % 2 == 0, f"`attention_window` should be an even value. Given {attention_window}"
|
||||
input_shape = input_ids.shape if input_ids is not None else inputs_embeds.shape
|
||||
batch_size, seqlen = input_shape[:2]
|
||||
|
||||
padding_len = (attention_window - seqlen % attention_window) % attention_window
|
||||
if padding_len > 0:
|
||||
logger.info(
|
||||
"Input ids are automatically padded from {} to {} to be a multiple of `config.attention_window`: {}".format(
|
||||
seqlen, seqlen + padding_len, attention_window
|
||||
)
|
||||
)
|
||||
if input_ids is not None:
|
||||
input_ids = F.pad(input_ids, (0, padding_len), value=pad_token_id)
|
||||
if attention_mask is not None:
|
||||
attention_mask = F.pad(
|
||||
attention_mask, (0, padding_len), value=False
|
||||
) # no attention on the padding tokens
|
||||
if token_type_ids is not None:
|
||||
token_type_ids = F.pad(token_type_ids, (0, padding_len), value=0) # pad with token_type_id = 0
|
||||
if position_ids is not None:
|
||||
# pad with position_id = pad_token_id as in modeling_roberta.RobertaEmbeddings
|
||||
position_ids = F.pad(position_ids, (0, padding_len), value=pad_token_id)
|
||||
if inputs_embeds is not None:
|
||||
input_ids_padding = inputs_embeds.new_full(
|
||||
(batch_size, padding_len), self.config.pad_token_id, dtype=torch.long,
|
||||
)
|
||||
inputs_embeds_padding = self.embeddings(input_ids_padding)
|
||||
inputs_embeds = torch.cat([inputs_embeds, inputs_embeds_padding], dim=-2)
|
||||
|
||||
return padding_len, input_ids, attention_mask, token_type_ids, position_ids, inputs_embeds
|
||||
|
||||
@add_start_docstrings_to_callable(LONGFORMER_INPUTS_DOCSTRING)
|
||||
def forward(
|
||||
self,
|
||||
input_ids=None,
|
||||
attention_mask=None,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
inputs_embeds=None,
|
||||
masked_lm_labels=None,
|
||||
):
|
||||
r"""
|
||||
|
||||
Returns:
|
||||
:obj:`tuple(torch.FloatTensor)` comprising various elements depending on the configuration (:class:`~transformers.RobertaConfig`) and inputs:
|
||||
masked_lm_loss (`optional`, returned when ``masked_lm_labels`` is provided) ``torch.FloatTensor`` of shape ``(1,)``:
|
||||
Masked language modeling loss.
|
||||
prediction_scores (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, config.vocab_size)`)
|
||||
Prediction scores of the language modeling head (scores for each vocabulary token before SoftMax).
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape
|
||||
:obj:`(batch_size, num_heads, sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
|
||||
Examples::
|
||||
|
||||
import torch
|
||||
from transformers import LongformerModel, LongformerTokenizer
|
||||
|
||||
model = LongformerModel.from_pretrained('longformer-base-4096')
|
||||
tokenizer = LongformerTokenizer.from_pretrained('longformer-base-4096')
|
||||
|
||||
SAMPLE_TEXT = ' '.join(['Hello world! '] * 1000) # long input document
|
||||
input_ids = torch.tensor(tokenizer.encode(SAMPLE_TEXT)).unsqueeze(0) # batch of size 1
|
||||
|
||||
# Attention mask values -- 0: no attention, 1: local attention, 2: global attention
|
||||
attention_mask = torch.ones(input_ids.shape, dtype=torch.long, device=input_ids.device) # initialize to local attention
|
||||
attention_mask[:, [1, 4, 21,]] = 2 # Set global attention based on the task. For example,
|
||||
# classification: the <s> token
|
||||
# QA: question tokens
|
||||
# LM: potentially on the beginning of sentences and paragraphs
|
||||
sequence_output, pooled_output = model(input_ids, attention_mask=attention_mask)
|
||||
"""
|
||||
|
||||
# padding
|
||||
attention_window = (
|
||||
self.config.attention_window
|
||||
if isinstance(self.config.attention_window, int)
|
||||
else max(self.config.attention_window)
|
||||
)
|
||||
padding_len, input_ids, attention_mask, token_type_ids, position_ids, inputs_embeds = self._pad_to_window_size(
|
||||
input_ids=input_ids,
|
||||
attention_mask=attention_mask,
|
||||
token_type_ids=token_type_ids,
|
||||
position_ids=position_ids,
|
||||
inputs_embeds=inputs_embeds,
|
||||
attention_window=attention_window,
|
||||
pad_token_id=self.config.pad_token_id,
|
||||
)
|
||||
|
||||
# embed
|
||||
output = super().forward(
|
||||
input_ids=input_ids,
|
||||
attention_mask=attention_mask,
|
||||
token_type_ids=token_type_ids,
|
||||
position_ids=position_ids,
|
||||
head_mask=None,
|
||||
inputs_embeds=inputs_embeds,
|
||||
encoder_hidden_states=None,
|
||||
encoder_attention_mask=None,
|
||||
)
|
||||
|
||||
# undo padding
|
||||
if padding_len > 0:
|
||||
# `output` has the following tensors: sequence_output, pooled_output, (hidden_states), (attentions)
|
||||
# `sequence_output`: unpad because the calling function is expecting a length == input_ids.size(1)
|
||||
# `pooled_output`: independent of the sequence length
|
||||
# `hidden_states`: mainly used for debugging and analysis, so keep the padding
|
||||
# `attentions`: mainly used for debugging and analysis, so keep the padding
|
||||
output = output[0][:, :-padding_len], *output[1:]
|
||||
|
||||
return output
|
||||
|
||||
|
||||
@add_start_docstrings("""Longformer Model with a `language modeling` head on top. """, LONGFORMER_START_DOCSTRING)
|
||||
class LongformerForMaskedLM(BertPreTrainedModel):
|
||||
config_class = LongformerConfig
|
||||
pretrained_model_archive_map = LONGFORMER_PRETRAINED_MODEL_ARCHIVE_MAP
|
||||
base_model_prefix = "longformer"
|
||||
|
||||
def __init__(self, config):
|
||||
super().__init__(config)
|
||||
|
||||
self.longformer = LongformerModel(config)
|
||||
self.lm_head = RobertaLMHead(config)
|
||||
|
||||
self.init_weights()
|
||||
|
||||
@add_start_docstrings_to_callable(LONGFORMER_INPUTS_DOCSTRING)
|
||||
def forward(
|
||||
self,
|
||||
input_ids=None,
|
||||
attention_mask=None,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
inputs_embeds=None,
|
||||
masked_lm_labels=None,
|
||||
):
|
||||
r"""
|
||||
masked_lm_labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`, defaults to :obj:`None`):
|
||||
Labels for computing the masked language modeling loss.
|
||||
Indices should be in ``[-100, 0, ..., config.vocab_size]`` (see ``input_ids`` docstring)
|
||||
Tokens with indices set to ``-100`` are ignored (masked), the loss is only computed for the tokens with labels
|
||||
in ``[0, ..., config.vocab_size]``
|
||||
|
||||
Returns:
|
||||
:obj:`tuple(torch.FloatTensor)` comprising various elements depending on the configuration (:class:`~transformers.RobertaConfig`) and inputs:
|
||||
masked_lm_loss (`optional`, returned when ``masked_lm_labels`` is provided) ``torch.FloatTensor`` of shape ``(1,)``:
|
||||
Masked language modeling loss.
|
||||
prediction_scores (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, config.vocab_size)`)
|
||||
Prediction scores of the language modeling head (scores for each vocabulary token before SoftMax).
|
||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``config.output_hidden_states=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape
|
||||
:obj:`(batch_size, num_heads, sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
|
||||
Examples::
|
||||
|
||||
import torch
|
||||
from transformers import LongformerForMaskedLM, LongformerTokenizer
|
||||
|
||||
model = LongformerForMaskedLM.from_pretrained('longformer-base-4096')
|
||||
tokenizer = LongformerTokenizer.from_pretrained('longformer-base-4096')
|
||||
|
||||
SAMPLE_TEXT = ' '.join(['Hello world! '] * 1000) # long input document
|
||||
input_ids = torch.tensor(tokenizer.encode(SAMPLE_TEXT)).unsqueeze(0) # batch of size 1
|
||||
|
||||
attention_mask = None # default is local attention everywhere, which is a good choice for MaskedLM
|
||||
# check ``LongformerModel.forward`` for more details how to set `attention_mask`
|
||||
loss, prediction_scores = model(input_ids, attention_mask=attention_mask, masked_lm_labels=input_ids)
|
||||
"""
|
||||
|
||||
outputs = self.longformer(
|
||||
input_ids,
|
||||
attention_mask=attention_mask,
|
||||
token_type_ids=token_type_ids,
|
||||
position_ids=position_ids,
|
||||
inputs_embeds=inputs_embeds,
|
||||
)
|
||||
sequence_output = outputs[0]
|
||||
prediction_scores = self.lm_head(sequence_output)
|
||||
|
||||
outputs = (prediction_scores,) + outputs[2:] # Add hidden states and attention if they are here
|
||||
|
||||
if masked_lm_labels is not None:
|
||||
loss_fct = CrossEntropyLoss()
|
||||
masked_lm_loss = loss_fct(prediction_scores.view(-1, self.config.vocab_size), masked_lm_labels.view(-1))
|
||||
outputs = (masked_lm_loss,) + outputs
|
||||
|
||||
return outputs # (masked_lm_loss), prediction_scores, (hidden_states), (attentions)
|
||||
@@ -770,7 +770,7 @@ class PreTrainedModel(nn.Module, ModuleUtilsMixin):
|
||||
import torch_xla.core.xla_model as xm
|
||||
|
||||
model = xm.send_cpu_data_to_device(model, xm.xla_device())
|
||||
model = model.to(xm.xla_device())
|
||||
model.to(xm.xla_device())
|
||||
|
||||
return model
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ class AdamW(Optimizer):
|
||||
bias_correction2 = 1.0 - beta2 ** state["step"]
|
||||
step_size = step_size * math.sqrt(bias_correction2) / bias_correction1
|
||||
|
||||
p.data.addcdiv_(-step_size, exp_avg, denom)
|
||||
p.data.addcdiv_(exp_avg, denom, value=-step_size)
|
||||
|
||||
# Just adding the square of the weights to the loss function is *not*
|
||||
# the correct way of using L2 regularization/weight decay with Adam,
|
||||
|
||||
@@ -75,7 +75,7 @@ def create_optimizer(init_lr, num_train_steps, num_warmup_steps, end_lr=0.0, opt
|
||||
beta_1=0.9,
|
||||
beta_2=0.999,
|
||||
epsilon=1e-6,
|
||||
exclude_from_weight_decay=["layer_norm", "bias"],
|
||||
exclude_from_weight_decay=["LayerNorm", "layer_norm", "bias"],
|
||||
)
|
||||
|
||||
return optimizer
|
||||
|
||||
@@ -29,6 +29,7 @@ from .configuration_auto import (
|
||||
ElectraConfig,
|
||||
FlaubertConfig,
|
||||
GPT2Config,
|
||||
LongformerConfig,
|
||||
OpenAIGPTConfig,
|
||||
ReformerConfig,
|
||||
RobertaConfig,
|
||||
@@ -50,6 +51,7 @@ from .tokenization_distilbert import DistilBertTokenizer, DistilBertTokenizerFas
|
||||
from .tokenization_electra import ElectraTokenizer, ElectraTokenizerFast
|
||||
from .tokenization_flaubert import FlaubertTokenizer
|
||||
from .tokenization_gpt2 import GPT2Tokenizer, GPT2TokenizerFast
|
||||
from .tokenization_longformer import LongformerTokenizer
|
||||
from .tokenization_marian import MarianTokenizer
|
||||
from .tokenization_openai import OpenAIGPTTokenizer, OpenAIGPTTokenizerFast
|
||||
from .tokenization_reformer import ReformerTokenizer
|
||||
@@ -73,6 +75,7 @@ TOKENIZER_MAPPING = OrderedDict(
|
||||
(XLMRobertaConfig, (XLMRobertaTokenizer, None)),
|
||||
(MarianConfig, (MarianTokenizer, None)),
|
||||
(BartConfig, (BartTokenizer, None)),
|
||||
(LongformerConfig, (LongformerTokenizer, None)),
|
||||
(RobertaConfig, (RobertaTokenizer, RobertaTokenizerFast)),
|
||||
(ReformerConfig, (ReformerTokenizer, None)),
|
||||
(ElectraConfig, (ElectraTokenizer, ElectraTokenizerFast)),
|
||||
@@ -105,6 +108,7 @@ class AutoTokenizer:
|
||||
- contains `albert`: AlbertTokenizer (ALBERT model)
|
||||
- contains `camembert`: CamembertTokenizer (CamemBERT model)
|
||||
- contains `xlm-roberta`: XLMRobertaTokenizer (XLM-RoBERTa model)
|
||||
- contains `longformer`: LongformerTokenizer (AllenAI Longformer model)
|
||||
- contains `roberta`: RobertaTokenizer (RoBERTa model)
|
||||
- contains `bert`: BertTokenizer (Bert model)
|
||||
- contains `openai-gpt`: OpenAIGPTTokenizer (OpenAI GPT model)
|
||||
@@ -136,6 +140,7 @@ class AutoTokenizer:
|
||||
- contains `albert`: AlbertTokenizer (ALBERT model)
|
||||
- contains `camembert`: CamembertTokenizer (CamemBERT model)
|
||||
- contains `xlm-roberta`: XLMRobertaTokenizer (XLM-RoBERTa model)
|
||||
- contains `longformer`: LongformerTokenizer (AllenAI Longformer model)
|
||||
- contains `roberta`: RobertaTokenizer (RoBERTa model)
|
||||
- contains `bert-base-japanese`: BertJapaneseTokenizer (Bert model)
|
||||
- contains `bert`: BertTokenizer (Bert model)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2020 The Allen Institute for AI team and The HuggingFace Inc. team.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
|
||||
from .tokenization_roberta import RobertaTokenizer
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# vocab and merges same as roberta
|
||||
vocab_url = "https://s3.amazonaws.com/models.huggingface.co/bert/roberta-large-vocab.json"
|
||||
merges_url = "https://s3.amazonaws.com/models.huggingface.co/bert/roberta-large-merges.txt"
|
||||
_all_longformer_models = ["longformer-base-4096", "longformer-large-4096"]
|
||||
|
||||
|
||||
PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES = {
|
||||
"longformer-base-4096": 4096,
|
||||
"longformer-large-4096": 4096,
|
||||
}
|
||||
|
||||
|
||||
class LongformerTokenizer(RobertaTokenizer):
|
||||
# merges and vocab same as Roberta
|
||||
max_model_input_sizes = PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
|
||||
pretrained_vocab_files_map = {
|
||||
"vocab_file": {m: vocab_url for m in _all_longformer_models},
|
||||
"merges_file": {m: merges_url for m in _all_longformer_models},
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import json
|
||||
import re
|
||||
import warnings
|
||||
from typing import Dict, List, Optional, Union
|
||||
from pathlib import Path
|
||||
from shutil import copyfile
|
||||
from typing import Dict, List, Optional, Tuple, Union
|
||||
|
||||
import sentencepiece
|
||||
|
||||
@@ -15,7 +17,7 @@ vocab_files_names = {
|
||||
"vocab": "vocab.json",
|
||||
"tokenizer_config_file": "tokenizer_config.json",
|
||||
}
|
||||
MODEL_NAMES = ("opus-mt-en-de",) # TODO(SS): the only required constant is vocab_files_names
|
||||
MODEL_NAMES = ("opus-mt-en-de",) # TODO(SS): delete this, 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()
|
||||
@@ -55,14 +57,16 @@ class MarianTokenizer(PreTrainedTokenizer):
|
||||
eos_token="</s>",
|
||||
pad_token="<pad>",
|
||||
max_len=512,
|
||||
**kwargs,
|
||||
):
|
||||
|
||||
super().__init__(
|
||||
# bos_token=bos_token,
|
||||
# bos_token=bos_token, unused. Start decoding with config.decoder_start_token_id
|
||||
max_len=max_len,
|
||||
eos_token=eos_token,
|
||||
unk_token=unk_token,
|
||||
pad_token=pad_token,
|
||||
**kwargs,
|
||||
)
|
||||
self.encoder = load_json(vocab)
|
||||
if self.unk_token not in self.encoder:
|
||||
@@ -72,21 +76,23 @@ class MarianTokenizer(PreTrainedTokenizer):
|
||||
|
||||
self.source_lang = source_lang
|
||||
self.target_lang = target_lang
|
||||
self.supported_language_codes: list = [k for k in self.encoder if k.startswith(">>") and k.endswith("<<")]
|
||||
self.spm_files = [source_spm, target_spm]
|
||||
|
||||
# load SentencePiece model for pre-processing
|
||||
self.spm_source = sentencepiece.SentencePieceProcessor()
|
||||
self.spm_source.Load(source_spm)
|
||||
|
||||
self.spm_target = sentencepiece.SentencePieceProcessor()
|
||||
self.spm_target.Load(target_spm)
|
||||
self.spm_source = load_spm(source_spm)
|
||||
self.spm_target = load_spm(target_spm)
|
||||
self.current_spm = self.spm_source
|
||||
|
||||
# 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._setup_normalizer()
|
||||
|
||||
def _setup_normalizer(self):
|
||||
try:
|
||||
from mosestokenizer import MosesPunctuationNormalizer
|
||||
|
||||
self.punc_normalizer = MosesPunctuationNormalizer(source_lang)
|
||||
self.punc_normalizer = MosesPunctuationNormalizer(self.source_lang)
|
||||
except ImportError:
|
||||
warnings.warn("Recommended: pip install mosestokenizer")
|
||||
self.punc_normalizer = lambda x: x
|
||||
@@ -176,6 +182,65 @@ class MarianTokenizer(PreTrainedTokenizer):
|
||||
def vocab_size(self) -> int:
|
||||
return len(self.encoder)
|
||||
|
||||
def save_vocabulary(self, save_directory: str) -> Tuple[str]:
|
||||
"""save vocab file to json and copy spm files from their original path."""
|
||||
save_dir = Path(save_directory)
|
||||
assert save_dir.is_dir(), f"{save_directory} should be a directory"
|
||||
save_json(self.encoder, save_dir / self.vocab_files_names["vocab"])
|
||||
|
||||
for f in self.spm_files:
|
||||
dest_path = save_dir / Path(f).name
|
||||
if not dest_path.exists():
|
||||
copyfile(f, save_dir / Path(f).name)
|
||||
return tuple(save_dir / f for f in self.vocab_files_names)
|
||||
|
||||
def get_vocab(self) -> Dict:
|
||||
vocab = self.encoder.copy()
|
||||
vocab.update(self.added_tokens_encoder)
|
||||
return vocab
|
||||
|
||||
def __getstate__(self) -> Dict:
|
||||
state = self.__dict__.copy()
|
||||
state.update({k: None for k in ["spm_source", "spm_target", "current_spm", "punc_normalizer"]})
|
||||
return state
|
||||
|
||||
def __setstate__(self, d: Dict) -> None:
|
||||
self.__dict__ = d
|
||||
self.spm_source, self.spm_target = (load_spm(f) for f in self.spm_files)
|
||||
self.current_spm = self.spm_source
|
||||
self._setup_normalizer()
|
||||
|
||||
def num_special_tokens_to_add(self, **unused):
|
||||
"""Just EOS"""
|
||||
return 1
|
||||
|
||||
def _special_token_mask(self, seq):
|
||||
all_special_ids = set(self.all_special_ids) # call it once instead of inside list comp
|
||||
all_special_ids.remove(self.unk_token_id) # <unk> is only sometimes special
|
||||
return [1 if x in all_special_ids else 0 for x in seq]
|
||||
|
||||
def get_special_tokens_mask(
|
||||
self, token_ids_0: List, token_ids_1: Optional[List] = None, already_has_special_tokens: bool = False
|
||||
) -> List[int]:
|
||||
"""Get list where entries are [1] if a token is [eos] or [pad] else 0."""
|
||||
if already_has_special_tokens:
|
||||
return self._special_token_mask(token_ids_0)
|
||||
elif token_ids_1 is None:
|
||||
return self._special_token_mask(token_ids_0) + [1]
|
||||
else:
|
||||
return self._special_token_mask(token_ids_0 + token_ids_1) + [1]
|
||||
|
||||
|
||||
def load_spm(path: str) -> sentencepiece.SentencePieceProcessor:
|
||||
spm = sentencepiece.SentencePieceProcessor()
|
||||
spm.Load(path)
|
||||
return spm
|
||||
|
||||
|
||||
def save_json(data, path: str) -> None:
|
||||
with open(path, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
|
||||
def load_json(path: str) -> Union[Dict, List]:
|
||||
with open(path, "r") as f:
|
||||
|
||||
@@ -199,7 +199,7 @@ class RobertaTokenizer(GPT2Tokenizer):
|
||||
if token_ids_1 is not None:
|
||||
raise ValueError(
|
||||
"You should not supply a second sequence if the provided sequence of "
|
||||
"ids is already formated with special tokens for the model."
|
||||
"ids is already formatted with special tokens for the model."
|
||||
)
|
||||
return list(map(lambda x: 1 if x in [self.sep_token_id, self.cls_token_id] else 0, token_ids_0))
|
||||
|
||||
|
||||
@@ -771,26 +771,26 @@ class PreTrainedTokenizer(SpecialTokensMixin):
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def is_fast(self):
|
||||
def is_fast(self) -> bool:
|
||||
return False
|
||||
|
||||
@property
|
||||
def max_len(self):
|
||||
def max_len(self) -> int:
|
||||
""" Kept here for backward compatibility.
|
||||
Now renamed to `model_max_length` to avoid ambiguity.
|
||||
"""
|
||||
return self.model_max_length
|
||||
|
||||
@property
|
||||
def max_len_single_sentence(self):
|
||||
def max_len_single_sentence(self) -> int:
|
||||
return self.model_max_length - self.num_special_tokens_to_add(pair=False)
|
||||
|
||||
@property
|
||||
def max_len_sentences_pair(self):
|
||||
def max_len_sentences_pair(self) -> int:
|
||||
return self.model_max_length - self.num_special_tokens_to_add(pair=True)
|
||||
|
||||
@max_len_single_sentence.setter
|
||||
def max_len_single_sentence(self, value):
|
||||
def max_len_single_sentence(self, value) -> int:
|
||||
""" For backward compatibility, allow to try to setup 'max_len_single_sentence' """
|
||||
if value == self.model_max_length - self.num_special_tokens_to_add(pair=False):
|
||||
logger.warning(
|
||||
@@ -802,7 +802,7 @@ class PreTrainedTokenizer(SpecialTokensMixin):
|
||||
)
|
||||
|
||||
@max_len_sentences_pair.setter
|
||||
def max_len_sentences_pair(self, value):
|
||||
def max_len_sentences_pair(self, value) -> int:
|
||||
""" For backward compatibility, allow to try to setup 'max_len_sentences_pair' """
|
||||
if value == self.model_max_length - self.num_special_tokens_to_add(pair=True):
|
||||
logger.warning(
|
||||
@@ -1118,7 +1118,7 @@ class PreTrainedTokenizer(SpecialTokensMixin):
|
||||
|
||||
return vocab_files + (special_tokens_map_file, added_tokens_file)
|
||||
|
||||
def save_vocabulary(self, save_directory):
|
||||
def save_vocabulary(self, save_directory) -> Tuple[str]:
|
||||
""" Save the tokenizer vocabulary to a directory. This method does *NOT* save added tokens
|
||||
and special token mappings.
|
||||
|
||||
@@ -1128,7 +1128,7 @@ class PreTrainedTokenizer(SpecialTokensMixin):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def add_tokens(self, new_tokens):
|
||||
def add_tokens(self, new_tokens: Union[str, List[str]]) -> int:
|
||||
"""
|
||||
Add a list of new tokens to the tokenizer class. If the new tokens are not in the
|
||||
vocabulary, they are added to it with indices starting from length of the current vocabulary.
|
||||
@@ -1156,7 +1156,7 @@ class PreTrainedTokenizer(SpecialTokensMixin):
|
||||
if not isinstance(new_tokens, list):
|
||||
new_tokens = [new_tokens]
|
||||
|
||||
to_add_tokens = []
|
||||
tokens_to_add = []
|
||||
for token in new_tokens:
|
||||
assert isinstance(token, str)
|
||||
if self.init_kwargs.get("do_lower_case", False) and token not in self.all_special_tokens:
|
||||
@@ -1164,18 +1164,18 @@ class PreTrainedTokenizer(SpecialTokensMixin):
|
||||
if (
|
||||
token != self.unk_token
|
||||
and self.convert_tokens_to_ids(token) == self.convert_tokens_to_ids(self.unk_token)
|
||||
and token not in to_add_tokens
|
||||
and token not in tokens_to_add
|
||||
):
|
||||
to_add_tokens.append(token)
|
||||
tokens_to_add.append(token)
|
||||
logger.info("Adding %s to the vocabulary", token)
|
||||
|
||||
added_tok_encoder = dict((tok, len(self) + i) for i, tok in enumerate(to_add_tokens))
|
||||
added_tok_encoder = dict((tok, len(self) + i) for i, tok in enumerate(tokens_to_add))
|
||||
added_tok_decoder = {v: k for k, v in added_tok_encoder.items()}
|
||||
self.added_tokens_encoder.update(added_tok_encoder)
|
||||
self.unique_added_tokens_encoder = set(self.added_tokens_encoder.keys()).union(set(self.all_special_tokens))
|
||||
self.added_tokens_decoder.update(added_tok_decoder)
|
||||
|
||||
return len(to_add_tokens)
|
||||
return len(tokens_to_add)
|
||||
|
||||
def num_special_tokens_to_add(self, pair=False):
|
||||
"""
|
||||
@@ -2080,10 +2080,7 @@ class PreTrainedTokenizer(SpecialTokensMixin):
|
||||
def build_inputs_with_special_tokens(self, token_ids_0: List, token_ids_1: Optional[List] = None) -> List:
|
||||
"""
|
||||
Build model inputs from a sequence or a pair of sequence for sequence classification tasks
|
||||
by concatenating and adding special tokens.
|
||||
A RoBERTa sequence has the following format:
|
||||
single sequence: <s> X </s>
|
||||
pair of sequences: <s> A </s></s> B </s>
|
||||
by concatenating and adding special tokens. This implementation does not add special tokens.
|
||||
"""
|
||||
if token_ids_1 is None:
|
||||
return token_ids_0
|
||||
|
||||
+34
-39
@@ -7,11 +7,10 @@ import re
|
||||
import shutil
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
from typing import Callable, Dict, List, Optional, Tuple, Union
|
||||
from typing import Callable, Dict, List, Optional, Tuple
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
from packaging import version
|
||||
from torch import nn
|
||||
from torch.utils.data.dataloader import DataLoader
|
||||
from torch.utils.data.dataset import Dataset
|
||||
@@ -242,9 +241,6 @@ class Trainer:
|
||||
collate_fn=self.data_collator.collate_batch,
|
||||
)
|
||||
|
||||
if is_tpu_available():
|
||||
data_loader = pl.ParallelLoader(data_loader, [self.args.device]).per_device_loader(self.args.device)
|
||||
|
||||
return data_loader
|
||||
|
||||
def get_eval_dataloader(self, eval_dataset: Optional[Dataset] = None) -> DataLoader:
|
||||
@@ -269,9 +265,6 @@ class Trainer:
|
||||
collate_fn=self.data_collator.collate_batch,
|
||||
)
|
||||
|
||||
if is_tpu_available():
|
||||
data_loader = pl.ParallelLoader(data_loader, [self.args.device]).per_device_loader(self.args.device)
|
||||
|
||||
return data_loader
|
||||
|
||||
def get_test_dataloader(self, test_dataset: Dataset) -> DataLoader:
|
||||
@@ -292,9 +285,6 @@ class Trainer:
|
||||
collate_fn=self.data_collator.collate_batch,
|
||||
)
|
||||
|
||||
if is_tpu_available():
|
||||
data_loader = pl.ParallelLoader(data_loader, [self.args.device]).per_device_loader(self.args.device)
|
||||
|
||||
return data_loader
|
||||
|
||||
def get_optimizers(
|
||||
@@ -351,15 +341,11 @@ class Trainer:
|
||||
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:
|
||||
def num_examples(self, dataloader: DataLoader) -> int:
|
||||
"""
|
||||
Helper to get num of examples from a DataLoader, by accessing its Dataset.
|
||||
"""
|
||||
if is_tpu_available():
|
||||
assert isinstance(dataloader, pl.PerDeviceLoader)
|
||||
return len(dataloader._loader._loader.dataset)
|
||||
else:
|
||||
return len(dataloader.dataset)
|
||||
return len(dataloader.dataset)
|
||||
|
||||
def train(self, model_path: Optional[str] = None):
|
||||
"""
|
||||
@@ -466,7 +452,14 @@ class Trainer:
|
||||
if isinstance(train_dataloader, DataLoader) and isinstance(train_dataloader.sampler, DistributedSampler):
|
||||
train_dataloader.sampler.set_epoch(epoch)
|
||||
|
||||
epoch_iterator = tqdm(train_dataloader, desc="Iteration", disable=not self.is_local_master())
|
||||
if is_tpu_available():
|
||||
parallel_loader = pl.ParallelLoader(train_dataloader, [self.args.device]).per_device_loader(
|
||||
self.args.device
|
||||
)
|
||||
epoch_iterator = tqdm(parallel_loader, desc="Iteration", disable=not self.is_local_master())
|
||||
else:
|
||||
epoch_iterator = tqdm(train_dataloader, desc="Iteration", disable=not self.is_local_master())
|
||||
|
||||
for step, inputs in enumerate(epoch_iterator):
|
||||
|
||||
# Skip past any already trained steps if resuming training
|
||||
@@ -501,11 +494,8 @@ class Trainer:
|
||||
):
|
||||
logs: Dict[str, float] = {}
|
||||
logs["loss"] = (tr_loss - logging_loss) / self.args.logging_steps
|
||||
# backward compatibility for pytorch schedulers
|
||||
logs["learning_rate"] = (
|
||||
scheduler.get_last_lr()[0]
|
||||
if version.parse(torch.__version__) >= version.parse("1.4")
|
||||
else scheduler.get_lr()[0]
|
||||
)
|
||||
logging_loss = tr_loss
|
||||
|
||||
@@ -514,24 +504,28 @@ class Trainer:
|
||||
if self.args.evaluate_during_training:
|
||||
self.evaluate()
|
||||
|
||||
if self.is_world_master():
|
||||
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"):
|
||||
assert model.module is self.model
|
||||
else:
|
||||
assert model is self.model
|
||||
# Save model checkpoint
|
||||
output_dir = os.path.join(
|
||||
self.args.output_dir, f"{PREFIX_CHECKPOINT_DIR}-{self.global_step}"
|
||||
)
|
||||
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"):
|
||||
assert model.module is self.model
|
||||
else:
|
||||
assert model is self.model
|
||||
# Save model checkpoint
|
||||
output_dir = os.path.join(self.args.output_dir, f"{PREFIX_CHECKPOINT_DIR}-{self.global_step}")
|
||||
|
||||
self.save_model(output_dir)
|
||||
self.save_model(output_dir)
|
||||
|
||||
if self.is_world_master():
|
||||
self._rotate_checkpoints()
|
||||
|
||||
if is_tpu_available():
|
||||
xm.rendezvous("saving_optimizer_states")
|
||||
xm.save(optimizer.state_dict(), os.path.join(output_dir, "optimizer.pt"))
|
||||
xm.save(scheduler.state_dict(), os.path.join(output_dir, "scheduler.pt"))
|
||||
elif self.is_world_master():
|
||||
torch.save(optimizer.state_dict(), os.path.join(output_dir, "optimizer.pt"))
|
||||
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 self.global_step > self.args.max_steps:
|
||||
epoch_iterator.close()
|
||||
@@ -713,6 +707,7 @@ class Trainer:
|
||||
In that case, this method will also return metrics, like in evaluate().
|
||||
"""
|
||||
test_dataloader = self.get_test_dataloader(test_dataset)
|
||||
|
||||
return self._prediction_loop(test_dataloader, description="Prediction")
|
||||
|
||||
def _prediction_loop(
|
||||
@@ -735,10 +730,7 @@ class Trainer:
|
||||
# Note: in torch.distributed mode, there's no point in wrapping the model
|
||||
# inside a DistributedDataParallel as we'll be under `no_grad` anyways.
|
||||
|
||||
if is_tpu_available():
|
||||
batch_size = dataloader._loader._loader.batch_size
|
||||
else:
|
||||
batch_size = dataloader.batch_size
|
||||
batch_size = dataloader.batch_size
|
||||
logger.info("***** Running %s *****", description)
|
||||
logger.info(" Num examples = %d", self.num_examples(dataloader))
|
||||
logger.info(" Batch size = %d", batch_size)
|
||||
@@ -747,6 +739,9 @@ class Trainer:
|
||||
label_ids: torch.Tensor = None
|
||||
model.eval()
|
||||
|
||||
if is_tpu_available():
|
||||
dataloader = pl.ParallelLoader(dataloader, [self.args.device]).per_device_loader(self.args.device)
|
||||
|
||||
for inputs in tqdm(dataloader, desc=description):
|
||||
has_labels = any(inputs.get(k) is not None for k in ["labels", "lm_labels", "masked_lm_labels"])
|
||||
|
||||
|
||||
@@ -141,7 +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))
|
||||
logger.info("Created an/a {} optimizer".format(self.args.optimizer_name))
|
||||
|
||||
def _create_checkpoint_manager(self, max_to_keep: int = 5, load_model: bool = True) -> None:
|
||||
"""
|
||||
@@ -335,12 +335,8 @@ class TFTrainer:
|
||||
gradient / tf.cast(gradient_scale, gradient.dtype) for gradient in self.gradient_accumulator.gradients
|
||||
]
|
||||
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 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)))
|
||||
self.optimizer.apply_gradients(list(zip(gradients, self.model.trainable_variables)))
|
||||
self.gradient_accumulator.reset()
|
||||
|
||||
def _accumulate_next_gradients(self):
|
||||
@@ -375,12 +371,10 @@ class TFTrainer:
|
||||
def _forward(self, features, labels):
|
||||
"""Forwards a training example and accumulates the gradients."""
|
||||
per_example_loss, _ = self._run_model(features, labels, True)
|
||||
vars = self.model.trainable_variables
|
||||
|
||||
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)
|
||||
gradients = tf.gradients(per_example_loss, self.model.trainable_variables)
|
||||
gradients = [
|
||||
g if g is not None else tf.zeros_like(v) for g, v in zip(gradients, self.model.trainable_variables)
|
||||
]
|
||||
|
||||
self.gradient_accumulator(gradients)
|
||||
|
||||
|
||||
@@ -80,8 +80,9 @@ class AutoModelTest(unittest.TestCase):
|
||||
model, loading_info = AutoModelForPreTraining.from_pretrained(model_name, output_loading_info=True)
|
||||
self.assertIsNotNone(model)
|
||||
self.assertIsInstance(model, BertForPreTraining)
|
||||
for value in loading_info.values():
|
||||
self.assertEqual(len(value), 0)
|
||||
for key, value in loading_info.items():
|
||||
# Only one value should not be initialized and in the missing keys.
|
||||
self.assertEqual(len(value), 1 if key == "missing_keys" else 0)
|
||||
|
||||
@slow
|
||||
def test_lmhead_model_from_pretrained(self):
|
||||
|
||||
@@ -231,7 +231,7 @@ class BartTranslationTests(unittest.TestCase):
|
||||
"""Only load the model if needed."""
|
||||
if self._model is None:
|
||||
model = BartForConditionalGeneration.from_pretrained("mbart-large-en-ro")
|
||||
self._model = model
|
||||
self._model = model.to(torch_device)
|
||||
return self._model
|
||||
|
||||
@slow
|
||||
@@ -257,10 +257,7 @@ class BartTranslationTests(unittest.TestCase):
|
||||
)
|
||||
}
|
||||
translated_tokens = model.generate(input_ids=inputs["input_ids"].to(torch_device), num_beams=5,)
|
||||
decoded = [
|
||||
self.tokenizer.decode(g, skip_special_tokens=True, clean_up_tokenization_spaces=False)
|
||||
for g in translated_tokens
|
||||
]
|
||||
decoded = self.tokenizer.batch_decode(translated_tokens, skip_special_tokens=True)
|
||||
self.assertEqual(expected_translation_romanian, decoded[0])
|
||||
|
||||
def test_mbart_enro_config(self):
|
||||
@@ -576,11 +573,13 @@ class BartModelIntegrationTests(unittest.TestCase):
|
||||
|
||||
PGE_ARTICLE = """ PG&E stated it scheduled the blackouts in response to forecasts for high winds amid dry conditions. The aim is to reduce the risk of wildfires. Nearly 800 thousand customers were scheduled to be affected by the shutoffs which were expected to last through at least midday tomorrow."""
|
||||
EXPECTED_SUMMARY = "California's largest power company has begun shutting off power to tens of thousands of homes and businesses in the state."
|
||||
dct = tok.batch_encode_plus([PGE_ARTICLE], max_length=1024, pad_to_max_length=True, return_tensors="pt",)
|
||||
dct = tok.batch_encode_plus([PGE_ARTICLE], max_length=1024, pad_to_max_length=True, return_tensors="pt",).to(
|
||||
torch_device
|
||||
)
|
||||
|
||||
hypotheses_batch = model.generate(
|
||||
input_ids=dct["input_ids"].to(torch_device),
|
||||
attention_mask=dct["attention_mask"].to(torch_device),
|
||||
input_ids=dct["input_ids"],
|
||||
attention_mask=dct["attention_mask"],
|
||||
num_beams=2,
|
||||
max_length=62,
|
||||
min_length=11,
|
||||
@@ -590,9 +589,7 @@ class BartModelIntegrationTests(unittest.TestCase):
|
||||
decoder_start_token_id=model.config.eos_token_id,
|
||||
)
|
||||
|
||||
decoded = [
|
||||
tok.decode(g, skip_special_tokens=True, clean_up_tokenization_spaces=False) for g in hypotheses_batch
|
||||
]
|
||||
decoded = tok.batch_decode(hypotheses_batch, skip_special_tokens=True,)
|
||||
self.assertEqual(EXPECTED_SUMMARY, decoded[0])
|
||||
|
||||
def test_xsum_config_generation_params(self):
|
||||
|
||||
@@ -30,6 +30,7 @@ class CamembertModelIntegrationTest(unittest.TestCase):
|
||||
@slow
|
||||
def test_output_embeds_base_model(self):
|
||||
model = CamembertModel.from_pretrained("camembert-base")
|
||||
model.to(torch_device)
|
||||
|
||||
input_ids = torch.tensor(
|
||||
[[5, 121, 11, 660, 16, 730, 25543, 110, 83, 6]], device=torch_device, dtype=torch.long,
|
||||
|
||||
@@ -219,6 +219,7 @@ class CTRLModelLanguageGenerationTest(unittest.TestCase):
|
||||
@slow
|
||||
def test_lm_generate_ctrl(self):
|
||||
model = CTRLLMHeadModel.from_pretrained("ctrl")
|
||||
model.to(torch_device)
|
||||
input_ids = torch.tensor(
|
||||
[[11859, 0, 1611, 8]], dtype=torch.long, device=torch_device
|
||||
) # Legal the president is
|
||||
|
||||
@@ -30,6 +30,7 @@ if is_torch_available():
|
||||
ElectraForMaskedLM,
|
||||
ElectraForTokenClassification,
|
||||
ElectraForPreTraining,
|
||||
ElectraForSequenceClassification,
|
||||
)
|
||||
from transformers.modeling_electra import ELECTRA_PRETRAINED_MODEL_ARCHIVE_MAP
|
||||
|
||||
@@ -242,6 +243,31 @@ class ElectraModelTest(ModelTesterMixin, unittest.TestCase):
|
||||
self.parent.assertListEqual(list(result["logits"].size()), [self.batch_size, self.seq_length])
|
||||
self.check_loss_output(result)
|
||||
|
||||
def create_and_check_electra_for_sequence_classification(
|
||||
self,
|
||||
config,
|
||||
input_ids,
|
||||
token_type_ids,
|
||||
input_mask,
|
||||
sequence_labels,
|
||||
token_labels,
|
||||
choice_labels,
|
||||
fake_token_labels,
|
||||
):
|
||||
config.num_labels = self.num_labels
|
||||
model = ElectraForSequenceClassification(config)
|
||||
model.to(torch_device)
|
||||
model.eval()
|
||||
loss, logits = model(
|
||||
input_ids, attention_mask=input_mask, token_type_ids=token_type_ids, labels=sequence_labels
|
||||
)
|
||||
result = {
|
||||
"loss": loss,
|
||||
"logits": logits,
|
||||
}
|
||||
self.parent.assertListEqual(list(result["logits"].size()), [self.batch_size, self.num_labels])
|
||||
self.check_loss_output(result)
|
||||
|
||||
def prepare_config_and_inputs_for_common(self):
|
||||
config_and_inputs = self.prepare_config_and_inputs()
|
||||
(
|
||||
@@ -280,6 +306,10 @@ class ElectraModelTest(ModelTesterMixin, unittest.TestCase):
|
||||
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
||||
self.model_tester.create_and_check_electra_for_pretraining(*config_and_inputs)
|
||||
|
||||
def test_for_sequence_classification(self):
|
||||
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
||||
self.model_tester.create_and_check_electra_for_sequence_classification(*config_and_inputs)
|
||||
|
||||
@slow
|
||||
def test_model_from_pretrained(self):
|
||||
for model_name in list(ELECTRA_PRETRAINED_MODEL_ARCHIVE_MAP.keys())[:1]:
|
||||
|
||||
@@ -329,5 +329,5 @@ class EncoderDecoderModelTest(unittest.TestCase):
|
||||
|
||||
@slow
|
||||
def test_real_bert_model_from_pretrained(self):
|
||||
model = EncoderDecoderModel.from_pretrained("bert-base-uncased", "bert-base-uncased")
|
||||
model = EncoderDecoderModel.from_encoder_decoder_pretrained("bert-base-uncased", "bert-base-uncased")
|
||||
self.assertIsNotNone(model)
|
||||
@@ -343,6 +343,7 @@ class GPT2ModelLanguageGenerationTest(unittest.TestCase):
|
||||
@slow
|
||||
def test_lm_generate_gpt2(self):
|
||||
model = GPT2LMHeadModel.from_pretrained("gpt2")
|
||||
model.to(torch_device)
|
||||
input_ids = torch.tensor([[464, 3290]], dtype=torch.long, device=torch_device) # The dog
|
||||
expected_output_ids = [
|
||||
464,
|
||||
@@ -372,6 +373,7 @@ class GPT2ModelLanguageGenerationTest(unittest.TestCase):
|
||||
@slow
|
||||
def test_lm_generate_distilgpt2(self):
|
||||
model = GPT2LMHeadModel.from_pretrained("distilgpt2")
|
||||
model.to(torch_device)
|
||||
input_ids = torch.tensor([[464, 1893]], dtype=torch.long, device=torch_device) # The president
|
||||
expected_output_ids = [
|
||||
464,
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The Google AI Language Team Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
from transformers import is_torch_available
|
||||
|
||||
from .test_configuration_common import ConfigTester
|
||||
from .test_modeling_common import ModelTesterMixin, ids_tensor
|
||||
from .utils import require_torch, slow, torch_device
|
||||
|
||||
|
||||
if is_torch_available():
|
||||
import torch
|
||||
from transformers import (
|
||||
LongformerConfig,
|
||||
LongformerModel,
|
||||
LongformerForMaskedLM,
|
||||
)
|
||||
|
||||
|
||||
class LongformerModelTester(object):
|
||||
def __init__(
|
||||
self,
|
||||
parent,
|
||||
batch_size=13,
|
||||
seq_length=7,
|
||||
is_training=True,
|
||||
use_input_mask=True,
|
||||
use_token_type_ids=True,
|
||||
use_labels=True,
|
||||
vocab_size=99,
|
||||
hidden_size=32,
|
||||
num_hidden_layers=5,
|
||||
num_attention_heads=4,
|
||||
intermediate_size=37,
|
||||
hidden_act="gelu",
|
||||
hidden_dropout_prob=0.1,
|
||||
attention_probs_dropout_prob=0.1,
|
||||
max_position_embeddings=512,
|
||||
type_vocab_size=16,
|
||||
type_sequence_label_size=2,
|
||||
initializer_range=0.02,
|
||||
num_labels=3,
|
||||
num_choices=4,
|
||||
scope=None,
|
||||
attention_window=4,
|
||||
):
|
||||
self.parent = parent
|
||||
self.batch_size = batch_size
|
||||
self.seq_length = seq_length
|
||||
self.is_training = is_training
|
||||
self.use_input_mask = use_input_mask
|
||||
self.use_token_type_ids = use_token_type_ids
|
||||
self.use_labels = use_labels
|
||||
self.vocab_size = vocab_size
|
||||
self.hidden_size = hidden_size
|
||||
self.num_hidden_layers = num_hidden_layers
|
||||
self.num_attention_heads = num_attention_heads
|
||||
self.intermediate_size = intermediate_size
|
||||
self.hidden_act = hidden_act
|
||||
self.hidden_dropout_prob = hidden_dropout_prob
|
||||
self.attention_probs_dropout_prob = attention_probs_dropout_prob
|
||||
self.max_position_embeddings = max_position_embeddings
|
||||
self.type_vocab_size = type_vocab_size
|
||||
self.type_sequence_label_size = type_sequence_label_size
|
||||
self.initializer_range = initializer_range
|
||||
self.num_labels = num_labels
|
||||
self.num_choices = num_choices
|
||||
self.scope = scope
|
||||
self.attention_window = attention_window
|
||||
|
||||
# `ModelTesterMixin.test_attention_outputs` is expecting attention tensors to be of size
|
||||
# [num_attention_heads, encoder_seq_length, encoder_key_length], but LongformerSelfAttention
|
||||
# returns attention of shape [num_attention_heads, encoder_seq_length, self.attention_window + 1]
|
||||
# because its local attention only attends to `self.attention_window + 1` locations
|
||||
self.key_length = self.attention_window + 1
|
||||
|
||||
# because of padding `encoder_seq_length`, is different from `seq_length`. Relevant for
|
||||
# the `test_attention_outputs` and `test_hidden_states_output` tests
|
||||
self.encoder_seq_length = (
|
||||
self.seq_length + (self.attention_window - self.seq_length % self.attention_window) % self.attention_window
|
||||
)
|
||||
|
||||
def prepare_config_and_inputs(self):
|
||||
input_ids = ids_tensor([self.batch_size, self.seq_length], self.vocab_size)
|
||||
|
||||
input_mask = None
|
||||
if self.use_input_mask:
|
||||
input_mask = ids_tensor([self.batch_size, self.seq_length], vocab_size=2)
|
||||
|
||||
token_type_ids = None
|
||||
if self.use_token_type_ids:
|
||||
token_type_ids = ids_tensor([self.batch_size, self.seq_length], self.type_vocab_size)
|
||||
|
||||
sequence_labels = None
|
||||
token_labels = None
|
||||
choice_labels = None
|
||||
if self.use_labels:
|
||||
sequence_labels = ids_tensor([self.batch_size], self.type_sequence_label_size)
|
||||
token_labels = ids_tensor([self.batch_size, self.seq_length], self.num_labels)
|
||||
choice_labels = ids_tensor([self.batch_size], self.num_choices)
|
||||
|
||||
config = LongformerConfig(
|
||||
vocab_size=self.vocab_size,
|
||||
hidden_size=self.hidden_size,
|
||||
num_hidden_layers=self.num_hidden_layers,
|
||||
num_attention_heads=self.num_attention_heads,
|
||||
intermediate_size=self.intermediate_size,
|
||||
hidden_act=self.hidden_act,
|
||||
hidden_dropout_prob=self.hidden_dropout_prob,
|
||||
attention_probs_dropout_prob=self.attention_probs_dropout_prob,
|
||||
max_position_embeddings=self.max_position_embeddings,
|
||||
type_vocab_size=self.type_vocab_size,
|
||||
initializer_range=self.initializer_range,
|
||||
attention_window=self.attention_window,
|
||||
)
|
||||
|
||||
return config, input_ids, token_type_ids, input_mask, sequence_labels, token_labels, choice_labels
|
||||
|
||||
def check_loss_output(self, result):
|
||||
self.parent.assertListEqual(list(result["loss"].size()), [])
|
||||
|
||||
def create_and_check_longformer_model(
|
||||
self, config, input_ids, token_type_ids, input_mask, sequence_labels, token_labels, choice_labels
|
||||
):
|
||||
model = LongformerModel(config=config)
|
||||
model.to(torch_device)
|
||||
model.eval()
|
||||
sequence_output, pooled_output = model(input_ids, attention_mask=input_mask, token_type_ids=token_type_ids)
|
||||
sequence_output, pooled_output = model(input_ids, token_type_ids=token_type_ids)
|
||||
sequence_output, pooled_output = model(input_ids)
|
||||
|
||||
result = {
|
||||
"sequence_output": sequence_output,
|
||||
"pooled_output": pooled_output,
|
||||
}
|
||||
self.parent.assertListEqual(
|
||||
list(result["sequence_output"].size()), [self.batch_size, self.seq_length, self.hidden_size]
|
||||
)
|
||||
self.parent.assertListEqual(list(result["pooled_output"].size()), [self.batch_size, self.hidden_size])
|
||||
|
||||
def create_and_check_longformer_for_masked_lm(
|
||||
self, config, input_ids, token_type_ids, input_mask, sequence_labels, token_labels, choice_labels
|
||||
):
|
||||
model = LongformerForMaskedLM(config=config)
|
||||
model.to(torch_device)
|
||||
model.eval()
|
||||
loss, prediction_scores = model(
|
||||
input_ids, attention_mask=input_mask, token_type_ids=token_type_ids, masked_lm_labels=token_labels
|
||||
)
|
||||
result = {
|
||||
"loss": loss,
|
||||
"prediction_scores": prediction_scores,
|
||||
}
|
||||
self.parent.assertListEqual(
|
||||
list(result["prediction_scores"].size()), [self.batch_size, self.seq_length, self.vocab_size]
|
||||
)
|
||||
self.check_loss_output(result)
|
||||
|
||||
def prepare_config_and_inputs_for_common(self):
|
||||
config_and_inputs = self.prepare_config_and_inputs()
|
||||
(
|
||||
config,
|
||||
input_ids,
|
||||
token_type_ids,
|
||||
input_mask,
|
||||
sequence_labels,
|
||||
token_labels,
|
||||
choice_labels,
|
||||
) = config_and_inputs
|
||||
inputs_dict = {"input_ids": input_ids, "token_type_ids": token_type_ids, "attention_mask": input_mask}
|
||||
return config, inputs_dict
|
||||
|
||||
|
||||
@require_torch
|
||||
class LongformerModelTest(ModelTesterMixin, unittest.TestCase):
|
||||
test_pruning = False # pruning is not supported
|
||||
test_headmasking = False # head masking is not supported
|
||||
test_torchscript = False
|
||||
|
||||
all_model_classes = (LongformerForMaskedLM, LongformerModel) if is_torch_available() else ()
|
||||
|
||||
def setUp(self):
|
||||
self.model_tester = LongformerModelTester(self)
|
||||
self.config_tester = ConfigTester(self, config_class=LongformerConfig, hidden_size=37)
|
||||
|
||||
def test_config(self):
|
||||
self.config_tester.run_common_tests()
|
||||
|
||||
def test_longformer_model(self):
|
||||
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
||||
self.model_tester.create_and_check_longformer_model(*config_and_inputs)
|
||||
|
||||
def test_longformer_for_masked_lm(self):
|
||||
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
||||
self.model_tester.create_and_check_longformer_for_masked_lm(*config_and_inputs)
|
||||
|
||||
|
||||
class LongformerModelIntegrationTest(unittest.TestCase):
|
||||
@slow
|
||||
def test_inference_no_head(self):
|
||||
model = LongformerModel.from_pretrained("longformer-base-4096")
|
||||
model.to(torch_device)
|
||||
|
||||
# 'Hello world! ' repeated 1000 times
|
||||
input_ids = torch.tensor(
|
||||
[[0] + [20920, 232, 328, 1437] * 1000 + [2]], dtype=torch.long, device=torch_device
|
||||
) # long input
|
||||
|
||||
attention_mask = torch.ones(input_ids.shape, dtype=torch.long, device=input_ids.device)
|
||||
attention_mask[:, [1, 4, 21]] = 2 # Set global attention on a few random positions
|
||||
|
||||
output = model(input_ids, attention_mask=attention_mask)[0]
|
||||
|
||||
expected_output_sum = torch.tensor(74585.8594, device=torch_device)
|
||||
expected_output_mean = torch.tensor(0.0243, device=torch_device)
|
||||
self.assertTrue(torch.allclose(output.sum(), expected_output_sum, atol=1e-4))
|
||||
self.assertTrue(torch.allclose(output.mean(), expected_output_mean, atol=1e-4))
|
||||
|
||||
@slow
|
||||
def test_inference_masked_lm(self):
|
||||
model = LongformerForMaskedLM.from_pretrained("longformer-base-4096")
|
||||
model.to(torch_device)
|
||||
|
||||
# 'Hello world! ' repeated 1000 times
|
||||
input_ids = torch.tensor(
|
||||
[[0] + [20920, 232, 328, 1437] * 1000 + [2]], dtype=torch.long, device=torch_device
|
||||
) # long input
|
||||
|
||||
loss, prediction_scores = model(input_ids, masked_lm_labels=input_ids)
|
||||
|
||||
expected_loss = torch.tensor(0.0620, device=torch_device)
|
||||
expected_prediction_scores_sum = torch.tensor(-6.1599e08, device=torch_device)
|
||||
expected_prediction_scores_mean = torch.tensor(-3.0622, device=torch_device)
|
||||
input_ids = input_ids.to(torch_device)
|
||||
|
||||
self.assertTrue(torch.allclose(loss, expected_loss, atol=1e-4))
|
||||
self.assertTrue(torch.allclose(prediction_scores.sum(), expected_prediction_scores_sum, atol=1e-4))
|
||||
self.assertTrue(torch.allclose(prediction_scores.mean(), expected_prediction_scores_mean, atol=1e-4))
|
||||
@@ -129,11 +129,6 @@ class TestMarian_EN_DE_More(MarianIntegrationTest):
|
||||
max_indices = logits.argmax(-1)
|
||||
self.tokenizer.batch_decode(max_indices)
|
||||
|
||||
def test_tokenizer_equivalence(self):
|
||||
batch = self.tokenizer.prepare_translation_batch(["I am a small frog"]).to(torch_device)
|
||||
expected = [38, 121, 14, 697, 38848, 0]
|
||||
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()
|
||||
|
||||
@@ -227,6 +227,7 @@ class OPENAIGPTModelLanguageGenerationTest(unittest.TestCase):
|
||||
@slow
|
||||
def test_lm_generate_openai_gpt(self):
|
||||
model = OpenAIGPTLMHeadModel.from_pretrained("openai-gpt")
|
||||
model.to(torch_device)
|
||||
input_ids = torch.tensor([[481, 4735, 544]], dtype=torch.long, device=torch_device) # the president is
|
||||
expected_output_ids = [
|
||||
481,
|
||||
|
||||
@@ -444,6 +444,7 @@ class T5ModelIntegrationTests(unittest.TestCase):
|
||||
)
|
||||
|
||||
input_ids = tok.encode(model.config.prefix + original_input, return_tensors="pt")
|
||||
input_ids = input_ids.to(torch_device)
|
||||
|
||||
output = model.generate(
|
||||
input_ids=input_ids,
|
||||
@@ -471,6 +472,7 @@ class T5ModelIntegrationTests(unittest.TestCase):
|
||||
expected_translation = "Cette section d'images provenant de l'enregistrement infrarouge effectué par le télescope Spitzer montre un « portrait familial » de générations innombrables de étoiles : les plus anciennes sont observées sous forme de pointes bleues, alors que les « nouveau-nés » de couleur rose dans la salle des accouchements doivent être plus difficiles "
|
||||
|
||||
input_ids = tok.encode(model.config.prefix + original_input, return_tensors="pt")
|
||||
input_ids = input_ids.to(torch_device)
|
||||
|
||||
output = model.generate(
|
||||
input_ids=input_ids,
|
||||
@@ -498,6 +500,7 @@ class T5ModelIntegrationTests(unittest.TestCase):
|
||||
expected_translation = "Taco Bell a declarat că intenţionează să adauge 2 000 de locaţii în SUA până în 2022."
|
||||
|
||||
input_ids = tok.encode(model.config.prefix + original_input, return_tensors="pt")
|
||||
input_ids = input_ids.to(torch_device)
|
||||
|
||||
output = model.generate(
|
||||
input_ids=input_ids,
|
||||
|
||||
@@ -223,6 +223,7 @@ class TransfoXLModelLanguageGenerationTest(unittest.TestCase):
|
||||
@slow
|
||||
def test_lm_generate_transfo_xl_wt103(self):
|
||||
model = TransfoXLLMHeadModel.from_pretrained("transfo-xl-wt103")
|
||||
model.to(torch_device)
|
||||
input_ids = torch.tensor(
|
||||
[
|
||||
[
|
||||
|
||||
@@ -434,6 +434,7 @@ class XLMModelLanguageGenerationTest(unittest.TestCase):
|
||||
@slow
|
||||
def test_lm_generate_xlm_mlm_en_2048(self):
|
||||
model = XLMWithLMHeadModel.from_pretrained("xlm-mlm-en-2048")
|
||||
model.to(torch_device)
|
||||
input_ids = torch.tensor([[14, 447]], dtype=torch.long, device=torch_device) # the president
|
||||
expected_output_ids = [
|
||||
14,
|
||||
@@ -459,4 +460,4 @@ class XLMModelLanguageGenerationTest(unittest.TestCase):
|
||||
] # the president the president the president the president the president the president the president the president the president the president
|
||||
# TODO(PVP): this and other input_ids I tried for generation give pretty bad results. Not sure why. Model might just not be made for auto-regressive inference
|
||||
output_ids = model.generate(input_ids, do_sample=False)
|
||||
self.assertListEqual(output_ids[0].numpy().tolist(), expected_output_ids)
|
||||
self.assertListEqual(output_ids[0].cpu().numpy().tolist(), expected_output_ids)
|
||||
@@ -517,6 +517,7 @@ class XLNetModelLanguageGenerationTest(unittest.TestCase):
|
||||
@slow
|
||||
def test_lm_generate_xlnet_base_cased(self):
|
||||
model = XLNetLMHeadModel.from_pretrained("xlnet-base-cased")
|
||||
model.to(torch_device)
|
||||
input_ids = torch.tensor(
|
||||
[
|
||||
[
|
||||
|
||||
@@ -36,9 +36,6 @@ class AlbertTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
tokenizer = AlbertTokenizer(SAMPLE_VOCAB)
|
||||
tokenizer.save_pretrained(self.tmpdirname)
|
||||
|
||||
def get_tokenizer(self, **kwargs):
|
||||
return AlbertTokenizer.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
def get_input_output_texts(self):
|
||||
input_text = "this is a test"
|
||||
output_text = "this is a test"
|
||||
|
||||
@@ -59,9 +59,6 @@ class BertTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
with open(self.vocab_file, "w", encoding="utf-8") as vocab_writer:
|
||||
vocab_writer.write("".join([x + "\n" for x in vocab_tokens]))
|
||||
|
||||
def get_tokenizer(self, **kwargs):
|
||||
return BertTokenizer.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
def get_rust_tokenizer(self, **kwargs):
|
||||
return BertTokenizerFast.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ from transformers.tokenization_bert_japanese import (
|
||||
)
|
||||
|
||||
from .test_tokenization_common import TokenizerTesterMixin
|
||||
from .utils import custom_tokenizers, slow
|
||||
from .utils import custom_tokenizers
|
||||
|
||||
|
||||
@custom_tokenizers
|
||||
@@ -60,9 +60,6 @@ class BertJapaneseTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
with open(self.vocab_file, "w", encoding="utf-8") as vocab_writer:
|
||||
vocab_writer.write("".join([x + "\n" for x in vocab_tokens]))
|
||||
|
||||
def get_tokenizer(self, **kwargs):
|
||||
return BertJapaneseTokenizer.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
def get_input_output_texts(self):
|
||||
input_text = "こんにちは、世界。 \nこんばんは、世界。"
|
||||
output_text = "こんにちは 、 世界 。 こんばんは 、 世界 。"
|
||||
@@ -129,7 +126,6 @@ class BertJapaneseTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
|
||||
self.assertListEqual(tokenizer.tokenize("こんばんは こんばんにちは こんにちは"), ["こん", "##ばんは", "[UNK]", "こんにちは"])
|
||||
|
||||
@slow
|
||||
def test_sequence_builders(self):
|
||||
tokenizer = self.tokenizer_class.from_pretrained("bert-base-japanese")
|
||||
|
||||
@@ -144,6 +140,7 @@ class BertJapaneseTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
assert encoded_pair == [2] + text + [3] + text_2 + [3]
|
||||
|
||||
|
||||
@custom_tokenizers
|
||||
class BertJapaneseCharacterTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
|
||||
tokenizer_class = BertJapaneseTokenizer
|
||||
@@ -190,7 +187,6 @@ class BertJapaneseCharacterTokenizationTest(TokenizerTesterMixin, unittest.TestC
|
||||
|
||||
self.assertListEqual(tokenizer.tokenize("こんにちほ"), ["こ", "ん", "に", "ち", "[UNK]"])
|
||||
|
||||
@slow
|
||||
def test_sequence_builders(self):
|
||||
tokenizer = self.tokenizer_class.from_pretrained("bert-base-japanese-char")
|
||||
|
||||
|
||||
@@ -22,12 +22,12 @@ from collections import OrderedDict
|
||||
from typing import TYPE_CHECKING, Dict, Tuple, Union
|
||||
|
||||
from tests.utils import require_tf, require_torch
|
||||
from transformers import PreTrainedTokenizer
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from transformers import (
|
||||
PretrainedConfig,
|
||||
PreTrainedTokenizer,
|
||||
PreTrainedTokenizerFast,
|
||||
PreTrainedModel,
|
||||
TFPreTrainedModel,
|
||||
@@ -67,19 +67,24 @@ class TokenizerTesterMixin:
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.tmpdirname)
|
||||
|
||||
def get_tokenizer(self, **kwargs):
|
||||
raise NotImplementedError
|
||||
def get_tokenizer(self, **kwargs) -> PreTrainedTokenizer:
|
||||
return self.tokenizer_class.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
def get_rust_tokenizer(self, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
||||
def get_input_output_texts(self):
|
||||
raise NotImplementedError
|
||||
def get_input_output_texts(self) -> Tuple[str, str]:
|
||||
"""Feel free to overwrite"""
|
||||
# TODO: @property
|
||||
return (
|
||||
"This is a test",
|
||||
"This is a test",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def convert_batch_encode_plus_format_to_encode_plus(batch_encode_plus_sequences):
|
||||
# Switch from batch_encode_plus format: {'input_ids': [[...], [...]], ...}
|
||||
# to the concatenated encode_plus format: [{'input_ids': [...], ...}, {'input_ids': [...], ...}]
|
||||
# to the list of examples/ encode_plus format: [{'input_ids': [...], ...}, {'input_ids': [...], ...}]
|
||||
return [
|
||||
{value: batch_encode_plus_sequences[value][i] for value in batch_encode_plus_sequences.keys()}
|
||||
for i in range(len(batch_encode_plus_sequences["input_ids"]))
|
||||
@@ -114,13 +119,13 @@ class TokenizerTesterMixin:
|
||||
|
||||
# Now let's start the test
|
||||
tokenizer = self.get_tokenizer(max_len=42)
|
||||
|
||||
before_tokens = tokenizer.encode("He is very happy, UNwant\u00E9d,running", add_special_tokens=False)
|
||||
sample_text = "He is very happy, UNwant\u00E9d,running"
|
||||
before_tokens = tokenizer.encode(sample_text, add_special_tokens=False)
|
||||
|
||||
tokenizer.save_pretrained(self.tmpdirname)
|
||||
tokenizer = self.tokenizer_class.from_pretrained(self.tmpdirname)
|
||||
|
||||
after_tokens = tokenizer.encode("He is very happy, UNwant\u00E9d,running", add_special_tokens=False)
|
||||
after_tokens = tokenizer.encode(sample_text, add_special_tokens=False)
|
||||
self.assertListEqual(before_tokens, after_tokens)
|
||||
|
||||
self.assertEqual(tokenizer.max_len, 42)
|
||||
@@ -128,6 +133,7 @@ class TokenizerTesterMixin:
|
||||
self.assertEqual(tokenizer.max_len, 43)
|
||||
|
||||
def test_pickle_tokenizer(self):
|
||||
"""Google pickle __getstate__ __setstate__ if you are struggling with this."""
|
||||
tokenizer = self.get_tokenizer()
|
||||
self.assertIsNotNone(tokenizer)
|
||||
|
||||
@@ -253,7 +259,7 @@ class TokenizerTesterMixin:
|
||||
decoded = tokenizer.decode(encoded, skip_special_tokens=True)
|
||||
assert special_token not in decoded
|
||||
|
||||
def test_required_methods_tokenizer(self):
|
||||
def test_internal_consistency(self):
|
||||
tokenizer = self.get_tokenizer()
|
||||
input_text, output_text = self.get_input_output_texts()
|
||||
|
||||
@@ -263,13 +269,12 @@ class TokenizerTesterMixin:
|
||||
self.assertListEqual(ids, ids_2)
|
||||
|
||||
tokens_2 = tokenizer.convert_ids_to_tokens(ids)
|
||||
self.assertNotEqual(len(tokens_2), 0)
|
||||
text_2 = tokenizer.decode(ids)
|
||||
self.assertIsInstance(text_2, str)
|
||||
|
||||
self.assertEqual(text_2, output_text)
|
||||
|
||||
self.assertNotEqual(len(tokens_2), 0)
|
||||
self.assertIsInstance(text_2, str)
|
||||
|
||||
def test_encode_decode_with_spaces(self):
|
||||
tokenizer = self.get_tokenizer()
|
||||
|
||||
@@ -429,10 +434,7 @@ class TokenizerTesterMixin:
|
||||
|
||||
def test_special_tokens_mask(self):
|
||||
tokenizer = self.get_tokenizer()
|
||||
|
||||
sequence_0 = "Encode this."
|
||||
sequence_1 = "This one too please."
|
||||
|
||||
# Testing single inputs
|
||||
encoded_sequence = tokenizer.encode(sequence_0, add_special_tokens=False)
|
||||
encoded_sequence_dict = tokenizer.encode_plus(
|
||||
@@ -442,13 +444,13 @@ class TokenizerTesterMixin:
|
||||
special_tokens_mask = encoded_sequence_dict["special_tokens_mask"]
|
||||
self.assertEqual(len(special_tokens_mask), len(encoded_sequence_w_special))
|
||||
|
||||
filtered_sequence = [
|
||||
(x if not special_tokens_mask[i] else None) for i, x in enumerate(encoded_sequence_w_special)
|
||||
]
|
||||
filtered_sequence = [x for x in filtered_sequence if x is not None]
|
||||
filtered_sequence = [x for i, x in enumerate(encoded_sequence_w_special) if not special_tokens_mask[i]]
|
||||
self.assertEqual(encoded_sequence, filtered_sequence)
|
||||
|
||||
# Testing inputs pairs
|
||||
def test_special_tokens_mask_input_pairs(self):
|
||||
tokenizer = self.get_tokenizer()
|
||||
sequence_0 = "Encode this."
|
||||
sequence_1 = "This one too please."
|
||||
encoded_sequence = tokenizer.encode(sequence_0, add_special_tokens=False)
|
||||
encoded_sequence += tokenizer.encode(sequence_1, add_special_tokens=False)
|
||||
encoded_sequence_dict = tokenizer.encode_plus(
|
||||
@@ -464,7 +466,9 @@ class TokenizerTesterMixin:
|
||||
filtered_sequence = [x for x in filtered_sequence if x is not None]
|
||||
self.assertEqual(encoded_sequence, filtered_sequence)
|
||||
|
||||
# Testing with already existing special tokens
|
||||
def test_special_tokens_mask_already_has_special_tokens(self):
|
||||
tokenizer = self.get_tokenizer()
|
||||
sequence_0 = "Encode this."
|
||||
if tokenizer.cls_token_id == tokenizer.unk_token_id and tokenizer.cls_token_id == tokenizer.unk_token_id:
|
||||
tokenizer.add_special_tokens({"cls_token": "</s>", "sep_token": "<s>"})
|
||||
encoded_sequence_dict = tokenizer.encode_plus(
|
||||
@@ -514,13 +518,12 @@ class TokenizerTesterMixin:
|
||||
tokenizer.padding_side = "right"
|
||||
padded_sequence_right = tokenizer.encode(sequence, pad_to_max_length=True)
|
||||
padded_sequence_right_length = len(padded_sequence_right)
|
||||
assert sequence_length == padded_sequence_right_length
|
||||
assert encoded_sequence == padded_sequence_right
|
||||
|
||||
tokenizer.padding_side = "left"
|
||||
padded_sequence_left = tokenizer.encode(sequence, pad_to_max_length=True)
|
||||
padded_sequence_left_length = len(padded_sequence_left)
|
||||
|
||||
assert sequence_length == padded_sequence_right_length
|
||||
assert encoded_sequence == padded_sequence_right
|
||||
assert sequence_length == padded_sequence_left_length
|
||||
assert encoded_sequence == padded_sequence_left
|
||||
|
||||
@@ -617,6 +620,9 @@ class TokenizerTesterMixin:
|
||||
self.assertIsInstance(vocab, dict)
|
||||
self.assertEqual(len(vocab), len(tokenizer))
|
||||
|
||||
def test_conversion_reversible(self):
|
||||
tokenizer = self.get_tokenizer()
|
||||
vocab = tokenizer.get_vocab()
|
||||
for word, ind in vocab.items():
|
||||
self.assertEqual(tokenizer.convert_tokens_to_ids(word), ind)
|
||||
self.assertEqual(tokenizer.convert_ids_to_tokens(ind), word)
|
||||
@@ -746,6 +752,7 @@ class TokenizerTesterMixin:
|
||||
|
||||
@require_torch
|
||||
def test_torch_encode_plus_sent_to_model(self):
|
||||
import torch
|
||||
from transformers import MODEL_MAPPING, TOKENIZER_MAPPING
|
||||
|
||||
MODEL_TOKENIZER_MAPPING = merge_model_tokenizer_mappings(MODEL_MAPPING, TOKENIZER_MAPPING)
|
||||
@@ -773,8 +780,10 @@ class TokenizerTesterMixin:
|
||||
encoded_sequence = tokenizer.encode_plus(sequence, return_tensors="pt")
|
||||
batch_encoded_sequence = tokenizer.batch_encode_plus([sequence, sequence], return_tensors="pt")
|
||||
# This should not fail
|
||||
model(**encoded_sequence)
|
||||
model(**batch_encoded_sequence)
|
||||
|
||||
with torch.no_grad(): # saves some time
|
||||
model(**encoded_sequence)
|
||||
model(**batch_encoded_sequence)
|
||||
|
||||
if self.test_rust_tokenizer:
|
||||
fast_tokenizer = self.get_rust_tokenizer()
|
||||
|
||||
@@ -24,9 +24,6 @@ class DistilBertTokenizationTest(BertTokenizationTest):
|
||||
|
||||
tokenizer_class = DistilBertTokenizer
|
||||
|
||||
def get_tokenizer(self, **kwargs):
|
||||
return DistilBertTokenizer.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
def get_rust_tokenizer(self, **kwargs):
|
||||
return DistilBertTokenizerFast.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2020 Huggingface
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
import os
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from shutil import copyfile
|
||||
|
||||
from transformers.tokenization_marian import MarianTokenizer, save_json, vocab_files_names
|
||||
from transformers.tokenization_utils import BatchEncoding
|
||||
|
||||
from .test_tokenization_common import TokenizerTesterMixin
|
||||
from .utils import slow
|
||||
|
||||
|
||||
SAMPLE_SP = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures/test_sentencepiece.model")
|
||||
|
||||
mock_tokenizer_config = {"target_lang": "fi", "source_lang": "en"}
|
||||
zh_code = ">>zh<<"
|
||||
ORG_NAME = "Helsinki-NLP/"
|
||||
|
||||
|
||||
class MarianTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
|
||||
tokenizer_class = MarianTokenizer
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
vocab = ["</s>", "<unk>", "▁This", "▁is", "▁a", "▁t", "est", "\u0120", "<pad>"]
|
||||
vocab_tokens = dict(zip(vocab, range(len(vocab))))
|
||||
save_dir = Path(self.tmpdirname)
|
||||
save_json(vocab_tokens, save_dir / vocab_files_names["vocab"])
|
||||
save_json(mock_tokenizer_config, save_dir / vocab_files_names["tokenizer_config_file"])
|
||||
if not (save_dir / vocab_files_names["source_spm"]).exists():
|
||||
copyfile(SAMPLE_SP, save_dir / vocab_files_names["source_spm"])
|
||||
copyfile(SAMPLE_SP, save_dir / vocab_files_names["target_spm"])
|
||||
|
||||
tokenizer = MarianTokenizer.from_pretrained(self.tmpdirname)
|
||||
tokenizer.save_pretrained(self.tmpdirname)
|
||||
|
||||
def get_tokenizer(self, max_len=None, **kwargs) -> MarianTokenizer:
|
||||
# overwrite max_len=512 default
|
||||
return MarianTokenizer.from_pretrained(self.tmpdirname, max_len=max_len, **kwargs)
|
||||
|
||||
def get_input_output_texts(self):
|
||||
return (
|
||||
"This is a test",
|
||||
"This is a test",
|
||||
)
|
||||
|
||||
@slow
|
||||
def test_tokenizer_equivalence_en_de(self):
|
||||
en_de_tokenizer = MarianTokenizer.from_pretrained(f"{ORG_NAME}opus-mt-en-de")
|
||||
batch = en_de_tokenizer.prepare_translation_batch(["I am a small frog"], return_tensors=None)
|
||||
self.assertIsInstance(batch, BatchEncoding)
|
||||
expected = [38, 121, 14, 697, 38848, 0]
|
||||
self.assertListEqual(expected, batch.input_ids[0])
|
||||
@@ -64,13 +64,8 @@ class OpenAIGPTTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
with open(self.merges_file, "w") as fp:
|
||||
fp.write("\n".join(merges))
|
||||
|
||||
def get_tokenizer(self, **kwargs):
|
||||
return OpenAIGPTTokenizer.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
def get_input_output_texts(self):
|
||||
input_text = "lower newer"
|
||||
output_text = "lower newer"
|
||||
return input_text, output_text
|
||||
return "lower newer", "lower newer"
|
||||
|
||||
def test_full_tokenizer(self):
|
||||
tokenizer = OpenAIGPTTokenizer(self.vocab_file, self.merges_file)
|
||||
|
||||
@@ -100,9 +100,11 @@ class RobertaTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
text = tokenizer.encode("sequence builders", add_special_tokens=False)
|
||||
text_2 = tokenizer.encode("multi-sequence build", add_special_tokens=False)
|
||||
|
||||
encoded_text_from_decode = tokenizer.encode("sequence builders", add_special_tokens=True)
|
||||
encoded_text_from_decode = tokenizer.encode(
|
||||
"sequence builders", add_special_tokens=True, add_prefix_space=False
|
||||
)
|
||||
encoded_pair_from_decode = tokenizer.encode(
|
||||
"sequence builders", "multi-sequence build", add_special_tokens=True
|
||||
"sequence builders", "multi-sequence build", add_special_tokens=True, add_prefix_space=False
|
||||
)
|
||||
|
||||
encoded_sentence = tokenizer.build_inputs_with_special_tokens(text)
|
||||
|
||||
@@ -37,14 +37,6 @@ class T5TokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
tokenizer = T5Tokenizer(SAMPLE_VOCAB)
|
||||
tokenizer.save_pretrained(self.tmpdirname)
|
||||
|
||||
def get_tokenizer(self, **kwargs):
|
||||
return T5Tokenizer.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
def get_input_output_texts(self):
|
||||
input_text = "This is a test"
|
||||
output_text = "This is a test"
|
||||
return input_text, output_text
|
||||
|
||||
def test_full_tokenizer(self):
|
||||
tokenizer = T5Tokenizer(SAMPLE_VOCAB)
|
||||
|
||||
|
||||
@@ -65,9 +65,6 @@ class XLMTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
with open(self.merges_file, "w") as fp:
|
||||
fp.write("\n".join(merges))
|
||||
|
||||
def get_tokenizer(self, **kwargs):
|
||||
return XLMTokenizer.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
def get_input_output_texts(self):
|
||||
input_text = "lower newer"
|
||||
output_text = "lower newer"
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from transformers.file_utils import cached_property
|
||||
from transformers.tokenization_xlm_roberta import SPIECE_UNDERLINE, XLMRobertaTokenizer
|
||||
|
||||
from .test_tokenization_common import TokenizerTesterMixin
|
||||
@@ -37,14 +38,6 @@ class XLMRobertaTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
tokenizer = XLMRobertaTokenizer(SAMPLE_VOCAB, keep_accents=True)
|
||||
tokenizer.save_pretrained(self.tmpdirname)
|
||||
|
||||
def get_tokenizer(self, **kwargs):
|
||||
return XLMRobertaTokenizer.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
def get_input_output_texts(self):
|
||||
input_text = "This is a test"
|
||||
output_text = "This is a test"
|
||||
return input_text, output_text
|
||||
|
||||
def test_full_tokenizer(self):
|
||||
tokenizer = XLMRobertaTokenizer(SAMPLE_VOCAB, keep_accents=True)
|
||||
|
||||
@@ -121,22 +114,22 @@ class XLMRobertaTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
],
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def big_tokenizer(self):
|
||||
return XLMRobertaTokenizer.from_pretrained("xlm-roberta-base")
|
||||
|
||||
@slow
|
||||
def test_tokenization_base_easy_symbols(self):
|
||||
tokenizer = XLMRobertaTokenizer.from_pretrained("xlm-roberta-base")
|
||||
|
||||
symbols = "Hello World!"
|
||||
original_tokenizer_encodings = [0, 35378, 6661, 38, 2]
|
||||
# xlmr = torch.hub.load('pytorch/fairseq', 'xlmr.base') # xlmr.large has same tokenizer
|
||||
# xlmr.eval()
|
||||
# xlmr.encode(symbols)
|
||||
|
||||
self.assertListEqual(original_tokenizer_encodings, tokenizer.encode(symbols))
|
||||
self.assertListEqual(original_tokenizer_encodings, self.big_tokenizer.encode(symbols))
|
||||
|
||||
@slow
|
||||
def test_tokenization_base_hard_symbols(self):
|
||||
tokenizer = XLMRobertaTokenizer.from_pretrained("xlm-roberta-base")
|
||||
|
||||
symbols = 'This is a very long text with a lot of weird characters, such as: . , ~ ? ( ) " [ ] ! : - . Also we will add words that should not exsist and be tokenized to <unk>, such as saoneuhaoesuth'
|
||||
original_tokenizer_encodings = [
|
||||
0,
|
||||
@@ -209,4 +202,4 @@ class XLMRobertaTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
# xlmr.eval()
|
||||
# xlmr.encode(symbols)
|
||||
|
||||
self.assertListEqual(original_tokenizer_encodings, tokenizer.encode(symbols))
|
||||
self.assertListEqual(original_tokenizer_encodings, self.big_tokenizer.encode(symbols))
|
||||
@@ -37,14 +37,6 @@ class XLNetTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||
tokenizer = XLNetTokenizer(SAMPLE_VOCAB, keep_accents=True)
|
||||
tokenizer.save_pretrained(self.tmpdirname)
|
||||
|
||||
def get_tokenizer(self, **kwargs):
|
||||
return XLNetTokenizer.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
def get_input_output_texts(self):
|
||||
input_text = "This is a test"
|
||||
output_text = "This is a test"
|
||||
return input_text, output_text
|
||||
|
||||
def test_full_tokenizer(self):
|
||||
tokenizer = XLNetTokenizer(SAMPLE_VOCAB, keep_accents=True)
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class DataCollatorIntegrationTest(unittest.TestCase):
|
||||
data_args = GlueDataTrainingArguments(
|
||||
task_name="mrpc", data_dir="./tests/fixtures/tests_samples/MRPC", overwrite_cache=True
|
||||
)
|
||||
dataset = GlueDataset(data_args, tokenizer=tokenizer, evaluate=True)
|
||||
dataset = GlueDataset(data_args, tokenizer=tokenizer, mode="dev")
|
||||
data_collator = DefaultDataCollator()
|
||||
batch = data_collator.collate_batch(dataset.features)
|
||||
self.assertEqual(batch["labels"].dtype, torch.long)
|
||||
@@ -41,7 +41,7 @@ class DataCollatorIntegrationTest(unittest.TestCase):
|
||||
data_args = GlueDataTrainingArguments(
|
||||
task_name="sts-b", data_dir="./tests/fixtures/tests_samples/STS-B", overwrite_cache=True
|
||||
)
|
||||
dataset = GlueDataset(data_args, tokenizer=tokenizer, evaluate=True)
|
||||
dataset = GlueDataset(data_args, tokenizer=tokenizer, mode="dev")
|
||||
data_collator = DefaultDataCollator()
|
||||
batch = data_collator.collate_batch(dataset.features)
|
||||
self.assertEqual(batch["labels"].dtype, torch.float)
|
||||
@@ -93,7 +93,7 @@ class TrainerIntegrationTest(unittest.TestCase):
|
||||
data_args = GlueDataTrainingArguments(
|
||||
task_name="mrpc", data_dir="./tests/fixtures/tests_samples/MRPC", overwrite_cache=True
|
||||
)
|
||||
eval_dataset = GlueDataset(data_args, tokenizer=tokenizer, evaluate=True)
|
||||
eval_dataset = GlueDataset(data_args, tokenizer=tokenizer, mode="dev")
|
||||
|
||||
training_args = TrainingArguments(output_dir="./examples", no_cuda=True)
|
||||
trainer = Trainer(model=model, args=training_args, eval_dataset=eval_dataset)
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
# python ./tests/test_trainer_distributed.py
|
||||
# and in single-GPU mode:
|
||||
# CUDA_VISIBLE_DEVICES=0 python ./tests/test_trainer_distributed.py
|
||||
# and in CPU mode:
|
||||
# CUDA_VISIBLE_DEVICES=-1 python ./tests/test_trainer_distributed.py
|
||||
#
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user