


import argparse
import json
import os

import numpy as np
import PIL
import requests
import tensorflow.keras.applications.efficientnet as efficientnet
import torch
from huggingface_hub import hf_hub_download
from PIL import Image
from tensorflow.keras.preprocessing import image

from transformers import (
    EfficientNetConfig,
    EfficientNetForImageClassification,
    EfficientNetImageProcessor,
)
from transformers.utils import logging


logging.set_verbosity_info()
__lowerCAmelCase		       =							logging.get_logger(__name__)

__lowerCAmelCase		       =							{
    '''b0''': efficientnet.EfficientNetBa,
    '''b1''': efficientnet.EfficientNetBa,
    '''b2''': efficientnet.EfficientNetBa,
    '''b3''': efficientnet.EfficientNetBa,
    '''b4''': efficientnet.EfficientNetBa,
    '''b5''': efficientnet.EfficientNetBa,
    '''b6''': efficientnet.EfficientNetBa,
    '''b7''': efficientnet.EfficientNetBa,
}

__lowerCAmelCase		       =							{
    '''b0''': {
        '''hidden_dim''': 12_80,
        '''width_coef''': 1.0,
        '''depth_coef''': 1.0,
        '''image_size''': 2_24,
        '''dropout_rate''': 0.2,
        '''dw_padding''': [],
    },
    '''b1''': {
        '''hidden_dim''': 12_80,
        '''width_coef''': 1.0,
        '''depth_coef''': 1.1,
        '''image_size''': 2_40,
        '''dropout_rate''': 0.2,
        '''dw_padding''': [16],
    },
    '''b2''': {
        '''hidden_dim''': 14_08,
        '''width_coef''': 1.1,
        '''depth_coef''': 1.2,
        '''image_size''': 2_60,
        '''dropout_rate''': 0.3,
        '''dw_padding''': [5, 8, 16],
    },
    '''b3''': {
        '''hidden_dim''': 15_36,
        '''width_coef''': 1.2,
        '''depth_coef''': 1.4,
        '''image_size''': 3_00,
        '''dropout_rate''': 0.3,
        '''dw_padding''': [5, 18],
    },
    '''b4''': {
        '''hidden_dim''': 17_92,
        '''width_coef''': 1.4,
        '''depth_coef''': 1.8,
        '''image_size''': 3_80,
        '''dropout_rate''': 0.4,
        '''dw_padding''': [6],
    },
    '''b5''': {
        '''hidden_dim''': 20_48,
        '''width_coef''': 1.6,
        '''depth_coef''': 2.2,
        '''image_size''': 4_56,
        '''dropout_rate''': 0.4,
        '''dw_padding''': [13, 27],
    },
    '''b6''': {
        '''hidden_dim''': 23_04,
        '''width_coef''': 1.8,
        '''depth_coef''': 2.6,
        '''image_size''': 5_28,
        '''dropout_rate''': 0.5,
        '''dw_padding''': [31],
    },
    '''b7''': {
        '''hidden_dim''': 25_60,
        '''width_coef''': 2.0,
        '''depth_coef''': 3.1,
        '''image_size''': 6_00,
        '''dropout_rate''': 0.5,
        '''dw_padding''': [18],
    },
}




def    snake_case_     (  snake_case     )  ->				Tuple:
       lowercase__:   Any  			=   EfficientNetConfig()
       lowercase__:   Union[str, Any]  			=   CONFIG_MAP[model_name]['hidden_dim']
       lowercase__:   Tuple  			=   CONFIG_MAP[model_name]['width_coef']
       lowercase__:   int  			=   CONFIG_MAP[model_name]['depth_coef']
       lowercase__:   Tuple  			=   CONFIG_MAP[model_name]['image_size']
       lowercase__:   Tuple  			=   CONFIG_MAP[model_name]['dropout_rate']
       lowercase__:   Optional[Any]  			=   CONFIG_MAP[model_name]['dw_padding']

       lowercase__:   str  			=   'huggingface/label-files'
       lowercase__:   List[Any]  			=   'imagenet-1k-id2label.json'
       lowercase__:   Optional[Any]  			=   10_00
       lowercase__:   Tuple  			=   json.load(open(hf_hub_download(snake_case			,							snake_case			,							repo_type='dataset'     )			,							'r'     )     )
       lowercase__:   str  			=   {int(snake_case     ): v for k, v in idalabel.items()}

       lowercase__:   List[Any]  			=   idalabel
       lowercase__:   int  			=   {v: k for k, v in idalabel.items()}
       return config




