Compare commits
14
Commits
v2.6.0
...
mem-benchmark
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4344c34e11 | ||
|
|
7420a6a9cc | ||
|
|
022e8fab97 | ||
|
|
3c5c567507 | ||
|
|
9c683ef01e | ||
|
|
ffcffebe85 | ||
|
|
010e0460b2 | ||
|
|
ffa17fe322 | ||
|
|
83272a3853 | ||
|
|
ccbe839ee0 | ||
|
|
3d76df3a12 | ||
|
|
eaabaaf750 | ||
|
|
f8823bad9a | ||
|
|
d0c36a7b72 |
No files matched your search
@@ -85,6 +85,8 @@ jobs:
|
||||
parallelism: 1
|
||||
steps:
|
||||
- checkout
|
||||
# we need a version of isort with https://github.com/timothycrosley/isort/pull/1000
|
||||
- run: sudo pip install git+git://github.com/timothycrosley/isort.git@e63ae06ec7d70b06df9e528357650281a3d3ec22#egg=isort
|
||||
- run: sudo pip install .[tf,torch,quality]
|
||||
- run: black --check --line-length 119 --target-version py35 examples templates tests src utils
|
||||
- run: isort --check-only --recursive examples templates tests src utils
|
||||
|
||||
+16
-9
@@ -375,24 +375,31 @@ def print_summary_statistics(summary: MemorySummary):
|
||||
"\nLines by line memory consumption:\n"
|
||||
+ "\n".join(
|
||||
f"{state.frame.filename}:{state.frame.line_number}: mem {state.cpu_gpu}: {state.frame.line_text}"
|
||||
for state in summary.sequential
|
||||
for state in summary.relative_mem_list
|
||||
)
|
||||
)
|
||||
print(
|
||||
"\nLines with top memory consumption:\n"
|
||||
"\nLines with top memory increase:\n"
|
||||
+ "\n".join(
|
||||
f"=> {state.frame.filename}:{state.frame.line_number}: mem {state.cpu_gpu}: {state.frame.line_text}"
|
||||
for state in summary.cumulative[:6]
|
||||
f"=> {state.frame.filename}:{state.frame.line_number}: mem {state.cpu_gpu_with_units}: {state.frame.line_text}"
|
||||
for state in summary.relative_mem_sorted[:6]
|
||||
)
|
||||
)
|
||||
print(
|
||||
"\nLines with lowest memory consumption:\n"
|
||||
"\nLines with lowest memory increase:\n"
|
||||
+ "\n".join(
|
||||
f"=> {state.frame.filename}:{state.frame.line_number}: mem {state.cpu_gpu}: {state.frame.line_text}"
|
||||
for state in summary.cumulative[-6:]
|
||||
f"=> {state.frame.filename}:{state.frame.line_number}: mem {state.cpu_gpu_with_units}: {state.frame.line_text}"
|
||||
for state in summary.relative_mem_sorted[-6:]
|
||||
)
|
||||
)
|
||||
print(f"\nTotal memory increase: {summary.total}")
|
||||
print(
|
||||
"\nLines with peak memory used:\n"
|
||||
+ "\n".join(
|
||||
f"=> {state.frame.filename}:{state.frame.line_number}: mem {state.cpu_gpu_with_units}: {state.frame.line_text}"
|
||||
for state in summary.absolute_mem_sorted[:6]
|
||||
)
|
||||
)
|
||||
print(f"\nTotal memory increase: {summary.relative_mem_total.cpu_gpu_with_units}")
|
||||
|
||||
|
||||
def _compute_pytorch(
|
||||
@@ -453,7 +460,7 @@ def _compute_pytorch(
|
||||
if verbose:
|
||||
print_summary_statistics(summary)
|
||||
|
||||
dictionary[model_name]["memory"][batch_size][slice_size] = str(summary.total)
|
||||
dictionary[model_name]["memory"][batch_size][slice_size] = summary.relative_mem_total.cpu_gpu_with_units
|
||||
else:
|
||||
dictionary[model_name]["memory"][batch_size][slice_size] = "N/A"
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ from torch.utils.data.distributed import DistributedSampler
|
||||
from tqdm import tqdm, trange
|
||||
|
||||
from transformers import (
|
||||
CONFIG_MAPPING,
|
||||
MODEL_WITH_LM_HEAD_MAPPING,
|
||||
WEIGHTS_NAME,
|
||||
AdamW,
|
||||
@@ -679,7 +678,12 @@ def main():
|
||||
elif args.model_name_or_path:
|
||||
config = AutoConfig.from_pretrained(args.model_name_or_path, cache_dir=args.cache_dir)
|
||||
else:
|
||||
config = CONFIG_MAPPING[args.model_type]()
|
||||
# When we release a pip version exposing CONFIG_MAPPING,
|
||||
# we can do `config = CONFIG_MAPPING[args.model_type]()`.
|
||||
raise ValueError(
|
||||
"You are instantiating a new config instance from scratch. This is not supported, but you can do it from another script, save it,"
|
||||
"and load it from here, using --config_name"
|
||||
)
|
||||
|
||||
if args.tokenizer_name:
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.tokenizer_name, cache_dir=args.cache_dir)
|
||||
@@ -687,8 +691,8 @@ def main():
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path, cache_dir=args.cache_dir)
|
||||
else:
|
||||
raise ValueError(
|
||||
"You are instantiating a new {} tokenizer. This is not supported, but you can do it from another script, save it,"
|
||||
"and load it from here, using --tokenizer_name".format(AutoTokenizer.__name__)
|
||||
"You are instantiating a new tokenizer from scratch. This is not supported, but you can do it from another script, save it,"
|
||||
"and load it from here, using --tokenizer_name"
|
||||
)
|
||||
|
||||
if args.block_size <= 0:
|
||||
@@ -706,7 +710,7 @@ def main():
|
||||
)
|
||||
else:
|
||||
logger.info("Training new model from scratch")
|
||||
model = AutoModelWithLMHead(config=config)
|
||||
model = AutoModelWithLMHead.from_config(config)
|
||||
|
||||
model.to(args.device)
|
||||
|
||||
|
||||
@@ -14,6 +14,19 @@ python evaluate_cnn.py <path_to_test.source> cnn_test_summaries.txt
|
||||
```
|
||||
the default batch size, 8, fits in 16GB GPU memory, but may need to be adjusted to fit your system.
|
||||
|
||||
|
||||
### Training
|
||||
|
||||
|
||||
|
||||
After downloading the CNN and Daily Mail datasets, preprocess the dataset:
|
||||
```commandline
|
||||
git clone https://github.com/artmatsak/cnn-dailymail
|
||||
cd cnn-dailymail && python make_datafiles.py ../cnn/stories/ ../dailymail/stories/
|
||||
```
|
||||
|
||||
Run the training script: `run_train.sh`
|
||||
|
||||
### Where is the code?
|
||||
The core model is in `src/transformers/modeling_bart.py`. This directory only contains examples.
|
||||
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
import argparse
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
|
||||
import torch
|
||||
from torch.utils.data import DataLoader
|
||||
|
||||
from transformer_base import BaseTransformer, add_generic_args, generic_train, get_linear_schedule_with_warmup
|
||||
from utils import SummarizationDataset
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BartSystem(BaseTransformer):
|
||||
|
||||
mode = "language-modeling"
|
||||
|
||||
def __init__(self, hparams):
|
||||
super(BartSystem, self).__init__(hparams, num_labels=None, mode=self.mode)
|
||||
|
||||
def forward(
|
||||
self, input_ids, attention_mask=None, decoder_input_ids=None, decoder_attention_mask=None, lm_labels=None
|
||||
):
|
||||
return self.model(
|
||||
input_ids,
|
||||
attention_mask=attention_mask,
|
||||
decoder_input_ids=decoder_input_ids,
|
||||
decoder_attention_mask=decoder_attention_mask,
|
||||
lm_labels=lm_labels,
|
||||
)
|
||||
|
||||
def _step(self, batch):
|
||||
y = batch["target_ids"]
|
||||
y_ids = y[:, :-1].contiguous()
|
||||
lm_labels = y[:, 1:].clone()
|
||||
lm_labels[y[:, 1:] == self.tokenizer.pad_token_id] = -100
|
||||
outputs = self(
|
||||
input_ids=batch["source_ids"],
|
||||
attention_mask=batch["source_mask"],
|
||||
decoder_input_ids=y_ids,
|
||||
lm_labels=lm_labels,
|
||||
)
|
||||
|
||||
loss = outputs[0]
|
||||
|
||||
return loss
|
||||
|
||||
def training_step(self, batch, batch_idx):
|
||||
loss = self._step(batch)
|
||||
|
||||
tensorboard_logs = {"train_loss": loss}
|
||||
return {"loss": loss, "log": tensorboard_logs}
|
||||
|
||||
def validation_step(self, batch, batch_idx):
|
||||
loss = self._step(batch)
|
||||
return {"val_loss": loss}
|
||||
|
||||
def validation_end(self, outputs):
|
||||
avg_loss = torch.stack([x["val_loss"] for x in outputs]).mean()
|
||||
tensorboard_logs = {"val_loss": avg_loss}
|
||||
return {"avg_val_loss": avg_loss, "log": tensorboard_logs}
|
||||
|
||||
def test_step(self, batch, batch_idx):
|
||||
generated_ids = self.model.generate(
|
||||
batch["source_ids"],
|
||||
attention_mask=batch["source_mask"],
|
||||
num_beams=1,
|
||||
max_length=80,
|
||||
repetition_penalty=2.5,
|
||||
length_penalty=1.0,
|
||||
early_stopping=True,
|
||||
)
|
||||
preds = [
|
||||
self.tokenizer.decode(g, skip_special_tokens=True, clean_up_tokenization_spaces=True)
|
||||
for g in generated_ids
|
||||
]
|
||||
target = [
|
||||
self.tokenizer.decode(t, skip_special_tokens=True, clean_up_tokenization_spaces=True)
|
||||
for t in batch["target_ids"]
|
||||
]
|
||||
loss = self._step(batch)
|
||||
|
||||
return {"val_loss": loss, "preds": preds, "target": target}
|
||||
|
||||
def test_end(self, outputs):
|
||||
return self.validation_end(outputs)
|
||||
|
||||
def test_epoch_end(self, outputs):
|
||||
output_test_predictions_file = os.path.join(self.hparams.output_dir, "test_predictions.txt")
|
||||
output_test_targets_file = os.path.join(self.hparams.output_dir, "test_targets.txt")
|
||||
# write predictions and targets for later rouge evaluation.
|
||||
with open(output_test_predictions_file, "w+") as p_writer, open(output_test_targets_file, "w+") as t_writer:
|
||||
for output_batch in outputs:
|
||||
p_writer.writelines(s + "\n" for s in output_batch["preds"])
|
||||
t_writer.writelines(s + "\n" for s in output_batch["target"])
|
||||
p_writer.close()
|
||||
t_writer.close()
|
||||
|
||||
return self.test_end(outputs)
|
||||
|
||||
def train_dataloader(self):
|
||||
train_dataset = SummarizationDataset(
|
||||
self.tokenizer, data_dir=self.hparams.data_dir, type_path="train", block_size=self.hparams.max_seq_length
|
||||
)
|
||||
dataloader = DataLoader(train_dataset, batch_size=self.hparams.train_batch_size)
|
||||
t_total = (
|
||||
(len(dataloader.dataset) // (self.hparams.train_batch_size * max(1, self.hparams.n_gpu)))
|
||||
// self.hparams.gradient_accumulation_steps
|
||||
* float(self.hparams.num_train_epochs)
|
||||
)
|
||||
scheduler = get_linear_schedule_with_warmup(
|
||||
self.opt, num_warmup_steps=self.hparams.warmup_steps, num_training_steps=t_total
|
||||
)
|
||||
self.lr_scheduler = scheduler
|
||||
return dataloader
|
||||
|
||||
def val_dataloader(self):
|
||||
val_dataset = SummarizationDataset(
|
||||
self.tokenizer, data_dir=self.hparams.data_dir, type_path="val", block_size=self.hparams.max_seq_length
|
||||
)
|
||||
return DataLoader(val_dataset, batch_size=self.hparams.eval_batch_size)
|
||||
|
||||
def test_dataloader(self):
|
||||
test_dataset = SummarizationDataset(
|
||||
self.tokenizer, data_dir=self.hparams.data_dir, type_path="test", block_size=self.hparams.max_seq_length
|
||||
)
|
||||
return DataLoader(test_dataset, batch_size=self.hparams.eval_batch_size)
|
||||
|
||||
@staticmethod
|
||||
def add_model_specific_args(parser, root_dir):
|
||||
BaseTransformer.add_model_specific_args(parser, root_dir)
|
||||
# Add BART specific options
|
||||
parser.add_argument(
|
||||
"--max_seq_length",
|
||||
default=1024,
|
||||
type=int,
|
||||
help="The maximum total input sequence length after tokenization. Sequences longer "
|
||||
"than this will be truncated, sequences shorter will be padded.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--data_dir",
|
||||
default=None,
|
||||
type=str,
|
||||
required=True,
|
||||
help="The input data dir. Should contain the dataset files for the CNN/DM summarization task.",
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
add_generic_args(parser, os.getcwd())
|
||||
parser = BartSystem.add_model_specific_args(parser, os.getcwd())
|
||||
args = parser.parse_args()
|
||||
|
||||
# If output_dir not provided, a folder will be generated in pwd
|
||||
if args.output_dir is None:
|
||||
args.output_dir = os.path.join("./results", f"{args.task}_{args.model_type}_{time.strftime('%Y%m%d_%H%M%S')}",)
|
||||
os.makedirs(args.output_dir)
|
||||
|
||||
model = BartSystem(args)
|
||||
trainer = generic_train(model, args)
|
||||
|
||||
# Optionally, predict on dev set and write to output_dir
|
||||
if args.do_predict:
|
||||
checkpoints = list(sorted(glob.glob(os.path.join(args.output_dir, "checkpointepoch=*.ckpt"), recursive=True)))
|
||||
BartSystem.load_from_checkpoint(checkpoints[-1])
|
||||
trainer.test(model)
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
# Install newest ptl.
|
||||
pip install -U git+http://github.com/PyTorchLightning/pytorch-lightning/
|
||||
|
||||
|
||||
export OUTPUT_DIR_NAME=bart_sum
|
||||
export CURRENT_DIR=${PWD}
|
||||
export OUTPUT_DIR=${CURRENT_DIR}/${OUTPUT_DIR_NAME}
|
||||
|
||||
# Make output directory if it doesn't exist
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# Add parent directory to python path to access transformer_base.py
|
||||
export PYTHONPATH="../../":"${PYTHONPATH}"
|
||||
|
||||
python run_bart_sum.py \
|
||||
--data_dir=./cnn-dailymail/cnn_dm \
|
||||
--model_type=bart \
|
||||
--model_name_or_path=bart-large \
|
||||
--learning_rate=3e-5 \
|
||||
--train_batch_size=4 \
|
||||
--eval_batch_size=4 \
|
||||
--output_dir=$OUTPUT_DIR \
|
||||
--do_train
|
||||
@@ -0,0 +1,43 @@
|
||||
import os
|
||||
|
||||
from torch.utils.data import Dataset
|
||||
|
||||
|
||||
class SummarizationDataset(Dataset):
|
||||
def __init__(self, tokenizer, data_dir="./cnn-dailymail/cnn_dm/", type_path="train", block_size=1024):
|
||||
super(SummarizationDataset,).__init__()
|
||||
self.tokenizer = tokenizer
|
||||
|
||||
self.source = []
|
||||
self.target = []
|
||||
|
||||
print("loading " + type_path + " source.")
|
||||
|
||||
with open(os.path.join(data_dir, type_path + ".source"), "r") as f:
|
||||
for text in f.readlines(): # each text is a line and a full story
|
||||
tokenized = tokenizer.batch_encode_plus(
|
||||
[text], max_length=block_size, pad_to_max_length=True, return_tensors="pt"
|
||||
)
|
||||
self.source.append(tokenized)
|
||||
f.close()
|
||||
|
||||
print("loading " + type_path + " target.")
|
||||
|
||||
with open(os.path.join(data_dir, type_path + ".target"), "r") as f:
|
||||
for text in f.readlines(): # each text is a line and a summary
|
||||
tokenized = tokenizer.batch_encode_plus(
|
||||
[text], max_length=56, pad_to_max_length=True, return_tensors="pt"
|
||||
)
|
||||
self.target.append(tokenized)
|
||||
f.close()
|
||||
|
||||
def __len__(self):
|
||||
return len(self.source)
|
||||
|
||||
def __getitem__(self, index):
|
||||
source_ids = self.source[index]["input_ids"].squeeze()
|
||||
target_ids = self.target[index]["input_ids"].squeeze()
|
||||
|
||||
src_mask = self.source[index]["attention_mask"].squeeze() # might need to squeeze
|
||||
|
||||
return {"source_ids": source_ids, "source_mask": src_mask, "target_ids": target_ids}
|
||||
@@ -53,10 +53,9 @@ class BaseTransformer(pl.LightningModule):
|
||||
super(BaseTransformer, self).__init__()
|
||||
self.hparams = hparams
|
||||
self.hparams.model_type = self.hparams.model_type.lower()
|
||||
|
||||
config = AutoConfig.from_pretrained(
|
||||
self.hparams.config_name if self.hparams.config_name else self.hparams.model_name_or_path,
|
||||
num_labels=num_labels,
|
||||
**({"num_labels": num_labels} if num_labels is not None else {}),
|
||||
cache_dir=self.hparams.cache_dir if self.hparams.cache_dir else None,
|
||||
)
|
||||
tokenizer = AutoTokenizer.from_pretrained(
|
||||
|
||||
@@ -320,7 +320,9 @@ def convert_examples_to_features(
|
||||
else:
|
||||
text_b = example.question + " " + ending
|
||||
|
||||
inputs = tokenizer.encode_plus(text_a, text_b, add_special_tokens=True, max_length=max_length,)
|
||||
inputs = tokenizer.encode_plus(
|
||||
text_a, text_b, add_special_tokens=True, max_length=max_length, return_token_type_ids=True
|
||||
)
|
||||
if "num_truncated_tokens" in inputs and inputs["num_truncated_tokens"] > 0:
|
||||
logger.info(
|
||||
"Attention! you are cropping tokens (swag task is ok). "
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# BioBERT-NLI
|
||||
|
||||
This is the model [BioBERT](https://github.com/dmis-lab/biobert) [1] fine-tuned on the [SNLI](https://nlp.stanford.edu/projects/snli/) and the [MultiNLI](https://www.nyu.edu/projects/bowman/multinli/) datasets using the [`sentence-transformers` library](https://github.com/UKPLab/sentence-transformers/) to produce universal sentence embeddings [2].
|
||||
|
||||
The model uses the original BERT wordpiece vocabulary and was trained using the **average pooling strategy** and a **softmax loss**.
|
||||
|
||||
**Base model**: `monologg/biobert_v1.1_pubmed` from HuggingFace's `AutoModel`.
|
||||
|
||||
**Training time**: ~6 hours on the NVIDIA Tesla P100 GPU provided in Kaggle Notebooks.
|
||||
|
||||
**Parameters**:
|
||||
|
||||
| Parameter | Value |
|
||||
|------------------|-------|
|
||||
| Batch size | 64 |
|
||||
| Training steps | 30000 |
|
||||
| Warmup steps | 1450 |
|
||||
| Lowercasing | False |
|
||||
| Max. Seq. Length | 128 |
|
||||
|
||||
**Performances**: The performance was evaluated on the test portion of the [STS dataset](http://ixa2.si.ehu.es/stswiki/index.php/STSbenchmark) using Spearman rank correlation and compared to the performances of a general BERT base model obtained with the same procedure to verify their similarity.
|
||||
|
||||
| Model | Score |
|
||||
|-------------------------------|-------------|
|
||||
| `biobert-nli` (this) | 73.40 |
|
||||
| `gsarti/scibert-nli` | 74.50 |
|
||||
| `bert-base-nli-mean-tokens`[3]| 77.12 |
|
||||
|
||||
An example usage for similarity-based scientific paper retrieval is provided in the [Covid Papers Browser](https://github.com/gsarti/covid-papers-browser) repository.
|
||||
|
||||
**References:**
|
||||
|
||||
[1] J. Lee et al, [BioBERT: a pre-trained biomedical language representation model for biomedical text mining](https://academic.oup.com/bioinformatics/article/36/4/1234/5566506)
|
||||
|
||||
[2] A. Conneau et al., [Supervised Learning of Universal Sentence Representations from Natural Language Inference Data](https://www.aclweb.org/anthology/D17-1070/)
|
||||
|
||||
[3] N. Reimers et I. Gurevych, [Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks](https://www.aclweb.org/anthology/D19-1410/)
|
||||
@@ -32,13 +32,54 @@ Preprocessing steps can reproduce from here, [Malaya/pretrained-model/preprocess
|
||||
You can use this model by installing `torch` or `tensorflow` and Huggingface library `transformers`. And you can use it directly by initializing it like this:
|
||||
|
||||
```python
|
||||
from transformers import XLNetTokenizer, BertModel
|
||||
from transformers import AlbertTokenizer, BertModel
|
||||
|
||||
model = BertModel.from_pretrained('huseinzol05/bert-base-bahasa-cased')
|
||||
tokenizer = XLNetTokenizer.from_pretrained('huseinzol05/bert-base-bahasa-cased')
|
||||
tokenizer = AlbertTokenizer.from_pretrained(
|
||||
'huseinzol05/bert-base-bahasa-cased',
|
||||
unk_token = '[UNK]',
|
||||
pad_token = '[PAD]',
|
||||
do_lower_case = False,
|
||||
)
|
||||
```
|
||||
|
||||
We use [google/sentencepiece](https://github.com/google/sentencepiece) to train the tokenizer, so to use it, need to load from `XLNetTokenizer`.
|
||||
We use [google/sentencepiece](https://github.com/google/sentencepiece) to train the tokenizer, so to use it, need to load from `AlbertTokenizer`.
|
||||
|
||||
## Example using AutoModelWithLMHead
|
||||
|
||||
```python
|
||||
from transformers import AlbertTokenizer, AutoModelWithLMHead, pipeline
|
||||
|
||||
model = AutoModelWithLMHead.from_pretrained('huseinzol05/bert-base-bahasa-cased')
|
||||
tokenizer = AlbertTokenizer.from_pretrained(
|
||||
'huseinzol05/bert-base-bahasa-cased',
|
||||
unk_token = '[UNK]',
|
||||
pad_token = '[PAD]',
|
||||
do_lower_case = False,
|
||||
)
|
||||
fill_mask = pipeline('fill-mask', model = model, tokenizer = tokenizer)
|
||||
print(fill_mask('makan ayam dengan [MASK]'))
|
||||
```
|
||||
|
||||
Output is,
|
||||
|
||||
```text
|
||||
[{'sequence': '[CLS] makan ayam dengan rendang[SEP]',
|
||||
'score': 0.10812027007341385,
|
||||
'token': 2446},
|
||||
{'sequence': '[CLS] makan ayam dengan kicap[SEP]',
|
||||
'score': 0.07653367519378662,
|
||||
'token': 12928},
|
||||
{'sequence': '[CLS] makan ayam dengan nasi[SEP]',
|
||||
'score': 0.06839974224567413,
|
||||
'token': 450},
|
||||
{'sequence': '[CLS] makan ayam dengan ayam[SEP]',
|
||||
'score': 0.059544261544942856,
|
||||
'token': 638},
|
||||
{'sequence': '[CLS] makan ayam dengan sayur[SEP]',
|
||||
'score': 0.05294966697692871,
|
||||
'token': 1639}]
|
||||
```
|
||||
|
||||
## Results
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
language: malay
|
||||
---
|
||||
|
||||
# Bahasa XLNet Model
|
||||
|
||||
Pretrained XLNet base language model for Malay and Indonesian.
|
||||
|
||||
## Pretraining Corpus
|
||||
|
||||
`XLNET-base-bahasa-cased` model was pretrained on ~1.8 Billion words. We trained on both standard and social media language structures, and below is list of data we trained on,
|
||||
|
||||
1. [dumping wikipedia](https://github.com/huseinzol05/Malaya-Dataset#wikipedia-1).
|
||||
2. [local instagram](https://github.com/huseinzol05/Malaya-Dataset#instagram).
|
||||
3. [local twitter](https://github.com/huseinzol05/Malaya-Dataset#twitter-1).
|
||||
4. [local news](https://github.com/huseinzol05/Malaya-Dataset#public-news).
|
||||
5. [local parliament text](https://github.com/huseinzol05/Malaya-Dataset#parliament).
|
||||
6. [local singlish/manglish text](https://github.com/huseinzol05/Malaya-Dataset#singlish-text).
|
||||
7. [IIUM Confession](https://github.com/huseinzol05/Malaya-Dataset#iium-confession).
|
||||
8. [Wattpad](https://github.com/huseinzol05/Malaya-Dataset#wattpad).
|
||||
9. [Academia PDF](https://github.com/huseinzol05/Malaya-Dataset#academia-pdf).
|
||||
|
||||
Preprocessing steps can reproduce from here, [Malaya/pretrained-model/preprocess](https://github.com/huseinzol05/Malaya/tree/master/pretrained-model/preprocess).
|
||||
|
||||
## Pretraining details
|
||||
|
||||
- This model was trained using zihangdai XLNet's github [repository](https://github.com/zihangdai/xlnet) on 3 Titan V100 32GB VRAM.
|
||||
- All steps can reproduce from here, [Malaya/pretrained-model/xlnet](https://github.com/huseinzol05/Malaya/tree/master/pretrained-model/xlnet).
|
||||
|
||||
## Load Pretrained Model
|
||||
|
||||
You can use this model by installing `torch` or `tensorflow` and Huggingface library `transformers`. And you can use it directly by initializing it like this:
|
||||
|
||||
```python
|
||||
from transformers import XLNetTokenizer, XLNetModel
|
||||
|
||||
model = XLNetModel.from_pretrained('huseinzol05/xlnet-base-bahasa-cased')
|
||||
tokenizer = XLNetTokenizer.from_pretrained(
|
||||
'huseinzol05/xlnet-base-bahasa-cased', do_lower_case = False
|
||||
)
|
||||
```
|
||||
|
||||
## Example using AutoModelWithLMHead
|
||||
|
||||
```python
|
||||
from transformers import AlbertTokenizer, AutoModelWithLMHead, pipeline
|
||||
|
||||
model = AutoModelWithLMHead.from_pretrained('huseinzol05/xlnet-base-bahasa-cased')
|
||||
tokenizer = XLNetTokenizer.from_pretrained(
|
||||
'huseinzol05/xlnet-base-bahasa-cased', do_lower_case = False
|
||||
)
|
||||
fill_mask = pipeline('fill-mask', model = model, tokenizer = tokenizer)
|
||||
print(fill_mask('makan ayam dengan [MASK]'))
|
||||
```
|
||||
|
||||
## Results
|
||||
|
||||
For further details on the model performance, simply checkout accuracy page from Malaya, https://malaya.readthedocs.io/en/latest/Accuracy.html, we compared with traditional models.
|
||||
|
||||
## Acknowledgement
|
||||
|
||||
Thanks to [Im Big](https://www.facebook.com/imbigofficial/), [LigBlou](https://www.facebook.com/ligblou), [Mesolitica](https://mesolitica.com/) and [KeyReply](https://www.keyreply.com/) for sponsoring AWS, Google and GPU clouds to train XLNet for Bahasa.
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
language: english
|
||||
thumbnail:
|
||||
---
|
||||
|
||||
# GPT-2 + CORD19 dataset : 🦠 ✍ ⚕
|
||||
|
||||
**GPT-2** fine-tuned on **biorxiv_medrxiv** and **comm_use_subset files** from [CORD-19](https://www.kaggle.com/allen-institute-for-ai/CORD-19-research-challenge) dataset.
|
||||
|
||||
|
||||
## Datasets details:
|
||||
|
||||
| Dataset | # Files |
|
||||
| ---------------------- | ----- |
|
||||
| biorxiv_medrxiv | 885 |
|
||||
| comm_use_subse | 9K |
|
||||
|
||||
## Model training
|
||||
|
||||
The model was trained on a Tesla P100 GPU and 25GB of RAM with the following command:
|
||||
|
||||
```bash
|
||||
|
||||
export TRAIN_FILE=/path/to/dataset/train.txt
|
||||
|
||||
python run_language_modeling.py \
|
||||
--model_type gpt2 \
|
||||
--model_name_or_path gpt2 \
|
||||
--do_train \
|
||||
--train_data_file $TRAIN_FILE \
|
||||
--num_train_epochs 4 \
|
||||
--output_dir model_output \
|
||||
--overwrite_output_dir \
|
||||
--save_steps 10000 \
|
||||
--per_gpu_train_batch_size 3
|
||||
```
|
||||
|
||||
<img alt="training loss" src="https://svgshare.com/i/JTf.svg' title='GTP-2-finetuned-CORDS19-loss" width="600" height="300" />
|
||||
|
||||
## Model in action / Example of usage: ✒
|
||||
|
||||
You can get the following script [here](https://github.com/huggingface/transformers/blob/master/examples/run_generation.py)
|
||||
|
||||
```bash
|
||||
python run_generation.py \
|
||||
--model_type gpt2 \
|
||||
--model_name_or_path mrm8488/GPT-2-finetuned-CORD19 \
|
||||
--length 200
|
||||
```
|
||||
```txt
|
||||
# Input: the effects of COVID-19 on the lungs
|
||||
# Output: === GENERATED SEQUENCE 1 ===
|
||||
the effects of COVID-19 on the lungs are currently debated (86). The role of this virus in the pathogenesis of pneumonia and lung cancer is still debated. MERS-CoV is also known to cause acute respiratory distress syndrome (87) and is associated with increased expression of pulmonary fibrosis markers (88). Thus, early airway inflammation may play an important role in the pathogenesis of coronavirus pneumonia and may contribute to the severe disease and/or mortality observed in coronavirus patients.
|
||||
Pneumonia is an acute, often fatal disease characterized by severe edema, leakage of oxygen and bronchiolar inflammation. Viruses include coronaviruses, and the role of oxygen depletion is complicated by lung injury and fibrosis in the lung, in addition to susceptibility to other lung diseases. The progression of the disease may be variable, depending on the lung injury, pathologic role, prognosis, and the immune status of the patient. Inflammatory responses to respiratory viruses cause various pathologies of the respiratory
|
||||
```
|
||||
|
||||
|
||||
> 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,22 +1,24 @@
|
||||
This model is ALBERT base v2 trained on SQuAD v2 as:
|
||||
This model is [ALBERT base v2](https://huggingface.co/albert-base-v2) trained on SQuAD v2 as:
|
||||
|
||||
```
|
||||
python run_squad.py
|
||||
--model_type albert
|
||||
--model_name_or_path albert-base-v2
|
||||
--do_train
|
||||
--do_eval
|
||||
--overwrite_cache
|
||||
--do_lower_case
|
||||
--version_2_with_negative
|
||||
--train_file $SQUAD_DIR/train-v2.0.json
|
||||
--predict_file $SQUAD_DIR/dev-v2.0.json
|
||||
--per_gpu_train_batch_size 8
|
||||
--num_train_epochs 3
|
||||
--learning_rate 3e-5
|
||||
--max_seq_length 384
|
||||
--doc_stride 128
|
||||
--output_dir ./tmp/albert_base_fine/
|
||||
export SQUAD_DIR=../../squad2
|
||||
python3 run_squad.py
|
||||
--model_type albert
|
||||
--model_name_or_path albert-base-v2
|
||||
--do_train
|
||||
--do_eval
|
||||
--overwrite_cache
|
||||
--do_lower_case
|
||||
--version_2_with_negative
|
||||
--save_steps 100000
|
||||
--train_file $SQUAD_DIR/train-v2.0.json
|
||||
--predict_file $SQUAD_DIR/dev-v2.0.json
|
||||
--per_gpu_train_batch_size 8
|
||||
--num_train_epochs 3
|
||||
--learning_rate 3e-5
|
||||
--max_seq_length 384
|
||||
--doc_stride 128
|
||||
--output_dir ./tmp/albert_fine/
|
||||
```
|
||||
|
||||
Performance on a dev subset is close to the original paper:
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
This model is BERT base uncased trained on SQuAD v2 as:
|
||||
This model is [BERT base uncased](https://huggingface.co/bert-base-uncased) trained on SQuAD v2 as:
|
||||
|
||||
```
|
||||
python run_squad.py
|
||||
--model_type bert
|
||||
--model_name_or_path bert-base-uncased
|
||||
--do_train
|
||||
--do_eval
|
||||
--overwrite_cache
|
||||
--do_lower_case
|
||||
--version_2_with_negative
|
||||
--train_file $SQUAD_DIR/train-v2.0.json
|
||||
--predict_file $SQUAD_DIR/dev-v2.0.json
|
||||
--per_gpu_train_batch_size 8
|
||||
--num_train_epochs 3
|
||||
--learning_rate 3e-5
|
||||
--max_seq_length 384
|
||||
--doc_stride 128
|
||||
--output_dir ./tmp/bert_base_fine/
|
||||
export SQUAD_DIR=../../squad2
|
||||
python3 run_squad.py
|
||||
--model_type bert
|
||||
--model_name_or_path bert-base-uncased
|
||||
--do_train
|
||||
--do_eval
|
||||
--overwrite_cache
|
||||
--do_lower_case
|
||||
--version_2_with_negative
|
||||
--save_steps 100000
|
||||
--train_file $SQUAD_DIR/train-v2.0.json
|
||||
--predict_file $SQUAD_DIR/dev-v2.0.json
|
||||
--per_gpu_train_batch_size 8
|
||||
--num_train_epochs 3
|
||||
--learning_rate 3e-5
|
||||
--max_seq_length 384
|
||||
--doc_stride 128
|
||||
--output_dir ./tmp/bert_fine_tuned/
|
||||
```
|
||||
|
||||
Performance on a dev subset is close to the original paper:
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
This model is [Distilbert base uncased](https://huggingface.co/distilbert-base-uncased) trained on SQuAD v2 as:
|
||||
|
||||
```
|
||||
export SQUAD_DIR=../../squad2
|
||||
python3 run_squad.py
|
||||
--model_type distilbert
|
||||
--model_name_or_path distilbert-base-uncased
|
||||
--do_train
|
||||
--do_eval
|
||||
--overwrite_cache
|
||||
--do_lower_case
|
||||
--version_2_with_negative
|
||||
--save_steps 100000
|
||||
--train_file $SQUAD_DIR/train-v2.0.json
|
||||
--predict_file $SQUAD_DIR/dev-v2.0.json
|
||||
--per_gpu_train_batch_size 8
|
||||
--num_train_epochs 3
|
||||
--learning_rate 3e-5
|
||||
--max_seq_length 384
|
||||
--doc_stride 128
|
||||
--output_dir ./tmp/distilbert_fine_tuned/
|
||||
```
|
||||
|
||||
Performance on a dev subset is close to the original paper:
|
||||
|
||||
```
|
||||
Results:
|
||||
{
|
||||
'exact': 64.88976637051661,
|
||||
'f1': 68.1776176526635,
|
||||
'total': 6078,
|
||||
'HasAns_exact': 69.7594501718213,
|
||||
'HasAns_f1': 76.62665295288285,
|
||||
'HasAns_total': 2910,
|
||||
'NoAns_exact': 60.416666666666664,
|
||||
'NoAns_f1': 60.416666666666664,
|
||||
'NoAns_total': 3168,
|
||||
'best_exact': 64.88976637051661,
|
||||
'best_exact_thresh': 0.0,
|
||||
'best_f1': 68.17761765266337,
|
||||
'best_f1_thresh': 0.0
|
||||
}
|
||||
```
|
||||
|
||||
We are hopeful this might save you time, energy, and compute. Cheers!
|
||||
@@ -0,0 +1,44 @@
|
||||
This model is [Distilroberta base](https://huggingface.co/distilroberta-base) trained on SQuAD v2 as:
|
||||
|
||||
```
|
||||
export SQUAD_DIR=../../squad2
|
||||
python3 run_squad.py
|
||||
--model_type robberta
|
||||
--model_name_or_path distilroberta-base
|
||||
--do_train
|
||||
--do_eval
|
||||
--overwrite_cache
|
||||
--do_lower_case
|
||||
--version_2_with_negative
|
||||
--save_steps 100000
|
||||
--train_file $SQUAD_DIR/train-v2.0.json
|
||||
--predict_file $SQUAD_DIR/dev-v2.0.json
|
||||
--per_gpu_train_batch_size 8
|
||||
--num_train_epochs 3
|
||||
--learning_rate 3e-5
|
||||
--max_seq_length 384
|
||||
--doc_stride 128
|
||||
--output_dir ./tmp/distilroberta_fine_tuned/
|
||||
```
|
||||
|
||||
Performance on a dev subset is close to the original paper:
|
||||
|
||||
```
|
||||
Results:
|
||||
{
|
||||
'exact': 70.9279368213228,
|
||||
'f1': 74.60439802429168,
|
||||
'total': 6078,
|
||||
'HasAns_exact': 67.62886597938144,
|
||||
'HasAns_f1': 75.30774267754136,
|
||||
'HasAns_total': 2910,
|
||||
'NoAns_exact': 73.95833333333333,
|
||||
'NoAns_f1': 73.95833333333333, 'NoAns_total': 3168,
|
||||
'best_exact': 70.94438960184272,
|
||||
'best_exact_thresh': 0.0,
|
||||
'best_f1': 74.62085080481161,
|
||||
'best_f1_thresh': 0.0
|
||||
}
|
||||
```
|
||||
|
||||
We are hopeful this might save you time, energy, and compute. Cheers!
|
||||
@@ -97,6 +97,8 @@ setup(
|
||||
install_requires=[
|
||||
"numpy",
|
||||
"tokenizers == 0.5.2",
|
||||
# dataclasses for Python versions that don't have it
|
||||
"dataclasses;python_version<'3.7'",
|
||||
# accessing files from S3 directly
|
||||
"boto3",
|
||||
# filesystem locks e.g. to prevent parallel downloads
|
||||
|
||||
@@ -22,17 +22,15 @@ import logging
|
||||
# Benchmarking
|
||||
from .benchmark_utils import (
|
||||
Frame,
|
||||
Memory,
|
||||
MemoryState,
|
||||
MemorySummary,
|
||||
MemoryTrace,
|
||||
UsedMemoryState,
|
||||
bytes_to_human_readable,
|
||||
start_memory_tracing,
|
||||
stop_memory_tracing,
|
||||
)
|
||||
from .configuration_albert import ALBERT_PRETRAINED_CONFIG_ARCHIVE_MAP, AlbertConfig
|
||||
from .configuration_auto import ALL_PRETRAINED_CONFIG_ARCHIVE_MAP, AutoConfig
|
||||
from .configuration_auto import ALL_PRETRAINED_CONFIG_ARCHIVE_MAP, CONFIG_MAPPING, AutoConfig
|
||||
from .configuration_bart import BartConfig
|
||||
from .configuration_bert import BERT_PRETRAINED_CONFIG_ARCHIVE_MAP, BertConfig
|
||||
from .configuration_camembert import CAMEMBERT_PRETRAINED_CONFIG_ARCHIVE_MAP, CamembertConfig
|
||||
@@ -116,10 +114,11 @@ from .pipelines import (
|
||||
SummarizationPipeline,
|
||||
TextClassificationPipeline,
|
||||
TokenClassificationPipeline,
|
||||
TranslationPipeline,
|
||||
pipeline,
|
||||
)
|
||||
from .tokenization_albert import AlbertTokenizer
|
||||
from .tokenization_auto import AutoTokenizer
|
||||
from .tokenization_auto import TOKENIZER_MAPPING, AutoTokenizer
|
||||
from .tokenization_bart import BartTokenizer
|
||||
from .tokenization_bert import BasicTokenizer, BertTokenizer, BertTokenizerFast, WordpieceTokenizer
|
||||
from .tokenization_bert_japanese import BertJapaneseTokenizer, CharacterTokenizer, MecabTokenizer
|
||||
|
||||
@@ -9,7 +9,8 @@ import logging
|
||||
import os
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from typing import Iterable, List, NamedTuple, Optional, Union
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterable, List, Optional, Union
|
||||
|
||||
from .file_utils import is_tf_available, is_torch_available
|
||||
|
||||
@@ -31,14 +32,14 @@ def is_memory_tracing_enabled():
|
||||
return _is_memory_tracing_enabled
|
||||
|
||||
|
||||
class Frame(NamedTuple):
|
||||
""" `Frame` is a NamedTuple used to gather the current frame state.
|
||||
`Frame` has the following fields:
|
||||
- 'filename' (string): Name of the file currently executed
|
||||
- 'module' (string): Name of the module currently executed
|
||||
- 'line_number' (int): Number of the line currently executed
|
||||
- 'event' (string): Event that triggered the tracing (default will be "line")
|
||||
- 'line_text' (string): Text of the line in the python script
|
||||
@dataclass(frozen=True)
|
||||
class Frame:
|
||||
""" `Frame` is used to gather the current frame state:
|
||||
- 'filename' (string): Name of the file currently executed
|
||||
- 'module' (string): Name of the module currently executed
|
||||
- 'line_number' (int): Number of the line currently executed
|
||||
- 'event' (string): Event that triggered the tracing (default will be "line")
|
||||
- 'line_text' (string): Text of the line in the python script
|
||||
"""
|
||||
|
||||
filename: str
|
||||
@@ -48,61 +49,67 @@ class Frame(NamedTuple):
|
||||
line_text: str
|
||||
|
||||
|
||||
class UsedMemoryState(NamedTuple):
|
||||
""" `UsedMemoryState` are named tuples with the following fields:
|
||||
- 'frame': a `Frame` namedtuple (see below) storing information on the current tracing frame (current file, location in current file)
|
||||
- 'cpu_memory': CPU RSS memory state *before* executing the line
|
||||
- 'gpu_memory': GPU used memory *before* executing the line (sum for all GPUs or for only `gpus_to_trace` if provided)
|
||||
@dataclass
|
||||
class MemoryState:
|
||||
""" `MemoryState` lists frame + CPU/GPU memory:
|
||||
- `cpu`: CPU memory at or before the current frame as a `Memory` named tuple
|
||||
- `gpu`: GPU memory at or before during the current frame as a `Memory` named tuple
|
||||
- `frame` (`Frame`): the current frame
|
||||
Also provide a few properties:
|
||||
`cpu_gpu`: sum of the CPU + GPU memory at or before during the current frame as a `Memory` named tuple
|
||||
`cpu_with_units`: CPU memory as a human readable string
|
||||
`gpu_with_units`: GPU memory as a human readable string
|
||||
`cpu_gpu_with_units`: CPU+GPU memory as a human readable string
|
||||
"""
|
||||
|
||||
frame: Frame
|
||||
cpu_memory: int
|
||||
gpu_memory: int
|
||||
cpu: int
|
||||
gpu: int
|
||||
frame: Optional[Frame] = None
|
||||
|
||||
@property
|
||||
def cpu_gpu(self) -> int:
|
||||
return self.cpu + self.gpu
|
||||
|
||||
@property
|
||||
def cpu_with_units(self) -> str:
|
||||
return bytes_to_human_readable(self.cpu)
|
||||
|
||||
@property
|
||||
def gpu_with_units(self) -> str:
|
||||
return bytes_to_human_readable(self.gpu)
|
||||
|
||||
@property
|
||||
def cpu_gpu_with_units(self) -> str:
|
||||
return bytes_to_human_readable(self.cpu + self.gpu)
|
||||
|
||||
|
||||
class Memory(NamedTuple):
|
||||
""" `Memory` NamedTuple have a single field `bytes` and
|
||||
you can get a human readable string of the number of bytes by calling `__repr__`
|
||||
- `byte` (integer): number of bytes,
|
||||
"""
|
||||
|
||||
bytes: int
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return bytes_to_human_readable(self.bytes)
|
||||
|
||||
|
||||
class MemoryState(NamedTuple):
|
||||
""" `MemoryState` are namedtuples listing frame + CPU/GPU memory with the following fields:
|
||||
- `frame` (`Frame`): the current frame (see above)
|
||||
- `cpu`: CPU memory consumed at during the current frame as a `Memory` named tuple
|
||||
- `gpu`: GPU memory consumed at during the current frame as a `Memory` named tuple
|
||||
- `cpu_gpu`: CPU + GPU memory consumed at during the current frame as a `Memory` named tuple
|
||||
"""
|
||||
|
||||
frame: Frame
|
||||
cpu: Memory
|
||||
gpu: Memory
|
||||
cpu_gpu: Memory
|
||||
|
||||
|
||||
class MemorySummary(NamedTuple):
|
||||
@dataclass
|
||||
class MemorySummary:
|
||||
""" `MemorySummary` namedtuple otherwise with the fields:
|
||||
- `sequential`: a list of `MemoryState` namedtuple (see below) computed from the provided `memory_trace`
|
||||
- `absolute_mem_list`: total CPU/GPU memory used at each line
|
||||
a list of `MemoryState` namedtuple (see below)
|
||||
- `relative_mem_list`: relative difference in CPU/GPU memory at each line
|
||||
a list of `MemoryState` namedtuple (see below) computed from the provided `memory_trace`
|
||||
by substracting the memory after executing each line from the memory before executing said line.
|
||||
- `cumulative`: a list of `MemoryState` namedtuple (see below) with cumulative increase in memory for each line
|
||||
- `absolute_mem_sorted`: total CPU/GPU memory used at each line sorted by lines (max among all the times a line is executed)
|
||||
a list of `MemoryState` namedtuple (see below)
|
||||
The list is sorted from the frame with the largest memory consumption to the frame with the smallest (can be negative if memory is released)
|
||||
- `relative_mem_sorted`: relative difference in CPU/GPU memory sorted by lines (cumulative increase among all the times a line is executed)
|
||||
a list of `MemoryState` namedtuple (see below) with cumulative increase in memory for each line
|
||||
obtained by summing repeted memory increase for a line if it's executed several times.
|
||||
The list is sorted from the frame with the largest memory consumption to the frame with the smallest (can be negative if memory is released)
|
||||
- `total`: total memory increase during the full tracing as a `Memory` named tuple (see below).
|
||||
Line with memory release (negative consumption) are ignored if `ignore_released_memory` is `True` (default).
|
||||
"""
|
||||
|
||||
sequential: List[MemoryState]
|
||||
cumulative: List[MemoryState]
|
||||
total: Memory
|
||||
absolute_mem_list: List[MemoryState]
|
||||
relative_mem_list: List[MemoryState]
|
||||
absolute_mem_sorted: List[MemoryState]
|
||||
relative_mem_sorted: List[MemoryState]
|
||||
relative_mem_total: MemoryState
|
||||
|
||||
|
||||
MemoryTrace = List[UsedMemoryState]
|
||||
MemoryTrace = List[MemoryState]
|
||||
|
||||
|
||||
def start_memory_tracing(
|
||||
@@ -129,13 +136,14 @@ def start_memory_tracing(
|
||||
- `gpus_to_trace`: (optional list, default None) list of GPUs to trace. Default to tracing all GPUs
|
||||
|
||||
Return:
|
||||
- `memory_trace` is a list of `UsedMemoryState` for each event (default each line of the traced script).
|
||||
- `UsedMemoryState` are named tuples with the following fields:
|
||||
- `memory_trace` is a list of `MemoryState` for each event (default each line of the traced script).
|
||||
- `MemoryState` are simple classes with the following attributes:
|
||||
- 'frame': a `Frame` namedtuple (see below) storing information on the current tracing frame (current file, location in current file)
|
||||
- 'cpu_memory': CPU RSS memory state *before* executing the line
|
||||
- 'gpu_memory': GPU used memory *before* executing the line (sum for all GPUs or for only `gpus_to_trace` if provided)
|
||||
- 'cpu': CPU RSS memory state *before* executing the line
|
||||
- 'gpu': GPU used memory *before* executing the line (sum for all GPUs or for only `gpus_to_trace` if provided)
|
||||
- `cpu_gpu`: CPU + GPU memory *before* executing the line
|
||||
|
||||
`Frame` is a namedtuple used by `UsedMemoryState` to list the current frame state.
|
||||
`Frame` is a namedtuple used by `MemoryState` to list the current frame state.
|
||||
`Frame` has the following fields:
|
||||
- 'filename' (string): Name of the file currently executed
|
||||
- 'module' (string): Name of the module currently executed
|
||||
@@ -240,7 +248,7 @@ def start_memory_tracing(
|
||||
gpu_mem += meminfo.used
|
||||
py3nvml.nvmlShutdown()
|
||||
|
||||
mem_state = UsedMemoryState(traced_state, cpu_mem, gpu_mem)
|
||||
mem_state = MemoryState(cpu_mem, gpu_mem, traced_state)
|
||||
memory_trace.append(mem_state)
|
||||
|
||||
return traceit
|
||||
@@ -294,39 +302,38 @@ def stop_memory_tracing(
|
||||
_is_memory_tracing_enabled = False
|
||||
|
||||
if memory_trace is not None and len(memory_trace) > 1:
|
||||
memory_diff_trace = []
|
||||
cumulative_memory_dict = defaultdict(lambda: [0, 0, 0])
|
||||
for (frame, cpu_mem, gpu_mem), (next_frame, next_cpu_mem, next_gpu_mem) in zip(
|
||||
memory_trace[:-1], memory_trace[1:]
|
||||
):
|
||||
cpu_mem_inc = next_cpu_mem - cpu_mem
|
||||
gpu_mem_inc = next_gpu_mem - gpu_mem
|
||||
cpu_gpu_mem_inc = cpu_mem_inc + gpu_mem_inc
|
||||
memory_diff_trace.append(
|
||||
MemoryState(
|
||||
frame=frame, cpu=Memory(cpu_mem_inc), gpu=Memory(gpu_mem_inc), cpu_gpu=Memory(cpu_gpu_mem_inc),
|
||||
)
|
||||
)
|
||||
cumulative_memory_dict[frame][0] += cpu_mem_inc
|
||||
cumulative_memory_dict[frame][1] += gpu_mem_inc
|
||||
cumulative_memory_dict[frame][2] += cpu_gpu_mem_inc
|
||||
init_mem = memory_trace[0]
|
||||
absolute_mem_list = []
|
||||
relative_mem_list = []
|
||||
absolute_mem_dict = defaultdict(lambda: [])
|
||||
relative_mem_dict = defaultdict(lambda: [])
|
||||
for line, next_line in zip(memory_trace[:-1], memory_trace[1:]):
|
||||
absolute_mem = MemoryState(line.cpu - init_mem.cpu, line.gpu - init_mem.gpu, line.frame)
|
||||
relative_mem = MemoryState(next_line.cpu - line.cpu, next_line.gpu - line.gpu, line.frame)
|
||||
absolute_mem_list.append(absolute_mem)
|
||||
relative_mem_list.append(relative_mem)
|
||||
absolute_mem_dict[line.frame].append(absolute_mem)
|
||||
relative_mem_dict[line.frame].append(relative_mem)
|
||||
|
||||
cumulative_memory = sorted(
|
||||
list(cumulative_memory_dict.items()), key=lambda x: x[1][2], reverse=True
|
||||
) # order by the total CPU + GPU memory increase
|
||||
cumulative_memory = list(
|
||||
MemoryState(
|
||||
frame=frame, cpu=Memory(cpu_mem_inc), gpu=Memory(gpu_mem_inc), cpu_gpu=Memory(cpu_gpu_mem_inc),
|
||||
)
|
||||
for frame, (cpu_mem_inc, gpu_mem_inc, cpu_gpu_mem_inc) in cumulative_memory
|
||||
relative_mem_sorted = list(MemoryState(sum(v.cpu for v in l), sum(v.gpu for v in l), k) for k, l in relative_mem_dict.items())
|
||||
absolute_mem_sorted = list(MemoryState(max(v.cpu for v in l), max(v.gpu for v in l), k) for k, l in absolute_mem_dict.items())
|
||||
|
||||
relative_mem_sorted = sorted(relative_mem_sorted, key=lambda x: x.cpu_gpu, reverse=True)
|
||||
absolute_mem_sorted = sorted(absolute_mem_sorted, key=lambda x: x.cpu_gpu, reverse=True)
|
||||
|
||||
to_sum = (
|
||||
filter(lambda m: m.cpu_gpu > 0, relative_mem_list)
|
||||
if ignore_released_memory
|
||||
else relative_mem_list
|
||||
)
|
||||
relative_mem_total = MemoryState(sum(v.cpu for v in to_sum), sum(v.gpu for v in to_sum))
|
||||
return MemorySummary(
|
||||
absolute_mem_list=absolute_mem_list,
|
||||
relative_mem_list=relative_mem_list,
|
||||
relative_mem_sorted=relative_mem_sorted,
|
||||
absolute_mem_sorted=absolute_mem_sorted,
|
||||
relative_mem_total=relative_mem_total,
|
||||
)
|
||||
|
||||
if ignore_released_memory:
|
||||
total_memory = sum(max(0, step_trace.cpu_gpu.bytes) for step_trace in memory_diff_trace)
|
||||
else:
|
||||
total_memory = sum(step_trace.cpu_gpu.bytes for step_trace in memory_diff_trace)
|
||||
total_memory = Memory(total_memory)
|
||||
return MemorySummary(sequential=memory_diff_trace, cumulative=cumulative_memory, total=total_memory)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -78,9 +78,6 @@ class PretrainedConfig(object):
|
||||
self.top_k = kwargs.pop("top_k", 50)
|
||||
self.top_p = kwargs.pop("top_p", 1.0)
|
||||
self.repetition_penalty = kwargs.pop("repetition_penalty", 1.0)
|
||||
self.bos_token_id = kwargs.pop("bos_token_id", None)
|
||||
self.pad_token_id = kwargs.pop("pad_token_id", None)
|
||||
self.eos_token_id = kwargs.pop("eos_token_id", None)
|
||||
self.length_penalty = kwargs.pop("length_penalty", 1.0)
|
||||
self.no_repeat_ngram_size = kwargs.pop("no_repeat_ngram_size", 0)
|
||||
self.num_return_sequences = kwargs.pop("num_return_sequences", 1)
|
||||
@@ -94,6 +91,16 @@ class PretrainedConfig(object):
|
||||
self.label2id = kwargs.pop("label2id", dict(zip(self.id2label.values(), self.id2label.keys())))
|
||||
self.label2id = dict((key, int(value)) for key, value in self.label2id.items())
|
||||
|
||||
# Tokenizer arguments TODO: eventually tokenizer and models should share the same config
|
||||
self.prefix = kwargs.pop("prefix", None)
|
||||
self.bos_token_id = kwargs.pop("bos_token_id", None)
|
||||
self.pad_token_id = kwargs.pop("pad_token_id", None)
|
||||
self.eos_token_id = kwargs.pop("eos_token_id", None)
|
||||
self.decoder_start_token_id = kwargs.pop("decoder_start_token_id", None)
|
||||
|
||||
# task specific arguments
|
||||
self.task_specific_params = kwargs.pop("task_specific_params", None)
|
||||
|
||||
# Additional attributes without default values
|
||||
for key, value in kwargs.items():
|
||||
try:
|
||||
@@ -373,3 +380,14 @@ class PretrainedConfig(object):
|
||||
"""
|
||||
with open(json_file_path, "w", encoding="utf-8") as writer:
|
||||
writer.write(self.to_json_string())
|
||||
|
||||
def update(self, config_dict: Dict):
|
||||
"""
|
||||
Updates attributes of this class
|
||||
with attributes from `config_dict`.
|
||||
|
||||
Args:
|
||||
:obj:`Dict[str, any]`: Dictionary of attributes that shall be updated for this class.
|
||||
"""
|
||||
for key, value in config_dict.items():
|
||||
setattr(self, key, value)
|
||||
@@ -139,6 +139,7 @@ def squad_convert_example_to_features(example, max_seq_length, doc_stride, max_q
|
||||
pad_to_max_length=True,
|
||||
stride=max_seq_length - doc_stride - len(truncated_query) - sequence_pair_added_tokens,
|
||||
truncation_strategy="only_second" if tokenizer.padding_side == "right" else "only_first",
|
||||
return_token_type_ids=True,
|
||||
)
|
||||
|
||||
paragraph_len = min(
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
|
||||
import copy
|
||||
import csv
|
||||
import dataclasses
|
||||
import json
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
from ...file_utils import is_tf_available, is_torch_available
|
||||
|
||||
@@ -25,7 +28,8 @@ from ...file_utils import is_tf_available, is_torch_available
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class InputExample(object):
|
||||
@dataclass(frozen=True)
|
||||
class InputExample:
|
||||
"""
|
||||
A single training/test example for simple sequence classification.
|
||||
|
||||
@@ -39,23 +43,14 @@ class InputExample(object):
|
||||
specified for train and dev examples, but not for test examples.
|
||||
"""
|
||||
|
||||
def __init__(self, guid, text_a, text_b=None, label=None):
|
||||
self.guid = guid
|
||||
self.text_a = text_a
|
||||
self.text_b = text_b
|
||||
self.label = label
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.to_json_string())
|
||||
|
||||
def to_dict(self):
|
||||
"""Serializes this instance to a Python dictionary."""
|
||||
output = copy.deepcopy(self.__dict__)
|
||||
return output
|
||||
guid: str
|
||||
text_a: str
|
||||
text_b: Optional[str] = None
|
||||
label: Optional[str] = None
|
||||
|
||||
def to_json_string(self):
|
||||
"""Serializes this instance to a JSON string."""
|
||||
return json.dumps(self.to_dict(), indent=2, sort_keys=True) + "\n"
|
||||
return json.dumps(dataclasses.asdict(self), indent=2, sort_keys=True) + "\n"
|
||||
|
||||
|
||||
class InputFeatures(object):
|
||||
|
||||
@@ -610,7 +610,9 @@ class TFPreTrainedModel(tf.keras.Model, TFModelUtilsMixin):
|
||||
num_return_sequences = (
|
||||
num_return_sequences if num_return_sequences is not None else self.config.num_return_sequences
|
||||
)
|
||||
decoder_start_token_id = decoder_start_token_id if decoder_start_token_id is not None else bos_token_id
|
||||
decoder_start_token_id = (
|
||||
decoder_start_token_id if decoder_start_token_id is not None else self.config.decoder_start_token_id
|
||||
)
|
||||
|
||||
if input_ids is not None:
|
||||
batch_size = shape_list(input_ids)[0] # overriden by the input batch_size
|
||||
@@ -635,9 +637,6 @@ class TFPreTrainedModel(tf.keras.Model, TFModelUtilsMixin):
|
||||
assert (eos_token_id is None) or (
|
||||
isinstance(eos_token_id, int) and (eos_token_id >= 0)
|
||||
), "`eos_token_id` should be a positive integer."
|
||||
assert (
|
||||
decoder_start_token_id is not None or self.config.is_encoder_decoder is False
|
||||
), "`decoder_start_token_id` has to be defined if model is encoder-decoder model"
|
||||
assert length_penalty > 0, "`length_penalty` should be strictely positive."
|
||||
assert (
|
||||
isinstance(num_return_sequences, int) and num_return_sequences > 0
|
||||
@@ -708,8 +707,12 @@ class TFPreTrainedModel(tf.keras.Model, TFModelUtilsMixin):
|
||||
) # shape: (batch_size * num_return_sequences * num_beams, cur_len)
|
||||
|
||||
if self.config.is_encoder_decoder:
|
||||
if decoder_start_token_id is None:
|
||||
decoder_start_token_id = bos_token_id
|
||||
|
||||
assert bos_token_id is not None, "Encoder Decoder Models need to have a bos_token_id"
|
||||
assert (
|
||||
decoder_start_token_id is not None
|
||||
), "decoder_start_token_id or bos_token_id has to be defined for encoder-decoder generation"
|
||||
assert hasattr(self, "get_encoder"), "{} should have a 'get_encoder' function defined".format(self)
|
||||
assert callable(self.get_encoder), "{} should be a method".format(self.get_encoder)
|
||||
|
||||
@@ -996,10 +999,12 @@ class TFPreTrainedModel(tf.keras.Model, TFModelUtilsMixin):
|
||||
# set eos token prob to zero if min_length is not reached
|
||||
if eos_token_id is not None and cur_len < min_length:
|
||||
# create eos_token_id boolean mask
|
||||
num_batch_hypotheses = batch_size * num_beams
|
||||
|
||||
is_token_logit_eos_token = tf.convert_to_tensor(
|
||||
[True if token is eos_token_id else False for token in range(vocab_size)], dtype=tf.bool
|
||||
)
|
||||
eos_token_indices_mask = tf.broadcast_to(is_token_logit_eos_token, [batch_size, vocab_size])
|
||||
eos_token_indices_mask = tf.broadcast_to(is_token_logit_eos_token, [num_batch_hypotheses, vocab_size])
|
||||
|
||||
scores = set_tensor_by_indices_to_value(scores, eos_token_indices_mask, -float("inf"))
|
||||
|
||||
|
||||
@@ -809,7 +809,9 @@ class PreTrainedModel(nn.Module, ModuleUtilsMixin):
|
||||
num_return_sequences = (
|
||||
num_return_sequences if num_return_sequences is not None else self.config.num_return_sequences
|
||||
)
|
||||
decoder_start_token_id = decoder_start_token_id if decoder_start_token_id is not None else bos_token_id
|
||||
decoder_start_token_id = (
|
||||
decoder_start_token_id if decoder_start_token_id is not None else self.config.decoder_start_token_id
|
||||
)
|
||||
|
||||
if input_ids is not None:
|
||||
batch_size = input_ids.shape[0] # overriden by the input batch_size
|
||||
@@ -831,9 +833,6 @@ class PreTrainedModel(nn.Module, ModuleUtilsMixin):
|
||||
assert pad_token_id is None or (
|
||||
isinstance(pad_token_id, int) and (pad_token_id >= 0)
|
||||
), "`pad_token_id` should be a positive integer."
|
||||
assert (
|
||||
decoder_start_token_id is not None or self.config.is_encoder_decoder is False
|
||||
), "`decoder_start_token_id` has to be defined if model is encoder-decoder model"
|
||||
assert (eos_token_id is None) or (
|
||||
isinstance(eos_token_id, int) and (eos_token_id >= 0)
|
||||
), "`eos_token_id` should be a positive integer."
|
||||
@@ -912,7 +911,12 @@ class PreTrainedModel(nn.Module, ModuleUtilsMixin):
|
||||
) # shape: (batch_size * num_return_sequences * num_beams, cur_len)
|
||||
|
||||
if self.config.is_encoder_decoder:
|
||||
assert bos_token_id is not None, "Encoder Decoder Models need to have a bos_token_id"
|
||||
if decoder_start_token_id is None:
|
||||
decoder_start_token_id = bos_token_id
|
||||
|
||||
assert (
|
||||
decoder_start_token_id is not None
|
||||
), "decoder_start_token_id or bos_token_id has to be defined for encoder-decoder generation"
|
||||
assert hasattr(self, "get_encoder"), "{} should have a 'get_encoder' function defined".format(self)
|
||||
assert callable(self.get_encoder), "{} should be a method".format(self.get_encoder)
|
||||
|
||||
|
||||
+241
-43
@@ -31,6 +31,7 @@ from .configuration_auto import ALL_PRETRAINED_CONFIG_ARCHIVE_MAP, AutoConfig
|
||||
from .configuration_bart import BartConfig
|
||||
from .configuration_distilbert import DistilBertConfig
|
||||
from .configuration_roberta import RobertaConfig
|
||||
from .configuration_t5 import T5Config
|
||||
from .configuration_utils import PretrainedConfig
|
||||
from .configuration_xlm import XLMConfig
|
||||
from .data import SquadExample, squad_convert_examples_to_features
|
||||
@@ -60,7 +61,6 @@ if is_torch_available():
|
||||
AutoModelForTokenClassification,
|
||||
AutoModelWithLMHead,
|
||||
)
|
||||
from .modeling_bart import BartForConditionalGeneration
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -130,7 +130,9 @@ class PipelineDataFormat:
|
||||
|
||||
SUPPORTED_FORMATS = ["json", "csv", "pipe"]
|
||||
|
||||
def __init__(self, output_path: Optional[str], input_path: Optional[str], column: Optional[str], overwrite=False):
|
||||
def __init__(
|
||||
self, output_path: Optional[str], input_path: Optional[str], column: Optional[str], overwrite=False,
|
||||
):
|
||||
self.output_path = output_path
|
||||
self.input_path = input_path
|
||||
self.column = column.split(",") if column is not None else [""]
|
||||
@@ -176,7 +178,7 @@ class PipelineDataFormat:
|
||||
|
||||
@staticmethod
|
||||
def from_str(
|
||||
format: str, output_path: Optional[str], input_path: Optional[str], column: Optional[str], overwrite=False
|
||||
format: str, output_path: Optional[str], input_path: Optional[str], column: Optional[str], overwrite=False,
|
||||
):
|
||||
if format == "json":
|
||||
return JsonPipelineDataFormat(output_path, input_path, column, overwrite=overwrite)
|
||||
@@ -189,7 +191,9 @@ class PipelineDataFormat:
|
||||
|
||||
|
||||
class CsvPipelineDataFormat(PipelineDataFormat):
|
||||
def __init__(self, output_path: Optional[str], input_path: Optional[str], column: Optional[str], overwrite=False):
|
||||
def __init__(
|
||||
self, output_path: Optional[str], input_path: Optional[str], column: Optional[str], overwrite=False,
|
||||
):
|
||||
super().__init__(output_path, input_path, column, overwrite=overwrite)
|
||||
|
||||
def __iter__(self):
|
||||
@@ -210,7 +214,9 @@ class CsvPipelineDataFormat(PipelineDataFormat):
|
||||
|
||||
|
||||
class JsonPipelineDataFormat(PipelineDataFormat):
|
||||
def __init__(self, output_path: Optional[str], input_path: Optional[str], column: Optional[str], overwrite=False):
|
||||
def __init__(
|
||||
self, output_path: Optional[str], input_path: Optional[str], column: Optional[str], overwrite=False,
|
||||
):
|
||||
super().__init__(output_path, input_path, column, overwrite=overwrite)
|
||||
|
||||
with open(input_path, "r") as f:
|
||||
@@ -336,6 +342,7 @@ class Pipeline(_ScikitCompat):
|
||||
tokenizer: PreTrainedTokenizer,
|
||||
modelcard: Optional[ModelCard] = None,
|
||||
framework: Optional[str] = None,
|
||||
task: str = "",
|
||||
args_parser: ArgumentHandler = None,
|
||||
device: int = -1,
|
||||
binary_output: bool = False,
|
||||
@@ -356,6 +363,11 @@ class Pipeline(_ScikitCompat):
|
||||
if self.framework == "pt" and self.device.type == "cuda":
|
||||
self.model = self.model.to(self.device)
|
||||
|
||||
# Update config with task specific parameters
|
||||
task_specific_params = self.model.config.task_specific_params
|
||||
if task_specific_params is not None and task in task_specific_params:
|
||||
self.model.config.update(task_specific_params.get(task))
|
||||
|
||||
def save_pretrained(self, save_directory):
|
||||
"""
|
||||
Save the pipeline's model and tokenizer to the specified save_directory
|
||||
@@ -420,7 +432,7 @@ class Pipeline(_ScikitCompat):
|
||||
"""
|
||||
args = ["input_ids", "attention_mask"]
|
||||
|
||||
if not isinstance(self.model.config, (DistilBertConfig, XLMConfig, RobertaConfig, BartConfig)):
|
||||
if not isinstance(self.model.config, (DistilBertConfig, XLMConfig, RobertaConfig, BartConfig, T5Config)):
|
||||
args += ["token_type_ids"]
|
||||
|
||||
# PR #1548 (CLI) There is an issue with attention_mask
|
||||
@@ -432,14 +444,18 @@ class Pipeline(_ScikitCompat):
|
||||
else:
|
||||
return {k: [feature[k] for feature in features] for k in args}
|
||||
|
||||
def _parse_and_tokenize(self, *texts, **kwargs):
|
||||
def _parse_and_tokenize(self, *texts, pad_to_max_length=False, **kwargs):
|
||||
"""
|
||||
Parse arguments and tokenize
|
||||
"""
|
||||
# Parse arguments
|
||||
inputs = self._args_parser(*texts, **kwargs)
|
||||
inputs = self.tokenizer.batch_encode_plus(
|
||||
inputs, add_special_tokens=True, return_tensors=self.framework, max_length=self.tokenizer.max_len
|
||||
inputs,
|
||||
add_special_tokens=True,
|
||||
return_tensors=self.framework,
|
||||
max_length=self.tokenizer.max_len,
|
||||
pad_to_max_length=pad_to_max_length,
|
||||
)
|
||||
|
||||
# Filter out features not available on specific models
|
||||
@@ -520,6 +536,7 @@ class FeatureExtractionPipeline(Pipeline):
|
||||
framework: Optional[str] = None,
|
||||
args_parser: ArgumentHandler = None,
|
||||
device: int = -1,
|
||||
task: str = "",
|
||||
):
|
||||
super().__init__(
|
||||
model=model,
|
||||
@@ -529,6 +546,7 @@ class FeatureExtractionPipeline(Pipeline):
|
||||
args_parser=args_parser,
|
||||
device=device,
|
||||
binary_output=True,
|
||||
task=task,
|
||||
)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
@@ -625,6 +643,7 @@ class FillMaskPipeline(Pipeline):
|
||||
args_parser: ArgumentHandler = None,
|
||||
device: int = -1,
|
||||
topk=5,
|
||||
task: str = "",
|
||||
):
|
||||
super().__init__(
|
||||
model=model,
|
||||
@@ -634,6 +653,7 @@ class FillMaskPipeline(Pipeline):
|
||||
args_parser=args_parser,
|
||||
device=device,
|
||||
binary_output=True,
|
||||
task=task,
|
||||
)
|
||||
|
||||
self.topk = topk
|
||||
@@ -725,6 +745,7 @@ class NerPipeline(Pipeline):
|
||||
device: int = -1,
|
||||
binary_output: bool = False,
|
||||
ignore_labels=["O"],
|
||||
task: str = "",
|
||||
):
|
||||
super().__init__(
|
||||
model=model,
|
||||
@@ -734,6 +755,7 @@ class NerPipeline(Pipeline):
|
||||
args_parser=args_parser,
|
||||
device=device,
|
||||
binary_output=binary_output,
|
||||
task=task,
|
||||
)
|
||||
|
||||
self._basic_tokenizer = BasicTokenizer(do_lower_case=False)
|
||||
@@ -896,6 +918,7 @@ class QuestionAnsweringPipeline(Pipeline):
|
||||
modelcard: Optional[ModelCard] = None,
|
||||
framework: Optional[str] = None,
|
||||
device: int = -1,
|
||||
task: str = "",
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
@@ -905,6 +928,7 @@ class QuestionAnsweringPipeline(Pipeline):
|
||||
framework=framework,
|
||||
args_parser=QuestionAnsweringArgumentHandler(),
|
||||
device=device,
|
||||
task=task,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
@@ -1102,7 +1126,11 @@ class QuestionAnsweringPipeline(Pipeline):
|
||||
chars_idx += len(word) + 1
|
||||
|
||||
# Join text with spaces
|
||||
return {"answer": " ".join(words), "start": max(0, char_start_idx), "end": min(len(text), char_end_idx)}
|
||||
return {
|
||||
"answer": " ".join(words),
|
||||
"start": max(0, char_start_idx),
|
||||
"end": min(len(text), char_end_idx),
|
||||
}
|
||||
|
||||
|
||||
class SummarizationPipeline(Pipeline):
|
||||
@@ -1111,12 +1139,16 @@ class SummarizationPipeline(Pipeline):
|
||||
|
||||
Usage::
|
||||
|
||||
# use bart in pytorch
|
||||
summarizer = pipeline("summarization")
|
||||
summarizer("Sam Shleifer writes the best docstring examples in the whole world.")
|
||||
summarizer("Sam Shleifer writes the best docstring examples in the whole world.", min_length=5, max_length=20)
|
||||
|
||||
# use t5 in tf
|
||||
summarizer = pipeline("summarization", model="t5-base", tokenizer="t5-base", framework="tf")
|
||||
summarizer("Sam Shleifer writes the best docstring examples in the whole world.", min_length=5, max_length=20)
|
||||
|
||||
Supported Models:
|
||||
The models that this pipeline can use are models that have been fine-tuned on a summarization task, which is
|
||||
currently only ``BartForConditionalGeneration.from_pretrained('bart-large-cnn')``
|
||||
The models that this pipeline can use are models that have been fine-tuned on a summarization task, which is currently, '`bart-large-cnn`', '`t5-small`', '`t5-base`', '`t5-large`', '`t5-3b`', '`t5-11b`'.
|
||||
|
||||
Arguments:
|
||||
model (:obj:`str` or :obj:`~transformers.PreTrainedModel` or :obj:`~transformers.TFPreTrainedModel`, `optional`, defaults to :obj:`None`):
|
||||
@@ -1147,17 +1179,8 @@ class SummarizationPipeline(Pipeline):
|
||||
on the associated CUDA device id.
|
||||
"""
|
||||
|
||||
task = "summarization"
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
*documents,
|
||||
return_tensors=False,
|
||||
return_text=True,
|
||||
max_length=142,
|
||||
min_length=21,
|
||||
clean_up_tokenization_spaces=False,
|
||||
**generate_kwargs
|
||||
self, *documents, return_tensors=False, return_text=True, clean_up_tokenization_spaces=False, **generate_kwargs
|
||||
):
|
||||
r"""
|
||||
Args:
|
||||
@@ -1165,10 +1188,6 @@ class SummarizationPipeline(Pipeline):
|
||||
return_text: (bool, default=True) whether to add a decoded "summary_text" to each result
|
||||
return_tensors: (bool, default=False) whether to return the raw "summary_token_ids" to each result
|
||||
|
||||
max_length: (`optional`) int
|
||||
The max length of the sequence to be generated. Does not include tokens in input_ids.
|
||||
min_len: (`optional`) int
|
||||
no_repeat_ngram_size: (`optional`) int. ban ngrams of this length from being repeated in the generated text
|
||||
clean_up_tokenization_spaces: (`optional`) bool whether to include extra spaces in the output
|
||||
**generate_kwargs: extra kwargs passed to `self.model.generate`_
|
||||
|
||||
@@ -1180,19 +1199,60 @@ class SummarizationPipeline(Pipeline):
|
||||
|
||||
"""
|
||||
assert return_tensors or return_text, "You must specify return_tensors=True or return_text=True"
|
||||
if self.framework == "tf":
|
||||
raise NotImplementedError("Tensorflow not supported")
|
||||
with self.device_placement():
|
||||
inputs = self._parse_and_tokenize(*documents)
|
||||
inputs = self.ensure_tensor_on_device(**inputs)
|
||||
summaries = self.model.generate(
|
||||
inputs["input_ids"],
|
||||
attention_mask=inputs["attention_mask"],
|
||||
max_length=max_length,
|
||||
min_length=min_length,
|
||||
do_sample=False,
|
||||
**generate_kwargs,
|
||||
assert len(documents) > 0, "Please provide a document to summarize"
|
||||
|
||||
if self.framework == "tf" and "BartForConditionalGeneration" in self.model.__class__.__name__:
|
||||
raise NotImplementedError(
|
||||
"Tensorflow is not yet supported for Bart. Please consider using T5, e.g. `t5-base`"
|
||||
)
|
||||
|
||||
prefix = self.model.config.prefix if self.model.config.prefix is not None else ""
|
||||
|
||||
if isinstance(documents[0], list):
|
||||
assert (
|
||||
self.tokenizer.pad_token_id is not None
|
||||
), "Please make sure that the tokenizer has a pad_token_id when using a batch input"
|
||||
|
||||
documents = ([prefix + document for document in documents[0]],)
|
||||
pad_to_max_length = True
|
||||
|
||||
elif isinstance(documents[0], str):
|
||||
documents = (prefix + documents[0],)
|
||||
pad_to_max_length = False
|
||||
else:
|
||||
raise ValueError(
|
||||
" `documents[0]`: {} have the wrong format. The should be either of type `str` or type `list`".format(
|
||||
documents[0]
|
||||
)
|
||||
)
|
||||
|
||||
with self.device_placement():
|
||||
inputs = self._parse_and_tokenize(*documents, pad_to_max_length=pad_to_max_length)
|
||||
|
||||
if self.framework == "pt":
|
||||
inputs = self.ensure_tensor_on_device(**inputs)
|
||||
input_length = inputs["input_ids"].shape[-1]
|
||||
elif self.framework == "tf":
|
||||
input_length = tf.shape(inputs["input_ids"])[-1].numpy()
|
||||
|
||||
if input_length < self.model.config.min_length // 2:
|
||||
logger.warning(
|
||||
"Your min_length is set to {}, but you input_length is only {}. You might consider decreasing min_length manually, e.g. summarizer('...', min_length=10)".format(
|
||||
self.model.config.min_length, input_length
|
||||
)
|
||||
)
|
||||
|
||||
if input_length < self.model.config.max_length:
|
||||
logger.warning(
|
||||
"Your max_length is set to {}, but you input_length is only {}. You might consider decreasing max_length manually, e.g. summarizer('...', max_length=50)".format(
|
||||
self.model.config.max_length, input_length
|
||||
)
|
||||
)
|
||||
|
||||
summaries = self.model.generate(
|
||||
inputs["input_ids"], attention_mask=inputs["attention_mask"], **generate_kwargs,
|
||||
)
|
||||
|
||||
results = []
|
||||
for summary in summaries:
|
||||
record = {}
|
||||
@@ -1200,7 +1260,115 @@ class SummarizationPipeline(Pipeline):
|
||||
record["summary_token_ids"] = summary
|
||||
if return_text:
|
||||
record["summary_text"] = self.tokenizer.decode(
|
||||
summary, skip_special_tokens=True, clean_up_tokenization_spaces=clean_up_tokenization_spaces
|
||||
summary, skip_special_tokens=True, clean_up_tokenization_spaces=clean_up_tokenization_spaces,
|
||||
)
|
||||
results.append(record)
|
||||
return results
|
||||
|
||||
|
||||
class TranslationPipeline(Pipeline):
|
||||
"""
|
||||
Translates from one language to another.
|
||||
|
||||
Usage::
|
||||
en_fr_translator = pipeline("translation_en_to_fr")
|
||||
en_fr_translator("How old are you?")
|
||||
|
||||
Supported Models: "t5-small", "t5-base", "t5-large", "t5-3b", "t5-11b"
|
||||
|
||||
Arguments:
|
||||
model (:obj:`str` or :obj:`~transformers.PreTrainedModel` or :obj:`~transformers.TFPreTrainedModel`, `optional`, defaults to :obj:`None`):
|
||||
The model that will be used by the pipeline to make predictions. This can be :obj:`None`, a string
|
||||
checkpoint identifier or an actual pre-trained model inheriting from
|
||||
:class:`~transformers.PreTrainedModel` for PyTorch and :class:`~transformers.TFPreTrainedModel` for
|
||||
TensorFlow.
|
||||
If :obj:`None`, the default of the pipeline will be loaded.
|
||||
tokenizer (:obj:`str` or :obj:`~transformers.PreTrainedTokenizer`, `optional`, defaults to :obj:`None`):
|
||||
The tokenizer that will be used by the pipeline to encode data for the model. This can be :obj:`None`,
|
||||
a string checkpoint identifier or an actual pre-trained tokenizer inheriting from
|
||||
:class:`~transformers.PreTrainedTokenizer`.
|
||||
If :obj:`None`, the default of the pipeline will be loaded.
|
||||
modelcard (:obj:`str` or :class:`~transformers.ModelCard`, `optional`, defaults to :obj:`None`):
|
||||
Model card attributed to the model for this pipeline.
|
||||
framework (:obj:`str`, `optional`, defaults to :obj:`None`):
|
||||
The framework to use, either "pt" for PyTorch or "tf" for TensorFlow. The specified framework must be
|
||||
installed.
|
||||
If no framework is specified, will default to the one currently installed. If no framework is specified
|
||||
and both frameworks are installed, will default to PyTorch.
|
||||
args_parser (:class:`~transformers.pipelines.ArgumentHandler`, `optional`, defaults to :obj:`None`):
|
||||
Reference to the object in charge of parsing supplied pipeline parameters.
|
||||
device (:obj:`int`, `optional`, defaults to :obj:`-1`):
|
||||
Device ordinal for CPU/GPU supports. Setting this to -1 will leverage CPU, >=0 will run the model
|
||||
on the associated CUDA device id.
|
||||
"""
|
||||
|
||||
def __call__(
|
||||
self, *texts, return_tensors=False, return_text=True, clean_up_tokenization_spaces=False, **generate_kwargs
|
||||
):
|
||||
r"""
|
||||
Args:
|
||||
*texts: (list of strings) articles to be summarized
|
||||
return_text: (bool, default=True) whether to add a decoded "translation_text" to each result
|
||||
return_tensors: (bool, default=False) whether to return the raw "translation_token_ids" to each result
|
||||
|
||||
**generate_kwargs: extra kwargs passed to `self.model.generate`_
|
||||
|
||||
Returns:
|
||||
list of dicts with 'translation_text' and/or 'translation_token_ids' for each text_to_translate
|
||||
.. _`self.model.generate`:
|
||||
https://huggingface.co/transformers/model_doc/bart.html#transformers.BartForConditionalGeneration.generate
|
||||
"""
|
||||
assert return_tensors or return_text, "You must specify return_tensors=True or return_text=True"
|
||||
|
||||
prefix = self.model.config.prefix if self.model.config.prefix is not None else ""
|
||||
|
||||
if isinstance(texts[0], list):
|
||||
assert (
|
||||
self.tokenizer.pad_token_id is not None
|
||||
), "Please make sure that the tokenizer has a pad_token_id when using a batch input"
|
||||
texts = ([prefix + text for text in texts[0]],)
|
||||
pad_to_max_length = True
|
||||
|
||||
elif isinstance(texts[0], str):
|
||||
texts = (prefix + texts[0],)
|
||||
pad_to_max_length = False
|
||||
else:
|
||||
raise ValueError(
|
||||
" `documents[0]`: {} have the wrong format. The should be either of type `str` or type `list`".format(
|
||||
texts[0]
|
||||
)
|
||||
)
|
||||
|
||||
with self.device_placement():
|
||||
inputs = self._parse_and_tokenize(*texts, pad_to_max_length=pad_to_max_length)
|
||||
|
||||
if self.framework == "pt":
|
||||
inputs = self.ensure_tensor_on_device(**inputs)
|
||||
input_length = inputs["input_ids"].shape[-1]
|
||||
|
||||
elif self.framework == "tf":
|
||||
input_length = tf.shape(inputs["input_ids"])[-1].numpy()
|
||||
|
||||
if input_length > 0.9 * self.model.config.max_length:
|
||||
logger.warning(
|
||||
"Your input_length: {} is bigger than 0.9 * max_length: {}. You might consider increasing your max_length manually, e.g. translator('...', max_length=400)".format(
|
||||
input_length, self.model.config.max_length
|
||||
)
|
||||
)
|
||||
|
||||
translations = self.model.generate(
|
||||
inputs["input_ids"], attention_mask=inputs["attention_mask"], **generate_kwargs,
|
||||
)
|
||||
results = []
|
||||
for translation in translations:
|
||||
record = {}
|
||||
if return_tensors:
|
||||
record["translation_token_ids"] = translation
|
||||
if return_text:
|
||||
record["translation_text"] = self.tokenizer.decode(
|
||||
translation,
|
||||
skip_special_tokens=True,
|
||||
clean_up_tokenization_spaces=clean_up_tokenization_spaces,
|
||||
)
|
||||
results.append(record)
|
||||
return results
|
||||
@@ -1266,14 +1434,44 @@ SUPPORTED_TASKS = {
|
||||
},
|
||||
"summarization": {
|
||||
"impl": SummarizationPipeline,
|
||||
"pt": BartForConditionalGeneration if is_torch_available() else None,
|
||||
"tf": None,
|
||||
"tf": TFAutoModelWithLMHead if is_tf_available() else None,
|
||||
"pt": AutoModelWithLMHead if is_torch_available() else None,
|
||||
"default": {
|
||||
"model": {"pt": "bart-large-cnn", "tf": None},
|
||||
"config": None,
|
||||
"tokenizer": ("bart-large-cnn", {"use_fast": False}),
|
||||
},
|
||||
},
|
||||
"translation_en_to_fr": {
|
||||
"impl": TranslationPipeline,
|
||||
"tf": TFAutoModelWithLMHead if is_tf_available() else None,
|
||||
"pt": AutoModelWithLMHead if is_torch_available() else None,
|
||||
"default": {
|
||||
"model": {"pt": "t5-base", "tf": "t5-base"},
|
||||
"config": None,
|
||||
"tokenizer": ("t5-base", {"use_fast": False}),
|
||||
},
|
||||
},
|
||||
"translation_en_to_de": {
|
||||
"impl": TranslationPipeline,
|
||||
"tf": TFAutoModelWithLMHead if is_tf_available() else None,
|
||||
"pt": AutoModelWithLMHead if is_torch_available() else None,
|
||||
"default": {
|
||||
"model": {"pt": "t5-base", "tf": "t5-base"},
|
||||
"config": None,
|
||||
"tokenizer": ("t5-base", {"use_fast": False}),
|
||||
},
|
||||
},
|
||||
"translation_en_to_ro": {
|
||||
"impl": TranslationPipeline,
|
||||
"tf": TFAutoModelWithLMHead if is_tf_available() else None,
|
||||
"pt": AutoModelWithLMHead if is_torch_available() else None,
|
||||
"default": {
|
||||
"model": {"pt": "t5-base", "tf": "t5-base"},
|
||||
"config": None,
|
||||
"tokenizer": ("t5-base", {"use_fast": False}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1361,7 +1559,7 @@ def pipeline(
|
||||
framework = framework or get_framework(model)
|
||||
|
||||
targeted_task = SUPPORTED_TASKS[task]
|
||||
task, model_class = targeted_task["impl"], targeted_task[framework]
|
||||
task_class, model_class = targeted_task["impl"], targeted_task[framework]
|
||||
|
||||
# Use default model/config/tokenizer for the task if no model is provided
|
||||
if model is None:
|
||||
@@ -1422,4 +1620,4 @@ def pipeline(
|
||||
)
|
||||
model = model_class.from_pretrained(model, config=config, **model_kwargs)
|
||||
|
||||
return task(model=model, tokenizer=tokenizer, modelcard=modelcard, framework=framework, **kwargs)
|
||||
return task_class(model=model, tokenizer=tokenizer, modelcard=modelcard, framework=framework, task=task, **kwargs,)
|
||||
+47
-4
@@ -78,6 +78,15 @@ TF_FILL_MASK_FINETUNED_MODELS = [
|
||||
(("distilroberta-base", {"use_fast": False}), "distilroberta-base", None),
|
||||
]
|
||||
|
||||
SUMMARIZATION_FINETUNED_MODELS = {("bart-large-cnn", "bart-large-cnn"), ("t5-small", "t5-small")}
|
||||
TF_SUMMARIZATION_FINETUNED_MODELS = {("t5-small", "t5-small")}
|
||||
|
||||
TRANSLATION_FINETUNED_MODELS = {
|
||||
("t5-small", "t5-small", "translation_en_to_de"),
|
||||
("t5-small", "t5-small", "translation_en_to_ro"),
|
||||
}
|
||||
TF_TRANSLATION_FINETUNED_MODELS = {("t5-small", "t5-small", "translation_en_to_fr")}
|
||||
|
||||
|
||||
class MonoColumnInputTestCase(unittest.TestCase):
|
||||
def _test_mono_column_pipeline(
|
||||
@@ -252,10 +261,44 @@ class MonoColumnInputTestCase(unittest.TestCase):
|
||||
valid_inputs = ["A string like this", ["list of strings entry 1", "list of strings v2"]]
|
||||
invalid_inputs = [4, "<mask>"]
|
||||
mandatory_keys = ["summary_text"]
|
||||
nlp = pipeline(task="summarization")
|
||||
self._test_mono_column_pipeline(
|
||||
nlp, valid_inputs, invalid_inputs, mandatory_keys,
|
||||
)
|
||||
for model, tokenizer in SUMMARIZATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="summarization", model=model, tokenizer=tokenizer)
|
||||
self._test_mono_column_pipeline(
|
||||
nlp, valid_inputs, invalid_inputs, mandatory_keys,
|
||||
)
|
||||
|
||||
@require_tf
|
||||
def test_tf_summarization(self):
|
||||
valid_inputs = ["A string like this", ["list of strings entry 1", "list of strings v2"]]
|
||||
invalid_inputs = [4, "<mask>"]
|
||||
mandatory_keys = ["summary_text"]
|
||||
for model, tokenizer in TF_SUMMARIZATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task="summarization", model=model, tokenizer=tokenizer, framework="tf")
|
||||
self._test_mono_column_pipeline(
|
||||
nlp, valid_inputs, invalid_inputs, mandatory_keys,
|
||||
)
|
||||
|
||||
@require_torch
|
||||
def test_translation(self):
|
||||
valid_inputs = ["A string like this", ["list of strings entry 1", "list of strings v2"]]
|
||||
invalid_inputs = [4, "<mask>"]
|
||||
mandatory_keys = ["translation_text"]
|
||||
for model, tokenizer, task in TRANSLATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task=task, model=model, tokenizer=tokenizer)
|
||||
self._test_mono_column_pipeline(
|
||||
nlp, valid_inputs, invalid_inputs, mandatory_keys,
|
||||
)
|
||||
|
||||
@require_tf
|
||||
def test_tf_translation(self):
|
||||
valid_inputs = ["A string like this", ["list of strings entry 1", "list of strings v2"]]
|
||||
invalid_inputs = [4, "<mask>"]
|
||||
mandatory_keys = ["translation_text"]
|
||||
for model, tokenizer, task in TF_TRANSLATION_FINETUNED_MODELS:
|
||||
nlp = pipeline(task=task, model=model, tokenizer=tokenizer, framework="tf")
|
||||
self._test_mono_column_pipeline(
|
||||
nlp, valid_inputs, invalid_inputs, mandatory_keys,
|
||||
)
|
||||
|
||||
|
||||
class MultiColumnInputTestCase(unittest.TestCase):
|
||||
|
||||
Reference in new issue
Block a user