"""simple docstring"""






import itertools
from dataclasses import dataclass
from typing import Any, Callable, Dict, List, Optional, Union

import pandas as pd
import pyarrow as pa

import datasets
import datasets.config
from datasets.features.features import require_storage_cast
from datasets.table import table_cast
from datasets.utils.py_utils import Literal


lowerCAmelCase__  :  Tuple						     =	datasets.utils.logging.get_logger(__name__)

lowerCAmelCase__  :  Any						     =	['names', 'prefix']
lowerCAmelCase__  :  List[Any]						     =	['warn_bad_lines', 'error_bad_lines', 'mangle_dupe_cols']
lowerCAmelCase__  :  List[str]						     =	['encoding_errors', 'on_bad_lines']
lowerCAmelCase__  :  Optional[Any]						     =	['date_format']
@dataclass
class 				snake_case       ( datasets.BuilderConfig				):




					"""simple docstring"""

					snake_case__				    = ","
					snake_case__				    = None
					snake_case__				    = "infer"
					snake_case__				    = None
					snake_case__				    = None
					snake_case__				    = None
					snake_case__				    = None
					snake_case__				    = None
					snake_case__				    = True
					snake_case__				    = None
					snake_case__				    = None
					snake_case__				    = None
					snake_case__				    = None
					snake_case__				    = False
					snake_case__				    = None
					snake_case__				    = None
					snake_case__				    = None
					snake_case__				    = True
					snake_case__				    = True
					snake_case__				    = False
					snake_case__				    = True
					snake_case__				    = None
					snake_case__				    = "."
					snake_case__				    = None
					snake_case__				    = '"'
					snake_case__				    = 0
					snake_case__				    = None
					snake_case__				    = None
					snake_case__				    = None
					snake_case__				    = None
					snake_case__				    = True
					snake_case__				    = True
					snake_case__				    = 0
					snake_case__				    = True
					snake_case__				    = False
					snake_case__				    = None
					snake_case__				    = 1_00_00
					snake_case__				    = None
					snake_case__				    = "strict"
					snake_case__				    = "error"
					snake_case__				    = None







					def 		__lowerCAmelCase						(				self   :	int			):
									if self.delimiter is not None:
													UpperCAmelCase__             =							self.delimiter
									if self.column_names is not None:
													UpperCAmelCase__             =							self.column_names







					@property
					def 		__lowerCAmelCase						(				self   :	Dict			):
									UpperCAmelCase__             =							{
									    'sep': self.sep,
									    'header': self.header,
									    'names': self.names,
									    'index_col': self.index_col,
									    'usecols': self.usecols,
									    'prefix': self.prefix,
									    'mangle_dupe_cols': self.mangle_dupe_cols,
									    'engine': self.engine,
									    'converters': self.converters,
									    'true_values': self.true_values,
									    'false_values': self.false_values,
									    'skipinitialspace': self.skipinitialspace,
									    'skiprows': self.skiprows,
									    'nrows': self.nrows,
									    'na_values': self.na_values,
									    'keep_default_na': self.keep_default_na,
									    'na_filter': self.na_filter,
									    'verbose': self.verbose,
									    'skip_blank_lines': self.skip_blank_lines,
									    'thousands': self.thousands,
									    'decimal': self.decimal,
									    'lineterminator': self.lineterminator,
									    'quotechar': self.quotechar,
									    'quoting': self.quoting,
									    'escapechar': self.escapechar,
									    'comment': self.comment,
									    'encoding': self.encoding,
									    'dialect': self.dialect,
									    'error_bad_lines': self.error_bad_lines,
									    'warn_bad_lines': self.warn_bad_lines,
									    'skipfooter': self.skipfooter,
									    'doublequote': self.doublequote,
									    'memory_map': self.memory_map,
									    'float_precision': self.float_precision,
									    'chunksize': self.chunksize,
									    'encoding_errors': self.encoding_errors,
									    'on_bad_lines': self.on_bad_lines,
									    'date_format': self.date_format,
									}

									# some kwargs must not be passed if they don't have a default value
									# some others are deprecated and we can also not pass them if they are the default value
									for pd_read_csv_parameter in _PANDAS_READ_CSV_NO_DEFAULT_PARAMETERS + _PANDAS_READ_CSV_DEPRECATED_PARAMETERS:
													if pd_read_csv_kwargs[pd_read_csv_parameter] == getattr(CsvConfig()    ,lowerCamelCase__			):
																	del pd_read_csv_kwargs[pd_read_csv_parameter]

        # Remove 2.0 new arguments
									if not (datasets.config.PANDAS_VERSION.major >= 2):
													for pd_read_csv_parameter in _PANDAS_READ_CSV_NEW_2_0_0_PARAMETERS:
																	del pd_read_csv_kwargs[pd_read_csv_parameter]

        # Remove 1.3 new arguments
									if not (datasets.config.PANDAS_VERSION.major >= 1 and datasets.config.PANDAS_VERSION.minor >= 3):
													for pd_read_csv_parameter in _PANDAS_READ_CSV_NEW_1_3_0_PARAMETERS:
																	del pd_read_csv_kwargs[pd_read_csv_parameter]

									return pd_read_csv_kwargs






