data audit week: texture-swap bug + colour-space convention found and fixed · v12 restarted on fixed data (S1 done, S2 at 29–45k) · text-to-3D benchmark closed out
weeklydata-auditv12S1S2text-to-3D
TL;DR
Two silent data defects found and fixed this week. (1) 45% of TexVerse and 30% of SketchfabV1 condition renders showed another asset's texture (Blender persistent-data cache bug) — 461k assets flagged, 313k re-rendered, 309k re-captioned. (2) Textureless materials store their baseColorFactor as linear light but are read as sRGB, so their GT colours are darker and more saturated than the input render — 97k latents repaired. Both fixes are pointer-manifest based and fully revertible.
v12 restarted from scratch on the fixed data. Stage 1 (connector-only, 26k) finished for all three towers; Stage 2 (full fine-tune, 106k) is at shape 45k / tex 45k / SS 29k. The tex tower's image path reached parity with the s3_t50b reference by S2 10k; SS text alignment (ULIP rel. GT) climbed 0.86 → 0.975.
Text-to-3D benchmark finalised (7 models, 47 prompts, UV bug fixed): roadv1 beats our previous v10 on every metric and matches TIGON / TRELLIS-text on ULIP-T and Uni3D-T, but trails them on CLIP-T and DINO distance. The gain over v10 comes from the SS tower (paired t ≥ 3), not the geo/tex towers.
Blocking now: the /fsx user quota was cut to 5 TB against 37.8 TB used, so every checkpoint save fails (tex already lost its 45k save). Needs an admin decision before the S2 runs reach their next save.
1 · Text-to-3D benchmark closed out (Sep 1–2)
runs/s3_ss_roadv1 (ROAD-REPA SS, 60k × 256) finished; EMA became the standard eval weight after raw-weight snapshots were shown to oscillate (28k "clearly better" vs 33k "mediocre" tracked the same seed-0 samples).
Text track (eval_suite/text/, 47 SWH prompts, 0/47 in TRELLIS-500K) scored with certified scorers (Uni3D-g 87.3 / ULIP-2 73.2 top-1 on ModelNet40).
UV bug: trimesh flips glTF V to a lower-left origin, nvdiffrast expects upper-left — every atlas rendered as scrambled patches. All render-based metrics before Sep 2 are void; new GLB sources must pass uv_flip_probe.py.
After the fix the earlier "roadv1 improves appearance (KD 48→43)" claim reversed; the 2.2× appearance gap to the baselines sits in the tex tower, not in SS.
Model (n=47)
CLIP-T×100 ↑
ULIP-T ↑
Uni3D-T ↑
Hung-CLIP ↑
KD_dinov2×100 ↓
FD_point ↓
GT ceiling
26.31
0.161
0.264
—
0
0
roadv1 46k-EMA
25.87
0.163
0.273
82.4
70.4
39.3
roadv1 60k-EMA
25.62
0.165
0.280
81.3
77.9
34.7
v10 cascade (previous model)
24.58
0.142
0.244
80.5
71.9
48.6
TIGON
27.97
0.177
0.281
83.7
31.7
44.5
TRELLIS-text-XL
27.69
0.166
0.278
83.4
33.0
37.1
Paired tests: SS-swap (v10 SS → roadv1 SS, same towers) CLIP-T +0.014 (t=3.1), ULIP-T +0.019 (t=3.0), Uni3D-T +0.031 (t=4.1); tower-swap with fixed SS |t| ≤ 1. 60k vs 46k: no significant change.
UV bug evidence: the same GLB rendered before (scrambled atlas patches) and after the V-flip fix. Every render-based metric before Sep 2 was measuring this artefact.roadv1 60k-EMA full chain on held-out assets (GT | text seed 0 | text seed 1 | image). Text→3D produces plausible but differently-posed objects, image→3D tracks GT — the reason text is scored GT-free.
2 · Frozen-DiT ablation and the v12 recipe (Sep 2–4)
runs/s3_ss_roadfrz: roadv1 recipe with the DiT frozen (--flow_tune none, 36.7M trainable), 60k schedule, stopped at 35k. Connector-only reaches the same occupancy IoU as the fully fine-tuned roadv1 at 46k (text 0.110 vs 0.109) and higher ULIP alignment at 20k (0.995 vs 0.931) — the connector, not the DiT, carries most of the early gain.
Literature/config audit (TRELLIS, TRELLIS.2, TIGON, Pixal3D): all use constant LR and EMA 0.9999 → new runs use EMA 0.9999 with warm-up; WSD schedule with forked 6k decays.
v12 plan locked: S1 connector-only 20k+6k @1e-4 → S2 full unfreeze 100k+6k @2e-5 (connector and DiT same LR) → S3 unify 30–40k @1e-5. Mixture per tower: 60% real text / 10% synthetic text / 15% single-image / 15% multi-image (2–4 views, DINO 512).
Conditioning (CondStamp): hashed near-orthogonal view codes (unlimited views), fixed segment codes for DINO/Qwen streams, fixed 2D sin-cos patch positions for Qwen image tokens. Geometry-tower ROAD implemented (Uni3D teacher, tap at block 9).
Eval hygiene: 23,456 eval/held-out assets removed from every training pool (*_train_evalclean.jsonl); roadv1/roadfrz/v10 remain contaminated on the SWH track.
SS tower (EMA, n=24)
roadfrz 20k
roadfrz 35k
roadv1 46k-EMA (full FT)
occ IoU text / image
0.094 / 0.222
0.110 / 0.229
0.109 / 0.231
ULIP rel. GT text / image
0.995 / 1.012
0.939 / 1.002
0.931 / 0.987
retrieval top-1 text / image (random 0.042)
0.375 / 0.333
0.292 / 0.292
—
roadv1 60k-EMA (full fine-tune) vs roadfrz 35k (connector only), same six held-out assets. Visually indistinguishable — the case for starting v12 with a connector-only stage.v12 task mixture per tower: text-heavy (70%) with 2–4-view multi-image at 15%. Same mixture for SS, shape and tex.
Found from a tex-tower probe: the decoded GT texture did not match the condition render for two TexVerse assets. A 100-asset human audit found 15–20% of TexVerse wrong, all with a texture belonging to a different asset.
Root cause: blender_batch_cond.py renders 25 assets per Blender 3.0.1 process with use_persistent_data=True; Cycles caches images by data-block pointer, so after init_scene() frees them, a later asset reuses an earlier asset's pixels (Blender T92980). Reproduced: persistent ON 25/43 wrong, OFF 0/43. The first asset of every chunk is never affected (0% at position 0, 41% at position 5+). pbr latents are correct; captions, VLM scores and aesthetic scores are contaminated.
Full-pool scan (96 GPU workers, ~2 h): chunk order rebuilt for 862k assets; each render compared to its own decoded GT and to the GT of same-chunk predecessors with a lighting-robust 32×32 chromaticity histogram. SWAP if a predecessor's GT matches better; MISMATCH if far from own GT; plus a strict p85 rule (user's choice: "rather re-render good assets than let a bad one through") and a pixel-level rule for assets without chunk order.
Tally: 281,900 confirmed bad → 461,094 flagged with strict rules; 286k re-renderable (source GLBs on hand), ~153k excluded only (SWH / ObjaverseXL sources unavailable). Eval sets were contaminated too (val200 36, test200 29, sketchfab_val200 45, sketchfab_test200 51) and were re-rendered first.
Re-render: one Blender process per asset, persistent ON (verified pixel-identical to OFF, 1.7× faster); 6 nodes × 16 workers, 11–13k assets/h, CPU-bound (Blender's GPU utilisation 5–45%). 313,194 assets re-rendered into renders_cond_refix in ~26 h.
Acceptance: new render vs GT still mismatched for TexVerse 9.4% and SketchfabV1 24.3% — traced to the colour-space convention below, not to rendering.
Re-caption: Qwen3.6-27B holistic + texture captions for 309,337 re-rendered assets (48 vLLM shards, ~1.5 h per pass, parse failures 16 / 618k).
Subset
with GT
confirmed SWAP+MISMATCH
note
TexVerse (chunk-indexed)
324,806
146,522 (45%)
re-rendered
SketchfabV1 (chunk-indexed)
349,422
104,729 (30%)
re-rendered
SWH
301,928
15,966 (5.3%)
own-GT rule only (recall ~55%); excluded
ObjaverseXL github / sketchfab
150,583 / 60,288
8,243 / 4,708 (5.5 / 7.8%)
excluded
TexVerse old route, ABO/HSSD/Toys4k
109,000 / ~14k
1,393 / 409
excluded
Share of GT-bearing assets flagged per subset. Dark = confirmed swap/mismatch; light = extra assets caught by the strict p85 rule, mostly good ones re-rendered on purpose. Chunk-indexed subsets are 6–9× worse because only they had chunk order to catch swaps.Reproduction: the same chunk rendered with persistent data ON (top) vs OFF (bottom). ON shows an earlier asset's texture; OFF matches the source.Spot check of SWAP verdicts: condition render | own decoded GT | GT of the alleged predecessor asset. The render matches the predecessor, not itself (23/24 sampled verdicts confirmed).Before/after for re-rendered assets: old render | decoded GT | new per-asset render. The new render matches GT.
4 · Second finding: flat-colour materials stored in linear light (Sep 6)
Acceptance leftovers were all textureless materials. o-voxel/…/volumetic_attr.py:458 writes textured colours as sRGB bytes but writes baseColorFactor raw (glTF spec: factor is linear, texture is sRGB) — so flat-coloured parts decode darker and more saturated than any renderer shows them (orange input → deep-red GT).
Official TRELLIS.2-4B reproduces the bias (4/5 coloured all-flat assets generate too dark/saturated); no GitHub issue exists — it is a toolkit convention, not our bug.
Fix (user's tier A): decode → linear→sRGB on base colour → re-encode with the frozen tex encoder (coords identical, 8/8 pilot exact). All-flat assets fixed in full (68k); mixed assets fixed per material cluster with a render judge (63k; validation recall 77%, 13% partial false edits on textured assets). SWH/ObjaverseXL (no sources) left as-is. 97,192 repaired latents in trellis2/_flatfix/.
Revertible by construction: no file moved. *_train_texfixed.jsonl points renders/captions at the re-rendered set and drops non-re-renderable bad assets; *_train_texfixed_ff.jsonl additionally points pbr latents at the repaired ones. Revert = switch manifest.
Manifest (_ff)
kept
dropped
renders repointed
pbr repointed
pool1800k
1,469,650
174,748
267,465
87,375
pool800k_pbr
554,353
121,416
85,778
25,092
pool400k
346,625
28,743
85,504
—
Colour-space sheet: old render | decoded GT | new render | factor interpreted as sRGB | factor raw. GT equals the raw factor to ±1; every renderer shows the sRGB-interpreted colour.Flat-fix pilot on 8 assets: condition render | GT before | GT after linear→sRGB re-encode. Fixed GT now matches the input colour; voxel coordinates unchanged.Acceptance leftovers after re-render (old render | GT | new render): the residual mismatches are flat-coloured parts, i.e. the convention issue, not swapped textures.
5 · v12 Stage 1 on fixed data (Sep 6–7)
v12s1b: three towers from scratch (init none) on the _texfixed_ff mixes; connector-only, LR 1e-4, 20k stable + 6k cosine, eff. batch 256, 2 nodes per tower. SS 2.2–2.6 s/it (ROAD), shape/tex 1.7–1.9 s/it. All three reached 26k by Sep 7 midday.
Shape image path improved monotonically through S1 (surf_dev 0.057 → 0.028, already below the t50b reference at 0.050). Tex image path plateaued at ~0.23 vs t50b 0.15 — a frozen DiT cannot fix appearance. Text paths of both towers stayed 2–3× worse than image paths.
SS at 5k on fixed data vs the same recipe on old data: ULIP text 0.860 vs 0.804, image 0.997 vs 0.967 — the only same-step comparison we have of clean vs dirty data.
Held-out n=16/24 probes swing ±0.02 between checkpoints; trends are read from ≥3 points, single checkpoints are not conclusions.
Tower probes across S1 (connector-only) and S2 (full unfreeze): shape surf_dev and tex chroma_dev on viz16 (medians). Tex image path drops to t50b parity within 10k steps of unfreezing; shape image path oscillates around the reference; text paths remain the weak point.S1 end: all-new full chain (SS 20k → shape/tex 26k), GT | text seed 0 | text seed 1 | image. Geometry follows the prompt; colours of textureless parts are flatter than GT.Tex tower at S1 26k (input | GT | text | image | t50b reference). Image-conditioned colours are close but desaturated; text-conditioned colours are the outlier.
6 · v12 Stage 2 full fine-tune (Sep 7–8, running)
v12s2: init from S1 checkpoint-20000_ema (EMA overlaid onto model.safetensors, since init only reads that file), --flow_tune full, LR 2e-5, 100k stable + 6k decay, save every 5k (limit 6), EMA 0.9999. Shape/tex bs8 × GA2 with elastic GC 0.6 (0.75 OOMed), 2.4–2.6 s/it; SS bs4 × GA4 without GC (ROAD hook incompatible with GC; tap-safe GC fits but is 4–5× slower), 3.05–3.5 s/it.
Status Sep 8 23:00: shape 45k, tex 45k (resumed from 40k after the quota failure), SS 29k. ETA to 106k: shape/tex ~Sep 10, SS ~Sep 11; the 60k fork-decay checkpoint is due in ~12 h.
Readings so far (EMA): tex image reaches t50b parity by S2 10k and holds (0.135–0.154 vs 0.150); shape image 0.037–0.063 around the 0.050 reference, but val32 shows 0.083 vs 0.063 at 40k (single point); SS ULIP text 0.896 → 0.975 with retrieval top-1 0.333; occupancy IoU flat (text ~0.10, image ~0.22). Text paths of shape/tex are not yet better than the S1 end.
SS tower (24 held-out, EMA)
S1 20k
S1 26k
S2 5k
S2 10k
S2 20k
occ IoU text / image
0.097 / 0.214
0.104 / 0.217
0.103 / 0.223
0.108 / 0.228
0.101 / 0.224
ULIP rel. GT text / image
0.931 / 0.991
—
0.896 / 0.981
0.928 / 0.969
0.975 / 0.971
retrieval top-1 text / image
0.250 / 0.292
—
0.292 / 0.333
0.292 / 0.333
0.333 / 0.292
SS tower readouts across S1 and S2. Occupancy IoU is flat; ULIP text alignment keeps climbing after unfreezing and now nearly matches the image path.S2 full chain (SS 20k → shape/tex 30k), GT | text s0 | text s1 | image. Compared with the S1 chain above, textures are more saturated and closer to GT on the image path.Shape tower at S2 40k (input | GT | text | image | t50b). Image path comparable to the reference tower; text path plausible but coarser.Tex tower at S2 40k. Image path now matches t50b in colour fidelity; text path still guesses colours.
7 · Incidents and lessons
Disk: /fsx/home hit 100% (quota 39.65/40 TB) during the 15k saves — 2.2 TB of TexVerse re-download copies deleted, save_total_limit 24 → 6, half-written checkpoints quarantined. Then the user quota was cut to 5 TB (37.8 TB used): tex lost its 45k save; SS/shape will fail at 30k/50k unless resolved.
OOM: shape at 1610 (GC 0.75 → 0.6), tex at 11.5k (→ 0.6), SS at start (bs8 → bs4×GA4). GC experiment on SS cost 2.5 h.
Shared tmux server on the agent node restarted and silently killed the reservation heartbeat and two towers' srun clients; the benchmark service then took the SS GPUs. Launchers moved to node-local tmux per rank; heartbeat now self-restarts from the monitor.
Hold rotation: SS died on a 7-day hold timeout and waited 3 h for permission to restart; rule now: re-point to the new hold and restart without asking. Likewise S2 waited 4 h for a go-ahead that the plan already gave.
pkill -f inside srun bash -c kills its own step (three times this week) — kills now go through script files.
Feeder crash on an unknown subset idled 96 render workers for 12 h overnight; fixed with subset skip, HF timeouts and orphan reclaim.
Agent shells (claude/codex) moved from the login node to compute nodes; cluster skill updated (§0.1.2).
Open questions
Quota: restore 40 TB or shrink to 5 TB (would need deleting ~33 TB). Candidates for cleanup: runs/s3_*_v12s1 (150 GB), S1b intermediate checkpoints (~400 GB), s3_ss_roadfrz (45 GB), runs/_broken.
Is the shape image-path gap on val32 (0.083 vs 0.063) a trend? Needs the 50k point; formal val200 evaluation at the 60k fork.
Will the text paths of shape/tex recover during S2, or does text need its own fix (caption weighting, more epochs)?
Flat-colour convention on SWH/ObjaverseXL (no sources) — leave, or re-voxelise from decoded slats? File a TRELLIS.2 issue?
~153k non-re-renderable swapped assets remain excluded; ~307k assets without GT were never judged.
No ablation yet of fixed vs unfixed data at equal steps beyond the SS 5k point.
WilD3DGen weekly · Sep 1 – Sep 8, 2026 · probes on viz16 (n=16) and 24 held-out assets are trend indicators, not formal results (formal = val200 / test200).