





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 ConvNextConfig, ConvNextForImageClassification, ConvNextImageProcessor
from transformers.utils import logging


logging.set_verbosity_info()
SCREAMING_SNAKE_CASE_      :			str		  =      logging.get_logger(__name__)



def    SCREAMING_SNAKE_CASE							(			snake_case       )		->						List[str]:
		__lowercase					=    ConvNextConfig()

		if "tiny" in checkpoint_url:
				__lowercase					=    [3, 3, 9, 3]
				__lowercase					=    [96, 192, 384, 768]
		if "small" in checkpoint_url:
				__lowercase					=    [3, 3, 27, 3]
				__lowercase					=    [96, 192, 384, 768]
		if "base" in checkpoint_url:
				__lowercase					=    [3, 3, 27, 3]
				__lowercase					=    [128, 256, 512, 1_024]
		if "large" in checkpoint_url:
				__lowercase					=    [3, 3, 27, 3]
				__lowercase					=    [192, 384, 768, 1_536]
		if "xlarge" in checkpoint_url:
				__lowercase					=    [3, 3, 27, 3]
				__lowercase					=    [256, 512, 1_024, 2_048]

		if "1k" in checkpoint_url:
				__lowercase					=    1_000
				__lowercase					=    'imagenet-1k-id2label.json'
				__lowercase					=    (1, 1_000)
		else:
				__lowercase					=    21_841
				__lowercase					=    'imagenet-22k-id2label.json'
				__lowercase					=    (1, 21_841)

		__lowercase					=    'huggingface/label-files'
		__lowercase					=    num_labels
		__lowercase					=    json.load(open(hf_hub_download(snake_case	,      snake_case	,      repo_type='dataset'       )	,      'r'       )       )
		__lowercase					=    {int(snake_case       ): v for k, v in idalabel.items()}
		if "1k" not in checkpoint_url:
				# this dataset contains 21843 labels but the model only has 21841
				# we delete the classes as mentioned in https://github.com/google-research/big_transfer/issues/18
				del idalabel[9_205]
				del idalabel[15_027]
		__lowercase					=    idalabel
		__lowercase					=    {v: k for k, v in idalabel.items()}
		__lowercase					=    hidden_sizes
		__lowercase					=    depths

		return config, expected_shape



def    SCREAMING_SNAKE_CASE							(			snake_case       )		->						Any:
		if "downsample_layers.0.0" in name:
				__lowercase					=    name.replace('downsample_layers.0.0'	,      'embeddings.patch_embeddings'       )
		if "downsample_layers.0.1" in name:
				__lowercase					=    name.replace('downsample_layers.0.1'	,      'embeddings.norm'       )  # we rename to layernorm later on
		if "downsample_layers.1.0" in name:
				__lowercase					=    name.replace('downsample_layers.1.0'	,      'stages.1.downsampling_layer.0'       )
		if "downsample_layers.1.1" in name:
				__lowercase					=    name.replace('downsample_layers.1.1'	,      'stages.1.downsampling_layer.1'       )
		if "downsample_layers.2.0" in name:
				__lowercase					=    name.replace('downsample_layers.2.0'	,      'stages.2.downsampling_layer.0'       )
		if "downsample_layers.2.1" in name:
				__lowercase					=    name.replace('downsample_layers.2.1'	,      'stages.2.downsampling_layer.1'       )
		if "downsample_layers.3.0" in name:
				__lowercase					=    name.replace('downsample_layers.3.0'	,      'stages.3.downsampling_layer.0'       )
		if "downsample_layers.3.1" in name:
				__lowercase					=    name.replace('downsample_layers.3.1'	,      'stages.3.downsampling_layer.1'       )
		if "stages" in name and "downsampling_layer" not in name:
				# stages.0.0. for instance should be renamed to stages.0.layers.0.
				__lowercase					=    name[: len('stages.0'       )] + '.layers' + name[len('stages.0'       ) :]
		if "stages" in name:
				__lowercase					=    name.replace('stages'	,      'encoder.stages'       )
		if "norm" in name:
				__lowercase					=    name.replace('norm'	,      'layernorm'       )
		if "gamma" in name:
				__lowercase					=    name.replace('gamma'	,      'layer_scale_parameter'       )
		if "head" in name:
				__lowercase					=    name.replace('head'	,      'classifier'       )

		return name



def    SCREAMING_SNAKE_CASE							(			)		->						List[str]:
		__lowercase					=    'http://images.cocodataset.org/val2017/000000039769.jpg'
		__lowercase					=    Image.open(requests.get(snake_case	,      stream=snake_case       ).raw       )
		return im



