Instructions to use OzzyGT/Pixal3D_Modular with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use OzzyGT/Pixal3D_Modular with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("OzzyGT/Pixal3D_Modular", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
Download denoise.py from OzzyGT/Pixal3D_Modular: direct link, hf CLI and curl.
- Browser
- Download file 9.88 kB
-
https://huggingface.co/OzzyGT/Pixal3D_Modular/resolve/main/denoise.py
- Command line
-
hf download hf://OzzyGT/Pixal3D_Modular/denoise.py
-
curl -L -o denoise.py https://huggingface.co/OzzyGT/Pixal3D_Modular/resolve/main/denoise.py
9.88 kB
| from dataclasses import dataclass, field | |
| import torch | |
| from diffusers import ModelMixin, SchedulerMixin | |
| from diffusers.modular_pipelines import LoopSequentialPipelineBlocks | |
| from diffusers.modular_pipelines.modular_pipeline_utils import ComponentSpec, InputParam, OutputParam | |
| from diffusers.utils.torch_utils import randn_tensor | |
| from .guidance import Pixal3DGuidance | |
| from .resolvable import ResolvableBlock | |
| class Pixal3DStage: | |
| """Components and guidance settings of one flow stage.""" | |
| transformer: str | |
| scheduler: str | |
| guider: str | |
| guider_config: dict = field(default_factory=dict) | |
| sparse: bool = True | |
| concat_cond: bool = False | |
| STRUCTURE_STAGE = Pixal3DStage( | |
| "sparse_structure_flow_model", | |
| "structure_scheduler", | |
| "structure_guider", | |
| {"guidance_scale": 7.5, "guidance_rescale": 0.7, "guidance_interval": (0.6, 1.0)}, | |
| sparse=False, | |
| ) | |
| SHAPE_GUIDANCE = {"guidance_scale": 7.5, "guidance_rescale": 0.5, "guidance_interval": (0.6, 1.0)} | |
| SHAPE_LOW_STAGE = Pixal3DStage("shape_slat_flow_model_512", "shape_scheduler", "shape_guider", SHAPE_GUIDANCE) | |
| SHAPE_HIGH_STAGE = Pixal3DStage("shape_slat_flow_model_1024", "shape_scheduler", "shape_guider", SHAPE_GUIDANCE) | |
| TEXTURE_STAGE = Pixal3DStage( | |
| "tex_slat_flow_model_1024", | |
| "texture_scheduler", | |
| "texture_guider", | |
| {"guidance_scale": 1.0, "guidance_rescale": 0.0, "guidance_interval": (0.6, 0.9)}, | |
| concat_cond=True, | |
| ) | |
| class Pixal3DPrepareLatentsStep(ResolvableBlock): | |
| model_name = "pixal3d" | |
| def __init__(self, stage: Pixal3DStage): | |
| self.stage = stage | |
| super().__init__() | |
| def description(self): | |
| return "Draw the initial noise for a dense structure volume or for the sparse shape/texture tokens." | |
| def expected_components(self): | |
| return self.resolve([ComponentSpec(self.stage.transformer, ModelMixin)]) | |
| def inputs(self): | |
| inputs = [InputParam.template("generator")] | |
| if self.stage.sparse: | |
| inputs.append( | |
| InputParam("coords", required=True, type_hint=torch.Tensor, description="Sparse (N, 4) coordinates.") | |
| ) | |
| if self.stage.concat_cond: | |
| inputs.append( | |
| InputParam("concat_cond", required=True, type_hint=torch.Tensor, description="Shape latents.") | |
| ) | |
| return inputs | |
| def intermediate_outputs(self): | |
| return [OutputParam("latents", type_hint=torch.Tensor, description="Initial noise for this stage.")] | |
| def __call__(self, components, state): | |
| b = self.get_block_state(state) | |
| config = getattr(components, self.stage.transformer).config | |
| if not self.stage.sparse: | |
| shape = (1, config.in_channels, *([config.resolution] * 3)) | |
| else: | |
| if len(b.coords) == 0: | |
| raise ValueError("Nonempty sparse coordinates are required") | |
| channels = config.in_channels - (b.concat_cond.shape[-1] if self.stage.concat_cond else 0) | |
| shape = (1, len(b.coords), channels) | |
| b.latents = randn_tensor( | |
| shape, generator=b.generator, device=components._execution_device, dtype=torch.float32 | |
| ) | |
| self.set_block_state(state, b) | |
| return components, state | |
| class Pixal3DSetTimestepsStep(ResolvableBlock): | |
| model_name = "pixal3d" | |
| def __init__(self, stage: Pixal3DStage): | |
| self.stage = stage | |
| super().__init__() | |
| def description(self): | |
| return "Set the shifted flow-matching sigmas for this stage." | |
| def expected_components(self): | |
| return self.resolve([ComponentSpec(self.stage.scheduler, SchedulerMixin)]) | |
| def inputs(self): | |
| return [InputParam.template("num_inference_steps", default=12)] | |
| def intermediate_outputs(self): | |
| return [OutputParam("timesteps", type_hint=list, description="Sigmas in [0, 1], one per step.")] | |
| def __call__(self, components, state): | |
| b = self.get_block_state(state) | |
| scheduler = getattr(components, self.stage.scheduler) | |
| scheduler.set_timesteps(b.num_inference_steps) | |
| b.timesteps = scheduler.timesteps | |
| self.set_block_state(state, b) | |
| return components, state | |
| class Pixal3DLoopDenoiser(ResolvableBlock): | |
| model_name = "pixal3d" | |
| # Conditional batches use the image features; the unconditional batch uses zeros of the same shape. | |
| _guider_input_fields = { | |
| "global_features": ("global_features", "negative_global_features"), | |
| "projected_features": ("projected_features", "negative_projected_features"), | |
| "latents": "latents", | |
| } | |
| def __init__(self, stage: Pixal3DStage): | |
| self.stage = stage | |
| super().__init__() | |
| def description(self): | |
| return "Step within the denoising loop: run the flow model for each guider batch and combine them." | |
| def expected_components(self): | |
| return self.resolve( | |
| [ | |
| ComponentSpec(self.stage.transformer, ModelMixin), | |
| ComponentSpec( | |
| self.stage.guider, | |
| Pixal3DGuidance, | |
| default_creation_method="from_config", | |
| config=self.stage.guider_config, | |
| ), | |
| ] | |
| ) | |
| def inputs(self): | |
| return [ | |
| InputParam("global_features", required=True, type_hint=torch.Tensor, description="DINOv3 global tokens."), | |
| InputParam( | |
| "projected_features", required=True, type_hint=torch.Tensor, description="Camera-projected features." | |
| ), | |
| ] | |
| def __call__(self, components, block_state, i, t): | |
| model = getattr(components, self.stage.transformer) | |
| guider = getattr(components, self.stage.guider) | |
| guider.set_state(step=i, num_inference_steps=len(block_state.timesteps), timestep=t) | |
| batches = guider.prepare_inputs_from_block_state(block_state, self._guider_input_fields) | |
| latents = block_state.latents | |
| timestep = torch.full((latents.shape[0],), 1000 * t, device=latents.device, dtype=torch.float32) | |
| for batch in batches: | |
| guider.prepare_models(model) | |
| batch.noise_pred = model( | |
| latents, | |
| timestep, | |
| batch.global_features, | |
| batch.projected_features, | |
| coords=block_state.model_coords, | |
| concat_cond=block_state.model_concat_cond, | |
| ) | |
| guider.cleanup_models(model) | |
| block_state.noise_pred = guider(batches).pred | |
| return components, block_state | |
| class Pixal3DLoopAfterDenoiser(ResolvableBlock): | |
| model_name = "pixal3d" | |
| def __init__(self, stage: Pixal3DStage): | |
| self.stage = stage | |
| super().__init__() | |
| def description(self): | |
| return "Step within the denoising loop: take one Euler step with the guided velocity." | |
| def expected_components(self): | |
| return self.resolve([ComponentSpec(self.stage.scheduler, SchedulerMixin)]) | |
| def __call__(self, components, block_state, i, t): | |
| scheduler = getattr(components, self.stage.scheduler) | |
| prediction = block_state.noise_pred | |
| block_state.latents = scheduler.step(prediction, t, block_state.latents.to(prediction.device)).prev_sample | |
| return components, block_state | |
| class Pixal3DDenoiseLoop(LoopSequentialPipelineBlocks): | |
| model_name = "pixal3d" | |
| def __init__(self, stage: Pixal3DStage): | |
| self.stage = stage | |
| self.block_classes = [Pixal3DLoopDenoiser(stage), Pixal3DLoopAfterDenoiser(stage)] | |
| self.block_names = ["denoiser", "after_denoiser"] | |
| super().__init__() | |
| def description(self): | |
| return ( | |
| "Iteratively denoise one stage's latents over `timesteps`. Each iteration runs:\n" | |
| " - `Pixal3DLoopDenoiser`: flow model per guider batch, then guidance\n" | |
| " - `Pixal3DLoopAfterDenoiser`: Euler step" | |
| ) | |
| def loop_inputs(self): | |
| inputs = [ | |
| InputParam("timesteps", required=True, type_hint=list, description="From the set-timesteps step."), | |
| InputParam("latents", required=True, type_hint=torch.Tensor, description="From the prepare-latents step."), | |
| ] | |
| if self.stage.sparse: | |
| inputs.append(InputParam("coords", required=True, type_hint=torch.Tensor)) | |
| if self.stage.concat_cond: | |
| inputs.append(InputParam("concat_cond", required=True, type_hint=torch.Tensor)) | |
| return inputs | |
| def loop_intermediate_outputs(self): | |
| return [OutputParam("latents", type_hint=torch.Tensor, description="Denoised latents of this stage.")] | |
| def __call__(self, components, state): | |
| b = self.get_block_state(state) | |
| device = components._execution_device | |
| b.latents = b.latents.to(device) | |
| b.global_features = b.global_features.to(device) | |
| b.projected_features = b.projected_features.to(device) | |
| b.negative_global_features = torch.zeros_like(b.global_features) | |
| b.negative_projected_features = torch.zeros_like(b.projected_features) | |
| b.model_coords = b.coords[None, :, 1:].to(device) if self.stage.sparse else None | |
| b.model_concat_cond = b.concat_cond.to(device) if self.stage.concat_cond else None | |
| with self.progress_bar(total=len(b.timesteps)) as progress_bar: | |
| for i, t in enumerate(b.timesteps): | |
| components, b = self.loop_step(components, b, i=i, t=t) | |
| progress_bar.update() | |
| self.set_block_state(state, b) | |
| return components, state | |