Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9f6d07c23 | ||
|
|
afd4037e64 | ||
|
|
f0d579eb4f | ||
|
|
9e288305ad | ||
|
|
f70d67cfb6 | ||
|
|
78166e6dc3 | ||
|
|
524bb46224 | ||
|
|
e4437a462b | ||
|
|
fa5423b169 | ||
|
|
7d0ef00420 | ||
|
|
0cc4eae0e6 | ||
|
|
82ce8488bb | ||
|
|
d6b6ab11f0 | ||
|
|
40d98ebf50 |
@@ -52,7 +52,7 @@ size of 267,735!
|
||||
|
||||
A huge vocabulary size means a huge embedding matrix at the start of the model, which will cause memory problems.
|
||||
TransformerXL deals with it by using a special kind of embeddings called adaptive embeddings, but in general,
|
||||
transformers model rarely have a vocabulary size greater than 50,000, especially if they are trained on a single
|
||||
transformers models rarely have a vocabulary size greater than 50,000, especially if they are trained on a single
|
||||
language.
|
||||
|
||||
So if tokenizing on words is unsatisfactory, we could go on the opposite direction and simply tokenize on characters.
|
||||
@@ -69,7 +69,7 @@ decomposed as "annoying" and "ly". This is especially useful in agglutinative la
|
||||
form (almost) arbitrarily long complex words by stringing together some subwords.
|
||||
|
||||
This allows the model to keep a reasonable vocabulary while still learning useful representations for common words or
|
||||
subwords. This also gives the ability to the model to process words it has never seen before, by decomposing them into
|
||||
subwords. This also enables the model to process words it has never seen before, by decomposing them into
|
||||
subwords it knows. For instance, the base :class:`~transformers.BertTokenizer` will tokenize "I have a new GPU!" like
|
||||
this:
|
||||
|
||||
@@ -110,7 +110,7 @@ splitting the training data into words, which can be a simple space tokenization
|
||||
(:doc:`GPT-2 <model_doc/gpt2>` and :doc:`Roberta <model_doc/roberta>` uses this for instance) or a rule-based tokenizer
|
||||
(:doc:`XLM <model_doc/xlm>` use Moses for most languages, as does :doc:`FlauBERT <model_doc/flaubert>`),
|
||||
|
||||
:doc:`GPT <model_doc/gpt>` uses Spacy and ftfy) and, counts the frequency of each word in the training corpus.
|
||||
:doc:`GPT <model_doc/gpt>` uses Spacy and ftfy, and counts the frequency of each word in the training corpus.
|
||||
|
||||
It then begins from the list of all characters, and will learn merge rules to form a new token from two symbols in the
|
||||
vocabulary until it has learned a vocabulary of the desired size (this is a hyperparameter to pick).
|
||||
@@ -178,7 +178,7 @@ WordPiece is the subword tokenization algorithm used for :doc:`BERT <model_doc/b
|
||||
`this paper <https://static.googleusercontent.com/media/research.google.com/ja//pubs/archive/37842.pdf>`__. It relies
|
||||
on the same base as BPE, which is to initialize the vocabulary to every character present in the corpus and
|
||||
progressively learn a given number of merge rules, the difference is that it doesn't choose the pair that is the most
|
||||
frequent but the one that will maximize the likelihood on the corpus once merged.
|
||||
frequent but the one that will maximize the likelihood on the corpus once merged.
|
||||
|
||||
What does this mean? Well, in the previous example, it means we would only merge 'u' and 'g' if the probability of
|
||||
having 'ug' divided by the probability of having 'u' then 'g' is greater than for any other pair of symbols. It's
|
||||
@@ -217,7 +217,7 @@ training corpus. You can then give a probability to each tokenization (which is
|
||||
tokens forming it) and pick the most likely one (or if you want to apply some data augmentation, you could sample one
|
||||
of the tokenization according to their probabilities).
|
||||
|
||||
Those probabilities are what are used to define the loss that trains the tokenizer: if our corpus consists of the
|
||||
Those probabilities define the loss that trains the tokenizer: if our corpus consists of the
|
||||
words :math:`x_{1}, \dots, x_{N}` and if for the word :math:`x_{i}` we note :math:`S(x_{i})` the set of all possible
|
||||
tokenizations of :math:`x_{i}` (with the current vocabulary), then the loss is defined as
|
||||
|
||||
@@ -229,15 +229,15 @@ tokenizations of :math:`x_{i}` (with the current vocabulary), then the loss is d
|
||||
SentencePiece
|
||||
=============
|
||||
|
||||
All the methods we have been looking at so far required some from of pretrokenization, which has a central problem: not
|
||||
All the methods we have been looking at so far required some form of pretokenization, which has a central problem: not
|
||||
all languages use spaces to separate words. This is a problem :doc:`XLM <model_doc/xlm>` solves by using specific
|
||||
pretokenizers for each of those languages (in this case, Chinese, Japanese and Thai). To solve this problem,
|
||||
SentencePiece (introduced in `this paper <https://arxiv.org/pdf/1808.06226.pdf>`__) treats the input as a raw stream,
|
||||
includes the space in the set of characters to use, then uses BPE or unigram to construct the appropriate vocabulary.
|
||||
|
||||
That's why in the example we saw before using :class:`~transformers.XLNetTokenizer` (which uses SentencePiece), we had
|
||||
some '▁' characters, that represent spaces. Decoding a tokenized text is then super easy: we just have to concatenate
|
||||
all of them together and replace those '▁' by spaces.
|
||||
the '▁' character, that represents space. Decoding a tokenized text is then super easy: we just have to concatenate
|
||||
all of them together and replace '▁' with space.
|
||||
|
||||
All transformers models in the library that use SentencePiece use it with unigram. Examples of models using it are
|
||||
:doc:`ALBERT <model_doc/albert>`, :doc:`XLNet <model_doc/xlnet>` or the :doc:`Marian framework <model_doc/marian>`.
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# Multi-dialect-Arabic-BERT
|
||||
This is a repository of Multi-dialect Arabic BERT model.
|
||||
|
||||
By [Mawdoo3-AI](https://ai.mawdoo3.com/).
|
||||
|
||||
<p align="center">
|
||||
<br>
|
||||
<img src="https://github.com/mawdoo3/Multi-dialect-Arabic-BERT/blob/master/multidialct_arabic_bert.png" alt="Background reference: http://www.qfi.org/wp-content/uploads/2018/02/Qfi_Infographic_Mother-Language_Final.pdf" width="500"/>
|
||||
<br>
|
||||
<p>
|
||||
|
||||
|
||||
|
||||
### About our Multi-dialect-Arabic-BERT model
|
||||
Instead of training the Multi-dialect Arabic BERT model from scratch, we initialized the weights of the model using [Arabic-BERT](https://github.com/alisafaya/Arabic-BERT) and trained it on 10M arabic tweets from the unlabled data of [The Nuanced Arabic Dialect Identification (NADI) shared task](https://sites.google.com/view/nadi-shared-task).
|
||||
|
||||
### To cite this work
|
||||
We haven't published any paper on this work. Please cite this repository:
|
||||
```
|
||||
@inproceedings{talafha-etal-2020-nadi,
|
||||
title ={{Multi-dialect Arabic BERT for Country-level Dialect Identification}},
|
||||
author = {Talafha, Bashar, Ali, Mohammad, Za'ter, Muhy Eddin, Seelawi, Haitham, Tuffaha, Ibraheem, Samir, Mostafa, Farhan, Wael and Al-Natsheh, Hussein},
|
||||
booktitle ={{Proceedings of the Fifth Arabic Natural Language Processing Workshop (WANLP2020)}},
|
||||
year = {2020},
|
||||
address = {Barcelona, Spain}
|
||||
}
|
||||
```
|
||||
We will update the BibTeX once the paper published.
|
||||
|
||||
### Usage
|
||||
The model weights can be loaded using `transformers` library by HuggingFace.
|
||||
|
||||
```python
|
||||
from transformers import AutoTokenizer, AutoModel
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("bashar-talafha/multi-dialect-bert-base-arabic")
|
||||
model = AutoModel.from_pretrained("bashar-talafha/multi-dialect-bert-base-arabic")
|
||||
```
|
||||
|
||||
Example using `pipeline`:
|
||||
|
||||
```python
|
||||
from transformers import pipeline
|
||||
|
||||
fill_mask = pipeline(
|
||||
"fill-mask",
|
||||
model="bashar-talafha/multi-dialect-bert-base-arabic ",
|
||||
tokenizer="bashar-talafha/multi-dialect-bert-base-arabic "
|
||||
)
|
||||
|
||||
fill_mask(" سافر الرحالة من مطار [MASK] ")
|
||||
```
|
||||
```
|
||||
[{'sequence': '[CLS] سافر الرحالة من مطار الكويت [SEP]', 'score': 0.08296813815832138, 'token': 3226},
|
||||
{'sequence': '[CLS] سافر الرحالة من مطار دبي [SEP]', 'score': 0.05123933032155037, 'token': 4747},
|
||||
{'sequence': '[CLS] سافر الرحالة من مطار مسقط [SEP]', 'score': 0.046838656067848206, 'token': 13205},
|
||||
{'sequence': '[CLS] سافر الرحالة من مطار القاهرة [SEP]', 'score': 0.03234650194644928, 'token': 4003},
|
||||
{'sequence': '[CLS] سافر الرحالة من مطار الرياض [SEP]', 'score': 0.02606341242790222, 'token': 2200}]
|
||||
```
|
||||
### Repository
|
||||
Please check the [original repository](https://github.com/mawdoo3/Multi-dialect-Arabic-BERT) for more information.
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
language: "ca"
|
||||
tags:
|
||||
- lm-head
|
||||
- masked-lm
|
||||
- catalan
|
||||
- exbert
|
||||
license: mit
|
||||
---
|
||||
|
||||
# Calbert: a Catalan Language Model
|
||||
|
||||
## Introduction
|
||||
|
||||
CALBERT is an open-source language model for Catalan pretrained on the ALBERT architecture.
|
||||
|
||||
It is now available on Hugging Face in its `tiny-uncased` version (the one you're looking at) and `base-uncased` as well, and was pretrained on the [OSCAR dataset](https://traces1.inria.fr/oscar/).
|
||||
|
||||
For further information or requests, please go to the [GitHub repository](https://github.com/codegram/calbert)
|
||||
|
||||
## Pre-trained models
|
||||
|
||||
| Model | Arch. | Training data |
|
||||
| ----------------------------------- | -------------- | ---------------------- |
|
||||
| `codegram` / `calbert-tiny-uncased` | Tiny (uncased) | OSCAR (4.3 GB of text) |
|
||||
| `codegram` / `calbert-base-uncased` | Base (uncased) | OSCAR (4.3 GB of text) |
|
||||
|
||||
## How to use Calbert with HuggingFace
|
||||
|
||||
#### Load Calbert and its tokenizer:
|
||||
|
||||
```python
|
||||
from transformers import AutoModel, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("codegram/calbert-tiny-uncased")
|
||||
model = AutoModel.from_pretrained("codegram/calbert-tiny-uncased")
|
||||
|
||||
model.eval() # disable dropout (or leave in train mode to finetune
|
||||
```
|
||||
|
||||
#### Filling masks using pipeline
|
||||
|
||||
```python
|
||||
from transformers import pipeline
|
||||
|
||||
calbert_fill_mask = pipeline("fill-mask", model="codegram/calbert-tiny-uncased", tokenizer="codegram/calbert-tiny-uncased")
|
||||
results = calbert_fill_mask("M'agrada [MASK] això")
|
||||
# results
|
||||
# [{'sequence': "[CLS] m'agrada molt aixo[SEP]", 'score': 0.4403671622276306, 'token': 61},
|
||||
# {'sequence': "[CLS] m'agrada més aixo[SEP]", 'score': 0.050061386078596115, 'token': 43},
|
||||
# {'sequence': "[CLS] m'agrada veure aixo[SEP]", 'score': 0.026286985725164413, 'token': 157},
|
||||
# {'sequence': "[CLS] m'agrada bastant aixo[SEP]", 'score': 0.022483550012111664, 'token': 2143},
|
||||
# {'sequence': "[CLS] m'agrada moltíssim aixo[SEP]", 'score': 0.014491282403469086, 'token': 4867}]
|
||||
|
||||
```
|
||||
|
||||
#### Extract contextual embedding features from Calbert output
|
||||
|
||||
```python
|
||||
import torch
|
||||
# Tokenize in sub-words with SentencePiece
|
||||
tokenized_sentence = tokenizer.tokenize("M'és una mica igual")
|
||||
# ['▁m', "'", 'es', '▁una', '▁mica', '▁igual']
|
||||
|
||||
# 1-hot encode and add special starting and end tokens
|
||||
encoded_sentence = tokenizer.encode(tokenized_sentence)
|
||||
# [2, 109, 7, 71, 36, 371, 1103, 3]
|
||||
# NB: Can be done in one step : tokenize.encode("M'és una mica igual")
|
||||
|
||||
# Feed tokens to Calbert as a torch tensor (batch dim 1)
|
||||
encoded_sentence = torch.tensor(encoded_sentence).unsqueeze(0)
|
||||
embeddings, _ = model(encoded_sentence)
|
||||
embeddings.size()
|
||||
# torch.Size([1, 8, 312])
|
||||
embeddings.detach()
|
||||
# tensor([[[-0.2726, -0.9855, 0.9643, ..., 0.3511, 0.3499, -0.1984],
|
||||
# [-0.2824, -1.1693, -0.2365, ..., -3.1866, -0.9386, -1.3718],
|
||||
# [-2.3645, -2.2477, -1.6985, ..., -1.4606, -2.7294, 0.2495],
|
||||
# ...,
|
||||
# [ 0.8800, -0.0244, -3.0446, ..., 0.5148, -3.0903, 1.1879],
|
||||
# [ 1.1300, 0.2425, 0.2162, ..., -0.5722, -2.2004, 0.4045],
|
||||
# [ 0.4549, -0.2378, -0.2290, ..., -2.1247, -2.2769, -0.0820]]])
|
||||
```
|
||||
|
||||
## Authors
|
||||
|
||||
CALBERT was trained and evaluated by [Txus Bach](https://twitter.com/txustice), as part of [Codegram](https://www.codegram.com)'s applied research.
|
||||
|
||||
<a href="https://huggingface.co/exbert/?model=codegram/calbert-tiny-uncased&modelKind=bidirectional&sentence=M%27agradaria%20força%20saber-ne%20més">
|
||||
<img width="300px" src="https://hf-dinosaur.huggingface.co/exbert/button.png">
|
||||
</a>
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
datasets:
|
||||
- squad
|
||||
tags:
|
||||
- question-generation
|
||||
widget:
|
||||
- text: "Python is a programming language. It is developed by Guido Van Rossum and released in 1991. </s>"
|
||||
license: "MIT"
|
||||
---
|
||||
|
||||
## T5 for question-generation
|
||||
This is [t5-base](https://arxiv.org/abs/1910.10683) model trained for end-to-end question generation task. Simply input the text and the model will generate multile questions.
|
||||
|
||||
You can play with the model using the inference API, just put the text and see the results!
|
||||
|
||||
For more deatils see [this](https://github.com/patil-suraj/question_generation) repo.
|
||||
|
||||
### Model in action 🚀
|
||||
|
||||
You'll need to clone the [repo](https://github.com/patil-suraj/question_generation).
|
||||
|
||||
[](https://colab.research.google.com/github/patil-suraj/question_generation/blob/master/question_generation.ipynb)
|
||||
|
||||
```python3
|
||||
from pipelines import pipeline
|
||||
|
||||
text = "Python is an interpreted, high-level, general-purpose programming language. Created by Guido van Rossum \
|
||||
and first released in 1991, Python's design philosophy emphasizes code \
|
||||
readability with its notable use of significant whitespace."
|
||||
|
||||
nlp = pipeline("e2e-qg", model="valhalla/t5-base-e2e-qg")
|
||||
nlp(text)
|
||||
=> [
|
||||
'Who created Python?',
|
||||
'When was Python first released?',
|
||||
"What is Python's design philosophy?"
|
||||
]
|
||||
```
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
datasets:
|
||||
- squad
|
||||
tags:
|
||||
- question-generation
|
||||
widget:
|
||||
- text: "generate question: <hl> 42 <hl> is the answer to life, the universe and everything. </s>"
|
||||
- text: "question: What is 42 context: 42 is the answer to life, the universe and everything. </s>"
|
||||
license: "MIT"
|
||||
---
|
||||
|
||||
## T5 for multi-task QA and QG
|
||||
This is multi-task [t5-base](https://arxiv.org/abs/1910.10683) model trained for question answering and answer aware question generation tasks.
|
||||
|
||||
For question generation the answer spans are highlighted within the text with special highlight tokens (`<hl>`) and prefixed with 'generate question: '. For QA the input is processed like this `question: question_text context: context_text </s>`
|
||||
|
||||
You can play with the model using the inference API. Here's how you can use it
|
||||
|
||||
For QG
|
||||
|
||||
`generate question: <hl> 42 <hl> is the answer to life, the universe and everything. </s>`
|
||||
|
||||
For QA
|
||||
|
||||
`question: What is 42 context: 42 is the answer to life, the universe and everything. </s>`
|
||||
|
||||
For more deatils see [this](https://github.com/patil-suraj/question_generation) repo.
|
||||
|
||||
|
||||
### Model in action 🚀
|
||||
|
||||
You'll need to clone the [repo](https://github.com/patil-suraj/question_generation).
|
||||
|
||||
[](https://colab.research.google.com/github/patil-suraj/question_generation/blob/master/question_generation.ipynb)
|
||||
|
||||
```python3
|
||||
from pipelines import pipeline
|
||||
nlp = pipeline("multitask-qa-qg", model="valhalla/t5-base-qa-qg-hl")
|
||||
|
||||
# to generate questions simply pass the text
|
||||
nlp("42 is the answer to life, the universe and everything.")
|
||||
=> [{'answer': '42', 'question': 'What is the answer to life, the universe and everything?'}]
|
||||
|
||||
# for qa pass a dict with "question" and "context"
|
||||
nlp({
|
||||
"question": "What is 42 ?",
|
||||
"context": "42 is the answer to life, the universe and everything."
|
||||
})
|
||||
=> 'the answer to life, the universe and everything'
|
||||
```
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
datasets:
|
||||
- squad
|
||||
tags:
|
||||
- question-generation
|
||||
widget:
|
||||
- text: "<hl> 42 <hl> is the answer to life, the universe and everything. </s>"
|
||||
- text: "Python is a programming language. It is developed by <hl> Guido Van Rossum <hl>. </s>"
|
||||
- text: "Although <hl> practicality <hl> beats purity </s>"
|
||||
license: "MIT"
|
||||
---
|
||||
|
||||
## T5 for question-generation
|
||||
This is [t5-base](https://arxiv.org/abs/1910.10683) model trained for answer aware question generation task. The answer spans are highlighted within the text with special highlight tokens.
|
||||
|
||||
You can play with the model using the inference API, just highlight the answer spans with `<hl>` tokens and end the text with `</s>`. For example
|
||||
|
||||
`<hl> 42 <hl> is the answer to life, the universe and everything. </s>`
|
||||
|
||||
For more deatils see [this](https://github.com/patil-suraj/question_generation) repo.
|
||||
|
||||
### Model in action 🚀
|
||||
|
||||
You'll need to clone the [repo](https://github.com/patil-suraj/question_generation).
|
||||
|
||||
[](https://colab.research.google.com/github/patil-suraj/question_generation/blob/master/question_generation.ipynb)
|
||||
|
||||
```python3
|
||||
from pipelines import pipeline
|
||||
nlp = pipeline("question-generation", model="valhalla/t5-base-qg-hl")
|
||||
nlp("42 is the answer to life, universe and everything.")
|
||||
=> [{'answer': '42', 'question': 'What is the answer to life, universe and everything?'}]
|
||||
```
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
datasets:
|
||||
- squad
|
||||
tags:
|
||||
- question-generation
|
||||
widget:
|
||||
- text: "answer: 42 context: 42 is the answer to life, the universe and everything. </s>"
|
||||
- text: "answer: Guido Van Rossum context: Python is a programming language. It is developed by Guido Van Rossum. </s>"
|
||||
- text: "answer: Explicit context: Explicit is better than implicit </s>"
|
||||
license: "MIT"
|
||||
---
|
||||
|
||||
## T5 for question-generation
|
||||
This is [t5-small](https://arxiv.org/abs/1910.10683) model trained for answer aware question generation task. The answer text is prepended before the context text.
|
||||
|
||||
You can play with the model using the inference API, just get the input text in this format and see the results!
|
||||
`answer: answer_text context: context_text </s>`
|
||||
|
||||
For example
|
||||
|
||||
`answer: 42 context: 42 is the answer to life, the universe and everything. </s>`
|
||||
|
||||
For more deatils see [this](https://github.com/patil-suraj/question_generation) repo.
|
||||
|
||||
### Model in action 🚀
|
||||
|
||||
You'll need to clone the [repo](https://github.com/patil-suraj/question_generation).
|
||||
|
||||
[](https://colab.research.google.com/github/patil-suraj/question_generation/blob/master/question_generation.ipynb)
|
||||
|
||||
```python3
|
||||
from pipelines import pipeline
|
||||
nlp = pipeline("question-generation", qg_format="prepend")
|
||||
nlp("42 is the answer to life, universe and everything.")
|
||||
=> [{'answer': '42', 'question': 'What is the answer to life, universe and everything?'}]
|
||||
```
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
datasets:
|
||||
- squad
|
||||
tags:
|
||||
- question-generation
|
||||
widget:
|
||||
- text: "Python is developed by Guido Van Rossum and released in 1991. </s>"
|
||||
license: "MIT"
|
||||
---
|
||||
|
||||
## T5 for question-generation
|
||||
This is [t5-small](https://arxiv.org/abs/1910.10683) model trained for end-to-end question generation task. Simply input the text and the model will generate multile questions.
|
||||
|
||||
You can play with the model using the inference API, just put the text and see the results!
|
||||
|
||||
For more deatils see [this](https://github.com/patil-suraj/question_generation) repo.
|
||||
|
||||
### Model in action 🚀
|
||||
|
||||
You'll need to clone the [repo](https://github.com/patil-suraj/question_generation).
|
||||
|
||||
[](https://colab.research.google.com/github/patil-suraj/question_generation/blob/master/question_generation.ipynb)
|
||||
|
||||
```python3
|
||||
from pipelines import pipeline
|
||||
|
||||
text = "Python is an interpreted, high-level, general-purpose programming language. Created by Guido van Rossum \
|
||||
and first released in 1991, Python's design philosophy emphasizes code \
|
||||
readability with its notable use of significant whitespace."
|
||||
|
||||
nlp = pipeline("e2e-qg")
|
||||
nlp(text)
|
||||
=> [
|
||||
'Who created Python?',
|
||||
'When was Python first released?',
|
||||
"What is Python's design philosophy?"
|
||||
]
|
||||
```
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
datasets:
|
||||
- squad
|
||||
tags:
|
||||
- question-generation
|
||||
widget:
|
||||
- text: "generate question: <hl> 42 <hl> is the answer to life, the universe and everything. </s>"
|
||||
- text: "question: What is 42 context: 42 is the answer to life, the universe and everything. </s>"
|
||||
license: "MIT"
|
||||
---
|
||||
|
||||
## T5 for multi-task QA and QG
|
||||
This is multi-task [t5-small](https://arxiv.org/abs/1910.10683) model trained for question answering and answer aware question generation tasks.
|
||||
|
||||
For question generation the answer spans are highlighted within the text with special highlight tokens (`<hl>`) and prefixed with 'generate question: '. For QA the input is processed like this `question: question_text context: context_text </s>`
|
||||
|
||||
You can play with the model using the inference API. Here's how you can use it
|
||||
|
||||
For QG
|
||||
|
||||
`generate question: <hl> 42 <hl> is the answer to life, the universe and everything. </s>`
|
||||
|
||||
For QA
|
||||
|
||||
`question: What is 42 context: 42 is the answer to life, the universe and everything. </s>`
|
||||
|
||||
For more deatils see [this](https://github.com/patil-suraj/question_generation) repo.
|
||||
|
||||
### Model in action 🚀
|
||||
|
||||
You'll need to clone the [repo](https://github.com/patil-suraj/question_generation).
|
||||
|
||||
[](https://colab.research.google.com/github/patil-suraj/question_generation/blob/master/question_generation.ipynb)
|
||||
|
||||
```python3
|
||||
from pipelines import pipeline
|
||||
nlp = pipeline("multitask-qa-qg")
|
||||
|
||||
# to generate questions simply pass the text
|
||||
nlp("42 is the answer to life, the universe and everything.")
|
||||
=> [{'answer': '42', 'question': 'What is the answer to life, the universe and everything?'}]
|
||||
|
||||
# for qa pass a dict with "question" and "context"
|
||||
nlp({
|
||||
"question": "What is 42 ?",
|
||||
"context": "42 is the answer to life, the universe and everything."
|
||||
})
|
||||
=> 'the answer to life, the universe and everything'
|
||||
```
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
datasets:
|
||||
- squad
|
||||
tags:
|
||||
- question-generation
|
||||
widget:
|
||||
- text: "<hl> 42 <hl> is the answer to life, the universe and everything. </s>"
|
||||
- text: "Python is a programming language. It is developed by <hl> Guido Van Rossum <hl>. </s>"
|
||||
- text: "Simple is better than <hl> complex <hl>. </s>"
|
||||
license: "MIT"
|
||||
---
|
||||
|
||||
## T5 for question-generation
|
||||
This is [t5-small](https://arxiv.org/abs/1910.10683) model trained for answer aware question generation task. The answer spans are highlighted within the text with special highlight tokens.
|
||||
|
||||
You can play with the model using the inference API, just highlight the answer spans with `<hl>` tokens and end the text with `</s>`. For example
|
||||
|
||||
`<hl> 42 <hl> is the answer to life, the universe and everything. </s>`
|
||||
|
||||
For more deatils see [this](https://github.com/patil-suraj/question_generation) repo.
|
||||
|
||||
### Model in action 🚀
|
||||
|
||||
You'll need to clone the [repo](https://github.com/patil-suraj/question_generation).
|
||||
|
||||
[](https://colab.research.google.com/github/patil-suraj/question_generation/blob/master/question_generation.ipynb)
|
||||
|
||||
```python3
|
||||
from pipelines import pipeline
|
||||
nlp = pipeline("question-generation")
|
||||
nlp("42 is the answer to life, universe and everything.")
|
||||
=> [{'answer': '42', 'question': 'What is the answer to life, universe and everything?'}]
|
||||
```
|
||||
@@ -6,7 +6,7 @@
|
||||
"name": "05-benchmark",
|
||||
"provenance": [],
|
||||
"collapsed_sections": [],
|
||||
"authorship_tag": "ABX9TyNQ2BQG0erOGhTFF/2Mdn5a",
|
||||
"authorship_tag": "ABX9TyOAUMA92fdE4FM6A349/FWI",
|
||||
"include_colab_link": true
|
||||
},
|
||||
"kernelspec": {
|
||||
@@ -272,7 +272,7 @@
|
||||
"colab_type": "text"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/huggingface/transformers/blob/add_benchmark_notebook/05_benchmark.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
"<a href=\"https://colab.research.google.com/github/huggingface/transformers/blob/update_notebook/notebooks/05_benchmark.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -407,7 +407,7 @@
|
||||
" print(\"GPU RAM Free: {0:.0f}MB | Used: {1:.0f}MB | Util {2:3.0f}% | Total {3:.0f}MB\".format(gpu.memoryFree, gpu.memoryUsed, gpu.memoryUtil*100, gpu.memoryTotal))\n",
|
||||
"printm()"
|
||||
],
|
||||
"execution_count": 1,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -431,7 +431,7 @@
|
||||
"# If GPU RAM Util > 0% => crash notebook on purpose\n",
|
||||
"# !kill -9 -1"
|
||||
],
|
||||
"execution_count": 2,
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
@@ -499,7 +499,7 @@
|
||||
"source": [
|
||||
"!python run_benchmark.py --help"
|
||||
],
|
||||
"execution_count": 4,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -615,7 +615,7 @@
|
||||
"# create plots folder in content\n",
|
||||
"!mkdir -p plots_pt"
|
||||
],
|
||||
"execution_count": 5,
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
@@ -638,7 +638,7 @@
|
||||
" --inference_memory_csv_file plots_pt/required_memory.csv \\\n",
|
||||
" --env_info_csv_file plots_pt/env.csv >/dev/null 2>&1 # redirect all prints"
|
||||
],
|
||||
"execution_count": 6,
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
@@ -666,7 +666,7 @@
|
||||
"df = pd.read_csv('plots_pt/required_memory.csv')\n",
|
||||
"df"
|
||||
],
|
||||
"execution_count": 7,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "execute_result",
|
||||
@@ -901,7 +901,7 @@
|
||||
"df = pd.read_csv('plots_pt/env.csv')\n",
|
||||
"df"
|
||||
],
|
||||
"execution_count": 8,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "execute_result",
|
||||
@@ -1086,7 +1086,7 @@
|
||||
"colab_type": "code",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 514
|
||||
"height": 534
|
||||
},
|
||||
"outputId": "22499f33-bafc-42b3-f1b7-fcb202df9cd2"
|
||||
},
|
||||
@@ -1098,7 +1098,7 @@
|
||||
"from IPython.display import Image\n",
|
||||
"Image('plots_pt/required_memory_plot.png')"
|
||||
],
|
||||
"execution_count": 9,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -1133,7 +1133,7 @@
|
||||
"In short, all memory that is allocated for a given *model identifier*, *batch size* and *sequence length* is measured in a separate process. This way it can be ensured that there is no previously unreleased memory falsely included in the measurement. One should also note that the measured memory even includes the memory allocated by the CUDA driver to load PyTorch and TensorFlow and is, therefore, higher than library-specific memory measurement function, *e.g.* this one for [PyTorch](https://pytorch.org/docs/stable/cuda.html#torch.cuda.max_memory_allocated).\n",
|
||||
"\n",
|
||||
"Alright, let's analyze the results. It can be noted that the models `aodiniz/bert_uncased_L-10_H-512_A-8_cord19-200616_squad2` and `deepset/roberta-base-squad2` require significantly less memory than the other three models. Besides `mrm8488/longformer-base-4096-finetuned-squadv2` all models more or less follow the same memory consumption pattern with `aodiniz/bert_uncased_L-10_H-512_A-8_cord19-200616_squad2` seemingly being able to better scale to larger sequence lengths. \n",
|
||||
"`mrm8488/longformer-base-4096-finetuned-squadv2` is a *Longformer* model, which makes use of *LocalAttention* (check this blog post to learn more about local attention) so that the model scales much better to longer input sequences.\n",
|
||||
"`mrm8488/longformer-base-4096-finetuned-squadv2` is a *Longformer* model, which makes use of *LocalAttention* (check [this](https://huggingface.co/blog/reformer) blog post to learn more about local attention) so that the model scales much better to longer input sequences.\n",
|
||||
"\n",
|
||||
"For the sake of this notebook, we assume that the longest required input will be less than 512 tokens so that we settle on the models `aodiniz/bert_uncased_L-10_H-512_A-8_cord19-200616_squad2` and `deepset/roberta-base-squad2`. \n",
|
||||
"\n",
|
||||
@@ -1161,7 +1161,7 @@
|
||||
" --batch_sizes 64 128 256 512\\\n",
|
||||
" --no_env_print"
|
||||
],
|
||||
"execution_count": 10,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -1207,7 +1207,7 @@
|
||||
"colab_type": "code",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 514
|
||||
"height": 534
|
||||
},
|
||||
"outputId": "092c4dac-5002-4603-8eba-cd4bca727744"
|
||||
},
|
||||
@@ -1223,7 +1223,7 @@
|
||||
"from IPython.display import Image\n",
|
||||
"Image('plots_pt/required_memory_plot_2.png')"
|
||||
],
|
||||
"execution_count": 11,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -1283,7 +1283,7 @@
|
||||
" --batch_sizes 64 128 256 512 \\\n",
|
||||
" --no_env_print \\"
|
||||
],
|
||||
"execution_count": 12,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -1351,7 +1351,7 @@
|
||||
"colab_type": "code",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 514
|
||||
"height": 534
|
||||
},
|
||||
"outputId": "3947ccf0-b91c-43bf-8569-d6afe0232185"
|
||||
},
|
||||
@@ -1363,7 +1363,7 @@
|
||||
"from IPython.display import Image\n",
|
||||
"Image('plots_tf/required_memory_plot_2.png')"
|
||||
],
|
||||
"execution_count": 13,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -1420,7 +1420,7 @@
|
||||
" --batch_sizes 256 \\\n",
|
||||
" --no_env_print \\"
|
||||
],
|
||||
"execution_count": 14,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -1454,7 +1454,7 @@
|
||||
"colab_type": "code",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 514
|
||||
"height": 534
|
||||
},
|
||||
"outputId": "152f14c7-288a-4471-9cc0-5108cb24804c"
|
||||
},
|
||||
@@ -1466,7 +1466,7 @@
|
||||
"from IPython.display import Image\n",
|
||||
"Image('plots_tf/time_plot_2.png')"
|
||||
],
|
||||
"execution_count": 15,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -1523,7 +1523,7 @@
|
||||
" --no_env_print \\\n",
|
||||
" --use_xla"
|
||||
],
|
||||
"execution_count": 16,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -1584,7 +1584,7 @@
|
||||
"# Imports\n",
|
||||
"from transformers import BartConfig, PyTorchBenchmark, PyTorchBenchmarkArguments"
|
||||
],
|
||||
"execution_count": 17,
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
@@ -1622,7 +1622,7 @@
|
||||
"source": [
|
||||
"BartConfig.from_pretrained(\"facebook/bart-large-mnli\").to_diff_dict()"
|
||||
],
|
||||
"execution_count": 18,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "display_data",
|
||||
@@ -1720,7 +1720,7 @@
|
||||
"config_10000_vocab = BartConfig.from_pretrained(\"facebook/bart-large-mnli\", vocab_size=10000)\n",
|
||||
"config_8_layers = BartConfig.from_pretrained(\"facebook/bart-large-mnli\", encoder_layers=8, decoder_layers=8)"
|
||||
],
|
||||
"execution_count": 19,
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
@@ -1770,7 +1770,7 @@
|
||||
"# run benchmark\n",
|
||||
"result = benchmark.run()"
|
||||
],
|
||||
"execution_count": 20,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -1829,7 +1829,7 @@
|
||||
"colab_type": "code",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 514
|
||||
"height": 534
|
||||
},
|
||||
"outputId": "5dbeb7f7-c996-4db2-a560-735354a5b76f"
|
||||
},
|
||||
@@ -1841,7 +1841,7 @@
|
||||
"from IPython.display import Image\n",
|
||||
"Image('plots_pt/training_mem_fp16.png')"
|
||||
],
|
||||
"execution_count": 21,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -1916,7 +1916,7 @@
|
||||
"# run benchmark\n",
|
||||
"result = benchmark.run()"
|
||||
],
|
||||
"execution_count": 22,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -1961,7 +1961,7 @@
|
||||
"colab_type": "code",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 514
|
||||
"height": 534
|
||||
},
|
||||
"outputId": "8a4b4db7-abed-47c4-da61-c3b1ccae66f1"
|
||||
},
|
||||
@@ -1973,7 +1973,7 @@
|
||||
"from IPython.display import Image\n",
|
||||
"Image('plots_pt/training_speed_fp16.png')"
|
||||
],
|
||||
"execution_count": 23,
|
||||
"execution_count": null,
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
@@ -2017,7 +2017,7 @@
|
||||
"source": [
|
||||
"Alright, that's it! Now you should be able to benchmark your favorite models on your favorite configurations. \n",
|
||||
"\n",
|
||||
"Transparency for the computational cost of a model is becoming more and more important. Feel free to share your results with the community on a shared spreadsheet or by tweeting us @huggingface 🤗."
|
||||
"Feel free to share your results with the community [here](https://github.com/huggingface/transformers/blob/master/examples/benchmarking/README.md) or by tweeting us https://twitter.com/HuggingFace 🤗."
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1003,8 +1003,6 @@ class TokenClassificationPipeline(Pipeline):
|
||||
labels_idx = score.argmax(axis=-1)
|
||||
|
||||
entities = []
|
||||
entity_groups = []
|
||||
entity_group_disagg = []
|
||||
# Filter to labels not in `self.ignore_labels`
|
||||
filtered_labels_idx = [
|
||||
(idx, label_idx)
|
||||
@@ -1020,37 +1018,13 @@ class TokenClassificationPipeline(Pipeline):
|
||||
"entity": self.model.config.id2label[label_idx],
|
||||
"index": idx,
|
||||
}
|
||||
last_idx, _ = filtered_labels_idx[-1]
|
||||
if self.grouped_entities:
|
||||
if not entity_group_disagg:
|
||||
entity_group_disagg += [entity]
|
||||
if idx == last_idx:
|
||||
entity_groups += [self.group_entities(entity_group_disagg)]
|
||||
continue
|
||||
|
||||
# If the current entity is similar and adjacent to the previous entity, append it to the disaggregated entity group
|
||||
if (
|
||||
entity["entity"] == entity_group_disagg[-1]["entity"]
|
||||
and entity["index"] == entity_group_disagg[-1]["index"] + 1
|
||||
):
|
||||
entity_group_disagg += [entity]
|
||||
# Group the entities at the last entity
|
||||
if idx == last_idx:
|
||||
entity_groups += [self.group_entities(entity_group_disagg)]
|
||||
# If the current entity is different from the previous entity, aggregate the disaggregated entity group
|
||||
else:
|
||||
entity_groups += [self.group_entities(entity_group_disagg)]
|
||||
entity_group_disagg = [entity]
|
||||
|
||||
entities += [entity]
|
||||
|
||||
# Ensure if an entity is the latest one in the sequence it gets appended to the output
|
||||
if len(entity_group_disagg) > 0:
|
||||
entity_groups.append(self.group_entities(entity_group_disagg))
|
||||
|
||||
# Append
|
||||
# Append grouped entities
|
||||
if self.grouped_entities:
|
||||
answers += [entity_groups]
|
||||
answers += [self.group_entities(entities)]
|
||||
# Append ungrouped entities
|
||||
else:
|
||||
answers += [entities]
|
||||
|
||||
@@ -1058,12 +1032,12 @@ class TokenClassificationPipeline(Pipeline):
|
||||
return answers[0]
|
||||
return answers
|
||||
|
||||
def group_entities(self, entities):
|
||||
def group_sub_entities(self, entities: List[dict]) -> dict:
|
||||
"""
|
||||
Returns grouped entities
|
||||
Returns grouped sub entities
|
||||
"""
|
||||
# Get the last entity in the entity group
|
||||
entity = entities[-1]["entity"]
|
||||
# Get the first entity in the entity group
|
||||
entity = entities[0]["entity"]
|
||||
scores = np.mean([entity["score"] for entity in entities])
|
||||
tokens = [entity["word"] for entity in entities]
|
||||
|
||||
@@ -1074,6 +1048,45 @@ class TokenClassificationPipeline(Pipeline):
|
||||
}
|
||||
return entity_group
|
||||
|
||||
def group_entities(self, entities: List[dict]) -> List[dict]:
|
||||
"""
|
||||
Returns grouped entities
|
||||
"""
|
||||
|
||||
entity_groups = []
|
||||
entity_group_disagg = []
|
||||
|
||||
if entities:
|
||||
last_idx = entities[-1]["index"]
|
||||
|
||||
for entity in entities:
|
||||
is_last_idx = entity["index"] == last_idx
|
||||
if not entity_group_disagg:
|
||||
entity_group_disagg += [entity]
|
||||
if is_last_idx:
|
||||
entity_groups += [self.group_sub_entities(entity_group_disagg)]
|
||||
continue
|
||||
|
||||
# If the current entity is similar and adjacent to the previous entity, append it to the disaggregated entity group
|
||||
# The split is meant to account for the "B" and "I" suffixes
|
||||
if (
|
||||
entity["entity"].split("-")[-1] == entity_group_disagg[-1]["entity"].split("-")[-1]
|
||||
and entity["index"] == entity_group_disagg[-1]["index"] + 1
|
||||
):
|
||||
entity_group_disagg += [entity]
|
||||
# Group the entities at the last entity
|
||||
if is_last_idx:
|
||||
entity_groups += [self.group_sub_entities(entity_group_disagg)]
|
||||
# If the current entity is different from the previous entity, aggregate the disaggregated entity group
|
||||
else:
|
||||
entity_groups += [self.group_sub_entities(entity_group_disagg)]
|
||||
entity_group_disagg = [entity]
|
||||
# If it's the last entity, add it to the entity groups
|
||||
if is_last_idx:
|
||||
entity_groups += [self.group_sub_entities(entity_group_disagg)]
|
||||
|
||||
return entity_groups
|
||||
|
||||
|
||||
NerPipeline = TokenClassificationPipeline
|
||||
|
||||
|
||||
@@ -820,15 +820,29 @@ class Trainer:
|
||||
inputs["mems"] = past
|
||||
|
||||
with torch.no_grad():
|
||||
outputs = model(**inputs)
|
||||
if has_labels:
|
||||
step_eval_loss, logits = outputs[:2]
|
||||
eval_losses += [step_eval_loss.mean().item()]
|
||||
else:
|
||||
logits = outputs[0]
|
||||
if self.args.past_index >= 0:
|
||||
past = outputs[self.args.past_index if has_labels else self.args.past_index - 1]
|
||||
if self.args.predict_from_generate:
|
||||
max_length = model.config.max_length
|
||||
logits_out = model.generate(inputs["input_ids"], attention_mask=inputs["attention_mask"])
|
||||
# in case the batch is shorter then max length, the output should be padded
|
||||
logits = model.config.eos_token_id * torch.ones(
|
||||
(logits_out.shape[0], max_length), dtype=logits_out.dtype, device=logits_out.device
|
||||
)
|
||||
logits[:, : logits_out.shape[-1]] = logits_out
|
||||
|
||||
if has_labels:
|
||||
outputs = model(**inputs)
|
||||
step_eval_loss = outputs[0]
|
||||
eval_losses += [step_eval_loss.mean().item()]
|
||||
else:
|
||||
outputs = model(**inputs)
|
||||
|
||||
if has_labels:
|
||||
step_eval_loss, logits = outputs[:2]
|
||||
eval_losses += [step_eval_loss.mean().item()]
|
||||
else:
|
||||
logits = outputs[0]
|
||||
if self.args.past_index >= 0:
|
||||
past = outputs[self.args.past_index if has_labels else self.args.past_index - 1]
|
||||
if not prediction_loss_only:
|
||||
if preds is None:
|
||||
preds = logits.detach()
|
||||
|
||||
@@ -157,6 +157,12 @@ class TrainingArguments:
|
||||
default=1,
|
||||
metadata={"help": "Number of updates steps to accumulate before performing a backward/update pass."},
|
||||
)
|
||||
predict_from_generate: bool = field(
|
||||
default=False,
|
||||
metadata={
|
||||
"help": "Use generate function to predict logits. This is usually the case for summarization or translation."
|
||||
},
|
||||
)
|
||||
|
||||
learning_rate: float = field(default=5e-5, metadata={"help": "The initial learning rate for Adam."})
|
||||
weight_decay: float = field(default=0.0, metadata={"help": "Weight decay if we apply some."})
|
||||
|
||||
+95
-28
@@ -38,6 +38,7 @@ expected_fill_mask_result = [
|
||||
{"sequence": "<s>The largest city in France is Lyon</s>", "score": 0.21112334728240967, "token": 12790},
|
||||
],
|
||||
]
|
||||
|
||||
SUMMARIZATION_KWARGS = dict(num_beams=2, min_length=2, max_length=5)
|
||||
|
||||
|
||||
@@ -156,34 +157,6 @@ class MonoColumnInputTestCase(unittest.TestCase):
|
||||
|
||||
self.assertRaises(Exception, nlp, invalid_inputs)
|
||||
|
||||
@require_torch
|
||||
def test_torch_ner(self):
|
||||
mandatory_keys = {"entity", "word", "score"}
|
||||
for model_name in NER_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="ner", model=model_name, tokenizer=model_name)
|
||||
self._test_mono_column_pipeline(nlp, VALID_INPUTS, mandatory_keys)
|
||||
|
||||
@require_torch
|
||||
def test_ner_grouped(self):
|
||||
mandatory_keys = {"entity_group", "word", "score"}
|
||||
for model_name in NER_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="ner", model=model_name, tokenizer=model_name, grouped_entities=True)
|
||||
self._test_mono_column_pipeline(nlp, VALID_INPUTS, mandatory_keys)
|
||||
|
||||
@require_tf
|
||||
def test_tf_ner(self):
|
||||
mandatory_keys = {"entity", "word", "score"}
|
||||
for model_name in NER_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="ner", model=model_name, tokenizer=model_name, framework="tf")
|
||||
self._test_mono_column_pipeline(nlp, VALID_INPUTS, mandatory_keys)
|
||||
|
||||
@require_tf
|
||||
def test_tf_ner_grouped(self):
|
||||
mandatory_keys = {"entity_group", "word", "score"}
|
||||
for model_name in NER_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="ner", model=model_name, tokenizer=model_name, framework="tf", grouped_entities=True)
|
||||
self._test_mono_column_pipeline(nlp, VALID_INPUTS, mandatory_keys)
|
||||
|
||||
@require_torch
|
||||
def test_torch_sentiment_analysis(self):
|
||||
mandatory_keys = {"label", "score"}
|
||||
@@ -393,6 +366,100 @@ class QAPipelineTests(unittest.TestCase):
|
||||
self._test_qa_pipeline(nlp)
|
||||
|
||||
|
||||
class NerPipelineTests(unittest.TestCase):
|
||||
def _test_ner_pipeline(
|
||||
self, nlp: Pipeline, output_keys: Iterable[str],
|
||||
):
|
||||
|
||||
ungrouped_ner_inputs = [
|
||||
[
|
||||
{"entity": "B-PER", "index": 1, "score": 0.9994944930076599, "word": "Cons"},
|
||||
{"entity": "B-PER", "index": 2, "score": 0.8025449514389038, "word": "##uelo"},
|
||||
{"entity": "I-PER", "index": 3, "score": 0.9993102550506592, "word": "Ara"},
|
||||
{"entity": "I-PER", "index": 4, "score": 0.9993743896484375, "word": "##új"},
|
||||
{"entity": "I-PER", "index": 5, "score": 0.9992871880531311, "word": "##o"},
|
||||
{"entity": "I-PER", "index": 6, "score": 0.9993029236793518, "word": "No"},
|
||||
{"entity": "I-PER", "index": 7, "score": 0.9981776475906372, "word": "##guera"},
|
||||
{"entity": "B-PER", "index": 15, "score": 0.9998136162757874, "word": "Andrés"},
|
||||
{"entity": "I-PER", "index": 16, "score": 0.999740719795227, "word": "Pas"},
|
||||
{"entity": "I-PER", "index": 17, "score": 0.9997414350509644, "word": "##tran"},
|
||||
{"entity": "I-PER", "index": 18, "score": 0.9996136426925659, "word": "##a"},
|
||||
{"entity": "B-ORG", "index": 28, "score": 0.9989739060401917, "word": "Far"},
|
||||
{"entity": "I-ORG", "index": 29, "score": 0.7188422083854675, "word": "##c"},
|
||||
],
|
||||
[
|
||||
{"entity": "I-PER", "index": 1, "score": 0.9968166351318359, "word": "En"},
|
||||
{"entity": "I-PER", "index": 2, "score": 0.9957635998725891, "word": "##zo"},
|
||||
{"entity": "I-ORG", "index": 7, "score": 0.9986497163772583, "word": "UN"},
|
||||
],
|
||||
]
|
||||
expected_grouped_ner_results = [
|
||||
[
|
||||
{"entity_group": "B-PER", "score": 0.9710702640669686, "word": "Consuelo Araújo Noguera"},
|
||||
{"entity_group": "B-PER", "score": 0.9997273534536362, "word": "Andrés Pastrana"},
|
||||
{"entity_group": "B-ORG", "score": 0.8589080572128296, "word": "Farc"},
|
||||
],
|
||||
[
|
||||
{"entity_group": "I-PER", "score": 0.9962901175022125, "word": "Enzo"},
|
||||
{"entity_group": "I-ORG", "score": 0.9986497163772583, "word": "UN"},
|
||||
],
|
||||
]
|
||||
|
||||
self.assertIsNotNone(nlp)
|
||||
|
||||
mono_result = nlp(VALID_INPUTS[0])
|
||||
self.assertIsInstance(mono_result, list)
|
||||
self.assertIsInstance(mono_result[0], (dict, list))
|
||||
|
||||
if isinstance(mono_result[0], list):
|
||||
mono_result = mono_result[0]
|
||||
|
||||
for key in output_keys:
|
||||
self.assertIn(key, mono_result[0])
|
||||
|
||||
multi_result = [nlp(input) for input in VALID_INPUTS]
|
||||
self.assertIsInstance(multi_result, list)
|
||||
self.assertIsInstance(multi_result[0], (dict, list))
|
||||
|
||||
if isinstance(multi_result[0], list):
|
||||
multi_result = multi_result[0]
|
||||
|
||||
for result in multi_result:
|
||||
for key in output_keys:
|
||||
self.assertIn(key, result)
|
||||
|
||||
for ungrouped_input, grouped_result in zip(ungrouped_ner_inputs, expected_grouped_ner_results):
|
||||
self.assertEqual(nlp.group_entities(ungrouped_input), grouped_result)
|
||||
|
||||
@require_torch
|
||||
def test_torch_ner(self):
|
||||
mandatory_keys = {"entity", "word", "score"}
|
||||
for model_name in NER_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="ner", model=model_name, tokenizer=model_name)
|
||||
self._test_ner_pipeline(nlp, mandatory_keys)
|
||||
|
||||
@require_torch
|
||||
def test_ner_grouped(self):
|
||||
mandatory_keys = {"entity_group", "word", "score"}
|
||||
for model_name in NER_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="ner", model=model_name, tokenizer=model_name, grouped_entities=True)
|
||||
self._test_ner_pipeline(nlp, mandatory_keys)
|
||||
|
||||
@require_tf
|
||||
def test_tf_ner(self):
|
||||
mandatory_keys = {"entity", "word", "score"}
|
||||
for model_name in NER_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="ner", model=model_name, tokenizer=model_name, framework="tf")
|
||||
self._test_ner_pipeline(nlp, mandatory_keys)
|
||||
|
||||
@require_tf
|
||||
def test_tf_ner_grouped(self):
|
||||
mandatory_keys = {"entity_group", "word", "score"}
|
||||
for model_name in NER_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="ner", model=model_name, tokenizer=model_name, framework="tf", grouped_entities=True)
|
||||
self._test_ner_pipeline(nlp, mandatory_keys)
|
||||
|
||||
|
||||
class PipelineCommonTests(unittest.TestCase):
|
||||
|
||||
pipelines = SUPPORTED_TASKS.keys()
|
||||
|
||||
Reference in New Issue
Block a user