
import importlib.util
import weakref
from functools import partialmethod

from .dependency_versions_check import dep_version_check
from .utils import is_accelerate_available, is_torch_available, logging


if is_torch_available():
						import torch

SCREAMING_SNAKE_CASE   :		Optional[Any]					 =       logging.get_logger(__name__)



def        lowerCamelCase_  (   ):
				return importlib.util.find_spec('''deepspeed'''     ) is not None


if is_accelerate_available() and is_deepspeed_available():
						from accelerate.utils.deepspeed import HfDeepSpeedConfig as DeepSpeedConfig
else:
						# Inherits from a dummy `object` if accelerate is not available, so that python succeeds to import this file.
						# Deepspeed glue code will never inherit this dummy object as it checks if accelerate is available.
						from builtins import object as DeepSpeedConfig






class 					__lowercase		(					A       ):


					def __init__(	self       ,       a__						)		->							Dict:





									'''simple docstring'''
									# set global weakref object
									set_hf_deepspeed_config(self						)
									dep_version_check('''accelerate'''						)
									dep_version_check('''deepspeed'''						)
									super().__init__(a__						)






class 					__lowercase		(					A       ):


					def __init__(	self       ,       a__						)		->							List[Any]:





									'''simple docstring'''
									super().__init__(a__						)
									A_       	=  None
									A_       	=  []


					def        lowerCAmelCase_    (	self						)		->							Optional[Any]:





									'''simple docstring'''
									if self._dtype is None:
													raise ValueError('''trainer_config_process() wasn\'t called yet to tell dtype'''						)
									return self._dtype


					def        lowerCAmelCase_    (	self       ,       a__						)		->							Optional[int]:





									'''simple docstring'''
									A_       	=  self.get_value(a__						)
									if val is None:
													return False
									else:
													return val == "auto"


					def        lowerCAmelCase_    (	self       ,       a__       ,       a__       ,       a__=None       ,       a__=True						)		->							List[str]:





									'''simple docstring'''
									A_	,					A_       	=  self.find_config_node(a__						)
									if config is None:
													return

									if config.get(a__						) == "auto":
													A_       	=  hf_val
													return

									if not must_match:
													return

									A_       	=  config.get(a__						)
									if ds_val is not None and ds_val != hf_val:
													self.mismatches.append(F"- ds {ds_key_long}={ds_val} vs hf {hf_key}={hf_val}"						)

					__magic_name__						:							str     	=	partialmethod(A							,       must_match=A       )


					def        lowerCAmelCase_    (	self       ,       a__						)		->							str:





									'''simple docstring'''
									A_       	=  args.world_size * args.per_device_train_batch_size * args.gradient_accumulation_steps
									self.fill_match(
									    '''train_micro_batch_size_per_gpu'''       ,       args.per_device_train_batch_size       ,       '''per_device_train_batch_size'''						)
									self.fill_match('''gradient_accumulation_steps'''       ,       args.gradient_accumulation_steps       ,       '''gradient_accumulation_steps'''						)
									self.fill_match('''train_batch_size'''       ,       a__       ,       '''train_batch_size (calculated)'''						)
									self.fill_match('''gradient_clipping'''       ,       args.max_grad_norm       ,       '''max_grad_norm'''						)

									self.fill_match('''optimizer.params.lr'''       ,       args.learning_rate       ,       '''learning_rate'''						)
									self.fill_match('''optimizer.params.betas'''       ,       [args.adam_betaa, args.adam_betaa]       ,       '''adam_beta1+adam_beta2'''						)
									self.fill_match('''optimizer.params.eps'''       ,       args.adam_epsilon       ,       '''adam_epsilon'''						)
									self.fill_match('''optimizer.params.weight_decay'''       ,       args.weight_decay       ,       '''weight_decay'''						)

									self.fill_only('''scheduler.params.warmup_min_lr'''       ,       0						)  # not a trainer arg
									self.fill_match('''scheduler.params.warmup_max_lr'''       ,       args.learning_rate       ,       '''learning_rate'''						)
									# total_num_steps - will get set in trainer_config_finalize

									# fp16
									if args.fpaa or args.fpaa_full_eval:
													A_       	=  '''apex''' if args.fpaa_backend == '''apex''' else '''amp'''
									else:
													A_       	=  None

									if args.save_on_each_node:
													# deepspeed uses shared storage by default. Let's override this setting if save_on_each_node == True
													A_       	=  self.config.get('''checkpoint'''       ,       {}						)
													A_       	=  args.save_on_each_node

									# amp: similar to the pytorch native amp - it has a bunch of optional params but we won't set
									# any here unless the user did the work
									self.fill_match(
									    '''fp16.enabled'''       ,       ((args.fpaa or args.fpaa_full_eval) and fpaa_backend == '''amp''')       ,       '''fp16|fp16_full_eval+fp16_backend(amp)'''       ,       )

									# apex: delegates amp work to apex (which needs to be available), but it cannot be used with any
									# ZeRO features
									self.fill_match('''amp.enabled'''       ,       fpaa_backend == '''apex'''       ,       '''fp16+fp16_backend(apex)'''						)
									self.fill_match('''amp.opt_level'''       ,       args.fpaa_opt_level       ,       '''fp16_opt_level'''						)

									self.fill_match('''bf16.enabled'''       ,       (args.bfaa or args.bfaa_full_eval)       ,       '''bf16|bf16_full_eval'''						)

									# deepspeed's default mode is fp16 unless there is a config that says differently
									if self.is_true('''bf16.enabled'''						):
													A_       	=  torch.bfloataa
									elif self.is_false('''fp16.enabled'''						):
													A_       	=  torch.floataa
									else:
													A_       	=  torch.floataa


					def        lowerCAmelCase_    (	self       ,       a__       ,       a__       ,       a__						)		->							Tuple:





									'''simple docstring'''
									A_       	=  [
									    '''zero_optimization.reduce_bucket_size''',
									    '''zero_optimization.stage3_prefetch_bucket_size''',
									    '''zero_optimization.stage3_param_persistence_threshold''',
									]
									A_       	=  [x for x in hidden_size_based_keys if self.is_auto(a__						)]

									if len(a__						) > 0:
													if hasattr(model.config       ,       '''hidden_size'''						):
																	A_       	=  model.config.hidden_size
													elif hasattr(model.config       ,       '''hidden_sizes'''						):
																	# if there are many hidden sizes pick the largest one
																	A_       	=  max(model.config.hidden_sizes						)
													else:
																	raise ValueError(
																	    '''The model\'s config file has neither `hidden_size` nor `hidden_sizes` entry, '''
																	    '''therefore it\'s not possible to automatically fill out the following `auto` entries '''
																	    F"in the DeepSpeed config file: {hidden_size_auto_keys}. You can fix that by replacing "
																	    '''`auto` values for these keys with an integer value of your choice.'''						)

													self.fill_only('''zero_optimization.reduce_bucket_size'''       ,       hidden_size * hidden_size						)
													if self.is_zeroa():
																	# automatically assign the optimal config values based on model config
																	self.fill_only('''zero_optimization.stage3_prefetch_bucket_size'''       ,       0.9 * hidden_size * hidden_size						)
																	self.fill_only('''zero_optimization.stage3_param_persistence_threshold'''       ,       1_0 * hidden_size						)

        # scheduler
									self.fill_match('''scheduler.params.total_num_steps'''       ,       a__       ,       '''num_training_steps (calculated)'''						)
									self.fill_match('''scheduler.params.warmup_num_steps'''       ,       args.get_warmup_steps(a__						)       ,       '''warmup_steps'''						)

									if len(self.mismatches						) > 0:
													A_       	=  '''\n'''.join(self.mismatches						)
													raise ValueError(
													    '''Please correct the following DeepSpeed config values that mismatch TrainingArguments'''
													    F" values:\n{mismatches}\nThe easiest method is to set these DeepSpeed config values to 'auto'."						)