def    snake_case_     (  )  ->				str:
       lowercase__:   int  			=   'http://images.cocodataset.org/val2017/000000039769.jpg'
       lowercase__:   Optional[Any]  			=   Image.open(requests.get(snake_case			,							stream=snake_case     ).raw     )
       return im




def    snake_case_     (  snake_case     )  ->				Dict:
       lowercase__:   Optional[int]  			=   CONFIG_MAP[model_name]['image_size']
       lowercase__:   List[Any]  			=   EfficientNetImageProcessor(
           size={'height': size, 'width': size}			,							image_mean=[0.4_8_5, 0.4_5_6, 0.4_0_6]			,							image_std=[0.4_7_8_5_3_9_4_4, 0.4_7_3_2_8_6_4, 0.4_7_4_3_4_1_6_3]			,							do_center_crop=snake_case			,							)
       return preprocessor




def    snake_case_     (  snake_case     )  ->				Any:
       lowercase__:   Tuple  			=   [v.split('_'     )[0].split('block'     )[1] for v in original_param_names if v.startswith('block'     )]
       lowercase__:   Optional[Any]  			=   sorted(set(snake_case     )     )
       lowercase__:   str  			=   len(snake_case     )
       lowercase__:   Tuple  			=   {b: str(snake_case     ) for b, i in zip(snake_case			,							range(snake_case     )     )}

       lowercase__:   Tuple  			=   []
       rename_keys.append(('stem_conv/kernel:0', 'embeddings.convolution.weight')     )
       rename_keys.append(('stem_bn/gamma:0', 'embeddings.batchnorm.weight')     )
       rename_keys.append(('stem_bn/beta:0', 'embeddings.batchnorm.bias')     )
       rename_keys.append(('stem_bn/moving_mean:0', 'embeddings.batchnorm.running_mean')     )
       rename_keys.append(('stem_bn/moving_variance:0', 'embeddings.batchnorm.running_var')     )

       for b in block_names:
              lowercase__:   Any  			=   block_name_mapping[b]
              rename_keys.append((f'block{b}_expand_conv/kernel:0', f'encoder.blocks.{hf_b}.expansion.expand_conv.weight')     )
              rename_keys.append((f'block{b}_expand_bn/gamma:0', f'encoder.blocks.{hf_b}.expansion.expand_bn.weight')     )
              rename_keys.append((f'block{b}_expand_bn/beta:0', f'encoder.blocks.{hf_b}.expansion.expand_bn.bias')     )
              rename_keys.append(
                  (f'block{b}_expand_bn/moving_mean:0', f'encoder.blocks.{hf_b}.expansion.expand_bn.running_mean')     )
              rename_keys.append(
                  (f'block{b}_expand_bn/moving_variance:0', f'encoder.blocks.{hf_b}.expansion.expand_bn.running_var')     )
              rename_keys.append(
                  (f'block{b}_dwconv/depthwise_kernel:0', f'encoder.blocks.{hf_b}.depthwise_conv.depthwise_conv.weight')     )
              rename_keys.append((f'block{b}_bn/gamma:0', f'encoder.blocks.{hf_b}.depthwise_conv.depthwise_norm.weight')     )
              rename_keys.append((f'block{b}_bn/beta:0', f'encoder.blocks.{hf_b}.depthwise_conv.depthwise_norm.bias')     )
              rename_keys.append(
                  (f'block{b}_bn/moving_mean:0', f'encoder.blocks.{hf_b}.depthwise_conv.depthwise_norm.running_mean')     )
              rename_keys.append(
                  (f'block{b}_bn/moving_variance:0', f'encoder.blocks.{hf_b}.depthwise_conv.depthwise_norm.running_var')     )

              rename_keys.append((f'block{b}_se_reduce/kernel:0', f'encoder.blocks.{hf_b}.squeeze_excite.reduce.weight')     )
              rename_keys.append((f'block{b}_se_reduce/bias:0', f'encoder.blocks.{hf_b}.squeeze_excite.reduce.bias')     )
              rename_keys.append((f'block{b}_se_expand/kernel:0', f'encoder.blocks.{hf_b}.squeeze_excite.expand.weight')     )
              rename_keys.append((f'block{b}_se_expand/bias:0', f'encoder.blocks.{hf_b}.squeeze_excite.expand.bias')     )
              rename_keys.append(
                  (f'block{b}_project_conv/kernel:0', f'encoder.blocks.{hf_b}.projection.project_conv.weight')     )
              rename_keys.append((f'block{b}_project_bn/gamma:0', f'encoder.blocks.{hf_b}.projection.project_bn.weight')     )
              rename_keys.append((f'block{b}_project_bn/beta:0', f'encoder.blocks.{hf_b}.projection.project_bn.bias')     )
              rename_keys.append(
                  (f'block{b}_project_bn/moving_mean:0', f'encoder.blocks.{hf_b}.projection.project_bn.running_mean')     )
              rename_keys.append(
                  (f'block{b}_project_bn/moving_variance:0', f'encoder.blocks.{hf_b}.projection.project_bn.running_var')     )

       rename_keys.append(('top_conv/kernel:0', 'encoder.top_conv.weight')     )
       rename_keys.append(('top_bn/gamma:0', 'encoder.top_bn.weight')     )
       rename_keys.append(('top_bn/beta:0', 'encoder.top_bn.bias')     )
       rename_keys.append(('top_bn/moving_mean:0', 'encoder.top_bn.running_mean')     )
       rename_keys.append(('top_bn/moving_variance:0', 'encoder.top_bn.running_var')     )

       lowercase__:   Union[str, Any]  			=   {}
       for item in rename_keys:
              if item[0] in original_param_names:
                     lowercase__:   Any  			=   'efficientnet.' + item[1]

       lowercase__:   Optional[int]  			=   'classifier.weight'
       lowercase__:   Union[str, Any]  			=   'classifier.bias'
       return key_mapping




