
import argparse
import collections

import jax
import jax.numpy as jnp
import torch
import torch.nn as nn
from clip.model import CLIP
from flax.training import checkpoints
from huggingface_hub import Repository

from transformers import (
    CLIPTokenizer,
    OwlViTConfig,
    OwlViTForObjectDetection,
    OwlViTImageProcessor,
    OwlViTModel,
    OwlViTProcessor,
)


SCREAMING_SNAKE_CASE   :		Optional[Any]					 =       {
    "vit_b32": {
        "embed_dim": 512,
        "image_resolution": 768,
        "context_length": 16,
        "vocab_size": 4_9408,
        "vision_layers": 12,
        "vision_width": 768,
        "vision_patch_size": 32,
        "transformer_width": 512,
        "transformer_heads": 8,
        "transformer_layers": 12,
    },
    "vit_b16": {
        "embed_dim": 512,
        "image_resolution": 768,
        "context_length": 16,
        "vocab_size": 4_9408,
        "vision_layers": 12,
        "vision_width": 768,
        "vision_patch_size": 16,
        "transformer_width": 512,
        "transformer_heads": 8,
        "transformer_layers": 12,
    },
    "vit_l14": {
        "embed_dim": 768,
        "image_resolution": 840,
        "context_length": 16,
        "vocab_size": 4_9408,
        "vision_layers": 24,
        "vision_width": 1024,
        "vision_patch_size": 14,
        "transformer_width": 768,
        "transformer_heads": 12,
        "transformer_layers": 12,
    },
}



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase="" ,						__UpperCamelCase="/"     ):
				A_       	=  []

				for k, v in params.items():
								A_       	=  parent_key + sep + k if parent_key else k

								if isinstance(__UpperCamelCase ,						collections.MutableMapping     ):
												items.extend(flatten_nested_dict(__UpperCamelCase ,						__UpperCamelCase ,						sep=__UpperCamelCase     ).items()     )
								else:
												items.append((new_key, v)     )
				return dict(__UpperCamelCase     )



