import argparse
import os

import evaluate
import torch
from datasets import load_dataset
from torch.optim import AdamW
from torch.utils.data import DataLoader
from transformers import AutoModelForSequenceClassification, AutoTokenizer, get_linear_schedule_with_warmup, set_seed

from accelerate import Accelerator, DistributedType


########################################################################
# This is a fully working simple example to use Accelerate,
# specifically showcasing the checkpointing capability,
# and builds off the `nlp_example.py` script.
#
# This example trains a Bert base model on GLUE MRPC
# in any of the following settings (with the same script):
#   - single CPU or single GPU
#   - multi GPUS (using PyTorch distributed mode)
#   - (multi) TPUs
#   - fp16 (mixed-precision) or fp32 (normal precision)
#
# To help focus on the differences in the code, building `DataLoaders`
# was refactored into its own function.
# New additions from the base script can be found quickly by
# looking for the # New Code # tags
#
# To run it in each of these various modes, follow the instructions
# in the readme for examples:
# https://github.com/huggingface/accelerate/tree/main/examples
#
########################################################################

lowerCamelCase__           =				16
lowerCamelCase__           =				32



def 							_lowerCamelCase(				__snake_case						,						__snake_case = 16	)  ->   List[Any]:
		__snake_case		       =     AutoTokenizer.from_pretrained("bert-base-cased"	)
		__snake_case		       =     load_dataset("glue"						,						"mrpc"	)

		def tokenize_function(__snake_case	):
				# max_length=None => use the model max length (it's actually the default)
				__snake_case		       =     tokenizer(examples["sentence1"]						,						examples["sentence2"]						,						truncation=__snake_case						,						max_length=__snake_case	)
				return outputs

		# Apply the method we just defined to all the examples in all the splits of the dataset
		# starting with the main process first:
		with accelerator.main_process_first():
				__snake_case		       =     datasets.map(
				    __snake_case						,						batched=__snake_case						,						remove_columns=["idx", "sentence1", "sentence2"]						,						)

		# We also rename the 'label' column to 'labels' which is the expected name for labels by the models of the
		# transformers library
		__snake_case		       =     tokenized_datasets.rename_column("label"						,						"labels"	)

		def collate_fn(__snake_case	):
				# On TPU it's best to pad everything to the same length or training will be very slow.
				__snake_case		       =     128 if accelerator.distributed_type == DistributedType.TPU else None
				# When using mixed precision we want round multiples of 8/16
				if accelerator.mixed_precision == "fp8":
						__snake_case		       =     16
				elif accelerator.mixed_precision != "no":
						__snake_case		       =     8
				else:
						__snake_case		       =     None

				return tokenizer.pad(
				    __snake_case						,						padding="longest"						,						max_length=__snake_case						,						pad_to_multiple_of=__snake_case						,						return_tensors="pt"						,						)

		# Instantiate dataloaders.
		__snake_case		       =     DataLoader(
		    tokenized_datasets["train"]						,						shuffle=__snake_case						,						collate_fn=__snake_case						,						batch_size=__snake_case	)
		__snake_case		       =     DataLoader(
		    tokenized_datasets["validation"]						,						shuffle=__snake_case						,						collate_fn=__snake_case						,						batch_size=__snake_case	)

		return train_dataloader, eval_dataloader


# For testing only
if os.environ.get('TESTING_MOCKED_DATALOADERS', None) == "1":
		from accelerate.test_utils.training import mocked_dataloaders

		lowerCamelCase__           =				mocked_dataloaders  # noqa: F811



