






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


lowerCamelCase     :							int    =version.parse(version.parse(torch.__version__).base_version) < version.parse('''1.11''')







def 		SCREAMING_SNAKE_CASE							( __lowerCAmelCase ,   __lowerCAmelCase ,   __lowerCAmelCase ,   __lowerCAmelCase ,   __lowerCAmelCase ,   __lowerCAmelCase ,   __lowerCAmelCase ,   __lowerCAmelCase=False ,   )			->     List[Any]:
					output_path.parent.mkdir(parents=__lowerCAmelCase ,   exist_ok=__lowerCAmelCase      )
					# 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(
										    __lowerCAmelCase ,   __lowerCAmelCase ,   f=output_path.as_posix() ,   input_names=__lowerCAmelCase ,   output_names=__lowerCAmelCase ,   dynamic_axes=__lowerCAmelCase ,   do_constant_folding=__lowerCAmelCase ,   use_external_data_format=__lowerCAmelCase ,   enable_onnx_checker=__lowerCAmelCase ,   opset_version=__lowerCAmelCase ,   )
					else:
										export(
										    __lowerCAmelCase ,   __lowerCAmelCase ,   f=output_path.as_posix() ,   input_names=__lowerCAmelCase ,   output_names=__lowerCAmelCase ,   dynamic_axes=__lowerCAmelCase ,   do_constant_folding=__lowerCAmelCase ,   opset_version=__lowerCAmelCase ,   )