@torch.no_grad()
def    SCREAMING_SNAKE_CASE							(			snake_case	,      snake_case       )		->						Union[str, Any]:
		__lowercase	,			__lowercase					=    get_convnext_config(snake_case       )
		# load original state_dict from URL
		__lowercase					=    torch.hub.load_state_dict_from_url(snake_case       )['model']
		# rename keys
		for key in state_dict.copy().keys():
				__lowercase					=    state_dict.pop(snake_case       )
				__lowercase					=    val
		# add prefix to all keys expect classifier head
		for key in state_dict.copy().keys():
				__lowercase					=    state_dict.pop(snake_case       )
				if not key.startswith('classifier'       ):
						__lowercase					=    'convnext.' + key
				__lowercase					=    val

		# load HuggingFace model
		__lowercase					=    ConvNextForImageClassification(snake_case       )
		model.load_state_dict(snake_case       )
		model.eval()

		# Check outputs on an image, prepared by ConvNextImageProcessor
		__lowercase					=    224 if '224' in checkpoint_url else 384
		__lowercase					=    ConvNextImageProcessor(size=snake_case       )
		__lowercase					=    image_processor(images=prepare_img()	,      return_tensors='pt'       ).pixel_values

		__lowercase					=    model(snake_case       ).logits

		# note: the logits below were obtained without center cropping
		if checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_tiny_1k_224_ema.pth":
				__lowercase					=    torch.tensor([-0.1210, -0.6605, 0.1918]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_small_1k_224_ema.pth":
				__lowercase					=    torch.tensor([-0.4473, -0.1847, -0.6365]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_base_1k_224_ema.pth":
				__lowercase					=    torch.tensor([0.4525, 0.7539, 0.0308]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_base_1k_384.pth":
				__lowercase					=    torch.tensor([0.3561, 0.6350, -0.0384]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_large_1k_224_ema.pth":
				__lowercase					=    torch.tensor([0.4174, -0.0989, 0.1489]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_large_1k_384.pth":
				__lowercase					=    torch.tensor([0.2513, -0.1349, -0.1613]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_base_22k_224.pth":
				__lowercase					=    torch.tensor([1.2980, 0.3631, -0.1198]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_large_22k_224.pth":
				__lowercase					=    torch.tensor([1.2963, 0.1227, 0.1723]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_xlarge_22k_224.pth":
				__lowercase					=    torch.tensor([1.7956, 0.8390, 0.2820]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_base_22k_1k_224.pth":
				__lowercase					=    torch.tensor([-0.2822, -0.0502, -0.0878]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_base_22k_1k_384.pth":
				__lowercase					=    torch.tensor([-0.5672, -0.0730, -0.4348]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_large_22k_1k_224.pth":
				__lowercase					=    torch.tensor([0.2681, 0.2365, 0.6246]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_large_22k_1k_384.pth":
				__lowercase					=    torch.tensor([-0.2642, 0.3931, 0.5116]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_xlarge_22k_1k_224_ema.pth":
				__lowercase					=    torch.tensor([-0.6677, -0.1873, -0.8379]       )
		elif checkpoint_url == "https://dl.fbaipublicfiles.com/convnext/convnext_xlarge_22k_1k_384_ema.pth":
				__lowercase					=    torch.tensor([-0.7749, -0.2967, -0.6444]       )
		else:
				raise ValueError(F"Unknown URL: {checkpoint_url}"       )

		assert torch.allclose(logits[0, :3]	,      snake_case	,      atol=1E-3       )
		assert logits.shape == expected_shape

		Path(snake_case       ).mkdir(exist_ok=snake_case       )
		print(F"Saving model 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       )

		print('Pushing model to the hub...'       )
		__lowercase					=    'convnext'
		if "tiny" in checkpoint_url:
				model_name += "-tiny"
		elif "small" in checkpoint_url:
				model_name += "-small"
		elif "base" in checkpoint_url:
				model_name += "-base"
		elif "xlarge" in checkpoint_url:
				model_name += "-xlarge"
		elif "large" in checkpoint_url:
				model_name += "-large"
		if "224" in checkpoint_url:
				model_name += "-224"
		elif "384" in checkpoint_url:
				model_name += "-384"
		if "22k" in checkpoint_url and "1k" not in checkpoint_url:
				model_name += "-22k"
		if "22k" in checkpoint_url and "1k" in checkpoint_url:
				model_name += "-22k-1k"

		model.push_to_hub(
		    repo_path_or_name=Path(snake_case	,      snake_case       )	,      organization='nielsr'	,      commit_message='Add model'	,      )


if __name__ == "__main__":
		SCREAMING_SNAKE_CASE_      :			Dict		  =      argparse.ArgumentParser()
		# Required parameters
		parser.add_argument(
		    '''--checkpoint_url''',
		    default='''https://dl.fbaipublicfiles.com/convnext/convnext_tiny_1k_224_ema.pth''',
		    type=str,
		    help='''URL of the original ConvNeXT checkpoint you\'d like to convert.''',
		)
		parser.add_argument(
		    '''--pytorch_dump_folder_path''',
		    default=None,
		    type=str,
		    required=True,
		    help='''Path to the output PyTorch model directory.''',
		)

		SCREAMING_SNAKE_CASE_      :			Optional[Any]		  =      parser.parse_args()
		convert_convnext_checkpoint(args.checkpoint_url, args.pytorch_dump_folder_path)











def    SCREAMING_SNAKE_CASE							(			snake_case       )		->						int:
		__lowercase					=    str(snake_case       ).strip()
		if not bin_string:
				raise ValueError('Empty string was passed to the function'       )
		__lowercase					=    bin_string[0] == '-'
		if is_negative:
				__lowercase					=    bin_string[1:]
		if not all(char in '01' for char in bin_string       ):
				raise ValueError('Non-binary value was passed to the function'       )
		__lowercase					=    0
		for char in bin_string:
				__lowercase					=    2 * decimal_number + int(snake_case       )
		return -decimal_number if is_negative else decimal_number


if __name__ == "__main__":
		from doctest import testmod

		testmod()




