

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_			      =      version.parse(version.parse(torch.__version__).base_version) < version.parse('''1.11''')


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


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

						# TEXT ENCODER
						snake_case_  =      pipeline.text_encoder.config.max_position_embeddings
						snake_case_  =      pipeline.text_encoder.config.hidden_size
						snake_case_  =      pipeline.tokenizer(
						    '''A sample prompt'''    ,						padding='''max_length'''    ,						max_length=pipeline.tokenizer.model_max_length    ,						truncation=SCREAMING_SNAKE_CASE__    ,						return_tensors='''pt'''    ,						)
						onnx_export(
						    pipeline.text_encoder    ,						model_args=(text_input.input_ids.to(device=SCREAMING_SNAKE_CASE__    ,						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=SCREAMING_SNAKE_CASE__    ,						)
						del pipeline.text_encoder

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

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

						# VAE DECODER
						snake_case_  =      pipeline.vae
						snake_case_  =      vae_decoder.config.latent_channels
						snake_case_  =      vae_decoder.config.out_channels
						# forward only through the decoder part
						snake_case_  =      vae_encoder.decode
						onnx_export(
						    SCREAMING_SNAKE_CASE__    ,						model_args=(
						        torch.randn(1    ,						SCREAMING_SNAKE_CASE__    ,						SCREAMING_SNAKE_CASE__    ,						SCREAMING_SNAKE_CASE__			).to(device=SCREAMING_SNAKE_CASE__    ,						dtype=SCREAMING_SNAKE_CASE__			),
						        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=SCREAMING_SNAKE_CASE__    ,						)
						del pipeline.vae

						# SAFETY CHECKER
						if pipeline.safety_checker is not None:
												snake_case_  =      pipeline.safety_checker
												snake_case_  =      safety_checker.config.vision_config.num_channels
												snake_case_  =      safety_checker.config.vision_config.image_size
												snake_case_  =      safety_checker.forward_onnx
												onnx_export(
												    pipeline.safety_checker    ,						model_args=(
												        torch.randn(
												            1    ,						SCREAMING_SNAKE_CASE__    ,						SCREAMING_SNAKE_CASE__    ,						SCREAMING_SNAKE_CASE__    ,						).to(device=SCREAMING_SNAKE_CASE__    ,						dtype=SCREAMING_SNAKE_CASE__			),
												        torch.randn(1    ,						SCREAMING_SNAKE_CASE__    ,						SCREAMING_SNAKE_CASE__    ,						SCREAMING_SNAKE_CASE__			).to(device=SCREAMING_SNAKE_CASE__    ,						dtype=SCREAMING_SNAKE_CASE__			),
												    )    ,						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=SCREAMING_SNAKE_CASE__    ,						)
												del pipeline.safety_checker
												snake_case_  =      OnnxRuntimeModel.from_pretrained(output_path / '''safety_checker'''			)
												snake_case_  =      pipeline.feature_extractor
						else:
												snake_case_  =      None
												snake_case_  =      None

						snake_case_  =      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=SCREAMING_SNAKE_CASE__    ,						feature_extractor=SCREAMING_SNAKE_CASE__    ,						requires_safety_checker=safety_checker is not None    ,						)

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

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


if __name__ == "__main__":
					lowerCAmelCase_			      =      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_			      =      parser.parse_args()

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



from . import (
    albert,
    align,
    altclip,
    audio_spectrogram_transformer,
    auto,
    autoformer,
    bark,
    bart,
    barthez,
    bartpho,
    beit,
    bert,
    bert_generation,
    bert_japanese,
    bertweet,
    big_bird,
    bigbird_pegasus,
    biogpt,
    bit,
    blenderbot,
    blenderbot_small,
    blip,
    blip_a,
    bloom,
    bridgetower,
    byta,
    camembert,
    canine,
    chinese_clip,
    clap,
    clip,
    clipseg,
    codegen,
    conditional_detr,
    convbert,
    convnext,
    convnextva,
    cpm,
    cpmant,
    ctrl,
    cvt,
    dataavec,
    deberta,
    deberta_va,
    decision_transformer,
    deformable_detr,
    deit,
    deprecated,
    deta,
    detr,
    dialogpt,
    dinat,
    distilbert,
    dit,
    donut,
    dpr,
    dpt,
    efficientformer,
    efficientnet,
    electra,
    encodec,
    encoder_decoder,
    ernie,
    ernie_m,
    esm,
    falcon,
    flaubert,
    flava,
    fnet,
    focalnet,
    fsmt,
    funnel,
    git,
    glpn,
    gpta,
    gpt_bigcode,
    gpt_neo,
    gpt_neox,
    gpt_neox_japanese,
    gpt_swa,
    gptj,
    gptsan_japanese,
    graphormer,
    groupvit,
    herbert,
    hubert,
    ibert,
    imagegpt,
    informer,
    instructblip,
    jukebox,
    layoutlm,
    layoutlmva,
    layoutlmva,
    layoutxlm,
    led,
    levit,
    lilt,
    llama,
    longformer,
    longta,
    luke,
    lxmert,
    mam_aaa,
    marian,
    markuplm,
    maskaformer,
    maskformer,
    mbart,
    mbartaa,
    mega,
    megatron_bert,
    megatron_gpta,
    mgp_str,
    mluke,
    mobilebert,
    mobilenet_va,
    mobilenet_va,
    mobilevit,
    mobilevitva,
    mpnet,
    mra,
    mta,
    musicgen,
    mvp,
    nat,
    nezha,
    nllb,
    nllb_moe,
    nystromformer,
    oneformer,
    open_llama,
    openai,
    opt,
    owlvit,
    pegasus,
    pegasus_x,
    perceiver,
    phobert,
    pixastruct,
    plbart,
    poolformer,
    prophetnet,
    qdqbert,
    rag,
    realm,
    reformer,
    regnet,
    rembert,
    resnet,
    roberta,
    roberta_prelayernorm,
    roc_bert,
    roformer,
    rwkv,
    sam,
    segformer,
    sew,
    sew_d,
    speech_encoder_decoder,
    speech_to_text,
    speech_to_text_a,
    speechta,
    splinter,
    squeezebert,
    swiftformer,
    swin,
    swinasr,
    swinva,
    switch_transformers,
    ta,
    table_transformer,
    tapas,
    time_series_transformer,
    timesformer,
    timm_backbone,
    transfo_xl,
    trocr,
    tvlt,
    umta,
    unispeech,
    unispeech_sat,
    upernet,
    videomae,
    vilt,
    vision_encoder_decoder,
    vision_text_dual_encoder,
    visual_bert,
    vit,
    vit_hybrid,
    vit_mae,
    vit_msn,
    vivit,
    wavaveca,
    wavaveca_conformer,
    wavaveca_phoneme,
    wavaveca_with_lm,
    wavlm,
    whisper,
    x_clip,
    xglm,
    xlm,
    xlm_prophetnet,
    xlm_roberta,
    xlm_roberta_xl,
    xlnet,
    xmod,
    yolos,
    yoso,
)





