






'''simple docstring'''



import argparse

import torch
from datasets import load_dataset
from donut import DonutModel

from transformers import (
    DonutImageProcessor,
    DonutProcessor,
    DonutSwinConfig,
    DonutSwinModel,
    MBartConfig,
    MBartForCausalLM,
    VisionEncoderDecoderModel,
    XLMRobertaTokenizerFast,
)


def 							lowercase_				(    __A :       Any			)       ->      Optional[Any]:



 """simple docstring"""




 lowercase					:   Dict				  =model.config

 lowercase					:   List[Any]				  =DonutSwinConfig(
     image_size=original_config.input_size					,      patch_size=4					,      depths=original_config.encoder_layer					,      num_heads=[4, 8, 1_6, 3_2]					,      window_size=original_config.window_size					,      embed_dim=1_2_8					,      )
 lowercase					:   List[Any]				  =MBartConfig(
     is_decoder=__A					,      is_encoder_decoder=__A					,      add_cross_attention=__A					,      decoder_layers=original_config.decoder_layer					,      max_position_embeddings=original_config.max_position_embeddings					,      vocab_size=len(
         model.decoder.tokenizer			)					,      scale_embedding=__A					,      add_final_layer_norm=__A					,      )

 return encoder_config, decoder_config


def 							lowercase_				(    __A :       Optional[int]			)       ->      Union[str, Any]:



 """simple docstring"""




 if "encoder.model" in name:
  lowercase					:   int				  =name.replace('''encoder.model'''					,      '''encoder'''			)
 if "decoder.model" in name:
  lowercase					:   Dict				  =name.replace('''decoder.model'''					,      '''decoder'''			)
 if "patch_embed.proj" in name:
  lowercase					:   int				  =name.replace('''patch_embed.proj'''					,      '''embeddings.patch_embeddings.projection'''			)
 if "patch_embed.norm" in name:
  lowercase					:   Tuple				  =name.replace('''patch_embed.norm'''					,      '''embeddings.norm'''			)
 if name.startswith('''encoder'''			):
  if "layers" in name:
   lowercase					:   Any				  ="""encoder.""" + name
  if "attn.proj" in name:
   lowercase					:   Any				  =name.replace('''attn.proj'''					,      '''attention.output.dense'''			)
  if "attn" in name and "mask" not in name:
   lowercase					:   Tuple				  =name.replace('''attn'''					,      '''attention.self'''			)
  if "norm1" in name:
   lowercase					:   Dict				  =name.replace('''norm1'''					,      '''layernorm_before'''			)
  if "norm2" in name:
   lowercase					:   Union[str, Any]				  =name.replace('''norm2'''					,      '''layernorm_after'''			)
  if "mlp.fc1" in name:
   lowercase					:   List[Any]				  =name.replace('''mlp.fc1'''					,      '''intermediate.dense'''			)
  if "mlp.fc2" in name:
   lowercase					:   Dict				  =name.replace('''mlp.fc2'''					,      '''output.dense'''			)

  if name == "encoder.norm.weight":
   lowercase					:   str				  ="""encoder.layernorm.weight"""
  if name == "encoder.norm.bias":
   lowercase					:   Dict				  ="""encoder.layernorm.bias"""

 return name


def 							lowercase_				(    __A :       Optional[Any]					,      __A :       int			)       ->      Optional[Any]:



 """simple docstring"""




 for key in orig_state_dict.copy().keys():
  lowercase					:   List[str]				  =orig_state_dict.pop(__A			)

  if "qkv" in key:
   lowercase					:   int				  =key.split('''.'''			)
   lowercase					:   List[str]				  =int(key_split[3]			)
   lowercase					:   Optional[Any]				  =int(key_split[5]			)
   lowercase					:   str				  =model.encoder.encoder.layers[layer_num].blocks[block_num].attention.self.all_head_size

   if "weight" in key:
    lowercase					:   Union[str, Any]				  =val[:dim, :]
    lowercase					:   Optional[int]				  =val[dim : dim * 2, :]
    lowercase					:   Union[str, Any]				  =val[-dim:, :]
   else:
    lowercase					:   List[Any]				  =val[:dim]
    lowercase					:   Optional[Any]				  =val[dim : dim * 2]
    lowercase					:   Dict				  =val[-dim:]
  elif "attn_mask" in key or key in ["encoder.model.norm.weight", "encoder.model.norm.bias"]:
   # HuggingFace implementation doesn't use attn_mask buffer
   # and model doesn't use final LayerNorms for the encoder
   pass
  else:
   lowercase					:   List[str]				  =val

 return orig_state_dict