class 				snake_case       ( datasets.ArrowBasedBuilder				):




					"""simple docstring"""

					snake_case__				    = CsvConfig







					def 		__lowerCAmelCase						(				self   :	List[str]			):
									return datasets.DatasetInfo(features=self.config.features			)







					def 		__lowerCAmelCase						(				self   :	Any    ,lowerCamelCase__   :	Optional[Any]			):
									if not self.config.data_files:
													raise ValueError(f'''At least one data file must be specified, but got data_files={self.config.data_files}'''			)
									UpperCAmelCase__             =							dl_manager.download_and_extract(self.config.data_files			)
									if isinstance(lowerCamelCase__    ,(str, list, tuple)			):
													UpperCAmelCase__             =							data_files
													if isinstance(lowerCamelCase__    ,lowerCamelCase__			):
																	UpperCAmelCase__             =							[files]
													UpperCAmelCase__             =							[dl_manager.iter_files(lowerCamelCase__			) for file in files]
													return [datasets.SplitGenerator(name=datasets.Split.TRAIN    ,gen_kwargs={'files': files}			)]
									UpperCAmelCase__             =							[]
									for split_name, files in data_files.items():
													if isinstance(lowerCamelCase__    ,lowerCamelCase__			):
																	UpperCAmelCase__             =							[files]
													UpperCAmelCase__             =							[dl_manager.iter_files(lowerCamelCase__			) for file in files]
													splits.append(datasets.SplitGenerator(name=lowerCamelCase__    ,gen_kwargs={'files': files}			)			)
									return splits







					def 		__lowerCAmelCase						(				self   :	Union[str, Any]    ,lowerCamelCase__   :	pa.Table			):
									if self.config.features is not None:
													UpperCAmelCase__             =							self.config.features.arrow_schema
													if all(not require_storage_cast(lowerCamelCase__			) for feature in self.config.features.values()			):
																	# cheaper cast
																	UpperCAmelCase__             =							pa.Table.from_arrays([pa_table[field.name] for field in schema]    ,schema=lowerCamelCase__			)
													else:
																	# more expensive cast; allows str <-> int/float or str to Audio for example
																	UpperCAmelCase__             =							table_cast(lowerCamelCase__    ,lowerCamelCase__			)
									return pa_table







					def 		__lowerCAmelCase						(				self   :	Dict    ,lowerCamelCase__   :	Any			):
									UpperCAmelCase__             =							self.config.features.arrow_schema if self.config.features else None
									# dtype allows reading an int column as str
									UpperCAmelCase__             =							(
									    {
									        name: dtype.to_pandas_dtype() if not require_storage_cast(lowerCamelCase__			) else object
									        for name, dtype, feature in zip(schema.names    ,schema.types    ,self.config.features.values()			)
									    }
									    if schema is not None
									    else None
									)
									for file_idx, file in enumerate(itertools.chain.from_iterable(lowerCamelCase__			)			):
													UpperCAmelCase__             =							pd.read_csv(lowerCamelCase__    ,iterator=lowerCamelCase__    ,dtype=lowerCamelCase__    ,**self.config.pd_read_csv_kwargs			)
													try:
																	for batch_idx, df in enumerate(lowerCamelCase__			):
																					UpperCAmelCase__             =							pa.Table.from_pandas(lowerCamelCase__			)
																					# Uncomment for debugging (will print the Arrow table size and elements)
																					# logger.warning(f"pa_table: {pa_table} num rows: {pa_table.num_rows}")
																					# logger.warning('\n'.join(str(pa_table.slice(i, 1).to_pydict()) for i in range(pa_table.num_rows)))
																					yield (file_idx, batch_idx), self._cast_table(lowerCamelCase__			)
													except ValueError as e:
																	logger.error(f'''Failed to read file \'{file}\' with error {type(lowerCamelCase__			)}: {e}'''			)
																	raise







