






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()
lowercase    				=   logging.get_logger(__name__)





def 		__UpperCAmelCase     (	a_				,	a_=False):
							snake_case_           =				[]
							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"
														snake_case_           =				[(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 		__UpperCAmelCase     (	a_				,	a_				,	a_=False):
							for i in range(config.num_hidden_layers):
														if base_model:
																					snake_case_           =				''
														else:
																					snake_case_           =				'vit.'
														# read in weights + bias of input projection layer (in timm, this is a single matrix + bias)
														snake_case_           =				state_dict.pop(f'''blocks.{i}.attn.qkv.weight''')
														snake_case_           =				state_dict.pop(f'''blocks.{i}.attn.qkv.bias''')
														# next, add query, keys and values (in that order) to the state dict
														snake_case_           =				in_proj_weight[
														    : config.hidden_size, :
														]
														snake_case_           =				in_proj_bias[: config.hidden_size]
														snake_case_           =				in_proj_weight[
														    config.hidden_size : config.hidden_size * 2, :
														]
														snake_case_           =				in_proj_bias[
														    config.hidden_size : config.hidden_size * 2
														]
														snake_case_           =				in_proj_weight[
														    -config.hidden_size :, :
														]
														snake_case_           =				in_proj_bias[-config.hidden_size :]





def 		__UpperCAmelCase     (	a_):
							snake_case_           =				['head.weight', 'head.bias']
							for k in ignore_keys:
														state_dict.pop(a_				,	a_)





def 		__UpperCAmelCase     (	a_				,	a_				,	a_):
							snake_case_           =				dct.pop(a_)
							snake_case_           =				val





def 		__UpperCAmelCase     (	):
							snake_case_           =				'http://images.cocodataset.org/val2017/000000039769.jpg'
							snake_case_           =				Image.open(requests.get(a_				,	stream=a_).raw)
							return im





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

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

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

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

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

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

							Path(a_).mkdir(exist_ok=a_)
							print(f'''Saving model {model_name} to {pytorch_dump_folder_path}''')
							model.save_pretrained(a_)
							print(f'''Saving image processor to {pytorch_dump_folder_path}''')
							image_processor.save_pretrained(a_)


if __name__ == "__main__":
	lowercase    				=   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)
	lowercase    				=   parser.parse_args()
	convert_vit_checkpoint(args.model_name, args.pytorch_dump_folder_path, args.base_model)













from __future__ import annotations

from collections.abc import Callable
from typing import Generic, TypeVar

lowercase    				=   TypeVar("T")
lowercase    				=   TypeVar("U")




class 					UpperCamelCase_ (     Generic[T, U]							):



	'''simple docstring'''




	def __init__(			self			,     a			,     a   )			->       List[Any]:
								snake_case_           =				key
								snake_case_           =				val
								snake_case_           =				None
								snake_case_           =				None






	def __repr__(			self   )			->       str:
								return (
								    F'''Node: key: {self.key}, val: {self.val}, '''
								    F'''has next: {bool(self.next   )}, has prev: {bool(self.prev   )}'''
								)






class 					UpperCamelCase_ (     Generic[T, U]							):



	'''simple docstring'''




	def __init__(			self   )			->       None:
								snake_case_           =				DoubleLinkedListNode(a			,     a   )
								snake_case_           =				DoubleLinkedListNode(a			,     a   )
								snake_case_     ,						snake_case_           =				self.rear, self.head




	def __repr__(			self   )			->       str:
								snake_case_           =				['DoubleLinkedList']
								snake_case_           =				self.head
								while node.next is not None:
															rep.append(str(a   )   )
															snake_case_           =				node.next
								rep.append(str(self.rear   )   )
								return ",\n    ".join(a   )




	def 				_UpperCamelCase     (			self			,     a   )			->       None:
								snake_case_           =				self.rear.prev

								# All nodes other than self.head are guaranteed to have non-None previous
								assert previous is not None

								snake_case_           =				node
								snake_case_           =				previous
								snake_case_           =				node
								snake_case_           =				self.rear






	def 				_UpperCamelCase     (			self			,     a   )			->       DoubleLinkedListNode[T, U] | None:

								if node.prev is None or node.next is None:
															return None

								snake_case_           =				node.next
								snake_case_           =				node.prev
								snake_case_           =				None
								snake_case_           =				None
								return node






class 					UpperCamelCase_ (     Generic[T, U]							):



	'''simple docstring'''




	lowerCAmelCase						=					{}




	def __init__(			self			,     a   )			->       str:
								snake_case_           =				DoubleLinkedList()
								snake_case_           =				capacity
								snake_case_           =				0
								snake_case_           =				0
								snake_case_           =				0
								snake_case_           =				{}




	def __repr__(			self   )			->       str:
								return (
								    F'''CacheInfo(hits={self.hits}, misses={self.miss}, '''
								    F'''capacity={self.capacity}, current size={self.num_keys})'''
								)




	def __contains__(			self			,     a   )			->       bool:
								return key in self.cache




	def 				_UpperCamelCase     (			self			,     a   )			->       U | None:
								# Note: pythonic interface would throw KeyError rather than return None

								if key in self.cache:
															self.hits += 1
															snake_case_           =				self.cache[key]
															snake_case_           =				self.list.remove(self.cache[key]   )
															assert node == value_node

															# node is guaranteed not None because it is in self.cache
															assert node is not None
															self.list.add(a   )
															return node.val
								self.miss += 1
								return None




	def 				_UpperCamelCase     (			self			,     a			,     a   )			->       None:

								if key not in self.cache:
															if self.num_keys >= self.capacity:
																						# delete first node (oldest) when over capacity
																						snake_case_           =				self.list.head.next

																						# guaranteed to have a non-None first node when num_keys > 0
																						# explain to type checker via assertions
																						assert first_node is not None
																						assert first_node.key is not None
																						assert (
																						    self.list.remove(a   ) is not None
																						)  # node guaranteed to be in list assert node.key is not None

																						del self.cache[first_node.key]
																						self.num_keys -= 1
															snake_case_           =				DoubleLinkedListNode(a			,     a   )
															self.list.add(self.cache[key]   )
															self.num_keys += 1

								else:
															# bump node to the end of the list, update value
															snake_case_           =				self.list.remove(self.cache[key]   )
															assert node is not None  # node guaranteed to be in list
															snake_case_           =				value
															self.list.add(a   )






	@classmethod
	def 				_UpperCamelCase     (			cls			,     a = 1_28   )			->       Callable[[Callable[[T], U]], Callable[..., U]]:

								def cache_decorator_inner(a   ) -> Callable[..., U]:
															def cache_decorator_wrapper(*a   ) -> U:
																						if func not in cls.decorator_function_to_instance_map:
																													snake_case_           =				LRUCache(a   )

																						snake_case_           =				cls.decorator_function_to_instance_map[func].get(args[0]   )
																						if result is None:
																													snake_case_           =				func(*a   )
																													cls.decorator_function_to_instance_map[func].put(args[0]			,     a   )
																						return result

															def cache_info() -> LRUCache[T, U]:
																						return cls.decorator_function_to_instance_map[func]

															setattr(a			,     'cache_info'			,     a   )  # noqa: B010

															return cache_decorator_wrapper

								return cache_decorator_inner


if __name__ == "__main__":
	import doctest

	doctest.testmod()