SCREAMING_SNAKE_CASE   :		Optional[Any]					 =       None



def        lowerCamelCase_  (   __UpperCamelCase     ):
				# this is a special weakref global object to allow us to get to Deepspeed config from APIs
				# that don't have an easy way to get to the Deepspeed config outside of the Trainer domain.
				global _hf_deepspeed_config_weak_ref
				# will go away automatically when HfDeepSpeedConfig is destroyed (when TrainingArguments is destroyed)
				A_       	=  weakref.ref(__UpperCamelCase     )



def        lowerCamelCase_  (   ):
				# useful for unit tests to ensure the global state doesn't leak - call from `tearDown` method
				global _hf_deepspeed_config_weak_ref
				A_       	=  None



def        lowerCamelCase_  (   ):
				if _hf_deepspeed_config_weak_ref is not None and _hf_deepspeed_config_weak_ref() is not None:
								return _hf_deepspeed_config_weak_ref().is_zeroa()
				else:
								return False



def        lowerCamelCase_  (   ):
				if _hf_deepspeed_config_weak_ref is not None and _hf_deepspeed_config_weak_ref() is not None:
								return _hf_deepspeed_config_weak_ref().config
				else:
								return None



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase ,						__UpperCamelCase ,						__UpperCamelCase ,						__UpperCamelCase     ):
				from accelerate.utils import DummyOptim, DummyScheduler

				A_       	=  hf_deepspeed_config.config

				# Optimizer + Scheduler
				# Currently supported combos:
				# 1. DS scheduler + DS optimizer: Yes
				# 2. HF scheduler + HF optimizer: Yes
				# 3. DS scheduler + HF optimizer: Yes
				# 4. HF scheduler + DS optimizer: No
				#
				# Unless Offload is enabled in which case it's:
				# 1. DS scheduler + DS optimizer: Yes
				# 2. HF scheduler + HF optimizer: Mostly*
				# 3. DS scheduler + HF optimizer: Mostly*
				# 4. HF scheduler + DS optimizer: No
				#
				# Mostly*: All non-native DeepSpeed optimizers that have both CPU and GPU implementation should work (except LAMB)

				A_       	=  None
				if "optimizer" in config:
								if args.adafactor:
												raise ValueError(
												    '''--adafactor was passed, but also found `optimizer` configured in the DeepSpeed config. '''
												    '''Only one optimizer can be configured.'''     )
								A_       	=  DummyOptim(params=__UpperCamelCase     )
				else:
								if hf_deepspeed_config.is_offload():
												logger.info(
												    '''Detected ZeRO Offload and non-DeepSpeed optimizers: This combination should work as long as the'''
												    ''' custom optimizer has both CPU and GPU implementation (except LAMB)'''     )

								# ds supports Adam, OneBitAdam, and Lamb optimizers and can import other optimizers from torch.
								# But trainer uses AdamW by default.
								A_       	=  trainer.create_optimizer()
								# To use other optimizers requires voiding warranty with: `zero_allow_untested_optimizer`
								A_       	=  True

				A_       	=  None
				if "scheduler" in config:
								A_       	=  DummyScheduler(__UpperCamelCase     )
				else:
								if isinstance(__UpperCamelCase ,						__UpperCamelCase     ):
												raise ValueError(
												    '''Found `optimizer` configured in the DeepSpeed config, but no `scheduler`. '''
												    '''Please configure a scheduler in the DeepSpeed config.'''     )
								A_       	=  trainer.create_scheduler(num_training_steps=__UpperCamelCase ,						optimizer=__UpperCamelCase     )

				return optimizer, lr_scheduler



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase ,						__UpperCamelCase=False     ):
				from deepspeed.utils import logger as ds_logger

				A_       	=  trainer.model
				A_       	=  trainer.args

				A_       	=  trainer.accelerator.state.deepspeed_plugin.hf_ds_config

				# resume config update - some bits like `model` and `num_training_steps` only become available during train
				hf_deepspeed_config.trainer_config_finalize(__UpperCamelCase ,						__UpperCamelCase ,						__UpperCamelCase     )

				# set the Deepspeed log level consistent with the Trainer
				ds_logger.setLevel(args.get_process_log_level()     )

				if inference:
								# only Z3 makes sense for the inference
								if not hf_deepspeed_config.is_zeroa():
												raise ValueError('''ZeRO inference only makes sense with ZeRO Stage 3 - please adjust your config'''     )

								# in case the training config is re-used for inference
								hf_deepspeed_config.del_config_sub_tree('''optimizer'''     )
								hf_deepspeed_config.del_config_sub_tree('''lr_scheduler'''     )
								A_	,					A_       	=  None, None
								A_       	=  None
				else:
								A_       	=  None  # important for when deepspeed_init is used as re-init
								A_       	=  list(filter(lambda __UpperCamelCase     : p.requires_grad ,						model.parameters()     )     )
								A_	,					A_       	=  deepspeed_optim_sched(
								    __UpperCamelCase ,						__UpperCamelCase ,						__UpperCamelCase ,						__UpperCamelCase ,						__UpperCamelCase     )

				# keep for quick debug:
				# from pprint import pprint; pprint(config)

				return optimizer, lr_scheduler



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase     ):
				# it's possible that the user is trying to resume from model_path, which doesn't necessarily
				# contain a deepspeed checkpoint. e.g. examples just check if the dir exists and assume it's
				# a resume from a checkpoint and not just a local pretrained weight. So we check here if the
				# path contains what looks like a deepspeed checkpoint
				import glob

				A_       	=  sorted(glob.glob(F"{checkpoint_path}/global_step*"     )     )

				if len(__UpperCamelCase     ) > 0:
								logger.info(F"Attempting to resume from {checkpoint_path}"     )
								# this magically updates self.optimizer and self.lr_scheduler
								A_	,					A_       	=  deepspeed_engine.load_checkpoint(
								    __UpperCamelCase ,						load_optimizer_states=__UpperCamelCase ,						load_lr_scheduler_states=__UpperCamelCase     )
								if load_path is None:
												raise ValueError(F"[deepspeed] failed to resume from checkpoint {checkpoint_path}"     )
				else:
								raise ValueError(F"Can't find a valid checkpoint at {checkpoint_path}"     )