def 							lowercase_				(    __A :       int					,      __A :       List[Any]=None					,      __A :       Dict=False			)       ->      List[Any]:



 """simple docstring"""




 lowercase					:   Dict				  =DonutModel.from_pretrained(__A			).eval()

 # load HuggingFace model
 lowercase					:   List[str]				  =get_configs(__A			)
 lowercase					:   Union[str, Any]				  =DonutSwinModel(__A			)
 lowercase					:   Union[str, Any]				  =MBartForCausalLM(__A			)
 lowercase					:   Any				  =VisionEncoderDecoderModel(encoder=__A					,      decoder=__A			)
 model.eval()

 lowercase					:   List[Any]				  =original_model.state_dict()
 lowercase					:   List[Any]				  =convert_state_dict(__A					,      __A			)
 model.load_state_dict(__A			)

 # verify results on scanned document
 lowercase					:   str				  =load_dataset('''hf-internal-testing/example-documents'''			)
 lowercase					:   List[Any]				  =dataset["""test"""][0]["""image"""].convert('''RGB'''			)

 lowercase					:   List[Any]				  =XLMRobertaTokenizerFast.from_pretrained(__A					,      from_slow=__A			)
 lowercase					:   Tuple				  =DonutImageProcessor(
     do_align_long_axis=original_model.config.align_long_axis					,      size=original_model.config.input_size[::-1]			)
 lowercase					:   Optional[int]				  =DonutProcessor(__A					,      __A			)
 lowercase					:   Tuple				  =processor(__A					,      return_tensors='''pt'''			).pixel_values

 if model_name == "naver-clova-ix/donut-base-finetuned-docvqa":
  lowercase					:   List[str]				  ="""<s_docvqa><s_question>{user_input}</s_question><s_answer>"""
  lowercase					:   Union[str, Any]				  ="""When is the coffee break?"""
  lowercase					:   List[str]				  =task_prompt.replace('''{user_input}'''					,      __A			)
 elif model_name == "naver-clova-ix/donut-base-finetuned-rvlcdip":
  lowercase					:   str				  ="""<s_rvlcdip>"""
 elif model_name in [
     "naver-clova-ix/donut-base-finetuned-cord-v1",
     "naver-clova-ix/donut-base-finetuned-cord-v1-2560",
 ]:
  lowercase					:   str				  ="""<s_cord>"""
 elif model_name == "naver-clova-ix/donut-base-finetuned-cord-v2":
  lowercase					:   Any				  ="""s_cord-v2>"""
 elif model_name == "naver-clova-ix/donut-base-finetuned-zhtrainticket":
  lowercase					:   List[str]				  ="""<s_zhtrainticket>"""
 elif model_name in ["naver-clova-ix/donut-proto", "naver-clova-ix/donut-base"]:
  # use a random prompt
  lowercase					:   int				  ="""hello world"""
 else:
  raise ValueError('''Model name not supported'''			)
 lowercase					:   List[Any]				  =original_model.decoder.tokenizer(__A					,      add_special_tokens=__A					,      return_tensors='''pt'''			)[
     """input_ids"""
 ]

 lowercase					:   Tuple				  =original_model.encoder.model.patch_embed(__A			)
 lowercase					:   str				  =model.encoder.embeddings(__A			)
 assert torch.allclose(__A					,      __A					,      atol=1E-3			)

 # verify encoder hidden states
 lowercase					:   Any				  =original_model.encoder(__A			)
 lowercase					:   Optional[int]				  =model.encoder(__A			).last_hidden_state
 assert torch.allclose(__A					,      __A					,      atol=1E-2			)

 # verify decoder hidden states
 lowercase					:   int				  =original_model(__A					,      __A					,      __A			).logits
 lowercase					:   Dict				  =model(__A					,      decoder_input_ids=__A			).logits
 assert torch.allclose(__A					,      __A					,      atol=1E-3			)
 print('''Looks ok!'''			)

 if pytorch_dump_folder_path is not None:
  print(F'Saving model and processor to {pytorch_dump_folder_path}'			)
  model.save_pretrained(__A			)
  processor.save_pretrained(__A			)

 if push_to_hub:
  model.push_to_hub('''nielsr/''' + model_name.split('''/'''			)[-1]					,      commit_message='''Update model'''			)
  processor.push_to_hub('''nielsr/''' + model_name.split('''/'''			)[-1]					,      commit_message='''Update model'''			)