def    snake_case_     (  snake_case			,							snake_case			,							snake_case     )  ->				Any:
       for key, value in tf_params.items():
              if "normalization" in key:
                     continue

              lowercase__:   Optional[int]  			=   key_mapping[key]
              if "_conv" in key and "kernel" in key:
                     lowercase__:   str  			=   torch.from_numpy(snake_case     ).permute(3			,							2			,							0			,							1     )
              elif "depthwise_kernel" in key:
                     lowercase__:   Any  			=   torch.from_numpy(snake_case     ).permute(2			,							3			,							0			,							1     )
              elif "kernel" in key:
                     lowercase__:   List[Any]  			=   torch.from_numpy(np.transpose(snake_case     )     )
              else:
                     lowercase__:   List[str]  			=   torch.from_numpy(snake_case     )

              # Replace HF parameters with original TF model parameters
              assert hf_params[hf_key].shape == new_hf_value.shape
              hf_params[hf_key].copy_(snake_case     )




@torch.no_grad()
def    snake_case_     (  snake_case			,							snake_case			,							snake_case			,							snake_case     )  ->				Optional[int]:
       lowercase__:   List[Any]  			=   model_classes[model_name](
           include_top=snake_case			,							weights='imagenet'			,							input_tensor=snake_case			,							input_shape=snake_case			,							pooling=snake_case			,							classes=10_00			,							classifier_activation='softmax'			,							)

       lowercase__:   Optional[int]  			=   original_model.trainable_variables
       lowercase__:   Dict  			=   original_model.non_trainable_variables
       lowercase__:   str  			=   {param.name: param.numpy() for param in tf_params}
       for param in tf_non_train_params:
              lowercase__:   Any  			=   param.numpy()
       lowercase__:   List[Any]  			=   list(tf_params.keys()     )

       # Load HuggingFace model
       lowercase__:   int  			=   get_efficientnet_config(snake_case     )
       lowercase__:   List[str]  			=   EfficientNetForImageClassification(snake_case     ).eval()
       lowercase__:   Optional[int]  			=   hf_model.state_dict()

       # Create src-to-dst parameter name mapping dictionary
       print('Converting parameters...'     )
       lowercase__:   Optional[int]  			=   rename_keys(snake_case     )
       replace_params(snake_case			,							snake_case			,							snake_case     )

       # Initialize preprocessor and preprocess input image
       lowercase__:   Any  			=   convert_image_processor(snake_case     )
       lowercase__:   Optional[Any]  			=   preprocessor(images=prepare_img()			,							return_tensors='pt'     )

       # HF model inference
       hf_model.eval()
       with torch.no_grad():
              lowercase__:   List[Any]  			=   hf_model(**snake_case     )
       lowercase__:   Optional[int]  			=   outputs.logits.detach().numpy()

       # Original model inference
       lowercase__:   Tuple  			=   False
       lowercase__:   str  			=   CONFIG_MAP[model_name]['image_size']
       lowercase__:   Optional[int]  			=   prepare_img().resize((image_size, image_size)			,							resample=PIL.Image.NEAREST     )
       lowercase__:   Union[str, Any]  			=   image.img_to_array(snake_case     )
       lowercase__:   Optional[int]  			=   np.expand_dims(snake_case			,							axis=0     )
       lowercase__:   Dict  			=   original_model.predict(snake_case     )

       # Check whether original and HF model outputs match  -> np.allclose
       assert np.allclose(snake_case			,							snake_case			,							atol=1e-3     ), "The predicted logits are not the same."
       print('Model outputs match!'     )

       if save_model:
              # Create folder to save model
              if not os.path.isdir(snake_case     ):
                     os.mkdir(snake_case     )
              # Save converted model and image processor
              hf_model.save_pretrained(snake_case     )
              preprocessor.save_pretrained(snake_case     )

       if push_to_hub:
              # Push model and image processor to hub
              print(f'Pushing converted {model_name} to the hub...'     )
              lowercase__:   Dict  			=   f'efficientnet-{model_name}'
              preprocessor.push_to_hub(snake_case     )
              hf_model.push_to_hub(snake_case     )