def        lowerCamelCase_  (   __UpperCamelCase     ):
				return jax.tree_util.tree_map(lambda __UpperCamelCase     : x.astype(jnp.floataa     ) if x.dtype == jnp.bfloataa else x ,						__UpperCamelCase     )



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase     ):
				A_	,					A_	,					A_       	=  pt_attn_layer.in_proj_weight.chunk(3 ,						dim=0     )
				A_	,					A_	,					A_       	=  pt_attn_layer.in_proj_bias.chunk(3 ,						dim=0     )

				A_       	=  pt_attn_layer.out_proj.weight
				A_       	=  pt_attn_layer.out_proj.bias

				A_       	=  q_proj
				A_       	=  q_proj_bias

				A_       	=  k_proj
				A_       	=  k_proj_bias

				A_       	=  v_proj
				A_       	=  v_proj_bias

				A_       	=  out_proj_weights
				A_       	=  out_proj_bias



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase     ):
				copy_linear(hf_mlp.fca ,						pt_mlp.c_fc     )
				copy_linear(hf_mlp.fca ,						pt_mlp.c_proj     )



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase     ):
				A_       	=  pt_linear.weight
				A_       	=  pt_linear.bias



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase     ):
				# copy layer norms
				copy_linear(hf_layer.layer_norma ,						pt_layer.ln_a     )
				copy_linear(hf_layer.layer_norma ,						pt_layer.ln_a     )

				# copy MLP
				copy_mlp(hf_layer.mlp ,						pt_layer.mlp     )

				# copy attn
				copy_attn_layer(hf_layer.self_attn ,						pt_layer.attn     )



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase     ):
				for hf_layer, pt_layer in zip(__UpperCamelCase ,						__UpperCamelCase     ):
								copy_layer(__UpperCamelCase ,						__UpperCamelCase     )



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase     ):
				# copy  embeds
				A_       	=  pt_model.token_embedding.weight
				A_       	=  pt_model.positional_embedding

				# copy layer norm
				copy_linear(hf_encoder.final_layer_norm ,						pt_model.ln_final     )

				# copy hidden layers
				copy_layers(hf_encoder.encoder.layers ,						pt_model.transformer.resblocks     )



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase     ):
				# copy projection
				A_       	=  pt_model.text_projection.data.T

				# copy text encoder
				copy_encoder(hf_model.text_model ,						__UpperCamelCase     )



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase     ):
				# copy projection
				A_       	=  pt_model.visual.proj.data.T

				# copy layer norms
				copy_linear(hf_model.vision_model.pre_layernorm ,						pt_model.visual.ln_pre     )
				copy_linear(hf_model.vision_model.post_layernorm ,						pt_model.visual.ln_post     )

				# copy embeds
				A_       	=  pt_model.visual.conva.weight.data
				A_       	=  pt_model.visual.class_embedding
				A_       	=  pt_model.visual.positional_embedding.data

				# copy encoder
				copy_layers(hf_model.vision_model.encoder.layers ,						pt_model.visual.transformer.resblocks     )



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase     ):
				A_       	=  flatten_nested_dict(flax_params['''backbone''']['''merged_class_token''']     )

				A_       	=  torch.from_numpy(flax_class_token_params['''scale''']     )
				A_       	=  torch.from_numpy(flax_class_token_params['''bias''']     )
				A_       	=  nn.Parameter(__UpperCamelCase     )
				A_       	=  nn.Parameter(__UpperCamelCase     )



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase     ):
				A_       	=  hf_model.state_dict()
				A_       	=  {}

				# Rename class prediction head flax params to pytorch HF
				A_       	=  flatten_nested_dict(flax_params['''class_head''']     )

				for flax_key, v in flax_class_params.items():
								A_       	=  flax_key.replace('''/''' ,						'''.'''     )
								A_       	=  torch_key.replace('''.kernel''' ,						'''.weight'''     )
								A_       	=  torch_key.replace('''Dense_0''' ,						'''dense0'''     )
								A_       	=  '''class_head.''' + torch_key

								if "weight" in torch_key and v.ndim == 2:
												A_       	=  v.T

								A_       	=  nn.Parameter(torch.from_numpy(__UpperCamelCase     )     )

				# Rename box prediction box flax params to pytorch HF
				A_       	=  flatten_nested_dict(flax_params['''obj_box_head''']     )

				for flax_key, v in flax_box_params.items():
								A_       	=  flax_key.replace('''/''' ,						'''.'''     )
								A_       	=  torch_key.replace('''.kernel''' ,						'''.weight'''     )
								A_       	=  torch_key.replace('''_''' ,						''''''     ).lower()
								A_       	=  '''box_head.''' + torch_key

								if "weight" in torch_key and v.ndim == 2:
												A_       	=  v.T

								A_       	=  nn.Parameter(torch.from_numpy(__UpperCamelCase     )     )

				# Copy flax params to PyTorch params
				for name, param in new_params.items():
								if name in pt_params.keys():
												pt_params[name].copy_(__UpperCamelCase     )



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase     ):
				for k, v in flax_attn_params.items():
								if k.startswith('''transformer'''     ):
												A_       	=  k.replace('''transformer.resblocks''' ,						'''text_model.encoder.layers'''     )
								else:
												A_       	=  k.replace('''visual.transformer.resblocks''' ,						'''vision_model.encoder.layers'''     )

								A_       	=  torch_key.replace('''attn''' ,						'''self_attn'''     )
								A_       	=  torch_key.replace('''key''' ,						'''k_proj'''     )
								A_       	=  torch_key.replace('''value''' ,						'''v_proj'''     )
								A_       	=  torch_key.replace('''query''' ,						'''q_proj'''     )
								A_       	=  torch_key.replace('''out''' ,						'''out_proj'''     )

								if "bias" in torch_key and v.ndim == 2:
												A_       	=  v.shape[0] * v.shape[1]
												A_       	=  v.reshape(__UpperCamelCase     )

								if "weight" in torch_key and "out" in torch_key:
												A_       	=  (v.shape[0] * v.shape[1], v.shape[2])
												A_       	=  v.reshape(__UpperCamelCase     ).T

								if "weight" in torch_key and "out" not in torch_key:
												A_       	=  (v.shape[0], v.shape[1] * v.shape[2])
												A_       	=  v.reshape(__UpperCamelCase     ).T

								# Copy flax CLIP attn params to HF PyTorch params
								A_       	=  torch.from_numpy(__UpperCamelCase     )
								hf_backbone.state_dict()[torch_key].copy_(__UpperCamelCase     )