import math
from typing import Optional

import torch
import torch.utils.checkpoint as checkpoint
from torch import nn

from ....modeling_utils import PreTrainedModel
from ....utils import add_start_docstrings, logging
from ...bert.modeling_bert import BertModel
from .configuration_retribert import RetriBertConfig


SCREAMING_SNAKE_CASE   :		str					 =       logging.get_logger(__name__)

SCREAMING_SNAKE_CASE   :		List[str]					 =       [
    "yjernite/retribert-base-uncased",
    # See all RetriBert models at https://huggingface.co/models?filter=retribert
]






class 					__lowercase		(					A       ):
					__magic_name__						:							Any     	=	RetriBertConfig
					__magic_name__						:							Optional[Any]     	=	None
					__magic_name__						:							str     	=	'''retribert'''


					def        lowerCAmelCase_    (	self       ,       a__						)		->							int:





									'''simple docstring'''
									if isinstance(a__       ,       nn.Linear						):
													module.weight.data.normal_(mean=0.0       ,       std=self.config.initializer_range						)
													if module.bias is not None:
																	module.bias.data.zero_()
									elif isinstance(a__       ,       nn.Embedding						):
													module.weight.data.normal_(mean=0.0       ,       std=self.config.initializer_range						)
													if module.padding_idx is not None:
																	module.weight.data[module.padding_idx].zero_()
									elif isinstance(a__       ,       nn.LayerNorm						):
													module.bias.data.zero_()
													module.weight.data.fill_(1.0						)