def 							_lowerCamelCase(				__snake_case						,						__snake_case	)  ->   Any:
		# For testing only
		if os.environ.get("TESTING_MOCKED_DATALOADERS"						,						__snake_case	) == "1":
				__snake_case		       =     2
		# Initialize accelerator
		__snake_case		       =     Accelerator(cpu=args.cpu						,						mixed_precision=args.mixed_precision	)
		# Sample hyper-parameters for learning rate, batch size, seed and a few other HPs
		__snake_case		       =     config["lr"]
		__snake_case		       =     int(config["num_epochs"]	)
		__snake_case		       =     int(config["seed"]	)
		__snake_case		       =     int(config["batch_size"]	)

		# New Code #
		# Parse out whether we are saving every epoch or after a certain number of batches
		if hasattr(args.checkpointing_steps						,						"isdigit"	):
				if args.checkpointing_steps == "epoch":
						__snake_case		       =     args.checkpointing_steps
				elif args.checkpointing_steps.isdigit():
						__snake_case		       =     int(args.checkpointing_steps	)
				else:
						raise ValueError(
						    f"""Argument `checkpointing_steps` must be either a number or `epoch`. `{args.checkpointing_steps}` passed."""	)
		else:
				__snake_case		       =     None

		set_seed(__snake_case	)

		__snake_case       ,       __snake_case		       =     get_dataloaders(__snake_case						,						__snake_case	)
		__snake_case		       =     evaluate.load("glue"						,						"mrpc"	)

		# If the batch size is too big we use gradient accumulation
		__snake_case		       =     1
		if batch_size > MAX_GPU_BATCH_SIZE and accelerator.distributed_type != DistributedType.TPU:
				__snake_case		       =     batch_size // MAX_GPU_BATCH_SIZE
				__snake_case		       =     MAX_GPU_BATCH_SIZE

		# Instantiate the model (we build the model here so that the seed also control new weights initialization)
		__snake_case		       =     AutoModelForSequenceClassification.from_pretrained("bert-base-cased"						,						return_dict=__snake_case	)

		# We could avoid this line since the accelerator is set with `device_placement=True` (default value).
		# Note that if you are placing tensors on devices manually, this line absolutely needs to be before the optimizer
		# creation otherwise training will not work on TPU (`accelerate` will kindly throw an error to make us aware of that).
		__snake_case		       =     model.to(accelerator.device	)

		# Instantiate optimizer
		__snake_case		       =     AdamW(params=model.parameters()						,						lr=__snake_case	)

		# Instantiate scheduler
		__snake_case		       =     get_linear_schedule_with_warmup(
		    optimizer=__snake_case						,						num_warmup_steps=100						,						num_training_steps=(len(__snake_case	) * num_epochs) // gradient_accumulation_steps						,						)

		# Prepare everything
		# There is no specific order to remember, we just need to unpack the objects in the same order we gave them to the
		# prepare method.
		__snake_case       ,       __snake_case       ,       __snake_case       ,       __snake_case       ,       __snake_case		       =     accelerator.prepare(
		    __snake_case						,						__snake_case						,						__snake_case						,						__snake_case						,						__snake_case	)

		# New Code #
		# We need to keep track of how many total steps we have iterated over
		__snake_case		       =     0
		# We also need to keep track of the stating epoch so files are named properly
		__snake_case		       =     0

		# We need to load the checkpoint back in before training here with `load_state`
		# The total number of epochs is adjusted based on where the state is being loaded from,
		# as we assume continuation of the same training script
		if args.resume_from_checkpoint:
				if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "":
						accelerator.print(f"""Resumed from checkpoint: {args.resume_from_checkpoint}"""	)
						accelerator.load_state(args.resume_from_checkpoint	)
						__snake_case		       =     os.path.basename(args.resume_from_checkpoint	)
				else:
						# Get the most recent checkpoint
						__snake_case		       =     [f.name for f in os.scandir(os.getcwd()	) if f.is_dir()]
						dirs.sort(key=os.path.getctime	)
						__snake_case		       =     dirs[-1]  # Sorts folders by date modified, most recent checkpoint is the last
				# Extract `epoch_{i}` or `step_{i}`
				__snake_case		       =     os.path.splitext(__snake_case	)[0]

				if "epoch" in training_difference:
						__snake_case		       =     int(training_difference.replace("epoch_"						,						""	)	) + 1
						__snake_case		       =     None
				else:
						__snake_case		       =     int(training_difference.replace("step_"						,						""	)	)
						__snake_case		       =     resume_step // len(__snake_case	)
						resume_step -= starting_epoch * len(__snake_case	)

    # Now we train the model
		for epoch in range(__snake_case						,						__snake_case	):
				model.train()
				# New Code #
				if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None:
						# We need to skip steps until we reach the resumed step
						__snake_case		       =     accelerator.skip_first_batches(__snake_case						,						__snake_case	)
						overall_step += resume_step
				else:
						# After the first iteration though, we need to go back to the original dataloader
						__snake_case		       =     train_dataloader
				for step, batch in enumerate(__snake_case	):
						# We could avoid this line since we set the accelerator with `device_placement=True`.
						batch.to(accelerator.device	)
						__snake_case		       =     model(**__snake_case	)
						__snake_case		       =     outputs.loss
						__snake_case		       =     loss / gradient_accumulation_steps
						accelerator.backward(__snake_case	)
						if step % gradient_accumulation_steps == 0:
								optimizer.step()
								lr_scheduler.step()
								optimizer.zero_grad()
						# New Code #
						overall_step += 1

						# New Code #
						# We save the model, optimizer, lr_scheduler, and seed states by calling `save_state`
						# These are saved to folders named `step_{overall_step}`
						# Will contain files: "pytorch_model.bin", "optimizer.bin", "scheduler.bin", and "random_states.pkl"
						# If mixed precision was used, will also save a "scalar.bin" file
						if isinstance(__snake_case						,						__snake_case	):
								__snake_case		       =     f"""step_{overall_step}"""
								if overall_step % checkpointing_steps == 0:
										if args.output_dir is not None:
												__snake_case		       =     os.path.join(args.output_dir						,						__snake_case	)
										accelerator.save_state(__snake_case	)

				model.eval()
				for step, batch in enumerate(__snake_case	):
						# We could avoid this line since we set the accelerator with `device_placement=True` (the default).
						batch.to(accelerator.device	)
						with torch.no_grad():
								__snake_case		       =     model(**__snake_case	)
						__snake_case		       =     outputs.logits.argmax(dim=-1	)
						__snake_case       ,       __snake_case		       =     accelerator.gather_for_metrics((predictions, batch["labels"])	)
						metric.add_batch(
						    predictions=__snake_case						,						references=__snake_case						,						)

				__snake_case		       =     metric.compute()
				# Use accelerator.print to print only on the main process.
				accelerator.print(f"""epoch {epoch}:"""						,						__snake_case	)

				# New Code #
				# We save the model, optimizer, lr_scheduler, and seed states by calling `save_state`
				# These are saved to folders named `epoch_{epoch}`
				# Will contain files: "pytorch_model.bin", "optimizer.bin", "scheduler.bin", and "random_states.pkl"
				# If mixed precision was used, will also save a "scalar.bin" file
				if checkpointing_steps == "epoch":
						__snake_case		       =     f"""epoch_{epoch}"""
						if args.output_dir is not None:
								__snake_case		       =     os.path.join(args.output_dir						,						__snake_case	)
						accelerator.save_state(__snake_case	)



def 							_lowerCamelCase(				)  ->   List[Any]:
		__snake_case		       =     argparse.ArgumentParser(description="Simple example of training script."	)
		parser.add_argument(
		    "--mixed_precision"						,						type=__snake_case						,						default=__snake_case						,						choices=["no", "fp16", "bf16", "fp8"]						,						help="Whether to use mixed precision. Choose"
		    "between fp16 and bf16 (bfloat16). Bf16 requires PyTorch >= 1.10."
		    "and an Nvidia Ampere GPU."						,						)
		parser.add_argument("--cpu"						,						action="store_true"						,						help="If passed, will train on the CPU."	)
		parser.add_argument(
		    "--checkpointing_steps"						,						type=__snake_case						,						default=__snake_case						,						help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch."						,						)
		parser.add_argument(
		    "--output_dir"						,						type=__snake_case						,						default="."						,						help="Optional save directory where all checkpoint folders will be stored. Default is the current working directory."						,						)
		parser.add_argument(
		    "--resume_from_checkpoint"						,						type=__snake_case						,						default=__snake_case						,						help="If the training should continue from a checkpoint folder."						,						)
		__snake_case		       =     parser.parse_args()
		__snake_case		       =     {"lr": 2e-5, "num_epochs": 3, "seed": 42, "batch_size": 16}
		training_function(__snake_case						,						__snake_case	)


if __name__ == "__main__":
		main()






import math
from dataclasses import dataclass
from typing import List, Optional, Union

import numpy as np
import PIL
import torch
from transformers import CLIPTextModelWithProjection, CLIPTokenizer

from ...models import PriorTransformer
from ...pipelines import DiffusionPipeline
from ...schedulers import HeunDiscreteScheduler
from ...utils import (
    BaseOutput,
    is_accelerate_available,
    is_accelerate_version,
    logging,
    randn_tensor,
    replace_example_docstring,
)
from .renderer import ShapERenderer


lowerCamelCase__           =				logging.get_logger(__name__)  # pylint: disable=invalid-name

lowerCamelCase__           =				'\n    Examples:\n        ```py\n        >>> import torch\n        >>> from diffusers import DiffusionPipeline\n        >>> from diffusers.utils import export_to_gif\n\n        >>> device = torch.device("cuda" if torch.cuda.is_available() else "cpu")\n\n        >>> repo = "openai/shap-e"\n        >>> pipe = DiffusionPipeline.from_pretrained(repo, torch_dtype=torch.float16)\n        >>> pipe = pipe.to(device)\n\n        >>> guidance_scale = 15.0\n        >>> prompt = "a shark"\n\n        >>> images = pipe(\n        ...     prompt,\n        ...     guidance_scale=guidance_scale,\n        ...     num_inference_steps=64,\n        ...     frame_size=256,\n        ... ).images\n\n        >>> gif_path = export_to_gif(images[0], "shark_3d.gif")\n        ```\n'




@dataclass
class 					UpperCamelCase	(     snake_case__      ):
					__UpperCamelCase						=   42




class 					UpperCamelCase	(     snake_case__      ):




					def __init__( self :					int      ,_lowerCAmelCase :					PriorTransformer      ,_lowerCAmelCase :					CLIPTextModelWithProjection      ,_lowerCAmelCase :					CLIPTokenizer      ,_lowerCAmelCase :					HeunDiscreteScheduler      ,_lowerCAmelCase :					ShapERenderer      ,):


							"""simple docstring"""




							super().__init__()

							self.register_modules(
							    prior=_lowerCAmelCase      ,text_encoder=_lowerCAmelCase      ,tokenizer=_lowerCAmelCase      ,scheduler=_lowerCAmelCase      ,renderer=_lowerCAmelCase      ,)




					def 							UpperCamelCase_						( self :					Union[str, Any]      ,_lowerCAmelCase :					List[Any]      ,_lowerCAmelCase :					List[str]      ,_lowerCAmelCase :					List[str]      ,_lowerCAmelCase :					Tuple      ,_lowerCAmelCase :					Union[str, Any]      ,_lowerCAmelCase :					Optional[int]						):


							"""simple docstring"""




							if latents is None:
									__snake_case		       =     randn_tensor(_lowerCAmelCase      ,generator=_lowerCAmelCase      ,device=_lowerCAmelCase      ,dtype=_lowerCAmelCase						)
							else:
									if latents.shape != shape:
											raise ValueError(F"""Unexpected latents shape, got {latents.shape}, expected {shape}"""						)
									__snake_case		       =     latents.to(_lowerCAmelCase						)

							__snake_case		       =     latents * scheduler.init_noise_sigma
							return latents




					def 							UpperCamelCase_						( self :					str      ,_lowerCAmelCase :					Optional[Any]=0						):


							"""simple docstring"""




							if is_accelerate_available():
									from accelerate import cpu_offload
							else:
									raise ImportError("Please install accelerate via `pip install accelerate`"						)

							__snake_case		       =     torch.device(F"""cuda:{gpu_id}"""						)

							__snake_case		       =     [self.text_encoder, self.prior]
							for cpu_offloaded_model in models:
									if cpu_offloaded_model is not None:
											cpu_offload(_lowerCAmelCase      ,_lowerCAmelCase						)




					def 							UpperCamelCase_						( self :					Optional[int]      ,_lowerCAmelCase :					List[str]=0						):


							"""simple docstring"""




							if is_accelerate_available() and is_accelerate_version(">="      ,"0.17.0.dev0"						):
									from accelerate import cpu_offload_with_hook
							else:
									raise ImportError("`enable_model_cpu_offload` requires `accelerate v0.17.0` or higher."						)

							__snake_case		       =     torch.device(F"""cuda:{gpu_id}"""						)

							if self.device.type != "cpu":
									self.to("cpu"      ,silence_dtype_warnings=_lowerCAmelCase						)
									torch.cuda.empty_cache()  # otherwise we don't see the memory savings (but they probably exist)

							__snake_case		       =     None
							for cpu_offloaded_model in [self.text_encoder, self.prior, self.renderer]:
									__snake_case       ,       __snake_case		       =     cpu_offload_with_hook(_lowerCAmelCase      ,_lowerCAmelCase      ,prev_module_hook=_lowerCAmelCase						)

							if self.safety_checker is not None:
									__snake_case       ,       __snake_case		       =     cpu_offload_with_hook(self.safety_checker      ,_lowerCAmelCase      ,prev_module_hook=_lowerCAmelCase						)

							# We'll offload the last model manually.
							__snake_case		       =     hook




					@property
					def 							UpperCamelCase_						( self :					Optional[int]						):


							"""simple docstring"""




							if self.device != torch.device("meta"						) or not hasattr(self.text_encoder      ,"_hf_hook"						):
									return self.device
							for module in self.text_encoder.modules():
									if (
									    hasattr(_lowerCAmelCase      ,"_hf_hook"						)
									    and hasattr(module._hf_hook      ,"execution_device"						)
									    and module._hf_hook.execution_device is not None
									):
											return torch.device(module._hf_hook.execution_device						)
							return self.device




					def 							UpperCamelCase_						( self :					Optional[Any]      ,_lowerCAmelCase :					Dict      ,_lowerCAmelCase :					int      ,_lowerCAmelCase :					int      ,_lowerCAmelCase :					List[Any]      ,):


							"""simple docstring"""




							len(_lowerCAmelCase						) if isinstance(_lowerCAmelCase      ,_lowerCAmelCase						) else 1

							# YiYi Notes: set pad_token_id to be 0, not sure why I can't set in the config file
							__snake_case		       =     0
							# get prompt text embeddings
							__snake_case		       =     self.tokenizer(
							    _lowerCAmelCase      ,padding="max_length"      ,max_length=self.tokenizer.model_max_length      ,truncation=_lowerCAmelCase      ,return_tensors="pt"      ,)
							__snake_case		       =     text_inputs.input_ids
							__snake_case		       =     self.tokenizer(_lowerCAmelCase      ,padding="longest"      ,return_tensors="pt"						).input_ids

							if untruncated_ids.shape[-1] >= text_input_ids.shape[-1] and not torch.equal(_lowerCAmelCase      ,_lowerCAmelCase						):
									__snake_case		       =     self.tokenizer.batch_decode(untruncated_ids[:, self.tokenizer.model_max_length - 1 : -1]						)
									logger.warning(
									    "The following part of your input was truncated because CLIP can only handle sequences up to"
									    F""" {self.tokenizer.model_max_length} tokens: {removed_text}"""						)

							__snake_case		       =     self.text_encoder(text_input_ids.to(_lowerCAmelCase						)						)
							__snake_case		       =     text_encoder_output.text_embeds

							__snake_case		       =     prompt_embeds.repeat_interleave(_lowerCAmelCase      ,dim=0						)
							# in Shap-E it normalize the prompt_embeds and then later rescale it
							__snake_case		       =     prompt_embeds / torch.linalg.norm(_lowerCAmelCase      ,dim=-1      ,keepdim=_lowerCAmelCase						)

							if do_classifier_free_guidance:
									__snake_case		       =     torch.zeros_like(_lowerCAmelCase						)

									# For classifier free guidance, we need to do two forward passes.
									# Here we concatenate the unconditional and text embeddings into a single batch
									# to avoid doing two forward passes
									__snake_case		       =     torch.cat([negative_prompt_embeds, prompt_embeds]						)

							# Rescale the features to have unit variance
							__snake_case		       =     math.sqrt(prompt_embeds.shape[1]						) * prompt_embeds

							return prompt_embeds







					@torch.no_grad()
					@replace_example_docstring(_lowerCAmelCase						)
					def __call__( self :					int      ,_lowerCAmelCase :					str      ,_lowerCAmelCase :					int = 1      ,_lowerCAmelCase :					int = 25      ,_lowerCAmelCase :					Optional[Union[torch.Generator, List[torch.Generator]]] = None      ,_lowerCAmelCase :					Optional[torch.FloatTensor] = None      ,_lowerCAmelCase :					float = 4.0      ,_lowerCAmelCase :					int = 64      ,_lowerCAmelCase :					Optional[str] = "pil"      ,_lowerCAmelCase :					bool = True      ,):


							"""simple docstring"""




							if isinstance(_lowerCAmelCase      ,_lowerCAmelCase						):
									__snake_case		       =     1
							elif isinstance(_lowerCAmelCase      ,_lowerCAmelCase						):
									__snake_case		       =     len(_lowerCAmelCase						)
							else:
									raise ValueError(F"""`prompt` has to be of type `str` or `list` but is {type(_lowerCAmelCase						)}"""						)

							__snake_case		       =     self._execution_device

							__snake_case		       =     batch_size * num_images_per_prompt

							__snake_case		       =     guidance_scale > 1.0
							__snake_case		       =     self._encode_prompt(_lowerCAmelCase      ,_lowerCAmelCase      ,_lowerCAmelCase      ,_lowerCAmelCase						)

							# prior

							self.scheduler.set_timesteps(_lowerCAmelCase      ,device=_lowerCAmelCase						)
							__snake_case		       =     self.scheduler.timesteps

							__snake_case		       =     self.prior.config.num_embeddings
							__snake_case		       =     self.prior.config.embedding_dim

							__snake_case		       =     self.prepare_latents(
							    (batch_size, num_embeddings * embedding_dim)      ,prompt_embeds.dtype      ,_lowerCAmelCase      ,_lowerCAmelCase      ,_lowerCAmelCase      ,self.scheduler      ,)

							# YiYi notes: for testing only to match ldm, we can directly create a latents with desired shape: batch_size, num_embeddings, embedding_dim
							__snake_case		       =     latents.reshape(latents.shape[0]      ,_lowerCAmelCase      ,_lowerCAmelCase						)

							for i, t in enumerate(self.progress_bar(_lowerCAmelCase						)						):
									# expand the latents if we are doing classifier free guidance
									__snake_case		       =     torch.cat([latents] * 2						) if do_classifier_free_guidance else latents
									__snake_case		       =     self.scheduler.scale_model_input(_lowerCAmelCase      ,_lowerCAmelCase						)

									__snake_case		       =     self.prior(
									    _lowerCAmelCase      ,timestep=_lowerCAmelCase      ,proj_embedding=_lowerCAmelCase      ,).predicted_image_embedding

									# remove the variance
									__snake_case       ,       __snake_case		       =     noise_pred.split(
									    scaled_model_input.shape[2]      ,dim=2						)  # batch_size, num_embeddings, embedding_dim

									if do_classifier_free_guidance is not None:
											__snake_case       ,       __snake_case		       =     noise_pred.chunk(2						)
											__snake_case		       =     noise_pred_uncond + guidance_scale * (noise_pred - noise_pred_uncond)

									__snake_case		       =     self.scheduler.step(
									    _lowerCAmelCase      ,timestep=_lowerCAmelCase      ,sample=_lowerCAmelCase      ,).prev_sample

							if output_type == "latent":
									return ShapEPipelineOutput(images=_lowerCAmelCase						)

							__snake_case		       =     []
							for i, latent in enumerate(_lowerCAmelCase						):
									__snake_case		       =     self.renderer.decode(
									    latent[None, :]      ,_lowerCAmelCase      ,size=_lowerCAmelCase      ,ray_batch_size=4_096      ,n_coarse_samples=64      ,n_fine_samples=128      ,)
									images.append(_lowerCAmelCase						)

							__snake_case		       =     torch.stack(_lowerCAmelCase						)

							if output_type not in ["np", "pil"]:
									raise ValueError(F"""Only the output types `pil` and `np` are supported not output_type={output_type}"""						)

							__snake_case		       =     images.cpu().numpy()

							if output_type == "pil":
									__snake_case		       =     [self.numpy_to_pil(_lowerCAmelCase						) for image in images]

							# Offload last model to CPU
							if hasattr(self      ,"final_offload_hook"						) and self.final_offload_hook is not None:
									self.final_offload_hook.offload()

							if not return_dict:
									return (images,)

							return ShapEPipelineOutput(images=_lowerCAmelCase						)