if __name__ == "__main__":
      SCREAMING_SNAKE_CASE						=	argparse.ArgumentParser()
      # Required parameters
      parser.add_argument(
          '--model_name',
          default='naver-clova-ix/donut-base-finetuned-docvqa',
          required=False,
          type=str,
          help='Name of the original model you\'d like to convert.',
      )
      parser.add_argument(
          '--pytorch_dump_folder_path',
          default=None,
          required=False,
          type=str,
          help='Path to the output PyTorch model directory.',
      )
      parser.add_argument(
          '--push_to_hub',
          action='store_true',
          help='Whether or not to push the converted model and processor to the 🤗 hub.',
      )

      SCREAMING_SNAKE_CASE						=	parser.parse_args()
      convert_donut_checkpoint(args.model_name, args.pytorch_dump_folder_path, args.push_to_hub)











'''simple docstring'''



import warnings
from typing import List, Optional, Union

from ...processing_utils import ProcessorMixin
from ...tokenization_utils_base import BatchEncoding, PaddingStrategy, PreTokenizedInput, TextInput, TruncationStrategy
from ...utils import TensorType
class UpperCAmelCase_					(    __A				):




      """simple docstring"""




      UpperCamelCase_								=			['''image_processor''', '''tokenizer''']
      UpperCamelCase_								=			'''LayoutLMv2ImageProcessor'''
      UpperCamelCase_								=			('''LayoutXLMTokenizer''', '''LayoutXLMTokenizerFast''')






      def __init__( self			:		List[str]     ,      UpperCAmelCase			:		Tuple=None     ,      UpperCAmelCase			:		str=None     ,      **UpperCAmelCase			:		Dict		)  ->  Optional[int]:


       '''simple docstring'''

       if "feature_extractor" in kwargs:
        warnings.warn(
            '''The `feature_extractor` argument is deprecated and will be removed in v5, use `image_processor`'''
            ''' instead.'''     ,      UpperCAmelCase     ,      )
        lowercase					:   Any				  =kwargs.pop('''feature_extractor'''		)

       lowercase					:   Dict				  =image_processor if image_processor is not None else feature_extractor
       if image_processor is None:
        raise ValueError('''You need to specify an `image_processor`.'''		)
       if tokenizer is None:
        raise ValueError('''You need to specify a `tokenizer`.'''		)

       super().__init__(UpperCAmelCase     ,      UpperCAmelCase		)






      def __call__( self			:		Any     ,      UpperCAmelCase			:		Optional[Any]     ,      UpperCAmelCase			:		Union[TextInput, PreTokenizedInput, List[TextInput], List[PreTokenizedInput]] = None     ,      UpperCAmelCase			:		Optional[Union[PreTokenizedInput, List[PreTokenizedInput]]] = None     ,      UpperCAmelCase			:		Union[List[List[int]], List[List[List[int]]]] = None     ,      UpperCAmelCase			:		Optional[Union[List[int], List[List[int]]]] = None     ,      UpperCAmelCase			:		bool = True     ,      UpperCAmelCase			:		Union[bool, str, PaddingStrategy] = False     ,      UpperCAmelCase			:		Union[bool, str, TruncationStrategy] = None     ,      UpperCAmelCase			:		Optional[int] = None     ,      UpperCAmelCase			:		int = 0     ,      UpperCAmelCase			:		Optional[int] = None     ,      UpperCAmelCase			:		Optional[bool] = None     ,      UpperCAmelCase			:		Optional[bool] = None     ,      UpperCAmelCase			:		bool = False     ,      UpperCAmelCase			:		bool = False     ,      UpperCAmelCase			:		bool = False     ,      UpperCAmelCase			:		bool = False     ,      UpperCAmelCase			:		bool = True     ,      UpperCAmelCase			:		Optional[Union[str, TensorType]] = None     ,      **UpperCAmelCase			:		Any     ,      )  ->  BatchEncoding:


       '''simple docstring'''

       if self.image_processor.apply_ocr and (boxes is not None):
        raise ValueError(
            '''You cannot provide bounding boxes '''
            '''if you initialized the image processor with apply_ocr set to True.'''		)

       if self.image_processor.apply_ocr and (word_labels is not None):
        raise ValueError(
            '''You cannot provide word labels if you initialized the image processor with apply_ocr set to True.'''		)

       if return_overflowing_tokens is True and return_offsets_mapping is False:
        raise ValueError('''You cannot return overflowing tokens without returning the offsets mapping.'''		)

       # first, apply the image processor
       lowercase					:   Tuple				  =self.image_processor(images=UpperCAmelCase     ,      return_tensors=UpperCAmelCase		)

       # second, apply the tokenizer
       if text is not None and self.image_processor.apply_ocr and text_pair is None:
        if isinstance(UpperCAmelCase     ,      UpperCAmelCase		):
         lowercase					:   Optional[Any]				  =[text]  # add batch dimension (as the image processor always adds a batch dimension)
        lowercase					:   List[str]				  =features['''words''']

       lowercase					:   Optional[Any]				  =self.tokenizer(
           text=text if text is not None else features['''words''']     ,      text_pair=text_pair if text_pair is not None else None     ,      boxes=boxes if boxes is not None else features['''boxes''']     ,      word_labels=UpperCAmelCase     ,      add_special_tokens=UpperCAmelCase     ,      padding=UpperCAmelCase     ,      truncation=UpperCAmelCase     ,      max_length=UpperCAmelCase     ,      stride=UpperCAmelCase     ,      pad_to_multiple_of=UpperCAmelCase     ,      return_token_type_ids=UpperCAmelCase     ,      return_attention_mask=UpperCAmelCase     ,      return_overflowing_tokens=UpperCAmelCase     ,      return_special_tokens_mask=UpperCAmelCase     ,      return_offsets_mapping=UpperCAmelCase     ,      return_length=UpperCAmelCase     ,      verbose=UpperCAmelCase     ,      return_tensors=UpperCAmelCase     ,      **UpperCAmelCase     ,      )

       # add pixel values
       lowercase					:   List[str]				  =features.pop('''pixel_values'''		)
       if return_overflowing_tokens is True:
        lowercase					:   str				  =self.get_overflowing_images(UpperCAmelCase     ,      encoded_inputs['''overflow_to_sample_mapping''']		)
       lowercase					:   Dict				  =images

       return encoded_inputs






      def 				A__      ( self			:		Any     ,      UpperCAmelCase			:		Optional[Any]     ,      UpperCAmelCase			:		str		)  ->  str:


       '''simple docstring'''

       lowercase					:   str				  =[]
       for sample_idx in overflow_to_sample_mapping:
        images_with_overflow.append(images[sample_idx]		)

       if len(UpperCAmelCase		) != len(UpperCAmelCase		):
        raise ValueError(
            '''Expected length of images to be the same as the length of `overflow_to_sample_mapping`, but got'''
            f' {len(UpperCAmelCase		)} and {len(UpperCAmelCase		)}'		)

       return images_with_overflow






      def 				A__      ( self			:		Union[str, Any]     ,      *UpperCAmelCase			:		Tuple     ,      **UpperCAmelCase			:		Dict		)  ->  int:


       '''simple docstring'''

       return self.tokenizer.batch_decode(*UpperCAmelCase     ,      **UpperCAmelCase		)






      def 				A__      ( self			:		Dict     ,      *UpperCAmelCase			:		Any     ,      **UpperCAmelCase			:		Dict		)  ->  str:


       '''simple docstring'''

       return self.tokenizer.decode(*UpperCAmelCase     ,      **UpperCAmelCase		)






      @property
      def 				A__      ( self			:		List[str]		)  ->  List[str]:


       '''simple docstring'''

       return ["input_ids", "bbox", "attention_mask", "image"]






      @property
      def 				A__      ( self			:		int		)  ->  List[str]:


       '''simple docstring'''

       warnings.warn(
           '''`feature_extractor_class` is deprecated and will be removed in v5. Use `image_processor_class` instead.'''     ,      UpperCAmelCase     ,      )
       return self.image_processor_class






      @property
      def 				A__      ( self			:		Dict		)  ->  List[str]:


       '''simple docstring'''

       warnings.warn(
           '''`feature_extractor` is deprecated and will be removed in v5. Use `image_processor` instead.'''     ,      UpperCAmelCase     ,      )
       return self.image_processor



