Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49a43e0c7b | ||
|
|
e49393c361 | ||
|
|
fbd8792195 | ||
|
|
d2a9399115 | ||
|
|
2e653d89d7 | ||
|
|
beaf60e589 | ||
|
|
e6eba8419c | ||
|
|
43b7ad5df5 | ||
|
|
87aa857d7e | ||
|
|
c7d96b60e4 | ||
|
|
b95dfcf110 | ||
|
|
6912265711 | ||
|
|
989ae326b5 | ||
|
|
3dcb748e31 |
No files matched your search
@@ -121,7 +121,10 @@ conversion utilities for the following models:
|
||||
trained using `OPUS <http://opus.nlpl.eu/>`_ pretrained_models data by Jörg Tiedemann.
|
||||
21. `Longformer <https://github.com/allenai/longformer>`_ (from AllenAI) released with the paper `Longformer: The
|
||||
Long-Document Transformer <https://arxiv.org/abs/2004.05150>`_ by Iz Beltagy, Matthew E. Peters, and Arman Cohan.
|
||||
22. `Other community models <https://huggingface.co/models>`_, contributed by the `community
|
||||
22. `DPR <https://github.com/facebookresearch/DPR>`_ (from Facebook) released with the paper `Dense Passage Retrieval
|
||||
for Open-Domain Question Answering <https://arxiv.org/abs/2004.04906>`_ by Vladimir Karpukhin, Barlas Oğuz, Sewon
|
||||
Min, Patrick Lewis, Ledell Wu, Sergey Edunov, Danqi Chen, and Wen-tau Yih.
|
||||
23. `Other community models <https://huggingface.co/models>`_, contributed by the `community
|
||||
<https://huggingface.co/users>`_.
|
||||
|
||||
.. toctree::
|
||||
@@ -199,3 +202,4 @@ conversion utilities for the following models:
|
||||
model_doc/longformer
|
||||
model_doc/retribert
|
||||
model_doc/mobilebert
|
||||
model_doc/dpr
|
||||
@@ -0,0 +1,89 @@
|
||||
DPR
|
||||
----------------------------------------------------
|
||||
|
||||
Overview
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Dense Passage Retrieval (DPR) - is a set of tools and models for state-of-the-art open-domain Q&A research.
|
||||
It is based on the following paper:
|
||||
|
||||
Vladimir Karpukhin, Barlas Oğuz, Sewon Min, Patrick Lewis, Ledell Wu, Sergey Edunov, Danqi Chen, Wen-tau Yih, Dense Passage Retrieval for Open-Domain Question Answering.
|
||||
|
||||
The abstract from the paper is the following:
|
||||
|
||||
*Open-domain question answering relies on efficient passage retrieval to select candidate contexts, where traditional
|
||||
sparse vector space models, such as TF-IDF or BM25, are the de facto method. In this work, we show that retrieval can
|
||||
be practically implemented using dense representations alone, where embeddings are learned from a small number of
|
||||
questions and passages by a simple dual-encoder framework. When evaluated on a wide range of open-domain QA datasets,
|
||||
our dense retriever outperforms a strong Lucene-BM25 system largely by 9%-19% absolute in terms of top-20 passage
|
||||
retrieval accuracy, and helps our end-to-end QA system establish new state-of-the-art on multiple open-domain QA
|
||||
benchmarks.*
|
||||
|
||||
The original code can be found `here <https://github.com/facebookresearch/DPR>`_.
|
||||
|
||||
|
||||
DPRConfig
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.DPRConfig
|
||||
:members:
|
||||
|
||||
|
||||
DPRContextEncoderTokenizer
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.DPRContextEncoderTokenizer
|
||||
:members:
|
||||
|
||||
|
||||
DPRContextEncoderTokenizerFast
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.DPRContextEncoderTokenizerFast
|
||||
:members:
|
||||
|
||||
DPRQuestionEncoderTokenizer
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.DPRQuestionEncoderTokenizer
|
||||
:members:
|
||||
|
||||
|
||||
DPRQuestionEncoderTokenizerFast
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.DPRQuestionEncoderTokenizerFast
|
||||
:members:
|
||||
|
||||
DPRReaderTokenizer
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.DPRReaderTokenizer
|
||||
:members:
|
||||
|
||||
|
||||
DPRReaderTokenizerFast
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.DPRReaderTokenizerFast
|
||||
:members:
|
||||
|
||||
|
||||
DPRContextEncoder
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.DPRContextEncoder
|
||||
:members:
|
||||
|
||||
DPRQuestionEncoder
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.DPRQuestionEncoder
|
||||
:members:
|
||||
|
||||
|
||||
DPRReader
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: transformers.DPRReader
|
||||
:members:
|
||||
@@ -55,7 +55,7 @@ Original GPT
|
||||
<a href="https://huggingface.co/models?filter=openai-gpt">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-openai--gpt-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/gpt.html">
|
||||
<a href="/model_doc/gpt">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-openai--gpt-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -75,7 +75,7 @@ GPT-2
|
||||
<a href="https://huggingface.co/models?filter=gpt2">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-gpt2-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/gpt2.html">
|
||||
<a href="/model_doc/gpt2">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-gpt2-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -96,7 +96,7 @@ CTRL
|
||||
<a href="https://huggingface.co/models?filter=ctrl">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-ctrl-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/ctrl.html">
|
||||
<a href="/model_doc/ctrl">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-ctrl-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -117,7 +117,7 @@ Transformer-XL
|
||||
<a href="https://huggingface.co/models?filter=transfo-xl">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-transfo--xl-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/transformerxl.html">
|
||||
<a href="/model_doc/transformerxl">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-transfo--xl-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -148,7 +148,7 @@ Reformer
|
||||
<a href="https://huggingface.co/models?filter=reformer">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-reformer-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/reformer.html">
|
||||
<a href="/model_doc/reformer">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-reformer-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -183,7 +183,7 @@ XLNet
|
||||
<a href="https://huggingface.co/models?filter=xlnet">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-xlnet-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/xlnet.html">
|
||||
<a href="/model_doc/xlnet">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-xlnet-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -217,7 +217,7 @@ BERT
|
||||
<a href="https://huggingface.co/models?filter=bert">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-bert-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/bert.html">
|
||||
<a href="/model_doc/bert">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-bert-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -246,7 +246,7 @@ ALBERT
|
||||
<a href="https://huggingface.co/models?filter=albert">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-albert-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/albert.html">
|
||||
<a href="/model_doc/albert">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-albert-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -275,7 +275,7 @@ RoBERTa
|
||||
<a href="https://huggingface.co/models?filter=roberta">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-roberta-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/roberta.html">
|
||||
<a href="/model_doc/roberta">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-roberta-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -301,7 +301,7 @@ DistilBERT
|
||||
<a href="https://huggingface.co/models?filter=distilbert">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-distilbert-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/distilbert.html">
|
||||
<a href="/model_doc/distilbert">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-distilbert-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -326,7 +326,7 @@ XLM
|
||||
<a href="https://huggingface.co/models?filter=xlm">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-xlm-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/xlm.html">
|
||||
<a href="/model_doc/xlm">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-xlm-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -361,7 +361,7 @@ XLM-RoBERTa
|
||||
<a href="https://huggingface.co/models?filter=xlm-roberta">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-xlm--roberta-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/xlmroberta.html">
|
||||
<a href="/model_doc/xlmroberta">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-xlm--roberta-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -383,7 +383,7 @@ FlauBERT
|
||||
<a href="https://huggingface.co/models?filter=flaubert">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-flaubert-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/flaubert.html">
|
||||
<a href="/model_doc/flaubert">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-flaubert-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -401,7 +401,7 @@ ELECTRA
|
||||
<a href="https://huggingface.co/models?filter=electra">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-electra-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/electra.html">
|
||||
<a href="/model_doc/electra">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-electra-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -427,7 +427,7 @@ Longformer
|
||||
<a href="https://huggingface.co/models?filter=longformer">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-longformer-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/longformer.html">
|
||||
<a href="/model_doc/longformer">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-longformer-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -461,7 +461,7 @@ BART
|
||||
<a href="https://huggingface.co/models?filter=bart">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-bart-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/bart.html">
|
||||
<a href="/model_doc/bart">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-bart-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -488,7 +488,7 @@ MarianMT
|
||||
<a href="https://huggingface.co/models?filter=marian">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-marian-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/marian.html">
|
||||
<a href="/model_doc/marian">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-marian-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -506,7 +506,7 @@ T5
|
||||
<a href="https://huggingface.co/models?filter=t5">
|
||||
<img alt="Models" src="https://img.shields.io/badge/All_model_pages-t5-blueviolet">
|
||||
</a>
|
||||
<a href="model_doc/t5.html">
|
||||
<a href="/model_doc/t5">
|
||||
<img alt="Doc" src="https://img.shields.io/badge/Model_documentation-t5-blueviolet">
|
||||
</a>
|
||||
|
||||
@@ -555,7 +555,7 @@ model know which part of the input vector corresponds to the text or the image.
|
||||
The pretrained model only works for classification.
|
||||
|
||||
..
|
||||
More information in this :doc:`model documentation </model_doc/mmbt.html>`.
|
||||
More information in this :doc:`model documentation </model_doc/mmbt>`.
|
||||
TODO: write this page
|
||||
|
||||
More technical aspects
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
Fine-tuning the library models for language modeling on a text file (GPT, GPT-2, BERT, RoBERTa).
|
||||
GPT and GPT-2 are fine-tuned using a causal language modeling (CLM) loss while BERT and RoBERTa are fine-tuned
|
||||
using a masked language modeling (MLM) loss.
|
||||
Fine-tuning the library models for language modeling on a text file (GPT, GPT-2, CTRL, BERT, RoBERTa, XLNet).
|
||||
GPT, GPT-2 and CTRL are fine-tuned using a causal language modeling (CLM) loss. BERT and RoBERTa are fine-tuned
|
||||
using a masked language modeling (MLM) loss. XLNet is fine-tuned using a permutation language modeling (PLM) loss.
|
||||
"""
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ from transformers import (
|
||||
AutoModelWithLMHead,
|
||||
AutoTokenizer,
|
||||
DataCollatorForLanguageModeling,
|
||||
DataCollatorForPermutationLanguageModeling,
|
||||
HfArgumentParser,
|
||||
LineByLineTextDataset,
|
||||
PreTrainedTokenizer,
|
||||
@@ -101,6 +102,15 @@ class DataTrainingArguments:
|
||||
mlm_probability: float = field(
|
||||
default=0.15, metadata={"help": "Ratio of tokens to mask for masked language modeling loss"}
|
||||
)
|
||||
plm_probability: float = field(
|
||||
default=1 / 6,
|
||||
metadata={
|
||||
"help": "Ratio of length of a span of masked tokens to surrounding context length for permutation language modeling."
|
||||
},
|
||||
)
|
||||
max_span_length: int = field(
|
||||
default=5, metadata={"help": "Maximum length of a span of masked tokens for permutation language modeling."}
|
||||
)
|
||||
|
||||
block_size: int = field(
|
||||
default=-1,
|
||||
@@ -207,8 +217,8 @@ def main():
|
||||
|
||||
if config.model_type in ["bert", "roberta", "distilbert", "camembert"] and not data_args.mlm:
|
||||
raise ValueError(
|
||||
"BERT and RoBERTa-like models do not have LM heads but masked LM heads. They must be run using the --mlm "
|
||||
"flag (masked language modeling)."
|
||||
"BERT and RoBERTa-like models do not have LM heads but masked LM heads. They must be run using the"
|
||||
"--mlm flag (masked language modeling)."
|
||||
)
|
||||
|
||||
if data_args.block_size <= 0:
|
||||
@@ -221,9 +231,14 @@ def main():
|
||||
|
||||
train_dataset = get_dataset(data_args, tokenizer=tokenizer) if training_args.do_train else None
|
||||
eval_dataset = get_dataset(data_args, tokenizer=tokenizer, evaluate=True) if training_args.do_eval else None
|
||||
data_collator = DataCollatorForLanguageModeling(
|
||||
tokenizer=tokenizer, mlm=data_args.mlm, mlm_probability=data_args.mlm_probability
|
||||
)
|
||||
if config.model_type == "xlnet":
|
||||
data_collator = DataCollatorForPermutationLanguageModeling(
|
||||
tokenizer=tokenizer, plm_probability=data_args.plm_probability, max_span_length=data_args.max_span_length,
|
||||
)
|
||||
else:
|
||||
data_collator = DataCollatorForLanguageModeling(
|
||||
tokenizer=tokenizer, mlm=data_args.mlm, mlm_probability=data_args.mlm_probability
|
||||
)
|
||||
|
||||
# Initialize our Trainer
|
||||
trainer = Trainer(
|
||||
|
||||
@@ -77,7 +77,7 @@ exact_match = 86.91
|
||||
```
|
||||
|
||||
This fine-tuned model is available as a checkpoint under the reference
|
||||
`bert-large-uncased-whole-word-masking-finetuned-squad`.
|
||||
[`bert-large-uncased-whole-word-masking-finetuned-squad`](https://huggingface.co/bert-large-uncased-whole-word-masking-finetuned-squad).
|
||||
|
||||
#### Fine-tuning XLNet on SQuAD
|
||||
|
||||
@@ -176,4 +176,5 @@ python run_tf_squad.py \
|
||||
--doc_stride 128
|
||||
```
|
||||
|
||||
For the moment the evaluation is not available in the Tensorflow Trainer only the training.
|
||||
|
||||
For the moment evaluation is not available in the Tensorflow Trainer only the training.
|
||||
@@ -0,0 +1,160 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team.
|
||||
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
""" Fine-tuning the library models for question-answering."""
|
||||
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
|
||||
from transformers import AutoConfig, AutoModelForQuestionAnswering, AutoTokenizer, HfArgumentParser, SquadDataset
|
||||
from transformers import SquadDataTrainingArguments as DataTrainingArguments
|
||||
from transformers import Trainer, TrainingArguments
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ModelArguments:
|
||||
"""
|
||||
Arguments pertaining to which model/config/tokenizer we are going to fine-tune from.
|
||||
"""
|
||||
|
||||
model_name_or_path: str = field(
|
||||
metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"}
|
||||
)
|
||||
config_name: Optional[str] = field(
|
||||
default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"}
|
||||
)
|
||||
tokenizer_name: Optional[str] = field(
|
||||
default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"}
|
||||
)
|
||||
use_fast: bool = field(default=False, metadata={"help": "Set this flag to use fast tokenization."})
|
||||
# If you want to tweak more attributes on your tokenizer, you should do it in a distinct script,
|
||||
# or just modify its tokenizer_config.json.
|
||||
cache_dir: Optional[str] = field(
|
||||
default=None, metadata={"help": "Where do you want to store the pretrained models downloaded from s3"}
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
# See all possible arguments in src/transformers/training_args.py
|
||||
# or by passing the --help flag to this script.
|
||||
# We now keep distinct sets of args, for a cleaner separation of concerns.
|
||||
|
||||
parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments))
|
||||
|
||||
if len(sys.argv) == 2 and sys.argv[1].endswith(".json"):
|
||||
# If we pass only one argument to the script and it's the path to a json file,
|
||||
# let's parse it to get our arguments.
|
||||
model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1]))
|
||||
else:
|
||||
model_args, data_args, training_args = parser.parse_args_into_dataclasses()
|
||||
|
||||
if (
|
||||
os.path.exists(training_args.output_dir)
|
||||
and os.listdir(training_args.output_dir)
|
||||
and training_args.do_train
|
||||
and not training_args.overwrite_output_dir
|
||||
):
|
||||
raise ValueError(
|
||||
f"Output directory ({training_args.output_dir}) already exists and is not empty. Use --overwrite_output_dir to overcome."
|
||||
)
|
||||
|
||||
# Setup logging
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
|
||||
datefmt="%m/%d/%Y %H:%M:%S",
|
||||
level=logging.INFO if training_args.local_rank in [-1, 0] else logging.WARN,
|
||||
)
|
||||
logger.warning(
|
||||
"Process rank: %s, device: %s, n_gpu: %s, distributed training: %s, 16-bits training: %s",
|
||||
training_args.local_rank,
|
||||
training_args.device,
|
||||
training_args.n_gpu,
|
||||
bool(training_args.local_rank != -1),
|
||||
training_args.fp16,
|
||||
)
|
||||
logger.info("Training/evaluation parameters %s", training_args)
|
||||
|
||||
# Prepare Question-Answering task
|
||||
# Load pretrained model and tokenizer
|
||||
#
|
||||
# Distributed training:
|
||||
# The .from_pretrained methods guarantee that only one local process can concurrently
|
||||
# download model & vocab.
|
||||
|
||||
config = AutoConfig.from_pretrained(
|
||||
model_args.config_name if model_args.config_name else model_args.model_name_or_path,
|
||||
cache_dir=model_args.cache_dir,
|
||||
)
|
||||
tokenizer = AutoTokenizer.from_pretrained(
|
||||
model_args.tokenizer_name if model_args.tokenizer_name else model_args.model_name_or_path,
|
||||
cache_dir=model_args.cache_dir,
|
||||
)
|
||||
model = AutoModelForQuestionAnswering.from_pretrained(
|
||||
model_args.model_name_or_path,
|
||||
from_tf=bool(".ckpt" in model_args.model_name_or_path),
|
||||
config=config,
|
||||
cache_dir=model_args.cache_dir,
|
||||
)
|
||||
|
||||
# Get datasets
|
||||
is_language_sensitive = hasattr(model.config, "lang2id")
|
||||
train_dataset = (
|
||||
SquadDataset(
|
||||
data_args, tokenizer=tokenizer, is_language_sensitive=is_language_sensitive, cache_dir=model_args.cache_dir
|
||||
)
|
||||
if training_args.do_train
|
||||
else None
|
||||
)
|
||||
eval_dataset = (
|
||||
SquadDataset(
|
||||
data_args,
|
||||
tokenizer=tokenizer,
|
||||
mode="dev",
|
||||
is_language_sensitive=is_language_sensitive,
|
||||
cache_dir=model_args.cache_dir,
|
||||
)
|
||||
if training_args.do_eval
|
||||
else None
|
||||
)
|
||||
|
||||
# Initialize our Trainer
|
||||
trainer = Trainer(model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset,)
|
||||
|
||||
# Training
|
||||
if training_args.do_train:
|
||||
trainer.train(
|
||||
model_path=model_args.model_name_or_path if os.path.isdir(model_args.model_name_or_path) else None
|
||||
)
|
||||
trainer.save_model()
|
||||
# For convenience, we also re-save the tokenizer to the same directory,
|
||||
# so that you can share your model easily on huggingface.co/models =)
|
||||
if trainer.is_world_master():
|
||||
tokenizer.save_pretrained(training_args.output_dir)
|
||||
|
||||
|
||||
def _mp_fn(index):
|
||||
# For xla_spawn (TPUs)
|
||||
main()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
language: zulu
|
||||
---
|
||||
|
||||
# zuBERTa
|
||||
zuBERTa is a RoBERTa style transformer language model trained on zulu text.
|
||||
|
||||
## Intended uses & limitations
|
||||
The model can be used for getting embeddings to use on a down-stream task such as question answering.
|
||||
|
||||
#### How to use
|
||||
|
||||
```python
|
||||
>>> from transformers import pipeline
|
||||
>>> from transformers import AutoTokenizer, AutoModelWithLMHead
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("MoseliMotsoehli/zuBERTa")
|
||||
>>> model = AutoModelWithLMHead.from_pretrained("MoseliMotsoehli/zuBERTa")
|
||||
>>> unmasker = pipeline('fill-mask', model=model, tokenizer=tokenizer)
|
||||
>>> unmasker("Abafika eNkandla bafika sebeholwa <mask> uMpongo kaZingelwayo.")
|
||||
|
||||
[
|
||||
{
|
||||
"sequence": "<s>Abafika eNkandla bafika sebeholwa khona uMpongo kaZingelwayo.</s>",
|
||||
"score": 0.050459690392017365,
|
||||
"token": 555,
|
||||
"token_str": "Ġkhona"
|
||||
},
|
||||
{
|
||||
"sequence": "<s>Abafika eNkandla bafika sebeholwa inkosi uMpongo kaZingelwayo.</s>",
|
||||
"score": 0.03668094798922539,
|
||||
"token": 2321,
|
||||
"token_str": "Ġinkosi"
|
||||
},
|
||||
{
|
||||
"sequence": "<s>Abafika eNkandla bafika sebeholwa ubukhosi uMpongo kaZingelwayo.</s>",
|
||||
"score": 0.028774697333574295,
|
||||
"token": 5101,
|
||||
"token_str": "Ġubukhosi"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Training data
|
||||
|
||||
1. 30k sentences of text, came from the [Leipzig Corpora Collection](https://wortschatz.uni-leipzig.de/en/download) of zulu 2018. These were collected from news articles and creative writtings.
|
||||
2. ~7500 articles of human generated translations were scraped from the zulu [wikipedia](https://zu.wikipedia.org/wiki/Special:AllPages).
|
||||
|
||||
### BibTeX entry and citation info
|
||||
|
||||
```bibtex
|
||||
@inproceedings{author = {Moseli Motsoehli},
|
||||
title = {Towards transformation of Southern African language models through transformers.},
|
||||
year={2020}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
language: english
|
||||
---
|
||||
|
||||
# Electra small ⚡ + SQuAD v1 ❓
|
||||
|
||||
[Electra-small-discriminator](https://huggingface.co/google/electra-small-discriminator) fine-tuned on [SQUAD v1.1 dataset](https://rajpurkar.github.io/SQuAD-explorer/explore/1.1/dev/) for **Q&A** downstream task.
|
||||
|
||||
## Details of the downstream task (Q&A) - Model 🧠
|
||||
|
||||
**ELECTRA** is a new method for self-supervised language representation learning. It can be used to pre-train transformer networks using relatively little compute. ELECTRA models are trained to distinguish "real" input tokens vs "fake" input tokens generated by another neural network, similar to the discriminator of a [GAN](https://arxiv.org/pdf/1406.2661.pdf). At small scale, ELECTRA achieves strong results even when trained on a single GPU. At large scale, ELECTRA achieves state-of-the-art results on the [SQuAD 2.0](https://rajpurkar.github.io/SQuAD-explorer/) dataset.
|
||||
|
||||
|
||||
## Details of the downstream task (Q&A) - Dataset 📚
|
||||
|
||||
**S**tanford **Q**uestion **A**nswering **D**ataset (SQuAD) is a reading comprehension dataset, consisting of questions posed by crowdworkers on a set of Wikipedia articles, where the answer to every question is a segment of text, or span, from the corresponding reading passage, or the question might be unanswerable.
|
||||
SQuAD v1.1 contains **100,000+** question-answer pairs on **500+** articles.
|
||||
|
||||
## Model training 🏋️
|
||||
|
||||
The model was trained on a Tesla P100 GPU and 25GB of RAM with the following command:
|
||||
|
||||
```bash
|
||||
python transformers/examples/question-answering/run_squad.py \
|
||||
--model_type electra \
|
||||
--model_name_or_path 'google/electra-small-discriminator' \
|
||||
--do_eval \
|
||||
--do_train \
|
||||
--do_lower_case \
|
||||
--train_file '/content/dataset/train-v1.1.json' \
|
||||
--predict_file '/content/dataset/dev-v1.1.json' \
|
||||
--per_gpu_train_batch_size 16 \
|
||||
--learning_rate 3e-5 \
|
||||
--num_train_epochs 10 \
|
||||
--max_seq_length 384 \
|
||||
--doc_stride 128 \
|
||||
--output_dir '/content/output' \
|
||||
--overwrite_output_dir \
|
||||
--save_steps 1000
|
||||
```
|
||||
|
||||
## Test set Results 🧾
|
||||
|
||||
| Metric | # Value |
|
||||
| ------ | --------- |
|
||||
| **EM** | **77.70** |
|
||||
| **F1** | **85.74** |
|
||||
| **Size**| **50 MB** |
|
||||
|
||||
Very good metrics for such a "small" model!
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
'exact': 77.70104068117313,
|
||||
'f1': 85.73991234187997,
|
||||
'total': 10570,
|
||||
'HasAns_exact': 77.70104068117313,
|
||||
'HasAns_f1': 85.73991234187997,
|
||||
'HasAns_total': 10570,
|
||||
'best_exact': 77.70104068117313,
|
||||
'best_exact_thresh': 0.0,
|
||||
'best_f1': 85.73991234187997,
|
||||
'best_f1_thresh': 0.0
|
||||
}
|
||||
```
|
||||
|
||||
### Model in action 🚀
|
||||
|
||||
Fast usage with **pipelines**:
|
||||
|
||||
```python
|
||||
from transformers import pipeline
|
||||
|
||||
QnA_pipeline = pipeline('question-answering', model='mrm8488/electra-small-finetuned-squadv1')
|
||||
QnA_pipeline({
|
||||
'context': 'A new strain of flu that has the potential to become a pandemic has been identified in China by scientists.',
|
||||
'question': 'What has been discovered by scientists from China ?'
|
||||
})
|
||||
|
||||
# Output:
|
||||
{'answer': 'A new strain of flu', 'end': 19, 'score': 0.7950334108113424, 'start': 0}
|
||||
```
|
||||
|
||||
> Created by [Manuel Romero/@mrm8488](https://twitter.com/mrm8488) | [LinkedIn](https://www.linkedin.com/in/manuel-romero-cs/)
|
||||
|
||||
> Made with <span style="color: #e25555;">♥</span> in Spain
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
language: english
|
||||
---
|
||||
|
||||
# RoBERTa-base (1B-1) + SQuAD v1 ❓
|
||||
|
||||
[roberta-base-1B-1](https://huggingface.co/nyu-mll/roberta-base-1B-1) fine-tuned on [SQUAD v1.1 dataset](https://rajpurkar.github.io/SQuAD-explorer/explore/1.1/dev/) for **Q&A** downstream task.
|
||||
|
||||
## Details of the downstream task (Q&A) - Model 🧠
|
||||
|
||||
RoBERTa Pretrained on Smaller Datasets
|
||||
|
||||
[NYU Machine Learning for Language](https://huggingface.co/nyu-mll) pretrained RoBERTa on smaller datasets (1M, 10M, 100M, 1B tokens). They released 3 models with lowest perplexities for each pretraining data size out of 25 runs (or 10 in the case of 1B tokens). The pretraining data reproduces that of BERT: They combine English Wikipedia and a reproduction of BookCorpus using texts from smashwords in a ratio of approximately 3:1.
|
||||
|
||||
|
||||
## Details of the downstream task (Q&A) - Dataset 📚
|
||||
|
||||
**S**tanford **Q**uestion **A**nswering **D**ataset (SQuAD) is a reading comprehension dataset, consisting of questions posed by crowdworkers on a set of Wikipedia articles, where the answer to every question is a segment of text, or span, from the corresponding reading passage, or the question might be unanswerable.
|
||||
SQuAD v1.1 contains **100,000+** question-answer pairs on **500+** articles.
|
||||
|
||||
## Model training 🏋️
|
||||
|
||||
The model was trained on a Tesla P100 GPU and 25GB of RAM with the following command:
|
||||
|
||||
```bash
|
||||
python transformers/examples/question-answering/run_squad.py \
|
||||
--model_type roberta \
|
||||
--model_name_or_path 'nyu-mll/roberta-base-1B-1' \
|
||||
--do_eval \
|
||||
--do_train \
|
||||
--do_lower_case \
|
||||
--train_file /content/dataset/train-v1.1.json \
|
||||
--predict_file /content/dataset/dev-v1.1.json \
|
||||
--per_gpu_train_batch_size 16 \
|
||||
--learning_rate 3e-5 \
|
||||
--num_train_epochs 10 \
|
||||
--max_seq_length 384 \
|
||||
--doc_stride 128 \
|
||||
--output_dir /content/output \
|
||||
--overwrite_output_dir \
|
||||
--save_steps 1000
|
||||
```
|
||||
|
||||
## Test set Results 🧾
|
||||
|
||||
| Metric | # Value |
|
||||
| ------ | --------- |
|
||||
| **EM** | **72.62** |
|
||||
| **F1** | **82.19** |
|
||||
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
'exact': 72.62062440870388,
|
||||
'f1': 82.19430877136834,
|
||||
'total': 10570,
|
||||
'HasAns_exact': 72.62062440870388,
|
||||
'HasAns_f1': 82.19430877136834,
|
||||
'HasAns_total': 10570,
|
||||
'best_exact': 72.62062440870388,
|
||||
'best_exact_thresh': 0.0,
|
||||
'best_f1': 82.19430877136834,
|
||||
'best_f1_thresh': 0.0
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Model in action 🚀
|
||||
|
||||
Fast usage with **pipelines**:
|
||||
|
||||
```python
|
||||
from transformers import pipeline
|
||||
|
||||
QnA_pipeline = pipeline('question-answering', model='mrm8488/roberta-base-1B-1-finetuned-squadv1')
|
||||
|
||||
QnA_pipeline({
|
||||
'context': 'A new strain of flu that has the potential to become a pandemic has been identified in China by scientists.',
|
||||
'question': 'What has been discovered by scientists from China ?'
|
||||
})
|
||||
# Output:
|
||||
|
||||
{'answer': 'A new strain of flu', 'end': 19, 'score': 0.04702283976040074, 'start': 0}
|
||||
```
|
||||
|
||||
> Created by [Manuel Romero/@mrm8488](https://twitter.com/mrm8488) | [LinkedIn](https://www.linkedin.com/in/manuel-romero-cs/)
|
||||
> Made with <span style="color: #e25555;">♥</span> in Spain
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
language: english
|
||||
---
|
||||
|
||||
# RoBERTa-base (1B-1) + SQuAD v2 ❓
|
||||
|
||||
[roberta-base-1B-1](https://huggingface.co/nyu-mll/roberta-base-1B-1) fine-tuned on [SQUAD v2 dataset](https://rajpurkar.github.io/SQuAD-explorer/explore/v2.0/dev/) for **Q&A** downstream task.
|
||||
|
||||
## Details of the downstream task (Q&A) - Model 🧠
|
||||
|
||||
RoBERTa Pretrained on Smaller Datasets
|
||||
|
||||
[NYU Machine Learning for Language](https://huggingface.co/nyu-mll) pretrained RoBERTa on smaller datasets (1M, 10M, 100M, 1B tokens). They released 3 models with lowest perplexities for each pretraining data size out of 25 runs (or 10 in the case of 1B tokens). The pretraining data reproduces that of BERT: They combine English Wikipedia and a reproduction of BookCorpus using texts from smashwords in a ratio of approximately 3:1.
|
||||
|
||||
|
||||
## Details of the downstream task (Q&A) - Dataset 📚
|
||||
|
||||
**S**tanford **Q**uestion **A**nswering **D**ataset (SQuAD) is a reading comprehension dataset, consisting of questions posed by crowdworkers on a set of Wikipedia articles, where the answer to every question is a segment of text, or span, from the corresponding reading passage, or the question might be unanswerable.
|
||||
|
||||
**SQuAD2.0** combines the 100,000 questions in SQuAD1.1 with over 50,000 unanswerable questions written adversarially by crowdworkers to look similar to answerable ones. To do well on SQuAD2.0, systems must not only answer questions when possible, but also determine when no answer is supported by the paragraph and abstain from answering.
|
||||
|
||||
## Model training 🏋️
|
||||
|
||||
The model was trained on a Tesla P100 GPU and 25GB of RAM with the following command:
|
||||
|
||||
```bash
|
||||
python transformers/examples/question-answering/run_squad.py \
|
||||
--model_type roberta \
|
||||
--model_name_or_path 'nyu-mll/roberta-base-1B-1' \
|
||||
--do_eval \
|
||||
--do_train \
|
||||
--do_lower_case \
|
||||
--train_file /content/dataset/train-v2.0.json \
|
||||
--predict_file /content/dataset/dev-v2.0.json \
|
||||
--per_gpu_train_batch_size 16 \
|
||||
--learning_rate 3e-5 \
|
||||
--num_train_epochs 10 \
|
||||
--max_seq_length 384 \
|
||||
--doc_stride 128 \
|
||||
--output_dir /content/output \
|
||||
--overwrite_output_dir \
|
||||
--save_steps 1000 \
|
||||
--version_2_with_negative
|
||||
```
|
||||
|
||||
## Test set Results 🧾
|
||||
|
||||
| Metric | # Value |
|
||||
| ------ | --------- |
|
||||
| **EM** | **64.86** |
|
||||
| **F1** | **68.99** |
|
||||
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
'exact': 64.86145034953255,
|
||||
'f1': 68.9902640378272,
|
||||
'total': 11873,
|
||||
'HasAns_exact': 64.03508771929825,
|
||||
'HasAns_f1': 72.3045554860189,
|
||||
'HasAns_total': 5928,
|
||||
'NoAns_exact': 65.68544995794785,
|
||||
'NoAns_f1': 65.68544995794785,
|
||||
'NoAns_total': 5945,
|
||||
'best_exact': 64.86987282068559,
|
||||
'best_exact_thresh': 0.0,
|
||||
'best_f1': 68.99868650898054,
|
||||
'best_f1_thresh': 0.0
|
||||
}
|
||||
```
|
||||
|
||||
### Model in action 🚀
|
||||
|
||||
Fast usage with **pipelines**:
|
||||
|
||||
```python
|
||||
from transformers import pipeline
|
||||
|
||||
QnA_pipeline = pipeline('question-answering', model='mrm8488/roberta-base-1B-1-finetuned-squadv2')
|
||||
|
||||
QnA_pipeline({
|
||||
'context': 'A new strain of flu that has the potential to become a pandemic has been identified in China by scientists.',
|
||||
'question': 'What has been discovered by scientists from China ?'
|
||||
})
|
||||
# Output:
|
||||
|
||||
{'answer': 'A new strain of flu', 'end': 19, 'score': 0.7145650685380576,'start': 0}
|
||||
```
|
||||
|
||||
> Created by [Manuel Romero/@mrm8488](https://twitter.com/mrm8488) | [LinkedIn](https://www.linkedin.com/in/manuel-romero-cs/)
|
||||
> Made with <span style="color: #e25555;">♥</span> in Spain
|
||||
@@ -1,3 +1,6 @@
|
||||
---
|
||||
language: turkish
|
||||
---
|
||||
|
||||
# For Turkish language, here is an easy-to-use NER application.
|
||||
** Türkçe için kolay bir python NER (Bert + Transfer Learning) (İsim Varlık Tanıma) modeli...
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
---
|
||||
language: turkish
|
||||
---
|
||||
# Bert-base Turkish Sentiment Model
|
||||
|
||||
https://huggingface.co/savasy/bert-base-turkish-sentiment-cased
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
---
|
||||
language: turkish
|
||||
---
|
||||
|
||||
# Turkish Text Classification
|
||||
|
||||
This model is a fine-tune model of https://github.com/stefan-it/turkish-bert by using text classification data where there are 7 categories as follows
|
||||
|
||||
```
|
||||
code_to_label={
|
||||
'LABEL_0': 'dunya ',
|
||||
'LABEL_1': 'ekonomi ',
|
||||
'LABEL_2': 'kultur ',
|
||||
'LABEL_3': 'saglik ',
|
||||
'LABEL_4': 'siyaset ',
|
||||
'LABEL_5': 'spor ',
|
||||
'LABEL_6': 'teknoloji '}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Data
|
||||
The following Turkish benchmark dataset is used for fine-tuning
|
||||
|
||||
https://www.kaggle.com/savasy/ttc4900
|
||||
|
||||
## Quick Start
|
||||
|
||||
Bewgin with installing transformers as follows
|
||||
> pip install transformers
|
||||
|
||||
```
|
||||
# Code:
|
||||
# import libraries
|
||||
from transformers import pipeline, AutoModelForTokenClassification, AutoTokenizer, AutoModelForSequenceClassification
|
||||
tokenizer= AutoTokenizer.from_pretrained("savasy/bert-turkish-text-classification")
|
||||
|
||||
# build and load model, it take time depending on your internet connection
|
||||
model= AutoModelForSequenceClassification.from_pretrained("savasy/bert-turkish-text-classification")
|
||||
|
||||
# make pipeline
|
||||
nlp=pipeline("sentiment-analysis", model=model, tokenizer=tokenizer)
|
||||
|
||||
# apply model
|
||||
nlp("bla bla")
|
||||
# [{'label': 'LABEL_2', 'score': 0.4753005802631378}]
|
||||
|
||||
code_to_label={
|
||||
'LABEL_0': 'dunya ',
|
||||
'LABEL_1': 'ekonomi ',
|
||||
'LABEL_2': 'kultur ',
|
||||
'LABEL_3': 'saglik ',
|
||||
'LABEL_4': 'siyaset ',
|
||||
'LABEL_5': 'spor ',
|
||||
'LABEL_6': 'teknoloji '}
|
||||
|
||||
code_to_label[nlp("bla bla")[0]['label']]
|
||||
# > 'kultur '
|
||||
```
|
||||
|
||||
## How the model was trained
|
||||
|
||||
```
|
||||
|
||||
## loading data for Turkish text classification
|
||||
import pandas as pd
|
||||
# https://www.kaggle.com/savasy/ttc4900
|
||||
df=pd.read_csv("7allV03.csv")
|
||||
df.columns=["labels","text"]
|
||||
df.labels=pd.Categorical(df.labels)
|
||||
|
||||
traind_df=...
|
||||
eval_df=...
|
||||
|
||||
# model
|
||||
from simpletransformers.classification import ClassificationModel
|
||||
import torch,sklearn
|
||||
|
||||
model_args = {
|
||||
"use_early_stopping": True,
|
||||
"early_stopping_delta": 0.01,
|
||||
"early_stopping_metric": "mcc",
|
||||
"early_stopping_metric_minimize": False,
|
||||
"early_stopping_patience": 5,
|
||||
"evaluate_during_training_steps": 1000,
|
||||
"fp16": False,
|
||||
"num_train_epochs":3
|
||||
}
|
||||
|
||||
model = ClassificationModel(
|
||||
"bert",
|
||||
"dbmdz/bert-base-turkish-cased",
|
||||
use_cuda=cuda_available,
|
||||
args=model_args,
|
||||
num_labels=7
|
||||
)
|
||||
model.train_model(train_df, acc=sklearn.metrics.accuracy_score)
|
||||
```
|
||||
For other training models please check https://simpletransformers.ai/
|
||||
|
||||
|
||||
For the detailed usage of Turkish Text Classification please check [python notebook](https://github.com/savasy/TurkishTextClassification/blob/master/Bert_base_Text_Classification_for_Turkish.ipynb)
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
language:
|
||||
- ukrainian
|
||||
---
|
||||
|
||||
# ukr-roberta-base
|
||||
|
||||
## Pre-training corpora
|
||||
Below is the list of corpora used along with the output of wc command (counting lines, words and characters). These corpora were concatenated and tokenized with HuggingFace Roberta Tokenizer.
|
||||
|
||||
| Tables | Lines | Words | Characters |
|
||||
| ------------- |--------------:| -----:| -----:|
|
||||
| [Ukrainian Wikipedia - May 2020](https://dumps.wikimedia.org/ukwiki/latest/ukwiki-latest-pages-articles.xml.bz2) | 18 001 466| 201 207 739 | 2 647 891 947 |
|
||||
| [Ukrainian OSCAR deduplicated dataset](https://oscar-public.huma-num.fr/shuffled/uk_dedup.txt.gz) | 56 560 011 | 2 250 210 650 | 29 705 050 592 |
|
||||
| Sampled mentions from social networks | 11 245 710 | 128 461 796 | 1 632 567 763 |
|
||||
| Total | 85 807 187 | 2 579 880 185 | 33 985 510 302 |
|
||||
|
||||
## Pre-training details
|
||||
|
||||
* Ukrainian Roberta was trained with code provided in [HuggingFace tutorial](https://huggingface.co/blog/how-to-train)
|
||||
* Currently released model follows roberta-base-cased model architecture (12-layer, 768-hidden, 12-heads, 125M parameters)
|
||||
* The model was trained on 4xV100 (85 hours)
|
||||
* Training configuration you can find in the [original repository](https://github.com/youscan/language-models)
|
||||
|
||||
## Author
|
||||
Vitalii Radchenko - contact me on Twitter [@vitaliradchenko](https://twitter.com/vitaliradchenko)
|
||||
@@ -27,6 +27,7 @@ from .configuration_bert import BERT_PRETRAINED_CONFIG_ARCHIVE_MAP, BertConfig
|
||||
from .configuration_camembert import CAMEMBERT_PRETRAINED_CONFIG_ARCHIVE_MAP, CamembertConfig
|
||||
from .configuration_ctrl import CTRL_PRETRAINED_CONFIG_ARCHIVE_MAP, CTRLConfig
|
||||
from .configuration_distilbert import DISTILBERT_PRETRAINED_CONFIG_ARCHIVE_MAP, DistilBertConfig
|
||||
from .configuration_dpr import DPR_PRETRAINED_CONFIG_ARCHIVE_MAP, DPRConfig
|
||||
from .configuration_electra import ELECTRA_PRETRAINED_CONFIG_ARCHIVE_MAP, ElectraConfig
|
||||
from .configuration_encoder_decoder import EncoderDecoderConfig
|
||||
from .configuration_flaubert import FLAUBERT_PRETRAINED_CONFIG_ARCHIVE_MAP, FlaubertConfig
|
||||
@@ -129,6 +130,14 @@ from .tokenization_bert_japanese import BertJapaneseTokenizer, CharacterTokenize
|
||||
from .tokenization_camembert import CamembertTokenizer
|
||||
from .tokenization_ctrl import CTRLTokenizer
|
||||
from .tokenization_distilbert import DistilBertTokenizer, DistilBertTokenizerFast
|
||||
from .tokenization_dpr import (
|
||||
DPRContextEncoderTokenizer,
|
||||
DPRContextEncoderTokenizerFast,
|
||||
DPRQuestionEncoderTokenizer,
|
||||
DPRQuestionEncoderTokenizerFast,
|
||||
DPRReaderTokenizer,
|
||||
DPRReaderTokenizerFast,
|
||||
)
|
||||
from .tokenization_electra import ElectraTokenizer, ElectraTokenizerFast
|
||||
from .tokenization_flaubert import FlaubertTokenizer
|
||||
from .tokenization_gpt2 import GPT2Tokenizer, GPT2TokenizerFast
|
||||
@@ -382,6 +391,14 @@ if is_torch_available():
|
||||
LONGFORMER_PRETRAINED_MODEL_ARCHIVE_LIST,
|
||||
)
|
||||
|
||||
from .modeling_dpr import (
|
||||
DPRPretrainedContextEncoder,
|
||||
DPRPretrainedQuestionEncoder,
|
||||
DPRPretrainedReader,
|
||||
DPRContextEncoder,
|
||||
DPRQuestionEncoder,
|
||||
DPRReader,
|
||||
)
|
||||
from .modeling_retribert import (
|
||||
RetriBertPreTrainedModel,
|
||||
RetriBertModel,
|
||||
@@ -399,9 +416,21 @@ if is_torch_available():
|
||||
)
|
||||
|
||||
# Trainer
|
||||
from .trainer import Trainer, torch_distributed_zero_first
|
||||
from .data.data_collator import default_data_collator, DataCollator, DataCollatorForLanguageModeling
|
||||
from .data.datasets import GlueDataset, TextDataset, LineByLineTextDataset, GlueDataTrainingArguments
|
||||
from .trainer import Trainer, set_seed, torch_distributed_zero_first, EvalPrediction
|
||||
from .data.data_collator import (
|
||||
default_data_collator,
|
||||
DataCollator,
|
||||
DataCollatorForLanguageModeling,
|
||||
DataCollatorForPermutationLanguageModeling,
|
||||
)
|
||||
from .data.datasets import (
|
||||
GlueDataset,
|
||||
TextDataset,
|
||||
LineByLineTextDataset,
|
||||
GlueDataTrainingArguments,
|
||||
SquadDataset,
|
||||
SquadDataTrainingArguments,
|
||||
)
|
||||
|
||||
# Benchmarks
|
||||
from .benchmark.benchmark import PyTorchBenchmark
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2010, DPR 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.
|
||||
""" DPR model configuration """
|
||||
|
||||
|
||||
import logging
|
||||
|
||||
from .configuration_bert import BertConfig
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
DPR_PRETRAINED_CONFIG_ARCHIVE_MAP = {
|
||||
"facebook/dpr-ctx_encoder-single-nq-base": "https://s3.amazonaws.com/models.huggingface.co/bert/facebook/dpr-ctx_encoder-single-nq-base/config.json",
|
||||
"facebook/dpr-question_encoder-single-nq-base": "https://s3.amazonaws.com/models.huggingface.co/bert/facebook/dpr-question_encoder-single-nq-base/config.json",
|
||||
"facebook/dpr-reader-single-nq-base": "https://s3.amazonaws.com/models.huggingface.co/bert/facebook/dpr-reader-single-nq-base/config.json",
|
||||
}
|
||||
|
||||
|
||||
class DPRConfig(BertConfig):
|
||||
r"""
|
||||
:class:`~transformers.DPRConfig` is the configuration class to store the configuration of a
|
||||
`DPRModel`.
|
||||
|
||||
This is the configuration class to store the configuration of a `DPRContextEncoder`, `DPRQuestionEncoder`, or a `DPRReader`.
|
||||
It is used to instantiate the components of the DPR model.
|
||||
|
||||
Args:
|
||||
projection_dim (:obj:`int`, optional, defaults to 0):
|
||||
Dimension of the projection for the context and question encoders.
|
||||
If it is set to zero (default), then no projection is done.
|
||||
"""
|
||||
model_type = "dpr"
|
||||
|
||||
def __init__(self, projection_dim: int = 0, **kwargs): # projection of the encoders, 0 for no projection
|
||||
super().__init__(**kwargs)
|
||||
self.projection_dim = projection_dim
|
||||
@@ -0,0 +1,120 @@
|
||||
import argparse
|
||||
import collections
|
||||
from pathlib import Path
|
||||
|
||||
import torch
|
||||
from torch.serialization import default_restore_location
|
||||
|
||||
from transformers import BertConfig, DPRConfig, DPRContextEncoder, DPRQuestionEncoder, DPRReader
|
||||
|
||||
|
||||
CheckpointState = collections.namedtuple(
|
||||
"CheckpointState", ["model_dict", "optimizer_dict", "scheduler_dict", "offset", "epoch", "encoder_params"]
|
||||
)
|
||||
|
||||
|
||||
def load_states_from_checkpoint(model_file: str) -> CheckpointState:
|
||||
print("Reading saved model from %s", model_file)
|
||||
state_dict = torch.load(model_file, map_location=lambda s, l: default_restore_location(s, "cpu"))
|
||||
return CheckpointState(**state_dict)
|
||||
|
||||
|
||||
class DPRState:
|
||||
def __init__(self, src_file: Path):
|
||||
self.src_file = src_file
|
||||
|
||||
def load_dpr_model(self):
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
def from_type(comp_type: str, *args, **kwargs) -> "DPRState":
|
||||
if comp_type.startswith("c"):
|
||||
return DPRContextEncoderState(*args, **kwargs)
|
||||
if comp_type.startswith("q"):
|
||||
return DPRQuestionEncoderState(*args, **kwargs)
|
||||
if comp_type.startswith("r"):
|
||||
return DPRReaderState(*args, **kwargs)
|
||||
else:
|
||||
raise ValueError("Component type must be either 'ctx_encoder', 'question_encoder' or 'reader'.")
|
||||
|
||||
|
||||
class DPRContextEncoderState(DPRState):
|
||||
def load_dpr_model(self):
|
||||
model = DPRContextEncoder(DPRConfig(**BertConfig.get_config_dict("bert-base-uncased")[0]))
|
||||
print("Loading DPR biencoder from {}".format(self.src_file))
|
||||
saved_state = load_states_from_checkpoint(self.src_file)
|
||||
encoder, prefix = model.ctx_encoder, "ctx_model."
|
||||
state_dict = {}
|
||||
for key, value in saved_state.model_dict.items():
|
||||
if key.startswith(prefix):
|
||||
key = key[len(prefix) :]
|
||||
if not key.startswith("encode_proj."):
|
||||
key = "bert_model." + key
|
||||
state_dict[key] = value
|
||||
encoder.load_state_dict(state_dict)
|
||||
return model
|
||||
|
||||
|
||||
class DPRQuestionEncoderState(DPRState):
|
||||
def load_dpr_model(self):
|
||||
model = DPRQuestionEncoder(DPRConfig(**BertConfig.get_config_dict("bert-base-uncased")[0]))
|
||||
print("Loading DPR biencoder from {}".format(self.src_file))
|
||||
saved_state = load_states_from_checkpoint(self.src_file)
|
||||
encoder, prefix = model.question_encoder, "question_model."
|
||||
state_dict = {}
|
||||
for key, value in saved_state.model_dict.items():
|
||||
if key.startswith(prefix):
|
||||
key = key[len(prefix) :]
|
||||
if not key.startswith("encode_proj."):
|
||||
key = "bert_model." + key
|
||||
state_dict[key] = value
|
||||
encoder.load_state_dict(state_dict)
|
||||
return model
|
||||
|
||||
|
||||
class DPRReaderState(DPRState):
|
||||
def load_dpr_model(self):
|
||||
model = DPRReader(DPRConfig(**BertConfig.get_config_dict("bert-base-uncased")[0]))
|
||||
print("Loading DPR reader from {}".format(self.src_file))
|
||||
saved_state = load_states_from_checkpoint(self.src_file)
|
||||
state_dict = {}
|
||||
for key, value in saved_state.model_dict.items():
|
||||
if key.startswith("encoder.") and not key.startswith("encoder.encode_proj"):
|
||||
key = "encoder.bert_model." + key[len("encoder.") :]
|
||||
state_dict[key] = value
|
||||
model.span_predictor.load_state_dict(state_dict)
|
||||
return model
|
||||
|
||||
|
||||
def convert(comp_type: str, src_file: Path, dest_dir: Path):
|
||||
dest_dir = Path(dest_dir)
|
||||
dest_dir.mkdir(exist_ok=True)
|
||||
|
||||
dpr_state = DPRState.from_type(comp_type, src_file=src_file)
|
||||
model = dpr_state.load_dpr_model()
|
||||
model.save_pretrained(dest_dir)
|
||||
model.from_pretrained(dest_dir) # sanity check
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
# Required parameters
|
||||
parser.add_argument(
|
||||
"--type", type=str, help="Type of the component to convert: 'ctx_encoder', 'question_encoder' or 'reader'."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--src",
|
||||
type=str,
|
||||
help="Path to the dpr checkpoint file. They can be downloaded from the official DPR repo https://github.com/facebookresearch/DPR. Note that in the official repo, both encoders are stored in the 'retriever' checkpoints.",
|
||||
)
|
||||
parser.add_argument("--dest", type=str, default=None, help="Path to the output PyTorch model directory.")
|
||||
args = parser.parse_args()
|
||||
|
||||
src_file = Path(args.src)
|
||||
dest_dir = f"converted-{src_file.name}" if args.dest is None else args.dest
|
||||
dest_dir = Path(dest_dir)
|
||||
assert src_file.exists()
|
||||
assert (
|
||||
args.type is not None
|
||||
), "Please specify the component type of the DPR model to convert: 'ctx_encoder', 'question_encoder' or 'reader'."
|
||||
convert(args.type, src_file, dest_dir)
|
||||
@@ -21,8 +21,8 @@ def default_data_collator(features: List[InputDataClass]) -> Dict[str, torch.Ten
|
||||
Very simple data collator that:
|
||||
- simply collates batches of dict-like objects
|
||||
- Performs special handling for potential keys named:
|
||||
- `label`: handles a single value (int or float) per object
|
||||
- `label_ids`: handles a list of values per object
|
||||
- ``label``: handles a single value (int or float) per object
|
||||
- ``label_ids``: handles a list of values per object
|
||||
- does not do any additional preprocessing
|
||||
|
||||
i.e., Property names of the input object will be used as corresponding inputs to the model.
|
||||
@@ -134,3 +134,126 @@ class DataCollatorForLanguageModeling:
|
||||
|
||||
# The rest of the time (10% of the time) we keep the masked input tokens unchanged
|
||||
return inputs, labels
|
||||
|
||||
|
||||
@dataclass
|
||||
class DataCollatorForPermutationLanguageModeling:
|
||||
"""
|
||||
Data collator used for permutation language modeling.
|
||||
- collates batches of tensors, honoring their tokenizer's pad_token
|
||||
- preprocesses batches for permutation language modeling with procedures specific to XLNet
|
||||
"""
|
||||
|
||||
tokenizer: PreTrainedTokenizer
|
||||
plm_probability: float = 1 / 6
|
||||
max_span_length: int = 5 # maximum length of a span of masked tokens
|
||||
|
||||
def __call__(self, examples: List[torch.Tensor]) -> Dict[str, torch.Tensor]:
|
||||
batch = self._tensorize_batch(examples)
|
||||
inputs, perm_mask, target_mapping, labels = self.mask_tokens(batch)
|
||||
return {"input_ids": inputs, "perm_mask": perm_mask, "target_mapping": target_mapping, "labels": labels}
|
||||
|
||||
def _tensorize_batch(self, examples: List[torch.Tensor]) -> torch.Tensor:
|
||||
length_of_first = examples[0].size(0)
|
||||
are_tensors_same_length = all(x.size(0) == length_of_first for x in examples)
|
||||
if are_tensors_same_length:
|
||||
return torch.stack(examples, dim=0)
|
||||
else:
|
||||
if self.tokenizer._pad_token is None:
|
||||
raise ValueError(
|
||||
"You are attempting to pad samples but the tokenizer you are using"
|
||||
f" ({self.tokenizer.__class__.__name__}) does not have one."
|
||||
)
|
||||
return pad_sequence(examples, batch_first=True, padding_value=self.tokenizer.pad_token_id)
|
||||
|
||||
def mask_tokens(self, inputs: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
|
||||
"""
|
||||
The masked tokens to be predicted for a particular sequence are determined by the following algorithm:
|
||||
0. Start from the beginning of the sequence by setting ``cur_len = 0`` (number of tokens processed so far).
|
||||
1. Sample a ``span_length`` from the interval ``[1, max_span_length]`` (length of span of tokens to be masked)
|
||||
2. Reserve a context of length ``context_length = span_length / plm_probability`` to surround span to be masked
|
||||
3. Sample a starting point ``start_index`` from the interval ``[cur_len, cur_len + context_length - span_length]`` and mask tokens ``start_index:start_index + span_length``
|
||||
4. Set ``cur_len = cur_len + context_length``. If ``cur_len < max_len`` (i.e. there are tokens remaining in the sequence to be processed), repeat from Step 1.
|
||||
"""
|
||||
|
||||
if self.tokenizer.mask_token is None:
|
||||
raise ValueError(
|
||||
"This tokenizer does not have a mask token which is necessary for permutation language modeling. Please add a mask token if you want to use this tokenizer."
|
||||
)
|
||||
|
||||
if inputs.size(1) % 2 != 0:
|
||||
raise ValueError(
|
||||
"This collator requires that sequence lengths be even to create a leakage-free perm_mask. Please see relevant comments in source code for details."
|
||||
)
|
||||
|
||||
labels = inputs.clone()
|
||||
# Creating the mask and target_mapping tensors
|
||||
masked_indices = torch.full(labels.shape, 0, dtype=torch.bool)
|
||||
target_mapping = torch.zeros((labels.size(0), labels.size(1), labels.size(1)), dtype=torch.float32)
|
||||
|
||||
for i in range(labels.size(0)):
|
||||
# Start from the beginning of the sequence by setting `cur_len = 0` (number of tokens processed so far).
|
||||
cur_len = 0
|
||||
max_len = labels.size(1)
|
||||
|
||||
while cur_len < max_len:
|
||||
# Sample a `span_length` from the interval `[1, max_span_length]` (length of span of tokens to be masked)
|
||||
span_length = torch.randint(1, self.max_span_length + 1, (1,)).item()
|
||||
# Reserve a context of length `context_length = span_length / plm_probability` to surround the span to be masked
|
||||
context_length = int(span_length / self.plm_probability)
|
||||
# Sample a starting point `start_index` from the interval `[cur_len, cur_len + context_length - span_length]` and mask tokens `start_index:start_index + span_length`
|
||||
start_index = cur_len + torch.randint(context_length - span_length + 1, (1,)).item()
|
||||
masked_indices[i, start_index : start_index + span_length] = 1
|
||||
# Set `cur_len = cur_len + context_length`
|
||||
cur_len += context_length
|
||||
|
||||
# Since we're replacing non-masked tokens with -100 in the labels tensor instead of skipping them altogether,
|
||||
# the i-th predict corresponds to the i-th token.
|
||||
target_mapping[i] = torch.eye(labels.size(1))
|
||||
|
||||
special_tokens_mask = torch.tensor(
|
||||
[self.tokenizer.get_special_tokens_mask(val, already_has_special_tokens=True) for val in labels.tolist()],
|
||||
dtype=torch.bool,
|
||||
)
|
||||
masked_indices.masked_fill_(special_tokens_mask, value=0.0)
|
||||
if self.tokenizer._pad_token is not None:
|
||||
padding_mask = labels.eq(self.tokenizer.pad_token_id)
|
||||
masked_indices.masked_fill_(padding_mask, value=0.0)
|
||||
|
||||
# Mask indicating non-functional tokens, where functional tokens are [SEP], [CLS], padding, etc.
|
||||
non_func_mask = ~(padding_mask & special_tokens_mask)
|
||||
|
||||
inputs[masked_indices] = self.tokenizer.mask_token_id
|
||||
labels[~masked_indices] = -100 # We only compute loss on masked tokens
|
||||
|
||||
perm_mask = torch.zeros((labels.size(0), labels.size(1), labels.size(1)), dtype=torch.float32)
|
||||
|
||||
for i in range(labels.size(0)):
|
||||
# Generate permutation indices i.e. sample a random factorisation order for the sequence. This will
|
||||
# determine which tokens a given token can attend to (encoded in `perm_mask`).
|
||||
# Note: Length of token sequence being permuted has to be less than or equal to reused sequence length
|
||||
# (see documentation for `mems`), otherwise information may leak through due to reuse. In this implementation,
|
||||
# we assume that reused length is half of sequence length and permutation length is equal to reused length.
|
||||
# This requires that the sequence length be even.
|
||||
|
||||
# Create a linear factorisation order
|
||||
perm_index = torch.arange(labels.size(1))
|
||||
# Split this into two halves, assuming that half the sequence is reused each time
|
||||
perm_index = perm_index.reshape((-1, labels.size(1) // 2)).transpose(0, 1)
|
||||
# Permute the two halves such that they do not cross over
|
||||
perm_index = perm_index[torch.randperm(labels.size(1) // 2)]
|
||||
# Flatten this out into the desired permuted factorisation order
|
||||
perm_index = torch.flatten(perm_index.transpose(0, 1))
|
||||
# Set the permutation indices of non-masked (non-functional) tokens to the
|
||||
# smallest index (-1) so that:
|
||||
# (1) They can be seen by all other positions
|
||||
# (2) They cannot see masked positions, so there won't be information leak
|
||||
perm_index.masked_fill_(~masked_indices[i] & non_func_mask[i], -1)
|
||||
# The logic for whether the i-th token can attend on the j-th token based on the factorisation order:
|
||||
# 0 (can attend): If perm_index[i] > perm_index[j] or j is neither masked nor a functional token
|
||||
# 1 (cannot attend): If perm_index[i] <= perm_index[j] and j is either masked or a functional token
|
||||
perm_mask[i] = (
|
||||
perm_index.reshape((labels.size(1), 1)) <= perm_index.reshape((1, labels.size(1)))
|
||||
) & masked_indices[i]
|
||||
|
||||
return inputs, perm_mask, target_mapping, labels
|
||||
@@ -4,3 +4,4 @@
|
||||
|
||||
from .glue import GlueDataset, GlueDataTrainingArguments
|
||||
from .language_modeling import LineByLineTextDataset, TextDataset
|
||||
from .squad import SquadDataset, SquadDataTrainingArguments
|
||||
@@ -0,0 +1,189 @@
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
import torch
|
||||
from filelock import FileLock
|
||||
from torch.utils.data.dataset import Dataset
|
||||
|
||||
from ...modeling_auto import MODEL_FOR_QUESTION_ANSWERING_MAPPING
|
||||
from ...tokenization_utils import PreTrainedTokenizer
|
||||
from ..processors.squad import SquadFeatures, SquadV1Processor, SquadV2Processor, squad_convert_examples_to_features
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
MODEL_CONFIG_CLASSES = list(MODEL_FOR_QUESTION_ANSWERING_MAPPING.keys())
|
||||
MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES)
|
||||
|
||||
|
||||
@dataclass
|
||||
class SquadDataTrainingArguments:
|
||||
"""
|
||||
Arguments pertaining to what data we are going to input our model for training and eval.
|
||||
"""
|
||||
|
||||
model_type: str = field(
|
||||
default=None, metadata={"help": "Model type selected in the list: " + ", ".join(MODEL_TYPES)}
|
||||
)
|
||||
data_dir: str = field(
|
||||
default=None, metadata={"help": "The input data dir. Should contain the .json files for the SQuAD task."}
|
||||
)
|
||||
max_seq_length: int = field(
|
||||
default=128,
|
||||
metadata={
|
||||
"help": "The maximum total input sequence length after tokenization. Sequences longer "
|
||||
"than this will be truncated, sequences shorter will be padded."
|
||||
},
|
||||
)
|
||||
doc_stride: int = field(
|
||||
default=128,
|
||||
metadata={"help": "When splitting up a long document into chunks, how much stride to take between chunks."},
|
||||
)
|
||||
max_query_length: int = field(
|
||||
default=64,
|
||||
metadata={
|
||||
"help": "The maximum number of tokens for the question. Questions longer than this will "
|
||||
"be truncated to this length."
|
||||
},
|
||||
)
|
||||
max_answer_length: int = field(
|
||||
default=30,
|
||||
metadata={
|
||||
"help": "The maximum length of an answer that can be generated. This is needed because the start "
|
||||
"and end predictions are not conditioned on one another."
|
||||
},
|
||||
)
|
||||
overwrite_cache: bool = field(
|
||||
default=False, metadata={"help": "Overwrite the cached training and evaluation sets"}
|
||||
)
|
||||
version_2_with_negative: bool = field(
|
||||
default=False, metadata={"help": "If true, the SQuAD examples contain some that do not have an answer."}
|
||||
)
|
||||
null_score_diff_threshold: float = field(
|
||||
default=0.0, metadata={"help": "If null_score - best_non_null is greater than the threshold predict null."}
|
||||
)
|
||||
n_best_size: int = field(
|
||||
default=20, metadata={"help": "If null_score - best_non_null is greater than the threshold predict null."}
|
||||
)
|
||||
lang_id: int = field(
|
||||
default=0,
|
||||
metadata={
|
||||
"help": "language id of input for language-specific xlm models (see tokenization_xlm.PRETRAINED_INIT_CONFIGURATION)"
|
||||
},
|
||||
)
|
||||
threads: int = field(default=1, metadata={"help": "multiple threads for converting example to features"})
|
||||
|
||||
|
||||
class Split(Enum):
|
||||
train = "train"
|
||||
dev = "dev"
|
||||
|
||||
|
||||
class SquadDataset(Dataset):
|
||||
"""
|
||||
This will be superseded by a framework-agnostic approach
|
||||
soon.
|
||||
"""
|
||||
|
||||
args: SquadDataTrainingArguments
|
||||
features: List[SquadFeatures]
|
||||
mode: Split
|
||||
is_language_sensitive: bool
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
args: SquadDataTrainingArguments,
|
||||
tokenizer: PreTrainedTokenizer,
|
||||
limit_length: Optional[int] = None,
|
||||
mode: Union[str, Split] = Split.train,
|
||||
is_language_sensitive: Optional[bool] = False,
|
||||
cache_dir: Optional[str] = None,
|
||||
):
|
||||
self.args = args
|
||||
self.is_language_sensitive = is_language_sensitive
|
||||
self.processor = SquadV2Processor() if args.version_2_with_negative else SquadV1Processor()
|
||||
if isinstance(mode, str):
|
||||
try:
|
||||
mode = Split[mode]
|
||||
except KeyError:
|
||||
raise KeyError("mode is not a valid split name")
|
||||
self.mode = mode
|
||||
# Load data features from cache or dataset file
|
||||
cached_features_file = os.path.join(
|
||||
cache_dir if cache_dir is not None else args.data_dir,
|
||||
"cached_{}_{}_{}".format(mode.value, tokenizer.__class__.__name__, str(args.max_seq_length),),
|
||||
)
|
||||
|
||||
# Make sure only the first process in distributed training processes the dataset,
|
||||
# and the others will use the cache.
|
||||
lock_path = cached_features_file + ".lock"
|
||||
with FileLock(lock_path):
|
||||
if os.path.exists(cached_features_file) and not args.overwrite_cache:
|
||||
start = time.time()
|
||||
self.features = torch.load(cached_features_file)
|
||||
logger.info(
|
||||
f"Loading features from cached file {cached_features_file} [took %.3f s]", time.time() - start
|
||||
)
|
||||
else:
|
||||
if mode == Split.dev:
|
||||
examples = self.processor.get_dev_examples(args.data_dir)
|
||||
else:
|
||||
examples = self.processor.get_train_examples(args.data_dir)
|
||||
|
||||
self.features = squad_convert_examples_to_features(
|
||||
examples=examples,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length,
|
||||
doc_stride=args.doc_stride,
|
||||
max_query_length=args.max_query_length,
|
||||
is_training=mode == Split.train,
|
||||
threads=args.threads,
|
||||
)
|
||||
|
||||
start = time.time()
|
||||
torch.save(self.features, cached_features_file)
|
||||
# ^ This seems to take a lot of time so I want to investigate why and how we can improve.
|
||||
logger.info(
|
||||
"Saving features into cached file %s [took %.3f s]", cached_features_file, time.time() - start
|
||||
)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.features)
|
||||
|
||||
def __getitem__(self, i) -> Dict[str, torch.Tensor]:
|
||||
# Convert to Tensors and build dataset
|
||||
feature = self.features[i]
|
||||
|
||||
input_ids = torch.tensor(feature.input_ids, dtype=torch.long)
|
||||
attention_mask = torch.tensor(feature.attention_mask, dtype=torch.long)
|
||||
token_type_ids = torch.tensor(feature.token_type_ids, dtype=torch.long)
|
||||
cls_index = torch.tensor(feature.cls_index, dtype=torch.long)
|
||||
p_mask = torch.tensor(feature.p_mask, dtype=torch.float)
|
||||
is_impossible = torch.tensor(feature.is_impossible, dtype=torch.float)
|
||||
|
||||
inputs = {
|
||||
"input_ids": input_ids,
|
||||
"attention_mask": attention_mask,
|
||||
"token_type_ids": token_type_ids,
|
||||
}
|
||||
|
||||
if self.args.model_type in ["xlm", "roberta", "distilbert", "camembert"]:
|
||||
del inputs["token_type_ids"]
|
||||
|
||||
if self.args.model_type in ["xlnet", "xlm"]:
|
||||
inputs.update({"cls_index": cls_index, "p_mask": p_mask})
|
||||
if self.args.version_2_with_negative:
|
||||
inputs.update({"is_impossible": is_impossible})
|
||||
if self.is_language_sensitive:
|
||||
inputs.update({"langs": (torch.ones(input_ids.shape, dtype=torch.int64) * self.args.lang_id)})
|
||||
|
||||
if self.mode == Split.train:
|
||||
start_positions = torch.tensor(feature.start_position, dtype=torch.long)
|
||||
end_positions = torch.tensor(feature.end_position, dtype=torch.long)
|
||||
inputs.update({"start_positions": start_positions, "end_positions": end_positions})
|
||||
|
||||
return inputs
|
||||
@@ -617,6 +617,8 @@ BERT_INPUTS_DOCSTRING = r"""
|
||||
``1`` for tokens that are NOT MASKED, ``0`` for MASKED tokens.
|
||||
output_attentions (:obj:`bool`, `optional`, defaults to :obj:`None`):
|
||||
If set to ``True``, the attentions tensors of all attention layers are returned. See ``attentions`` under returned tensors for more detail.
|
||||
output_hidden_states (:obj:`bool`, `optional`, defaults to :obj:`None`):
|
||||
If set to ``True``, the hidden states tensors of all layers are returned. See ``hidden_states`` under returned tensors for more detail.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,541 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 DPR 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.
|
||||
""" PyTorch DPR model for Open Domain Question Answering."""
|
||||
|
||||
|
||||
import logging
|
||||
from typing import Optional, Tuple
|
||||
|
||||
import torch
|
||||
from torch import Tensor, nn
|
||||
|
||||
from .configuration_dpr import DPRConfig
|
||||
from .file_utils import add_start_docstrings, add_start_docstrings_to_callable
|
||||
from .modeling_bert import BertModel
|
||||
from .modeling_utils import PreTrainedModel
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
DPR_CONTEXT_ENCODER_PRETRAINED_MODEL_ARCHIVE_LIST = [
|
||||
"facebook/dpr-ctx_encoder-single-nq-base",
|
||||
]
|
||||
DPR_QUESTION_ENCODER_PRETRAINED_MODEL_ARCHIVE_LIST = [
|
||||
"facebook/dpr-question_encoder-single-nq-base",
|
||||
]
|
||||
DPR_READER_PRETRAINED_MODEL_ARCHIVE_LIST = [
|
||||
"facebook/dpr-reader-single-nq-base",
|
||||
]
|
||||
|
||||
|
||||
class DPREncoder(PreTrainedModel):
|
||||
|
||||
base_model_prefix = "bert_model"
|
||||
|
||||
def __init__(self, config: DPRConfig):
|
||||
super().__init__(config)
|
||||
self.bert_model = BertModel(config)
|
||||
assert self.bert_model.config.hidden_size > 0, "Encoder hidden_size can't be zero"
|
||||
self.projection_dim = config.projection_dim
|
||||
if self.projection_dim > 0:
|
||||
self.encode_proj = nn.Linear(self.bert_model.config.hidden_size, config.projection_dim)
|
||||
self.init_weights()
|
||||
|
||||
def forward(
|
||||
self,
|
||||
input_ids: Tensor,
|
||||
attention_mask: Optional[Tensor] = None,
|
||||
token_type_ids: Optional[Tensor] = None,
|
||||
inputs_embeds: Optional[Tensor] = None,
|
||||
output_attentions: bool = False,
|
||||
output_hidden_states: bool = False,
|
||||
) -> Tuple[Tensor, ...]:
|
||||
outputs = self.bert_model(
|
||||
input_ids=input_ids,
|
||||
attention_mask=attention_mask,
|
||||
token_type_ids=token_type_ids,
|
||||
inputs_embeds=inputs_embeds,
|
||||
output_hidden_states=True,
|
||||
output_attentions=output_attentions,
|
||||
)
|
||||
sequence_output, pooled_output, hidden_states = outputs[:3]
|
||||
pooled_output = sequence_output[:, 0, :]
|
||||
if self.projection_dim > 0:
|
||||
pooled_output = self.encode_proj(pooled_output)
|
||||
|
||||
dpr_encoder_outputs = (sequence_output, pooled_output)
|
||||
|
||||
if output_hidden_states:
|
||||
dpr_encoder_outputs += (hidden_states,)
|
||||
if output_attentions:
|
||||
dpr_encoder_outputs += (outputs[-1],)
|
||||
|
||||
return dpr_encoder_outputs
|
||||
|
||||
@property
|
||||
def embeddings_size(self) -> int:
|
||||
if self.projection_dim > 0:
|
||||
return self.encode_proj.out_features
|
||||
return self.bert_model.config.hidden_size
|
||||
|
||||
def init_weights(self):
|
||||
self.bert_model.init_weights()
|
||||
if self.projection_dim > 0:
|
||||
self.encode_proj.apply(self.bert_model._init_weights)
|
||||
|
||||
|
||||
class DPRSpanPredictor(PreTrainedModel):
|
||||
|
||||
base_model_prefix = "encoder"
|
||||
|
||||
def __init__(self, config: DPRConfig):
|
||||
super().__init__(config)
|
||||
self.encoder = DPREncoder(config)
|
||||
self.qa_outputs = nn.Linear(self.encoder.embeddings_size, 2)
|
||||
self.qa_classifier = nn.Linear(self.encoder.embeddings_size, 1)
|
||||
self.init_weights()
|
||||
|
||||
def forward(
|
||||
self,
|
||||
input_ids: Tensor,
|
||||
attention_mask: Tensor,
|
||||
inputs_embeds: Optional[Tensor] = None,
|
||||
output_attentions: bool = False,
|
||||
output_hidden_states: bool = False,
|
||||
):
|
||||
# notations: N - number of questions in a batch, M - number of passages per questions, L - sequence length
|
||||
n_passages, sequence_length = input_ids.size() if input_ids is not None else inputs_embeds.size()[:2]
|
||||
# feed encoder
|
||||
outputs = self.encoder(
|
||||
input_ids,
|
||||
attention_mask=attention_mask,
|
||||
inputs_embeds=inputs_embeds,
|
||||
output_attentions=output_attentions,
|
||||
output_hidden_states=output_hidden_states,
|
||||
)
|
||||
sequence_output = outputs[0]
|
||||
|
||||
# compute logits
|
||||
logits = self.qa_outputs(sequence_output)
|
||||
start_logits, end_logits = logits.split(1, dim=-1)
|
||||
start_logits = start_logits.squeeze(-1)
|
||||
end_logits = end_logits.squeeze(-1)
|
||||
relevance_logits = self.qa_classifier(sequence_output[:, 0, :])
|
||||
# resize and return
|
||||
return (
|
||||
start_logits.view(n_passages, sequence_length),
|
||||
end_logits.view(n_passages, sequence_length),
|
||||
relevance_logits.view(n_passages),
|
||||
) + outputs[2:]
|
||||
|
||||
def init_weights(self):
|
||||
self.encoder.init_weights()
|
||||
|
||||
|
||||
##################
|
||||
# PreTrainedModel
|
||||
##################
|
||||
|
||||
|
||||
class DPRPretrainedContextEncoder(PreTrainedModel):
|
||||
""" An abstract class to handle weights initialization and
|
||||
a simple interface for downloading and loading pretrained models.
|
||||
"""
|
||||
|
||||
config_class = DPRConfig
|
||||
load_tf_weights = None
|
||||
base_model_prefix = "ctx_encoder"
|
||||
|
||||
def init_weights(self):
|
||||
self.ctx_encoder.init_weights()
|
||||
|
||||
|
||||
class DPRPretrainedQuestionEncoder(PreTrainedModel):
|
||||
""" An abstract class to handle weights initialization and
|
||||
a simple interface for downloading and loading pretrained models.
|
||||
"""
|
||||
|
||||
config_class = DPRConfig
|
||||
load_tf_weights = None
|
||||
base_model_prefix = "question_encoder"
|
||||
|
||||
def init_weights(self):
|
||||
self.question_encoder.init_weights()
|
||||
|
||||
|
||||
class DPRPretrainedReader(PreTrainedModel):
|
||||
""" An abstract class to handle weights initialization and
|
||||
a simple interface for downloading and loading pretrained models.
|
||||
"""
|
||||
|
||||
config_class = DPRConfig
|
||||
load_tf_weights = None
|
||||
base_model_prefix = "span_predictor"
|
||||
|
||||
def init_weights(self):
|
||||
self.span_predictor.encoder.init_weights()
|
||||
self.span_predictor.qa_classifier.apply(self.span_predictor.encoder.bert_model._init_weights)
|
||||
self.span_predictor.qa_outputs.apply(self.span_predictor.encoder.bert_model._init_weights)
|
||||
|
||||
|
||||
###############
|
||||
# Actual Models
|
||||
###############
|
||||
|
||||
|
||||
DPR_START_DOCSTRING = r"""
|
||||
|
||||
This model is a PyTorch `torch.nn.Module <https://pytorch.org/docs/stable/nn.html#torch.nn.Module>`_ sub-class.
|
||||
Use it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general
|
||||
usage and behavior.
|
||||
|
||||
Parameters:
|
||||
config (:class:`~transformers.DPRConfig`): Model configuration class with all the parameters of the model.
|
||||
Initializing with a config file does not load the weights associated with the model, only the configuration.
|
||||
Check out the :meth:`~transformers.PreTrainedModel.from_pretrained` method to load the model weights.
|
||||
"""
|
||||
|
||||
DPR_ENCODERS_INPUTS_DOCSTRING = r"""
|
||||
Args:
|
||||
input_ids: (:obj:``torch.LongTensor`` of shape ``(batch_size, sequence_length)``):
|
||||
Indices of input sequence tokens in the vocabulary.
|
||||
To match pre-training, DPR input sequence should be formatted with [CLS] and [SEP] tokens as follows:
|
||||
|
||||
(a) For sequence pairs (for a pair title+text for example):
|
||||
|
||||
``tokens: [CLS] is this jack ##son ##ville ? [SEP] no it is not . [SEP]``
|
||||
|
||||
``token_type_ids: 0 0 0 0 0 0 0 0 1 1 1 1 1 1``
|
||||
|
||||
(b) For single sequences (for a question for example):
|
||||
|
||||
``tokens: [CLS] the dog is hairy . [SEP]``
|
||||
|
||||
``token_type_ids: 0 0 0 0 0 0 0``
|
||||
|
||||
DPR is a model with absolute position embeddings so it's usually advised to pad the inputs on
|
||||
the right rather than the left.
|
||||
|
||||
Indices can be obtained using :class:`transformers.DPRTokenizer`.
|
||||
See :func:`transformers.PreTrainedTokenizer.encode` and
|
||||
:func:`transformers.PreTrainedTokenizer.convert_tokens_to_ids` for details.
|
||||
attention_mask: (:obj:``torch.FloatTensor`` of shape ``(batch_size, sequence_length)``, `optional`, defaults to :obj:`None`):
|
||||
Mask to avoid performing attention on padding token indices.
|
||||
Mask values selected in ``[0, 1]``:
|
||||
``1`` for tokens that are NOT MASKED, ``0`` for MASKED tokens.
|
||||
token_type_ids: (:obj:``torch.LongTensor`` of shape ``(batch_size, sequence_length)``, `optional`, defaults to :obj:`None`):
|
||||
Segment token indices to indicate first and second portions of the inputs.
|
||||
Indices are selected in ``[0, 1]``: ``0`` corresponds to a `sentence A` token, ``1``
|
||||
corresponds to a `sentence B` token
|
||||
inputs_embeds (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`, `optional`, defaults to :obj:`None`):
|
||||
Optionally, instead of passing :obj:`input_ids` you can choose to directly pass an embedded representation.
|
||||
This is useful if you want more control over how to convert `input_ids` indices into associated vectors
|
||||
output_attentions (:obj:`bool`, `optional`, defaults to :obj:`None`):
|
||||
If set to ``True``, the attentions tensors of all attention layers are returned. See ``attentions`` under returned tensors for more detail.
|
||||
output_hidden_states (:obj:`bool`, `optional`, defaults to :obj:`None`):
|
||||
If set to ``True``, the hidden states tensors of all layers are returned. See ``hidden_states`` under returned tensors for more detail.
|
||||
"""
|
||||
|
||||
DPR_READER_INPUTS_DOCSTRING = r"""
|
||||
Args:
|
||||
input_ids: (:obj:``torch.LongTensor`` of shape ``(n_passages, sequence_length)``):
|
||||
Indices of input sequence tokens in the vocabulary.
|
||||
It has to be a sequence triplet with 1) the question and 2) the passages titles and 3) the passages texts
|
||||
To match pre-training, DPR `input_ids` sequence should be formatted with [CLS] and [SEP] with the format:
|
||||
|
||||
[CLS] <question token ids> [SEP] <titles ids> [SEP] <texts ids>
|
||||
|
||||
DPR is a model with absolute position embeddings so it's usually advised to pad the inputs on
|
||||
the right rather than the left.
|
||||
|
||||
Indices can be obtained using :class:`transformers.DPRReaderTokenizer`.
|
||||
See :class:`transformers.DPRReaderTokenizer` for more details
|
||||
attention_mask: (:obj:torch.FloatTensor``, of shape ``(n_passages, sequence_length)``, `optional`, defaults to :obj:`None):
|
||||
Mask to avoid performing attention on padding token indices.
|
||||
Mask values selected in ``[0, 1]``:
|
||||
``1`` for tokens that are NOT MASKED, ``0`` for MASKED tokens.
|
||||
inputs_embeds (:obj:`torch.FloatTensor` of shape :obj:`(n_passages, sequence_length, hidden_size)`, `optional`, defaults to :obj:`None`):
|
||||
Optionally, instead of passing :obj:`input_ids` you can choose to directly pass an embedded representation.
|
||||
This is useful if you want more control over how to convert `input_ids` indices into associated vectors
|
||||
output_attentions (:obj:`bool`, `optional`, defaults to :obj:`None`):
|
||||
If set to ``True``, the attentions tensors of all attention layers are returned. See ``attentions`` under returned tensors for more detail.
|
||||
output_hidden_states (:obj:`bool`, `optional`, defaults to :obj:`None`):
|
||||
If set to ``True``, the hidden states tensors of all layers are returned. See ``hidden_states`` under returned tensors for more detail.
|
||||
"""
|
||||
|
||||
|
||||
@add_start_docstrings(
|
||||
"The bare DPRContextEncoder transformer outputting pooler outputs as context representations.",
|
||||
DPR_START_DOCSTRING,
|
||||
)
|
||||
class DPRContextEncoder(DPRPretrainedContextEncoder):
|
||||
def __init__(self, config: DPRConfig):
|
||||
super().__init__(config)
|
||||
self.config = config
|
||||
self.ctx_encoder = DPREncoder(config)
|
||||
self.init_weights()
|
||||
|
||||
@add_start_docstrings_to_callable(DPR_ENCODERS_INPUTS_DOCSTRING)
|
||||
def forward(
|
||||
self,
|
||||
input_ids: Optional[Tensor] = None,
|
||||
attention_mask: Optional[Tensor] = None,
|
||||
token_type_ids: Optional[Tensor] = None,
|
||||
inputs_embeds: Optional[Tensor] = None,
|
||||
output_attentions=None,
|
||||
output_hidden_states=None,
|
||||
) -> Tensor:
|
||||
r"""
|
||||
Return:
|
||||
:obj:`tuple(torch.FloatTensor)` comprising various elements depending on the configuration (:class:`~transformers.DPRConfig`) and inputs:
|
||||
pooler_output: (:obj:``torch.FloatTensor`` of shape ``(batch_size, embeddings_size)``):
|
||||
The DPR encoder outputs the `pooler_output` that corresponds to the context representation.
|
||||
Last layer hidden-state of the first token of the sequence (classification token)
|
||||
further processed by a Linear layer. This output is to be used to embed contexts for
|
||||
nearest neighbors queries with questions embeddings.
|
||||
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)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape
|
||||
:obj:`(batch_size, num_heads, sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
|
||||
Examples::
|
||||
|
||||
from transformers import DPRContextEncoder, DPRContextEncoderTokenizer
|
||||
tokenizer = DPRContextEncoderTokenizer.from_pretrained('facebook/dpr-ctx_encoder-single-nq-base')
|
||||
model = DPRContextEncoder.from_pretrained('facebook/dpr-ctx_encoder-single-nq-base')
|
||||
input_ids = tokenizer("Hello, is my dog cute ?", return_tensors='pt')["input_ids"]
|
||||
embeddings = model(input_ids)[0] # the embeddings of the given context.
|
||||
|
||||
"""
|
||||
|
||||
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
||||
output_hidden_states = (
|
||||
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
||||
)
|
||||
|
||||
if input_ids is not None and inputs_embeds is not None:
|
||||
raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
|
||||
elif input_ids is not None:
|
||||
input_shape = input_ids.size()
|
||||
elif inputs_embeds is not None:
|
||||
input_shape = inputs_embeds.size()[:-1]
|
||||
else:
|
||||
raise ValueError("You have to specify either input_ids or inputs_embeds")
|
||||
|
||||
device = input_ids.device if input_ids is not None else inputs_embeds.device
|
||||
|
||||
if attention_mask is None:
|
||||
attention_mask = (
|
||||
torch.ones(input_shape, device=device)
|
||||
if input_ids is None
|
||||
else (input_ids != self.config.pad_token_id)
|
||||
)
|
||||
if token_type_ids is None:
|
||||
token_type_ids = torch.zeros(input_shape, dtype=torch.long, device=device)
|
||||
|
||||
outputs = self.ctx_encoder(
|
||||
input_ids=input_ids,
|
||||
attention_mask=attention_mask,
|
||||
token_type_ids=token_type_ids,
|
||||
inputs_embeds=inputs_embeds,
|
||||
output_attentions=output_attentions,
|
||||
output_hidden_states=output_hidden_states,
|
||||
)
|
||||
sequence_output, pooled_output = outputs[:2]
|
||||
return (pooled_output,) + outputs[2:]
|
||||
|
||||
|
||||
@add_start_docstrings(
|
||||
"The bare DPRQuestionEncoder transformer outputting pooler outputs as question representations.",
|
||||
DPR_START_DOCSTRING,
|
||||
)
|
||||
class DPRQuestionEncoder(DPRPretrainedQuestionEncoder):
|
||||
def __init__(self, config: DPRConfig):
|
||||
super().__init__(config)
|
||||
self.config = config
|
||||
self.question_encoder = DPREncoder(config)
|
||||
self.init_weights()
|
||||
|
||||
@add_start_docstrings_to_callable(DPR_ENCODERS_INPUTS_DOCSTRING)
|
||||
def forward(
|
||||
self,
|
||||
input_ids: Optional[Tensor] = None,
|
||||
attention_mask: Optional[Tensor] = None,
|
||||
token_type_ids: Optional[Tensor] = None,
|
||||
inputs_embeds: Optional[Tensor] = None,
|
||||
output_attentions=None,
|
||||
output_hidden_states=None,
|
||||
) -> Tensor:
|
||||
r"""
|
||||
Return:
|
||||
:obj:`tuple(torch.FloatTensor)` comprising various elements depending on the configuration (:class:`~transformers.DPRConfig`) and inputs:
|
||||
pooler_output: (:obj:``torch.FloatTensor`` of shape ``(batch_size, embeddings_size)``):
|
||||
The DPR encoder outputs the `pooler_output` that corresponds to the question representation.
|
||||
Last layer hidden-state of the first token of the sequence (classification token)
|
||||
further processed by a Linear layer. This output is to be used to embed questions for
|
||||
nearest neighbors queries with context embeddings.
|
||||
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)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape
|
||||
:obj:`(batch_size, num_heads, sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
|
||||
Examples::
|
||||
|
||||
from transformers import DPRQuestionEncoder, DPRQuestionEncoderTokenizer
|
||||
tokenizer = DPRQuestionEncoderTokenizer.from_pretrained('facebook/dpr-question_encoder-single-nq-base')
|
||||
model = DPRQuestionEncoder.from_pretrained('facebook/dpr-question_encoder-single-nq-base')
|
||||
input_ids = tokenizer("Hello, is my dog cute ?", return_tensors='pt')["input_ids"]
|
||||
embeddings = model(input_ids)[0] # the embeddings of the given question.
|
||||
"""
|
||||
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
||||
output_hidden_states = (
|
||||
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
||||
)
|
||||
|
||||
if input_ids is not None and inputs_embeds is not None:
|
||||
raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
|
||||
elif input_ids is not None:
|
||||
input_shape = input_ids.size()
|
||||
elif inputs_embeds is not None:
|
||||
input_shape = inputs_embeds.size()[:-1]
|
||||
else:
|
||||
raise ValueError("You have to specify either input_ids or inputs_embeds")
|
||||
|
||||
device = input_ids.device if input_ids is not None else inputs_embeds.device
|
||||
|
||||
if attention_mask is None:
|
||||
attention_mask = (
|
||||
torch.ones(input_shape, device=device)
|
||||
if input_ids is None
|
||||
else (input_ids != self.config.pad_token_id)
|
||||
)
|
||||
if token_type_ids is None:
|
||||
token_type_ids = torch.zeros(input_shape, dtype=torch.long, device=device)
|
||||
|
||||
outputs = self.question_encoder(
|
||||
input_ids=input_ids,
|
||||
attention_mask=attention_mask,
|
||||
token_type_ids=token_type_ids,
|
||||
inputs_embeds=inputs_embeds,
|
||||
output_attentions=output_attentions,
|
||||
output_hidden_states=output_hidden_states,
|
||||
)
|
||||
sequence_output, pooled_output = outputs[:2]
|
||||
return (pooled_output,) + outputs[2:]
|
||||
|
||||
|
||||
@add_start_docstrings(
|
||||
"The bare DPRReader transformer outputting span predictions.", DPR_START_DOCSTRING,
|
||||
)
|
||||
class DPRReader(DPRPretrainedReader):
|
||||
def __init__(self, config: DPRConfig):
|
||||
super().__init__(config)
|
||||
self.config = config
|
||||
self.span_predictor = DPRSpanPredictor(config)
|
||||
self.init_weights()
|
||||
|
||||
@add_start_docstrings_to_callable(DPR_READER_INPUTS_DOCSTRING)
|
||||
def forward(
|
||||
self,
|
||||
input_ids: Optional[Tensor] = None,
|
||||
attention_mask: Optional[Tensor] = None,
|
||||
inputs_embeds: Optional[Tensor] = None,
|
||||
output_attentions: bool = None,
|
||||
output_hidden_states: bool = None,
|
||||
) -> Tuple[Tensor, ...]:
|
||||
r"""
|
||||
Return:
|
||||
:obj:`tuple(torch.FloatTensor)` comprising various elements depending on the configuration (:class:`~transformers.DPRConfig`) and inputs:
|
||||
input_ids: (:obj:``torch.FloatTensor`` of shape ``(n_passages, sequence_length)``)
|
||||
They correspond to the combined `input_ids` from `(question + context title + context content`).
|
||||
start_logits: (:obj:``torch.FloatTensor`` of shape ``(n_passages, sequence_length)``):
|
||||
Logits of the start index of the span for each passage.
|
||||
end_logits: (:obj:``torch.FloatTensor`` of shape ``(n_passages, sequence_length)``):
|
||||
Logits of the end index of the span for each passage.
|
||||
relevance_logits: (:obj:`torch.FloatTensor`` of shape ``(n_passages, )``):
|
||||
Outputs of the QA classifier of the DPRReader that corresponds to the scores of each passage
|
||||
to answer the question, compared to all the other passages.
|
||||
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)
|
||||
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||
|
||||
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``output_attentions=True`` is passed or when ``config.output_attentions=True``):
|
||||
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape
|
||||
:obj:`(batch_size, num_heads, sequence_length, sequence_length)`.
|
||||
|
||||
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||
heads.
|
||||
|
||||
Examples::
|
||||
|
||||
from transformers import DPRReader, DPRReaderTokenizer
|
||||
tokenizer = DPRReaderTokenizer.from_pretrained('facebook/dpr-reader-single-nq-base')
|
||||
model = DPRReader.from_pretrained('facebook/dpr-reader-single-nq-base')
|
||||
encoded_inputs = tokenizer(
|
||||
questions=["What is love ?"],
|
||||
titles=["Haddaway"],
|
||||
texts=["'What Is Love' is a song recorded by the artist Haddaway"],
|
||||
return_tensors='pt'
|
||||
)
|
||||
outputs = model(**encoded_inputs)
|
||||
start_logits = outputs[0] # The logits of the start of the spans
|
||||
end_logits = outputs[1] # The logits of the end of the spans
|
||||
relevance_logits = outputs[2] # The relevance scores of the passages
|
||||
|
||||
"""
|
||||
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
||||
output_hidden_states = (
|
||||
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
||||
)
|
||||
|
||||
if input_ids is not None and inputs_embeds is not None:
|
||||
raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
|
||||
elif input_ids is not None:
|
||||
input_shape = input_ids.size()
|
||||
elif inputs_embeds is not None:
|
||||
input_shape = inputs_embeds.size()[:-1]
|
||||
else:
|
||||
raise ValueError("You have to specify either input_ids or inputs_embeds")
|
||||
|
||||
device = input_ids.device if input_ids is not None else inputs_embeds.device
|
||||
|
||||
if attention_mask is None:
|
||||
attention_mask = torch.ones(input_shape, device=device)
|
||||
|
||||
span_outputs = self.span_predictor(
|
||||
input_ids,
|
||||
attention_mask,
|
||||
inputs_embeds=inputs_embeds,
|
||||
output_attentions=output_attentions,
|
||||
output_hidden_states=output_hidden_states,
|
||||
)
|
||||
start_logits, end_logits, relevance_logits = span_outputs[:3]
|
||||
|
||||
return (start_logits, end_logits, relevance_logits) + span_outputs[3:]
|
||||
@@ -373,7 +373,7 @@ class LSHSelfAttention(nn.Module, EfficientAttentionMixin):
|
||||
# use cached buckets for backprop only
|
||||
if buckets is None:
|
||||
# hash query key vectors into buckets
|
||||
buckets = self._hash_vectors(query_key_vectors, num_hashes)
|
||||
buckets = self._hash_vectors(query_key_vectors, num_hashes, attention_mask)
|
||||
|
||||
assert (
|
||||
int(buckets.shape[-1]) == num_hashes * sequence_length
|
||||
@@ -460,7 +460,7 @@ class LSHSelfAttention(nn.Module, EfficientAttentionMixin):
|
||||
|
||||
return LSHSelfAttentionOutput(hidden_states=out_vectors, attention_probs=attention_probs, buckets=buckets)
|
||||
|
||||
def _hash_vectors(self, vectors, num_hashes):
|
||||
def _hash_vectors(self, vectors, num_hashes, attention_mask):
|
||||
batch_size = vectors.shape[0]
|
||||
|
||||
# See https://arxiv.org/pdf/1509.02897.pdf
|
||||
@@ -514,6 +514,15 @@ class LSHSelfAttention(nn.Module, EfficientAttentionMixin):
|
||||
|
||||
cur_product = cur_product * bucket_factor
|
||||
|
||||
if attention_mask is not None:
|
||||
# add an extra bucket for padding tokens only
|
||||
num_buckets = num_buckets + 1
|
||||
# assign padding tokens extra bucket
|
||||
buckets_mask = attention_mask.to(torch.uint8)[:, None, None, :].expand(buckets.shape)
|
||||
buckets = torch.where(
|
||||
buckets_mask, buckets, torch.tensor(num_buckets - 1, dtype=torch.long, device=buckets.device)
|
||||
)
|
||||
|
||||
# buckets is now (Batch_size x Num_Attn_Heads x Num_Hashes x Seq_Len).
|
||||
# Next we add offsets so that bucket numbers from different hashing rounds don't overlap.
|
||||
offsets = torch.arange(num_hashes, device=vectors.device)
|
||||
@@ -614,7 +623,9 @@ class LSHSelfAttention(nn.Module, EfficientAttentionMixin):
|
||||
self_mask_value = self.self_mask_value_float32
|
||||
mask_value = self.mask_value_float32
|
||||
|
||||
mask = self._compute_attn_mask(query_bucket_idx, key_value_bucket_idx, attention_mask, sequence_length)
|
||||
mask = self._compute_attn_mask(
|
||||
query_bucket_idx, key_value_bucket_idx, attention_mask, query_key_dots.shape, sequence_length
|
||||
)
|
||||
|
||||
if mask is not None:
|
||||
query_key_dots = torch.where(mask, query_key_dots, mask_value)
|
||||
@@ -669,45 +680,32 @@ class LSHSelfAttention(nn.Module, EfficientAttentionMixin):
|
||||
|
||||
return out_vectors, logits, attention_probs
|
||||
|
||||
def _compute_attn_mask(self, query_indices, key_indices, attention_mask, sequence_length):
|
||||
mask = None
|
||||
def _compute_attn_mask(self, query_indices, key_indices, attention_mask, query_key_dot_shape, sequence_length):
|
||||
|
||||
# Causal mask
|
||||
if self.is_decoder:
|
||||
mask = torch.ge(query_indices.unsqueeze(-1), key_indices.unsqueeze(-2)).to(query_indices.device)
|
||||
|
||||
# Attention mask: chunk, look up correct mask value from key_value_bucket_idx
|
||||
# IMPORTANT: official trax code does not use a mask for LSH Atttention. Not sure why.
|
||||
# attention mask for LSH
|
||||
if attention_mask is not None:
|
||||
# if chunked attention, the attention mask has to correspond to LSH order
|
||||
attention_mask = attention_mask.to(torch.uint8)[:, None, :]
|
||||
if sequence_length > self.chunk_length:
|
||||
attention_mask = attention_mask.to(torch.uint8)[:, None, None, :]
|
||||
# expand attn_mask to fit with key_value_bucket_idx shape
|
||||
attention_mask = attention_mask[:, None, :]
|
||||
attention_mask = attention_mask.expand(query_indices.shape[:-1] + (-1,))
|
||||
key_attn_mask = torch.gather(attention_mask, -1, key_indices)
|
||||
query_attn_mask = torch.gather(attention_mask, -1, query_indices)
|
||||
# expand to query_key_dots shape: duplicate along query axis since key sorting is the same for each query position in chunk
|
||||
attn_mask = query_attn_mask.unsqueeze(-1) * key_attn_mask.unsqueeze(-2)
|
||||
# extract attention mask from LSH sorted key_indices
|
||||
attention_mask = torch.gather(attention_mask, -1, key_indices)
|
||||
|
||||
# free memory
|
||||
del query_attn_mask, key_attn_mask
|
||||
attention_mask = attention_mask.unsqueeze(-2).expand(query_key_dot_shape)
|
||||
|
||||
# Causal mask
|
||||
if self.is_decoder is True:
|
||||
causal_mask = torch.ge(query_indices.unsqueeze(-1), key_indices.unsqueeze(-2)).to(query_indices.device)
|
||||
|
||||
# add attention mask if not None
|
||||
if attention_mask is not None:
|
||||
attention_mask = causal_mask * attention_mask
|
||||
else:
|
||||
# usual attention mask creation
|
||||
attention_mask = attention_mask.to(torch.uint8)[:, None, :]
|
||||
attn_mask = (attention_mask.unsqueeze(-1) * attention_mask.unsqueeze(-2)).expand(
|
||||
query_indices.shape + attention_mask.shape[-1:]
|
||||
)
|
||||
attention_mask = causal_mask
|
||||
|
||||
# free memory
|
||||
del attention_mask
|
||||
|
||||
# multiply by casaul mask if necessary
|
||||
if mask is not None:
|
||||
mask = mask * attn_mask
|
||||
else:
|
||||
mask = attn_mask
|
||||
|
||||
return mask
|
||||
return attention_mask
|
||||
|
||||
def _len_and_dim_norm(self, vectors):
|
||||
"""
|
||||
@@ -923,7 +921,6 @@ class LocalSelfAttention(nn.Module, EfficientAttentionMixin):
|
||||
return LocalSelfAttentionOutput(hidden_states=out_vectors, attention_probs=attention_probs)
|
||||
|
||||
def _compute_attn_mask(self, query_indices, key_indices, attention_mask, query_key_dots_shape, sequence_length):
|
||||
mask = None
|
||||
|
||||
# chunk attention mask and look before and after
|
||||
if attention_mask is not None:
|
||||
@@ -931,24 +928,21 @@ class LocalSelfAttention(nn.Module, EfficientAttentionMixin):
|
||||
|
||||
if self.chunk_length < sequence_length:
|
||||
attention_mask = self._split_seq_length_dim_to(attention_mask, -1, self.chunk_length, 1)
|
||||
attention_mask_key = self._look_adjacent(attention_mask, self.num_chunks_before, self.num_chunks_after)
|
||||
else:
|
||||
attention_mask_key = attention_mask
|
||||
attention_mask = self._look_adjacent(attention_mask, self.num_chunks_before, self.num_chunks_after)
|
||||
# create attn_mask
|
||||
attention_mask = attention_mask.unsqueeze(-2).expand(query_key_dots_shape)
|
||||
|
||||
# Causal mask
|
||||
if self.is_decoder is True:
|
||||
mask = torch.ge(query_indices.unsqueeze(-1), key_indices.unsqueeze(-2)).to(query_indices.device)
|
||||
causal_mask = torch.ge(query_indices.unsqueeze(-1), key_indices.unsqueeze(-2)).to(query_indices.device)
|
||||
|
||||
# Attention mask
|
||||
if attention_mask is not None:
|
||||
# create attn_mask
|
||||
attn_mask = (attention_mask.unsqueeze(-1) * attention_mask_key.unsqueeze(-2)).expand(query_key_dots_shape)
|
||||
# multiply by casaul mask if necessary
|
||||
if mask is not None:
|
||||
mask = mask * attn_mask
|
||||
# add attention mask if not None
|
||||
if attention_mask is not None:
|
||||
attention_mask = causal_mask * attention_mask
|
||||
else:
|
||||
mask = attn_mask
|
||||
return mask
|
||||
attention_mask = causal_mask
|
||||
|
||||
return attention_mask
|
||||
|
||||
|
||||
class ReformerSelfOutput(nn.Module):
|
||||
|
||||
@@ -358,7 +358,10 @@ class T5Attention(nn.Module):
|
||||
else:
|
||||
present_key_value_state = (None,)
|
||||
|
||||
scores = torch.einsum("bnqd,bnkd->bnqk", q, k) # (bs, n_heads, qlen, klen)
|
||||
# (bs, n_heads, qlen, klen)
|
||||
scores = torch.matmul(
|
||||
q, k.transpose(3, 2)
|
||||
) # equivalent of torch.einsum("bnqd,bnkd->bnqk", q, k), compatible with onnx op>9
|
||||
|
||||
if position_bias is None:
|
||||
if not self.has_relative_attention_bias:
|
||||
@@ -818,7 +821,8 @@ T5_INPUTS_DOCSTRING = r"""
|
||||
Provide for sequence to sequence training. T5 uses the pad_token_id as the starting token for decoder_input_ids generation.
|
||||
If `decoder_past_key_value_states` is used, optionally only the last `decoder_input_ids` have to be input (see `decoder_past_key_value_states`).
|
||||
To know more on how to prepare :obj:`decoder_input_ids` for pre-training take a look at
|
||||
`T5 Training <./t5.html#training>`__.
|
||||
`T5 Training <./t5.html#training>`__. If decoder_input_ids and decoder_inputs_embeds are both None,
|
||||
decoder_input_ids takes the value of input_ids.
|
||||
decoder_attention_mask (:obj:`torch.BoolTensor` of shape :obj:`(batch_size, tgt_seq_len)`, `optional`, defaults to :obj:`None`):
|
||||
Default behavior: generate a tensor that ignores pad tokens in decoder_input_ids. Causal mask will also be used by default.
|
||||
decoder_past_key_value_states (:obj:`tuple(tuple(torch.FloatTensor))` of length :obj:`config.n_layers` with each tuple having 4 tensors of shape :obj:`(batch_size, num_heads, sequence_length - 1, embed_size_per_head)`):
|
||||
@@ -837,7 +841,8 @@ T5_INPUTS_DOCSTRING = r"""
|
||||
Optionally, instead of passing :obj:`decoder_input_ids` you can choose to directly pass an embedded representation.
|
||||
If `decoder_past_key_value_states` is used, optionally only the last `decoder_inputs_embeds` have to be input (see `decoder_past_key_value_states`).
|
||||
This is useful if you want more control over how to convert `decoder_input_ids` indices into associated vectors
|
||||
than the model's internal embedding lookup matrix.
|
||||
than the model's internal embedding lookup matrix. If decoder_input_ids and decoder_inputs_embeds are both None,
|
||||
decoder_inputs_embeds takes the value of inputs_embeds.
|
||||
head_mask: (:obj:`torch.FloatTensor` of shape :obj:`(num_heads,)` or :obj:`(num_layers, num_heads)`, `optional`, defaults to :obj:`None`):
|
||||
Mask to nullify selected heads of the self-attention modules.
|
||||
Mask values selected in ``[0, 1]``:
|
||||
@@ -934,7 +939,7 @@ class T5Model(T5PreTrainedModel):
|
||||
>>> model = T5Model.from_pretrained('t5-small')
|
||||
|
||||
>>> input_ids = tokenizer.encode("Hello, my dog is cute", return_tensors="pt") # Batch size 1
|
||||
>>> outputs = model(input_ids=input_ids, decoder_input_ids=input_ids)
|
||||
>>> outputs = model(input_ids=input_ids)
|
||||
|
||||
>>> last_hidden_states = outputs[0] # The last hidden-state is the first element of the output tuple
|
||||
"""
|
||||
@@ -953,6 +958,12 @@ class T5Model(T5PreTrainedModel):
|
||||
|
||||
hidden_states = encoder_outputs[0]
|
||||
|
||||
# If the model is only provided with either input_ids or inputs_embeds,
|
||||
# use them as the inputs of the decoder. self.encoder checks for input_ids XOR inputs_embeds
|
||||
if (decoder_input_ids is None) and (decoder_inputs_embeds is None):
|
||||
decoder_input_ids = input_ids
|
||||
decoder_inputs_embeds = inputs_embeds
|
||||
|
||||
# If decoding with past key value states, only the last tokens
|
||||
# should be given as an input
|
||||
if decoder_past_key_value_states is not None:
|
||||
@@ -1076,7 +1087,7 @@ class T5ForConditionalGeneration(T5PreTrainedModel):
|
||||
>>> tokenizer = T5Tokenizer.from_pretrained('t5-small')
|
||||
>>> model = T5ForConditionalGeneration.from_pretrained('t5-small')
|
||||
>>> input_ids = tokenizer.encode("Hello, my dog is cute", return_tensors="pt") # Batch size 1
|
||||
>>> outputs = model(input_ids=input_ids, decoder_input_ids=input_ids, labels=input_ids)
|
||||
>>> outputs = model(input_ids=input_ids, labels=input_ids)
|
||||
>>> loss, prediction_scores = outputs[:2]
|
||||
|
||||
>>> tokenizer = T5Tokenizer.from_pretrained('t5-small')
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2018 The HuggingFace Inc. team.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Tokenization classes for DPR."""
|
||||
|
||||
|
||||
import collections
|
||||
import logging
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from .file_utils import add_end_docstrings, add_start_docstrings
|
||||
from .tokenization_bert import BertTokenizer, BertTokenizerFast
|
||||
from .tokenization_utils_base import BatchEncoding, TensorType
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
VOCAB_FILES_NAMES = {"vocab_file": "vocab.txt"}
|
||||
|
||||
CONTEXT_ENCODER_PRETRAINED_VOCAB_FILES_MAP = {
|
||||
"vocab_file": {
|
||||
"facebook/dpr-ctx_encoder-single-nq-base": "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased-vocab.txt",
|
||||
}
|
||||
}
|
||||
QUESTION_ENCODER_PRETRAINED_VOCAB_FILES_MAP = {
|
||||
"vocab_file": {
|
||||
"facebook/dpr-question_encoder-single-nq-base": "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased-vocab.txt",
|
||||
}
|
||||
}
|
||||
READER_PRETRAINED_VOCAB_FILES_MAP = {
|
||||
"vocab_file": {
|
||||
"facebook/dpr-reader-single-nq-base": "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased-vocab.txt",
|
||||
}
|
||||
}
|
||||
|
||||
CONTEXT_ENCODER_PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES = {
|
||||
"facebook/dpr-ctx_encoder-single-nq-base": 512,
|
||||
}
|
||||
QUESTION_ENCODER_PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES = {
|
||||
"facebook/dpr-question_encoder-single-nq-base": 512,
|
||||
}
|
||||
READER_PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES = {
|
||||
"facebook/dpr-reader-single-nq-base": 512,
|
||||
}
|
||||
|
||||
|
||||
CONTEXT_ENCODER_PRETRAINED_INIT_CONFIGURATION = {
|
||||
"facebook/dpr-ctx_encoder-single-nq-base": {"do_lower_case": True},
|
||||
}
|
||||
QUESTION_ENCODER_PRETRAINED_INIT_CONFIGURATION = {
|
||||
"facebook/dpr-question_encoder-single-nq-base": {"do_lower_case": True},
|
||||
}
|
||||
READER_PRETRAINED_INIT_CONFIGURATION = {
|
||||
"facebook/dpr-reader-single-nq-base": {"do_lower_case": True},
|
||||
}
|
||||
|
||||
|
||||
class DPRContextEncoderTokenizer(BertTokenizer):
|
||||
r"""
|
||||
Constructs a DPRContextEncoderTokenizer.
|
||||
|
||||
:class:`~transformers.DPRContextEncoderTokenizer` is identical to :class:`~transformers.BertTokenizer` and runs end-to-end
|
||||
tokenization: punctuation splitting + wordpiece.
|
||||
|
||||
Refer to superclass :class:`~transformers.BertTokenizer` for usage examples and documentation concerning
|
||||
parameters.
|
||||
"""
|
||||
|
||||
vocab_files_names = VOCAB_FILES_NAMES
|
||||
pretrained_vocab_files_map = CONTEXT_ENCODER_PRETRAINED_VOCAB_FILES_MAP
|
||||
max_model_input_sizes = CONTEXT_ENCODER_PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
|
||||
pretrained_init_configuration = CONTEXT_ENCODER_PRETRAINED_INIT_CONFIGURATION
|
||||
|
||||
|
||||
class DPRContextEncoderTokenizerFast(BertTokenizerFast):
|
||||
r"""
|
||||
Constructs a "Fast" DPRContextEncoderTokenizer (backed by HuggingFace's `tokenizers` library).
|
||||
|
||||
:class:`~transformers.DPRContextEncoderTokenizerFast` is identical to :class:`~transformers.BertTokenizerFast` and runs end-to-end
|
||||
tokenization: punctuation splitting + wordpiece.
|
||||
|
||||
Refer to superclass :class:`~transformers.BertTokenizerFast` for usage examples and documentation concerning
|
||||
parameters.
|
||||
"""
|
||||
|
||||
vocab_files_names = VOCAB_FILES_NAMES
|
||||
pretrained_vocab_files_map = CONTEXT_ENCODER_PRETRAINED_VOCAB_FILES_MAP
|
||||
max_model_input_sizes = CONTEXT_ENCODER_PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
|
||||
pretrained_init_configuration = CONTEXT_ENCODER_PRETRAINED_INIT_CONFIGURATION
|
||||
|
||||
|
||||
class DPRQuestionEncoderTokenizer(BertTokenizer):
|
||||
r"""
|
||||
Constructs a DPRQuestionEncoderTokenizer.
|
||||
|
||||
:class:`~transformers.DPRQuestionEncoderTokenizer` is identical to :class:`~transformers.BertTokenizer` and runs end-to-end
|
||||
tokenization: punctuation splitting + wordpiece.
|
||||
|
||||
Refer to superclass :class:`~transformers.BertTokenizer` for usage examples and documentation concerning
|
||||
parameters.
|
||||
"""
|
||||
|
||||
vocab_files_names = VOCAB_FILES_NAMES
|
||||
pretrained_vocab_files_map = QUESTION_ENCODER_PRETRAINED_VOCAB_FILES_MAP
|
||||
max_model_input_sizes = QUESTION_ENCODER_PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
|
||||
pretrained_init_configuration = QUESTION_ENCODER_PRETRAINED_INIT_CONFIGURATION
|
||||
|
||||
|
||||
class DPRQuestionEncoderTokenizerFast(BertTokenizerFast):
|
||||
r"""
|
||||
Constructs a "Fast" DPRQuestionEncoderTokenizer (backed by HuggingFace's `tokenizers` library).
|
||||
|
||||
:class:`~transformers.DPRQuestionEncoderTokenizerFast` is identical to :class:`~transformers.BertTokenizerFast` and runs end-to-end
|
||||
tokenization: punctuation splitting + wordpiece.
|
||||
|
||||
Refer to superclass :class:`~transformers.BertTokenizerFast` for usage examples and documentation concerning
|
||||
parameters.
|
||||
"""
|
||||
|
||||
vocab_files_names = VOCAB_FILES_NAMES
|
||||
pretrained_vocab_files_map = QUESTION_ENCODER_PRETRAINED_VOCAB_FILES_MAP
|
||||
max_model_input_sizes = QUESTION_ENCODER_PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
|
||||
pretrained_init_configuration = QUESTION_ENCODER_PRETRAINED_INIT_CONFIGURATION
|
||||
|
||||
|
||||
DPRSpanPrediction = collections.namedtuple(
|
||||
"DPRSpanPrediction", ["span_score", "relevance_score", "doc_id", "start_index", "end_index", "text"]
|
||||
)
|
||||
|
||||
DPRReaderOutput = collections.namedtuple("DPRReaderOutput", ["start_logits", "end_logits", "relevance_logits"])
|
||||
|
||||
|
||||
CUSTOM_DPR_READER_DOCSTRING = r"""
|
||||
Return a dictionary with the token ids of the input strings and other information to give to :obj:`.decode_best_spans`.
|
||||
It converts the strings of a question and different passages (title + text) in a sequence of ids (integer), using the tokenizer and vocabulary.
|
||||
The resulting `input_ids` is a matrix of size :obj:`(n_passages, sequence_length)` with the format:
|
||||
|
||||
[CLS] <question token ids> [SEP] <titles ids> [SEP] <texts ids>
|
||||
|
||||
Inputs:
|
||||
questions (:obj:`str`, :obj:`List[str]`):
|
||||
The questions to be encoded.
|
||||
You can specify one question for many passages. In this case, the question will be duplicated like :obj:`[questions] * n_passages`.
|
||||
Otherwise you have to specify as many questions as in :obj:`titles` or :obj:`texts`.
|
||||
titles (:obj:`str`, :obj:`List[str]`):
|
||||
The passages titles to be encoded. This can be a string, a list of strings if there are several passages.
|
||||
texts (:obj:`str`, :obj:`List[str]`):
|
||||
The passages texts to be encoded. This can be a string, a list of strings if there are several passages.
|
||||
padding (:obj:`Union[bool, str]`, `optional`, defaults to :obj:`True`):
|
||||
Activate and control padding. Accepts the following values:
|
||||
|
||||
* `True` or `'longest'`: pad to the longest sequence in the batch (or no padding if only a single sequence if provided),
|
||||
* `'max_length'`: pad to a max length specified in `max_length` or to the max acceptable input length for the model if no length is provided (`max_length=None`)
|
||||
* `False` or `'do_not_pad'` (default): No padding (i.e. can output batch with sequences of uneven lengths)
|
||||
truncation (:obj:`Union[bool, str]`, `optional`, defaults to :obj:`True`):
|
||||
Activate and control truncation. Accepts the following values:
|
||||
|
||||
* `True` or `'only_first'`: truncate to a max length specified in `max_length` or to the max acceptable input length for the model if no length is provided (`max_length=None`).
|
||||
* `False` or `'do_not_truncate'` (default): No truncation (i.e. can output batch with sequences length greater than the model max admissible input size)
|
||||
max_length (:obj:`Union[int, None]`, `optional`, defaults to :obj:`None`):
|
||||
Control the length for padding/truncation. Accepts the following values
|
||||
|
||||
* `None` (default): This will use the predefined model max length if required by one of the truncation/padding parameters. If the model has no specific max input length (e.g. XLNet) truncation/padding to max length is deactivated.
|
||||
* `any integer value` (e.g. `42`): Use this specific maximum length value if required by one of the truncation/padding parameters.
|
||||
return_tensors (:obj:`str`, `optional`, defaults to :obj:`None`):
|
||||
Can be set to 'tf', 'pt' or 'np' to return respectively TensorFlow :obj:`tf.constant`,
|
||||
PyTorch :obj:`torch.Tensor` or Numpy :obj: `np.ndarray` instead of a list of python integers.
|
||||
return_attention_mask (:obj:`bool`, `optional`, defaults to :obj:`none`):
|
||||
Whether to return the attention mask. If left to the default, will return the attention mask according
|
||||
to the specific tokenizer's default, defined by the :obj:`return_outputs` attribute.
|
||||
|
||||
`What are attention masks? <../glossary.html#attention-mask>`__
|
||||
|
||||
Return:
|
||||
A Dictionary of shape::
|
||||
|
||||
{
|
||||
input_ids: list[list[int]],
|
||||
attention_mask: list[int] if return_attention_mask is True (default)
|
||||
}
|
||||
|
||||
With the fields:
|
||||
|
||||
- ``input_ids``: list of token ids to be fed to a model
|
||||
- ``attention_mask``: list of indices specifying which tokens should be attended to by the model
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@add_start_docstrings(CUSTOM_DPR_READER_DOCSTRING)
|
||||
class CustomDPRReaderTokenizerMixin:
|
||||
def __call__(
|
||||
self,
|
||||
questions,
|
||||
titles,
|
||||
texts,
|
||||
padding: Union[bool, str] = True,
|
||||
truncation: Union[bool, str] = True,
|
||||
max_length: Optional[int] = 512,
|
||||
return_tensors: Optional[Union[str, TensorType]] = None,
|
||||
return_attention_mask: Optional[bool] = None,
|
||||
**kwargs
|
||||
) -> BatchEncoding:
|
||||
titles = titles if not isinstance(titles, str) else [titles]
|
||||
texts = texts if not isinstance(texts, str) else [texts]
|
||||
n_passages = len(titles)
|
||||
questions = questions if not isinstance(questions, str) else [questions] * n_passages
|
||||
assert len(titles) == len(
|
||||
texts
|
||||
), "There should be as many titles than texts but got {} titles and {} texts.".format(len(titles), len(texts))
|
||||
encoded_question_and_titles = super().__call__(questions, titles, padding=False, truncation=False)["input_ids"]
|
||||
encoded_texts = super().__call__(texts, add_special_tokens=False, padding=False, truncation=False)["input_ids"]
|
||||
encoded_inputs = {
|
||||
"input_ids": [
|
||||
(encoded_question_and_title + encoded_text)[:max_length]
|
||||
if max_length is not None and truncation
|
||||
else encoded_question_and_title + encoded_text
|
||||
for encoded_question_and_title, encoded_text in zip(encoded_question_and_titles, encoded_texts)
|
||||
]
|
||||
}
|
||||
if return_attention_mask is not False:
|
||||
attention_mask = [input_ids != self.pad_token_id for input_ids in encoded_inputs["input_ids"]]
|
||||
encoded_inputs["attention_mask"] = attention_mask
|
||||
return self.pad(encoded_inputs, padding=padding, max_length=max_length, return_tensors=return_tensors)
|
||||
|
||||
def decode_best_spans(
|
||||
self,
|
||||
reader_input: BatchEncoding,
|
||||
reader_output: DPRReaderOutput,
|
||||
num_spans: int = 16,
|
||||
max_answer_length: int = 64,
|
||||
num_spans_per_passage: int = 4,
|
||||
) -> List[DPRSpanPrediction]:
|
||||
"""
|
||||
Get the span predictions for the extractive Q&A model.
|
||||
Outputs: `List` of `DPRReaderOutput` sorted by descending `(relevance_score, span_score)`.
|
||||
Each `DPRReaderOutput` is a `Tuple` with:
|
||||
**span_score**: ``float`` that corresponds to the score given by the reader for this span compared to other spans
|
||||
in the same passage. It corresponds to the sum of the start and end logits of the span.
|
||||
**relevance_score**: ``float`` that corresponds to the score of the each passage to answer the question,
|
||||
compared to all the other passages. It corresponds to the output of the QA classifier of the DPRReader.
|
||||
**doc_id**: ``int``` the id of the passage.
|
||||
**start_index**: ``int`` the start index of the span (inclusive).
|
||||
**end_index**: ``int`` the end index of the span (inclusive).
|
||||
|
||||
Examples::
|
||||
|
||||
from transformers import DPRReader, DPRReaderTokenizer
|
||||
tokenizer = DPRReaderTokenizer.from_pretrained('facebook/dpr-reader-single-nq-base')
|
||||
model = DPRReader.from_pretrained('facebook/dpr-reader-single-nq-base')
|
||||
encoded_inputs = tokenizer(
|
||||
questions=["What is love ?"],
|
||||
titles=["Haddaway"],
|
||||
texts=["'What Is Love' is a song recorded by the artist Haddaway"],
|
||||
return_tensors='pt'
|
||||
)
|
||||
outputs = model(**encoded_inputs)
|
||||
predicted_spans = tokenizer.decode_best_spans(encoded_inputs, outputs)
|
||||
print(predicted_spans[0].text) # best span
|
||||
|
||||
"""
|
||||
input_ids = reader_input["input_ids"]
|
||||
start_logits, end_logits, relevance_logits = reader_output[:3]
|
||||
n_passages = len(relevance_logits)
|
||||
sorted_docs = sorted(range(n_passages), reverse=True, key=relevance_logits.__getitem__)
|
||||
nbest_spans_predictions: List[DPRReaderOutput] = []
|
||||
for doc_id in sorted_docs:
|
||||
sequence_ids = list(input_ids[doc_id])
|
||||
# assuming question & title information is at the beginning of the sequence
|
||||
passage_offset = sequence_ids.index(self.sep_token_id, 2) + 1 # second sep id
|
||||
if sequence_ids[-1] == self.pad_token_id:
|
||||
sequence_len = sequence_ids.index(self.pad_token_id)
|
||||
else:
|
||||
sequence_len = len(sequence_ids)
|
||||
|
||||
best_spans = self._get_best_spans(
|
||||
start_logits=start_logits[doc_id][passage_offset:sequence_len],
|
||||
end_logits=end_logits[doc_id][passage_offset:sequence_len],
|
||||
max_answer_length=max_answer_length,
|
||||
top_spans=num_spans_per_passage,
|
||||
)
|
||||
for start_index, end_index in best_spans:
|
||||
start_index += passage_offset
|
||||
end_index += passage_offset
|
||||
nbest_spans_predictions.append(
|
||||
DPRSpanPrediction(
|
||||
span_score=start_logits[doc_id][start_index] + end_logits[doc_id][end_index],
|
||||
relevance_score=relevance_logits[doc_id],
|
||||
doc_id=doc_id,
|
||||
start_index=start_index,
|
||||
end_index=end_index,
|
||||
text=self.decode(sequence_ids[start_index : end_index + 1]),
|
||||
)
|
||||
)
|
||||
if len(nbest_spans_predictions) >= num_spans:
|
||||
break
|
||||
return nbest_spans_predictions[:num_spans]
|
||||
|
||||
def _get_best_spans(
|
||||
self, start_logits: List[int], end_logits: List[int], max_answer_length: int, top_spans: int,
|
||||
) -> List[DPRSpanPrediction]:
|
||||
"""
|
||||
Finds the best answer span for the extractive Q&A model for one passage.
|
||||
It returns the best span by descending `span_score` order and keeping max `top_spans` spans.
|
||||
Spans longer that `max_answer_length` are ignored.
|
||||
"""
|
||||
scores = []
|
||||
for (start_index, start_score) in enumerate(start_logits):
|
||||
for (answer_length, end_score) in enumerate(end_logits[start_index : start_index + max_answer_length]):
|
||||
scores.append(((start_index, start_index + answer_length), start_score + end_score))
|
||||
scores = sorted(scores, key=lambda x: x[1], reverse=True)
|
||||
chosen_span_intervals = []
|
||||
for (start_index, end_index), score in scores:
|
||||
assert start_index <= end_index, "Wrong span indices: [{}:{}]".format(start_index, end_index)
|
||||
length = end_index - start_index + 1
|
||||
assert length <= max_answer_length, "Span is too long: {} > {}".format(length, max_answer_length)
|
||||
if any(
|
||||
[
|
||||
start_index <= prev_start_index <= prev_end_index <= end_index
|
||||
or prev_start_index <= start_index <= end_index <= prev_end_index
|
||||
for (prev_start_index, prev_end_index) in chosen_span_intervals
|
||||
]
|
||||
):
|
||||
continue
|
||||
chosen_span_intervals.append((start_index, end_index))
|
||||
|
||||
if len(chosen_span_intervals) == top_spans:
|
||||
break
|
||||
return chosen_span_intervals
|
||||
|
||||
|
||||
@add_end_docstrings(CUSTOM_DPR_READER_DOCSTRING)
|
||||
class DPRReaderTokenizer(CustomDPRReaderTokenizerMixin, BertTokenizer):
|
||||
r"""
|
||||
Constructs a DPRReaderTokenizer.
|
||||
|
||||
:class:`~transformers.DPRReaderTokenizer` is alsmost identical to :class:`~transformers.BertTokenizer` and runs end-to-end
|
||||
tokenization: punctuation splitting + wordpiece.
|
||||
|
||||
What is different is that is has three inputs strings: question, titles and texts that are combined to feed into the DPRReader model.
|
||||
|
||||
Refer to superclass :class:`~transformers.BertTokenizer` for usage examples and documentation concerning
|
||||
parameters.
|
||||
|
||||
"""
|
||||
|
||||
vocab_files_names = VOCAB_FILES_NAMES
|
||||
pretrained_vocab_files_map = READER_PRETRAINED_VOCAB_FILES_MAP
|
||||
max_model_input_sizes = READER_PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
|
||||
pretrained_init_configuration = READER_PRETRAINED_INIT_CONFIGURATION
|
||||
model_input_names = ["attention_mask"]
|
||||
|
||||
|
||||
@add_end_docstrings(CUSTOM_DPR_READER_DOCSTRING)
|
||||
class DPRReaderTokenizerFast(CustomDPRReaderTokenizerMixin, BertTokenizerFast):
|
||||
r"""
|
||||
Constructs a DPRReaderTokenizerFast.
|
||||
|
||||
:class:`~transformers.DPRReaderTokenizerFast` is almost identical to :class:`~transformers.BertTokenizerFast` and runs end-to-end
|
||||
tokenization: punctuation splitting + wordpiece.
|
||||
|
||||
What is different is that is has three inputs strings: question, titles and texts that are combined to feed into the DPRReader model.
|
||||
|
||||
Refer to superclass :class:`~transformers.BertTokenizer` for usage examples and documentation concerning
|
||||
parameters.
|
||||
|
||||
"""
|
||||
|
||||
vocab_files_names = VOCAB_FILES_NAMES
|
||||
pretrained_vocab_files_map = READER_PRETRAINED_VOCAB_FILES_MAP
|
||||
max_model_input_sizes = READER_PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
|
||||
pretrained_init_configuration = READER_PRETRAINED_INIT_CONFIGURATION
|
||||
model_input_names = ["attention_mask"]
|
||||
@@ -965,7 +965,7 @@ ENCODE_KWARGS_DOCSTRING = r"""
|
||||
>= 7.5 (Volta).
|
||||
return_tensors (:obj:`str`, `optional`, defaults to :obj:`None`):
|
||||
Can be set to 'tf', 'pt' or 'np' to return respectively TensorFlow :obj:`tf.constant`,
|
||||
PyTorch :obj:`torch.Tensor` or Numpy :oj: `np.ndarray` instead of a list of python integers.
|
||||
PyTorch :obj:`torch.Tensor` or Numpy :obj: `np.ndarray` instead of a list of python integers.
|
||||
"""
|
||||
|
||||
ENCODE_PLUS_ADDITIONAL_KWARGS_DOCSTRING = r"""
|
||||
@@ -1352,6 +1352,15 @@ class PreTrainedTokenizerBase(SpecialTokensMixin):
|
||||
added_tokens_file = os.path.join(save_directory, ADDED_TOKENS_FILE)
|
||||
tokenizer_config_file = os.path.join(save_directory, TOKENIZER_CONFIG_FILE)
|
||||
|
||||
def convert_values(dic):
|
||||
write_dict = {}
|
||||
for key, value in dic.items():
|
||||
if isinstance(value, AddedToken):
|
||||
write_dict[key] = value.__getstate__()
|
||||
else:
|
||||
write_dict[key] = value
|
||||
return write_dict
|
||||
|
||||
tokenizer_config = copy.deepcopy(self.init_kwargs)
|
||||
if len(self.init_inputs) > 0:
|
||||
tokenizer_config["init_inputs"] = copy.deepcopy(self.init_inputs)
|
||||
@@ -1359,16 +1368,10 @@ class PreTrainedTokenizerBase(SpecialTokensMixin):
|
||||
tokenizer_config.pop(file_id, None)
|
||||
|
||||
with open(tokenizer_config_file, "w", encoding="utf-8") as f:
|
||||
f.write(json.dumps(tokenizer_config, ensure_ascii=False))
|
||||
f.write(json.dumps(convert_values(tokenizer_config), ensure_ascii=False))
|
||||
|
||||
with open(special_tokens_map_file, "w", encoding="utf-8") as f:
|
||||
write_dict = {}
|
||||
for key, value in self.special_tokens_map_extended.items():
|
||||
if isinstance(value, AddedToken):
|
||||
write_dict[key] = value.__getstate__()
|
||||
else:
|
||||
write_dict[key] = value
|
||||
f.write(json.dumps(write_dict, ensure_ascii=False))
|
||||
f.write(json.dumps(convert_values(self.special_tokens_map_extended), ensure_ascii=False))
|
||||
|
||||
added_vocab = self.get_added_vocab()
|
||||
if added_vocab:
|
||||
@@ -1900,7 +1903,7 @@ class PreTrainedTokenizerBase(SpecialTokensMixin):
|
||||
return_attention_mask: (optional) Set to False to avoid returning attention mask (default: set to model specifics)
|
||||
return_tensors (:obj:`str`, `optional`, defaults to :obj:`None`):
|
||||
Can be set to 'tf', 'pt' or 'np' to return respectively TensorFlow :obj:`tf.constant`,
|
||||
PyTorch :obj:`torch.Tensor` or Numpy :oj: `np.ndarray` instead of a list of python integers.
|
||||
PyTorch :obj:`torch.Tensor` or Numpy :obj: `np.ndarray` instead of a list of python integers.
|
||||
verbose (:obj:`bool`, `optional`, defaults to :obj:`True`):
|
||||
Set to ``False`` to avoid printing infos and warnings.
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2020 Huggingface
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
from transformers import is_torch_available
|
||||
|
||||
from .test_configuration_common import ConfigTester
|
||||
from .test_modeling_common import ModelTesterMixin, ids_tensor
|
||||
from .utils import require_torch, slow, torch_device
|
||||
|
||||
|
||||
if is_torch_available():
|
||||
from transformers import BertConfig, DPRConfig, DPRContextEncoder, DPRQuestionEncoder, DPRReader
|
||||
from transformers.modeling_dpr import (
|
||||
DPR_CONTEXT_ENCODER_PRETRAINED_MODEL_ARCHIVE_LIST,
|
||||
DPR_QUESTION_ENCODER_PRETRAINED_MODEL_ARCHIVE_LIST,
|
||||
DPR_READER_PRETRAINED_MODEL_ARCHIVE_LIST,
|
||||
)
|
||||
|
||||
|
||||
class DPRModelTester:
|
||||
def __init__(
|
||||
self,
|
||||
parent,
|
||||
batch_size=13,
|
||||
seq_length=7,
|
||||
is_training=True,
|
||||
use_input_mask=True,
|
||||
use_token_type_ids=True,
|
||||
use_labels=True,
|
||||
vocab_size=99,
|
||||
hidden_size=32,
|
||||
num_hidden_layers=5,
|
||||
num_attention_heads=4,
|
||||
intermediate_size=37,
|
||||
hidden_act="gelu",
|
||||
hidden_dropout_prob=0.1,
|
||||
attention_probs_dropout_prob=0.1,
|
||||
max_position_embeddings=512,
|
||||
type_vocab_size=16,
|
||||
type_sequence_label_size=2,
|
||||
initializer_range=0.02,
|
||||
num_labels=3,
|
||||
num_choices=4,
|
||||
scope=None,
|
||||
projection_dim=0,
|
||||
):
|
||||
self.parent = parent
|
||||
self.batch_size = batch_size
|
||||
self.seq_length = seq_length
|
||||
self.is_training = is_training
|
||||
self.use_input_mask = use_input_mask
|
||||
self.use_token_type_ids = use_token_type_ids
|
||||
self.use_labels = use_labels
|
||||
self.vocab_size = vocab_size
|
||||
self.hidden_size = hidden_size
|
||||
self.num_hidden_layers = num_hidden_layers
|
||||
self.num_attention_heads = num_attention_heads
|
||||
self.intermediate_size = intermediate_size
|
||||
self.hidden_act = hidden_act
|
||||
self.hidden_dropout_prob = hidden_dropout_prob
|
||||
self.attention_probs_dropout_prob = attention_probs_dropout_prob
|
||||
self.max_position_embeddings = max_position_embeddings
|
||||
self.type_vocab_size = type_vocab_size
|
||||
self.type_sequence_label_size = type_sequence_label_size
|
||||
self.initializer_range = initializer_range
|
||||
self.num_labels = num_labels
|
||||
self.num_choices = num_choices
|
||||
self.scope = scope
|
||||
self.projection_dim = projection_dim
|
||||
|
||||
def prepare_config_and_inputs(self):
|
||||
input_ids = ids_tensor([self.batch_size, self.seq_length], self.vocab_size)
|
||||
|
||||
input_mask = None
|
||||
if self.use_input_mask:
|
||||
input_mask = ids_tensor([self.batch_size, self.seq_length], vocab_size=2)
|
||||
|
||||
token_type_ids = None
|
||||
if self.use_token_type_ids:
|
||||
token_type_ids = ids_tensor([self.batch_size, self.seq_length], self.type_vocab_size)
|
||||
|
||||
sequence_labels = None
|
||||
token_labels = None
|
||||
choice_labels = None
|
||||
if self.use_labels:
|
||||
sequence_labels = ids_tensor([self.batch_size], self.type_sequence_label_size)
|
||||
token_labels = ids_tensor([self.batch_size, self.seq_length], self.num_labels)
|
||||
choice_labels = ids_tensor([self.batch_size], self.num_choices)
|
||||
|
||||
config = BertConfig(
|
||||
vocab_size=self.vocab_size,
|
||||
hidden_size=self.hidden_size,
|
||||
num_hidden_layers=self.num_hidden_layers,
|
||||
num_attention_heads=self.num_attention_heads,
|
||||
intermediate_size=self.intermediate_size,
|
||||
hidden_act=self.hidden_act,
|
||||
hidden_dropout_prob=self.hidden_dropout_prob,
|
||||
attention_probs_dropout_prob=self.attention_probs_dropout_prob,
|
||||
max_position_embeddings=self.max_position_embeddings,
|
||||
type_vocab_size=self.type_vocab_size,
|
||||
is_decoder=False,
|
||||
initializer_range=self.initializer_range,
|
||||
)
|
||||
config = DPRConfig(projection_dim=self.projection_dim, **config.to_dict())
|
||||
|
||||
return config, input_ids, token_type_ids, input_mask, sequence_labels, token_labels, choice_labels
|
||||
|
||||
def create_and_check_dpr_context_encoder(
|
||||
self, config, input_ids, token_type_ids, input_mask, sequence_labels, token_labels, choice_labels
|
||||
):
|
||||
model = DPRContextEncoder(config=config)
|
||||
model.to(torch_device)
|
||||
model.eval()
|
||||
embeddings = model(input_ids, attention_mask=input_mask, token_type_ids=token_type_ids)[0]
|
||||
embeddings = model(input_ids, token_type_ids=token_type_ids)[0]
|
||||
embeddings = model(input_ids)[0]
|
||||
|
||||
result = {
|
||||
"embeddings": embeddings,
|
||||
}
|
||||
self.parent.assertListEqual(
|
||||
list(result["embeddings"].size()), [self.batch_size, self.projection_dim or self.hidden_size]
|
||||
)
|
||||
|
||||
def create_and_check_dpr_question_encoder(
|
||||
self, config, input_ids, token_type_ids, input_mask, sequence_labels, token_labels, choice_labels
|
||||
):
|
||||
model = DPRQuestionEncoder(config=config)
|
||||
model.to(torch_device)
|
||||
model.eval()
|
||||
embeddings = model(input_ids, attention_mask=input_mask, token_type_ids=token_type_ids)[0]
|
||||
embeddings = model(input_ids, token_type_ids=token_type_ids)[0]
|
||||
embeddings = model(input_ids)[0]
|
||||
|
||||
result = {
|
||||
"embeddings": embeddings,
|
||||
}
|
||||
self.parent.assertListEqual(
|
||||
list(result["embeddings"].size()), [self.batch_size, self.projection_dim or self.hidden_size]
|
||||
)
|
||||
|
||||
def create_and_check_dpr_reader(
|
||||
self, config, input_ids, token_type_ids, input_mask, sequence_labels, token_labels, choice_labels
|
||||
):
|
||||
model = DPRReader(config=config)
|
||||
model.to(torch_device)
|
||||
model.eval()
|
||||
start_logits, end_logits, relevance_logits, *_ = model(input_ids, attention_mask=input_mask,)
|
||||
result = {
|
||||
"relevance_logits": relevance_logits,
|
||||
"start_logits": start_logits,
|
||||
"end_logits": end_logits,
|
||||
}
|
||||
self.parent.assertListEqual(list(result["start_logits"].size()), [self.batch_size, self.seq_length])
|
||||
self.parent.assertListEqual(list(result["end_logits"].size()), [self.batch_size, self.seq_length])
|
||||
self.parent.assertListEqual(list(result["relevance_logits"].size()), [self.batch_size])
|
||||
|
||||
def prepare_config_and_inputs_for_common(self):
|
||||
config_and_inputs = self.prepare_config_and_inputs()
|
||||
(
|
||||
config,
|
||||
input_ids,
|
||||
token_type_ids,
|
||||
input_mask,
|
||||
sequence_labels,
|
||||
token_labels,
|
||||
choice_labels,
|
||||
) = config_and_inputs
|
||||
inputs_dict = {"input_ids": input_ids}
|
||||
return config, inputs_dict
|
||||
|
||||
|
||||
@require_torch
|
||||
class DPRModelTest(ModelTesterMixin, unittest.TestCase):
|
||||
|
||||
all_model_classes = (DPRContextEncoder, DPRQuestionEncoder, DPRReader,) if is_torch_available() else ()
|
||||
|
||||
test_resize_embeddings = False
|
||||
test_missing_keys = False # why?
|
||||
test_pruning = False
|
||||
test_head_masking = False
|
||||
|
||||
def setUp(self):
|
||||
self.model_tester = DPRModelTester(self)
|
||||
self.config_tester = ConfigTester(self, config_class=DPRConfig, hidden_size=37)
|
||||
|
||||
def test_config(self):
|
||||
self.config_tester.run_common_tests()
|
||||
|
||||
def test_dpr_context_encoder_model(self):
|
||||
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
||||
self.model_tester.create_and_check_dpr_context_encoder(*config_and_inputs)
|
||||
|
||||
def test_dpr_question_encoder_model(self):
|
||||
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
||||
self.model_tester.create_and_check_dpr_question_encoder(*config_and_inputs)
|
||||
|
||||
def test_dpr_reader_model(self):
|
||||
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
||||
self.model_tester.create_and_check_dpr_reader(*config_and_inputs)
|
||||
|
||||
@slow
|
||||
def test_model_from_pretrained(self):
|
||||
for model_name in DPR_CONTEXT_ENCODER_PRETRAINED_MODEL_ARCHIVE_LIST[:1]:
|
||||
model = DPRContextEncoder.from_pretrained(model_name)
|
||||
self.assertIsNotNone(model)
|
||||
|
||||
for model_name in DPR_CONTEXT_ENCODER_PRETRAINED_MODEL_ARCHIVE_LIST[:1]:
|
||||
model = DPRContextEncoder.from_pretrained(model_name)
|
||||
self.assertIsNotNone(model)
|
||||
|
||||
for model_name in DPR_QUESTION_ENCODER_PRETRAINED_MODEL_ARCHIVE_LIST[:1]:
|
||||
model = DPRQuestionEncoder.from_pretrained(model_name)
|
||||
self.assertIsNotNone(model)
|
||||
|
||||
for model_name in DPR_READER_PRETRAINED_MODEL_ARCHIVE_LIST[:1]:
|
||||
model = DPRReader.from_pretrained(model_name)
|
||||
self.assertIsNotNone(model)
|
||||
@@ -407,7 +407,8 @@ class ReformerModelTester:
|
||||
model.to(torch_device)
|
||||
model.half()
|
||||
model.eval()
|
||||
output = model.generate(input_ids, attention_mask=input_mask, do_sample=False)
|
||||
# only use last 10 inputs for generation
|
||||
output = model.generate(input_ids[:, -10:], attention_mask=input_mask, do_sample=False)
|
||||
self.parent.assertFalse(torch.isnan(output).any().item())
|
||||
|
||||
def create_and_check_reformer_no_chunking(self, config, input_ids, input_mask, choice_labels):
|
||||
@@ -623,7 +624,7 @@ class ReformerLSHAttnModelTest(ReformerTesterMixin, ModelTesterMixin, unittest.T
|
||||
@require_torch
|
||||
class ReformerIntegrationTests(unittest.TestCase):
|
||||
"""
|
||||
These integration tests test the current layer activations and gradients againts the output of the Hugging Face Reformer model at time of integration: 29/04/2020. During integration, the model was tested against the output of the official Trax ReformerLM model for various cases ("lsh" only, "local" only, masked / non-masked, different chunk length, ....). In order to recover the original trax integration tests, one should use patrickvonplaten's fork of trax and the code that lives on the branch `branch_to_save_trax_integration_tests`.
|
||||
These integration tests test the current layer activations and gradients againts the output of the Hugging Face Reformer model at time of integration: 29/06/2020. During integration, the model was tested against the output of the official Trax ReformerLM model for various cases ("lsh" only, "local" only, masked / non-masked, different chunk length, ....). In order to recover the original trax integration tests, one should use patrickvonplaten's fork of trax and the code that lives on the branch `reformer_trax_tests`.
|
||||
"""
|
||||
|
||||
def _get_basic_config_and_input(self):
|
||||
@@ -940,7 +941,7 @@ class ReformerIntegrationTests(unittest.TestCase):
|
||||
hidden_states = model(input_ids=input_ids, attention_mask=attn_mask)[0]
|
||||
output_slice = hidden_states[1, -1, :5]
|
||||
expected_output_slice = torch.tensor(
|
||||
[0.0324, -0.0121, 0.0615, 0.0031, -0.0297], dtype=torch.float, device=torch_device,
|
||||
[0.0256, -0.0121, 0.0636, 0.0024, -0.0393], dtype=torch.float, device=torch_device,
|
||||
)
|
||||
self.assertTrue(torch.allclose(output_slice, expected_output_slice, atol=1e-3))
|
||||
|
||||
|
||||
@@ -351,6 +351,16 @@ class T5ModelTest(ModelTesterMixin, unittest.TestCase):
|
||||
model = T5Model.from_pretrained(model_name)
|
||||
self.assertIsNotNone(model)
|
||||
|
||||
def test_export_to_onnx(self):
|
||||
import tempfile
|
||||
|
||||
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
||||
model = T5Model(config_and_inputs[0])
|
||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||
torch.onnx.export(
|
||||
model, config_and_inputs[1], f"{tmpdirname}/t5_test.onnx", export_params=True, opset_version=9,
|
||||
)
|
||||
|
||||
|
||||
@require_torch
|
||||
class T5ModelIntegrationTests(unittest.TestCase):
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
# coding=utf-8
|
||||
# Copyright 2020 Huggingface
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
from transformers.tokenization_dpr import (
|
||||
DPRContextEncoderTokenizer,
|
||||
DPRContextEncoderTokenizerFast,
|
||||
DPRQuestionEncoderTokenizer,
|
||||
DPRQuestionEncoderTokenizerFast,
|
||||
DPRReaderOutput,
|
||||
DPRReaderTokenizer,
|
||||
DPRReaderTokenizerFast,
|
||||
)
|
||||
from transformers.tokenization_utils_base import BatchEncoding
|
||||
|
||||
from .test_tokenization_bert import BertTokenizationTest
|
||||
from .utils import slow
|
||||
|
||||
|
||||
class DPRContextEncoderTokenizationTest(BertTokenizationTest):
|
||||
|
||||
tokenizer_class = DPRContextEncoderTokenizer
|
||||
|
||||
def get_rust_tokenizer(self, **kwargs):
|
||||
return DPRContextEncoderTokenizerFast.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
|
||||
class DPRQuestionEncoderTokenizationTest(BertTokenizationTest):
|
||||
|
||||
tokenizer_class = DPRQuestionEncoderTokenizer
|
||||
|
||||
def get_rust_tokenizer(self, **kwargs):
|
||||
return DPRQuestionEncoderTokenizerFast.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
|
||||
class DPRReaderTokenizationTest(BertTokenizationTest):
|
||||
|
||||
tokenizer_class = DPRReaderTokenizer
|
||||
|
||||
def get_rust_tokenizer(self, **kwargs):
|
||||
return DPRReaderTokenizerFast.from_pretrained(self.tmpdirname, **kwargs)
|
||||
|
||||
@slow
|
||||
def test_decode_best_spans(self):
|
||||
tokenizer = self.tokenizer_class.from_pretrained("bert-base-uncased")
|
||||
|
||||
text_1 = tokenizer.encode("question sequence", add_special_tokens=False)
|
||||
text_2 = tokenizer.encode("title sequence", add_special_tokens=False)
|
||||
text_3 = tokenizer.encode("text sequence " * 4, add_special_tokens=False)
|
||||
input_ids = [[101] + text_1 + [102] + text_2 + [102] + text_3]
|
||||
reader_input = BatchEncoding({"input_ids": input_ids})
|
||||
|
||||
start_logits = [[0] * len(input_ids[0])]
|
||||
end_logits = [[0] * len(input_ids[0])]
|
||||
relevance_logits = [0]
|
||||
reader_output = DPRReaderOutput(start_logits, end_logits, relevance_logits)
|
||||
|
||||
start_index, end_index = 8, 9
|
||||
start_logits[0][start_index] = 10
|
||||
end_logits[0][end_index] = 10
|
||||
predicted_spans = tokenizer.decode_best_spans(reader_input, reader_output)
|
||||
self.assertEqual(predicted_spans[0].start_index, start_index)
|
||||
self.assertEqual(predicted_spans[0].end_index, end_index)
|
||||
self.assertEqual(predicted_spans[0].doc_id, 0)
|
||||
|
||||
@slow
|
||||
def test_call(self):
|
||||
tokenizer = self.tokenizer_class.from_pretrained("bert-base-uncased")
|
||||
|
||||
text_1 = tokenizer.encode("question sequence", add_special_tokens=False)
|
||||
text_2 = tokenizer.encode("title sequence", add_special_tokens=False)
|
||||
text_3 = tokenizer.encode("text sequence", add_special_tokens=False)
|
||||
expected_input_ids = [101] + text_1 + [102] + text_2 + [102] + text_3
|
||||
encoded_input = tokenizer(questions=["question sequence"], titles=["title sequence"], texts=["text sequence"])
|
||||
self.assertIn("input_ids", encoded_input)
|
||||
self.assertIn("attention_mask", encoded_input)
|
||||
self.assertListEqual(encoded_input["input_ids"][0], expected_input_ids)
|
||||
@@ -12,6 +12,7 @@ if is_torch_available():
|
||||
AutoModelForSequenceClassification,
|
||||
default_data_collator,
|
||||
DataCollatorForLanguageModeling,
|
||||
DataCollatorForPermutationLanguageModeling,
|
||||
GlueDataset,
|
||||
GlueDataTrainingArguments,
|
||||
TextDataset,
|
||||
@@ -123,6 +124,34 @@ class DataCollatorIntegrationTest(unittest.TestCase):
|
||||
self.assertEqual(batch["input_ids"].shape, torch.Size((2, 512)))
|
||||
self.assertEqual(batch["labels"].shape, torch.Size((2, 512)))
|
||||
|
||||
def test_plm(self):
|
||||
tokenizer = AutoTokenizer.from_pretrained("xlnet-base-cased")
|
||||
data_collator = DataCollatorForPermutationLanguageModeling(tokenizer)
|
||||
# ^ permutation lm
|
||||
|
||||
dataset = LineByLineTextDataset(tokenizer, file_path=PATH_SAMPLE_TEXT, block_size=512)
|
||||
examples = [dataset[i] for i in range(len(dataset))]
|
||||
batch = data_collator(examples)
|
||||
self.assertIsInstance(batch, dict)
|
||||
self.assertEqual(batch["input_ids"].shape, torch.Size((31, 112)))
|
||||
self.assertEqual(batch["perm_mask"].shape, torch.Size((31, 112, 112)))
|
||||
self.assertEqual(batch["target_mapping"].shape, torch.Size((31, 112, 112)))
|
||||
self.assertEqual(batch["labels"].shape, torch.Size((31, 112)))
|
||||
|
||||
dataset = TextDataset(tokenizer, file_path=PATH_SAMPLE_TEXT, block_size=512, overwrite_cache=True)
|
||||
examples = [dataset[i] for i in range(len(dataset))]
|
||||
batch = data_collator(examples)
|
||||
self.assertIsInstance(batch, dict)
|
||||
self.assertEqual(batch["input_ids"].shape, torch.Size((2, 512)))
|
||||
self.assertEqual(batch["perm_mask"].shape, torch.Size((2, 512, 512)))
|
||||
self.assertEqual(batch["target_mapping"].shape, torch.Size((2, 512, 512)))
|
||||
self.assertEqual(batch["labels"].shape, torch.Size((2, 512)))
|
||||
|
||||
example = [torch.randint(5, [5])]
|
||||
with self.assertRaises(ValueError):
|
||||
# Expect error due to odd sequence length
|
||||
data_collator(example)
|
||||
|
||||
|
||||
@require_torch
|
||||
class TrainerIntegrationTest(unittest.TestCase):
|
||||
|
||||
Reference in new issue
Block a user