



"""simple docstring"""





import logging
from pathlib import Path

import numpy as np
import pytorch_lightning as pl
import torch
from pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint
from pytorch_lightning.utilities import rank_zero_only
from utils_rag import save_json




def 	UpperCAmelCase     (		A	:						Dict       ):
		_UpperCAmelCase							 =		filter(lambda A       : p.requires_grad     ,				model.parameters()       )
		_UpperCAmelCase							 =		sum([np.prod(p.size()       ) for p in model_parameters]       )
		return params


lowercase  							=					logging.getLogger(__name__)




def 	UpperCAmelCase     (		A	:						str     ,				A	:						int       ):


		if metric == "rouge2":
				_UpperCAmelCase							 =		'{val_avg_rouge2:.4f}-{step_count}'
		elif metric == "bleu":
				_UpperCAmelCase							 =		'{val_avg_bleu:.4f}-{step_count}'
		elif metric == "em":
				_UpperCAmelCase							 =		'{val_avg_em:.4f}-{step_count}'
		elif metric == "loss":
				_UpperCAmelCase							 =		'{val_avg_loss:.4f}-{step_count}'
		else:
				raise NotImplementedError(
				    f'seq2seq callbacks only support rouge2 and bleu, got {metric}, You can make your own by adding to this'
				    ' function.'       )

		_UpperCAmelCase							 =		ModelCheckpoint(
		    dirpath=A     ,				filename=A     ,				monitor=f'val_{metric}'     ,				mode='max'     ,				save_top_k=1     ,				every_n_epochs=1     ,				)

		return checkpoint_callback




def 	UpperCAmelCase     (		A	:						Union[str, Any]     ,				A	:						Optional[int]       ):
		return EarlyStopping(
		    monitor=f'val_{metric}'     ,				mode='min' if 'loss' in metric else 'max'     ,				patience=A     ,				verbose=A     ,				)






class 			lowercase__			(      pl.Callback    ):
							'''simple docstring'''







							def        lowerCamelCase_   (  self	,       snake_case	,       snake_case						)			->							Optional[int]:
									_UpperCAmelCase							 =		{f'lr_group_{i}': param['lr'] for i, param in enumerate(pl_module.trainer.optimizers[0].param_groups						)}
									pl_module.logger.log_metrics(snake_case						)






							@rank_zero_only
							def        lowerCamelCase_   (  self	,       snake_case	,       snake_case	,       snake_case	,       snake_case=True						)			->							None:
									logger.info(f'***** {type_path} results at step {trainer.global_step:05d} *****'						)
									_UpperCAmelCase							 =		trainer.callback_metrics
									trainer.logger.log_metrics({k: v for k, v in metrics.items() if k not in ['log', 'progress_bar', 'preds']}						)
									# Log results
									_UpperCAmelCase							 =		Path(pl_module.hparams.output_dir						)
									if type_path == "test":
											_UpperCAmelCase							 =		od / 'test_results.txt'
											_UpperCAmelCase							 =		od / 'test_generations.txt'
									else:
											# this never gets hit. I prefer not to save intermediate generations, and results are in metrics.json
											# If people want this it will be easy enough to add back.
											_UpperCAmelCase							 =		od / f'{type_path}_results/{trainer.global_step:05d}.txt'
											_UpperCAmelCase							 =		od / f'{type_path}_generations/{trainer.global_step:05d}.txt'
											results_file.parent.mkdir(exist_ok=snake_case						)
											generations_file.parent.mkdir(exist_ok=snake_case						)
									with open(snake_case	,       'a+'						) as writer:
											for key in sorted(snake_case						):
													if key in ["log", "progress_bar", "preds"]:
															continue
													_UpperCAmelCase							 =		metrics[key]
													if isinstance(snake_case	,       torch.Tensor						):
															_UpperCAmelCase							 =		val.item()
													_UpperCAmelCase							 =		f'{key}: {val:.6f}\n'
													writer.write(snake_case						)

									if not save_generations:
											return

									if "preds" in metrics:
											_UpperCAmelCase							 =		'\n'.join(metrics['preds']						)
											generations_file.open('w+'						).write(snake_case						)






							@rank_zero_only
							def        lowerCamelCase_   (  self	,       snake_case	,       snake_case						)			->							List[Any]:
									try:
											_UpperCAmelCase							 =		pl_module.model.model.num_parameters()
									except AttributeError:
											_UpperCAmelCase							 =		pl_module.model.num_parameters()

									_UpperCAmelCase							 =		count_trainable_parameters(snake_case						)
									# mp stands for million parameters
									trainer.logger.log_metrics({'n_params': npars, 'mp': npars / 1E6, 'grad_mp': n_trainable_pars / 1E6}						)






							@rank_zero_only
							def        lowerCamelCase_   (  self	,       snake_case	,       snake_case						)			->							int:
									save_json(pl_module.metrics	,       pl_module.metrics_save_path						)
									return self._write_logs(snake_case	,       snake_case	,       'test'						)






							@rank_zero_only
							def        lowerCamelCase_   (  self	,       snake_case	,       snake_case						)			->							List[Any]:
									save_json(pl_module.metrics	,       pl_module.metrics_save_path						)
									# Uncommenting this will save val generations
									# return self._write_logs(trainer, pl_module, "valid")