def        lowerCamelCase_  (   __UpperCamelCase     ):
				A_       	=  {}
				A_       	=  []

				for k, v in params.items():
								if "attn." in k:
												A_       	=  k[: k.rindex('''attn.'''     ) + 5]
												if base in processed_attn_layers:
																continue

												processed_attn_layers.append(__UpperCamelCase     )
												A_       	=  params[base + '''out.weight'''].shape[-1]
												A_       	=  params[base + '''out.weight'''].reshape(__UpperCamelCase ,						__UpperCamelCase     ).T
												A_       	=  params[base + '''out.bias''']
								else:
												A_       	=  v
				return new_params



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase     ):
				A_       	=  CLIP(**__UpperCamelCase     )
				torch_model.eval()
				A_       	=  torch_model.state_dict()

				A_       	=  flatten_nested_dict(flax_params['''backbone''']['''clip''']     )
				A_       	=  {}

				for flax_key, v in flax_clip_params.items():
								A_       	=  flax_key.replace('''/''' ,						'''.'''     )
								A_       	=  torch_key.replace('''text.token_embedding.embedding''' ,						'''token_embedding.kernel'''     )

								if (
								    torch_key.startswith('''text.transformer'''     )
								    or torch_key.startswith('''text.text_projection'''     )
								    or torch_key.startswith('''text.ln_final'''     )
								    or torch_key.startswith('''text.positional_embedding'''     )
								):
												A_       	=  torch_key[5:]

								A_       	=  torch_key.replace('''text_projection.kernel''' ,						'''text_projection'''     )
								A_       	=  torch_key.replace('''visual.proj.kernel''' ,						'''visual.proj'''     )
								A_       	=  torch_key.replace('''.scale''' ,						'''.weight'''     )
								A_       	=  torch_key.replace('''.kernel''' ,						'''.weight'''     )

								if "conv" in torch_key or "downsample.0.weight" in torch_key:
												A_       	=  v.transpose(3 ,						2 ,						0 ,						1     )

								elif "weight" in torch_key and v.ndim == 2 and "embedding" not in torch_key:
												# Fully connected layers are transposed, embeddings are not
												A_       	=  v.T

								A_       	=  v

				A_       	=  _convert_attn_layers(__UpperCamelCase     )
				new_torch_params.update(__UpperCamelCase     )
				A_       	=  {}

				# Copy flax CLIP backbone params to PyTorch params
				for name, param in new_torch_params.items():
								if name in torch_clip_params.keys():
												A_       	=  torch.from_numpy(new_torch_params[name]     )
												torch_clip_params[name].copy_(__UpperCamelCase     )
								else:
												A_       	=  param

				return torch_clip_params, torch_model, attn_params



@torch.no_grad()
def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase ,						__UpperCamelCase ,						__UpperCamelCase ,						__UpperCamelCase=None     ):
				A_       	=  Repository(__UpperCamelCase ,						clone_from=F"google/{pytorch_dump_folder_path}"     )
				repo.git_pull()

				if config_path is not None:
								A_       	=  OwlViTConfig.from_pretrained(__UpperCamelCase     )
				else:
								A_       	=  OwlViTConfig()

				A_       	=  OwlViTModel(__UpperCamelCase     ).eval()
				A_       	=  OwlViTForObjectDetection(__UpperCamelCase     ).eval()

				copy_text_model_and_projection(__UpperCamelCase ,						__UpperCamelCase     )
				copy_vision_model_and_projection(__UpperCamelCase ,						__UpperCamelCase     )
				A_       	=  pt_backbone.logit_scale
				copy_flax_attn_params(__UpperCamelCase ,						__UpperCamelCase     )

				A_       	=  hf_backbone
				copy_class_merge_token(__UpperCamelCase ,						__UpperCamelCase     )
				copy_class_box_heads(__UpperCamelCase ,						__UpperCamelCase     )

				# Save HF model
				hf_model.save_pretrained(repo.local_dir     )

				# Initialize image processor
				A_       	=  OwlViTImageProcessor(
				    size=config.vision_config.image_size ,						crop_size=config.vision_config.image_size     )
				# Initialize tokenizer
				A_       	=  CLIPTokenizer.from_pretrained('''openai/clip-vit-base-patch32''' ,						pad_token='''!''' ,						model_max_length=16     )

				# Initialize processor
				A_       	=  OwlViTProcessor(image_processor=__UpperCamelCase ,						tokenizer=__UpperCamelCase     )
				image_processor.save_pretrained(repo.local_dir     )
				processor.save_pretrained(repo.local_dir     )

				repo.git_add()
				repo.git_commit('''Upload model and processor'''     )
				repo.git_push()