@torch.no_grad()
def 		SCREAMING_SNAKE_CASE							( __lowerCAmelCase ,   __lowerCAmelCase ,   __lowerCAmelCase ,   __lowerCAmelCase = False      )			->     Optional[int]:
					UpperCamelCase__      :       Optional[int]	    =  torch.floataa if fpaa else torch.floataa
					if fpaa and torch.cuda.is_available():
										UpperCamelCase__      :       int	    =  "cuda"
					elif fpaa and not torch.cuda.is_available():
										raise ValueError("`float16` model export is only supported on GPUs with CUDA"      )
					else:
										UpperCamelCase__      :       str	    =  "cpu"
					UpperCamelCase__      :       List[Any]	    =  StableDiffusionPipeline.from_pretrained(__lowerCAmelCase ,   torch_dtype=__lowerCAmelCase      ).to(__lowerCAmelCase      )
					UpperCamelCase__      :       Dict	    =  Path(__lowerCAmelCase      )

					# TEXT ENCODER
					UpperCamelCase__      :       List[Any]	    =  pipeline.text_encoder.config.max_position_embeddings
					UpperCamelCase__      :       Tuple	    =  pipeline.text_encoder.config.hidden_size
					UpperCamelCase__      :       List[Any]	    =  pipeline.tokenizer(
					    "A sample prompt" ,   padding="max_length" ,   max_length=pipeline.tokenizer.model_max_length ,   truncation=__lowerCAmelCase ,   return_tensors="pt" ,   )
					onnx_export(
					    pipeline.text_encoder ,   model_args=(text_input.input_ids.to(device=__lowerCAmelCase ,   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=__lowerCAmelCase ,   )
					del pipeline.text_encoder

					# UNET
					UpperCamelCase__      :       str	    =  pipeline.unet.config.in_channels
					UpperCamelCase__      :       List[str]	    =  pipeline.unet.config.sample_size
					UpperCamelCase__      :       List[str]	    =  output_path / "unet" / "model.onnx"
					onnx_export(
					    pipeline.unet ,   model_args=(
					        torch.randn(2 ,   __lowerCAmelCase ,   __lowerCAmelCase ,   __lowerCAmelCase      ).to(device=__lowerCAmelCase ,   dtype=__lowerCAmelCase      ),
					        torch.randn(2      ).to(device=__lowerCAmelCase ,   dtype=__lowerCAmelCase      ),
					        torch.randn(2 ,   __lowerCAmelCase ,   __lowerCAmelCase      ).to(device=__lowerCAmelCase ,   dtype=__lowerCAmelCase      ),
					        False,
					    ) ,   output_path=__lowerCAmelCase ,   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=__lowerCAmelCase ,   use_external_data_format=__lowerCAmelCase ,   )
					UpperCamelCase__      :       str	    =  str(unet_path.absolute().as_posix()      )
					UpperCamelCase__      :       str	    =  os.path.dirname(__lowerCAmelCase      )
					UpperCamelCase__      :       str	    =  onnx.load(__lowerCAmelCase      )
					# clean up existing tensor files
					shutil.rmtree(__lowerCAmelCase      )
					os.mkdir(__lowerCAmelCase      )
					# collate external tensor files into one
					onnx.save_model(
					    __lowerCAmelCase ,   __lowerCAmelCase ,   save_as_external_data=__lowerCAmelCase ,   all_tensors_to_one_file=__lowerCAmelCase ,   location="weights.pb" ,   convert_attribute=__lowerCAmelCase ,   )
					del pipeline.unet

					# VAE ENCODER
					UpperCamelCase__      :       Any	    =  pipeline.vae
					UpperCamelCase__      :       Any	    =  vae_encoder.config.in_channels
					UpperCamelCase__      :       str	    =  vae_encoder.config.sample_size
					# need to get the raw tensor output (sample) from the encoder
					UpperCamelCase__      :       List[str]	    =  lambda __lowerCAmelCase ,   __lowerCAmelCase      : vae_encoder.encode(__lowerCAmelCase ,   __lowerCAmelCase      )[0].sample()
					onnx_export(
					    __lowerCAmelCase ,   model_args=(
					        torch.randn(1 ,   __lowerCAmelCase ,   __lowerCAmelCase ,   __lowerCAmelCase      ).to(device=__lowerCAmelCase ,   dtype=__lowerCAmelCase      ),
					        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=__lowerCAmelCase ,   )

					# VAE DECODER
					UpperCamelCase__      :       Tuple	    =  pipeline.vae
					UpperCamelCase__      :       int	    =  vae_decoder.config.latent_channels
					UpperCamelCase__      :       List[str]	    =  vae_decoder.config.out_channels
					# forward only through the decoder part
					UpperCamelCase__      :       Optional[Any]	    =  vae_encoder.decode
					onnx_export(
					    __lowerCAmelCase ,   model_args=(
					        torch.randn(1 ,   __lowerCAmelCase ,   __lowerCAmelCase ,   __lowerCAmelCase      ).to(device=__lowerCAmelCase ,   dtype=__lowerCAmelCase      ),
					        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=__lowerCAmelCase ,   )
					del pipeline.vae

					# SAFETY CHECKER
					if pipeline.safety_checker is not None:
										UpperCamelCase__      :       List[Any]	    =  pipeline.safety_checker
										UpperCamelCase__      :       Optional[Any]	    =  safety_checker.config.vision_config.num_channels
										UpperCamelCase__      :       Union[str, Any]	    =  safety_checker.config.vision_config.image_size
										UpperCamelCase__      :       int	    =  safety_checker.forward_onnx
										onnx_export(
										    pipeline.safety_checker ,   model_args=(
										        torch.randn(
										            1 ,   __lowerCAmelCase ,   __lowerCAmelCase ,   __lowerCAmelCase ,   ).to(device=__lowerCAmelCase ,   dtype=__lowerCAmelCase      ),
										        torch.randn(1 ,   __lowerCAmelCase ,   __lowerCAmelCase ,   __lowerCAmelCase      ).to(device=__lowerCAmelCase ,   dtype=__lowerCAmelCase      ),
										    ) ,   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=__lowerCAmelCase ,   )
										del pipeline.safety_checker
										UpperCamelCase__      :       List[Any]	    =  OnnxRuntimeModel.from_pretrained(output_path / "safety_checker"      )
										UpperCamelCase__      :       List[str]	    =  pipeline.feature_extractor
					else:
										UpperCamelCase__      :       List[str]	    =  None
										UpperCamelCase__      :       Dict	    =  None

					UpperCamelCase__      :       int	    =  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=__lowerCAmelCase ,   feature_extractor=__lowerCAmelCase ,   requires_safety_checker=safety_checker is not None ,   )

					onnx_pipeline.save_pretrained(__lowerCAmelCase      )
					print("ONNX pipeline saved to" ,   __lowerCAmelCase      )

					del pipeline
					del onnx_pipeline
					UpperCamelCase__      :       Union[str, Any]	    =  OnnxStableDiffusionPipeline.from_pretrained(__lowerCAmelCase ,   provider="CPUExecutionProvider"      )
					print("ONNX pipeline is loadable"      )


if __name__ == "__main__":
	lowerCamelCase     :							str    =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=14,
	    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''')

	lowerCamelCase     :							Optional[Any]    =parser.parse_args()

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







def 		SCREAMING_SNAKE_CASE							( __lowerCAmelCase      )			->     int:
     assert isinstance(__lowerCAmelCase ,   __lowerCAmelCase      ), f'The input value of [n={number}] is not an integer'

     if number == 1:
          return 2
     elif number < 1:
          UpperCamelCase__      :       List[Any]	    =  f'The input value of [n={number}] has to be > 0'
          raise ValueError(__lowerCAmelCase      )
     else:
          UpperCamelCase__      :       Optional[Any]	    =  sylvester(number - 1      )
          UpperCamelCase__      :       str	    =  num - 1
          UpperCamelCase__      :       int	    =  num
          return lower * upper + 1


if __name__ == "__main__":
 print(F"""The 8th number in Sylvester's sequence: {sylvester(8)}""")