SCREAMING_SNAKE_CASE   :		Optional[Any]					 =       R"\n\n    This model inherits from [`PreTrainedModel`]. Check the superclass documentation for the generic methods the\n    library implements for all its model (such as downloading or saving, resizing the input embeddings, pruning heads\n    etc.)\n\n    This model is also a PyTorch [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) subclass.\n    Use it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage\n    and behavior.\n\n    Parameters:\n        config ([`RetriBertConfig`]): Model configuration class with all the parameters of the model.\n            Initializing with a config file does not load the weights associated with the model, only the\n            configuration. Check out the [`~PreTrainedModel.from_pretrained`] method to load the model weights.\n"






@add_start_docstrings(
    '''Bert Based model to embed queries or document for document retrieval.'''							,       A							,       )
class 					__lowercase		(					A       ):


					def __init__(	self       ,       a__						)		->							None:





									'''simple docstring'''
									super().__init__(a__						)
									A_       	=  config.projection_dim

									A_       	=  BertModel(a__						)
									A_       	=  None if config.share_encoders else BertModel(a__						)
									A_       	=  nn.Dropout(config.hidden_dropout_prob						)
									A_       	=  nn.Linear(config.hidden_size       ,       config.projection_dim       ,       bias=a__						)
									A_       	=  nn.Linear(config.hidden_size       ,       config.projection_dim       ,       bias=a__						)

									A_       	=  nn.CrossEntropyLoss(reduction='''mean'''						)

									# Initialize weights and apply final processing
									self.post_init()


					def        lowerCAmelCase_    (	self       ,       a__       ,       a__       ,       a__       ,       a__=-1       ,       )		->							int:





									'''simple docstring'''
									# reproduces BERT forward pass with checkpointing
									if checkpoint_batch_size < 0 or input_ids.shape[0] < checkpoint_batch_size:
													return sent_encoder(a__       ,       attention_mask=a__						)[1]
									else:
													# prepare implicit variables
													A_       	=  input_ids.device
													A_       	=  input_ids.size()
													A_       	=  torch.zeros(a__       ,       dtype=torch.long       ,       device=a__						)
													A_       	=  [None] * sent_encoder.config.num_hidden_layers
													A_       	=  sent_encoder.get_extended_attention_mask(
													    a__       ,       a__						)

													# define function for checkpointing
													def partial_encode(*a__						):
																	A_       	=  sent_encoder.encoder(
																	    inputs[0]       ,       attention_mask=inputs[1]       ,       head_mask=a__       ,       )
																	A_       	=  encoder_outputs[0]
																	A_       	=  sent_encoder.pooler(a__						)
																	return pooled_output

													# run embedding layer on everything at once
													A_       	=  sent_encoder.embeddings(
													    input_ids=a__       ,       position_ids=a__       ,       token_type_ids=a__       ,       inputs_embeds=a__						)
													# run encoding and pooling on one mini-batch at a time
													A_       	=  []
													for b in range(math.ceil(input_ids.shape[0] / checkpoint_batch_size						)						):
																	A_       	=  embedding_output[b * checkpoint_batch_size : (b + 1) * checkpoint_batch_size]
																	A_       	=  extended_attention_mask[b * checkpoint_batch_size : (b + 1) * checkpoint_batch_size]
																	A_       	=  checkpoint.checkpoint(a__       ,       a__       ,       a__						)
																	pooled_output_list.append(a__						)
													return torch.cat(a__       ,       dim=0						)


					def        lowerCAmelCase_    (	self       ,       a__       ,       a__=None       ,       a__=-1       ,       )		->							int:





									'''simple docstring'''
									A_       	=  self.embed_sentences_checkpointed(
									    a__       ,       a__       ,       self.bert_query       ,       a__       ,       )
									return self.project_query(a__						)


					def        lowerCAmelCase_    (	self       ,       a__       ,       a__=None       ,       a__=-1       ,       )		->							Optional[Any]:





									'''simple docstring'''
									A_       	=  self.embed_sentences_checkpointed(
									    a__       ,       a__       ,       self.bert_query if self.bert_doc is None else self.bert_doc       ,       a__       ,       )
									return self.project_doc(a__						)


					def        lowerCAmelCase_    (	self       ,       a__       ,       a__       ,       a__       ,       a__       ,       a__ = -1       ,       )		->							torch.FloatTensor:





									'''simple docstring'''
									A_       	=  input_ids_query.device
									A_       	=  self.embed_questions(a__       ,       a__       ,       a__						)
									A_       	=  self.embed_answers(a__       ,       a__       ,       a__						)
									A_       	=  torch.mm(a__       ,       a_reps.t()						)
									A_       	=  self.ce_loss(a__       ,       torch.arange(compare_scores.shape[1]						).to(a__						)						)
									A_       	=  self.ce_loss(compare_scores.t()       ,       torch.arange(compare_scores.shape[0]						).to(a__						)						)
									A_       	=  (loss_qa + loss_aq) / 2
									return loss