"""simple docstring"""







import argparse
import glob
import logging
import os
from argparse import Namespace
from importlib import import_module

import numpy as np
import torch
from lightning_base import BaseTransformer, add_generic_args, generic_train
from seqeval.metrics import accuracy_score, fa_score, precision_score, recall_score
from torch.nn import CrossEntropyLoss
from torch.utils.data import DataLoader, TensorDataset
from utils_ner import TokenClassificationTask


lowerCAmelCase__      				=   logging.getLogger(__name__)


class       SCREAMING_SNAKE_CASE__				(		lowercase				):
       """simple docstring"""


       a  :				Tuple   ="token-classification"

       def __init__(						self		,     snake_case__						):






         """simple docstring"""





         if type(snake_case__						) == dict:
           lowerCAmelCase     :     List[str]								=							Namespace(**snake_case__						)
         lowerCAmelCase     :     Optional[Any]								=							import_module("tasks"						)
         try:
           lowerCAmelCase     :     Dict								=							getattr(snake_case__		,     hparams.task_type						)
           lowerCAmelCase     :     TokenClassificationTask								=							token_classification_task_clazz()
         except AttributeError:
           raise ValueError(
               f"""Task {hparams.task_type} needs to be defined as a TokenClassificationTask subclass in {module}. """
               f"""Available tasks classes are: {TokenClassificationTask.__subclasses__()}"""						)
         lowerCAmelCase     :     Dict								=							self.token_classification_task.get_labels(hparams.labels						)
         lowerCAmelCase     :     str								=							CrossEntropyLoss().ignore_index
         super().__init__(snake_case__		,     len(self.labels						)		,     self.mode						)

       def        lowercase__							(						self		,     **snake_case__						):






         """simple docstring"""





         return self.model(**snake_case__						)

       def        lowercase__							(						self		,     snake_case__		,     snake_case__						):






         """simple docstring"""





         lowerCAmelCase     :     List[str]								=							{"input_ids": batch[0], "attention_mask": batch[1], "labels": batch[3]}
         if self.config.model_type != "distilbert":
           lowerCAmelCase     :     Optional[int]								=							(
               batch[2] if self.config.model_type in ["bert", "xlnet"] else None
           )  # XLM and RoBERTa don"t use token_type_ids

         lowerCAmelCase     :     str								=							self(**snake_case__						)
         lowerCAmelCase     :     Tuple								=							outputs[0]
         # tensorboard_logs = {"loss": loss, "rate": self.lr_scheduler.get_last_lr()[-1]}
         return {"loss": loss}

       def        lowercase__							(						self						):






         """simple docstring"""





         lowerCAmelCase     :     List[str]								=							self.hparams
         for mode in ["train", "dev", "test"]:
           lowerCAmelCase     :     Optional[int]								=							self._feature_file(snake_case__						)
           if os.path.exists(snake_case__						) and not args.overwrite_cache:
             logger.info("Loading features from cached file %s"		,     snake_case__						)
             lowerCAmelCase     :     Dict								=							torch.load(snake_case__						)
           else:
             logger.info("Creating features from dataset file at %s"		,     args.data_dir						)
             lowerCAmelCase     :     Optional[int]								=							self.token_classification_task.read_examples_from_file(args.data_dir		,     snake_case__						)
             lowerCAmelCase     :     Optional[int]								=							self.token_classification_task.convert_examples_to_features(
                 snake_case__		,     self.labels		,     args.max_seq_length		,     self.tokenizer		,     cls_token_at_end=bool(self.config.model_type in ["xlnet"]						)		,     cls_token=self.tokenizer.cls_token		,     cls_token_segment_id=2 if self.config.model_type in ["xlnet"] else 0		,     sep_token=self.tokenizer.sep_token		,     sep_token_extra=snake_case__		,     pad_on_left=bool(self.config.model_type in ["xlnet"]						)		,     pad_token=self.tokenizer.pad_token_id		,     pad_token_segment_id=self.tokenizer.pad_token_type_id		,     pad_token_label_id=self.pad_token_label_id		,     )
             logger.info("Saving features into cached file %s"		,     snake_case__						)
             torch.save(snake_case__		,     snake_case__						)

       def        lowercase__							(						self		,     snake_case__		,     snake_case__		,     snake_case__ = False						):






         """simple docstring"""





         lowerCAmelCase     :     Dict								=							self._feature_file(snake_case__						)
         logger.info("Loading features from cached file %s"		,     snake_case__						)
         lowerCAmelCase     :     Optional[Any]								=							torch.load(snake_case__						)
         lowerCAmelCase     :     Optional[int]								=							torch.tensor([f.input_ids for f in features]		,     dtype=torch.long						)
         lowerCAmelCase     :     int								=							torch.tensor([f.attention_mask for f in features]		,     dtype=torch.long						)
         if features[0].token_type_ids is not None:
           lowerCAmelCase     :     Tuple								=							torch.tensor([f.token_type_ids for f in features]		,     dtype=torch.long						)
         else:
           lowerCAmelCase     :     Optional[Any]								=							torch.tensor([0 for f in features]		,     dtype=torch.long						)
           # HACK(we will not use this anymore soon)
         lowerCAmelCase     :     Optional[int]								=							torch.tensor([f.label_ids for f in features]		,     dtype=torch.long						)
         return DataLoader(
             TensorDataset(snake_case__		,     snake_case__		,     snake_case__		,     snake_case__						)		,     batch_size=snake_case__						)

       def        lowercase__							(						self		,     snake_case__		,     snake_case__						):






         """simple docstring"""





         """Compute validation""" ""
         lowerCAmelCase     :     str								=							{"input_ids": batch[0], "attention_mask": batch[1], "labels": batch[3]}
         if self.config.model_type != "distilbert":
           lowerCAmelCase     :     List[Any]								=							(
               batch[2] if self.config.model_type in ["bert", "xlnet"] else None
           )  # XLM and RoBERTa don"t use token_type_ids
         lowerCAmelCase     :     Any								=							self(**snake_case__						)
         lowerCAmelCase						,  lowerCAmelCase     :     List[str]								=							outputs[:2]
         lowerCAmelCase     :     Dict								=							logits.detach().cpu().numpy()
         lowerCAmelCase     :     Optional[Any]								=							inputs["labels"].detach().cpu().numpy()
         return {"val_loss": tmp_eval_loss.detach().cpu(), "pred": preds, "target": out_label_ids}

       def        lowercase__							(						self		,     snake_case__						):






         """simple docstring"""





         lowerCAmelCase     :     List[str]								=							torch.stack([x["val_loss"] for x in outputs]						).mean()
         lowerCAmelCase     :     Optional[Any]								=							np.concatenate([x["pred"] for x in outputs]		,     axis=0						)
         lowerCAmelCase     :     List[Any]								=							np.argmax(snake_case__		,     axis=2						)
         lowerCAmelCase     :     Optional[int]								=							np.concatenate([x["target"] for x in outputs]		,     axis=0						)

         lowerCAmelCase     :     str								=							dict(enumerate(self.labels						)						)
         lowerCAmelCase     :     Optional[int]								=							[[] for _ in range(out_label_ids.shape[0]						)]
         lowerCAmelCase     :     Dict								=							[[] for _ in range(out_label_ids.shape[0]						)]

         for i in range(out_label_ids.shape[0]						):
           for j in range(out_label_ids.shape[1]						):
             if out_label_ids[i, j] != self.pad_token_label_id:
               out_label_list[i].append(label_map[out_label_ids[i][j]]						)
               preds_list[i].append(label_map[preds[i][j]]						)

         lowerCAmelCase     :     Dict								=							{
             "val_loss": val_loss_mean,
             "accuracy_score": accuracy_score(snake_case__		,     snake_case__						),
             "precision": precision_score(snake_case__		,     snake_case__						),
             "recall": recall_score(snake_case__		,     snake_case__						),
             "f1": fa_score(snake_case__		,     snake_case__						),
         }

         lowerCAmelCase     :     int								=							dict(results.items()						)
         lowerCAmelCase     :     Tuple								=							results
         return ret, preds_list, out_label_list

       def        lowercase__							(						self		,     snake_case__						):






         """simple docstring"""





         lowerCAmelCase						,  lowerCAmelCase						,  lowerCAmelCase     :     Dict								=							self._eval_end(snake_case__						)
         lowerCAmelCase     :     int								=							ret["log"]
         return {"val_loss": logs["val_loss"], "log": logs, "progress_bar": logs}

       def        lowercase__							(						self		,     snake_case__						):






         """simple docstring"""





         lowerCAmelCase						,  lowerCAmelCase						,  lowerCAmelCase     :     int								=							self._eval_end(snake_case__						)

         # Converting to the dict required by pl
         # https://github.com/PyTorchLightning/pytorch-lightning/blob/master/\
         # pytorch_lightning/trainer/logging.py#L139
         lowerCAmelCase     :     str								=							ret["log"]
         # `val_loss` is the key returned by `self._eval_end()` but actually refers to `test_loss`
         return {"avg_test_loss": logs["val_loss"], "log": logs, "progress_bar": logs}







       @staticmethod
       def        lowercase__							(						snake_case__		,     snake_case__						):






         """simple docstring"""





         BaseTransformer.add_model_specific_args(snake_case__		,     snake_case__						)
         parser.add_argument(
             "--task_type"		,     default="NER"		,     type=snake_case__		,     help="Task type to fine tune in training (e.g. NER, POS, etc)"						)
         parser.add_argument(
             "--max_seq_length"		,     default=128		,     type=snake_case__		,     help=(
                 "The maximum total input sequence length after tokenization. Sequences longer "
                 "than this will be truncated, sequences shorter will be padded."
             )		,     )

         parser.add_argument(
             "--labels"		,     default=""		,     type=snake_case__		,     help="Path to a file containing all labels. If not specified, CoNLL-2003 labels are used."		,     )
         parser.add_argument(
             "--gpus"		,     default=0		,     type=snake_case__		,     help="The number of GPUs allocated for this, it is by default 0 meaning none"		,     )

         parser.add_argument(
             "--overwrite_cache"		,     action="store_true"		,     help="Overwrite the cached training and evaluation sets"						)

         return parser


if __name__ == "__main__":
     lowerCAmelCase__      				=   argparse.ArgumentParser()
     add_generic_args(parser, os.getcwd())
     lowerCAmelCase__      				=   NERTransformer.add_model_specific_args(parser, os.getcwd())
     lowerCAmelCase__      				=   parser.parse_args()
     lowerCAmelCase__      				=   NERTransformer(args)
     lowerCAmelCase__      				=   generic_train(model, args)

     if args.do_predict:
          # See https://github.com/huggingface/transformers/issues/3159
          # pl use this default format to create a checkpoint:
          # https://github.com/PyTorchLightning/pytorch-lightning/blob/master\
          # /pytorch_lightning/callbacks/model_checkpoint.py#L322
          lowerCAmelCase__      				=   sorted(glob.glob(os.path.join(args.output_dir, '''checkpoint-epoch=*.ckpt'''), recursive=True))
          lowerCAmelCase__      				=   model.load_from_checkpoint(checkpoints[-1])
          trainer.test(model)





