



def    _lowerCAmelCase    (_lowerCAmelCase   ,	_lowerCAmelCase   ,	_lowerCAmelCase):

					if exponent == 1:
										return base
					if exponent % 2 == 0:
										UpperCamelCase_		  =   _modexpt(_lowerCAmelCase   ,	exponent // 2   ,	_lowerCAmelCase) % modulo_value
										return (x * x) % modulo_value
					else:
										return (base * _modexpt(_lowerCAmelCase   ,	exponent - 1   ,	_lowerCAmelCase)) % modulo_value



def    _lowerCAmelCase    (_lowerCAmelCase = 17_77   ,	_lowerCAmelCase = 18_55   ,	_lowerCAmelCase = 8):
					UpperCamelCase_		  =   base
					for _ in range(1   ,	_lowerCAmelCase):
										UpperCamelCase_		  =   _modexpt(_lowerCAmelCase   ,	_lowerCAmelCase   ,	10**digits)

					return result


if __name__ == "__main__":
	print(F"{solution() = }")





import logging
import os

import quant_trainer
import torch
from torch.utils.data import DataLoader

from transformers import Trainer, is_torch_tpu_available
from transformers.trainer_utils import PredictionOutput


UpperCAmelCase   :							str							 =logging.getLogger(__name__)

if is_torch_tpu_available(check_device=False):
	import torch_xla.core.xla_model as xm
	import torch_xla.debug.metrics as met


class       _lowercase   (a_      ):
				'''simple docstring'''







				def __init__( self     , *snake_case__     , snake_case__=None     , snake_case__=None     , snake_case__=None     , **snake_case__    ):

									'''simple docstring'''


									super().__init__(*snake_case__     , **snake_case__    )
									UpperCamelCase_		  =   eval_examples
									UpperCamelCase_		  =   post_process_function
									UpperCamelCase_		  =   quant_trainer_args
									UpperCamelCase_		  =   128  # default number of calibration samples

				def       _lowerCamelCase					( self     , snake_case__=None    ):

									'''simple docstring'''


									if calib_dataset is None and self.calib_dataset is None:
														raise ValueError("Trainer: calibration requires an calib_dataset."    )
									UpperCamelCase_		  =   calib_dataset if calib_dataset is not None else self.calib_dataset

									UpperCamelCase_		  =   self._remove_unused_columns(snake_case__     , description="Calibration"    )

									return DataLoader(
									    snake_case__     , batch_size=self.args.eval_batch_size     , collate_fn=self.data_collator     , drop_last=self.args.dataloader_drop_last     , num_workers=self.args.dataloader_num_workers     , pin_memory=self.args.dataloader_pin_memory     , shuffle=snake_case__     , )

				def       _lowerCamelCase					( self     , snake_case__=None    ):

									'''simple docstring'''


									UpperCamelCase_		  =   self.train_dataset if calib_dataset is None else calib_dataset
									UpperCamelCase_		  =   self.get_calib_dataloader(snake_case__    )

									UpperCamelCase_		  =   self.model
									quant_trainer.configure_model(snake_case__     , self.quant_trainer_args     , calib=snake_case__    )
									model.eval()
									quant_trainer.enable_calibration(snake_case__    )

									logger.info("***** Running calibration *****"    )
									logger.info(F"""  Num examples = {self.calib_num}"""    )
									logger.info(F"""  Batch size = {calib_dataloader.batch_size}"""    )

									for step, inputs in enumerate(snake_case__    ):
														# Prediction step
														UpperCamelCase_  ,    UpperCamelCase_  ,    UpperCamelCase_		  =   self.prediction_step(snake_case__     , snake_case__     , prediction_loss_only=snake_case__    )
														if (step + 1) * calib_dataloader.batch_size >= self.calib_num:
																			break

									quant_trainer.finish_calibration(snake_case__     , self.quant_trainer_args    )
									UpperCamelCase_		  =   model

				def       _lowerCamelCase					( self     , snake_case__=None     , snake_case__=None     , snake_case__=None     , snake_case__ = "eval"    ):

									'''simple docstring'''


									UpperCamelCase_		  =   self.eval_dataset if eval_dataset is None else eval_dataset
									UpperCamelCase_		  =   self.get_eval_dataloader(snake_case__    )
									UpperCamelCase_		  =   self.eval_examples if eval_examples is None else eval_examples

									# Temporarily disable metric computation, we will do it in the loop here.
									UpperCamelCase_		  =   self.compute_metrics
									UpperCamelCase_		  =   None
									UpperCamelCase_		  =   self.prediction_loop if self.args.use_legacy_prediction_loop else self.evaluation_loop
									try:
														UpperCamelCase_		  =   eval_loop(
														    snake_case__     , description="Evaluation"     , prediction_loss_only=True if compute_metrics is None else None     , ignore_keys=snake_case__     , )
									finally:
														UpperCamelCase_		  =   compute_metrics

									if self.post_process_function is not None and self.compute_metrics is not None:
														UpperCamelCase_		  =   self.post_process_function(snake_case__     , snake_case__     , output.predictions    )
														UpperCamelCase_		  =   self.compute_metrics(snake_case__    )

														# Prefix all keys with metric_key_prefix + '_'
														for key in list(metrics.keys()    ):
																			if not key.startswith(F"""{metric_key_prefix}_"""    ):
																								UpperCamelCase_		  =   metrics.pop(snake_case__    )

														self.log(snake_case__    )
									else:
														UpperCamelCase_		  =   {}

									if self.args.tpu_metrics_debug or self.args.debug:
														# tpu-comment: Logging debug metrics for PyTorch/XLA (compile, execute times, ops, etc.)
														xm.master_print(met.metrics_report()    )

									UpperCamelCase_		  =   self.callback_handler.on_evaluate(self.args     , self.state     , self.control     , snake_case__    )
									return metrics

				def       _lowerCamelCase					( self     , snake_case__     , snake_case__     , snake_case__=None     , snake_case__ = "test"    ):

									'''simple docstring'''


									UpperCamelCase_		  =   self.get_test_dataloader(snake_case__    )

									# Temporarily disable metric computation, we will do it in the loop here.
									UpperCamelCase_		  =   self.compute_metrics
									UpperCamelCase_		  =   None
									UpperCamelCase_		  =   self.prediction_loop if self.args.use_legacy_prediction_loop else self.evaluation_loop
									try:
														UpperCamelCase_		  =   eval_loop(
														    snake_case__     , description="Prediction"     , prediction_loss_only=True if compute_metrics is None else None     , ignore_keys=snake_case__     , )
									finally:
														UpperCamelCase_		  =   compute_metrics

									if self.post_process_function is None or self.compute_metrics is None:
														return output

									UpperCamelCase_		  =   self.post_process_function(snake_case__     , snake_case__     , output.predictions     , "predict"    )
									UpperCamelCase_		  =   self.compute_metrics(snake_case__    )

									# Prefix all keys with metric_key_prefix + '_'
									for key in list(metrics.keys()    ):
														if not key.startswith(F"""{metric_key_prefix}_"""    ):
																			UpperCamelCase_		  =   metrics.pop(snake_case__    )

									return PredictionOutput(predictions=predictions.predictions     , label_ids=predictions.label_ids     , metrics=snake_case__    )

				def       _lowerCamelCase					( self     , snake_case__="./"    ):

									'''simple docstring'''


									UpperCamelCase_		  =   self.eval_dataset
									UpperCamelCase_		  =   self.get_eval_dataloader(snake_case__    )

									UpperCamelCase_		  =   next(iter(snake_case__    )    )

									# saving device - to make it consistent
									UpperCamelCase_		  =   torch.device("cuda" if torch.cuda.is_available() else "cpu"    )

									# convert to tuple
									UpperCamelCase_		  =   tuple(v.to(snake_case__    ) for k, v in batch.items()    )

									logger.info("Converting model to be onnx compatible"    )
									from pytorch_quantization.nn import TensorQuantizer

									UpperCamelCase_		  =   True

									UpperCamelCase_		  =   self.model.to(snake_case__    )

									model.eval()
									model.float()

									UpperCamelCase_		  =   model.module if hasattr(snake_case__     , "module"    ) else model
									quant_trainer.configure_model(snake_case__     , self.quant_trainer_args    )

									UpperCamelCase_		  =   os.path.join(snake_case__     , "model.onnx"    )
									logger.info(F"""exporting model to {output_model_file}"""    )

									UpperCamelCase_		  =   {0: "batch_size", 1: "seq_len"}

									torch.onnx.export(
									    snake_case__     , snake_case__     , snake_case__     , export_params=snake_case__     , opset_version=13     , do_constant_folding=snake_case__     , input_names=["input_ids", "attention_mask", "token_type_ids"]     , output_names=["output_start_logits", "output_end_logits"]     , dynamic_axes={
									        "input_ids": axes,
									        "attention_mask": axes,
									        "token_type_ids": axes,
									        "output_start_logits": axes,
									        "output_end_logits": axes,
									    }     , verbose=snake_case__     , )
									logger.info("onnx export finished"    )
