Spaces:
Runtime error
Runtime error
| #!/usr/bin/env python | |
| # coding=utf-8 | |
| # Copyright 2021 The HuggingFace Team. 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 sequence to sequence. | |
| """ | |
| # You can also adapt this script on your own sequence to sequence task. Pointers for this are left as comments. | |
| import logging | |
| import os | |
| import sys | |
| import numpy as np | |
| from unlimiformer import Unlimiformer | |
| from random_training_unlimiformer import RandomTrainingUnlimiformer | |
| import nltk | |
| # we import the logging frameworks before any other import to make sure all monkey patching for the logging are active | |
| # from sled import SledConfig | |
| import wandb | |
| import torch | |
| sys.path.insert(0, os.path.dirname(__file__)) # seq2seq package path | |
| sys.path.insert(0, os.getcwd()) | |
| from dataclasses import dataclass, field, replace | |
| from typing import List, Optional | |
| import json | |
| from copy import deepcopy | |
| import torch.nn.functional as F | |
| import datasets | |
| import transformers | |
| from transformers import ( | |
| AutoConfig, | |
| AutoModelForSeq2SeqLM, | |
| AutoTokenizer, | |
| EarlyStoppingCallback, | |
| set_seed, WEIGHTS_NAME, | |
| ) | |
| from transformers.trainer_utils import get_last_checkpoint | |
| from transformers import DataCollatorForSeq2Seq | |
| from datasets import load_dataset | |
| # noinspection PyUnresolvedReferences | |
| # import sled # *** required so that SledModels will be registered for the AutoClasses *** | |
| from utils.config import handle_args_to_ignore | |
| from utils.decoding import decode | |
| from metrics import load_metric | |
| from utils.duplicates import drop_duplicates_in_input | |
| from utils.override_training_args import TrainingOverridesArguments | |
| from utils.custom_seq2seq_trainer import CustomTrainer | |
| from utils.custom_hf_argument_parser import CustomHfArgumentParser | |
| from metrics.metrics import HFMetricWrapper, MetricCollection | |
| logger = logging.getLogger('sled') | |
| PREFIX_DOC_SEP = '\n\n' | |
| DEBUG = os.environ.get('DEBUG', 'false').lower() in {'1', 'true', 'yes'} # If set, will set some configuration to help debug | |
| if DEBUG: | |
| assert not torch.cuda.is_available() or torch.cuda.device_count() == 1 | |
| class ModelArguments: | |
| """ | |
| Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. | |
| """ | |
| model_name_or_path: str = field( | |
| default=None, 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"} | |
| ) | |
| cache_dir: Optional[str] = field( | |
| default=None, | |
| metadata={"help": "Where to store the pretrained models downloaded from huggingface.co"}, | |
| ) | |
| use_fast_tokenizer: bool = field( | |
| default=True, | |
| metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, | |
| ) | |
| model_revision: str = field( | |
| default="main", | |
| metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, | |
| ) | |
| drop_duplicates_in_eval: bool = field( | |
| default=True, | |
| ) | |
| def __post_init__(self): | |
| pass | |
| class DataTrainingArguments: | |
| """ | |
| Arguments pertaining to what data we are going to input our model for training and eval. | |
| """ | |
| dataset_name: Optional[str] = field( | |
| default=None, | |
| metadata={ | |
| "help": "The name of the dataset to use (via the datasets library) or name of the file in src/data." | |
| }, | |
| ) | |
| dataset_config_name: Optional[str] = field( | |
| default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} | |
| ) | |
| metric_names: Optional[List[str]] = field( | |
| default=None, | |
| metadata={"help": "The name of the metric to use (from src/metrics)."}, | |
| ) | |
| input_column: Optional[str] = field( | |
| default=None, | |
| metadata={"help": "The name of the column in the datasets containing the full texts (for summarization)."}, | |
| ) | |
| input_prefix_column: Optional[str] = field( | |
| default=None, | |
| metadata={"help": "The name of the column in the datasets containing the input prefix (e.g. questions), when those exist."}, | |
| ) | |
| output_column: Optional[str] = field( | |
| default=None, | |
| metadata={"help": "The name of the column in the datasets containing the summaries (for summarization)."}, | |
| ) | |
| train_file: Optional[str] = field( | |
| default=None, metadata={"help": "The input training data file (a jsonlines or csv file)."} | |
| ) | |
| validation_file: Optional[str] = field( | |
| default=None, | |
| metadata={ | |
| "help": "An optional input evaluation data file to evaluate the metrics (rouge) on " | |
| "(a jsonlines or csv file)." | |
| }, | |
| ) | |
| test_file: Optional[str] = field( | |
| default=None, | |
| metadata={ | |
| "help": "An optional input test data file to evaluate the metrics (rouge) on " "(a jsonlines or csv file)." | |
| }, | |
| ) | |
| overwrite_cache: bool = field( | |
| default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} | |
| ) | |
| preprocessing_num_workers: Optional[int] = field( | |
| default=None, | |
| metadata={"help": "The number of processes to use for the preprocessing."}, | |
| ) | |
| max_source_length: Optional[int] = field( | |
| default=None, | |
| metadata={ | |
| "help": "The maximum total input sequence length after tokenization. Sequences longer " | |
| "than this will be truncated, sequences shorter will be padded." | |
| }, | |
| ) | |
| eval_max_source_length: Optional[int] = field( | |
| default=None, | |
| metadata={"help": "if None, will be same as max_source_length"}, | |
| ) | |
| max_prefix_length: Optional[int] = field( | |
| default=0, | |
| metadata={ | |
| "help": "The maximum total input_prefix sequence length after tokenization. Sequences longer " | |
| "than this will be truncated, sequences shorter will be padded from the left " | |
| "(only used if prefixes are not merged)." | |
| }, | |
| ) | |
| max_target_length: Optional[int] = field( | |
| default=128, | |
| metadata={ | |
| "help": "The maximum total sequence length for target text after tokenization. Sequences longer " | |
| "than this will be truncated, sequences shorter will be padded." | |
| }, | |
| ) | |
| val_max_target_length: Optional[int] = field( | |
| default=None, | |
| metadata={ | |
| "help": "The maximum total sequence length for validation target text after tokenization. Sequences longer " | |
| "than this will be truncated, sequences shorter will be padded. Will default to `max_target_length`." | |
| "This argument is also used to override the ``max_length`` param of ``model.generate``, which is used " | |
| "during ``evaluate`` and ``predict``." | |
| }, | |
| ) | |
| pad_to_max_length: bool = field( | |
| default=False, | |
| metadata={ | |
| "help": "Whether to pad all samples to model maximum sentence length. " | |
| "If False, will pad the samples dynamically when batching to the maximum length in the batch. More " | |
| "efficient on GPU but very bad for TPU." | |
| }, | |
| ) | |
| max_train_samples: Optional[int] = field( | |
| default=None, | |
| metadata={ | |
| "help": "For debugging purposes or quicker training, truncate the number of training examples to this " | |
| "value if set." | |
| }, | |
| ) | |
| max_eval_samples: Optional[int] = field( | |
| default=None, | |
| metadata={ | |
| "help": "For debugging purposes or quicker training, truncate the number of evaluation examples to this " | |
| "value if set." | |
| }, | |
| ) | |
| max_predict_samples: Optional[int] = field( | |
| default=None, | |
| metadata={ | |
| "help": "For debugging purposes or quicker training, truncate the number of prediction examples to this " | |
| "value if set." | |
| }, | |
| ) | |
| num_beams: Optional[int] = field( | |
| default=None, | |
| metadata={ | |
| "help": "Number of beams to use for evaluation. This argument will be passed to ``model.generate``, " | |
| "which is used during ``evaluate`` and ``predict``." | |
| }, | |
| ) | |
| ignore_pad_token_for_loss: bool = field( | |
| default=True, | |
| metadata={ | |
| "help": "Whether to ignore the tokens corresponding to padded labels in the loss computation or not." | |
| }, | |
| ) | |
| source_prefix: Optional[str] = field( | |
| default=None, metadata={"help": "A prefix to add before every source text (useful for T5 models)."} | |
| ) | |
| data_dir: Optional[str] = field( | |
| default=None, | |
| metadata={"help": "Defining the data_dir of the dataset configuration."}, | |
| ) | |
| download_mode: Optional[str] = field( | |
| default=None, | |
| metadata={ | |
| "help": "Defining the download_mode when loading the dataset. Options are `reuse_dataset_if_exists` (default), `reuse_cache_if_exists` and `force_redownload`." | |
| }, | |
| ) | |
| evaluate_on_training_data: bool = field( | |
| default=False, | |
| metadata={"help": "Whether to evaluate on training data or not, to make sure the model can overfit."}, | |
| ) | |
| folder_suffix: str = field( | |
| default="", | |
| metadata={"help": "args to be suffixes for the output folder of the run"}, | |
| ) | |
| preprocess_only: bool = field( | |
| default=False, | |
| metadata={"help": "Preprocess only: Don't start training, just do the things before"}, | |
| ) | |
| assign_zero_to_too_long_val_examples: bool = field( | |
| default=False, | |
| metadata={ | |
| "help": "If true, all sequences longer then max_source_length will be assign a score of 0 in the metric evaluation" | |
| }, | |
| ) | |
| shared_storage: bool = field( | |
| default=True, | |
| metadata={"help": "Whether nodes share the same storage"}, | |
| ) | |
| trim_very_long_strings: bool = field( | |
| default=False, | |
| metadata={"help": "Whether to trim very long strings before tokenizing them"}, | |
| ) | |
| pad_prefix: bool = field( | |
| default=False, | |
| metadata={ | |
| "help": "Whether to pad the prefix if it exists to max_prefix_length. " | |
| "Note - important if you are using a SLED model on an input that contains an input_prefix" | |
| }, | |
| ) | |
| test_start_ind: Optional[int] = field( | |
| default=None, | |
| metadata={"help": "if given, uses the test set starting from this index"}, | |
| ) | |
| test_end_ind: Optional[int] = field( | |
| default=None, | |
| metadata={"help": "if given, uses the test set ending at this index"}, | |
| ) | |
| # Uri: | |
| patience: Optional[int] = field( | |
| default=None, | |
| ) | |
| length_penalty: Optional[float] = field( | |
| default=1.0, | |
| ) | |
| extra_metrics: Optional[List[str]] = field( | |
| default=None, | |
| metadata={"help": "The name of the metric to use (from src/metrics)."}, | |
| ) | |
| chunked_training_size: Optional[int] = field( | |
| default=None, | |
| ) | |
| oracle_training: Optional[bool] = field( | |
| default=False, | |
| metadata={"help": "If True, train on the input sentences that provide the highest ROUGE score with the labels"} | |
| ) | |
| oracle_merge: Optional[bool] = field( | |
| default=False, | |
| metadata={"help": "If True, merge the oracle dataset and the standard training dataset"} | |
| ) | |
| def __post_init__(self): | |
| if self.val_max_target_length is None: | |
| self.val_max_target_length = self.max_target_length | |
| if self.pad_prefix and self.max_prefix_length == 0: | |
| raise ValueError('When padding prefix, you must set a max_prefix_length') | |
| assert self.max_prefix_length == 0 or self.max_prefix_length <= 0.5*self.max_source_length,\ | |
| 'If max_prefix_length is given, it must be much shorter than the total input' | |
| # Uri: | |
| if self.eval_max_source_length is None: | |
| self.eval_max_source_length = self.max_source_length | |
| class UnlimiformerArguments: | |
| """ | |
| Arguments pertaining to what data we are going to input our model for training and eval. | |
| """ | |
| test_unlimiformer: Optional[bool] = field( | |
| default=False, | |
| metadata={ | |
| "help": "whether to use KNN." | |
| }, | |
| ) | |
| unlimiformer_verbose: Optional[bool] = field( | |
| default=False, | |
| metadata={ | |
| "help": "whether to print KNN intermediate predictions (mostly for debugging)." | |
| }, | |
| ) | |
| layer_begin: Optional[int] = field( | |
| default=0, | |
| metadata={"help": "The layer to begin applying KNN to. KNN will be applied to layers[knn_layer_begin:layer_end]. " | |
| "By default, it will be applied to all layers: [0:None]]"}, | |
| ) | |
| layer_end: Optional[int] = field( | |
| default=None, | |
| metadata={"help": "The layer to end applying KNN to. KNN will be applied to layers[knn_layer_begin:layer_end]. " | |
| "By default, it will be applied to all layers: [0:None]]"}, | |
| ) | |
| unlimiformer_chunk_overlap: Optional[float] = field( | |
| default=0.5, | |
| metadata={"help": "The fraction of overlap between input chunks"}, | |
| ) | |
| unlimiformer_chunk_size: Optional[int] = field( | |
| default=None, | |
| metadata={"help": "The size of each input chunk"}, | |
| ) | |
| unlimiformer_head_num: Optional[int] = field( | |
| default=None, | |
| metadata={"help": "The head to apply KNN to (if None, apply to all heads)"}, | |
| ) | |
| unlimiformer_exclude: Optional[bool] = field( | |
| default=False, | |
| metadata={ | |
| "help": "If True, prioritize the inputs that are **not** in the standard attention window." | |
| }, | |
| ) | |
| random_unlimiformer_training: Optional[bool] = field( | |
| default=False, | |
| ) | |
| unlimiformer_training: Optional[bool] = field( | |
| default=False, | |
| ) | |
| use_datastore: Optional[bool] = field(default=False) | |
| flat_index: Optional[bool] = field(default=False) | |
| test_datastore: Optional[bool] = field(default=False) | |
| reconstruct_embeddings: Optional[bool] = field(default=False) | |
| gpu_datastore: Optional[bool] = field(default=True) | |
| gpu_index: Optional[bool] = field(default=True) | |
| def main(): | |
| handle_args_to_ignore(sys.argv) # Just for sweeps | |
| # 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 = CustomHfArgumentParser((ModelArguments, DataTrainingArguments, TrainingOverridesArguments, UnlimiformerArguments)) | |
| model_args, data_args, training_args, unlimiformer_args = parser.parse_dictionary_and_args() | |
| set_up_logging(training_args) | |
| logger.info(f"Training Arguments: {training_args}") | |
| logger.info(f"Data Arguments: {data_args}") | |
| logger.info(f"Model Arguments: {model_args}") | |
| logger.info(f"Unlimiformer Arguments: {unlimiformer_args}") | |
| # Added to avoid wandb.errors.UsageError: Error communicating with wandb process | |
| wandb.init(settings=wandb.Settings(start_method="fork"), name=training_args.output_dir) | |
| # Used to find missing dependencies early on | |
| load_metric(data_args.metric_names, **locals()) | |
| load_extra_metrics(data_args.extra_metrics) | |
| if data_args.source_prefix is None and model_args.model_name_or_path in [ | |
| "t5-small", | |
| "t5-base", | |
| "t5-large", | |
| "t5-3b", | |
| "t5-11b", | |
| ]: | |
| logger.warning( | |
| "You're running a t5 model but didn't provide a source prefix, which is the expected, e.g. with " | |
| "`--source_prefix 'summarize: ' `" | |
| ) | |
| # Detecting last checkpoint. | |
| last_checkpoint = _detect_last_checkpoint(training_args) | |
| # Set seed before initializing model. | |
| set_seed(training_args.seed) | |
| seq2seq_dataset = _get_dataset(data_args, model_args, training_args) | |
| # Load pretrained model and tokenizer | |
| # | |
| # Distributed training: | |
| # The .from_pretrained methods guarantee that only one local process can concurrently | |
| # download model & vocab. | |
| config_name = None | |
| if model_args.config_name: | |
| config_name = model_args.config_name | |
| else: | |
| if os.path.isfile(model_args.model_name_or_path): | |
| config_name = os.path.dirname(model_args.model_name_or_path) | |
| else: | |
| config_name = model_args.model_name_or_path | |
| config_overrides = {} | |
| if training_args.gradient_checkpointing is not None: | |
| config_overrides["gradient_checkpointing"] = training_args.gradient_checkpointing | |
| config = AutoConfig.from_pretrained( | |
| config_name, | |
| cache_dir=model_args.cache_dir, | |
| revision=model_args.model_revision, | |
| use_auth_token=training_args.use_auth_token, | |
| **config_overrides | |
| ) | |
| # override for sled models to make sure we are explicit in our request | |
| # if isinstance(config, SledConfig) and (not data_args.pad_prefix or data_args.max_prefix_length == 0): | |
| # logger.warning('Setting prepend_prefix to False if using a SLED model, as the input does not have a prefix or ' | |
| # 'pad_prefix is False (all prefixes must be of the same length for SLED). If you do not use SLED ' | |
| # 'or finetune on a dataset with no prefixes, ignore this warning') | |
| # config.prepend_prefix = False | |
| if model_args.model_name_or_path is None: | |
| # Padding for divisibility by 8 | |
| if config.vocab_size % 8 != 0 and training_args.fp16_padding: | |
| config.vocab_size += 8 - (config.vocab_size % 8) | |
| tokenizer_name = None | |
| if model_args.tokenizer_name: | |
| tokenizer_name = model_args.tokenizer_name | |
| else: | |
| if os.path.isfile(model_args.model_name_or_path): | |
| tokenizer_name = os.path.dirname(model_args.model_name_or_path) | |
| else: | |
| tokenizer_name = model_args.model_name_or_path | |
| tokenizer = AutoTokenizer.from_pretrained( | |
| tokenizer_name, | |
| cache_dir=model_args.cache_dir, | |
| use_fast=model_args.use_fast_tokenizer, | |
| revision=model_args.model_revision, | |
| use_auth_token=training_args.use_auth_token, | |
| ) | |
| if model_args.model_name_or_path is not None: | |
| model = AutoModelForSeq2SeqLM.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, | |
| revision=model_args.model_revision, | |
| use_auth_token=training_args.use_auth_token, | |
| ) | |
| else: | |
| model = AutoModelForSeq2SeqLM.from_config( | |
| config, | |
| ) | |
| if unlimiformer_args.test_unlimiformer: | |
| unlimiformer_kwargs = { | |
| 'layer_begin': unlimiformer_args.layer_begin, | |
| 'layer_end': unlimiformer_args.layer_end, | |
| 'unlimiformer_head_num': unlimiformer_args.unlimiformer_head_num, | |
| 'exclude_attention': unlimiformer_args.unlimiformer_exclude, | |
| 'chunk_overlap': unlimiformer_args.unlimiformer_chunk_overlap, | |
| 'model_encoder_max_len': unlimiformer_args.unlimiformer_chunk_size, | |
| 'verbose': unlimiformer_args.unlimiformer_verbose, 'tokenizer': tokenizer, | |
| 'unlimiformer_training': unlimiformer_args.unlimiformer_training, | |
| 'use_datastore': unlimiformer_args.use_datastore, | |
| 'flat_index': unlimiformer_args.flat_index, | |
| 'test_datastore': unlimiformer_args.test_datastore, | |
| 'reconstruct_embeddings': unlimiformer_args.reconstruct_embeddings, | |
| 'gpu_datastore': unlimiformer_args.gpu_datastore, | |
| 'gpu_index': unlimiformer_args.gpu_index | |
| } | |
| if unlimiformer_args.random_unlimiformer_training: | |
| model = RandomTrainingUnlimiformer.convert_model(model, **unlimiformer_kwargs) | |
| else: | |
| model = Unlimiformer.convert_model(model, **unlimiformer_kwargs) | |
| model.config.use_cache = True | |
| if training_args.gradient_checkpointing and getattr(model.config, 'use_cache', False) and training_args.do_train: | |
| logger.warning('Cannot use cache in models when using gradient checkpointing. turning it off') | |
| model.config.use_cache = False | |
| model.resize_token_embeddings(len(tokenizer)) | |
| if model.config.decoder_start_token_id is None: | |
| raise ValueError("Make sure that `config.decoder_start_token_id` is correctly defined") | |
| prefix = data_args.source_prefix if data_args.source_prefix is not None else "" | |
| # Preprocessing the datasets. | |
| # We need to tokenize inputs and targets. | |
| if training_args.do_train: | |
| column_names = seq2seq_dataset["train"].column_names | |
| elif training_args.do_eval: | |
| column_names = seq2seq_dataset["validation"].column_names | |
| elif training_args.do_predict: | |
| column_names = seq2seq_dataset["test"].column_names | |
| else: | |
| logger.info("There is nothing to do. Please pass `do_train`, `do_eval` and/or `do_predict`.") | |
| return | |
| # Get the column names for input/target. | |
| if data_args.input_column is None: | |
| input_column = "input" | |
| else: | |
| input_column = data_args.input_column | |
| if input_column not in column_names: | |
| raise ValueError( | |
| f"--input_column' value '{data_args.input_column}' needs to be one of: {', '.join(column_names)}" | |
| ) | |
| if data_args.input_prefix_column is None: | |
| input_prefix_column = "input_prefix" | |
| else: | |
| input_prefix_column = data_args.input_prefix_column | |
| if input_prefix_column not in column_names: | |
| raise ValueError( | |
| f"--input_prefix_column' value '{data_args.input_prefix_column}' needs to be one of: {', '.join(column_names)}" | |
| ) | |
| if data_args.output_column is None: | |
| output_column = "output" | |
| else: | |
| output_column = data_args.output_column | |
| if output_column not in column_names: | |
| raise ValueError( | |
| f"--output_column' value '{data_args.output_column}' needs to be one of: {', '.join(column_names)}" | |
| ) | |
| # Temporarily set max_target_length for training. | |
| max_target_length = data_args.max_target_length | |
| padding = "max_length" if data_args.pad_to_max_length else False | |
| if training_args.label_smoothing_factor > 0 and not hasattr(model, "prepare_decoder_input_ids_from_labels"): | |
| logger.warning( | |
| "label_smoothing is enabled but the `prepare_decoder_input_ids_from_labels` method is not defined for" | |
| f"`{model.__class__.__name__}`. This will lead to loss being calculated twice and will take up more memory" | |
| ) | |
| def preprocess_function_kwargs_fn(): | |
| return { | |
| "tokenizer": deepcopy(tokenizer), | |
| "prefix": prefix, | |
| "input_column": input_column, | |
| "input_prefix_column": input_prefix_column, | |
| "output_column": output_column, | |
| "max_source_length": data_args.max_source_length, | |
| "max_prefix_length": data_args.max_prefix_length, | |
| "max_target_length": max_target_length, | |
| "prefix_sep": PREFIX_DOC_SEP, | |
| "padding": padding, | |
| "ignore_pad_token_for_loss": data_args.ignore_pad_token_for_loss, | |
| "assign_zero_to_too_long_val_examples": data_args.assign_zero_to_too_long_val_examples, | |
| "trim_very_long_strings": data_args.trim_very_long_strings, | |
| "pad_prefix": data_args.pad_prefix | |
| } | |
| if training_args.do_train: | |
| if "train" not in seq2seq_dataset: | |
| raise ValueError("--do_train requires a train dataset") | |
| logger.info("") | |
| logger.info("Training examples before tokenization:") | |
| if input_prefix_column in column_names: | |
| logger.info(f"input_prefix #0: {seq2seq_dataset['train'][0][input_prefix_column]}") | |
| # logger.info(f"input #0: {seq2seq_dataset['train'][0]['input']}") | |
| # logger.info(f"output #0: {seq2seq_dataset['train'][0]['output']}") | |
| if input_prefix_column in column_names: | |
| logger.info(f"input_prefix #1: {seq2seq_dataset['train'][1][input_prefix_column]}") | |
| # logger.info(f"input #1: {seq2seq_dataset['train'][1]['input']}") | |
| # logger.info(f"output #1: {seq2seq_dataset['train'][1]['output']}") | |
| logger.info("") | |
| untokenized_train_dataset = seq2seq_dataset["train"] | |
| if data_args.max_train_samples is not None: | |
| untokenized_train_dataset = untokenized_train_dataset.select(range(data_args.max_train_samples)) | |
| if DEBUG: | |
| # In debug mode, we want to recreate the data | |
| data_args.shared_storage = False | |
| data_args.overwrite_cache = True | |
| with training_args.main_process_first( | |
| local=not data_args.shared_storage, desc="train dataset map pre-processing" | |
| ): | |
| if data_args.oracle_training: | |
| logger.info("Using oracle training") | |
| oracle_processed_dir = f'oracle_input_{data_args.dataset_config_name}' | |
| if os.path.isdir(oracle_processed_dir): | |
| logger.info(f"Using oracle training from {oracle_processed_dir}") | |
| oracle_training_set = datasets.load_from_disk(oracle_processed_dir) | |
| else: | |
| rouge_scorer = datasets.load_metric('rouge') | |
| oracle_training_set = untokenized_train_dataset.map( | |
| extract_oracle_sent_batch, | |
| fn_kwargs={'max_length': data_args.max_source_length, | |
| 'tokenizer': tokenizer, | |
| 'rouge_scorer': rouge_scorer}, | |
| batched=True, | |
| batch_size=1, | |
| num_proc=data_args.preprocessing_num_workers, | |
| load_from_cache_file=not data_args.overwrite_cache, | |
| desc="Extracting oracle sentences from every training example", | |
| ) | |
| oracle_training_set.save_to_disk(oracle_processed_dir) | |
| if data_args.oracle_merge: | |
| untokenized_train_dataset = datasets.concatenate_datasets([untokenized_train_dataset, oracle_training_set]) | |
| untokenized_train_dataset = untokenized_train_dataset.shuffle(seed=training_args.seed) | |
| else: | |
| untokenized_train_dataset = oracle_training_set | |
| train_dataset = untokenized_train_dataset.map( | |
| preprocess_function, | |
| fn_kwargs=preprocess_function_kwargs_fn(), | |
| batched=True, | |
| num_proc=data_args.preprocessing_num_workers, | |
| remove_columns=untokenized_train_dataset.column_names, | |
| load_from_cache_file=not data_args.overwrite_cache, | |
| desc="Running tokenizer on train dataset", | |
| ) | |
| if data_args.chunked_training_size is not None: | |
| train_dataset = train_dataset.map( | |
| chunk_dataset_function, | |
| fn_kwargs={'chunk_size': data_args.chunked_training_size}, | |
| batched=True, | |
| num_proc=data_args.preprocessing_num_workers, | |
| load_from_cache_file=not data_args.overwrite_cache, | |
| desc="Chunking train dataset source", | |
| ) | |
| train_dataset = train_dataset.shuffle(seed=training_args.seed) | |
| if training_args.do_eval: | |
| max_target_length = data_args.val_max_target_length | |
| preprocess_function_kwargs = preprocess_function_kwargs_fn() | |
| preprocess_function_kwargs["max_target_length"] = max_target_length | |
| preprocess_function_kwargs['max_source_length'] = data_args.eval_max_source_length | |
| if "validation" not in seq2seq_dataset: | |
| raise ValueError("--do_eval requires a validation dataset") | |
| logger.info("") | |
| logger.info("Validation examples before tokenization:") | |
| if input_prefix_column in column_names: | |
| logger.info(f"input_prefix #0: {seq2seq_dataset['validation'][0][input_prefix_column]}") | |
| # logger.info(f"input #0: {seq2seq_dataset['validation'][0]['input']}") | |
| # logger.info(f"output #0: {seq2seq_dataset['validation'][0]['output']}") | |
| if input_prefix_column in column_names: | |
| logger.info(f"input_prefix #1: {seq2seq_dataset['validation'][1][input_prefix_column]}") | |
| # logger.info(f"input #1: {seq2seq_dataset['validation'][1]['input']}") | |
| # logger.info(f"output #1: {seq2seq_dataset['validation'][1]['output']}") | |
| logger.info("") | |
| untokenized_eval_dataset = seq2seq_dataset["validation"] | |
| if data_args.max_eval_samples is not None: | |
| untokenized_eval_dataset = untokenized_eval_dataset.select(range(data_args.max_eval_samples)) | |
| if model_args.drop_duplicates_in_eval is True: | |
| untokenized_eval_dataset = drop_duplicates_in_input(untokenized_eval_dataset) | |
| untokenized_eval_dataset_orig = untokenized_eval_dataset | |
| assert training_args.eval_fraction > 0 | |
| n = len(untokenized_eval_dataset) | |
| training_args = replace(training_args, eval_fraction = min(training_args.eval_fraction, n)) | |
| if training_args.eval_fraction != 1: | |
| if training_args.eval_fraction > 1: | |
| assert training_args.eval_fraction == int(training_args.eval_fraction) | |
| logger.info(f'using predetermined absolute samples from eval set ({training_args.eval_fraction} )') | |
| training_args = replace(training_args, eval_fraction = training_args.eval_fraction / n) | |
| indices = np.random.permutation(n)[:int(np.ceil(max(1, training_args.eval_fraction * n)))] | |
| untokenized_eval_dataset = type(untokenized_eval_dataset).from_dict(untokenized_eval_dataset[indices]) | |
| logger.info(f'During training, will only use {training_args.eval_fraction:.3%} samples of the eval set ' | |
| f'which amounts to {len(untokenized_eval_dataset)} out of {n} samples') | |
| eval_dataset = process_eval_set(data_args, preprocess_function_kwargs, training_args, untokenized_eval_dataset) | |
| eval_dataset_orig = eval_dataset | |
| if training_args.eval_fraction < 1: | |
| eval_dataset_orig = process_eval_set(data_args, preprocess_function_kwargs, training_args, | |
| untokenized_eval_dataset_orig) | |
| if training_args.do_predict: | |
| max_target_length = data_args.val_max_target_length | |
| preprocess_function_kwargs = preprocess_function_kwargs_fn() | |
| preprocess_function_kwargs["max_target_length"] = max_target_length | |
| preprocess_function_kwargs['max_source_length'] = data_args.eval_max_source_length | |
| if "test" not in seq2seq_dataset: | |
| raise ValueError("--do_predict requires a test dataset") | |
| untokenized_predict_dataset = seq2seq_dataset["test"] | |
| if data_args.max_predict_samples is not None: | |
| untokenized_predict_dataset = untokenized_predict_dataset.select(range(data_args.max_predict_samples)) | |
| if model_args.drop_duplicates_in_eval is True: | |
| untokenized_predict_dataset = drop_duplicates_in_input(untokenized_predict_dataset) | |
| if output_column in untokenized_predict_dataset.column_names: | |
| untokenized_predict_dataset = untokenized_predict_dataset.remove_columns(output_column) | |
| if data_args.test_start_ind is not None: | |
| sind = data_args.test_start_ind | |
| eind = -1 if data_args.test_end_ind is None else data_args.test_end_ind | |
| logger.info(f'Using only a subset of the test dataset [{sind}, {eind}]') | |
| untokenized_predict_dataset = type(untokenized_predict_dataset).from_dict(untokenized_predict_dataset[sind:eind]) | |
| with training_args.main_process_first( | |
| local=not data_args.shared_storage, desc="prediction dataset map pre-processing" | |
| ): | |
| predict_dataset = untokenized_predict_dataset.map( | |
| preprocess_function, | |
| fn_kwargs=preprocess_function_kwargs, | |
| batched=True, | |
| num_proc=data_args.preprocessing_num_workers, | |
| remove_columns=untokenized_predict_dataset.column_names, | |
| load_from_cache_file=not data_args.overwrite_cache, | |
| desc="Running tokenizer on prediction dataset", | |
| ) | |
| if data_args.preprocess_only: | |
| logger.info(f"With --preprocess_only, exiting after preprocess_on the data") | |
| exit() | |
| # Data collator | |
| label_pad_token_id = -100 if data_args.ignore_pad_token_for_loss else tokenizer.pad_token_id | |
| pad_to = 8 if training_args.fp16 and training_args.fp16_padding else None | |
| data_collator = DataCollatorForSeq2Seq( | |
| tokenizer, | |
| model=model, | |
| label_pad_token_id=label_pad_token_id, | |
| pad_to_multiple_of=pad_to, | |
| ) | |
| # Metric | |
| compute_metrics = load_metric(data_args.metric_names, **locals()) | |
| compute_metrics = load_extra_metrics(data_args.extra_metrics, compute_metrics) | |
| # Initialize our Trainer | |
| trainer = CustomTrainer( | |
| model=model, | |
| args=training_args, | |
| train_dataset=train_dataset if training_args.do_train else None, | |
| eval_dataset=eval_dataset if training_args.do_eval else None, | |
| untokenized_eval_dataset=untokenized_eval_dataset if training_args.do_eval else None, | |
| tokenizer=tokenizer, | |
| data_collator=data_collator, | |
| compute_metrics=compute_metrics if training_args.predict_with_generate else None, | |
| output_dir=training_args.output_dir, | |
| data_args=data_args, | |
| callbacks=[EarlyStoppingCallback(early_stopping_patience=data_args.patience)] if data_args.patience is not None else None, | |
| ) | |
| # setup_cometml_trainer_callback(trainer) | |
| # Training | |
| if training_args.do_train: | |
| checkpoint = None | |
| if training_args.resume_from_checkpoint is not None: | |
| checkpoint = training_args.resume_from_checkpoint | |
| elif last_checkpoint is not None: | |
| checkpoint = last_checkpoint # look for checkpoints in the outdir | |
| train_result = trainer.train(resume_from_checkpoint=checkpoint) | |
| logger.info('Done training') | |
| trainer.save_model() # Saves the tokenizer too for easy upload | |
| metrics = train_result.metrics | |
| max_train_samples = ( | |
| data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) | |
| ) | |
| metrics["train_samples"] = min(max_train_samples, len(train_dataset)) | |
| trainer.log_metrics("train", metrics) | |
| trainer.save_metrics("train", metrics) | |
| trainer.save_state() | |
| # Evaluation | |
| results = {} | |
| if training_args.do_eval: | |
| logger.info("*** Evaluate ***") | |
| if training_args.eval_fraction < 1: | |
| logger.info('setting the eval set back to the full one') | |
| trainer.eval_dataset = eval_dataset_orig | |
| trainer._untokenized_eval_dataset = untokenized_eval_dataset_orig | |
| metrics = trainer.evaluate(metric_key_prefix="eval", use_cache=True, length_penalty=data_args.length_penalty) | |
| logger.info('Done evaluating') | |
| max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) | |
| metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) | |
| trainer.log_metrics("eval", metrics) | |
| trainer.save_metrics("eval", metrics) | |
| if training_args.do_predict: | |
| logger.info("*** Predict ***") | |
| trainer.args.predict_with_generate = True # during prediction, we don't have labels | |
| # load last (and best) model, or the one specified if any | |
| logger.info("*** Loading model weights before the prediction ***") | |
| last_checkpoint = model_args.model_name_or_path if os.path.isdir(model_args.model_name_or_path) else _detect_last_checkpoint(training_args) | |
| if last_checkpoint is not None and os.path.isdir(last_checkpoint): | |
| logger.info(f'Loading weights from {last_checkpoint} for the prediction') | |
| state_dict = torch.load(os.path.join(last_checkpoint, WEIGHTS_NAME), map_location="cpu") | |
| # If the model is on the GPU, it still works! | |
| # trainer._load_state_dict_in_model(state_dict) | |
| # release memory | |
| del state_dict | |
| logger.info("*** Done loading weights ***") | |
| elif training_args.do_train: | |
| raise ValueError('Could not find a model to load for prediction') | |
| else: | |
| logger.info(f'Using {model_args.model_name_or_path} as the model for the prediction') | |
| predict_results = trainer.predict(predict_dataset, metric_key_prefix="predict", use_cache=True) | |
| logger.info('Done predicting') | |
| metrics = predict_results.metrics | |
| max_predict_samples = ( | |
| data_args.max_predict_samples if data_args.max_predict_samples is not None else len(predict_dataset) | |
| ) | |
| metrics["predict_samples"] = min(max_predict_samples, len(predict_dataset)) | |
| trainer.log_metrics("predict", metrics) | |
| trainer.save_metrics("predict", metrics) | |
| if trainer.is_world_process_zero(): | |
| if training_args.predict_with_generate: | |
| id_to_prediction = {} | |
| for i, instance in enumerate(untokenized_predict_dataset): | |
| id_to_prediction[instance["id"]] = predict_results.predictions[i] | |
| predictions = decode(id_to_prediction, tokenizer, data_args) | |
| output_name = "generated_predictions.json" | |
| if data_args.test_start_ind is not None: | |
| output_name = f"generated_predictions_{data_args.test_start_ind}_{data_args.test_end_ind}.json" | |
| output_prediction_file = os.path.join(training_args.output_dir, output_name) | |
| with open(output_prediction_file, "w") as writer: | |
| json.dump(predictions, writer, indent=4) | |
| if training_args.push_to_hub: | |
| kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "summarization"} | |
| if data_args.dataset_name is not None: | |
| kwargs["dataset_tags"] = data_args.dataset_name | |
| if data_args.dataset_config_name is not None: | |
| kwargs["dataset_args"] = data_args.dataset_config_name | |
| kwargs["dataset"] = f"{data_args.dataset_name} {data_args.dataset_config_name}" | |
| else: | |
| kwargs["dataset"] = data_args.dataset_name | |
| trainer.push_to_hub(**kwargs) | |
| return results | |
| def _detect_last_checkpoint(training_args): | |
| last_checkpoint = None | |
| if os.path.isdir(training_args.output_dir) and training_args.do_train: | |
| if not training_args.overwrite_output_dir: | |
| last_checkpoint = get_last_checkpoint(training_args.output_dir) | |
| if last_checkpoint is not None and training_args.resume_from_checkpoint is None: | |
| logger.info( | |
| f"Checkpoint detected, resuming training at {last_checkpoint}. To avoid this behavior, change " | |
| "the `--output_dir` or add `--overwrite_output_dir` to train from scratch." | |
| ) | |
| return last_checkpoint | |
| def process_eval_set(data_args, preprocess_function_kwargs, training_args, untokenized_eval_dataset): | |
| with training_args.main_process_first( | |
| local=not data_args.shared_storage, desc="validation dataset map pre-processing" | |
| ): | |
| eval_dataset = untokenized_eval_dataset.map( | |
| preprocess_function, | |
| fn_kwargs=preprocess_function_kwargs, | |
| batched=True, | |
| num_proc=data_args.preprocessing_num_workers, | |
| remove_columns=untokenized_eval_dataset.column_names, | |
| load_from_cache_file=not data_args.overwrite_cache, | |
| desc="Running tokenizer on validation dataset", | |
| ) | |
| return eval_dataset | |
| def _get_dataset(data_args, model_args, training_args): | |
| # Get the datasets: you can either provide your own CSV/JSON training and evaluation files (see below) | |
| # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ | |
| # (the dataset will be downloaded automatically from the datasets Hub). | |
| # | |
| # For CSV/JSON files this script will use the first column for the full texts and the second column for the | |
| # summaries (unless you specify column names for this with the `input_column` and `output_column` arguments). | |
| # | |
| # In distributed training, the load_dataset function guarantee that only one local process can concurrently | |
| # download the dataset. | |
| data_files = None | |
| if data_args.train_file is not None or data_args.validation_file is not None or data_args.test_file is not None: | |
| data_files = {} | |
| if data_args.train_file is not None: | |
| data_files["train"] = data_args.train_file | |
| if data_args.validation_file is not None: | |
| data_files["validation"] = data_args.validation_file | |
| if data_args.test_file is not None: | |
| data_files["test"] = data_args.test_file | |
| # Downloading and loading a dataset from the hub/local script. | |
| seq2seq_dataset = load_dataset( | |
| data_args.dataset_name, | |
| data_args.dataset_config_name, | |
| verification_mode='no_checks', | |
| cache_dir=model_args.cache_dir, | |
| data_dir=data_args.data_dir, | |
| data_files=data_files, | |
| download_mode=data_args.download_mode, | |
| use_auth_token=training_args.use_auth_token | |
| ) | |
| if training_args.do_train: | |
| training_args.apply_overrides(len(seq2seq_dataset['train'])) | |
| if data_args.evaluate_on_training_data: | |
| seq2seq_dataset["validation"] = seq2seq_dataset["train"] | |
| # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at | |
| # https://huggingface.co/docs/datasets/loading_datasets.html. | |
| return seq2seq_dataset | |
| def set_up_logging(training_args): | |
| logging.basicConfig( | |
| format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", | |
| datefmt="%m/%d/%Y %H:%M:%S", | |
| handlers=[logging.StreamHandler(sys.stdout)], | |
| ) | |
| log_level = training_args.get_process_log_level() | |
| logger.setLevel(log_level) | |
| datasets.utils.logging.set_verbosity(log_level) | |
| transformers.utils.logging.set_verbosity(log_level) | |
| transformers.utils.logging.enable_default_handler() | |
| transformers.utils.logging.enable_explicit_format() | |
| # Log on each process the small summary: | |
| logger.warning( | |
| f"Process rank: {training_args.local_rank}, device: {training_args.device}, n_gpu: {training_args.n_gpu}" | |
| + f"distributed training: {bool(training_args.local_rank != -1)}, 16-bits training: {training_args.fp16}" | |
| ) | |
| logger.info(f"Training/evaluation parameters {training_args}") | |
| def extract_oracle_sent_batch(examples, max_length, tokenizer, rouge_scorer): | |
| items = examples.data.items() | |
| keys = [item[0] for item in items] | |
| values = [item[1] for item in items] | |
| extracted = {k: [] for k in keys} | |
| input_str = 'input' | |
| for ex in zip(*values): | |
| ex = dict(zip(keys, ex)) | |
| ex_input = ex[input_str] | |
| extracted_input = extract_oracle_sentences(ex_input, ex['output'], max_length, tokenizer, rouge_scorer) | |
| extracted[input_str].append(extracted_input) | |
| for k in set(keys) - {input_str}: | |
| extracted[k].append(ex[k]) | |
| return extracted | |
| def extract_oracle_sentences(input_sequence, output, max_length, tokenizer, rouge_scorer, criterion='rouge/geometric_mean'): | |
| sentences = nltk.sent_tokenize(input_sequence) | |
| selected_mask = [False for _ in sentences] | |
| max_rouge = 0.0 | |
| joined_selection = '' | |
| counter = 0 | |
| while len(tokenizer(joined_selection)) < max_length and counter < 100: | |
| cur_max_rouge = max_rouge | |
| max_index = -1 | |
| cur_candidate_indices = [] | |
| cur_candidates = [] | |
| for i in range(len(sentences)): | |
| if selected_mask[i]: | |
| # We already selected this sentence | |
| continue | |
| candidate_mask = list(selected_mask) | |
| candidate_mask[i] = True | |
| candidate_prediction = ' '.join(sent for sent, mask in zip(sentences, candidate_mask) if mask) | |
| cur_candidates.append(candidate_prediction) | |
| cur_candidate_indices.append(i) | |
| rouge = rouge_scorer.compute(predictions=cur_candidates, references=[[output]] * len(cur_candidates), use_aggregator=False) | |
| aggregated_rouge_types = [s1.fmeasure * s2.fmeasure * sL.fmeasure for s1, s2, sL in zip(rouge['rouge1'], rouge['rouge2'], rouge['rougeLsum'])] | |
| max_index = np.argmax(aggregated_rouge_types) | |
| cur_max_rouge = aggregated_rouge_types[max_index] | |
| if max_rouge >= cur_max_rouge: | |
| # No sentence improves the score | |
| break | |
| selected_mask[cur_candidate_indices[max_index]] = True | |
| max_rouge = cur_max_rouge | |
| joined_selection = ' '.join(sent for sent, mask in zip(sentences, selected_mask) if mask) | |
| counter += 1 | |
| return joined_selection | |
| def chunk_dataset_function(examples, chunk_size): | |
| input_ids_str = 'input_ids' | |
| attention_mask_str = 'attention_mask' | |
| items = examples.data.items() | |
| keys = [item[0] for item in items] | |
| values = [item[1] for item in items] | |
| chunked = {k: [] for k in keys} | |
| for ex in zip(*values): | |
| ex = dict(zip(keys, ex)) | |
| for i in range(0, len(ex[input_ids_str]), chunk_size): | |
| chunked_input_ids_st = ex[input_ids_str][i:i + chunk_size] | |
| chunked_attention_mask = ex[attention_mask_str][i:i + chunk_size] | |
| if sum(chunked_attention_mask) < 10: | |
| continue | |
| chunked[input_ids_str].append(chunked_input_ids_st) | |
| chunked[attention_mask_str].append(chunked_attention_mask) | |
| for k in set(keys) - {input_ids_str, attention_mask_str}: | |
| chunked[k].append(ex[k]) | |
| return chunked | |
| def preprocess_function( | |
| examples, | |
| tokenizer, | |
| prefix, | |
| input_column, | |
| input_prefix_column, | |
| output_column, | |
| max_source_length, | |
| max_prefix_length, | |
| max_target_length, | |
| prefix_sep, | |
| padding, | |
| ignore_pad_token_for_loss, | |
| assign_zero_to_too_long_val_examples, | |
| trim_very_long_strings, | |
| pad_prefix | |
| ): | |
| if not isinstance(examples[input_column][0], str): | |
| model_inputs = _preprocess_tokenized_inputs() | |
| else: | |
| model_inputs = _preprocess_raw_inputs(assign_zero_to_too_long_val_examples, examples, input_column, input_prefix_column, | |
| max_source_length, padding, prefix, tokenizer, trim_very_long_strings, max_prefix_length, | |
| prefix_sep, pad_prefix) | |
| _preprocess_targets(examples, ignore_pad_token_for_loss, max_target_length, model_inputs, output_column, padding, tokenizer) | |
| model_inputs["length"] = [len(x) for x in model_inputs["input_ids"]] | |
| return model_inputs | |
| def _preprocess_raw_inputs(assign_zero_to_too_long_val_examples, examples, input_column, input_prefix_column, | |
| max_source_length, padding, prefix, tokenizer, trim_very_long_strings, max_prefix_length, | |
| prefix_sep, pad_prefix): | |
| inputs = examples[input_column] | |
| # the given prefix is what used in models like T5 (e.g. "summarize: ") | |
| # if prefix exists, it is added to the input_prefixes | |
| if input_prefix_column in examples.keys(): | |
| input_prefixes = [inp + prefix_sep for inp in examples[input_prefix_column]] | |
| if prefix != "": | |
| input_prefixes = [prefix + inp for inp in input_prefixes] | |
| elif prefix != "": | |
| inputs = [prefix + inp for inp in inputs] | |
| # tokenize the input prefix if it exists | |
| model_prefix_inputs = None | |
| if input_prefix_column in examples.keys(): | |
| if trim_very_long_strings: | |
| input_prefixes = [inp[: max_prefix_length * 7] for inp in input_prefixes] | |
| if pad_prefix: | |
| model_prefix_inputs = tokenizer(input_prefixes, max_length=max_prefix_length, padding='max_length', truncation=True) | |
| else: | |
| # for led, we do not pad the prefix | |
| model_prefix_inputs = tokenizer(input_prefixes, max_length=max_source_length, padding='do_not_pad', truncation=True) | |
| if trim_very_long_strings: | |
| inputs = [inp[: max_source_length * 7] for inp in inputs] | |
| model_inputs = tokenizer(inputs, max_length=max_source_length, padding=padding, truncation=True) | |
| if max_source_length is not None and assign_zero_to_too_long_val_examples: | |
| model_inputs_untrimmed = tokenizer(inputs) | |
| model_inputs["not_valid_for_eval"] = [ | |
| len(token_ids) > max_source_length for token_ids in model_inputs_untrimmed["input_ids"] | |
| ] | |
| else: | |
| model_inputs["not_valid_for_eval"] = [False] * len(model_inputs["input_ids"]) | |
| # now, combine the concat prefix to the input, trimming it to max_source_length if given | |
| if model_prefix_inputs is not None: | |
| max_source_length = max_source_length or -1 | |
| model_inputs['input_ids'] = [(inp1+inp2)[:max_source_length] for inp1, inp2 | |
| in zip(model_prefix_inputs['input_ids'], model_inputs['input_ids'])] | |
| model_inputs['attention_mask'] = [(inp1+inp2)[:max_source_length] for inp1, inp2 | |
| in zip(model_prefix_inputs['attention_mask'], model_inputs['attention_mask'])] | |
| # add prefix_length | |
| if pad_prefix: | |
| # no need to go over them as they will all be of the same length | |
| model_inputs['prefix_length'] = [max_prefix_length] * len(model_inputs['input_ids']) | |
| else: | |
| model_inputs['prefix_length'] = [len(inp) for inp in model_prefix_inputs['input_ids']] | |
| return model_inputs | |
| def _preprocess_targets(examples, ignore_pad_token_for_loss, max_target_length, model_inputs, output_column, padding, tokenizer): | |
| targets = examples[output_column] if output_column in examples else None | |
| if targets is not None: | |
| if not isinstance(targets[0], str): | |
| if max_target_length is not None: | |
| targets = [target[:max_target_length] for target in targets] | |
| model_inputs["labels"] = targets | |
| else: | |
| # Setup the tokenizer for targets | |
| with tokenizer.as_target_tokenizer(): | |
| labels = tokenizer(targets, max_length=max_target_length, padding=padding, truncation=True) | |
| # If we are padding here, replace all tokenizer.pad_token_id in the labels by -100 when we want to ignore | |
| # padding in the loss. | |
| if padding == "max_length" and ignore_pad_token_for_loss: | |
| labels["input_ids"] = [ | |
| [(l if l != tokenizer.pad_token_id else -100) for l in label] for label in labels["input_ids"] | |
| ] | |
| model_inputs["labels"] = labels["input_ids"] | |
| def load_extra_metrics(metric_names, loaded_metrics=None): | |
| if loaded_metrics is None: | |
| loaded_metrics = MetricCollection([]) | |
| if metric_names is not None: | |
| for metric_name in metric_names: | |
| if len(metric_name) > 0: | |
| loaded_metrics._metrics.append(HFMetricWrapper(metric_name)) | |
| return loaded_metrics | |
| def _mp_fn(index): | |
| # For xla_spawn (TPUs) | |
| main() | |
| if __name__ == "__main__": | |
| main() | |