Pixal3D PR-1: artpipe manifest + WRAP backend + runner #834

Open
opened 2026-07-25 00:53:31 +00:00 by spikerj · 2 comments
Owner

Part of #833.

Add the pixal3d model to spikersoft-artpipe:

  • models/Pixal3D/artpipe.jsonimage_to_3d, vram_mb: 18000, python 3.10 / cu128, ATTN_BACKEND=sdpa, install.repo + extra_weights (MoGe-2, DINOv3, BiRefNet), verify_imports for the compiled extensions.
  • models/Pixal3D/run_pixal3d.py — our own runner. Upstream's argparse forwards only 7 of run_inference()'s ~20 kwargs, so the entire three-phase sampler surface is unreachable from the CLI. Also neutralises upstream's lossy extension_webp=True export.
  • src/artpipe/models/pixal3d.pyPixal3DBackend, modelled on trellis_mac.py: pure build_inference_command, bounded monotonic scan_progress_line, require_cuda_linux() guard, watchdog + stderr drain, output sanity check.
  • src/artpipe/config.pyTIMEOUT_PIXAL3D = 2700; pixal3d added to the CUDA profiles' allowed_models["modeling"] (NOT the default — hunyuan3d stays).
  • tests/test_pixal3d_backend.py — 33 pure-function tests, runnable on any host.

Setup-command ordering matters and is not the README's order: clone TRELLIS.2 → its setup.sh --basic --nvdiffrast --nvdiffrec --cumesh --o-voxel --flexgemm (verified: conda is only touched under --new-env; every other flag is plain pip) → Pixal3D requirements.txtnatten==0.21.0the utils3d wheel LAST, since it deliberately overrides the copy TRELLIS.2's --basic installs from git.

--flash-attn is skipped: ATTN_BACKEND=sdpa is read from env at import of pixal3d/modules/attention/config.py, and flash_attn is only imported inside functions. That legitimately avoids a multi-hour build.

Verification

  • pytest tests/test_pixal3d_backend.py — 33 passed (Mac)
  • Full suite unaffected — 734 passed; the 18 test_batch_stages errors are a pre-existing missing-flask gap, confirmed identical with the changes stashed
  • scripts/validate_model_manifests.py clean (only the known MediaPipe resource dir)
  • artpipe setup --model Pixal3D on the 4090 — the first real test of the setup-command chain
  • POST /jobs {model: "pixal3d", action: "image_to_3d"} on the 4090; record wall-clock + peak VRAM to confirm the 18000 declaration and TIMEOUT_PIXAL3D
  • Import the resulting GLB through Blender 5.1 import_gltf_compat() and confirm all PBR channels survive
Part of #833. Add the `pixal3d` model to `spikersoft-artpipe`: - `models/Pixal3D/artpipe.json` — `image_to_3d`, `vram_mb: 18000`, python 3.10 / cu128, `ATTN_BACKEND=sdpa`, `install.repo` + `extra_weights` (MoGe-2, DINOv3, BiRefNet), `verify_imports` for the compiled extensions. - `models/Pixal3D/run_pixal3d.py` — our own runner. Upstream's argparse forwards only 7 of `run_inference()`'s ~20 kwargs, so the entire three-phase sampler surface is unreachable from the CLI. Also neutralises upstream's lossy `extension_webp=True` export. - `src/artpipe/models/pixal3d.py` — `Pixal3DBackend`, modelled on `trellis_mac.py`: pure `build_inference_command`, bounded monotonic `scan_progress_line`, `require_cuda_linux()` guard, watchdog + stderr drain, output sanity check. - `src/artpipe/config.py` — `TIMEOUT_PIXAL3D = 2700`; `pixal3d` added to the CUDA profiles' `allowed_models["modeling"]` (NOT the default — hunyuan3d stays). - `tests/test_pixal3d_backend.py` — 33 pure-function tests, runnable on any host. **Setup-command ordering matters** and is not the README's order: clone TRELLIS.2 → its `setup.sh --basic --nvdiffrast --nvdiffrec --cumesh --o-voxel --flexgemm` (verified: conda is only touched under `--new-env`; every other flag is plain pip) → Pixal3D `requirements.txt` → `natten==0.21.0` → **the utils3d wheel LAST**, since it deliberately overrides the copy TRELLIS.2's `--basic` installs from git. `--flash-attn` is skipped: `ATTN_BACKEND=sdpa` is read from env at import of `pixal3d/modules/attention/config.py`, and flash_attn is only imported inside functions. That legitimately avoids a multi-hour build. ## Verification - [x] `pytest tests/test_pixal3d_backend.py` — 33 passed (Mac) - [x] Full suite unaffected — 734 passed; the 18 `test_batch_stages` errors are a pre-existing missing-`flask` gap, confirmed identical with the changes stashed - [x] `scripts/validate_model_manifests.py` clean (only the known MediaPipe resource dir) - [ ] `artpipe setup --model Pixal3D` on the 4090 — the first real test of the setup-command chain - [ ] `POST /jobs {model: "pixal3d", action: "image_to_3d"}` on the 4090; record wall-clock + peak VRAM to confirm the 18000 declaration and `TIMEOUT_PIXAL3D` - [ ] Import the resulting GLB through Blender 5.1 `import_gltf_compat()` and confirm all PBR channels survive
Author
Owner

⚠️ Export the gate knobs before the :9100 run, or it looks like a Pixal3D hang

artpipe serve + POST /jobs on the 4090 needs #835's overrides exported, otherwise _acquire_gpu waits out TIMEOUT_VRAM_WAIT (120s) and gives up with "GPU admit timeout" — nothing about that message points at the admission gate:

