



'''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       __lowercase  (_SCREAMING_SNAKE_CASE      :int       ):
				SCREAMING_SNAKE_CASE  :						str      					= filter(lambda _SCREAMING_SNAKE_CASE       : p.requires_grad    ,	model.parameters()       )
				SCREAMING_SNAKE_CASE  :						Tuple      					= sum([np.prod(p.size()       ) for p in model_parameters]       )
				return params


snake_case_			=     logging.getLogger(__name__)






def       __lowercase  (_SCREAMING_SNAKE_CASE      :int    ,	_SCREAMING_SNAKE_CASE      :Union[str, Any]       ):
				if metric == "rouge2":
								SCREAMING_SNAKE_CASE  :						List[str]      					= '''{val_avg_rouge2:.4f}-{step_count}'''
				elif metric == "bleu":
								SCREAMING_SNAKE_CASE  :						int      					= '''{val_avg_bleu:.4f}-{step_count}'''
				elif metric == "em":
								SCREAMING_SNAKE_CASE  :						Optional[int]      					= '''{val_avg_em:.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.'''       )

				SCREAMING_SNAKE_CASE  :						Optional[int]      					= ModelCheckpoint(
				    dirpath=_SCREAMING_SNAKE_CASE    ,	filename=_SCREAMING_SNAKE_CASE    ,	monitor=F'''val_{metric}'''    ,	mode='''max'''    ,	save_top_k=3    ,	every_n_epochs=1    ,	)
				return checkpoint_callback






def       __lowercase  (_SCREAMING_SNAKE_CASE      :List[Any]    ,	_SCREAMING_SNAKE_CASE      :Tuple       ):
				return EarlyStopping(
				    monitor=F'''val_{metric}'''    ,	mode='''min''' if '''loss''' in metric else '''max'''    ,	patience=_SCREAMING_SNAKE_CASE    ,	verbose=_SCREAMING_SNAKE_CASE    ,	)




class 	a__     (				pl.Callback	):


	def 				lowercase__  (self : List[Any],					__UpperCAmelCase : Any,					__UpperCAmelCase : Union[str, Any]      )     ->			List[str]:

					"""simple docstring"""

					SCREAMING_SNAKE_CASE  :						int      					= {F'''lr_group_{i}''': param['''lr'''] for i, param in enumerate(pl_module.trainer.optimizers[0].param_groups      )}
					pl_module.logger.log_metrics(__UpperCAmelCase      )


	@rank_zero_only
	def 				lowercase__  (self : str,					__UpperCAmelCase : pl.Trainer,					__UpperCAmelCase : pl.LightningModule,					__UpperCAmelCase : str,					__UpperCAmelCase : Optional[Any]=True      )     ->			None:

					"""simple docstring"""

					logger.info(F'''***** {type_path} results at step {trainer.global_step:05d} *****'''      )
					SCREAMING_SNAKE_CASE  :						Any      					= 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
					SCREAMING_SNAKE_CASE  :						Optional[Any]      					= Path(pl_module.hparams.output_dir      )
					if type_path == "test":
									SCREAMING_SNAKE_CASE  :						str      					= od / '''test_results.txt'''
									SCREAMING_SNAKE_CASE  :						Dict      					= 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.
									SCREAMING_SNAKE_CASE  :						Union[str, Any]      					= od / F'''{type_path}_results/{trainer.global_step:05d}.txt'''
									SCREAMING_SNAKE_CASE  :						Optional[Any]      					= od / F'''{type_path}_generations/{trainer.global_step:05d}.txt'''
									results_file.parent.mkdir(exist_ok=__UpperCAmelCase      )
									generations_file.parent.mkdir(exist_ok=__UpperCAmelCase      )
					with open(__UpperCAmelCase,					'''a+'''      ) as writer:
									for key in sorted(__UpperCAmelCase      ):
													if key in ["log", "progress_bar", "preds"]:
																	continue
													SCREAMING_SNAKE_CASE  :						List[Any]      					= metrics[key]
													if isinstance(__UpperCAmelCase,					torch.Tensor      ):
																	SCREAMING_SNAKE_CASE  :						List[Any]      					= val.item()
													SCREAMING_SNAKE_CASE  :						Optional[int]      					= F'''{key}: {val:.6f}\n'''
													writer.write(__UpperCAmelCase      )

					if not save_generations:
									return

					if "preds" in metrics:
									SCREAMING_SNAKE_CASE  :						List[Any]      					= '''\n'''.join(metrics['''preds''']      )
									generations_file.open('''w+'''      ).write(__UpperCAmelCase      )


	@rank_zero_only
	def 				lowercase__  (self : Optional[Any],					__UpperCAmelCase : Optional[int],					__UpperCAmelCase : str      )     ->			Any:

					"""simple docstring"""

					try:
									SCREAMING_SNAKE_CASE  :						Any      					= pl_module.model.model.num_parameters()
					except AttributeError:
									SCREAMING_SNAKE_CASE  :						Tuple      					= pl_module.model.num_parameters()

					SCREAMING_SNAKE_CASE  :						Optional[Any]      					= count_trainable_parameters(__UpperCAmelCase      )
					# 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 				lowercase__  (self : Any,					__UpperCAmelCase : pl.Trainer,					__UpperCAmelCase : pl.LightningModule      )     ->			Any:

					"""simple docstring"""

					save_json(pl_module.metrics,					pl_module.metrics_save_path      )
					return self._write_logs(__UpperCAmelCase,					__UpperCAmelCase,					'''test'''      )






	@rank_zero_only
	def 				lowercase__  (self : Union[str, Any],					__UpperCAmelCase : pl.Trainer,					__UpperCAmelCase : Optional[int]      )     ->			int:

					"""simple docstring"""

					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'''

import argparse
from pathlib import Path

import requests
import torch
from PIL import Image

from transformers import (
    RobertaTokenizer,
    TrOCRConfig,
    TrOCRForCausalLM,
    TrOCRProcessor,
    VisionEncoderDecoderModel,
    ViTConfig,
    ViTImageProcessor,
    ViTModel,
)
from transformers.utils import logging


logging.set_verbosity_info()
snake_case_			=     logging.get_logger(__name__)






def       __lowercase  (_SCREAMING_SNAKE_CASE      :Dict    ,	_SCREAMING_SNAKE_CASE      :int       ):
				SCREAMING_SNAKE_CASE  :						Dict      					= []
				for i in range(encoder_config.num_hidden_layers       ):
								# encoder layers: output projection, 2 feedforward neural networks and 2 layernorms
								rename_keys.append(
								    (F'''encoder.deit.blocks.{i}.norm1.weight''', F'''encoder.encoder.layer.{i}.layernorm_before.weight''')       )
								rename_keys.append((F'''encoder.deit.blocks.{i}.norm1.bias''', F'''encoder.encoder.layer.{i}.layernorm_before.bias''')       )
								rename_keys.append(
								    (F'''encoder.deit.blocks.{i}.attn.proj.weight''', F'''encoder.encoder.layer.{i}.attention.output.dense.weight''')       )
								rename_keys.append(
								    (F'''encoder.deit.blocks.{i}.attn.proj.bias''', F'''encoder.encoder.layer.{i}.attention.output.dense.bias''')       )
								rename_keys.append(
								    (F'''encoder.deit.blocks.{i}.norm2.weight''', F'''encoder.encoder.layer.{i}.layernorm_after.weight''')       )
								rename_keys.append((F'''encoder.deit.blocks.{i}.norm2.bias''', F'''encoder.encoder.layer.{i}.layernorm_after.bias''')       )
								rename_keys.append(
								    (F'''encoder.deit.blocks.{i}.mlp.fc1.weight''', F'''encoder.encoder.layer.{i}.intermediate.dense.weight''')       )
								rename_keys.append(
								    (F'''encoder.deit.blocks.{i}.mlp.fc1.bias''', F'''encoder.encoder.layer.{i}.intermediate.dense.bias''')       )
								rename_keys.append(
								    (F'''encoder.deit.blocks.{i}.mlp.fc2.weight''', F'''encoder.encoder.layer.{i}.output.dense.weight''')       )
								rename_keys.append((F'''encoder.deit.blocks.{i}.mlp.fc2.bias''', F'''encoder.encoder.layer.{i}.output.dense.bias''')       )

				# cls token, position embeddings and patch embeddings of encoder
				rename_keys.extend(
				    [
				        ('''encoder.deit.cls_token''', '''encoder.embeddings.cls_token'''),
				        ('''encoder.deit.pos_embed''', '''encoder.embeddings.position_embeddings'''),
				        ('''encoder.deit.patch_embed.proj.weight''', '''encoder.embeddings.patch_embeddings.projection.weight'''),
				        ('''encoder.deit.patch_embed.proj.bias''', '''encoder.embeddings.patch_embeddings.projection.bias'''),
				        ('''encoder.deit.norm.weight''', '''encoder.layernorm.weight'''),
				        ('''encoder.deit.norm.bias''', '''encoder.layernorm.bias'''),
				    ]       )

				return rename_keys






def       __lowercase  (_SCREAMING_SNAKE_CASE      :List[Any]    ,	_SCREAMING_SNAKE_CASE      :Tuple       ):
				for i in range(encoder_config.num_hidden_layers       ):
								# queries, keys and values (only weights, no biases)
								SCREAMING_SNAKE_CASE  :						str      					= state_dict.pop(F'''encoder.deit.blocks.{i}.attn.qkv.weight'''       )

								SCREAMING_SNAKE_CASE  :						Any      					= in_proj_weight[
								    : encoder_config.hidden_size, :
								]
								SCREAMING_SNAKE_CASE  :						List[Any]      					= in_proj_weight[
								    encoder_config.hidden_size : encoder_config.hidden_size * 2, :
								]
								SCREAMING_SNAKE_CASE  :						Dict      					= in_proj_weight[
								    -encoder_config.hidden_size :, :
								]






def       __lowercase  (_SCREAMING_SNAKE_CASE      :int    ,	_SCREAMING_SNAKE_CASE      :str    ,	_SCREAMING_SNAKE_CASE      :Optional[int]       ):
				SCREAMING_SNAKE_CASE  :						List[str]      					= dct.pop(_SCREAMING_SNAKE_CASE       )
				SCREAMING_SNAKE_CASE  :						Union[str, Any]      					= val






def       __lowercase  (_SCREAMING_SNAKE_CASE      :List[str]       ):
				if "handwritten" in checkpoint_url:
								SCREAMING_SNAKE_CASE  :						Any      					= '''https://fki.tic.heia-fr.ch/static/img/a01-122-02-00.jpg'''  # industry
								# url = "https://fki.tic.heia-fr.ch/static/img/a01-122-02-12.jpg" # have
								# url = "https://fki.tic.heia-fr.ch/static/img/a01-122-02-10.jpg" # let
								# url = "https://fki.tic.heia-fr.ch/static/img/a01-122-02.jpg"  #
								# url = "https://fki.tic.heia-fr.ch/static/img/a01-122.jpg"
				elif "printed" in checkpoint_url or "stage1" in checkpoint_url:
								SCREAMING_SNAKE_CASE  :						Union[str, Any]      					= '''https://www.researchgate.net/profile/Dinh-Sang/publication/338099565/figure/fig8/AS:840413229350922@1577381536857/An-receipt-example-in-the-SROIE-2019-dataset_Q640.jpg'''
				SCREAMING_SNAKE_CASE  :						List[Any]      					= Image.open(requests.get(_SCREAMING_SNAKE_CASE    ,	stream=_SCREAMING_SNAKE_CASE       ).raw       ).convert('''RGB'''       )
				return im






@torch.no_grad()
def       __lowercase  (_SCREAMING_SNAKE_CASE      :List[Any]    ,	_SCREAMING_SNAKE_CASE      :Optional[int]       ):
				SCREAMING_SNAKE_CASE  :						Union[str, Any]      					= ViTConfig(image_size=3_84    ,	qkv_bias=_SCREAMING_SNAKE_CASE       )
				SCREAMING_SNAKE_CASE  :						Any      					= TrOCRConfig()

				# size of the architecture
				if "base" in checkpoint_url:
								SCREAMING_SNAKE_CASE  :						List[Any]      					= 7_68
				elif "large" in checkpoint_url:
								# use ViT-large encoder
								SCREAMING_SNAKE_CASE  :						Union[str, Any]      					= 10_24
								SCREAMING_SNAKE_CASE  :						Optional[Any]      					= 40_96
								SCREAMING_SNAKE_CASE  :						List[str]      					= 24
								SCREAMING_SNAKE_CASE  :						Any      					= 16
								SCREAMING_SNAKE_CASE  :						Optional[Any]      					= 10_24
				else:
								raise ValueError('''Should either find \'base\' or \'large\' in checkpoint URL'''       )

				# the large-printed + stage1 checkpoints uses sinusoidal position embeddings, no layernorm afterwards
				if "large-printed" in checkpoint_url or "stage1" in checkpoint_url:
								SCREAMING_SNAKE_CASE  :						Optional[Any]      					= False
								SCREAMING_SNAKE_CASE  :						Optional[Any]      					= '''relu'''
								SCREAMING_SNAKE_CASE  :						Tuple      					= 10_24
								SCREAMING_SNAKE_CASE  :						int      					= True
								SCREAMING_SNAKE_CASE  :						Union[str, Any]      					= False
								SCREAMING_SNAKE_CASE  :						Any      					= False

				# load HuggingFace model
				SCREAMING_SNAKE_CASE  :						List[Any]      					= ViTModel(_SCREAMING_SNAKE_CASE    ,	add_pooling_layer=_SCREAMING_SNAKE_CASE       )
				SCREAMING_SNAKE_CASE  :						int      					= TrOCRForCausalLM(_SCREAMING_SNAKE_CASE       )
				SCREAMING_SNAKE_CASE  :						Any      					= VisionEncoderDecoderModel(encoder=_SCREAMING_SNAKE_CASE    ,	decoder=_SCREAMING_SNAKE_CASE       )
				model.eval()

				# load state_dict of original model, rename some keys
				SCREAMING_SNAKE_CASE  :						List[Any]      					= torch.hub.load_state_dict_from_url(_SCREAMING_SNAKE_CASE    ,	map_location='''cpu'''    ,	check_hash=_SCREAMING_SNAKE_CASE       )['''model''']

				SCREAMING_SNAKE_CASE  :						int      					= create_rename_keys(_SCREAMING_SNAKE_CASE    ,	_SCREAMING_SNAKE_CASE       )
				for src, dest in rename_keys:
								rename_key(_SCREAMING_SNAKE_CASE    ,	_SCREAMING_SNAKE_CASE    ,	_SCREAMING_SNAKE_CASE       )
				read_in_q_k_v(_SCREAMING_SNAKE_CASE    ,	_SCREAMING_SNAKE_CASE       )

				# remove parameters we don't need
				del state_dict["encoder.deit.head.weight"]
				del state_dict["encoder.deit.head.bias"]
				del state_dict["decoder.version"]

				# add prefix to decoder keys
				for key, val in state_dict.copy().items():
								SCREAMING_SNAKE_CASE  :						List[Any]      					= state_dict.pop(_SCREAMING_SNAKE_CASE       )
								if key.startswith('''decoder'''       ) and "output_projection" not in key:
												SCREAMING_SNAKE_CASE  :						Tuple      					= val
								else:
												SCREAMING_SNAKE_CASE  :						int      					= val

    # load state dict
				model.load_state_dict(_SCREAMING_SNAKE_CASE       )

				# Check outputs on an image
				SCREAMING_SNAKE_CASE  :						List[Any]      					= ViTImageProcessor(size=encoder_config.image_size       )
				SCREAMING_SNAKE_CASE  :						Tuple      					= RobertaTokenizer.from_pretrained('''roberta-large'''       )
				SCREAMING_SNAKE_CASE  :						Dict      					= TrOCRProcessor(_SCREAMING_SNAKE_CASE    ,	_SCREAMING_SNAKE_CASE       )

				SCREAMING_SNAKE_CASE  :						Tuple      					= processor(images=prepare_img(_SCREAMING_SNAKE_CASE       )    ,	return_tensors='''pt'''       ).pixel_values

				# verify logits
				SCREAMING_SNAKE_CASE  :						str      					= torch.tensor([[model.config.decoder.decoder_start_token_id]]       )
				SCREAMING_SNAKE_CASE  :						Dict      					= model(pixel_values=_SCREAMING_SNAKE_CASE    ,	decoder_input_ids=_SCREAMING_SNAKE_CASE       )
				SCREAMING_SNAKE_CASE  :						int      					= outputs.logits

				SCREAMING_SNAKE_CASE  :						Any      					= torch.Size([1, 1, 5_02_65]       )
				if "trocr-base-handwritten" in checkpoint_url:
								SCREAMING_SNAKE_CASE  :						Optional[int]      					= torch.tensor(
								    [-1.4502, -4.6683, -0.5347, -2.9291, 9.1435, -3.0571, 8.9764, 1.7560, 8.7358, -1.5311]       )
				elif "trocr-large-handwritten" in checkpoint_url:
								SCREAMING_SNAKE_CASE  :						Any      					= torch.tensor(
								    [-2.6437, -1.3129, -2.2596, -5.3455, 6.3539, 1.7604, 5.4991, 1.4702, 5.6113, 2.0170]       )
				elif "trocr-base-printed" in checkpoint_url:
								SCREAMING_SNAKE_CASE  :						str      					= torch.tensor(
								    [-5.6816, -5.8388, 1.1398, -6.9034, 6.8505, -2.4393, 1.2284, -1.0232, -1.9661, -3.9210]       )
				elif "trocr-large-printed" in checkpoint_url:
								SCREAMING_SNAKE_CASE  :						Optional[int]      					= torch.tensor(
								    [-6.0162, -7.0959, 4.4155, -5.1063, 7.0468, -3.1631, 2.6466, -0.3081, -0.8106, -1.7535]       )

				if "stage1" not in checkpoint_url:
								assert logits.shape == expected_shape, "Shape of logits not as expected"
								assert torch.allclose(logits[0, 0, :10]    ,	_SCREAMING_SNAKE_CASE    ,	atol=1E-3       ), "First elements of logits not as expected"

				Path(_SCREAMING_SNAKE_CASE       ).mkdir(exist_ok=_SCREAMING_SNAKE_CASE       )
				print(F'''Saving model to {pytorch_dump_folder_path}'''       )
				model.save_pretrained(_SCREAMING_SNAKE_CASE       )
				print(F'''Saving processor to {pytorch_dump_folder_path}'''       )
				processor.save_pretrained(_SCREAMING_SNAKE_CASE       )


if __name__ == "__main__":
	snake_case_			=     argparse.ArgumentParser()

	parser.add_argument(
	    """--checkpoint_url""",
	    default="""https://layoutlm.blob.core.windows.net/trocr/model_zoo/fairseq/trocr-base-handwritten.pt""",
	    type=str,
	    help="""URL to the original PyTorch checkpoint (.pth file).""",
	)
	parser.add_argument(
	    """--pytorch_dump_folder_path""", default=None, type=str, help="""Path to the folder to output PyTorch model."""
	)
	snake_case_			=     parser.parse_args()
	convert_tr_ocr_checkpoint(args.checkpoint_url, args.pytorch_dump_folder_path)