if __name__ == "__main__":
 __lowerCAmelCase		       =							argparse.ArgumentParser()
 # Required parameters
 parser.add_argument(
     '''--model_name''',
     default='''b0''',
     type=str,
     help='''Version name of the EfficientNet model you want to convert, select from [b0, b1, b2, b3, b4, b5, b6, b7].''',
 )
 parser.add_argument(
     '''--pytorch_dump_folder_path''',
     default='''hf_model''',
     type=str,
     help='''Path to the output PyTorch model directory.''',
 )
 parser.add_argument('''--save_model''', action='''store_true''', help='''Save model to local''')
 parser.add_argument('''--push_to_hub''', action='''store_true''', help='''Push model and image processor to the hub''')

 __lowerCAmelCase		       =							parser.parse_args()
 convert_efficientnet_checkpoint(args.model_name, args.pytorch_dump_folder_path, args.save_model, args.push_to_hub)






__lowerCAmelCase		       =							range(2, 20 + 1)
__lowerCAmelCase		       =							[10**k for k in range(ks[-1] + 1)]
__lowerCAmelCase		       =							{}




def    snake_case_     (  snake_case			,							snake_case			,							snake_case			,							snake_case     )  ->				Optional[int]:
       lowercase__:   str  			=   sum(a_i[j] for j in range(snake_case			,							len(snake_case     )     )     )
       lowercase__:   Optional[int]  			=   sum(a_i[j] * base[j] for j in range(min(len(snake_case     )			,							snake_case     )     )     )

       lowercase__			,						lowercase__:   str  			=   0, 0
       lowercase__:   Tuple  			=   n - i

       lowercase__:   Dict  			=   memo.get(snake_case     )

       if sub_memo is not None:
              lowercase__:   Optional[Any]  			=   sub_memo.get(snake_case     )

              if jumps is not None and len(snake_case     ) > 0:
                     # find and make the largest jump without going over
                     lowercase__:   int  			=   -1
                     for _k in range(len(snake_case     ) - 1			,							-1			,							-1     ):
                            if jumps[_k][2] <= k and jumps[_k][1] <= max_dn:
                                   lowercase__:   Union[str, Any]  			=   _k
                                   break

                     if max_jump >= 0:
                            lowercase__			,						lowercase__			,						lowercase__:   Any  			=   jumps[max_jump]
                            # since the difference between jumps is cached, add c
                            lowercase__:   str  			=   diff + c
                            for j in range(min(snake_case			,							len(snake_case     )     )     ):
                                   lowercase__			,						lowercase__:   Dict  			=   divmod(snake_case			,							10     )
                            if new_c > 0:
                                   add(snake_case			,							snake_case			,							snake_case     )

              else:
                     lowercase__:   List[Any]  			=   []
       else:
              lowercase__:   Optional[Any]  			=   {c: []}
              lowercase__:   Union[str, Any]  			=   sub_memo

       if dn >= max_dn or c + diff >= base[k]:
              return diff, dn

       if k > ks[0]:
              while True:
                     # keep doing smaller jumps
                     lowercase__			,						lowercase__:   Union[str, Any]  			=   next_term(snake_case			,							k - 1			,							i + dn			,							snake_case     )
                     diff += _diff
                     dn += terms_jumped

                     if dn >= max_dn or c + diff >= base[k]:
                            break
       else:
              # would be too small a jump, just compute sequential terms instead
              lowercase__			,						lowercase__:   Dict  			=   compute(snake_case			,							snake_case			,							i + dn			,							snake_case     )
              diff += _diff
              dn += terms_jumped

       lowercase__:   Any  			=   sub_memo[c]

       # keep jumps sorted by # of terms skipped
       lowercase__:   str  			=   0
       while j < len(snake_case     ):
              if jumps[j][1] > dn:
                     break
              j += 1

       # cache the jump for this value digitsum(b) and c
       sub_memo[c].insert(snake_case			,							(diff, dn, k)     )
       return (diff, dn)