export ARTPIPE_VRAM_OVERHEAD_FACTOR=1.15
export ARTPIPE_VRAM_MAX_UTILIZATION=0.95
artpipe serve --root .

(18000 × 1.4 = 25200 exceeds the card's total 24576, so the default factor alone makes it unadmittable.) Merge #34 first, or the constants aren't overridable at all.

Two review findings fixed in a follow-up commit on PR #33

1. The lossless-texture guarantee wasn't actually guaranteed. force_png_textures() patches trimesh.Scene / trimesh.Trimesh, but o_voxel.postprocess.to_glb() returns whatever it returns — a wrapper type or a subclass registered elsewhere would slip past the patch, extension_webp=True would reach the exporter, and every PBR map would come out lossy q80 while the log still said "PNG (lossless)". The original test only exercised the mechanism against classes the test itself defined, so it could never have caught that.

Replaced with a postcondition on the real artifact: parse the GLB's JSON chunk and fail if EXT_texture_webp is declared while texture_format=png. Unparseable input is treated as "couldn't tell", never as "contains WebP".

2. TRELLIS.2's --basic would have clobbered Pixal3D's pins. venv_setup pip-installs the cloned repo's requirements.txt before setup_commands run (Pixal3D ships requirements.txt but no setup.py, so the editable branch is skipped). --basic then installed unpinned transformers/trimesh over Pixal3D's transformers==4.57.3 / trimesh==4.10.1, plus abandoned pillow-simd (conflicts with pillow==12.0.0, wants sudo apt). Dropped --basic; ninja is installed explicitly as the only piece the extension builds still need.

Also confirmed rather than assumed: cumesh is the correct import name (pyproject.toml name = "cumesh"), and NATTEN_CUDA_ARCH takes the dotted form — _check_cuda_arch does float(arch) * 10, so 8.6;8.9 is right and 86;89 would have built for SM860.

Tests now 43 passed, 1 skipped.

### ⚠️ Export the gate knobs before the `:9100` run, or it looks like a Pixal3D hang `artpipe serve` + `POST /jobs` on the 4090 needs #835's overrides exported, otherwise `_acquire_gpu` waits out `TIMEOUT_VRAM_WAIT` (120s) and gives up with "GPU admit timeout" — nothing about that message points at the admission gate: ```bash export ARTPIPE_VRAM_OVERHEAD_FACTOR=1.15 export ARTPIPE_VRAM_MAX_UTILIZATION=0.95 artpipe serve --root . ``` (18000 × 1.4 = 25200 exceeds the card's *total* 24576, so the default factor alone makes it unadmittable.) Merge #34 first, or the constants aren't overridable at all. ### Two review findings fixed in a follow-up commit on PR #33 **1. The lossless-texture guarantee wasn't actually guaranteed.** `force_png_textures()` patches `trimesh.Scene` / `trimesh.Trimesh`, but `o_voxel.postprocess.to_glb()` returns whatever it returns — a wrapper type or a subclass registered elsewhere would slip past the patch, `extension_webp=True` would reach the exporter, and every PBR map would come out lossy q80 **while the log still said "PNG (lossless)"**. The original test only exercised the mechanism against classes the test itself defined, so it could never have caught that. Replaced with a postcondition on the real artifact: parse the GLB's JSON chunk and fail if `EXT_texture_webp` is declared while `texture_format=png`. Unparseable input is treated as "couldn't tell", never as "contains WebP". **2. TRELLIS.2's `--basic` would have clobbered Pixal3D's pins.** `venv_setup` pip-installs the cloned repo's `requirements.txt` *before* `setup_commands` run (Pixal3D ships `requirements.txt` but no `setup.py`, so the editable branch is skipped). `--basic` then installed unpinned `transformers`/`trimesh` over Pixal3D's `transformers==4.57.3` / `trimesh==4.10.1`, plus abandoned `pillow-simd` (conflicts with `pillow==12.0.0`, wants `sudo apt`). Dropped `--basic`; `ninja` is installed explicitly as the only piece the extension builds still need. Also confirmed rather than assumed: `cumesh` is the correct import name (`pyproject.toml` `name = "cumesh"`), and `NATTEN_CUDA_ARCH` takes the **dotted** form — `_check_cuda_arch` does `float(arch) * 10`, so `8.6;8.9` is right and `86;89` would have built for SM860. Tests now 43 passed, 1 skipped.
Author
Owner

Merged in spikersoft-artpipe PR #33 (main, commits 9993347 + fe0a1ff).

⚠️ main currently ships a known bug — the two review fixes above were pushed ~8 minutes after #33 merged, so they missed the window. They're now in PR #35:

  • TRELLIS.2's --basic clobbers Pixal3D's transformers==4.57.3 / trimesh==4.10.1 pins and pulls abandoned pillow-simd. Do not build the pixal3d env image until #35 merges — the venv it produces would have the wrong dependency set.
  • The lossless-texture guarantee has no artifact-level check, so a missed patch would produce lossy q80 maps silently.

Keeping this open until #35 lands and the 4090 verification steps are done.

Merged in spikersoft-artpipe PR #33 (`main`, commits `9993347` + `fe0a1ff`). **⚠️ `main` currently ships a known bug** — the two review fixes above were pushed ~8 minutes after #33 merged, so they missed the window. They're now in **PR #35**: - TRELLIS.2's `--basic` clobbers Pixal3D's `transformers==4.57.3` / `trimesh==4.10.1` pins and pulls abandoned `pillow-simd`. **Do not build the `pixal3d` env image until #35 merges** — the venv it produces would have the wrong dependency set. - The lossless-texture guarantee has no artifact-level check, so a missed patch would produce lossy q80 maps silently. Keeping this open until #35 lands and the 4090 verification steps are done.
Sign in to join this conversation.