if __name__ == "__main__":
						SCREAMING_SNAKE_CASE   :		int					 =       argparse.ArgumentParser()
						# Required parameters
						parser.add_argument(
						    "--owlvit_version",
						    default=None,
						    type=str,
						    required=True,
						    help="OWL-ViT model name [clip_b16, clip_b32, clip_l14].",
						)
						parser.add_argument(
						    "--owlvit_checkpoint", default=None, type=str, required=True, help="Path to flax model checkpoint."
						)
						parser.add_argument("--hf_config", default=None, type=str, required=True, help="Path to HF model config.")
						parser.add_argument(
						    "--pytorch_dump_folder_path", default="hf_model", type=str, help="Path to the output PyTorch model."
						)
						SCREAMING_SNAKE_CASE   :		Union[str, Any]					 =       parser.parse_args()

						# Initialize PyToch clip model
						SCREAMING_SNAKE_CASE   :		List[str]					 =       args.owlvit_version
						if model_name == "clip_b16":
												SCREAMING_SNAKE_CASE   :		int					 =       CONFIGS["vit_b16"]
						elif model_name == "clip_b32":
												SCREAMING_SNAKE_CASE   :		List[str]					 =       CONFIGS["vit_b32"]
						elif model_name == "clip_l14":
												SCREAMING_SNAKE_CASE   :		Any					 =       CONFIGS["vit_l14"]

						# Load from checkpoint and convert params to float-32
						SCREAMING_SNAKE_CASE   :		Any					 =       checkpoints.restore_checkpoint(args.owlvit_checkpoint, target=None)["optimizer"]["target"]
						SCREAMING_SNAKE_CASE   :		Optional[Any]					 =       jax.tree_util.tree_map(lambda x: x.astype(jnp.floataa) if x.dtype == jnp.bfloataa else x, variables)
						del variables

						# Convert CLIP backbone
						SCREAMING_SNAKE_CASE ,					SCREAMING_SNAKE_CASE ,					SCREAMING_SNAKE_CASE   :		List[str]					 =       convert_clip_backbone(flax_params, torch_config)

						convert_owlvit_checkpoint(clip_pt, flax_params, attn_params, args.pytorch_dump_folder_path, args.hf_config)

from collections import namedtuple

SCREAMING_SNAKE_CASE   :		Any					 =       namedtuple("from_to", "from_ to")

SCREAMING_SNAKE_CASE   :		str					 =       {
    "atm": from_to(1, 1),
    "pascal": from_to(0.0000098, 10_1325),
    "bar": from_to(0.986923, 1.01325),
    "kilopascal": from_to(0.00986923, 101.325),
    "megapascal": from_to(9.86923, 0.101325),
    "psi": from_to(0.068046, 14.6959),
    "inHg": from_to(0.0334211, 29.9213),
    "torr": from_to(0.00131579, 760),
}



def        lowerCamelCase_  (   __UpperCamelCase ,						__UpperCamelCase ,						__UpperCamelCase     ):
				if from_type not in PRESSURE_CONVERSION:
								raise ValueError(
								    F"Invalid 'from_type' value: {from_type!r}  Supported values are:\n"
								    + ''', '''.join(__UpperCamelCase     )     )
				if to_type not in PRESSURE_CONVERSION:
								raise ValueError(
								    F"Invalid 'to_type' value: {to_type!r}.  Supported values are:\n"
								    + ''', '''.join(__UpperCamelCase     )     )
				return (
				    value * PRESSURE_CONVERSION[from_type].from_ * PRESSURE_CONVERSION[to_type].to
				)


if __name__ == "__main__":
						import doctest

						doctest.testmod()