def    snake_case_     (  snake_case			,							snake_case			,							snake_case			,							snake_case     )  ->				str:
       if i >= n:
              return 0, i
       if k > len(snake_case     ):
              a_i.extend([0 for _ in range(k - len(snake_case     )     )]     )

       # note: a_i -> b * 10^k + c
       # ds_b -> digitsum(b)
       # ds_c -> digitsum(c)
       lowercase__:   List[Any]  			=   i
       lowercase__			,						lowercase__			,						lowercase__:   Any  			=   0, 0, 0
       for j in range(len(snake_case     )     ):
              if j >= k:
                     ds_b += a_i[j]
              else:
                     ds_c += a_i[j]

       while i < n:
              i += 1
              lowercase__:   str  			=   ds_c + ds_b
              diff += addend
              lowercase__:   List[str]  			=   0
              for j in range(snake_case     ):
                     lowercase__:   Any  			=   a_i[j] + addend
                     lowercase__			,						lowercase__:   List[Any]  			=   divmod(snake_case			,							10     )

                     ds_c += a_i[j]

              if addend > 0:
                     break

       if addend > 0:
              add(snake_case			,							snake_case			,							snake_case     )
       return diff, i - start_i




def    snake_case_     (  snake_case			,							snake_case			,							snake_case     )  ->				int:
       for j in range(snake_case			,							len(snake_case     )     ):
              lowercase__:   str  			=   digits[j] + addend
              if s >= 10:
                     lowercase__			,						lowercase__:   Any  			=   divmod(snake_case			,							10     )
                     lowercase__:   Any  			=   addend // 10 + quotient
              else:
                     lowercase__:   Union[str, Any]  			=   s
                     lowercase__:   Union[str, Any]  			=   addend // 10

              if addend == 0:
                     break

       while addend > 0:
              lowercase__			,						lowercase__:   Union[str, Any]  			=   divmod(snake_case			,							10     )
              digits.append(snake_case     )




def    snake_case_     (  snake_case = 10**15     )  ->				int:
       lowercase__:   Optional[Any]  			=   [1]
       lowercase__:   int  			=   1
       lowercase__:   Tuple  			=   0
       while True:
              lowercase__			,						lowercase__:   str  			=   next_term(snake_case			,							20			,							i + dn			,							snake_case     )
              dn += terms_jumped
              if dn == n - i:
                     break

       lowercase__:   Dict  			=   0
       for j in range(len(snake_case     )     ):
              a_n += digits[j] * 10**j
       return a_n


if __name__ == "__main__":
 print(F'''{solution() = }''')


