Compare commits
6
Commits
tapas-style
...
tapas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
005fcce7cc | ||
|
|
5102527eee | ||
|
|
6861aa9cc4 | ||
|
|
0691e49741 | ||
|
|
ca2725ee79 | ||
|
|
ba66c4c817 |
No files matched your search
@@ -145,8 +145,8 @@ conversion utilities for the following models:
|
|||||||
27. :doc:`T5 <model_doc/t5>` (from Google AI) released with the paper `Exploring the Limits of Transfer Learning with a
|
27. :doc:`T5 <model_doc/t5>` (from Google AI) released with the paper `Exploring the Limits of Transfer Learning with a
|
||||||
Unified Text-to-Text Transformer <https://arxiv.org/abs/1910.10683>`__ by Colin Raffel and Noam Shazeer and Adam
|
Unified Text-to-Text Transformer <https://arxiv.org/abs/1910.10683>`__ by Colin Raffel and Noam Shazeer and Adam
|
||||||
Roberts and Katherine Lee and Sharan Narang and Michael Matena and Yanqi Zhou and Wei Li and Peter J. Liu.
|
Roberts and Katherine Lee and Sharan Narang and Michael Matena and Yanqi Zhou and Wei Li and Peter J. Liu.
|
||||||
28. :doc:`TAPAS <model_doc/tapas>` (from Google AI) released with the paper `TAPAS: Weakly Supervised Table Parsing via
|
28. :doc:`TAPAS <model_doc/tapas>` (from Google AI) released with the paper `TAPAS: Weakly Supervised Table Parsing via
|
||||||
Pre-training <https://arxiv.org/abs/2004.02349>`__ by Jonathan Herzig, Paweł Krzysztof Nowak, Thomas Müller,
|
Pre-training <https://arxiv.org/abs/2004.02349>`__ by Jonathan Herzig, Paweł Krzysztof Nowak, Thomas Müller,
|
||||||
Francesco Piccinno and Julian Martin Eisenschlos.
|
Francesco Piccinno and Julian Martin Eisenschlos.
|
||||||
29. :doc:`Transformer-XL <model_doc/transformerxl>` (from Google/CMU) released with the paper `Transformer-XL:
|
29. :doc:`Transformer-XL <model_doc/transformerxl>` (from Google/CMU) released with the paper `Transformer-XL:
|
||||||
Attentive Language Models Beyond a Fixed-Length Context <https://arxiv.org/abs/1901.02860>`__ by Zihang Dai*,
|
Attentive Language Models Beyond a Fixed-Length Context <https://arxiv.org/abs/1901.02860>`__ by Zihang Dai*,
|
||||||
|
|||||||
@@ -5,85 +5,84 @@ Overview
|
|||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The TAPAS model was proposed in `TAPAS: Weakly Supervised Table Parsing via Pre-training
|
The TAPAS model was proposed in `TAPAS: Weakly Supervised Table Parsing via Pre-training
|
||||||
<https://arxiv.org/abs/2004.02349>`__ by Jonathan Herzig, Paweł Krzysztof Nowak, Thomas Müller, Francesco Piccinno and
|
<https://arxiv.org/abs/2004.02349>`__ by Jonathan Herzig, Paweł Krzysztof Nowak, Thomas Müller, Francesco Piccinno and
|
||||||
Julian Martin Eisenschlos.
|
Julian Martin Eisenschlos. It's a BERT-based model specifically designed (and pre-trained) for answering questions
|
||||||
It's a BERT-based model specifically designed (and pre-trained) for answering questions about tabular data. Compared to
|
about tabular data. Compared to BERT, TAPAS uses relative position embeddings and has 7 token types that encode tabular
|
||||||
BERT, TAPAS uses relative position embeddings and has 7 token types that encode tabular structure. TAPAS is pre-trained
|
structure. TAPAS is pre-trained on the masked language modeling (MLM) objective on a large dataset comprising millions
|
||||||
on the masked language modeling (MLM) objective on a large dataset comprising millions of tables from English Wikipedia and
|
of tables from English Wikipedia and corresponding texts. For question answering, TAPAS has 2 heads on top: a cell
|
||||||
corresponding texts. For question answering, TAPAS has 2 heads on top: a cell selection head and an aggregation head, for
|
selection head and an aggregation head, for (optionally) performing aggregations (such as counting or summing) among
|
||||||
(optionally) performing aggregations (such as counting or summing) among selected cells. TAPAS has been fine-tuned on several
|
selected cells. TAPAS has been fine-tuned on several datasets: SQA (Sequential Question Answering by Microsoft), WTQ
|
||||||
datasets: SQA (Sequential Question Answering by Microsoft), WTQ (Wiki Table Questions by Stanford University) and WikiSQL
|
(Wiki Table Questions by Stanford University) and WikiSQL (by Salesforce). It achieves state-of-the-art on both SQA and
|
||||||
(by Salesforce). It achieves state-of-the-art on both SQA and WTQ, while having comparable performance to SOTA on WikiSQL,
|
WTQ, while having comparable performance to SOTA on WikiSQL, with a much simpler architecture.
|
||||||
with a much simpler architecture.
|
|
||||||
|
|
||||||
The abstract from the paper is the following:
|
The abstract from the paper is the following:
|
||||||
|
|
||||||
*Answering natural language questions over tables is usually seen as a semantic parsing task.
|
*Answering natural language questions over tables is usually seen as a semantic parsing task. To alleviate the
|
||||||
To alleviate the collection cost of full logical forms, one popular approach focuses on weak
|
collection cost of full logical forms, one popular approach focuses on weak supervision consisting of denotations
|
||||||
supervision consisting of denotations instead of logical forms. However, training semantic parsers
|
instead of logical forms. However, training semantic parsers from weak supervision poses difficulties, and in addition,
|
||||||
from weak supervision poses difficulties, and in addition, the generated logical forms are only used
|
the generated logical forms are only used as an intermediate step prior to retrieving the denotation. In this paper, we
|
||||||
as an intermediate step prior to retrieving the denotation. In this paper, we present TAPAS, an
|
present TAPAS, an approach to question answering over tables without generating logical forms. TAPAS trains from weak
|
||||||
approach to question answering over tables without generating logical forms. TAPAS trains from weak
|
supervision, and predicts the denotation by selecting table cells and optionally applying a corresponding aggregation
|
||||||
supervision, and predicts the denotation by selecting table cells and optionally applying a corresponding
|
operator to such selection. TAPAS extends BERT's architecture to encode tables as input, initializes from an effective
|
||||||
aggregation operator to such selection. TAPAS extends BERT's architecture to encode tables as input,
|
joint pre-training of text segments and tables crawled from Wikipedia, and is trained end-to-end. We experiment with
|
||||||
initializes from an effective joint pre-training of text segments and tables crawled from Wikipedia,
|
three different semantic parsing datasets, and find that TAPAS outperforms or rivals semantic parsing models by
|
||||||
and is trained end-to-end. We experiment with three different semantic parsing datasets, and find
|
improving state-of-the-art accuracy on SQA from 55.1 to 67.2 and performing on par with the state-of-the-art on WIKISQL
|
||||||
that TAPAS outperforms or rivals semantic parsing models by improving state-of-the-art accuracy on
|
and WIKITQ, but with a simpler model architecture. We additionally find that transfer learning, which is trivial in our
|
||||||
SQA from 55.1 to 67.2 and performing on par with the state-of-the-art on WIKISQL and WIKITQ, but
|
setting, from WIKISQL to WIKITQ, yields 48.7 accuracy, 4.2 points above the state-of-the-art.*
|
||||||
with a simpler model architecture. We additionally find that transfer learning, which is trivial
|
|
||||||
in our setting, from WIKISQL to WIKITQ, yields 48.7 accuracy, 4.2 points above the state-of-the-art.*
|
|
||||||
|
|
||||||
In addition, the authors have further pre-trained TAPAS to recognize table entailment, by creating a balanced dataset of millions
|
In addition, the authors have further pre-trained TAPAS to recognize table entailment, by creating a balanced dataset
|
||||||
of automatically created training examples which are learned in an intermediate step prior to fine-tuning. The authors of TAPAS
|
of millions of automatically created training examples which are learned in an intermediate step prior to fine-tuning.
|
||||||
call this further pre-training intermediate pre-training (since TAPAS is first pre-trained on MLM, and then on another dataset).
|
The authors of TAPAS call this further pre-training intermediate pre-training (since TAPAS is first pre-trained on MLM,
|
||||||
They found that intermediate pre-training further improves performance on SQA, achieving a new state-of-the-art as well as
|
and then on another dataset). They found that intermediate pre-training further improves performance on SQA, achieving
|
||||||
state-of-the-art on TabFact, a large-scale dataset with 16k Wikipedia tables for table entailment (a binary classification task).
|
a new state-of-the-art as well as state-of-the-art on TabFact, a large-scale dataset with 16k Wikipedia tables for
|
||||||
For more details, see their new paper: `Understanding tables with intermediate pre-training <https://arxiv.org/abs/2010.00571>`__
|
table entailment (a binary classification task). For more details, see their new paper: `Understanding tables with
|
||||||
by Julian Martin Eisenschlos, Syrine Krichene and Thomas Müller.
|
intermediate pre-training <https://arxiv.org/abs/2010.00571>`__ by Julian Martin Eisenschlos, Syrine Krichene and
|
||||||
|
Thomas Müller.
|
||||||
|
|
||||||
The original code can be found `here <https://github.com/google-research/tapas>`__.
|
The original code can be found `here <https://github.com/google-research/tapas>`__.
|
||||||
|
|
||||||
Tips:
|
Tips:
|
||||||
|
|
||||||
- TAPAS is a model that uses relative position embeddings by default (restarting the position embeddings at every cell of the table). According to
|
- TAPAS is a model that uses relative position embeddings by default (restarting the position embeddings at every cell
|
||||||
the authors, this usually results in a slightly better performance, and allows you to encode longer sequences without running out
|
of the table). According to the authors, this usually results in a slightly better performance, and allows you to
|
||||||
of embeddings.
|
encode longer sequences without running out of embeddings. If you don't want this, you can set the
|
||||||
If you don't want this, you can set the `reset_position_index_per_cell` parameter of :class:`~transformers.TapasConfig` to False.
|
`reset_position_index_per_cell` parameter of :class:`~transformers.TapasConfig` to False.
|
||||||
- TAPAS has checkpoints fine-tuned on SQA, which are capable of answering questions related to a table in a conversational set-up. This
|
- TAPAS has checkpoints fine-tuned on SQA, which are capable of answering questions related to a table in a
|
||||||
means that you can ask follow-up questions such as "what is his age?" related to the previous question. Note that the forward pass of
|
conversational set-up. This means that you can ask follow-up questions such as "what is his age?" related to the
|
||||||
TAPAS is a bit different in case of a conversational set-up: in that case, you have to feed every training example one by one to the
|
previous question. Note that the forward pass of TAPAS is a bit different in case of a conversational set-up: in that
|
||||||
model, such that the `prev_label_ids` token type ids can be overwritten by the predicted `label_ids` of the model to the previous
|
case, you have to feed every training example one by one to the model, such that the `prev_label_ids` token type ids
|
||||||
question.
|
can be overwritten by the predicted `label_ids` of the model to the previous question.
|
||||||
- TAPAS is similar to BERT and therefore relies on the masked language modeling (MLM) objective.
|
- TAPAS is similar to BERT and therefore relies on the masked language modeling (MLM) objective. It is therefore
|
||||||
It is therefore efficient at predicting masked tokens and at NLU in general, but is not optimal for
|
efficient at predicting masked tokens and at NLU in general, but is not optimal for text generation. Models trained
|
||||||
text generation. Models trained with a causal language modeling (CLM) objective are better in that regard.
|
with a causal language modeling (CLM) objective are better in that regard.
|
||||||
|
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
If you just want to perform inference (i.e. making predictions) in a non-conversational setup, you can do the following:
|
If you just want to perform inference (i.e. making predictions) in a non-conversational setup, you can do the
|
||||||
|
following:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
>>> from transformers import TapasTokenizer, TapasForQuestionAnswering
|
>>> from transformers import TapasTokenizer, TapasForQuestionAnswering
|
||||||
>>> import pandas as pd
|
>>> import pandas as pd
|
||||||
|
|
||||||
>>> model_name = 'tapas-base-finetuned-wtq'
|
>>> model_name = 'tapas-base-finetuned-wtq'
|
||||||
>>> model = TapasForQuestionAnswering.from_pretrained(model_name)
|
>>> model = TapasForQuestionAnswering.from_pretrained(model_name)
|
||||||
>>> tokenizer = TapasTokenizer.from_pretrained(model_name)
|
>>> tokenizer = TapasTokenizer.from_pretrained(model_name)
|
||||||
|
|
||||||
>>> data = {'Actors': ["Brad Pitt", "Leonardo Di Caprio", "George Clooney"], 'Number of movies': ["87", "53", "69"]}
|
>>> data = {'Actors': ["Brad Pitt", "Leonardo Di Caprio", "George Clooney"], 'Number of movies': ["87", "53", "69"]}
|
||||||
>>> queries = ["What is the name of the first actor?", "How many movies has George Clooney played in?", "What is the total number of movies?"]
|
>>> queries = ["What is the name of the first actor?", "How many movies has George Clooney played in?", "What is the total number of movies?"]
|
||||||
>>> table = pd.Dataframe(data)
|
>>> table = pd.Dataframe(data)
|
||||||
>>> inputs = tokenizer(table, queries, return_tensors='pt')
|
>>> inputs = tokenizer(table, queries, return_tensors='pt')
|
||||||
>>> logits, logits_agg = model(**inputs)
|
>>> logits, logits_agg = model(**inputs)
|
||||||
>>> answer_coordinates_batch, aggregation_predictions = tokenizer.convert_logits_to_predictions(inputs, logits, logits_agg)
|
>>> answer_coordinates_batch, aggregation_predictions = tokenizer.convert_logits_to_predictions(inputs, logits, logits_agg)
|
||||||
|
|
||||||
>>> # let's print out the results:
|
>>> # let's print out the results:
|
||||||
>>> id2aggregation = {0: "NONE", 1: "SUM", 2: "AVERAGE", 3:"COUNT"}
|
>>> id2aggregation = {0: "NONE", 1: "SUM", 2: "AVERAGE", 3:"COUNT"}
|
||||||
>>> aggregation_predictions_string = [id2aggregation[x] for x in aggregation_predictions]
|
>>> aggregation_predictions_string = [id2aggregation[x] for x in aggregation_predictions]
|
||||||
|
|
||||||
>>> answers = []
|
>>> answers = []
|
||||||
>>> for coordinates in answer_coordinates_batch:
|
>>> for coordinates in answer_coordinates_batch:
|
||||||
... if len(coordinates) == 1:
|
... if len(coordinates) == 1:
|
||||||
@@ -95,7 +94,7 @@ If you just want to perform inference (i.e. making predictions) in a non-convers
|
|||||||
... for coordinate in coordinates:
|
... for coordinate in coordinates:
|
||||||
... cell_values.append(df.iat[coordinate])
|
... cell_values.append(df.iat[coordinate])
|
||||||
... answers.append(", ".join(cell_values))
|
... answers.append(", ".join(cell_values))
|
||||||
|
|
||||||
>>> display(df)
|
>>> display(df)
|
||||||
>>> print("")
|
>>> print("")
|
||||||
>>> for query, answer, predicted_agg in zip(queries, answers, aggregation_predictions_string):
|
>>> for query, answer, predicted_agg in zip(queries, answers, aggregation_predictions_string):
|
||||||
|
|||||||
@@ -562,10 +562,10 @@ if is_torch_available():
|
|||||||
)
|
)
|
||||||
from .modeling_tapas import (
|
from .modeling_tapas import (
|
||||||
TAPAS_PRETRAINED_MODEL_ARCHIVE_LIST,
|
TAPAS_PRETRAINED_MODEL_ARCHIVE_LIST,
|
||||||
TapasModel,
|
|
||||||
TapasForMaskedLM,
|
TapasForMaskedLM,
|
||||||
TapasForQuestionAnswering,
|
TapasForQuestionAnswering,
|
||||||
TapasForSequenceClassification,
|
TapasForSequenceClassification,
|
||||||
|
TapasModel,
|
||||||
load_tf_weights_in_tapas,
|
load_tf_weights_in_tapas,
|
||||||
)
|
)
|
||||||
from .modeling_transfo_xl import (
|
from .modeling_transfo_xl import (
|
||||||
|
|||||||
@@ -17,20 +17,20 @@
|
|||||||
|
|
||||||
from .configuration_utils import PretrainedConfig
|
from .configuration_utils import PretrainedConfig
|
||||||
|
|
||||||
|
|
||||||
TAPAS_PRETRAINED_CONFIG_ARCHIVE_MAP = {"tapas-base": "", "tapas-large": ""} # to be added # to be added
|
TAPAS_PRETRAINED_CONFIG_ARCHIVE_MAP = {"tapas-base": "", "tapas-large": ""} # to be added # to be added
|
||||||
|
|
||||||
|
|
||||||
class TapasConfig(PretrainedConfig):
|
class TapasConfig(PretrainedConfig):
|
||||||
r"""
|
r"""
|
||||||
This is the configuration class to store the configuration of a :class:`~transformers.TapasModel`.
|
This is the configuration class to store the configuration of a :class:`~transformers.TapasModel`. It is used to
|
||||||
It is used to instantiate a TAPAS model according to the specified arguments, defining the model
|
instantiate a TAPAS model according to the specified arguments, defining the model architecture. Instantiating a
|
||||||
architecture. Instantiating a configuration with the defaults will yield a similar configuration
|
configuration with the defaults will yield a similar configuration to that of the TAPAS `tapas-base-finetuned-sqa`
|
||||||
to that of the TAPAS `tapas-base-finetuned-sqa` architecture. Configuration objects
|
architecture. Configuration objects inherit from :class:`~transformers.PreTrainedConfig` and can be used to control
|
||||||
inherit from :class:`~transformers.PreTrainedConfig` and can be used to control the model outputs.
|
the model outputs. Read the documentation from :class:`~transformers.PretrainedConfig` for more information.
|
||||||
Read the documentation from :class:`~transformers.PretrainedConfig` for more information.
|
|
||||||
|
|
||||||
Hyperparameters additional to BERT are taken from run_task_main.py and hparam_utils.py of the original implementation.
|
Hyperparameters additional to BERT are taken from run_task_main.py and hparam_utils.py of the original
|
||||||
Original implementation available at https://github.com/google-research/tapas/tree/master.
|
implementation. Original implementation available at https://github.com/google-research/tapas/tree/master.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vocab_size (:obj:`int`, `optional`, defaults to 30522):
|
vocab_size (:obj:`int`, `optional`, defaults to 30522):
|
||||||
@@ -87,9 +87,9 @@ class TapasConfig(PretrainedConfig):
|
|||||||
average_approximation_function: (:obj:`string`, `optional`, defaults to :obj:`"ratio"`):
|
average_approximation_function: (:obj:`string`, `optional`, defaults to :obj:`"ratio"`):
|
||||||
Method to calculate expected average of cells in the relaxed case.
|
Method to calculate expected average of cells in the relaxed case.
|
||||||
cell_selection_preference: (:obj:`float`, `optional`, defaults to None):
|
cell_selection_preference: (:obj:`float`, `optional`, defaults to None):
|
||||||
Preference for cell selection in ambiguous cases. Only applicable in case of weak supervision for aggregation (WTQ, WikiSQL).
|
Preference for cell selection in ambiguous cases. Only applicable in case of weak supervision for
|
||||||
If the total mass of the aggregation probabilities (excluding the "NONE" operator) is higher than this hyperparameter,
|
aggregation (WTQ, WikiSQL). If the total mass of the aggregation probabilities (excluding the "NONE"
|
||||||
then aggregation is predicted for an example.
|
operator) is higher than this hyperparameter, then aggregation is predicted for an example.
|
||||||
answer_loss_cutoff: (:obj:`float`, `optional`, defaults to None):
|
answer_loss_cutoff: (:obj:`float`, `optional`, defaults to None):
|
||||||
Ignore examples with answer loss larger than cutoff.
|
Ignore examples with answer loss larger than cutoff.
|
||||||
max_num_rows: (:obj:`int`, `optional`, defaults to 64):
|
max_num_rows: (:obj:`int`, `optional`, defaults to 64):
|
||||||
@@ -109,7 +109,7 @@ class TapasConfig(PretrainedConfig):
|
|||||||
disable_per_token_loss: (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
disable_per_token_loss: (:obj:`bool`, `optional`, defaults to :obj:`False`):
|
||||||
Disable any (strong or weak) supervision on cells.
|
Disable any (strong or weak) supervision on cells.
|
||||||
span_prediction: (:obj:`string`, `optional`, defaults to :obj:`"none"`):
|
span_prediction: (:obj:`string`, `optional`, defaults to :obj:`"none"`):
|
||||||
Span selection mode to use. Currently only "none" is supported.
|
Span selection mode to use. Currently only "none" is supported.
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,12 @@ import argparse
|
|||||||
|
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
from transformers import TapasConfig, TapasForQuestionAnswering, TapasForSequenceClassification, load_tf_weights_in_tapas
|
from transformers import (
|
||||||
|
TapasConfig,
|
||||||
|
TapasForQuestionAnswering,
|
||||||
|
TapasForSequenceClassification,
|
||||||
|
load_tf_weights_in_tapas,
|
||||||
|
)
|
||||||
from transformers.utils import logging
|
from transformers.utils import logging
|
||||||
|
|
||||||
|
|
||||||
@@ -41,14 +46,14 @@ def convert_tf_checkpoint_to_pytorch(tf_checkpoint_path, tapas_config_file, pyto
|
|||||||
# select_one_column = True,
|
# select_one_column = True,
|
||||||
# allow_empty_column_selection = False,
|
# allow_empty_column_selection = False,
|
||||||
# temperature = 0.0352513)
|
# temperature = 0.0352513)
|
||||||
|
|
||||||
# SQA config
|
# SQA config
|
||||||
config = TapasConfig()
|
config = TapasConfig()
|
||||||
|
|
||||||
print("Building PyTorch model from configuration: {}".format(str(config)))
|
print("Building PyTorch model from configuration: {}".format(str(config)))
|
||||||
# model = TapasForMaskedLM(config)
|
# model = TapasForMaskedLM(config)
|
||||||
model = TapasForQuestionAnswering(config)
|
model = TapasForQuestionAnswering(config)
|
||||||
#model = TapasForSequenceClassification(config)
|
# model = TapasForSequenceClassification(config)
|
||||||
|
|
||||||
# Load weights from tf checkpoint
|
# Load weights from tf checkpoint
|
||||||
load_tf_weights_in_tapas(model, config, tf_checkpoint_path)
|
load_tf_weights_in_tapas(model, config, tf_checkpoint_path)
|
||||||
|
|||||||
@@ -191,10 +191,10 @@ try:
|
|||||||
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
_tokenizers_available = False
|
_tokenizers_available = False
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import torch_scatter
|
import torch_scatter
|
||||||
|
|
||||||
# Check we're not importing a "torch_scatter" directory somewhere
|
# Check we're not importing a "torch_scatter" directory somewhere
|
||||||
_scatter_available = hasattr(torch_scatter, "__version__") and hasattr(torch_scatter, "scatter")
|
_scatter_available = hasattr(torch_scatter, "__version__") and hasattr(torch_scatter, "scatter")
|
||||||
|
|||||||
+274
-246
@@ -15,11 +15,11 @@
|
|||||||
"""PyTorch TAPAS model. """
|
"""PyTorch TAPAS model. """
|
||||||
|
|
||||||
|
|
||||||
|
import enum
|
||||||
import math
|
import math
|
||||||
import os
|
import os
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
import enum
|
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
import torch.nn as nn
|
import torch.nn as nn
|
||||||
@@ -27,19 +27,15 @@ from torch.nn import CrossEntropyLoss, MSELoss
|
|||||||
|
|
||||||
from .activations import ACT2FN
|
from .activations import ACT2FN
|
||||||
from .configuration_tapas import TapasConfig
|
from .configuration_tapas import TapasConfig
|
||||||
from .file_utils import (ModelOutput,
|
from .file_utils import (
|
||||||
add_start_docstrings,
|
ModelOutput,
|
||||||
add_start_docstrings_to_model_forward,
|
add_start_docstrings,
|
||||||
replace_return_docstrings,
|
add_start_docstrings_to_model_forward,
|
||||||
is_scatter_available,
|
is_scatter_available,
|
||||||
requires_scatter,
|
replace_return_docstrings,
|
||||||
)
|
requires_scatter,
|
||||||
from .modeling_outputs import (
|
|
||||||
BaseModelOutput,
|
|
||||||
BaseModelOutputWithPooling,
|
|
||||||
MaskedLMOutput,
|
|
||||||
SequenceClassifierOutput,
|
|
||||||
)
|
)
|
||||||
|
from .modeling_outputs import BaseModelOutput, BaseModelOutputWithPooling, MaskedLMOutput, SequenceClassifierOutput
|
||||||
from .modeling_utils import (
|
from .modeling_utils import (
|
||||||
PreTrainedModel,
|
PreTrainedModel,
|
||||||
apply_chunking_to_forward,
|
apply_chunking_to_forward,
|
||||||
@@ -48,6 +44,7 @@ from .modeling_utils import (
|
|||||||
)
|
)
|
||||||
from .utils import logging
|
from .utils import logging
|
||||||
|
|
||||||
|
|
||||||
# soft dependency
|
# soft dependency
|
||||||
if is_scatter_available():
|
if is_scatter_available():
|
||||||
from torch_scatter import scatter
|
from torch_scatter import scatter
|
||||||
@@ -75,20 +72,20 @@ class TableQuestionAnsweringOutput(ModelOutput):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`label_ids` (and possibly :obj:`answer`, :obj:`aggregation_labels`, :obj:`numeric_values` and :obj:`numeric_values_scale` are provided)):
|
loss (:obj:`torch.FloatTensor` of shape :obj:`(1,)`, `optional`, returned when :obj:`label_ids` (and possibly :obj:`answer`, :obj:`aggregation_labels`, :obj:`numeric_values` and :obj:`numeric_values_scale` are provided)):
|
||||||
Total loss as the sum of the hierarchical cell selection log-likelihood loss and (optionally) the semi-supervised regression loss and (optionally) supervised loss for aggregations.
|
Total loss as the sum of the hierarchical cell selection log-likelihood loss and (optionally) the
|
||||||
|
semi-supervised regression loss and (optionally) supervised loss for aggregations.
|
||||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`):
|
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`):
|
||||||
Prediction scores of the cell selection head, for every token.
|
Prediction scores of the cell selection head, for every token.
|
||||||
logits_aggregation (:obj:`torch.FloatTensor`, `optional`, of shape :obj:`(batch_size, num_aggregation_labels)`):
|
logits_aggregation (:obj:`torch.FloatTensor`, `optional`, of shape :obj:`(batch_size, num_aggregation_labels)`):
|
||||||
Prediction scores of the aggregation head, for every aggregation operator.
|
Prediction scores of the aggregation head, for every aggregation operator.
|
||||||
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_hidden_states=True`` is passed or when ``config.output_hidden_states=True``):
|
||||||
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
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)`.
|
of shape :obj:`(batch_size, sequence_length, hidden_size)`. Hidden-states of the model at the output of
|
||||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
each layer plus the initial embedding outputs.
|
||||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape
|
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape :obj:`(batch_size, num_heads,
|
||||||
:obj:`(batch_size, num_heads, sequence_length, sequence_length)`.
|
sequence_length, sequence_length)`. Attentions weights after the attention softmax, used to compute the
|
||||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
weighted average in the self-attention heads.
|
||||||
heads.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
loss: Optional[torch.FloatTensor] = None
|
loss: Optional[torch.FloatTensor] = None
|
||||||
@@ -99,7 +96,9 @@ class TableQuestionAnsweringOutput(ModelOutput):
|
|||||||
|
|
||||||
|
|
||||||
def load_tf_weights_in_tapas(model, config, tf_checkpoint_path):
|
def load_tf_weights_in_tapas(model, config, tf_checkpoint_path):
|
||||||
"""Load tf checkpoints in a PyTorch model. This is an adaptation from load_tf_weights_in_bert
|
"""
|
||||||
|
Load tf checkpoints in a PyTorch model. This is an adaptation from load_tf_weights_in_bert
|
||||||
|
|
||||||
- add cell selection and aggregation heads
|
- add cell selection and aggregation heads
|
||||||
- take into account additional token type embedding layers
|
- take into account additional token type embedding layers
|
||||||
"""
|
"""
|
||||||
@@ -144,19 +143,19 @@ def load_tf_weights_in_tapas(model, config, tf_checkpoint_path):
|
|||||||
):
|
):
|
||||||
logger.info("Skipping {}".format("/".join(name)))
|
logger.info("Skipping {}".format("/".join(name)))
|
||||||
continue
|
continue
|
||||||
# in case the model is TapasForSequenceClassification, we skip output_bias and output_weights
|
# in case the model is TapasForSequenceClassification, we skip output_bias and output_weights
|
||||||
# since these are not used for classification
|
# since these are not used for classification
|
||||||
if isinstance(model, TapasForSequenceClassification):
|
if isinstance(model, TapasForSequenceClassification):
|
||||||
if any(
|
if any(
|
||||||
n
|
n
|
||||||
in [
|
in [
|
||||||
"output_bias",
|
"output_bias",
|
||||||
"output_weights",
|
"output_weights",
|
||||||
]
|
]
|
||||||
for n in name
|
for n in name
|
||||||
):
|
):
|
||||||
logger.info("Skipping {}".format("/".join(name)))
|
logger.info("Skipping {}".format("/".join(name)))
|
||||||
continue
|
continue
|
||||||
# if first scope name starts with "bert", change it to "tapas"
|
# if first scope name starts with "bert", change it to "tapas"
|
||||||
if name[0] == "bert":
|
if name[0] == "bert":
|
||||||
name[0] = "tapas"
|
name[0] = "tapas"
|
||||||
@@ -233,8 +232,8 @@ def load_tf_weights_in_tapas(model, config, tf_checkpoint_path):
|
|||||||
|
|
||||||
class TapasEmbeddings(nn.Module):
|
class TapasEmbeddings(nn.Module):
|
||||||
"""
|
"""
|
||||||
Construct the embeddings from word, position and token_type embeddings.
|
Construct the embeddings from word, position and token_type embeddings. Same as BertEmbeddings but with a number of
|
||||||
Same as BertEmbeddings but with a number of additional token type embeddings to encode tabular structure.
|
additional token type embeddings to encode tabular structure.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
@@ -632,8 +631,9 @@ class TapasPooler(nn.Module):
|
|||||||
|
|
||||||
|
|
||||||
class TapasPreTrainedModel(PreTrainedModel):
|
class TapasPreTrainedModel(PreTrainedModel):
|
||||||
"""An abstract class to handle weights initialization and
|
"""
|
||||||
a simple interface for downloading and loading pretrained models.
|
An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained
|
||||||
|
models.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
config_class = TapasConfig
|
config_class = TapasConfig
|
||||||
@@ -658,42 +658,40 @@ TAPAS_START_DOCSTRING = r"""
|
|||||||
methods the library implements for all its models (such as downloading or saving, resizing the input embeddings,
|
methods the library implements for all its models (such as downloading or saving, resizing the input embeddings,
|
||||||
pruning heads etc.)
|
pruning heads etc.)
|
||||||
|
|
||||||
This model is also a PyTorch `torch.nn.Module <https://pytorch.org/docs/stable/nn.html#torch.nn.Module>`__ subclass.
|
This model is also a PyTorch `torch.nn.Module <https://pytorch.org/docs/stable/nn.html#torch.nn.Module>`__
|
||||||
Use it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general
|
subclass. Use it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to
|
||||||
usage and behavior.
|
general usage and behavior.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
config (:class:`~transformers.TapasConfig`): Model configuration class with all the parameters of the model.
|
config (:class:`~transformers.TapasConfig`): 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.
|
Initializing with a config file does not load the weights associated with the model, only the
|
||||||
Check out the :meth:`~transformers.PreTrainedModel.from_pretrained` method to load the model weights.
|
configuration. Check out the :meth:`~transformers.PreTrainedModel.from_pretrained` method to load the model
|
||||||
|
weights.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
TAPAS_INPUTS_DOCSTRING = r"""
|
TAPAS_INPUTS_DOCSTRING = r"""
|
||||||
Args:
|
Args:
|
||||||
input_ids (:obj:`torch.LongTensor` of shape :obj:`({0})`):
|
input_ids (:obj:`torch.LongTensor` of shape :obj:`({0})`):
|
||||||
Indices of input sequence tokens in the vocabulary.
|
Indices of input sequence tokens in the vocabulary. Indices can be obtained using
|
||||||
Indices can be obtained using :class:`~transformers.TapasTokenizer`.
|
:class:`~transformers.TapasTokenizer`. See :meth:`transformers.PreTrainedTokenizer.encode` and
|
||||||
See :meth:`transformers.PreTrainedTokenizer.encode` and
|
:meth:`transformers.PreTrainedTokenizer.__call__` for details. `What are input IDs?
|
||||||
:meth:`transformers.PreTrainedTokenizer.__call__` for details.
|
<../glossary.html#input-ids>`__
|
||||||
`What are input IDs? <../glossary.html#input-ids>`__
|
|
||||||
attention_mask (:obj:`torch.FloatTensor` of shape :obj:`({0})`, `optional`):
|
attention_mask (:obj:`torch.FloatTensor` of shape :obj:`({0})`, `optional`):
|
||||||
Mask to avoid performing attention on padding token indices.
|
Mask to avoid performing attention on padding token indices. Mask values selected in ``[0, 1]``: - 1 for
|
||||||
Mask values selected in ``[0, 1]``:
|
tokens that are **not masked**, - 0 for tokens that are **masked**. `What are attention masks?
|
||||||
- 1 for tokens that are **not masked**,
|
<../glossary.html#attention-mask>`__
|
||||||
- 0 for tokens that are **masked**.
|
|
||||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
|
||||||
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`({0}, 7)`, `optional`):
|
token_type_ids (:obj:`torch.LongTensor` of shape :obj:`({0}, 7)`, `optional`):
|
||||||
Token indices that encode tabular structure. Indices can be obtained using :class:`~transformers.TapasTokenizer`. See this class for more info.
|
Token indices that encode tabular structure. Indices can be obtained using
|
||||||
`What are token type IDs? <../glossary.html#token-type-ids>`_
|
:class:`~transformers.TapasTokenizer`. See this class for more info. `What are token type IDs?
|
||||||
|
<../glossary.html#token-type-ids>`_
|
||||||
position_ids (:obj:`torch.LongTensor` of shape :obj:`({0})`, `optional`):
|
position_ids (:obj:`torch.LongTensor` of shape :obj:`({0})`, `optional`):
|
||||||
Indices of positions of each input sequence tokens in the position embeddings. If ``reset_position_index_per_cell`` of :class:`~transformers.TapasConfig` is set to ``True``, relative position embeddings will be used.
|
Indices of positions of each input sequence tokens in the position embeddings. If
|
||||||
Selected in the range ``[0, config.max_position_embeddings - 1]``.
|
``reset_position_index_per_cell`` of :class:`~transformers.TapasConfig` is set to ``True``, relative
|
||||||
`What are position IDs? <../glossary.html#position-ids>`_
|
position embeddings will be used. Selected in the range ``[0, config.max_position_embeddings - 1]``. `What
|
||||||
|
are position IDs? <../glossary.html#position-ids>`_
|
||||||
head_mask (:obj:`torch.FloatTensor` of shape :obj:`(num_heads,)` or :obj:`(num_layers, num_heads)`, `optional`):
|
head_mask (:obj:`torch.FloatTensor` of shape :obj:`(num_heads,)` or :obj:`(num_layers, num_heads)`, `optional`):
|
||||||
Mask to nullify selected heads of the self-attention modules.
|
Mask to nullify selected heads of the self-attention modules. Mask values selected in ``[0, 1]``: - 1
|
||||||
Mask values selected in ``[0, 1]``:
|
indicates the head is **not masked**, - 0 indicates the head is **masked**.
|
||||||
- 1 indicates the head is **not masked**,
|
|
||||||
- 0 indicates the head is **masked**.
|
|
||||||
inputs_embeds (:obj:`torch.FloatTensor` of shape :obj:`({0}, hidden_size)`, `optional`):
|
inputs_embeds (:obj:`torch.FloatTensor` of shape :obj:`({0}, hidden_size)`, `optional`):
|
||||||
Optionally, instead of passing :obj:`input_ids` you can choose to directly pass an embedded representation.
|
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 :obj:`input_ids` indices into associated
|
This is useful if you want more control over how to convert :obj:`input_ids` indices into associated
|
||||||
@@ -715,19 +713,18 @@ TAPAS_INPUTS_DOCSTRING = r"""
|
|||||||
)
|
)
|
||||||
class TapasModel(TapasPreTrainedModel):
|
class TapasModel(TapasPreTrainedModel):
|
||||||
"""
|
"""
|
||||||
This class is a small change compared to :class:`~transformers.BertModel`, taking into account the additional token type ids.
|
This class is a small change compared to :class:`~transformers.BertModel`, taking into account the additional token
|
||||||
|
type ids.
|
||||||
|
|
||||||
The model can behave as an encoder (with only self-attention) as well
|
The model can behave as an encoder (with only self-attention) as well as a decoder, in which case a layer of
|
||||||
as a decoder, in which case a layer of cross-attention is added between
|
cross-attention is added between the self-attention layers, following the architecture described in `Attention is
|
||||||
the self-attention layers, following the architecture described in `Attention is all you need
|
all you need <https://arxiv.org/abs/1706.03762>`__ by Ashish Vaswani, Noam Shazeer, Niki Parmar, Jakob Uszkoreit,
|
||||||
<https://arxiv.org/abs/1706.03762>`__ by Ashish Vaswani, Noam Shazeer, Niki Parmar, Jakob Uszkoreit, Llion Jones,
|
Llion Jones, Aidan N. Gomez, Lukasz Kaiser and Illia Polosukhin.
|
||||||
Aidan N. Gomez, Lukasz Kaiser and Illia Polosukhin.
|
|
||||||
|
|
||||||
To behave as an decoder the model needs to be initialized with the
|
To behave as an decoder the model needs to be initialized with the :obj:`is_decoder` argument of the configuration
|
||||||
:obj:`is_decoder` argument of the configuration set to :obj:`True`.
|
set to :obj:`True`. To be used in a Seq2Seq model, the model needs to initialized with both :obj:`is_decoder`
|
||||||
To be used in a Seq2Seq model, the model needs to initialized with both :obj:`is_decoder`
|
argument and :obj:`add_cross_attention` set to :obj:`True`; an :obj:`encoder_hidden_states` is then expected as an
|
||||||
argument and :obj:`add_cross_attention` set to :obj:`True`; an
|
input to the forward pass.
|
||||||
:obj:`encoder_hidden_states` is then expected as an input to the forward pass.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
config_class = TapasConfig
|
config_class = TapasConfig
|
||||||
@@ -751,9 +748,9 @@ class TapasModel(TapasPreTrainedModel):
|
|||||||
self.embeddings.word_embeddings = value
|
self.embeddings.word_embeddings = value
|
||||||
|
|
||||||
def _prune_heads(self, heads_to_prune):
|
def _prune_heads(self, heads_to_prune):
|
||||||
"""Prunes heads of the model.
|
"""
|
||||||
heads_to_prune: dict of {layer_num: list of heads to prune in this layer}
|
Prunes heads of the model. heads_to_prune: dict of {layer_num: list of heads to prune in this layer} See base
|
||||||
See base class PreTrainedModel
|
class PreTrainedModel
|
||||||
"""
|
"""
|
||||||
for layer, heads in heads_to_prune.items():
|
for layer, heads in heads_to_prune.items():
|
||||||
self.encoder.layer[layer].attention.prune_heads(heads)
|
self.encoder.layer[layer].attention.prune_heads(heads)
|
||||||
@@ -903,10 +900,9 @@ class TapasForMaskedLM(TapasPreTrainedModel):
|
|||||||
):
|
):
|
||||||
r"""
|
r"""
|
||||||
labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`):
|
||||||
Labels for computing the masked language modeling loss.
|
Labels for computing the masked language modeling loss. Indices should be in ``[-100, 0, ...,
|
||||||
Indices should be in ``[-100, 0, ..., config.vocab_size]`` (see ``input_ids`` docstring)
|
config.vocab_size]`` (see ``input_ids`` docstring) Tokens with indices set to ``-100`` are ignored
|
||||||
Tokens with indices set to ``-100`` are ignored (masked), the loss is only computed for the tokens with labels
|
(masked), the loss is only computed for the tokens with labels in ``[0, ..., config.vocab_size]``
|
||||||
in ``[0, ..., config.vocab_size]``
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
@@ -923,7 +919,7 @@ class TapasForMaskedLM(TapasPreTrainedModel):
|
|||||||
|
|
||||||
>>> inputs = tokenizer(table, "How many [MASK] has George [MASK] played in?", return_tensors="pt")
|
>>> inputs = tokenizer(table, "How many [MASK] has George [MASK] played in?", return_tensors="pt")
|
||||||
>>> labels = tokenizer(table, "How many movies has George Clooney played in?", return_tensors="pt")["input_ids"]
|
>>> labels = tokenizer(table, "How many movies has George Clooney played in?", return_tensors="pt")["input_ids"]
|
||||||
|
|
||||||
>>> outputs = model(**inputs, labels=labels)
|
>>> outputs = model(**inputs, labels=labels)
|
||||||
>>> last_hidden_states = outputs.last_hidden_state
|
>>> last_hidden_states = outputs.last_hidden_state
|
||||||
"""
|
"""
|
||||||
@@ -989,8 +985,11 @@ class TapasLMHead(nn.Module):
|
|||||||
|
|
||||||
|
|
||||||
@add_start_docstrings(
|
@add_start_docstrings(
|
||||||
"""Tapas Model with a cell selection head and optionally aggregation head on top for question-answering
|
"""
|
||||||
tasks on tables (linear layers on top of the hidden-states output to compute `logits` and optionally `logits_aggregation`), e.g. for SQA, WTQ or WikiSQL tasks. """,
|
Tapas Model with a cell selection head and optionally aggregation head on top for question-answering tasks on
|
||||||
|
tables (linear layers on top of the hidden-states output to compute `logits` and optionally `logits_aggregation`),
|
||||||
|
e.g. for SQA, WTQ or WikiSQL tasks.
|
||||||
|
""",
|
||||||
TAPAS_START_DOCSTRING,
|
TAPAS_START_DOCSTRING,
|
||||||
)
|
)
|
||||||
class TapasForQuestionAnswering(TapasPreTrainedModel):
|
class TapasForQuestionAnswering(TapasPreTrainedModel):
|
||||||
@@ -1049,27 +1048,29 @@ class TapasForQuestionAnswering(TapasPreTrainedModel):
|
|||||||
):
|
):
|
||||||
r"""
|
r"""
|
||||||
table_mask (:obj:`torch.LongTensor` of shape :obj:`(batch_size, seq_length)`, `optional`):
|
table_mask (:obj:`torch.LongTensor` of shape :obj:`(batch_size, seq_length)`, `optional`):
|
||||||
Mask for the table. Indicates which tokens belong to the table (1). Question tokens, table headers and padding are 0.
|
Mask for the table. Indicates which tokens belong to the table (1). Question tokens, table headers and
|
||||||
|
padding are 0.
|
||||||
label_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, seq_length)`, `optional`):
|
label_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, seq_length)`, `optional`):
|
||||||
Labels per token for computing the hierarchical cell selection loss. This encodes the positions of the answer appearing in the table. Can be obtained using :class:`~transformers.TapasTokenizer`.
|
Labels per token for computing the hierarchical cell selection loss. This encodes the positions of the
|
||||||
- 1 for tokens that are **part of the answer**,
|
answer appearing in the table. Can be obtained using :class:`~transformers.TapasTokenizer`. - 1 for tokens
|
||||||
- 0 for tokens that are **not part of the answer**.
|
that are **part of the answer**, - 0 for tokens that are **not part of the answer**.
|
||||||
aggregation_labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size, )`, `optional`):
|
aggregation_labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size, )`, `optional`):
|
||||||
Aggregation function index for every example in the batch for computing the aggregation loss.
|
Aggregation function index for every example in the batch for computing the aggregation loss. Indices
|
||||||
Indices should be in :obj:`[0, ..., config.num_aggregation_labels - 1]`.
|
should be in :obj:`[0, ..., config.num_aggregation_labels - 1]`. Only required in case of strong
|
||||||
Only required in case of strong supervision for aggregation (WikiSQL-SUPERVISED).
|
supervision for aggregation (WikiSQL-SUPERVISED).
|
||||||
answer (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, )`, `optional`):
|
answer (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, )`, `optional`):
|
||||||
Answer for every example in the batch. NaN if there is no scalar answer.
|
Answer for every example in the batch. NaN if there is no scalar answer. Only required in case of weak
|
||||||
Only required in case of weak supervision (WTQ, WikiSQL) to calculate the aggregate mask and regression loss.
|
supervision (WTQ, WikiSQL) to calculate the aggregate mask and regression loss.
|
||||||
numeric_values (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, seq_length)`, `optional`):
|
numeric_values (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, seq_length)`, `optional`):
|
||||||
Numeric values of every token, NaN for tokens which are not numeric values. Can be obtained using :class:`~transformers.TapasTokenizer`.
|
Numeric values of every token, NaN for tokens which are not numeric values. Can be obtained using
|
||||||
Only required in case of weak supervision for aggregation (WTQ, WikiSQL) to calculate the regression loss.
|
:class:`~transformers.TapasTokenizer`. Only required in case of weak supervision for aggregation (WTQ,
|
||||||
|
WikiSQL) to calculate the regression loss.
|
||||||
numeric_values_scale (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, seq_length)`, `optional`):
|
numeric_values_scale (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, seq_length)`, `optional`):
|
||||||
Scale of the numeric values of every token. Can be obtained using :class:`~transformers.TapasTokenizer`.
|
Scale of the numeric values of every token. Can be obtained using :class:`~transformers.TapasTokenizer`.
|
||||||
Only required in case of weak supervision for aggregation (WTQ, WikiSQL) to calculate the regression loss.
|
Only required in case of weak supervision for aggregation (WTQ, WikiSQL) to calculate the regression loss.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
Examples::
|
Examples::
|
||||||
|
|
||||||
>>> from transformers import TapasTokenizer, TapasForQuestionAnswering
|
>>> from transformers import TapasTokenizer, TapasForQuestionAnswering
|
||||||
@@ -1160,9 +1161,7 @@ class TapasForQuestionAnswering(TapasPreTrainedModel):
|
|||||||
cell_mask, _ = reduce_mean(input_mask_float, cell_index)
|
cell_mask, _ = reduce_mean(input_mask_float, cell_index)
|
||||||
|
|
||||||
# Compute logits per token. These are used to select individual cells.
|
# Compute logits per token. These are used to select individual cells.
|
||||||
logits = compute_token_logits(
|
logits = compute_token_logits(sequence_output, self.config.temperature, self.output_weights, self.output_bias)
|
||||||
sequence_output, self.config.temperature, self.output_weights, self.output_bias
|
|
||||||
)
|
|
||||||
|
|
||||||
# Compute logits per column. These are used to select a column.
|
# Compute logits per column. These are used to select a column.
|
||||||
column_logits = None
|
column_logits = None
|
||||||
@@ -1208,7 +1207,7 @@ class TapasForQuestionAnswering(TapasPreTrainedModel):
|
|||||||
pooled_output,
|
pooled_output,
|
||||||
self.config.cell_selection_preference,
|
self.config.cell_selection_preference,
|
||||||
label_ids,
|
label_ids,
|
||||||
self.aggregation_classifier
|
self.aggregation_classifier,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError("You have to specify answers in order to calculate the aggregate mask")
|
raise ValueError("You have to specify answers in order to calculate the aggregate mask")
|
||||||
@@ -1262,13 +1261,15 @@ class TapasForQuestionAnswering(TapasPreTrainedModel):
|
|||||||
logits_aggregation, aggregate_mask, aggregation_labels, self.config
|
logits_aggregation, aggregate_mask, aggregation_labels, self.config
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError("You have to specify aggregation labels in order to calculate the aggregation loss")
|
raise ValueError(
|
||||||
|
"You have to specify aggregation labels in order to calculate the aggregation loss"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# Set aggregation labels to zeros
|
# Set aggregation labels to zeros
|
||||||
aggregation_labels = torch.zeros(label_ids.shape[0], dtype=torch.long, device=label_ids.device)
|
aggregation_labels = torch.zeros(label_ids.shape[0], dtype=torch.long, device=label_ids.device)
|
||||||
per_example_additional_loss = _calculate_aggregation_loss(
|
per_example_additional_loss = _calculate_aggregation_loss(
|
||||||
logits_aggregation, aggregate_mask, aggregation_labels, self.config
|
logits_aggregation, aggregate_mask, aggregation_labels, self.config
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.config.use_answer_as_supervision:
|
if self.config.use_answer_as_supervision:
|
||||||
if numeric_values is not None and numeric_values_scale is not None:
|
if numeric_values is not None and numeric_values_scale is not None:
|
||||||
@@ -1288,7 +1289,9 @@ class TapasForQuestionAnswering(TapasPreTrainedModel):
|
|||||||
# Zero loss for examples with answer_loss > cutoff.
|
# Zero loss for examples with answer_loss > cutoff.
|
||||||
per_example_additional_loss *= large_answer_loss_mask
|
per_example_additional_loss *= large_answer_loss_mask
|
||||||
else:
|
else:
|
||||||
raise ValueError("You have to specify numeric values and numeric values scale in order to calculate the regression loss")
|
raise ValueError(
|
||||||
|
"You have to specify numeric values and numeric values scale in order to calculate the regression loss"
|
||||||
|
)
|
||||||
|
|
||||||
total_loss += torch.mean(per_example_additional_loss)
|
total_loss += torch.mean(per_example_additional_loss)
|
||||||
|
|
||||||
@@ -1310,9 +1313,12 @@ class TapasForQuestionAnswering(TapasPreTrainedModel):
|
|||||||
attentions=outputs.attentions,
|
attentions=outputs.attentions,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@add_start_docstrings(
|
@add_start_docstrings(
|
||||||
"""Tapas Model with a sequence classification head on top (a linear layer on top of
|
"""
|
||||||
the pooled output), e.g. for TabFact (Chen et al., 2020). """,
|
Tapas Model with a sequence classification head on top (a linear layer on top of the pooled output), e.g. for
|
||||||
|
TabFact (Chen et al., 2020).
|
||||||
|
""",
|
||||||
TAPAS_START_DOCSTRING,
|
TAPAS_START_DOCSTRING,
|
||||||
)
|
)
|
||||||
class TapasForSequenceClassification(TapasPreTrainedModel):
|
class TapasForSequenceClassification(TapasPreTrainedModel):
|
||||||
@@ -1343,14 +1349,13 @@ class TapasForSequenceClassification(TapasPreTrainedModel):
|
|||||||
):
|
):
|
||||||
r"""
|
r"""
|
||||||
labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size,)`, `optional`):
|
labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size,)`, `optional`):
|
||||||
Labels for computing the sequence classification/regression loss.
|
Labels for computing the sequence classification/regression loss. Indices should be in :obj:`[0, ...,
|
||||||
Indices should be in :obj:`[0, ..., config.num_labels - 1]`.
|
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 regression loss is computed (Mean-Square loss),
|
If :obj:`config.num_labels > 1` a classification loss is computed (Cross-Entropy). Note: this is called
|
||||||
If :obj:`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
"classification_class_index" in the original implementation.
|
||||||
Note: this is called "classification_class_index" in the original implementation.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
Examples::
|
Examples::
|
||||||
|
|
||||||
>>> from transformers import TapasTokenizer, TapasForSequenceClassification
|
>>> from transformers import TapasTokenizer, TapasForSequenceClassification
|
||||||
@@ -1366,13 +1371,13 @@ class TapasForSequenceClassification(TapasPreTrainedModel):
|
|||||||
|
|
||||||
>>> inputs = tokenizer(table, queries, return_tensors="pt")
|
>>> inputs = tokenizer(table, queries, return_tensors="pt")
|
||||||
>>> labels = torch.tensor([1, 0]) # 1 means entailed, 0 means refuted
|
>>> labels = torch.tensor([1, 0]) # 1 means entailed, 0 means refuted
|
||||||
|
|
||||||
>>> outputs = model(**inputs, labels=labels)
|
>>> outputs = model(**inputs, labels=labels)
|
||||||
>>> loss = outputs.loss
|
>>> loss = outputs.loss
|
||||||
>>> logits = outputs.logits
|
>>> logits = outputs.logits
|
||||||
"""
|
"""
|
||||||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||||||
|
|
||||||
outputs = self.tapas(
|
outputs = self.tapas(
|
||||||
input_ids,
|
input_ids,
|
||||||
attention_mask=attention_mask,
|
attention_mask=attention_mask,
|
||||||
@@ -1411,8 +1416,10 @@ class TapasForSequenceClassification(TapasPreTrainedModel):
|
|||||||
attentions=outputs.attentions,
|
attentions=outputs.attentions,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
""" TAPAS utilities."""
|
""" TAPAS utilities."""
|
||||||
|
|
||||||
|
|
||||||
class AverageApproximationFunction(str, enum.Enum):
|
class AverageApproximationFunction(str, enum.Enum):
|
||||||
RATIO = "ratio"
|
RATIO = "ratio"
|
||||||
FIRST_ORDER = "first_order"
|
FIRST_ORDER = "first_order"
|
||||||
@@ -1426,17 +1433,19 @@ class IndexMap(object):
|
|||||||
"""Index grouping entries within a tensor."""
|
"""Index grouping entries within a tensor."""
|
||||||
|
|
||||||
def __init__(self, indices, num_segments, batch_dims=0):
|
def __init__(self, indices, num_segments, batch_dims=0):
|
||||||
"""Creates an index.
|
"""
|
||||||
|
Creates an index
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
indices (:obj:`torch.LongTensor`, same shape as `values`):
|
indices (:obj:`torch.LongTensor`, same shape as `values`):
|
||||||
Tensor containing the indices.
|
Tensor containing the indices.
|
||||||
num_segments (:obj:`torch.LongTensor`):
|
num_segments (:obj:`torch.LongTensor`):
|
||||||
Scalar tensor, the number of segments. All elements in a batched segmented tensor
|
Scalar tensor, the number of segments. All elements in a batched segmented tensor must have the same
|
||||||
must have the same number of segments (although many segments can be empty).
|
number of segments (although many segments can be empty).
|
||||||
batch_dims (:obj:`int`, `optional`, defaults to 0):
|
batch_dims (:obj:`int`, `optional`, defaults to 0):
|
||||||
The number of batch dimensions. The first `batch_dims` dimensions of a SegmentedTensor
|
The number of batch dimensions. The first `batch_dims` dimensions of a SegmentedTensor are treated as
|
||||||
are treated as batch dimensions. Segments in different batch elements are always distinct
|
batch dimensions. Segments in different batch elements are always distinct even if they have the same
|
||||||
even if they have the same index.
|
index.
|
||||||
"""
|
"""
|
||||||
self.indices = torch.as_tensor(indices)
|
self.indices = torch.as_tensor(indices)
|
||||||
self.num_segments = torch.as_tensor(num_segments, device=indices.device)
|
self.num_segments = torch.as_tensor(num_segments, device=indices.device)
|
||||||
@@ -1450,14 +1459,13 @@ class ProductIndexMap(IndexMap):
|
|||||||
"""The product of two indices."""
|
"""The product of two indices."""
|
||||||
|
|
||||||
def __init__(self, outer_index, inner_index):
|
def __init__(self, outer_index, inner_index):
|
||||||
"""Combines indices i and j into pairs (i, j).
|
"""
|
||||||
The result is an index where each segment (i, j) is the intersection of
|
Combines indices i and j into pairs (i, j). The result is an index where each segment (i, j) is the
|
||||||
segments i and j. For example if the inputs represent table cells indexed by
|
intersection of segments i and j. For example if the inputs represent table cells indexed by respectively rows
|
||||||
respectively rows and columns the output will be a table indexed by
|
and columns the output will be a table indexed by (row, column) pairs, i.e. by cell. The implementation
|
||||||
(row, column) pairs, i.e. by cell.
|
combines indices {0, .., n - 1} and {0, .., m - 1} into {0, .., nm - 1}. The output has `num_segments` equal to
|
||||||
The implementation combines indices {0, .., n - 1} and {0, .., m - 1} into
|
`outer_index.num_segments` * `inner_index.num_segments`
|
||||||
{0, .., nm - 1}. The output has `num_segments` equal to
|
|
||||||
`outer_index.num_segments` * `inner_index.num_segments`.
|
|
||||||
Args:
|
Args:
|
||||||
outer_index (:obj:`IndexMap`):
|
outer_index (:obj:`IndexMap`):
|
||||||
IndexMap.
|
IndexMap.
|
||||||
@@ -1496,17 +1504,18 @@ class ProductIndexMap(IndexMap):
|
|||||||
|
|
||||||
|
|
||||||
def gather(values, index, name="segmented_gather"):
|
def gather(values, index, name="segmented_gather"):
|
||||||
"""Gathers from `values` using the index map.
|
"""
|
||||||
For each element in the domain of the index map this operation looks up a
|
Gathers from `values` using the index map. For each element in the domain of the index map this operation looks up
|
||||||
value for that index in `values`. Two elements from the same segment always
|
a value for that index in `values`. Two elements from the same segment always get assigned the same value
|
||||||
get assigned the same value.
|
|
||||||
Args:
|
Args:
|
||||||
values (:obj:`torch.Tensor` of shape (B1, ..., Bn, num_segments, V1, ...)):
|
values (:obj:`torch.Tensor` of shape (B1, ..., Bn, num_segments, V1, ...)):
|
||||||
Tensor with segment values.
|
Tensor with segment values.
|
||||||
index (:obj:`IndexMap` of shape (B1, ..., Bn, I1, ..., Ik)):
|
index (:obj:`IndexMap` of shape (B1, ..., Bn, I1, ..., Ik)):
|
||||||
IndexMap.
|
IndexMap.
|
||||||
name (:obj:`str`, `optional`, defaults to 'segmented_gather'):
|
name (:obj:`str`, `optional`, defaults to 'segmented_gather'):
|
||||||
Name for the operation. Currently not used.
|
Name for the operation. Currently not used
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
:obj:`tuple(torch.Tensor)`: Tensor of shape (B1, ..., Bn, I1, ..., Ik, V1, ...) with the gathered values.
|
:obj:`tuple(torch.Tensor)`: Tensor of shape (B1, ..., Bn, I1, ..., Ik, V1, ...) with the gathered values.
|
||||||
"""
|
"""
|
||||||
@@ -1528,16 +1537,18 @@ def gather(values, index, name="segmented_gather"):
|
|||||||
|
|
||||||
|
|
||||||
def flatten(index, name="segmented_flatten"):
|
def flatten(index, name="segmented_flatten"):
|
||||||
"""Flattens a batched index map (which is typically of shape batch_size, seq_length) to a 1d index map.
|
"""
|
||||||
This operation relabels the segments to keep batch elements distinct. The k-th
|
Flattens a batched index map (which is typically of shape batch_size, seq_length) to a 1d index map. This operation
|
||||||
batch element will have indices shifted by `num_segments` * (k - 1). The
|
relabels the segments to keep batch elements distinct. The k-th batch element will have indices shifted by
|
||||||
result is a tensor with `num_segments` multiplied by the number of elements
|
`num_segments` * (k - 1). The result is a tensor with `num_segments` multiplied by the number of elements in the
|
||||||
in the batch.
|
batch
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
index (:obj:`IndexMap`):
|
index (:obj:`IndexMap`):
|
||||||
IndexMap to flatten.
|
IndexMap to flatten.
|
||||||
name (:obj:`str`, `optional`, defaults to 'segmented_flatten'):
|
name (:obj:`str`, `optional`, defaults to 'segmented_flatten'):
|
||||||
Name for the operation. Currently not used.
|
Name for the operation. Currently not used
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
(:obj:`IndexMap`): The flattened IndexMap.
|
(:obj:`IndexMap`): The flattened IndexMap.
|
||||||
"""
|
"""
|
||||||
@@ -1555,14 +1566,17 @@ def flatten(index, name="segmented_flatten"):
|
|||||||
|
|
||||||
|
|
||||||
def range_index_map(batch_shape, num_segments, name="range_index_map"):
|
def range_index_map(batch_shape, num_segments, name="range_index_map"):
|
||||||
"""Constructs an index map equal to range(num_segments).
|
"""
|
||||||
|
Constructs an index map equal to range(num_segments)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
batch_shape (:obj:`torch.Size`):
|
batch_shape (:obj:`torch.Size`):
|
||||||
Batch shape
|
Batch shape
|
||||||
num_segments (:obj:`int`):
|
num_segments (:obj:`int`):
|
||||||
Number of segments
|
Number of segments
|
||||||
name (:obj:`str`, `optional`, defaults to 'range_index_map'):
|
name (:obj:`str`, `optional`, defaults to 'range_index_map'):
|
||||||
Name for the operation. Currently not used.
|
Name for the operation. Currently not used
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
(:obj:`IndexMap`): IndexMap of shape batch_shape with elements equal to range(num_segments).
|
(:obj:`IndexMap`): IndexMap of shape batch_shape with elements equal to range(num_segments).
|
||||||
"""
|
"""
|
||||||
@@ -1593,7 +1607,9 @@ def range_index_map(batch_shape, num_segments, name="range_index_map"):
|
|||||||
|
|
||||||
|
|
||||||
def _segment_reduce(values, index, segment_reduce_fn, name):
|
def _segment_reduce(values, index, segment_reduce_fn, name):
|
||||||
"""Applies a segment reduction segment-wise.
|
"""
|
||||||
|
Applies a segment reduction segment-wise
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
values (:obj:`torch.Tensor`):
|
values (:obj:`torch.Tensor`):
|
||||||
Tensor with segment values.
|
Tensor with segment values.
|
||||||
@@ -1602,7 +1618,8 @@ def _segment_reduce(values, index, segment_reduce_fn, name):
|
|||||||
segment_reduce_fn (:obj:`str`):
|
segment_reduce_fn (:obj:`str`):
|
||||||
Name for the reduce operation. One of "sum", "mean", "max" or "min".
|
Name for the reduce operation. One of "sum", "mean", "max" or "min".
|
||||||
name (:obj:`str`):
|
name (:obj:`str`):
|
||||||
Name for the operation. Currently not used.
|
Name for the operation. Currently not used
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
(:obj:`IndexMap`): IndexMap of shape batch_shape with elements equal to range(num_segments).
|
(:obj:`IndexMap`): IndexMap of shape batch_shape with elements equal to range(num_segments).
|
||||||
"""
|
"""
|
||||||
@@ -1641,99 +1658,99 @@ def _segment_reduce(values, index, segment_reduce_fn, name):
|
|||||||
|
|
||||||
|
|
||||||
def reduce_sum(values, index, name="segmented_reduce_sum"):
|
def reduce_sum(values, index, name="segmented_reduce_sum"):
|
||||||
"""Sums a tensor over its segments.
|
"""
|
||||||
Outputs 0 for empty segments.
|
Sums a tensor over its segments. Outputs 0 for empty segments. This operations computes the sum over segments, with
|
||||||
This operations computes the sum over segments, with support for:
|
support for:
|
||||||
|
|
||||||
- Batching using the first dimensions [B1, B2, ..., Bn]. Each element in
|
- Batching using the first dimensions [B1, B2, ..., Bn]. Each element in
|
||||||
a batch can have different indices.
|
a batch can have different indices. - Vectorization using the last dimension [V1, V2, ...]. If they are present
|
||||||
- Vectorization using the last dimension [V1, V2, ...]. If they are present
|
the output will be a sum of vectors rather than scalars. Only the middle dimensions [I1, ..., Ik] are reduced
|
||||||
the output will be a sum of vectors rather than scalars.
|
by the operation
|
||||||
Only the middle dimensions [I1, ..., Ik] are reduced by the operation.
|
|
||||||
Args:
|
Args:
|
||||||
values (:obj:`torch.Tensor` of shape [B1, B2, ..., Bn, I1, .., Ik, V1, V2, ..]):
|
values (:obj:`torch.Tensor` of shape [B1, B2, ..., Bn, I1, .., Ik, V1, V2, ..]):
|
||||||
Tensor containing the values of which the sum must be taken segment-wise.
|
Tensor containing the values of which the sum must be taken segment-wise.
|
||||||
index (:obj:`IndexMap`, indices are of shape [B1, B2, ..., Bn, I1, .., Ik].):
|
index (:obj:`IndexMap`, indices are of shape [B1, B2, ..., Bn, I1, .., Ik].):
|
||||||
Index defining the segments.
|
Index defining the segments.
|
||||||
name (:obj:`str`, `optional`, defaults to 'segmented_reduce_sum'):
|
name (:obj:`str`, `optional`, defaults to 'segmented_reduce_sum'):
|
||||||
Name for the operation. Currently not used.
|
Name for the operation. Currently not used
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
output_values (:obj:`torch.Tensor`of shape [B1, B2, ..., Bn, num_segments, V1, V2, ..]):
|
output_values (:obj:`torch.Tensor`of shape [B1, B2, ..., Bn, num_segments, V1, V2, ..]): Tensor containing the
|
||||||
Tensor containing the output values.
|
output values. output_index (:obj:`IndexMap`): IndexMap with shape [B1, B2, ..., Bn, num_segments]. .
|
||||||
output_index (:obj:`IndexMap`):
|
|
||||||
IndexMap with shape [B1, B2, ..., Bn, num_segments]. .
|
|
||||||
"""
|
"""
|
||||||
return _segment_reduce(values, index, "sum", name)
|
return _segment_reduce(values, index, "sum", name)
|
||||||
|
|
||||||
|
|
||||||
def reduce_mean(values, index, name="segmented_reduce_mean"):
|
def reduce_mean(values, index, name="segmented_reduce_mean"):
|
||||||
"""Averages a tensor over its segments.
|
"""
|
||||||
Outputs 0 for empty segments.
|
Averages a tensor over its segments. Outputs 0 for empty segments. This operations computes the mean over segments,
|
||||||
This operations computes the mean over segments, with support for:
|
with support for:
|
||||||
|
|
||||||
- Batching using the first dimensions [B1, B2, ..., Bn]. Each element in
|
- Batching using the first dimensions [B1, B2, ..., Bn]. Each element in
|
||||||
a batch can have different indices.
|
a batch can have different indices. - Vectorization using the last dimension [V1, V2, ...]. If they are present
|
||||||
- Vectorization using the last dimension [V1, V2, ...]. If they are present
|
the output will be a mean of vectors rather than scalars. Only the middle dimensions [I1, ..., Ik] are reduced
|
||||||
the output will be a mean of vectors rather than scalars.
|
by the operation
|
||||||
Only the middle dimensions [I1, ..., Ik] are reduced by the operation.
|
|
||||||
Args:
|
Args:
|
||||||
values (:obj:`torch.Tensor` of shape [B1, B2, ..., Bn, I1, .., Ik, V1, V2, ..]):
|
values (:obj:`torch.Tensor` of shape [B1, B2, ..., Bn, I1, .., Ik, V1, V2, ..]):
|
||||||
Tensor containing the values of which the mean must be taken segment-wise.
|
Tensor containing the values of which the mean must be taken segment-wise.
|
||||||
index (:obj:`IndexMap`, indices are of shape [B1, B2, ..., Bn, I1, .., Ik].):
|
index (:obj:`IndexMap`, indices are of shape [B1, B2, ..., Bn, I1, .., Ik].):
|
||||||
Index defining the segments.
|
Index defining the segments.
|
||||||
name (:obj:`str`, `optional`, defaults to 'segmented_reduce_sum'):
|
name (:obj:`str`, `optional`, defaults to 'segmented_reduce_sum'):
|
||||||
Name for the operation. Currently not used.
|
Name for the operation. Currently not used
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
output_values (:obj:`torch.Tensor`of shape [B1, B2, ..., Bn, num_segments, V1, V2, ..]):
|
output_values (:obj:`torch.Tensor`of shape [B1, B2, ..., Bn, num_segments, V1, V2, ..]): Tensor containing the
|
||||||
Tensor containing the output values.
|
output values. output_index (:obj:`IndexMap`): IndexMap with shape [B1, B2, ..., Bn, num_segments].
|
||||||
output_index (:obj:`IndexMap`):
|
|
||||||
IndexMap with shape [B1, B2, ..., Bn, num_segments].
|
|
||||||
"""
|
"""
|
||||||
return _segment_reduce(values, index, "mean", name)
|
return _segment_reduce(values, index, "mean", name)
|
||||||
|
|
||||||
|
|
||||||
def reduce_max(values, index, name="segmented_reduce_max"):
|
def reduce_max(values, index, name="segmented_reduce_max"):
|
||||||
"""Computes the maximum over segments.
|
"""
|
||||||
This operations computes the maximum over segments, with support for:
|
Computes the maximum over segments. This operations computes the maximum over segments, with support for:
|
||||||
|
|
||||||
- Batching using the first dimensions [B1, B2, ..., Bn]. Each element in
|
- Batching using the first dimensions [B1, B2, ..., Bn]. Each element in
|
||||||
a batch can have different indices.
|
a batch can have different indices. - Vectorization using the last dimension [V1, V2, ...]. If they are present
|
||||||
- Vectorization using the last dimension [V1, V2, ...]. If they are present
|
the output will be an element-wise maximum of vectors rather than scalars. Only the middle dimensions [I1, ...,
|
||||||
the output will be an element-wise maximum of vectors rather than scalars.
|
Ik] are reduced by the operation
|
||||||
Only the middle dimensions [I1, ..., Ik] are reduced by the operation.
|
|
||||||
Args:
|
Args:
|
||||||
values (:obj:`torch.Tensor` of shape [B1, B2, ..., Bn, I1, .., Ik, V1, V2, ..]):
|
values (:obj:`torch.Tensor` of shape [B1, B2, ..., Bn, I1, .., Ik, V1, V2, ..]):
|
||||||
Tensor containing the values of which the max must be taken segment-wise.
|
Tensor containing the values of which the max must be taken segment-wise.
|
||||||
index (:obj:`IndexMap`, indices are of shape [B1, B2, ..., Bn, I1, .., Ik].):
|
index (:obj:`IndexMap`, indices are of shape [B1, B2, ..., Bn, I1, .., Ik].):
|
||||||
Index defining the segments.
|
Index defining the segments.
|
||||||
name (:obj:`str`, `optional`, defaults to 'segmented_reduce_sum'):
|
name (:obj:`str`, `optional`, defaults to 'segmented_reduce_sum'):
|
||||||
Name for the operation. Currently not used.
|
Name for the operation. Currently not used
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
output_values (:obj:`torch.Tensor`of shape [B1, B2, ..., Bn, num_segments, V1, V2, ..]):
|
output_values (:obj:`torch.Tensor`of shape [B1, B2, ..., Bn, num_segments, V1, V2, ..]): Tensor containing the
|
||||||
Tensor containing the output values.
|
output values. output_index (:obj:`IndexMap`): IndexMap with shape [B1, B2, ..., Bn, num_segments].
|
||||||
output_index (:obj:`IndexMap`):
|
|
||||||
IndexMap with shape [B1, B2, ..., Bn, num_segments].
|
|
||||||
"""
|
"""
|
||||||
return _segment_reduce(values, index, "max", name)
|
return _segment_reduce(values, index, "max", name)
|
||||||
|
|
||||||
|
|
||||||
def reduce_min(values, index, name="segmented_reduce_min"):
|
def reduce_min(values, index, name="segmented_reduce_min"):
|
||||||
"""Computes the minimum over segments.
|
"""
|
||||||
This operations computes the maximum over segments, with support for:
|
Computes the minimum over segments. This operations computes the maximum over segments, with support for:
|
||||||
|
|
||||||
- Batching using the first dimensions [B1, B2, ..., Bn]. Each element in
|
- Batching using the first dimensions [B1, B2, ..., Bn]. Each element in
|
||||||
a batch can have different indices.
|
a batch can have different indices. - Vectorization using the last dimension [V1, V2, ...]. If they are present
|
||||||
- Vectorization using the last dimension [V1, V2, ...]. If they are present
|
the output will be an element-wise maximum of vectors rather than scalars. Only the middle dimensions [I1, ...,
|
||||||
the output will be an element-wise maximum of vectors rather than scalars.
|
Ik] are reduced by the operation
|
||||||
Only the middle dimensions [I1, ..., Ik] are reduced by the operation.
|
|
||||||
Args:
|
Args:
|
||||||
values (:obj:`torch.Tensor` of shape [B1, B2, ..., Bn, I1, .., Ik, V1, V2, ..]):
|
values (:obj:`torch.Tensor` of shape [B1, B2, ..., Bn, I1, .., Ik, V1, V2, ..]):
|
||||||
Tensor containing the values of which the min must be taken segment-wise.
|
Tensor containing the values of which the min must be taken segment-wise.
|
||||||
index (:obj:`IndexMap`, indices are of shape [B1, B2, ..., Bn, I1, .., Ik].):
|
index (:obj:`IndexMap`, indices are of shape [B1, B2, ..., Bn, I1, .., Ik].):
|
||||||
Index defining the segments.
|
Index defining the segments.
|
||||||
name (:obj:`str`, `optional`, defaults to 'segmented_reduce_sum'):
|
name (:obj:`str`, `optional`, defaults to 'segmented_reduce_sum'):
|
||||||
Name for the operation. Currently not used.
|
Name for the operation. Currently not used
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
output_values (:obj:`torch.Tensor`of shape [B1, B2, ..., Bn, num_segments, V1, V2, ..]):
|
output_values (:obj:`torch.Tensor`of shape [B1, B2, ..., Bn, num_segments, V1, V2, ..]): Tensor containing the
|
||||||
Tensor containing the output values.
|
output values. output_index (:obj:`IndexMap`): IndexMap with shape [B1, B2, ..., Bn, num_segments].
|
||||||
output_index (:obj:`IndexMap`):
|
|
||||||
IndexMap with shape [B1, B2, ..., Bn, num_segments].
|
|
||||||
"""
|
"""
|
||||||
return _segment_reduce(values, index, "min", name)
|
return _segment_reduce(values, index, "min", name)
|
||||||
|
|
||||||
@@ -1744,7 +1761,8 @@ def reduce_min(values, index, name="segmented_reduce_min"):
|
|||||||
def compute_column_logits(
|
def compute_column_logits(
|
||||||
sequence_output, column_output_weights, column_output_bias, cell_index, cell_mask, allow_empty_column_selection
|
sequence_output, column_output_weights, column_output_bias, cell_index, cell_mask, allow_empty_column_selection
|
||||||
):
|
):
|
||||||
"""Computes the column logits.
|
"""
|
||||||
|
Computes the column logits.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sequence_output (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`):
|
sequence_output (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`):
|
||||||
@@ -1758,10 +1776,11 @@ def compute_column_logits(
|
|||||||
cell_mask (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, max_num_rows * max_num_cols)`):
|
cell_mask (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, max_num_rows * max_num_cols)`):
|
||||||
Mask for cells that exist in the table (i.e. that are not padding).
|
Mask for cells that exist in the table (i.e. that are not padding).
|
||||||
allow_empty_column_selection (:obj:`bool`):
|
allow_empty_column_selection (:obj:`bool`):
|
||||||
Whether to allow not to select any column.
|
Whether to allow not to select any column
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
column_logits (:obj:`torch.FloatTensor`of shape :obj:`(batch_size, max_num_cols)`):
|
column_logits (:obj:`torch.FloatTensor`of shape :obj:`(batch_size, max_num_cols)`): Tensor containing the
|
||||||
Tensor containing the column logits for every example in the batch.
|
column logits for every example in the batch.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# First, compute the token logits (batch_size, seq_len) - without temperature
|
# First, compute the token logits (batch_size, seq_len) - without temperature
|
||||||
@@ -1792,10 +1811,10 @@ def compute_column_logits(
|
|||||||
|
|
||||||
|
|
||||||
def _single_column_cell_selection_loss(token_logits, column_logits, label_ids, cell_index, col_index, cell_mask):
|
def _single_column_cell_selection_loss(token_logits, column_logits, label_ids, cell_index, col_index, cell_mask):
|
||||||
"""Computes the loss for cell selection constrained to a single column.
|
"""
|
||||||
The loss is a hierarchical log-likelihood. The model first predicts a column
|
Computes the loss for cell selection constrained to a single column. The loss is a hierarchical log-likelihood. The
|
||||||
and then selects cells within that column (conditioned on the column). Cells
|
model first predicts a column and then selects cells within that column (conditioned on the column). Cells outside
|
||||||
outside the selected column are never selected.
|
the selected column are never selected.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
token_logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`):
|
token_logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`):
|
||||||
@@ -1812,11 +1831,10 @@ def _single_column_cell_selection_loss(token_logits, column_logits, label_ids, c
|
|||||||
Mask for cells that exist in the table (i.e. that are not padding).
|
Mask for cells that exist in the table (i.e. that are not padding).
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
selection_loss_per_example (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`):
|
selection_loss_per_example (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`): Loss for each example.
|
||||||
Loss for each example.
|
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`): New logits which are only
|
||||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`):
|
allowed to select cells in a single column. Logits outside of the most likely column according to
|
||||||
New logits which are only allowed to select cells in a single column. Logits outside of the most likely
|
`column_logits` will be set to a very low value (such that the probabilities are 0).
|
||||||
column according to `column_logits` will be set to a very low value (such that the probabilities are 0).
|
|
||||||
"""
|
"""
|
||||||
## Part 1: column loss
|
## Part 1: column loss
|
||||||
|
|
||||||
@@ -1903,7 +1921,9 @@ def _single_column_cell_selection_loss(token_logits, column_logits, label_ids, c
|
|||||||
|
|
||||||
|
|
||||||
def compute_token_logits(sequence_output, temperature, output_weights, output_bias):
|
def compute_token_logits(sequence_output, temperature, output_weights, output_bias):
|
||||||
"""Computes logits per token.
|
"""
|
||||||
|
Computes logits per token
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sequence_output (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`):
|
sequence_output (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`):
|
||||||
Also known as last_hidden_state. Sequence of hidden-states at the output of the last layer of the model.
|
Also known as last_hidden_state. Sequence of hidden-states at the output of the last layer of the model.
|
||||||
@@ -1912,10 +1932,10 @@ def compute_token_logits(sequence_output, temperature, output_weights, output_bi
|
|||||||
output_weights (:obj:`torch.FloatTensor` of shape :obj:`(hidden_size,)`):
|
output_weights (:obj:`torch.FloatTensor` of shape :obj:`(hidden_size,)`):
|
||||||
Weights of the linear layer for cell selection.
|
Weights of the linear layer for cell selection.
|
||||||
output_bias (:obj:`torch.FloatTensor` of shape :obj:`()`):
|
output_bias (:obj:`torch.FloatTensor` of shape :obj:`()`):
|
||||||
Bias of the linear layer for cell selection.
|
Bias of the linear layer for cell selection
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`):
|
logits (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`): Logits per token.
|
||||||
Logits per token.
|
|
||||||
"""
|
"""
|
||||||
logits = (torch.einsum("bsj,j->bs", sequence_output, output_weights) + output_bias) / temperature
|
logits = (torch.einsum("bsj,j->bs", sequence_output, output_weights) + output_bias) / temperature
|
||||||
|
|
||||||
@@ -1923,17 +1943,16 @@ def compute_token_logits(sequence_output, temperature, output_weights, output_bi
|
|||||||
|
|
||||||
|
|
||||||
def _calculate_aggregate_mask(answer, pooled_output, cell_selection_preference, label_ids, aggregation_classifier):
|
def _calculate_aggregate_mask(answer, pooled_output, cell_selection_preference, label_ids, aggregation_classifier):
|
||||||
"""Finds examples where the model should select cells with no aggregation.
|
"""
|
||||||
|
Finds examples where the model should select cells with no aggregation.
|
||||||
|
|
||||||
|
Returns a mask that determines for which examples should the model select answers directly from the table, without
|
||||||
|
any aggregation function. If the answer is a piece of text the case is unambiguous as aggregation functions only
|
||||||
|
apply to numbers. If the answer is a number but does not appear in the table then we must use some aggregation
|
||||||
|
case. The ambiguous case is when the answer is a number that also appears in the table. In this case we use the
|
||||||
|
aggregation function probabilities predicted by the model to decide whether to select or aggregate. The threshold
|
||||||
|
for this is a hyperparameter `cell_selection_preference
|
||||||
|
|
||||||
Returns a mask that determines for which examples should the model select
|
|
||||||
answers directly from the table, without any aggregation function. If the
|
|
||||||
answer is a piece of text the case is unambiguous as aggregation functions
|
|
||||||
only apply to numbers. If the answer is a number but does not appear in the
|
|
||||||
table then we must use some aggregation case. The ambiguous case is when the
|
|
||||||
answer is a number that also appears in the table. In this case we use the
|
|
||||||
aggregation function probabilities predicted by the model to decide whether
|
|
||||||
to select or aggregate. The threshold for this is a hyperparameter
|
|
||||||
`cell_selection_preference`
|
|
||||||
Args:
|
Args:
|
||||||
answer (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, )`):
|
answer (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, )`):
|
||||||
Answer for every example in the batch. Nan if there is no scalar answer.
|
Answer for every example in the batch. Nan if there is no scalar answer.
|
||||||
@@ -1942,12 +1961,11 @@ def _calculate_aggregate_mask(answer, pooled_output, cell_selection_preference,
|
|||||||
cell_selection_preference (:obj:`float`):
|
cell_selection_preference (:obj:`float`):
|
||||||
Preference for cell selection in ambiguous cases.
|
Preference for cell selection in ambiguous cases.
|
||||||
label_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`):
|
label_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`):
|
||||||
Labels per token.
|
Labels per token. aggregation_classifier (:obj:`torch.nn.Linear`): Aggregation head
|
||||||
aggregation_classifier (:obj:`torch.nn.Linear`):
|
|
||||||
Aggregation head.
|
|
||||||
Returns:
|
Returns:
|
||||||
aggregate_mask (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`):
|
aggregate_mask (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`): A mask set to 1 for examples that
|
||||||
A mask set to 1 for examples that should use aggregation functions.
|
should use aggregation functions.
|
||||||
"""
|
"""
|
||||||
# torch.FloatTensor(batch_size,)
|
# torch.FloatTensor(batch_size,)
|
||||||
aggregate_mask_init = torch.logical_not(torch.isnan(answer)).type(torch.FloatTensor).to(answer.device)
|
aggregate_mask_init = torch.logical_not(torch.isnan(answer)).type(torch.FloatTensor).to(answer.device)
|
||||||
@@ -1976,13 +1994,13 @@ def _calculate_aggregate_mask(answer, pooled_output, cell_selection_preference,
|
|||||||
|
|
||||||
|
|
||||||
def _calculate_aggregation_loss_known(logits_aggregation, aggregate_mask, aggregation_function_id, config):
|
def _calculate_aggregation_loss_known(logits_aggregation, aggregate_mask, aggregation_function_id, config):
|
||||||
"""Calculates aggregation loss when its type is known during training.
|
"""
|
||||||
|
Calculates aggregation loss when its type is known during training.
|
||||||
|
|
||||||
|
In the weakly supervised setting, the only known information is that for cell selection examples, "no aggregation"
|
||||||
|
should be predicted. For other examples (those that require aggregation), no loss is accumulated. In the setting
|
||||||
|
where aggregation type is always known, standard cross entropy loss is accumulated for all examples
|
||||||
|
|
||||||
In the weakly supervised setting, the only known information is that for
|
|
||||||
cell selection examples, "no aggregation" should be predicted. For other
|
|
||||||
examples (those that require aggregation), no loss is accumulated.
|
|
||||||
In the setting where aggregation type is always known, standard cross entropy
|
|
||||||
loss is accumulated for all examples.
|
|
||||||
Args:
|
Args:
|
||||||
logits_aggregation (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, num_aggregation_labels)`):
|
logits_aggregation (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, num_aggregation_labels)`):
|
||||||
Logits per aggregation operation.
|
Logits per aggregation operation.
|
||||||
@@ -1991,10 +2009,11 @@ def _calculate_aggregation_loss_known(logits_aggregation, aggregate_mask, aggreg
|
|||||||
aggregation_function_id (:obj:`torch.LongTensor` of shape :obj:`(batch_size, )`):
|
aggregation_function_id (:obj:`torch.LongTensor` of shape :obj:`(batch_size, )`):
|
||||||
Aggregation function id for every example in the batch.
|
Aggregation function id for every example in the batch.
|
||||||
config (:class:`~transformers.TapasConfig`):
|
config (:class:`~transformers.TapasConfig`):
|
||||||
Model configuration class with all the parameters of the model.
|
Model configuration class with all the parameters of the model
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
aggregation_loss_known (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`):
|
aggregation_loss_known (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`): Aggregation loss (when its
|
||||||
Aggregation loss (when its type is known during training) per example.
|
type is known during training) per example.
|
||||||
"""
|
"""
|
||||||
if config.use_answer_as_supervision:
|
if config.use_answer_as_supervision:
|
||||||
# Prepare "no aggregation" targets for cell selection examples.
|
# Prepare "no aggregation" targets for cell selection examples.
|
||||||
@@ -2019,15 +2038,18 @@ def _calculate_aggregation_loss_known(logits_aggregation, aggregate_mask, aggreg
|
|||||||
|
|
||||||
|
|
||||||
def _calculate_aggregation_loss_unknown(logits_aggregation, aggregate_mask):
|
def _calculate_aggregation_loss_unknown(logits_aggregation, aggregate_mask):
|
||||||
"""Calculates aggregation loss in the case of answer supervision.
|
"""
|
||||||
|
Calculates aggregation loss in the case of answer supervision
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
logits_aggregation (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, num_aggregation_labels)`):
|
logits_aggregation (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, num_aggregation_labels)`):
|
||||||
Logits per aggregation operation.
|
Logits per aggregation operation.
|
||||||
aggregate_mask (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, )`):
|
aggregate_mask (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, )`):
|
||||||
A mask set to 1 for examples that should use aggregation functions.
|
A mask set to 1 for examples that should use aggregation functions
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
aggregation_loss_unknown (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`):
|
aggregation_loss_unknown (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`): Aggregation loss (in case of
|
||||||
Aggregation loss (in case of answer supervision) per example.
|
answer supervision) per example.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
dist_aggregation = torch.distributions.categorical.Categorical(logits=logits_aggregation)
|
dist_aggregation = torch.distributions.categorical.Categorical(logits=logits_aggregation)
|
||||||
@@ -2041,7 +2063,9 @@ def _calculate_aggregation_loss_unknown(logits_aggregation, aggregate_mask):
|
|||||||
|
|
||||||
|
|
||||||
def _calculate_aggregation_loss(logits_aggregation, aggregate_mask, aggregation_function_id, config):
|
def _calculate_aggregation_loss(logits_aggregation, aggregate_mask, aggregation_function_id, config):
|
||||||
"""Calculates the aggregation loss per example.
|
"""
|
||||||
|
Calculates the aggregation loss per example
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
logits_aggregation (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, num_aggregation_labels)`):
|
logits_aggregation (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, num_aggregation_labels)`):
|
||||||
Logits per aggregation operation.
|
Logits per aggregation operation.
|
||||||
@@ -2050,10 +2074,10 @@ def _calculate_aggregation_loss(logits_aggregation, aggregate_mask, aggregation_
|
|||||||
aggregation_function_id (:obj:`torch.LongTensor` of shape :obj:`(batch_size, )`):
|
aggregation_function_id (:obj:`torch.LongTensor` of shape :obj:`(batch_size, )`):
|
||||||
Aggregation function id for every example in the batch.
|
Aggregation function id for every example in the batch.
|
||||||
config (:class:`~transformers.TapasConfig`):
|
config (:class:`~transformers.TapasConfig`):
|
||||||
Model configuration class with all the parameters of the model.
|
Model configuration class with all the parameters of the model
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
aggregation_loss (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`):
|
aggregation_loss (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`): Aggregation loss per example.
|
||||||
Aggregation loss per example.
|
|
||||||
"""
|
"""
|
||||||
per_example_aggregation_loss = _calculate_aggregation_loss_known(
|
per_example_aggregation_loss = _calculate_aggregation_loss_known(
|
||||||
logits_aggregation, aggregate_mask, aggregation_function_id, config
|
logits_aggregation, aggregate_mask, aggregation_function_id, config
|
||||||
@@ -2068,7 +2092,9 @@ def _calculate_aggregation_loss(logits_aggregation, aggregate_mask, aggregation_
|
|||||||
def _calculate_expected_result(
|
def _calculate_expected_result(
|
||||||
dist_per_cell, numeric_values, numeric_values_scale, input_mask_float, logits_aggregation, config
|
dist_per_cell, numeric_values, numeric_values_scale, input_mask_float, logits_aggregation, config
|
||||||
):
|
):
|
||||||
"""Calculate the expected result given cell and aggregation probabilities.
|
"""
|
||||||
|
Calculate the expected result given cell and aggregation probabilities
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
dist_per_cell (:obj:`torch.distributions.Bernoulli`):
|
dist_per_cell (:obj:`torch.distributions.Bernoulli`):
|
||||||
Cell selection distribution for each cell.
|
Cell selection distribution for each cell.
|
||||||
@@ -2081,10 +2107,10 @@ def _calculate_expected_result(
|
|||||||
logits_aggregation (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, num_aggregation_labels)`):
|
logits_aggregation (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, num_aggregation_labels)`):
|
||||||
Logits per aggregation operation.
|
Logits per aggregation operation.
|
||||||
config (:class:`~transformers.TapasConfig`):
|
config (:class:`~transformers.TapasConfig`):
|
||||||
Model configuration class with all the parameters of the model.
|
Model configuration class with all the parameters of the model
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
expected_result (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`):
|
expected_result (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`): The expected result per example.
|
||||||
The expected result per example.
|
|
||||||
"""
|
"""
|
||||||
if config.use_gumbel_for_cells:
|
if config.use_gumbel_for_cells:
|
||||||
gumbel_dist = torch.distributions.RelaxedBernoulli(
|
gumbel_dist = torch.distributions.RelaxedBernoulli(
|
||||||
@@ -2163,7 +2189,9 @@ def _calculate_regression_loss(
|
|||||||
logits_aggregation,
|
logits_aggregation,
|
||||||
config,
|
config,
|
||||||
):
|
):
|
||||||
"""Calculates the regression loss per example.
|
"""
|
||||||
|
Calculates the regression loss per example
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
answer (:obj: `torch.FloatTensor` of shape :obj:`(batch_size,)`):
|
answer (:obj: `torch.FloatTensor` of shape :obj:`(batch_size,)`):
|
||||||
Answer for every example in the batch. Nan if there is no scalar answer.
|
Answer for every example in the batch. Nan if there is no scalar answer.
|
||||||
@@ -2180,12 +2208,12 @@ def _calculate_regression_loss(
|
|||||||
logits_aggregation (:obj: `torch.FloatTensor` of shape :obj:`(batch_size, num_aggregation_labels)`):
|
logits_aggregation (:obj: `torch.FloatTensor` of shape :obj:`(batch_size, num_aggregation_labels)`):
|
||||||
Logits per aggregation operation.
|
Logits per aggregation operation.
|
||||||
config (:class:`~transformers.TapasConfig`):
|
config (:class:`~transformers.TapasConfig`):
|
||||||
Model configuration class with all the parameters of the model.
|
Model configuration class with all the parameters of the model
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
per_example_answer_loss_scaled (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`):
|
per_example_answer_loss_scaled (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`): Scales answer loss for
|
||||||
Scales answer loss for each example in the batch.
|
each example in the batch. large_answer_loss_mask (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`): A
|
||||||
large_answer_loss_mask (:obj:`torch.FloatTensor` of shape :obj:`(batch_size,)`):
|
mask which is 1 for examples for which their answer loss is larger than the answer_loss_cutoff.
|
||||||
A mask which is 1 for examples for which their answer loss is larger than the answer_loss_cutoff.
|
|
||||||
"""
|
"""
|
||||||
# <float32>[batch_size]
|
# <float32>[batch_size]
|
||||||
expected_result = _calculate_expected_result(
|
expected_result = _calculate_expected_result(
|
||||||
@@ -2219,4 +2247,4 @@ def _calculate_regression_loss(
|
|||||||
)
|
)
|
||||||
per_example_answer_loss_scaled = config.answer_loss_importance * (per_example_answer_loss * aggregate_mask)
|
per_example_answer_loss_scaled = config.answer_loss_importance * (per_example_answer_loss * aggregate_mask)
|
||||||
|
|
||||||
return per_example_answer_loss_scaled, large_answer_loss_mask
|
return per_example_answer_loss_scaled, large_answer_loss_mask
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -14,7 +14,6 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@@ -26,17 +25,16 @@ from .test_configuration_common import ConfigTester
|
|||||||
from .test_modeling_common import ModelTesterMixin, floats_tensor, ids_tensor, random_attention_mask
|
from .test_modeling_common import ModelTesterMixin, floats_tensor, ids_tensor, random_attention_mask
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if is_torch_available():
|
if is_torch_available():
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
from transformers import (
|
from transformers import (
|
||||||
TAPAS_PRETRAINED_MODEL_ARCHIVE_LIST,
|
TAPAS_PRETRAINED_MODEL_ARCHIVE_LIST,
|
||||||
TapasConfig,
|
TapasConfig,
|
||||||
TapasModel,
|
|
||||||
TapasForMaskedLM,
|
TapasForMaskedLM,
|
||||||
TapasForSequenceClassification,
|
|
||||||
TapasForQuestionAnswering,
|
TapasForQuestionAnswering,
|
||||||
|
TapasForSequenceClassification,
|
||||||
|
TapasModel,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -143,10 +141,8 @@ class TapasModelTester:
|
|||||||
input_mask = random_attention_mask([self.batch_size, self.seq_length])
|
input_mask = random_attention_mask([self.batch_size, self.seq_length])
|
||||||
|
|
||||||
token_type_ids = []
|
token_type_ids = []
|
||||||
for type_vocab_size in self.type_vocab_sizes:
|
for type_vocab_size in self.type_vocab_sizes:
|
||||||
token_type_ids.append(
|
token_type_ids.append(ids_tensor(shape=[self.batch_size, self.seq_length], vocab_size=type_vocab_size))
|
||||||
ids_tensor(shape=[self.batch_size, self.seq_length], vocab_size=type_vocab_size)
|
|
||||||
)
|
|
||||||
token_type_ids = torch.stack(token_type_ids, dim=2)
|
token_type_ids = torch.stack(token_type_ids, dim=2)
|
||||||
|
|
||||||
sequence_labels = None
|
sequence_labels = None
|
||||||
@@ -219,8 +215,18 @@ class TapasModelTester:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def create_and_check_model(
|
def create_and_check_model(
|
||||||
self, config, input_ids, input_mask, token_type_ids, sequence_labels, token_labels, label_ids, answer,
|
self,
|
||||||
numeric_values, numeric_values_scale, aggregation_labels
|
config,
|
||||||
|
input_ids,
|
||||||
|
input_mask,
|
||||||
|
token_type_ids,
|
||||||
|
sequence_labels,
|
||||||
|
token_labels,
|
||||||
|
label_ids,
|
||||||
|
answer,
|
||||||
|
numeric_values,
|
||||||
|
numeric_values_scale,
|
||||||
|
aggregation_labels,
|
||||||
):
|
):
|
||||||
model = TapasModel(config=config)
|
model = TapasModel(config=config)
|
||||||
model.to(torch_device)
|
model.to(torch_device)
|
||||||
@@ -232,8 +238,18 @@ class TapasModelTester:
|
|||||||
self.parent.assertEqual(result.pooler_output.shape, (self.batch_size, self.hidden_size))
|
self.parent.assertEqual(result.pooler_output.shape, (self.batch_size, self.hidden_size))
|
||||||
|
|
||||||
def create_and_check_for_masked_lm(
|
def create_and_check_for_masked_lm(
|
||||||
self, config, input_ids, input_mask, token_type_ids, sequence_labels, token_labels, label_ids, answer,
|
self,
|
||||||
numeric_values, numeric_values_scale, aggregation_labels
|
config,
|
||||||
|
input_ids,
|
||||||
|
input_mask,
|
||||||
|
token_type_ids,
|
||||||
|
sequence_labels,
|
||||||
|
token_labels,
|
||||||
|
label_ids,
|
||||||
|
answer,
|
||||||
|
numeric_values,
|
||||||
|
numeric_values_scale,
|
||||||
|
aggregation_labels,
|
||||||
):
|
):
|
||||||
model = TapasForMaskedLM(config=config)
|
model = TapasForMaskedLM(config=config)
|
||||||
model.to(torch_device)
|
model.to(torch_device)
|
||||||
@@ -242,22 +258,48 @@ class TapasModelTester:
|
|||||||
self.parent.assertEqual(result.logits.shape, (self.batch_size, self.seq_length, self.vocab_size))
|
self.parent.assertEqual(result.logits.shape, (self.batch_size, self.seq_length, self.vocab_size))
|
||||||
|
|
||||||
def create_and_check_for_question_answering(
|
def create_and_check_for_question_answering(
|
||||||
self, config, input_ids, input_mask, token_type_ids, sequence_labels, token_labels, label_ids, answer,
|
self,
|
||||||
numeric_values, numeric_values_scale, aggregation_labels
|
config,
|
||||||
|
input_ids,
|
||||||
|
input_mask,
|
||||||
|
token_type_ids,
|
||||||
|
sequence_labels,
|
||||||
|
token_labels,
|
||||||
|
label_ids,
|
||||||
|
answer,
|
||||||
|
numeric_values,
|
||||||
|
numeric_values_scale,
|
||||||
|
aggregation_labels,
|
||||||
):
|
):
|
||||||
model = TapasForQuestionAnswering(config=config)
|
model = TapasForQuestionAnswering(config=config)
|
||||||
model.to(torch_device)
|
model.to(torch_device)
|
||||||
model.eval()
|
model.eval()
|
||||||
result = model(input_ids, attention_mask=input_mask, token_type_ids=token_type_ids,
|
result = model(
|
||||||
label_ids=label_ids, answer=answer, numeric_values=numeric_values,
|
input_ids,
|
||||||
numeric_values_scale=numeric_values_scale, aggregation_labels=aggregation_labels
|
attention_mask=input_mask,
|
||||||
|
token_type_ids=token_type_ids,
|
||||||
|
label_ids=label_ids,
|
||||||
|
answer=answer,
|
||||||
|
numeric_values=numeric_values,
|
||||||
|
numeric_values_scale=numeric_values_scale,
|
||||||
|
aggregation_labels=aggregation_labels,
|
||||||
)
|
)
|
||||||
self.parent.assertEqual(result.logits.shape, (self.batch_size, self.seq_length))
|
self.parent.assertEqual(result.logits.shape, (self.batch_size, self.seq_length))
|
||||||
self.parent.assertEqual(result.logits_aggregation.shape, (self.batch_size, self.num_aggregation_labels))
|
self.parent.assertEqual(result.logits_aggregation.shape, (self.batch_size, self.num_aggregation_labels))
|
||||||
|
|
||||||
def create_and_check_for_sequence_classification(
|
def create_and_check_for_sequence_classification(
|
||||||
self, config, input_ids, input_mask, token_type_ids, sequence_labels, token_labels, label_ids, answer,
|
self,
|
||||||
numeric_values, numeric_values_scale, aggregation_labels
|
config,
|
||||||
|
input_ids,
|
||||||
|
input_mask,
|
||||||
|
token_type_ids,
|
||||||
|
sequence_labels,
|
||||||
|
token_labels,
|
||||||
|
label_ids,
|
||||||
|
answer,
|
||||||
|
numeric_values,
|
||||||
|
numeric_values_scale,
|
||||||
|
aggregation_labels,
|
||||||
):
|
):
|
||||||
config.num_labels = self.num_labels
|
config.num_labels = self.num_labels
|
||||||
model = TapasForSequenceClassification(config)
|
model = TapasForSequenceClassification(config)
|
||||||
@@ -375,6 +417,7 @@ class TapasModelTest(ModelTesterMixin, unittest.TestCase):
|
|||||||
# def test_large_inputs_in_fp16_dont_cause_overflow(self):
|
# def test_large_inputs_in_fp16_dont_cause_overflow(self):
|
||||||
# pass
|
# pass
|
||||||
|
|
||||||
|
|
||||||
# Below: tests for Tapas utilities, based on segmented_tensor_test.py of the original implementation.
|
# Below: tests for Tapas utilities, based on segmented_tensor_test.py of the original implementation.
|
||||||
# These test the operations on segmented tensors.
|
# These test the operations on segmented tensors.
|
||||||
class TapasUtilitiesTest(unittest.TestCase):
|
class TapasUtilitiesTest(unittest.TestCase):
|
||||||
|
|||||||
@@ -0,0 +1,573 @@
|
|||||||
|
# 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 functools
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
from typing import List, Tuple
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
import regex as re
|
||||||
|
from transformers import AddedToken, PreTrainedTokenizerBase
|
||||||
|
from transformers.testing_utils import require_tokenizers, slow
|
||||||
|
from transformers.tokenization_tapas import (
|
||||||
|
VOCAB_FILES_NAMES,
|
||||||
|
BasicTokenizer,
|
||||||
|
TapasTokenizer,
|
||||||
|
WordpieceTokenizer,
|
||||||
|
_is_control,
|
||||||
|
_is_punctuation,
|
||||||
|
_is_whitespace,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .test_tokenization_common import TokenizerTesterMixin, filter_non_english
|
||||||
|
|
||||||
|
|
||||||
|
@require_tokenizers
|
||||||
|
class TapasTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
|
||||||
|
|
||||||
|
tokenizer_class = TapasTokenizer
|
||||||
|
test_rust_tokenizer = False
|
||||||
|
space_between_special_tokens = True
|
||||||
|
from_pretrained_filter = filter_non_english
|
||||||
|
|
||||||
|
def get_clean_sequence(
|
||||||
|
self, tokenizer: TapasTokenizer, empty_table: bool = False, add_special_tokens: bool = True
|
||||||
|
) -> Tuple[pd.DataFrame, str, List[int]]:
|
||||||
|
if empty_table:
|
||||||
|
table = pd.DataFrame.from_dict({})
|
||||||
|
else:
|
||||||
|
data = {
|
||||||
|
"Actors": ["Brad Pitt", "Leonardo Di Caprio", "George Clooney"],
|
||||||
|
"Age": ["56", "45", "59"],
|
||||||
|
"Number of movies": ["87", "53", "69"],
|
||||||
|
"Date of birth": ["18 december 1963", "11 november 1974", "6 may 1961"],
|
||||||
|
}
|
||||||
|
table = pd.DataFrame.from_dict(data)
|
||||||
|
query = "Which actor appeared in the least number of movies?"
|
||||||
|
|
||||||
|
inputs = tokenizer.encode(table, query, add_special_tokens=add_special_tokens)
|
||||||
|
|
||||||
|
return table, query, inputs
|
||||||
|
|
||||||
|
# def get_clean_sequence(self, tokenizer, with_prefix_space=False, max_length=20, min_length=5) -> Tuple[str, list]:
|
||||||
|
# data = {
|
||||||
|
# 'Actors': ["Brad Pitt", "Leonardo Di Caprio", "George Clooney"],
|
||||||
|
# 'Age': ["56", "45", "59"],
|
||||||
|
# 'Number of movies': ["87", "53", "69"],
|
||||||
|
# 'Date of birth': ["18 december 1963", "11 november 1974", "6 may 1961"]
|
||||||
|
# }
|
||||||
|
# table = pd.DataFrame.from_dict(data)
|
||||||
|
# output_ids = tokenizer.encode(table, add_special_tokens=False, max_length=max_length)
|
||||||
|
# output_txt = tokenizer.decode(output_ids)
|
||||||
|
#
|
||||||
|
# return output_txt, output_ids
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
|
||||||
|
vocab_tokens = [
|
||||||
|
"[UNK]",
|
||||||
|
"[CLS]",
|
||||||
|
"[SEP]",
|
||||||
|
"[PAD]",
|
||||||
|
"[MASK]",
|
||||||
|
"want",
|
||||||
|
"##want",
|
||||||
|
"##ed",
|
||||||
|
"wa",
|
||||||
|
"un",
|
||||||
|
"runn",
|
||||||
|
"##ing",
|
||||||
|
",",
|
||||||
|
"low",
|
||||||
|
"lowest",
|
||||||
|
]
|
||||||
|
self.vocab_file = os.path.join(self.tmpdirname, VOCAB_FILES_NAMES["vocab_file"])
|
||||||
|
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_input_output_texts(self, tokenizer):
|
||||||
|
input_text = "UNwant\u00E9d,running"
|
||||||
|
output_text = "unwanted, running"
|
||||||
|
return input_text, output_text
|
||||||
|
|
||||||
|
def test_full_tokenizer(self):
|
||||||
|
tokenizer = self.tokenizer_class(self.vocab_file)
|
||||||
|
|
||||||
|
tokens = tokenizer.tokenize("UNwant\u00E9d,running")
|
||||||
|
self.assertListEqual(tokens, ["un", "##want", "##ed", ",", "runn", "##ing"])
|
||||||
|
self.assertListEqual(tokenizer.convert_tokens_to_ids(tokens), [9, 6, 7, 12, 10, 11])
|
||||||
|
|
||||||
|
def test_rust_and_python_full_tokenizers(self):
|
||||||
|
if not self.test_rust_tokenizer:
|
||||||
|
return
|
||||||
|
|
||||||
|
tokenizer = self.get_tokenizer()
|
||||||
|
rust_tokenizer = self.get_rust_tokenizer()
|
||||||
|
|
||||||
|
sequence = "UNwant\u00E9d,running"
|
||||||
|
|
||||||
|
tokens = tokenizer.tokenize(sequence)
|
||||||
|
rust_tokens = rust_tokenizer.tokenize(sequence)
|
||||||
|
self.assertListEqual(tokens, rust_tokens)
|
||||||
|
|
||||||
|
ids = tokenizer.encode(sequence, add_special_tokens=False)
|
||||||
|
rust_ids = rust_tokenizer.encode(sequence, add_special_tokens=False)
|
||||||
|
self.assertListEqual(ids, rust_ids)
|
||||||
|
|
||||||
|
rust_tokenizer = self.get_rust_tokenizer()
|
||||||
|
ids = tokenizer.encode(sequence)
|
||||||
|
rust_ids = rust_tokenizer.encode(sequence)
|
||||||
|
self.assertListEqual(ids, rust_ids)
|
||||||
|
|
||||||
|
# With lower casing
|
||||||
|
tokenizer = self.get_tokenizer(do_lower_case=True)
|
||||||
|
rust_tokenizer = self.get_rust_tokenizer(do_lower_case=True)
|
||||||
|
|
||||||
|
sequence = "UNwant\u00E9d,running"
|
||||||
|
|
||||||
|
tokens = tokenizer.tokenize(sequence)
|
||||||
|
rust_tokens = rust_tokenizer.tokenize(sequence)
|
||||||
|
self.assertListEqual(tokens, rust_tokens)
|
||||||
|
|
||||||
|
ids = tokenizer.encode(sequence, add_special_tokens=False)
|
||||||
|
rust_ids = rust_tokenizer.encode(sequence, add_special_tokens=False)
|
||||||
|
self.assertListEqual(ids, rust_ids)
|
||||||
|
|
||||||
|
rust_tokenizer = self.get_rust_tokenizer()
|
||||||
|
ids = tokenizer.encode(sequence)
|
||||||
|
rust_ids = rust_tokenizer.encode(sequence)
|
||||||
|
self.assertListEqual(ids, rust_ids)
|
||||||
|
|
||||||
|
def test_chinese(self):
|
||||||
|
tokenizer = BasicTokenizer()
|
||||||
|
|
||||||
|
self.assertListEqual(tokenizer.tokenize("ah\u535A\u63A8zz"), ["ah", "\u535A", "\u63A8", "zz"])
|
||||||
|
|
||||||
|
def test_basic_tokenizer_lower(self):
|
||||||
|
tokenizer = BasicTokenizer(do_lower_case=True)
|
||||||
|
|
||||||
|
self.assertListEqual(
|
||||||
|
tokenizer.tokenize(" \tHeLLo!how \n Are yoU? "), ["hello", "!", "how", "are", "you", "?"]
|
||||||
|
)
|
||||||
|
self.assertListEqual(tokenizer.tokenize("H\u00E9llo"), ["hello"])
|
||||||
|
|
||||||
|
def test_basic_tokenizer_lower_strip_accents_false(self):
|
||||||
|
tokenizer = BasicTokenizer(do_lower_case=True, strip_accents=False)
|
||||||
|
|
||||||
|
self.assertListEqual(
|
||||||
|
tokenizer.tokenize(" \tHäLLo!how \n Are yoU? "), ["hällo", "!", "how", "are", "you", "?"]
|
||||||
|
)
|
||||||
|
self.assertListEqual(tokenizer.tokenize("H\u00E9llo"), ["h\u00E9llo"])
|
||||||
|
|
||||||
|
def test_basic_tokenizer_lower_strip_accents_true(self):
|
||||||
|
tokenizer = BasicTokenizer(do_lower_case=True, strip_accents=True)
|
||||||
|
|
||||||
|
self.assertListEqual(
|
||||||
|
tokenizer.tokenize(" \tHäLLo!how \n Are yoU? "), ["hallo", "!", "how", "are", "you", "?"]
|
||||||
|
)
|
||||||
|
self.assertListEqual(tokenizer.tokenize("H\u00E9llo"), ["hello"])
|
||||||
|
|
||||||
|
def test_basic_tokenizer_lower_strip_accents_default(self):
|
||||||
|
tokenizer = BasicTokenizer(do_lower_case=True)
|
||||||
|
|
||||||
|
self.assertListEqual(
|
||||||
|
tokenizer.tokenize(" \tHäLLo!how \n Are yoU? "), ["hallo", "!", "how", "are", "you", "?"]
|
||||||
|
)
|
||||||
|
self.assertListEqual(tokenizer.tokenize("H\u00E9llo"), ["hello"])
|
||||||
|
|
||||||
|
def test_basic_tokenizer_no_lower(self):
|
||||||
|
tokenizer = BasicTokenizer(do_lower_case=False)
|
||||||
|
|
||||||
|
self.assertListEqual(
|
||||||
|
tokenizer.tokenize(" \tHeLLo!how \n Are yoU? "), ["HeLLo", "!", "how", "Are", "yoU", "?"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_basic_tokenizer_no_lower_strip_accents_false(self):
|
||||||
|
tokenizer = BasicTokenizer(do_lower_case=False, strip_accents=False)
|
||||||
|
|
||||||
|
self.assertListEqual(
|
||||||
|
tokenizer.tokenize(" \tHäLLo!how \n Are yoU? "), ["HäLLo", "!", "how", "Are", "yoU", "?"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_basic_tokenizer_no_lower_strip_accents_true(self):
|
||||||
|
tokenizer = BasicTokenizer(do_lower_case=False, strip_accents=True)
|
||||||
|
|
||||||
|
self.assertListEqual(
|
||||||
|
tokenizer.tokenize(" \tHäLLo!how \n Are yoU? "), ["HaLLo", "!", "how", "Are", "yoU", "?"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_basic_tokenizer_respects_never_split_tokens(self):
|
||||||
|
tokenizer = BasicTokenizer(do_lower_case=False, never_split=["[UNK]"])
|
||||||
|
|
||||||
|
self.assertListEqual(
|
||||||
|
tokenizer.tokenize(" \tHeLLo!how \n Are yoU? [UNK]"), ["HeLLo", "!", "how", "Are", "yoU", "?", "[UNK]"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_wordpiece_tokenizer(self):
|
||||||
|
vocab_tokens = ["[UNK]", "[CLS]", "[SEP]", "want", "##want", "##ed", "wa", "un", "runn", "##ing"]
|
||||||
|
|
||||||
|
vocab = {}
|
||||||
|
for (i, token) in enumerate(vocab_tokens):
|
||||||
|
vocab[token] = i
|
||||||
|
tokenizer = WordpieceTokenizer(vocab=vocab, unk_token="[UNK]")
|
||||||
|
|
||||||
|
self.assertListEqual(tokenizer.tokenize(""), [])
|
||||||
|
|
||||||
|
self.assertListEqual(tokenizer.tokenize("unwanted running"), ["un", "##want", "##ed", "runn", "##ing"])
|
||||||
|
|
||||||
|
self.assertListEqual(tokenizer.tokenize("unwantedX running"), ["[UNK]", "runn", "##ing"])
|
||||||
|
|
||||||
|
def test_is_whitespace(self):
|
||||||
|
self.assertTrue(_is_whitespace(" "))
|
||||||
|
self.assertTrue(_is_whitespace("\t"))
|
||||||
|
self.assertTrue(_is_whitespace("\r"))
|
||||||
|
self.assertTrue(_is_whitespace("\n"))
|
||||||
|
self.assertTrue(_is_whitespace("\u00A0"))
|
||||||
|
|
||||||
|
self.assertFalse(_is_whitespace("A"))
|
||||||
|
self.assertFalse(_is_whitespace("-"))
|
||||||
|
|
||||||
|
def test_is_control(self):
|
||||||
|
self.assertTrue(_is_control("\u0005"))
|
||||||
|
|
||||||
|
self.assertFalse(_is_control("A"))
|
||||||
|
self.assertFalse(_is_control(" "))
|
||||||
|
self.assertFalse(_is_control("\t"))
|
||||||
|
self.assertFalse(_is_control("\r"))
|
||||||
|
|
||||||
|
def test_is_punctuation(self):
|
||||||
|
self.assertTrue(_is_punctuation("-"))
|
||||||
|
self.assertTrue(_is_punctuation("$"))
|
||||||
|
self.assertTrue(_is_punctuation("`"))
|
||||||
|
self.assertTrue(_is_punctuation("."))
|
||||||
|
|
||||||
|
self.assertFalse(_is_punctuation("A"))
|
||||||
|
self.assertFalse(_is_punctuation(" "))
|
||||||
|
|
||||||
|
def test_clean_text(self):
|
||||||
|
tokenizer = self.get_tokenizer()
|
||||||
|
# rust_tokenizer = self.get_rust_tokenizer()
|
||||||
|
|
||||||
|
# Example taken from the issue https://github.com/huggingface/tokenizers/issues/340
|
||||||
|
self.assertListEqual([tokenizer.tokenize(t) for t in ["Test", "\xad", "test"]], [["[UNK]"], [], ["[UNK]"]])
|
||||||
|
|
||||||
|
# self.assertListEqual(
|
||||||
|
# [rust_tokenizer.tokenize(t) for t in ["Test", "\xad", "test"]], [["[UNK]"], [], ["[UNK]"]]
|
||||||
|
# )
|
||||||
|
|
||||||
|
@slow
|
||||||
|
def test_sequence_builders(self):
|
||||||
|
tokenizer = self.tokenizer_class.from_pretrained("tapas-base-uncased")
|
||||||
|
|
||||||
|
text = tokenizer.encode("sequence builders", add_special_tokens=False)
|
||||||
|
text_2 = tokenizer.encode("multi-sequence build", add_special_tokens=False)
|
||||||
|
|
||||||
|
encoded_sentence = tokenizer.build_inputs_with_special_tokens(text)
|
||||||
|
encoded_pair = tokenizer.build_inputs_with_special_tokens(text, text_2)
|
||||||
|
|
||||||
|
assert encoded_sentence == [101] + text + [102]
|
||||||
|
assert encoded_pair == [101] + text + [102] + text_2 + [102]
|
||||||
|
|
||||||
|
def test_offsets_with_special_characters(self):
|
||||||
|
for tokenizer, pretrained_name, kwargs in self.tokenizers_list:
|
||||||
|
with self.subTest("{} ({})".format(tokenizer.__class__.__name__, pretrained_name)):
|
||||||
|
tokenizer_r = self.rust_tokenizer_class.from_pretrained(pretrained_name, **kwargs)
|
||||||
|
|
||||||
|
sentence = f"A, naïve {tokenizer_r.mask_token} AllenNLP sentence."
|
||||||
|
tokens = tokenizer_r.encode_plus(
|
||||||
|
sentence,
|
||||||
|
return_attention_mask=False,
|
||||||
|
return_token_type_ids=False,
|
||||||
|
return_offsets_mapping=True,
|
||||||
|
add_special_tokens=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
do_lower_case = tokenizer_r.do_lower_case if hasattr(tokenizer_r, "do_lower_case") else False
|
||||||
|
expected_results = (
|
||||||
|
[
|
||||||
|
((0, 0), tokenizer_r.cls_token),
|
||||||
|
((0, 1), "A"),
|
||||||
|
((1, 2), ","),
|
||||||
|
((3, 5), "na"),
|
||||||
|
((5, 6), "##ï"),
|
||||||
|
((6, 8), "##ve"),
|
||||||
|
((9, 15), tokenizer_r.mask_token),
|
||||||
|
((16, 21), "Allen"),
|
||||||
|
((21, 23), "##NL"),
|
||||||
|
((23, 24), "##P"),
|
||||||
|
((25, 33), "sentence"),
|
||||||
|
((33, 34), "."),
|
||||||
|
((0, 0), tokenizer_r.sep_token),
|
||||||
|
]
|
||||||
|
if not do_lower_case
|
||||||
|
else [
|
||||||
|
((0, 0), tokenizer_r.cls_token),
|
||||||
|
((0, 1), "a"),
|
||||||
|
((1, 2), ","),
|
||||||
|
((3, 8), "naive"),
|
||||||
|
((9, 15), tokenizer_r.mask_token),
|
||||||
|
((16, 21), "allen"),
|
||||||
|
((21, 23), "##nl"),
|
||||||
|
((23, 24), "##p"),
|
||||||
|
((25, 33), "sentence"),
|
||||||
|
((33, 34), "."),
|
||||||
|
((0, 0), tokenizer_r.sep_token),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
[e[1] for e in expected_results], tokenizer_r.convert_ids_to_tokens(tokens["input_ids"])
|
||||||
|
)
|
||||||
|
self.assertEqual([e[0] for e in expected_results], tokens["offset_mapping"])
|
||||||
|
|
||||||
|
def test_add_special_tokens(self):
|
||||||
|
tokenizers: List[TapasTokenizer] = self.get_tokenizers(do_lower_case=False)
|
||||||
|
for tokenizer in tokenizers:
|
||||||
|
with self.subTest(f"{tokenizer.__class__.__name__}"):
|
||||||
|
input_table, input_query, ids = self.get_clean_sequence(
|
||||||
|
tokenizer, empty_table=True, add_special_tokens=False
|
||||||
|
)
|
||||||
|
|
||||||
|
special_token = "[SPECIAL_TOKEN]"
|
||||||
|
|
||||||
|
tokenizer.add_special_tokens({"cls_token": special_token})
|
||||||
|
encoded_special_token = tokenizer.encode(input_table, special_token, add_special_tokens=False)
|
||||||
|
self.assertEqual(len(encoded_special_token), 1)
|
||||||
|
|
||||||
|
text = tokenizer.decode(ids + encoded_special_token, clean_up_tokenization_spaces=False)
|
||||||
|
encoded = tokenizer.encode(input_table, text, add_special_tokens=False)
|
||||||
|
|
||||||
|
input_encoded = tokenizer.encode(input_table, input_query, add_special_tokens=False)
|
||||||
|
special_token_id = tokenizer.encode(input_table, special_token, add_special_tokens=False)
|
||||||
|
self.assertEqual(encoded, input_encoded + special_token_id)
|
||||||
|
|
||||||
|
decoded = tokenizer.decode(encoded, skip_special_tokens=True)
|
||||||
|
self.assertTrue(special_token not in decoded)
|
||||||
|
|
||||||
|
def test_add_tokens_tokenizer(self):
|
||||||
|
tokenizers: List[TapasTokenizer] = self.get_tokenizers(do_lower_case=False)
|
||||||
|
for tokenizer in tokenizers:
|
||||||
|
with self.subTest(f"{tokenizer.__class__.__name__}"):
|
||||||
|
input_table, input_query, ids = self.get_clean_sequence(tokenizer, empty_table=True)
|
||||||
|
vocab_size = tokenizer.vocab_size
|
||||||
|
all_size = len(tokenizer)
|
||||||
|
|
||||||
|
self.assertNotEqual(vocab_size, 0)
|
||||||
|
|
||||||
|
# We usually have added tokens from the start in tests because our vocab fixtures are
|
||||||
|
# smaller than the original vocabs - let's not assert this
|
||||||
|
# self.assertEqual(vocab_size, all_size)
|
||||||
|
|
||||||
|
new_toks = ["aaaaa bbbbbb", "cccccccccdddddddd"]
|
||||||
|
added_toks = tokenizer.add_tokens(new_toks)
|
||||||
|
vocab_size_2 = tokenizer.vocab_size
|
||||||
|
all_size_2 = len(tokenizer)
|
||||||
|
|
||||||
|
self.assertNotEqual(vocab_size_2, 0)
|
||||||
|
self.assertEqual(vocab_size, vocab_size_2)
|
||||||
|
self.assertEqual(added_toks, len(new_toks))
|
||||||
|
self.assertEqual(all_size_2, all_size + len(new_toks))
|
||||||
|
|
||||||
|
tokens = tokenizer.encode(
|
||||||
|
input_table, "aaaaa bbbbbb low cccccccccdddddddd l", add_special_tokens=False
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertGreaterEqual(len(tokens), 4)
|
||||||
|
self.assertGreater(tokens[0], tokenizer.vocab_size - 1)
|
||||||
|
self.assertGreater(tokens[-2], tokenizer.vocab_size - 1)
|
||||||
|
|
||||||
|
new_toks_2 = {"eos_token": ">>>>|||<||<<|<<", "pad_token": "<<<<<|||>|>>>>|>"}
|
||||||
|
added_toks_2 = tokenizer.add_special_tokens(new_toks_2)
|
||||||
|
vocab_size_3 = tokenizer.vocab_size
|
||||||
|
all_size_3 = len(tokenizer)
|
||||||
|
|
||||||
|
self.assertNotEqual(vocab_size_3, 0)
|
||||||
|
self.assertEqual(vocab_size, vocab_size_3)
|
||||||
|
self.assertEqual(added_toks_2, len(new_toks_2))
|
||||||
|
self.assertEqual(all_size_3, all_size_2 + len(new_toks_2))
|
||||||
|
|
||||||
|
tokens = tokenizer.encode(
|
||||||
|
input_table,
|
||||||
|
">>>>|||<||<<|<< aaaaabbbbbb low cccccccccdddddddd <<<<<|||>|>>>>|> l",
|
||||||
|
add_special_tokens=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertGreaterEqual(len(tokens), 6)
|
||||||
|
self.assertGreater(tokens[0], tokenizer.vocab_size - 1)
|
||||||
|
self.assertGreater(tokens[0], tokens[1])
|
||||||
|
self.assertGreater(tokens[-2], tokenizer.vocab_size - 1)
|
||||||
|
self.assertGreater(tokens[-2], tokens[-3])
|
||||||
|
self.assertEqual(tokens[0], tokenizer.eos_token_id)
|
||||||
|
self.assertEqual(tokens[-2], tokenizer.pad_token_id)
|
||||||
|
|
||||||
|
@require_tokenizers
|
||||||
|
def test_encode_decode_with_spaces(self):
|
||||||
|
tokenizers = self.get_tokenizers(do_lower_case=False)
|
||||||
|
for tokenizer in tokenizers:
|
||||||
|
with self.subTest(f"{tokenizer.__class__.__name__}"):
|
||||||
|
input_table, input_query, ids = self.get_clean_sequence(tokenizer, empty_table=True)
|
||||||
|
|
||||||
|
# new_toks = ["[ABC]", "[DEF]"] # TODO(thom) add this one back when Rust toks are ready: , "GHI IHG"]
|
||||||
|
new_toks = [AddedToken("[ABC]", normalized=False), AddedToken("[DEF]", normalized=False)]
|
||||||
|
tokenizer.add_tokens(new_toks)
|
||||||
|
input = "[ABC][DEF][ABC][DEF]" # TODO(thom) add back cf above: "[ABC] [DEF] [ABC] GHI IHG [DEF]"
|
||||||
|
if self.space_between_special_tokens:
|
||||||
|
output = "[ABC] [DEF] [ABC] [DEF]"
|
||||||
|
else:
|
||||||
|
output = input
|
||||||
|
encoded = tokenizer.encode(input_table, input, add_special_tokens=False)
|
||||||
|
decoded = tokenizer.decode(encoded, spaces_between_special_tokens=self.space_between_special_tokens)
|
||||||
|
self.assertIn(decoded, [output, output.lower()])
|
||||||
|
|
||||||
|
def test_encode_plus_with_padding(self):
|
||||||
|
tokenizers = self.get_tokenizers(do_lower_case=False)
|
||||||
|
for tokenizer in tokenizers:
|
||||||
|
with self.subTest(f"{tokenizer.__class__.__name__}"):
|
||||||
|
input_table, input_query, ids = self.get_clean_sequence(tokenizer, empty_table=True)
|
||||||
|
sequence = "Sequence"
|
||||||
|
|
||||||
|
# check correct behaviour if no pad_token_id exists and add it eventually
|
||||||
|
self._check_no_pad_token_padding(tokenizer, sequence)
|
||||||
|
|
||||||
|
padding_size = 10
|
||||||
|
padding_idx = tokenizer.pad_token_id
|
||||||
|
token_type_padding_idx = tokenizer.pad_token_type_id
|
||||||
|
|
||||||
|
encoded_sequence = tokenizer.encode_plus(input_table, sequence, return_special_tokens_mask=True)
|
||||||
|
input_ids = encoded_sequence["input_ids"]
|
||||||
|
special_tokens_mask = encoded_sequence["special_tokens_mask"]
|
||||||
|
sequence_length = len(input_ids)
|
||||||
|
|
||||||
|
# Test 'longest' and 'no_padding' don't do anything
|
||||||
|
tokenizer.padding_side = "right"
|
||||||
|
|
||||||
|
not_padded_sequence = tokenizer.encode_plus(
|
||||||
|
input_table,
|
||||||
|
sequence,
|
||||||
|
padding=True,
|
||||||
|
return_special_tokens_mask=True,
|
||||||
|
)
|
||||||
|
not_padded_input_ids = not_padded_sequence["input_ids"]
|
||||||
|
|
||||||
|
not_padded_special_tokens_mask = not_padded_sequence["special_tokens_mask"]
|
||||||
|
not_padded_sequence_length = len(not_padded_input_ids)
|
||||||
|
|
||||||
|
assert sequence_length == not_padded_sequence_length
|
||||||
|
assert input_ids == not_padded_input_ids
|
||||||
|
assert special_tokens_mask == not_padded_special_tokens_mask
|
||||||
|
|
||||||
|
not_padded_sequence = tokenizer.encode_plus(
|
||||||
|
input_table,
|
||||||
|
sequence,
|
||||||
|
padding=False,
|
||||||
|
return_special_tokens_mask=True,
|
||||||
|
)
|
||||||
|
not_padded_input_ids = not_padded_sequence["input_ids"]
|
||||||
|
|
||||||
|
not_padded_special_tokens_mask = not_padded_sequence["special_tokens_mask"]
|
||||||
|
not_padded_sequence_length = len(not_padded_input_ids)
|
||||||
|
|
||||||
|
assert sequence_length == not_padded_sequence_length
|
||||||
|
assert input_ids == not_padded_input_ids
|
||||||
|
assert special_tokens_mask == not_padded_special_tokens_mask
|
||||||
|
|
||||||
|
# Test right padding
|
||||||
|
tokenizer.padding_side = "right"
|
||||||
|
|
||||||
|
right_padded_sequence = tokenizer.encode_plus(
|
||||||
|
input_table,
|
||||||
|
sequence,
|
||||||
|
max_length=sequence_length + padding_size,
|
||||||
|
padding="max_length",
|
||||||
|
return_special_tokens_mask=True,
|
||||||
|
)
|
||||||
|
right_padded_input_ids = right_padded_sequence["input_ids"]
|
||||||
|
|
||||||
|
right_padded_special_tokens_mask = right_padded_sequence["special_tokens_mask"]
|
||||||
|
right_padded_sequence_length = len(right_padded_input_ids)
|
||||||
|
|
||||||
|
assert sequence_length + padding_size == right_padded_sequence_length
|
||||||
|
assert input_ids + [padding_idx] * padding_size == right_padded_input_ids
|
||||||
|
assert special_tokens_mask + [1] * padding_size == right_padded_special_tokens_mask
|
||||||
|
|
||||||
|
# Test left padding
|
||||||
|
tokenizer.padding_side = "left"
|
||||||
|
left_padded_sequence = tokenizer.encode_plus(
|
||||||
|
input_table,
|
||||||
|
sequence,
|
||||||
|
max_length=sequence_length + padding_size,
|
||||||
|
padding="max_length",
|
||||||
|
return_special_tokens_mask=True,
|
||||||
|
)
|
||||||
|
left_padded_input_ids = left_padded_sequence["input_ids"]
|
||||||
|
left_padded_special_tokens_mask = left_padded_sequence["special_tokens_mask"]
|
||||||
|
left_padded_sequence_length = len(left_padded_input_ids)
|
||||||
|
|
||||||
|
assert sequence_length + padding_size == left_padded_sequence_length
|
||||||
|
assert [padding_idx] * padding_size + input_ids == left_padded_input_ids
|
||||||
|
assert [1] * padding_size + special_tokens_mask == left_padded_special_tokens_mask
|
||||||
|
|
||||||
|
if "token_type_ids" in tokenizer.model_input_names:
|
||||||
|
token_type_ids = encoded_sequence["token_type_ids"]
|
||||||
|
left_padded_token_type_ids = left_padded_sequence["token_type_ids"]
|
||||||
|
right_padded_token_type_ids = right_padded_sequence["token_type_ids"]
|
||||||
|
|
||||||
|
assert (
|
||||||
|
token_type_ids + [[token_type_padding_idx] * 7] * padding_size == right_padded_token_type_ids
|
||||||
|
)
|
||||||
|
assert [[token_type_padding_idx] * 7] * padding_size + token_type_ids == left_padded_token_type_ids
|
||||||
|
|
||||||
|
if "attention_mask" in tokenizer.model_input_names:
|
||||||
|
attention_mask = encoded_sequence["attention_mask"]
|
||||||
|
right_padded_attention_mask = right_padded_sequence["attention_mask"]
|
||||||
|
left_padded_attention_mask = left_padded_sequence["attention_mask"]
|
||||||
|
|
||||||
|
assert attention_mask + [0] * padding_size == right_padded_attention_mask
|
||||||
|
assert [0] * padding_size + attention_mask == left_padded_attention_mask
|
||||||
|
|
||||||
|
def test_internal_consistency(self):
|
||||||
|
tokenizers = self.get_tokenizers()
|
||||||
|
for tokenizer in tokenizers:
|
||||||
|
with self.subTest(f"{tokenizer.__class__.__name__}"):
|
||||||
|
input_table, input_query, ids = self.get_clean_sequence(tokenizer, empty_table=True)
|
||||||
|
input_text, output_text = self.get_input_output_texts(tokenizer)
|
||||||
|
|
||||||
|
tokens = tokenizer.tokenize(input_text)
|
||||||
|
ids = tokenizer.convert_tokens_to_ids(tokens)
|
||||||
|
ids_2 = tokenizer.encode(input_table, input_text, add_special_tokens=False)
|
||||||
|
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)
|
||||||
|
|
||||||
|
def test_mask_output(self):
|
||||||
|
tokenizers = self.get_tokenizers(fast=False, do_lower_case=False)
|
||||||
|
for tokenizer in tokenizers:
|
||||||
|
with self.subTest(f"{tokenizer.__class__.__name__}"):
|
||||||
|
input_table, input_query, ids = self.get_clean_sequence(tokenizer)
|
||||||
|
|
||||||
|
if (
|
||||||
|
tokenizer.build_inputs_with_special_tokens.__qualname__.split(".")[0] != "PreTrainedTokenizer"
|
||||||
|
and "token_type_ids" in tokenizer.model_input_names
|
||||||
|
):
|
||||||
|
information = tokenizer.encode_plus(input_table, input_query, add_special_tokens=True)
|
||||||
|
sequences, mask = information["input_ids"], information["token_type_ids"]
|
||||||
|
self.assertEqual(len(sequences), len(mask))
|
||||||
Reference in new issue
Block a user