





import argparse
import json
from pathlib import Path

import requests
import torch
from huggingface_hub import hf_hub_download
from PIL import Image

from transformers import ViTConfig, ViTForImageClassification, ViTImageProcessor, ViTModel
from transformers.utils import logging


logging.set_verbosity_info()
snake_case__					:							List[Any]													=     logging.get_logger(__name__)



def _a				(	lowerCamelCase:   List[str]					,				lowerCamelCase:   List[Any]=False )	->						Tuple:







      '''simple docstring'''






      __A          =				[]
      for i in range(config.num_hidden_layers ):
            # encoder layers: output projection, 2 feedforward neural networks and 2 layernorms
            rename_keys.append((F"""blocks.{i}.norm1.weight""", F"""vit.encoder.layer.{i}.layernorm_before.weight""") )
            rename_keys.append((F"""blocks.{i}.norm1.bias""", F"""vit.encoder.layer.{i}.layernorm_before.bias""") )
            rename_keys.append((F"""blocks.{i}.attn.proj.weight""", F"""vit.encoder.layer.{i}.attention.output.dense.weight""") )
            rename_keys.append((F"""blocks.{i}.attn.proj.bias""", F"""vit.encoder.layer.{i}.attention.output.dense.bias""") )
            rename_keys.append((F"""blocks.{i}.norm2.weight""", F"""vit.encoder.layer.{i}.layernorm_after.weight""") )
            rename_keys.append((F"""blocks.{i}.norm2.bias""", F"""vit.encoder.layer.{i}.layernorm_after.bias""") )
            rename_keys.append((F"""blocks.{i}.mlp.fc1.weight""", F"""vit.encoder.layer.{i}.intermediate.dense.weight""") )
            rename_keys.append((F"""blocks.{i}.mlp.fc1.bias""", F"""vit.encoder.layer.{i}.intermediate.dense.bias""") )
            rename_keys.append((F"""blocks.{i}.mlp.fc2.weight""", F"""vit.encoder.layer.{i}.output.dense.weight""") )
            rename_keys.append((F"""blocks.{i}.mlp.fc2.bias""", F"""vit.encoder.layer.{i}.output.dense.bias""") )

      # projection layer + position embeddings
      rename_keys.extend(
          [
              ('''cls_token''', '''vit.embeddings.cls_token'''),
              ('''patch_embed.proj.weight''', '''vit.embeddings.patch_embeddings.projection.weight'''),
              ('''patch_embed.proj.bias''', '''vit.embeddings.patch_embeddings.projection.bias'''),
              ('''pos_embed''', '''vit.embeddings.position_embeddings'''),
          ] )

      if base_model:
            # layernorm + pooler
            rename_keys.extend(
                [
                    ('''norm.weight''', '''layernorm.weight'''),
                    ('''norm.bias''', '''layernorm.bias'''),
                ] )

            # if just the base model, we should remove "vit" from all keys that start with "vit"
            __A          =				[(pair[0], pair[1][4:]) if pair[1].startswith('''vit''' ) else pair for pair in rename_keys]
      else:
            # layernorm + classification head
            rename_keys.extend(
                [
                    ('''norm.weight''', '''vit.layernorm.weight'''),
                    ('''norm.bias''', '''vit.layernorm.bias'''),
                    ('''head.weight''', '''classifier.weight'''),
                    ('''head.bias''', '''classifier.bias'''),
                ] )

      return rename_keys



def _a				(	lowerCamelCase:   Dict					,				lowerCamelCase:   str					,				lowerCamelCase:   List[str]=False )	->						Tuple:







      '''simple docstring'''






      for i in range(config.num_hidden_layers ):
            if base_model:
                  __A          =				""""""
            else:
                  __A          =				"""vit."""
            # read in weights + bias of input projection layer (in timm, this is a single matrix + bias)
            __A          =				state_dict.pop(F"""blocks.{i}.attn.qkv.weight""" )
            __A          =				state_dict.pop(F"""blocks.{i}.attn.qkv.bias""" )
            # next, add query, keys and values (in that order) to the state dict
            __A          =				in_proj_weight[
                : config.hidden_size, :
            ]
            __A          =				in_proj_bias[: config.hidden_size]
            __A          =				in_proj_weight[
                config.hidden_size : config.hidden_size * 2, :
            ]
            __A          =				in_proj_bias[
                config.hidden_size : config.hidden_size * 2
            ]
            __A          =				in_proj_weight[
                -config.hidden_size :, :
            ]
            __A          =				in_proj_bias[-config.hidden_size :]



