operator: trellis2_mlx — the 72s/26GB MLX fork as a farm operator (vertex baker default; m1 routed via nodes.json)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
eb3862bb8a
commit
de0b509dfa
20
scripts/install_trellis2_mlx.sh
Executable file
20
scripts/install_trellis2_mlx.sh
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Vendor the MRP MLX fork of TRELLIS.2 (monster/trellis-2-mrp-mlx) for the
|
||||||
|
# trellis2_mlx operator. Idempotent. Existing per-box clones also work
|
||||||
|
# (run.py resolves m3 staging / m1 ~/trellis2-mlx automatically) — this
|
||||||
|
# script is for fresh boxes.
|
||||||
|
# Weights: TRELLIS.2-4B + gated facebook/dinov3 + briaai/RMBG-2.0 — rsync
|
||||||
|
# from m3ultra's HF cache (no HF login):
|
||||||
|
# for M in models--facebook--dinov3-vitl16-pretrain-lvd1689m \
|
||||||
|
# models--microsoft--TRELLIS.2-4B models--briaai--RMBG-2.0; do
|
||||||
|
# rsync -a m3ultra@100.89.131.57:.cache/huggingface/hub/$M ~/.cache/huggingface/hub/
|
||||||
|
# done
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
DEST="$ROOT/vendor/trellis2-mlx"
|
||||||
|
REPO="ssh://git@100.71.119.27:222/monster/trellis-2-mrp-mlx.git"
|
||||||
|
[ -d "$DEST/.git" ] && echo "already cloned: $DEST" || git clone "$REPO" "$DEST"
|
||||||
|
cd "$DEST"
|
||||||
|
PB="${PYTHON_BIN:-$(/opt/homebrew/bin/uv python find 3.11)}"
|
||||||
|
PYTHON_BIN="$PB" bash scripts/setup_macos.sh
|
||||||
|
.venv/bin/python -c "import mlx_backend" && echo "trellis2-mlx OK: $DEST"
|
||||||
20
server/operators/trellis2_mlx/manifest.json
Normal file
20
server/operators/trellis2_mlx/manifest.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"id": "trellis2_mlx",
|
||||||
|
"name": "TRELLIS.2 MLX (local, fastest)",
|
||||||
|
"category": "mesh-gen",
|
||||||
|
"description": "Image → full-density vertex-baked GLB via the MRP MLX fork of TRELLIS.2 (monster/trellis-2-mrp-mlx): pure-MLX sampler + vertex baker + validated pipeline. 72s/gen @ 26.5GB on m3ultra, 182s @ 17.2GB on m1ultra — 3× faster and 3× lighter than the torch-MPS trellis_mac operator. Vertex-colored output (albedo; no MR maps) — pair with the MESHGOD finish farm for game budgets. Weights: TRELLIS.2-4B + gated DINOv3/RMBG (rsync from m3 HF cache to workers; no HF login needed).",
|
||||||
|
"accepts": ["image"],
|
||||||
|
"produces": ["model"],
|
||||||
|
"resources": "gpu",
|
||||||
|
"entry": "run.py",
|
||||||
|
"python": "vendor/trellis2-mlx/.venv/bin/python",
|
||||||
|
"params_schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"pipeline_type": {"type": "string", "enum": ["512", "1024", "1024_cascade"], "default": "1024_cascade", "description": "Resolution tier"},
|
||||||
|
"seed": {"type": "integer", "default": 0, "description": "Random seed"},
|
||||||
|
"steps": {"type": "integer", "default": 12, "description": "Sampler steps per stage (12 = upstream default)"},
|
||||||
|
"baker": {"type": "string", "enum": ["vertex", "metal", "kdtree"], "default": "vertex", "description": "vertex = 1s bake, clean colors (recommended); metal = UV textures but has the dark-patch sampling bug"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
70
server/operators/trellis2_mlx/run.py
Normal file
70
server/operators/trellis2_mlx/run.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[3]
|
||||||
|
|
||||||
|
# fork checkout resolution: vendored path first, then the per-box conventional
|
||||||
|
# clones (m3 staging, m1 home) so existing installs work without re-vendoring.
|
||||||
|
CANDIDATES = [
|
||||||
|
ROOT / "vendor" / "trellis2-mlx",
|
||||||
|
Path.home() / "Documents" / "trellis2-mlx-staging" / "trellis2-jourloy",
|
||||||
|
Path.home() / "trellis2-mlx",
|
||||||
|
]
|
||||||
|
FORK = next((c for c in CANDIDATES if (c / "scripts" / "generate_asset.py").exists()), None)
|
||||||
|
|
||||||
|
ap = argparse.ArgumentParser()
|
||||||
|
ap.add_argument("--input", action="append", default=[])
|
||||||
|
ap.add_argument("--outdir", required=True)
|
||||||
|
ap.add_argument("--params", default="{}")
|
||||||
|
a = ap.parse_args()
|
||||||
|
p = json.loads(a.params)
|
||||||
|
|
||||||
|
if not a.input:
|
||||||
|
print("ERROR: no input image")
|
||||||
|
sys.exit(1)
|
||||||
|
if FORK is None:
|
||||||
|
print("ERROR: trellis-2-mrp-mlx not found. Run scripts/install_trellis2_mlx.sh")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
py = FORK / ".venv" / "bin" / "python"
|
||||||
|
if not py.exists():
|
||||||
|
print(f"ERROR: no venv at {FORK}/.venv — run its scripts/setup_macos.sh")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
outdir = Path(a.outdir)
|
||||||
|
cmd = [
|
||||||
|
str(py), str(FORK / "scripts" / "generate_asset.py"),
|
||||||
|
str(Path(a.input[0]).resolve()),
|
||||||
|
"--output-dir", str(outdir.resolve()),
|
||||||
|
"--backend", "mlx-experimental",
|
||||||
|
"--baker", str(p.get("baker", "vertex")),
|
||||||
|
"--pipeline-type", str(p.get("pipeline_type", "1024_cascade")),
|
||||||
|
"--seed", str(p.get("seed", 0)),
|
||||||
|
"--texture-size", "2048",
|
||||||
|
"--force",
|
||||||
|
]
|
||||||
|
if p.get("steps"):
|
||||||
|
cmd += ["--steps", str(p["steps"])]
|
||||||
|
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["HF_HUB_DISABLE_XET"] = "1"
|
||||||
|
|
||||||
|
print("+", " ".join(cmd), flush=True)
|
||||||
|
res = subprocess.run(cmd, cwd=str(FORK), stdout=sys.stdout,
|
||||||
|
stderr=subprocess.STDOUT, env=env)
|
||||||
|
if res.returncode != 0:
|
||||||
|
sys.exit(res.returncode)
|
||||||
|
|
||||||
|
glbs = sorted(outdir.rglob("candidate_pbr.glb")) or sorted(outdir.rglob("*.glb"))
|
||||||
|
if not glbs:
|
||||||
|
print("ERROR: no GLB produced")
|
||||||
|
sys.exit(1)
|
||||||
|
stem = Path(a.input[0]).stem
|
||||||
|
outputs = [{"path": str(glbs[0]), "name": f"trellis2mlx_{stem}.glb",
|
||||||
|
"meta": {"tool": "trellis2_mlx", "baker": p.get("baker", "vertex")}}]
|
||||||
|
(outdir / "result.json").write_text(json.dumps({"outputs": outputs}))
|
||||||
|
print("done:", glbs[0], flush=True)
|
||||||
Loading…
Reference in New Issue
Block a user