






import argparse
import os
import shutil
from pathlib import Path

import onnx
import torch
from packaging import version
from torch.onnx import export

from diffusers import OnnxRuntimeModel, OnnxStableDiffusionPipeline, StableDiffusionPipeline


snake_case__      :	Union[str, Any]       	=      version.parse(version.parse(torch.__version__).base_version) < version.parse("""1.11""")






def     _snake_case    (__lowercase    ,      __lowercase    ,      __lowercase    ,      __lowercase    ,      __lowercase    ,      __lowercase    ,      __lowercase    ,      __lowercase=False    ,      ):
   output_path.parent.mkdir(parents=__lowercase    ,      exist_ok=__lowercase)
   # PyTorch deprecated the `enable_onnx_checker` and `use_external_data_format` arguments in v1.11,
   # so we check the torch version for backwards compatibility
   if is_torch_less_than_1_11:
      export(
          __lowercase    ,      __lowercase    ,      f=output_path.as_posix()    ,      input_names=__lowercase    ,      output_names=__lowercase    ,      dynamic_axes=__lowercase    ,      do_constant_folding=__lowercase    ,      use_external_data_format=__lowercase    ,      enable_onnx_checker=__lowercase    ,      opset_version=__lowercase    ,      )
   else:
      export(
          __lowercase    ,      __lowercase    ,      f=output_path.as_posix()    ,      input_names=__lowercase    ,      output_names=__lowercase    ,      dynamic_axes=__lowercase    ,      do_constant_folding=__lowercase    ,      opset_version=__lowercase    ,      )






