


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       _a			(				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						,    ):


		"""simple docstring"""




		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       _a			(				SCREAMING_SNAKE_CASE						,    SCREAMING_SNAKE_CASE						,    SCREAMING_SNAKE_CASE						,    SCREAMING_SNAKE_CASE = False					):


		"""simple docstring"""




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

		# TEXT ENCODER
		lowercase__						=				pipeline.text_encoder.config.max_position_embeddings
		lowercase__						=				pipeline.text_encoder.config.hidden_size
		lowercase__						=				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
		lowercase__						=				pipeline.unet.config.in_channels
		lowercase__						=				pipeline.unet.config.sample_size
		lowercase__						=				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						,    )
		lowercase__						=				str(unet_path.absolute().as_posix()					)
		lowercase__						=				os.path.dirname(SCREAMING_SNAKE_CASE					)
		lowercase__						=				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
		lowercase__						=				pipeline.vae
		lowercase__						=				vae_encoder.config.in_channels
		lowercase__						=				vae_encoder.config.sample_size
		# need to get the raw tensor output (sample) from the encoder
		lowercase__						=				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
		lowercase__						=				pipeline.vae
		lowercase__						=				vae_decoder.config.latent_channels
		lowercase__						=				vae_decoder.config.out_channels
		# forward only through the decoder part
		lowercase__						=				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:
				lowercase__						=				pipeline.safety_checker
				lowercase__						=				safety_checker.config.vision_config.num_channels
				lowercase__						=				safety_checker.config.vision_config.image_size
				lowercase__						=				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
				lowercase__						=				OnnxRuntimeModel.from_pretrained(output_path / '''safety_checker'''					)
				lowercase__						=				pipeline.feature_extractor
		else:
				lowercase__						=				None
				lowercase__						=				None

		lowercase__						=				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
		lowercase__						=				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)






import argparse
from collections import defaultdict

import yaml


lowerCAmelCase	=							'docs/source/en/_toctree.yml'
def       _a			(				SCREAMING_SNAKE_CASE					):


		"""simple docstring"""




		lowercase__						=				defaultdict(SCREAMING_SNAKE_CASE					)
		lowercase__						=				[]
		lowercase__						=				[]
		for doc in doc_list:
				if "local" in doc:
						counts[doc["local"]] += 1

				if doc["title"].lower() == "overview":
						overview_doc.append({'''local''': doc['''local'''], '''title''': doc['''title''']}					)
				else:
						new_doc_list.append(SCREAMING_SNAKE_CASE					)

		lowercase__						=				new_doc_list
		lowercase__						=				[key for key, value in counts.items() if value > 1]

		lowercase__						=				[]
		for duplicate_key in duplicates:
				lowercase__						=				list({doc['''title'''] for doc in doc_list if doc['''local'''] == duplicate_key}					)
				if len(SCREAMING_SNAKE_CASE					) > 1:
						raise ValueError(
						    f'{duplicate_key} is present several times in the documentation table of content at '
						    '''`docs/source/en/_toctree.yml` with different *Title* values. Choose one of those and remove the '''
						    '''others.'''					)
				# Only add this once
				new_doc.append({'''local''': duplicate_key, '''title''': titles[0]}					)

		# Add none duplicate-keys
		new_doc.extend([doc for doc in doc_list if '''local''' not in counts or counts[doc['''local''']] == 1]					)
		lowercase__						=				sorted(SCREAMING_SNAKE_CASE						,    key=lambda SCREAMING_SNAKE_CASE					: s["title"].lower()					)

		# "overview" gets special treatment and is always first
		if len(SCREAMING_SNAKE_CASE					) > 1:
				raise ValueError('''{doc_list} has two \'overview\' docs which is not allowed.'''					)

		overview_doc.extend(SCREAMING_SNAKE_CASE					)

		# Sort
		return overview_doc
def       _a			(				SCREAMING_SNAKE_CASE=False					):


		"""simple docstring"""




		with open(SCREAMING_SNAKE_CASE						,    encoding='''utf-8'''					) as f:
				lowercase__						=				yaml.safe_load(f.read()					)

		# Get to the API doc
		lowercase__						=				0
		while content[api_idx]["title"] != "API":
				api_idx += 1
		lowercase__						=				content[api_idx]['''sections''']

		# Then to the model doc
		lowercase__						=				0
		while api_doc[scheduler_idx]["title"] != "Schedulers":
				scheduler_idx += 1

		lowercase__						=				api_doc[scheduler_idx]['''sections''']
		lowercase__						=				clean_doc_toc(SCREAMING_SNAKE_CASE					)

		lowercase__						=				False
		if new_scheduler_doc != scheduler_doc:
				lowercase__						=				True
				if overwrite:
						lowercase__						=				new_scheduler_doc

		if diff:
				if overwrite:
						lowercase__						=				api_doc
						with open(SCREAMING_SNAKE_CASE						,    '''w'''						,    encoding='''utf-8'''					) as f:
								f.write(yaml.dump(SCREAMING_SNAKE_CASE						,    allow_unicode=SCREAMING_SNAKE_CASE					)					)
				else:
						raise ValueError(
						    '''The model doc part of the table of content is not properly sorted, run `make style` to fix this.'''					)
def       _a			(				SCREAMING_SNAKE_CASE=False					):


		"""simple docstring"""




		with open(SCREAMING_SNAKE_CASE						,    encoding='''utf-8'''					) as f:
				lowercase__						=				yaml.safe_load(f.read()					)

		# Get to the API doc
		lowercase__						=				0
		while content[api_idx]["title"] != "API":
				api_idx += 1
		lowercase__						=				content[api_idx]['''sections''']

		# Then to the model doc
		lowercase__						=				0
		while api_doc[pipeline_idx]["title"] != "Pipelines":
				pipeline_idx += 1

		lowercase__						=				False
		lowercase__						=				api_doc[pipeline_idx]['''sections''']
		lowercase__						=				[]

		# sort sub pipeline docs
		for pipeline_doc in pipeline_docs:
				if "section" in pipeline_doc:
						lowercase__						=				pipeline_doc['''section''']
						lowercase__						=				clean_doc_toc(SCREAMING_SNAKE_CASE					)
						if overwrite:
								lowercase__						=				new_sub_pipeline_doc
				new_pipeline_docs.append(SCREAMING_SNAKE_CASE					)

		# sort overall pipeline doc
		lowercase__						=				clean_doc_toc(SCREAMING_SNAKE_CASE					)

		if new_pipeline_docs != pipeline_docs:
				lowercase__						=				True
				if overwrite:
						lowercase__						=				new_pipeline_docs

		if diff:
				if overwrite:
						lowercase__						=				api_doc
						with open(SCREAMING_SNAKE_CASE						,    '''w'''						,    encoding='''utf-8'''					) as f:
								f.write(yaml.dump(SCREAMING_SNAKE_CASE						,    allow_unicode=SCREAMING_SNAKE_CASE					)					)
				else:
						raise ValueError(
						    '''The model doc part of the table of content is not properly sorted, run `make style` to fix this.'''					)


if __name__ == "__main__":
			lowerCAmelCase	=							argparse.ArgumentParser()
			parser.add_argument('--fix_and_overwrite', action='store_true', help='Whether to fix inconsistencies.')
			lowerCAmelCase	=							parser.parse_args()

			check_scheduler_doc(args.fix_and_overwrite)
			check_pipeline_doc(args.fix_and_overwrite)