def _a				(	lowerCamelCase:   int )	->						str:







      '''simple docstring'''






      __A          =				["""head.weight""", """head.bias"""]
      for k in ignore_keys:
            state_dict.pop(snake_case_					,				snake_case_ )



def _a				(	lowerCamelCase:   int					,				lowerCamelCase:   Optional[Any]					,				lowerCamelCase:   Optional[int] )	->						List[Any]:







      '''simple docstring'''






      __A          =				dct.pop(snake_case_ )
      __A          =				val



def _a				(	)	->						Tuple:







      '''simple docstring'''






      __A          =				"""http://images.cocodataset.org/val2017/000000039769.jpg"""
      __A          =				Image.open(requests.get(snake_case_					,				stream=snake_case_ ).raw )
      return im



@torch.no_grad()
def _a				(	lowerCamelCase:   Tuple					,				lowerCamelCase:   Any					,				lowerCamelCase:   List[str]=True )	->						Dict:







      '''simple docstring'''






      __A          =				ViTConfig()
      # patch_size
      if model_name[-1] == "8":
            __A          =				8
      # set labels if required
      if not base_model:
            __A          =				10_00
            __A          =				"""huggingface/label-files"""
            __A          =				"""imagenet-1k-id2label.json"""
            __A          =				json.load(open(hf_hub_download(snake_case_					,				snake_case_					,				repo_type='''dataset''' )					,				'''r''' ) )
            __A          =				{int(snake_case_ ): v for k, v in idalabel.items()}
            __A          =				idalabel
            __A          =				{v: k for k, v in idalabel.items()}
      # size of the architecture
      if model_name in ["dino_vits8", "dino_vits16"]:
            __A          =				3_84
            __A          =				15_36
            __A          =				12
            __A          =				6

      # load original model from torch hub
      __A          =				torch.hub.load('''facebookresearch/dino:main'''					,				snake_case_ )
      original_model.eval()

      # load state_dict of original model, remove and rename some keys
      __A          =				original_model.state_dict()
      if base_model:
            remove_classification_head_(snake_case_ )
      __A          =				create_rename_keys(snake_case_					,				base_model=snake_case_ )
      for src, dest in rename_keys:
            rename_key(snake_case_					,				snake_case_					,				snake_case_ )
      read_in_q_k_v(snake_case_					,				snake_case_					,				snake_case_ )

      # load HuggingFace model
      if base_model:
            __A          =				ViTModel(snake_case_					,				add_pooling_layer=snake_case_ ).eval()
      else:
            __A          =				ViTForImageClassification(snake_case_ ).eval()
      model.load_state_dict(snake_case_ )

      # Check outputs on an image, prepared by ViTImageProcessor
      __A          =				ViTImageProcessor()
      __A          =				image_processor(images=prepare_img()					,				return_tensors='''pt''' )
      __A          =				encoding["""pixel_values"""]
      __A          =				model(snake_case_ )

      if base_model:
            __A          =				original_model(snake_case_ )
            assert torch.allclose(snake_case_					,				outputs.last_hidden_state[:, 0, :]					,				atol=1e-1 )
      else:
            __A          =				original_model(snake_case_ )
            assert logits.shape == outputs.logits.shape
            assert torch.allclose(snake_case_					,				outputs.logits					,				atol=1e-3 )

      Path(snake_case_ ).mkdir(exist_ok=snake_case_ )
      print(F"""Saving model {model_name} to {pytorch_dump_folder_path}""" )
      model.save_pretrained(snake_case_ )
      print(F"""Saving image processor to {pytorch_dump_folder_path}""" )
      image_processor.save_pretrained(snake_case_ )


if __name__ == "__main__":
       snake_case__					:							int													=     argparse.ArgumentParser()
       # Required parameters
       parser.add_argument(
           '--model_name',
           default='dino_vitb16',
           type=str,
           help='Name of the model trained with DINO you\'d like to convert.',
       )
       parser.add_argument(
           '--pytorch_dump_folder_path', default=None, type=str, help='Path to the output PyTorch model directory.'
       )
       parser.add_argument(
           '--base_model',
           action='store_true',
           help='Whether to only convert the base model (no projection head weights).',
       )

       parser.set_defaults(base_model=True)
       snake_case__					:							int													=     parser.parse_args()
       convert_vit_checkpoint(args.model_name, args.pytorch_dump_folder_path, args.base_model)











def 				lowerCAmelCase_	(     snake_case_     ):
      if number < 0:
            raise ValueError("""number must not be negative"""     )
      return number & (number - 1) == 0


if __name__ == "__main__":
  import doctest

  doctest.testmod()