@torch.no_grad()
def     _snake_case    (__lowercase    ,      __lowercase    ,      __lowercase    ,      __lowercase = False):
   UpperCamelCase_									=     torch.floataa if fpaa else torch.floataa
   if fpaa and torch.cuda.is_available():
      UpperCamelCase_									=     'cuda'
   elif fpaa and not torch.cuda.is_available():
      raise ValueError('`float16` model export is only supported on GPUs with CUDA')
   else:
      UpperCamelCase_									=     'cpu'
   UpperCamelCase_									=     StableDiffusionPipeline.from_pretrained(__lowercase    ,      torch_dtype=__lowercase).to(__lowercase)
   UpperCamelCase_									=     Path(__lowercase)

   # TEXT ENCODER
   UpperCamelCase_									=     pipeline.text_encoder.config.max_position_embeddings
   UpperCamelCase_									=     pipeline.text_encoder.config.hidden_size
   UpperCamelCase_									=     pipeline.tokenizer(
       'A sample prompt'    ,      padding='max_length'    ,      max_length=pipeline.tokenizer.model_max_length    ,      truncation=__lowercase    ,      return_tensors='pt'    ,      )
   onnx_export(
       pipeline.text_encoder    ,      model_args=(text_input.input_ids.to(device=__lowercase    ,      dtype=torch.intaa))    ,      output_path=output_path / 'text_encoder' / 'model.onnx'    ,      ordered_input_names=['input_ids']    ,      output_names=['last_hidden_state', 'pooler_output']    ,      dynamic_axes={
           'input_ids': {0: 'batch', 1: 'sequence'},
       }    ,      opset=__lowercase    ,      )
   del pipeline.text_encoder

   # UNET
   UpperCamelCase_									=     pipeline.unet.config.in_channels
   UpperCamelCase_									=     pipeline.unet.config.sample_size
   UpperCamelCase_									=     output_path / 'unet' / 'model.onnx'
   onnx_export(
       pipeline.unet    ,      model_args=(
           torch.randn(2    ,      __lowercase    ,      __lowercase    ,      __lowercase).to(device=__lowercase    ,      dtype=__lowercase),
           torch.randn(2).to(device=__lowercase    ,      dtype=__lowercase),
           torch.randn(2    ,      __lowercase    ,      __lowercase).to(device=__lowercase    ,      dtype=__lowercase),
           False,
       )    ,      output_path=__lowercase    ,      ordered_input_names=['sample', 'timestep', 'encoder_hidden_states', 'return_dict']    ,      output_names=['out_sample']    ,      dynamic_axes={
           'sample': {0: 'batch', 1: 'channels', 2: 'height', 3: 'width'},
           'timestep': {0: 'batch'},
           'encoder_hidden_states': {0: 'batch', 1: 'sequence'},
       }    ,      opset=__lowercase    ,      use_external_data_format=__lowercase    ,      )
   UpperCamelCase_									=     str(unet_path.absolute().as_posix())
   UpperCamelCase_									=     os.path.dirname(__lowercase)
   UpperCamelCase_									=     onnx.load(__lowercase)
   # clean up existing tensor files
   shutil.rmtree(__lowercase)
   os.mkdir(__lowercase)
   # collate external tensor files into one
   onnx.save_model(
       __lowercase    ,      __lowercase    ,      save_as_external_data=__lowercase    ,      all_tensors_to_one_file=__lowercase    ,      location='weights.pb'    ,      convert_attribute=__lowercase    ,      )
   del pipeline.unet

   # VAE ENCODER
   UpperCamelCase_									=     pipeline.vae
   UpperCamelCase_									=     vae_encoder.config.in_channels
   UpperCamelCase_									=     vae_encoder.config.sample_size
   # need to get the raw tensor output (sample) from the encoder
   UpperCamelCase_									=     lambda __lowercase    ,      __lowercase: vae_encoder.encode(__lowercase    ,      __lowercase)[0].sample()
   onnx_export(
       __lowercase    ,      model_args=(
           torch.randn(1    ,      __lowercase    ,      __lowercase    ,      __lowercase).to(device=__lowercase    ,      dtype=__lowercase),
           False,
       )    ,      output_path=output_path / 'vae_encoder' / 'model.onnx'    ,      ordered_input_names=['sample', 'return_dict']    ,      output_names=['latent_sample']    ,      dynamic_axes={
           'sample': {0: 'batch', 1: 'channels', 2: 'height', 3: 'width'},
       }    ,      opset=__lowercase    ,      )

   # VAE DECODER
   UpperCamelCase_									=     pipeline.vae
   UpperCamelCase_									=     vae_decoder.config.latent_channels
   UpperCamelCase_									=     vae_decoder.config.out_channels
   # forward only through the decoder part
   UpperCamelCase_									=     vae_encoder.decode
   onnx_export(
       __lowercase    ,      model_args=(
           torch.randn(1    ,      __lowercase    ,      __lowercase    ,      __lowercase).to(device=__lowercase    ,      dtype=__lowercase),
           False,
       )    ,      output_path=output_path / 'vae_decoder' / 'model.onnx'    ,      ordered_input_names=['latent_sample', 'return_dict']    ,      output_names=['sample']    ,      dynamic_axes={
           'latent_sample': {0: 'batch', 1: 'channels', 2: 'height', 3: 'width'},
       }    ,      opset=__lowercase    ,      )
   del pipeline.vae

   # SAFETY CHECKER
   if pipeline.safety_checker is not None:
      UpperCamelCase_									=     pipeline.safety_checker
      UpperCamelCase_									=     safety_checker.config.vision_config.num_channels
      UpperCamelCase_									=     safety_checker.config.vision_config.image_size
      UpperCamelCase_									=     safety_checker.forward_onnx
      onnx_export(
          pipeline.safety_checker    ,      model_args=(
              torch.randn(
                  1    ,      __lowercase    ,      __lowercase    ,      __lowercase    ,      ).to(device=__lowercase    ,      dtype=__lowercase),
              torch.randn(1    ,      __lowercase    ,      __lowercase    ,      __lowercase).to(device=__lowercase    ,      dtype=__lowercase),
          )    ,      output_path=output_path / 'safety_checker' / 'model.onnx'    ,      ordered_input_names=['clip_input', 'images']    ,      output_names=['out_images', 'has_nsfw_concepts']    ,      dynamic_axes={
              'clip_input': {0: 'batch', 1: 'channels', 2: 'height', 3: 'width'},
              'images': {0: 'batch', 1: 'height', 2: 'width', 3: 'channels'},
          }    ,      opset=__lowercase    ,      )
      del pipeline.safety_checker
      UpperCamelCase_									=     OnnxRuntimeModel.from_pretrained(output_path / 'safety_checker')
      UpperCamelCase_									=     pipeline.feature_extractor
   else:
      UpperCamelCase_									=     None
      UpperCamelCase_									=     None

   UpperCamelCase_									=     OnnxStableDiffusionPipeline(
       vae_encoder=OnnxRuntimeModel.from_pretrained(output_path / 'vae_encoder')    ,      vae_decoder=OnnxRuntimeModel.from_pretrained(output_path / 'vae_decoder')    ,      text_encoder=OnnxRuntimeModel.from_pretrained(output_path / 'text_encoder')    ,      tokenizer=pipeline.tokenizer    ,      unet=OnnxRuntimeModel.from_pretrained(output_path / 'unet')    ,      scheduler=pipeline.scheduler    ,      safety_checker=__lowercase    ,      feature_extractor=__lowercase    ,      requires_safety_checker=safety_checker is not None    ,      )

   onnx_pipeline.save_pretrained(__lowercase)
   print('ONNX pipeline saved to'    ,      __lowercase)

   del pipeline
   del onnx_pipeline
   UpperCamelCase_									=     OnnxStableDiffusionPipeline.from_pretrained(__lowercase    ,      provider='CPUExecutionProvider')
   print('ONNX pipeline is loadable')


if __name__ == "__main__":
 snake_case__      :	Union[str, Any]       	=      argparse.ArgumentParser()

 parser.add_argument(
     """--model_path""",
     type=str,
     required=True,
     help="""Path to the `diffusers` checkpoint to convert (either a local directory or on the Hub).""",
 )

 parser.add_argument("""--output_path""", type=str, required=True, help="""Path to the output model.""")

 parser.add_argument(
     """--opset""",
     default=1_4,
     type=int,
     help="""The version of the ONNX operator set to use.""",
 )
 parser.add_argument("""--fp16""", action="""store_true""", default=False, help="""Export the models in `float16` mode""")

 snake_case__      :	List[Any]       	=      parser.parse_args()

 convert_models(args.model_path, args.output_path, args.opset, args.fpaa)













import os
from math import logaa






def     _snake_case    (__lowercase = "base_exp.txt"):
   UpperCamelCase_									=     0
   UpperCamelCase_									=     0
   for i, line in enumerate(open(os.path.join(os.path.dirname(__lowercase)    ,      __lowercase))):
      UpperCamelCase_		,      UpperCamelCase_									=     list(map(__lowercase    ,      line.split(',')))
      if x * logaa(__lowercase) > largest:
         UpperCamelCase_									=     x * logaa(__lowercase)
         UpperCamelCase_									=     i + 1
   return result


if __name__ == "__main__":
 print(solution())