"""simple docstring"""





from typing import List, Optional, TypeVar

from .arrow_dataset import Dataset, _concatenate_map_style_datasets, _interleave_map_style_datasets
from .dataset_dict import DatasetDict, IterableDatasetDict
from .info import DatasetInfo
from .iterable_dataset import IterableDataset, _concatenate_iterable_datasets, _interleave_iterable_datasets
from .splits import NamedSplit
from .utils import logging
from .utils.py_utils import Literal


lowercase  							=					logging.get_logger(__name__)


lowercase  							=					TypeVar('''DatasetType''', Dataset, IterableDataset)




def 	UpperCAmelCase     (		A	:						List[DatasetType]     ,				A	:						Optional[List[float]] = None     ,				A	:						Optional[int] = None     ,				A	:						Optional[DatasetInfo] = None     ,				A	:						Optional[NamedSplit] = None     ,				A	:						Literal["first_exhausted", "all_exhausted"] = "first_exhausted"     ,				):

		'''simple docstring'''


		from .arrow_dataset import Dataset
		from .iterable_dataset import IterableDataset

		if not datasets:
				raise ValueError('Unable to interleave an empty list of datasets.'       )
		for i, dataset in enumerate(A       ):
				if not isinstance(A     ,				(Dataset, IterableDataset)       ):
						if isinstance(A     ,				(DatasetDict, IterableDatasetDict)       ):
								if not dataset:
										raise ValueError(
										    f'Expected a list of Dataset objects or a list of IterableDataset objects, but element at position {i} '
										    'is an empty dataset dictionary.'       )
								raise ValueError(
								    f'Dataset at position {i} has at least one split: {list(A       )}\n'
								    f'Please pick one to interleave with the other datasets, for example: dataset[\'{next(iter(A       )       )}\']'       )
						raise ValueError(
						    f'Expected a list of Dataset objects or a list of IterableDataset objects, but element at position {i} is a {type(A       ).__name__}.'       )
				if i == 0:
						_UpperCAmelCase ,					_UpperCAmelCase							 =		(
						    (Dataset, IterableDataset) if isinstance(A     ,				A       ) else (IterableDataset, Dataset)
						)
				elif not isinstance(A     ,				A       ):
						raise ValueError(
						    f'Unable to interleave a {dataset_type.__name__} (at position 0) with a {other_type.__name__} (at position {i}). Expected a list of Dataset objects or a list of IterableDataset objects.'       )
		if stopping_strategy not in ["first_exhausted", "all_exhausted"]:
				raise ValueError(f'{stopping_strategy} is not supported. Please enter a valid stopping_strategy.'       )
		if dataset_type is Dataset:
				return _interleave_map_style_datasets(
				    A     ,				A     ,				A     ,				info=A     ,				split=A     ,				stopping_strategy=A       )
		else:
				return _interleave_iterable_datasets(
				    A     ,				A     ,				A     ,				info=A     ,				split=A     ,				stopping_strategy=A       )






def 	UpperCAmelCase     (		A	:						List[DatasetType]     ,				A	:						Optional[DatasetInfo] = None     ,				A	:						Optional[NamedSplit] = None     ,				A	:						int = 0     ,				):

		'''simple docstring'''


		if not dsets:
				raise ValueError('Unable to concatenate an empty list of datasets.'       )
		for i, dataset in enumerate(A       ):
				if not isinstance(A     ,				(Dataset, IterableDataset)       ):
						if isinstance(A     ,				(DatasetDict, IterableDatasetDict)       ):
								if not dataset:
										raise ValueError(
										    f'Expected a list of Dataset objects or a list of IterableDataset objects, but element at position {i} '
										    'is an empty dataset dictionary.'       )
								raise ValueError(
								    f'Dataset at position {i} has at least one split: {list(A       )}\n'
								    f'Please pick one to interleave with the other datasets, for example: dataset[\'{next(iter(A       )       )}\']'       )
						raise ValueError(
						    f'Expected a list of Dataset objects or a list of IterableDataset objects, but element at position {i} is a {type(A       ).__name__}.'       )
				if i == 0:
						_UpperCAmelCase ,					_UpperCAmelCase							 =		(
						    (Dataset, IterableDataset) if isinstance(A     ,				A       ) else (IterableDataset, Dataset)
						)
				elif not isinstance(A     ,				A       ):
						raise ValueError(
						    f'Unable to interleave a {dataset_type.__name__} (at position 0) with a {other_type.__name__} (at position {i}). Expected a list of Dataset objects or a list of IterableDataset objects.'       )
		if dataset_type is Dataset:
				return _concatenate_map_style_datasets(A     ,				info=A     ,				split=A     ,				axis=A       )
		else:
				return _concatenate_iterable_datasets(A     ,				info=A     ,				split=A     ,				axis=A       )


