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 decoders.py from OzzyGT/Pixal3D_Modular: direct link, hf CLI and curl.
- Browser
- Download file 6.91 kB
-
https://huggingface.co/OzzyGT/Pixal3D_Modular/resolve/main/decoders.py
- Command line
-
hf download hf://OzzyGT/Pixal3D_Modular/decoders.py
-
curl -L -o decoders.py https://huggingface.co/OzzyGT/Pixal3D_Modular/resolve/main/decoders.py
6.91 kB
| import torch | |
| from diffusers import ModelMixin | |
| from diffusers.modular_pipelines.modular_pipeline_utils import ( | |
| ComponentSpec, | |
| InputParam, | |
| OutputParam, | |
| ) | |
| from torch.nn import functional as F | |
| from .resolvable import ResolvableBlock | |
| class Pixal3DStructureDecodeStep(ResolvableBlock): | |
| model_name = "pixal3d" | |
| def description(self): | |
| return "Decode structure latents and extract occupied sparse coordinates." | |
| def expected_components(self): | |
| return self.resolve([ComponentSpec("sparse_structure_decoder", ModelMixin)]) | |
| def inputs(self): | |
| return [ | |
| InputParam("latents", required=True, type_hint=torch.Tensor), | |
| InputParam( | |
| "structure_resolution", | |
| default=32, | |
| type_hint=int, | |
| description="Occupancy grid size; the decoded 64^3 grid is max-pooled down to it.", | |
| ), | |
| ] | |
| def intermediate_outputs(self): | |
| return [OutputParam("coords", type_hint=torch.Tensor)] | |
| def __call__(self, components, state): | |
| b = self.get_block_state(state) | |
| model = components.sparse_structure_decoder | |
| occupancy = model(b.latents.to(model.device)) > 0 | |
| if occupancy.shape[2] != b.structure_resolution: | |
| if occupancy.shape[2] % b.structure_resolution: | |
| raise ValueError("Structure resolution must divide the decoded grid size") | |
| ratio = occupancy.shape[2] // b.structure_resolution | |
| occupancy = F.max_pool3d(occupancy.float(), ratio, ratio) > 0.5 | |
| b.coords = torch.argwhere(occupancy)[:, [0, 2, 3, 4]].int() | |
| self.set_block_state(state, b) | |
| return components, state | |
| class Pixal3DShapeUpsampleStep(ResolvableBlock): | |
| model_name = "pixal3d" | |
| def description(self): | |
| return "Use the shape decoder to generate the high-resolution sparse coordinate set." | |
| def expected_components(self): | |
| return self.resolve([ComponentSpec("shape_slat_decoder", ModelMixin)]) | |
| def inputs(self): | |
| return [ | |
| InputParam("shape_latents", required=True, type_hint=torch.Tensor), | |
| InputParam("coords", required=True, type_hint=torch.Tensor), | |
| InputParam("resolution", default=1024, type_hint=int, description="Output grid resolution: 1024 or 1536."), | |
| InputParam( | |
| "max_num_tokens", | |
| default=49152, | |
| type_hint=int, | |
| description="Token budget; 1536 falls back in steps of 128 until the sparse grid fits.", | |
| ), | |
| ] | |
| def intermediate_outputs(self): | |
| return [ | |
| OutputParam("coords", type_hint=torch.Tensor), | |
| OutputParam("actual_resolution", type_hint=int), | |
| ] | |
| def __call__(self, components, state): | |
| b = self.get_block_state(state) | |
| if b.resolution not in (1024, 1536): | |
| raise ValueError("Supported resolutions are 1024 and 1536") | |
| model = components.shape_slat_decoder | |
| coords = model( | |
| b.shape_latents[0].to(model.device), | |
| b.coords.to(model.device), | |
| upsample_times=4, | |
| )["coords"] | |
| resolution = b.resolution | |
| while True: | |
| grid = resolution // 16 | |
| quantized = torch.cat( | |
| [ | |
| coords[:, :1], | |
| ((coords[:, 1:] + 0.5) / 512 * (grid - 1)).round().int(), | |
| ], | |
| 1, | |
| ).unique(dim=0) | |
| if len(quantized) < b.max_num_tokens or resolution == 1024: | |
| break | |
| resolution -= 128 | |
| b.coords = quantized | |
| b.actual_resolution = resolution | |
| self.set_block_state(state, b) | |
| return components, state | |
| class Pixal3DShapeDecodeStep(ResolvableBlock): | |
| model_name = "pixal3d" | |
| def description(self): | |
| return "Decode shape latents into a flexible dual grid and texture subdivision guides." | |
| def expected_components(self): | |
| return self.resolve([ComponentSpec("shape_slat_decoder", ModelMixin)]) | |
| def inputs(self): | |
| return [ | |
| InputParam("shape_latents", required=True, type_hint=torch.Tensor), | |
| InputParam("coords", required=True, type_hint=torch.Tensor), | |
| ] | |
| def intermediate_outputs(self): | |
| return [ | |
| OutputParam("geometry", type_hint=dict), | |
| OutputParam("subdivisions", type_hint=list), | |
| ] | |
| def __call__(self, components, state): | |
| b = self.get_block_state(state) | |
| model = components.shape_slat_decoder | |
| decoded = model( | |
| b.shape_latents[0].to(model.device), | |
| b.coords.to(model.device), | |
| return_subs=True, | |
| ) | |
| features = decoded["features"] | |
| b.geometry = { | |
| "coords": decoded["coords"], | |
| "vertex_offsets": 2 * features[:, :3].sigmoid() - 0.5, | |
| "intersected": features[:, 3:6] > 0, | |
| "quad_weights": F.softplus(features[:, 6:7]), | |
| } | |
| b.subdivisions = decoded["subdivisions"] | |
| self.set_block_state(state, b) | |
| return components, state | |
| class Pixal3DTextureDecodeStep(ResolvableBlock): | |
| model_name = "pixal3d" | |
| def description(self): | |
| return "Decode material attributes on the shape subdivision grid, without texture baking." | |
| def expected_components(self): | |
| return self.resolve([ComponentSpec("tex_slat_decoder", ModelMixin)]) | |
| def inputs(self): | |
| return [ | |
| InputParam("texture_latents", required=True, type_hint=torch.Tensor), | |
| InputParam("coords", required=True, type_hint=torch.Tensor), | |
| InputParam("subdivisions", required=True, type_hint=list), | |
| ] | |
| def intermediate_outputs(self): | |
| return [OutputParam("materials", type_hint=dict)] | |
| def __call__(self, components, state): | |
| b = self.get_block_state(state) | |
| model = components.tex_slat_decoder | |
| guides = [{k: v.to(model.device) for k, v in sub.items()} for sub in b.subdivisions] | |
| decoded = model( | |
| b.texture_latents[0].to(model.device), | |
| b.coords.to(model.device), | |
| guide_subs=guides, | |
| ) | |
| b.materials = { | |
| "coords": decoded["coords"], | |
| "attributes": decoded["features"] * 0.5 + 0.5, | |
| "layout": { | |
| "base_color": [0, 3], | |
| "metallic": [3, 4], | |
| "roughness": [4, 5], | |
| "alpha": [5, 6], | |
| }, | |
| } | |
| self.set_block_state(state, b) | |
| return components, state | |