From fb13e67acbc7d7dd2974a456fcb134966c47cee0 Mon Sep 17 00:00:00 2001 From: skal Date: Fri, 27 Mar 2026 07:59:00 +0100 Subject: fix(cnn_v3): remove dec0 ReLU, load FiLM MLP at runtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two bugs blocking training convergence: 1. dec0 ReLU before sigmoid constrained output to [0.5,1.0] — network could never produce dark pixels. Removed F.relu in train_cnn_v3.py and max(0,…) in cnn_v3_dec0.wgsl. Test vectors regenerated. 2. set_film_params() used hardcoded heuristics instead of the trained MLP. Added CNNv3FilmMlp struct + load_film_mlp() to cnn_v3_effect.h/.cc. MLP auto-loaded from ASSET_WEIGHTS_CNN_V3_FILM_MLP at construction; Linear(5→16)→ReLU→Linear(16→72) runs CPU-side each frame. 36/36 tests pass. Parity max_err=4.88e-4 unchanged. handoff(Gemini): retrain from scratch — needs ≥50 samples (currently 11). See cnn_v3/docs/HOWTO.md §2-3. --- PROJECT_CONTEXT.md | 4 +- TODO.md | 9 ++-- cnn_v3/docs/CNN_V3.md | 8 ++- cnn_v3/docs/HOWTO.md | 8 ++- cnn_v3/shaders/cnn_v3_dec0.wgsl | 2 +- cnn_v3/src/cnn_v3_effect.cc | 76 ++++++++++++++++++++++------ cnn_v3/src/cnn_v3_effect.h | 22 +++++++- cnn_v3/test_vectors.h | 64 +++++++++++------------ cnn_v3/tools/weights.js | 4 +- cnn_v3/training/gen_test_vectors.py | 8 +-- cnn_v3/training/train_cnn_v3.py | 7 ++- doc/COMPLETED.md | 4 ++ workspaces/main/weights/cnn_v3_film_mlp.bin | Bin 5280 -> 5280 bytes workspaces/main/weights/cnn_v3_weights.bin | Bin 15656 -> 15656 bytes 14 files changed, 147 insertions(+), 69 deletions(-) diff --git a/PROJECT_CONTEXT.md b/PROJECT_CONTEXT.md index 9a710f1..bffbeb8 100644 --- a/PROJECT_CONTEXT.md +++ b/PROJECT_CONTEXT.md @@ -36,7 +36,7 @@ - **Audio:** Sample-accurate sync. Zero heap allocations per frame. Variable tempo. OLA-IDCT synthesis (v2 .spec): Hann analysis window, rectangular synthesis, 50% overlap, click-free. V1 (raw DCT-512) preserved for generated notes. .spec files regenerated as v2. - **Shaders:** Parameterized effects (UniformHelper, .seq syntax). Beat-synchronized animation support (`beat_time`, `beat_phase`). Modular WGSL composition with ShaderComposer. 27 shared common shaders (math, render, compute). Reusable snippets: `render/scratch_lines`, `render/ntsc_common` (NTSC signal processing, RGB and YIQ input variants via `sample_ntsc_signal` hook), `math/color` (YIQ/NTSC), `math/color_c64` (C64 palette, Bayer dither, border animation). - **3D:** Hybrid SDF/rasterization with BVH. Binary scene loader. Blender pipeline. -- **Effects:** CNN post-processing: CNNEffect (v1) and CNNv2Effect operational. CNN v2: sigmoid activation, storage buffer weights (~3.2 KB), 7D static features, dynamic layers. Training stable, convergence validated. **CNN v3 Phases 1–7 complete** + runtime pipeline operational: `GBufferEffect` (MRT raster + sphere impostors + SDF shadow pass) → `GBufDeferredEffect` (albedo×diffuse debug view) wired in `cnn_v3_test` sequence. Shared snippets: `math/normal` (oct encode/decode), `ray_sphere`. Parity validated: max_err=4.88e-4. See `cnn_v3/docs/HOWTO.md`. +- **Effects:** CNN post-processing: CNNEffect (v1) and CNNv2Effect operational. CNN v2: sigmoid activation, storage buffer weights (~3.2 KB), 7D static features, dynamic layers. Training stable, convergence validated. **CNN v3 Phases 1–9 complete** + runtime pipeline operational: `GBufferEffect` (MRT raster + sphere impostors + SDF shadow pass) → `GBufDeferredEffect` (albedo×diffuse debug view) wired in `cnn_v3_test` sequence. Two training bugs fixed: dec0 ReLU removed (full [0,1] output range), FiLM MLP loaded from `.bin` at runtime. Parity validated: max_err=4.88e-4. See `cnn_v3/docs/HOWTO.md`. - **Tools:** CNN test tool operational. Texture readback utility functional. Timeline editor (web-based, beat-aligned, audio playback). - **Build:** Asset dependency tracking. Size measurement. Hot-reload (debug-only). WSL (Windows 10) supported: native Linux build and cross-compile to `.exe` via `mingw-w64`. - **Sequence:** DAG-based effect routing with explicit node system. Python compiler with topological sort and ping-pong optimization. 12 effects operational (Passthrough, Placeholder, GaussianBlur, Heptagon, Particles, RotatingCube, Hybrid3D, Flash, PeakMeter, Scene1, Scene2, Scratch). Effect times are absolute (seq_compiler adds sequence start offset). See `doc/SEQUENCE.md`. @@ -46,7 +46,7 @@ ## Next Up -**Active:** CNN v3 shadow ✅ fixed — restore full scene, then training pass. Spectral Brush Editor. +**Active:** CNN v3 training bugs fixed ✅ — retrain from scratch with more data (≥50 samples). Spectral Brush Editor. **Ongoing:** Test infrastructure maintenance (38/38 passing) **Future:** CNN v3 training pass, size optimization (64k target) diff --git a/TODO.md b/TODO.md index eb530ec..4c22212 100644 --- a/TODO.md +++ b/TODO.md @@ -71,15 +71,18 @@ Ongoing shader code hygiene for granular, reusable snippets. ## CNN v3 — U-Net + FiLM [IN PROGRESS] -**Design:** `cnn_v3/docs/CNN_V3.md` | All phases 1–7 complete. Runtime pipeline operational. +**Design:** `cnn_v3/docs/CNN_V3.md` | All phases 1–9 complete. Runtime pipeline operational. **Current pipeline:** `GBufferEffect` → `GBufDeferredEffect` → `GBufViewEffect` → sink -**Shadow pass status:** ✅ Fixed and re-enabled. Cube + sphere shadows correct. Pulsating sphere scale confirmed correct end-to-end. Scene is currently simplified (1 cube + 1 sphere, 1 light) for debugging. +**Training bugs fixed (2026-03-27):** +- ✅ dec0 ReLU removed: output now spans full [0,1] range (was stuck ≥0.5) +- ✅ FiLM MLP loaded from `cnn_v3_film_mlp.bin` at runtime (was hardcoded heuristics) **Active work:** - [ ] Restore full scene in `GBufferEffect::set_scene()` (20 cubes + 4 spheres, 2 lights) -- [ ] Run first real training pass — see `cnn_v3/docs/HOWTO.md` §3 +- [ ] Collect ≥50 training samples (currently 11) — see `cnn_v3/docs/HOWTO.md` §2 +- [ ] Retrain from scratch — see `cnn_v3/docs/HOWTO.md` §3 **Pending (lower priority):** - [ ] GBufferEffect: Pass 3 transparency (transp=0 placeholder) diff --git a/cnn_v3/docs/CNN_V3.md b/cnn_v3/docs/CNN_V3.md index a197a1d..081adf8 100644 --- a/cnn_v3/docs/CNN_V3.md +++ b/cnn_v3/docs/CNN_V3.md @@ -19,7 +19,7 @@ CNN v3 is a next-generation post-processing effect using: - Training from both Blender renders and real photos - Strict test framework: per-pixel bit-exact validation across all implementations -**Status:** Phases 1–7 complete. Architecture upgraded to enc_channels=[8,16] for improved capacity. Parity test and runtime updated. Next: training pass. +**Status:** Phases 1–9 complete. Architecture upgraded to enc_channels=[8,16]. Two training bugs fixed (dec0 ReLU removed; FiLM MLP loaded at runtime). Parity validated. Next: retrain from scratch with more data. --- @@ -34,9 +34,13 @@ FiLM is applied **inside each encoder/decoder block**, after each convolution. ### U-Net Block (per level) ``` -input → Conv 3×3 → BN (or none) → FiLM(γ,β) → ReLU → output +enc0/enc1/dec1: input → Conv 3×3 → FiLM(γ,β) → ReLU → output +dec0 (final): input → Conv 3×3 → FiLM(γ,β) → Sigmoid → output ``` +The final decoder layer uses sigmoid directly — **no ReLU** — so the network +can output the full [0,1] range. ReLU before sigmoid would clamp to [0.5,1.0]. + FiLM at level `l`: ``` FiLM(x, γ_l, β_l) = γ_l ⊙ x + β_l (per-channel affine) diff --git a/cnn_v3/docs/HOWTO.md b/cnn_v3/docs/HOWTO.md index ff8793f..67f7931 100644 --- a/cnn_v3/docs/HOWTO.md +++ b/cnn_v3/docs/HOWTO.md @@ -371,7 +371,9 @@ cnn_v3_effect->set_film_params( style_p0, style_p1); ``` -FiLM γ/β default to identity (γ=1, β=0) until `train_cnn_v3.py` produces a trained MLP. +FiLM MLP weights are auto-loaded from `ASSET_WEIGHTS_CNN_V3_FILM_MLP` at construction. +The MLP forward pass (`Linear(5→16)→ReLU→Linear(16→72)`) runs CPU-side in `set_film_params()`. +Falls back to identity (γ=1, β=0) if no `.bin` is present. --- @@ -407,6 +409,7 @@ Test vectors generated by `cnn_v3/training/gen_test_vectors.py` (PyTorch referen | 7 — G-buffer visualizer (C++) | ✅ Done | GBufViewEffect, 36/36 tests pass | | 8 — Architecture upgrade [8,16] | ✅ Done | enc_channels=[8,16], multi-scale loss, 16ch textures split into lo/hi pairs | | 7 — Sample loader (web tool) | ✅ Done | "Load sample directory" in cnn_v3/tools/ | +| 9 — Training bug fixes | ✅ Done | dec0 ReLU removed (output unblocked); FiLM MLP loaded at runtime | --- @@ -428,7 +431,8 @@ The common snippet provides `get_w()` and `unpack_8ch()`. - AvgPool 2×2 for downsampling (exact, deterministic) - Nearest-neighbor for upsampling (integer `coord / 2`) - Skip connections: channel concatenation (not add) -- FiLM applied after conv+bias, before ReLU: `max(0, γ·x + β)` +- FiLM applied after conv+bias, before ReLU: `max(0, γ·x + β)` (enc0/enc1/dec1) +- dec0 final layer: FiLM then sigmoid directly — **no ReLU** (`sigmoid(γ·x + β)`) - No batch norm at inference - Weight layout: OIHW (out × in × kH × kW), biases after conv weights diff --git a/cnn_v3/shaders/cnn_v3_dec0.wgsl b/cnn_v3/shaders/cnn_v3_dec0.wgsl index 617b5a2..79fd837 100644 --- a/cnn_v3/shaders/cnn_v3_dec0.wgsl +++ b/cnn_v3/shaders/cnn_v3_dec0.wgsl @@ -64,7 +64,7 @@ fn dec0_main(@builtin(global_invocation_id) id: vec3u) { } } } - let v = max(0.0, params.gamma[o] * sum + params.beta[o]); + let v = params.gamma[o] * sum + params.beta[o]; out[o] = 1.0 / (1.0 + exp(-v)); } diff --git a/cnn_v3/src/cnn_v3_effect.cc b/cnn_v3/src/cnn_v3_effect.cc index dc26751..e576ceb 100644 --- a/cnn_v3/src/cnn_v3_effect.cc +++ b/cnn_v3/src/cnn_v3_effect.cc @@ -187,6 +187,13 @@ CNNv3Effect::CNNv3Effect(const GpuContext& ctx, if (weights_data && weights_size == kWeightsBufBytes) { upload_weights(ctx_.queue, weights_data, (uint32_t)weights_size); } + + size_t mlp_size = 0; + const void* mlp_data = + GetAsset(AssetId::ASSET_WEIGHTS_CNN_V3_FILM_MLP, &mlp_size); + if (mlp_data) { + load_film_mlp(mlp_data, (uint32_t)mlp_size); + } } // --------------------------------------------------------------------------- @@ -219,28 +226,67 @@ void CNNv3Effect::upload_weights(WGPUQueue queue, const void* data, wgpuQueueWriteBuffer(queue, weights_buf_.buffer, 0, data, size_bytes); } +void CNNv3Effect::load_film_mlp(const void* data, uint32_t size_bytes) { + if (size_bytes != sizeof(CNNv3FilmMlp)) return; + memcpy(&mlp_, data, sizeof(CNNv3FilmMlp)); + mlp_loaded_ = true; +} + void CNNv3Effect::set_film_params(const CNNv3FiLMParams& fp) { - const float a = fp.audio_intensity; - const float b = fp.beat_phase; + if (!mlp_loaded_) { + // Identity FiLM (γ=1, β=0) — no learned conditioning available. + return; + } + + // cond[5] = {beat_phase, beat_norm, audio_intensity, style_p0, style_p1} + const float cond[5] = {fp.beat_phase, fp.beat_norm, fp.audio_intensity, + fp.style_p0, fp.style_p1}; + // Layer 0: Linear(5→16) + ReLU + float h[16]; + for (int j = 0; j < 16; ++j) { + float s = mlp_.l0_b[j]; + for (int i = 0; i < 5; ++i) s += mlp_.l0_w[j * 5 + i] * cond[i]; + h[j] = s > 0.f ? s : 0.f; + } + + // Layer 1: Linear(16→72) + // Output split: g_enc0(8)|b_enc0(8)|g_enc1(16)|b_enc1(16)|g_dec1(8)|b_dec1(8)|g_dec0(4)|b_dec0(4) + float film[72]; + for (int j = 0; j < 72; ++j) { + float s = mlp_.l1_b[j]; + for (int i = 0; i < 16; ++i) s += mlp_.l1_w[j * 16 + i] * h[i]; + film[j] = s; + } + + const float* p = film; for (int i = 0; i < 4; ++i) { - enc0_params_.gamma_lo[i] = 1.0f + a * 0.5f; - enc0_params_.gamma_hi[i] = 1.0f + a * 0.5f; - enc0_params_.beta_lo[i] = b * 0.1f; - enc0_params_.beta_hi[i] = b * 0.1f; + enc0_params_.gamma_lo[i] = p[i]; + enc0_params_.gamma_hi[i] = p[i + 4]; } - for (int i = 0; i < 16; ++i) { - enc1_params_.gamma[i] = 1.0f + a * 0.3f; - enc1_params_.beta[i] = fp.beat_norm * 0.1f; + p += 8; + for (int i = 0; i < 4; ++i) { + enc0_params_.beta_lo[i] = p[i]; + enc0_params_.beta_hi[i] = p[i + 4]; + } + p += 8; + for (int i = 0; i < 16; ++i) enc1_params_.gamma[i] = p[i]; + p += 16; + for (int i = 0; i < 16; ++i) enc1_params_.beta[i] = p[i]; + p += 16; + for (int i = 0; i < 4; ++i) { + dec1_params_.gamma_lo[i] = p[i]; + dec1_params_.gamma_hi[i] = p[i + 4]; } + p += 8; for (int i = 0; i < 4; ++i) { - dec1_params_.gamma_lo[i] = 1.0f + fp.style_p0 * 0.5f; - dec1_params_.gamma_hi[i] = 1.0f + fp.style_p0 * 0.5f; - dec1_params_.beta_lo[i] = fp.style_p1 * 0.1f; - dec1_params_.beta_hi[i] = fp.style_p1 * 0.1f; - dec0_params_.gamma[i] = 1.0f + fp.style_p0 * 0.5f; - dec0_params_.beta[i] = fp.style_p1 * 0.1f; + dec1_params_.beta_lo[i] = p[i]; + dec1_params_.beta_hi[i] = p[i + 4]; } + p += 8; + for (int i = 0; i < 4; ++i) dec0_params_.gamma[i] = p[i]; + p += 4; + for (int i = 0; i < 4; ++i) dec0_params_.beta[i] = p[i]; } // --------------------------------------------------------------------------- diff --git a/cnn_v3/src/cnn_v3_effect.h b/cnn_v3/src/cnn_v3_effect.h index 070f988..589680c 100644 --- a/cnn_v3/src/cnn_v3_effect.h +++ b/cnn_v3/src/cnn_v3_effect.h @@ -7,7 +7,7 @@ // enc1: Conv(8→16, 3×3) + FiLM16 + ReLU H/2×W/2 2× rgba32uint // bottleneck: Conv(16→16, 3×3, dil=2) + ReLU H/4×W/4 2× rgba32uint // dec1: Conv(32→8, 3×3) + FiLM8 + ReLU H/2×W/2 rgba32uint -// dec0: Conv(16→4, 3×3) + FiLM4 + ReLU + sig H×W rgba16float +// dec0: Conv(16→4, 3×3) + FiLM4 + sig H×W rgba16float // // Inputs: feat_tex0, feat_tex1 (rgba32uint, 20-channel G-buffer) // Output: output_tex (rgba16float, 4-channel RGBA) @@ -97,6 +97,17 @@ struct CNNv3FiLMParams { float style_p1 = 0.0f; // user-defined style param }; +// FiLM MLP weights: Linear(5→16)→ReLU→Linear(16→72). +// Loaded from cnn_v3_film_mlp.bin (1320 f32 = 5280 bytes). +// Layout: l0_w(80) | l0_b(16) | l1_w(1152) | l1_b(72), all row-major f32. +struct CNNv3FilmMlp { + float l0_w[16 * 5]; // (16, 5) row-major + float l0_b[16]; + float l1_w[72 * 16]; // (72, 16) row-major + float l1_b[72]; +}; +static_assert(sizeof(CNNv3FilmMlp) == 1320 * 4, "CNNv3FilmMlp size mismatch"); + class CNNv3Effect : public Effect { public: CNNv3Effect(const GpuContext& ctx, const std::vector& inputs, @@ -111,9 +122,13 @@ class CNNv3Effect : public Effect { // Update FiLM conditioning; call before render() each frame. void set_film_params(const CNNv3FiLMParams& fp); - // Upload packed-f16 weights (kWeightsBufBytes bytes of u32 pairs). + // Upload packed-f16 conv weights (kWeightsBufBytes bytes of u32 pairs). void upload_weights(WGPUQueue queue, const void* data, uint32_t size_bytes); + // Load FiLM MLP weights from cnn_v3_film_mlp.bin (1320 f32 = 5280 bytes). + // Must be called before set_film_params() for learned conditioning. + void load_film_mlp(const void* data, uint32_t size_bytes); + private: // Intermediate node names (prefixed from output[0]) std::string node_enc0_; @@ -156,4 +171,7 @@ class CNNv3Effect : public Effect { void create_pipelines(); void update_bind_groups(NodeRegistry& nodes); + + CNNv3FilmMlp mlp_{}; + bool mlp_loaded_ = false; }; diff --git a/cnn_v3/test_vectors.h b/cnn_v3/test_vectors.h index 647b84e..080d295 100644 --- a/cnn_v3/test_vectors.h +++ b/cnn_v3/test_vectors.h @@ -668,37 +668,37 @@ static const uint16_t kCnnV3ExpectedDec1U16[128] = { // 256 uint16 values (raw f16 bits) static const uint16_t kCnnV3ExpectedOutputU16[256] = { - 0x3800u, 0x3800u, 0x3a22u, 0x3800u, 0x3800u, 0x3800u, 0x3b3du, 0x391fu, - 0x3800u, 0x3800u, 0x3b8au, 0x3979u, 0x3800u, 0x3800u, 0x3b53u, 0x38ceu, - 0x3800u, 0x3800u, 0x3af2u, 0x38a3u, 0x3800u, 0x3800u, 0x3b4au, 0x389du, - 0x3800u, 0x3898u, 0x3addu, 0x3800u, 0x3800u, 0x3800u, 0x3accu, 0x3800u, - 0x3800u, 0x3800u, 0x3b36u, 0x3800u, 0x3800u, 0x3977u, 0x3b7du, 0x39a3u, - 0x3800u, 0x3800u, 0x3b90u, 0x3971u, 0x3800u, 0x3800u, 0x3bceu, 0x38e1u, - 0x3800u, 0x3800u, 0x3be5u, 0x3925u, 0x3800u, 0x3800u, 0x3ac5u, 0x38bbu, - 0x3800u, 0x3925u, 0x3b70u, 0x3a5fu, 0x3800u, 0x3800u, 0x3aeeu, 0x3800u, - 0x3800u, 0x3800u, 0x3afeu, 0x3800u, 0x3800u, 0x3952u, 0x3bb0u, 0x39fbu, - 0x3800u, 0x3800u, 0x3b64u, 0x3800u, 0x3800u, 0x39e9u, 0x3bb4u, 0x38c8u, - 0x3800u, 0x3852u, 0x3bd6u, 0x396au, 0x3800u, 0x3808u, 0x3bdfu, 0x3800u, - 0x3800u, 0x3826u, 0x3bc8u, 0x3928u, 0x3800u, 0x3800u, 0x3b10u, 0x38e7u, - 0x3800u, 0x3800u, 0x3baau, 0x3800u, 0x3800u, 0x3800u, 0x3b11u, 0x3a64u, - 0x3800u, 0x3800u, 0x3bccu, 0x3b12u, 0x3800u, 0x3800u, 0x3bd3u, 0x3a4fu, - 0x3800u, 0x3800u, 0x3b8bu, 0x3923u, 0x3800u, 0x3800u, 0x3b90u, 0x3927u, - 0x3800u, 0x3800u, 0x3ba9u, 0x38d6u, 0x3800u, 0x3800u, 0x3b40u, 0x3800u, - 0x3800u, 0x3800u, 0x3b85u, 0x3800u, 0x3800u, 0x3800u, 0x3bd1u, 0x3800u, - 0x3800u, 0x3882u, 0x3bc3u, 0x3800u, 0x3800u, 0x3800u, 0x3b2cu, 0x3a92u, - 0x3800u, 0x3800u, 0x3baeu, 0x3816u, 0x3800u, 0x3800u, 0x3bb0u, 0x3a63u, - 0x3800u, 0x3800u, 0x3b2bu, 0x3acdu, 0x3800u, 0x3800u, 0x3ae6u, 0x393eu, - 0x3800u, 0x3800u, 0x3b7bu, 0x3800u, 0x3800u, 0x3800u, 0x3bc9u, 0x3999u, - 0x3800u, 0x3800u, 0x3bbau, 0x3863u, 0x3800u, 0x3800u, 0x3bafu, 0x392du, - 0x3800u, 0x3800u, 0x3b65u, 0x3853u, 0x3800u, 0x3800u, 0x3b82u, 0x3800u, - 0x3800u, 0x3800u, 0x3b73u, 0x3953u, 0x3800u, 0x3800u, 0x3a01u, 0x3800u, - 0x3800u, 0x3800u, 0x3b96u, 0x3800u, 0x3800u, 0x3800u, 0x3b3du, 0x3800u, - 0x3800u, 0x3800u, 0x3b88u, 0x3b20u, 0x3800u, 0x3800u, 0x3ae2u, 0x395au, - 0x3803u, 0x38f7u, 0x3b09u, 0x3a3eu, 0x3800u, 0x3800u, 0x3b58u, 0x399cu, - 0x3800u, 0x3825u, 0x3a2fu, 0x3a2fu, 0x38bfu, 0x393eu, 0x38d7u, 0x39e9u, - 0x3870u, 0x3800u, 0x3b09u, 0x3800u, 0x3800u, 0x3800u, 0x3a92u, 0x3800u, - 0x3800u, 0x3a3au, 0x3800u, 0x3a01u, 0x38eau, 0x3945u, 0x3939u, 0x3800u, - 0x3800u, 0x3801u, 0x3856u, 0x3800u, 0x3800u, 0x3800u, 0x385du, 0x3829u, - 0x3800u, 0x384du, 0x3828u, 0x383au, 0x3800u, 0x380bu, 0x38beu, 0x3800u, + 0x36f2u, 0x3630u, 0x3a22u, 0x365cu, 0x3470u, 0x3679u, 0x3b3du, 0x391fu, + 0x31a8u, 0x3743u, 0x3b8au, 0x3979u, 0x2f33u, 0x365fu, 0x3b53u, 0x38ceu, + 0x3468u, 0x3299u, 0x3af2u, 0x38a3u, 0x3587u, 0x35d0u, 0x3b4au, 0x389du, + 0x3452u, 0x3898u, 0x3addu, 0x3588u, 0x3542u, 0x35c3u, 0x3accu, 0x3603u, + 0x35eeu, 0x3272u, 0x3b36u, 0x36ccu, 0x32a6u, 0x3977u, 0x3b7du, 0x39a3u, + 0x31a5u, 0x37a6u, 0x3b90u, 0x3971u, 0x2cd7u, 0x3638u, 0x3bceu, 0x38e1u, + 0x2d5du, 0x34a9u, 0x3be5u, 0x3925u, 0x2d35u, 0x359eu, 0x3ac5u, 0x38bbu, + 0x3463u, 0x3925u, 0x3b70u, 0x3a5fu, 0x31a7u, 0x367eu, 0x3aeeu, 0x35f2u, + 0x3337u, 0x3527u, 0x3afeu, 0x3403u, 0x2de4u, 0x3952u, 0x3bb0u, 0x39fbu, + 0x2e84u, 0x37f5u, 0x3b64u, 0x3700u, 0x2e32u, 0x39e9u, 0x3bb4u, 0x38c8u, + 0x2d30u, 0x3852u, 0x3bd6u, 0x396au, 0x301du, 0x3808u, 0x3bdfu, 0x3610u, + 0x2d95u, 0x3826u, 0x3bc8u, 0x3928u, 0x2dceu, 0x37cfu, 0x3b10u, 0x38e7u, + 0x2e91u, 0x35e9u, 0x3baau, 0x3695u, 0x2f9bu, 0x365au, 0x3b11u, 0x3a64u, + 0x2d9au, 0x34cau, 0x3bccu, 0x3b12u, 0x314du, 0x3672u, 0x3bd3u, 0x3a4fu, + 0x319fu, 0x370du, 0x3b8bu, 0x3923u, 0x2db3u, 0x351eu, 0x3b90u, 0x3927u, + 0x3002u, 0x36c6u, 0x3ba9u, 0x38d6u, 0x351du, 0x3497u, 0x3b40u, 0x3755u, + 0x36bfu, 0x3646u, 0x3b85u, 0x3628u, 0x321bu, 0x3305u, 0x3bd1u, 0x378au, + 0x2adeu, 0x3882u, 0x3bc3u, 0x3760u, 0x3037u, 0x3765u, 0x3b2cu, 0x3a92u, + 0x2cb2u, 0x3129u, 0x3baeu, 0x3816u, 0x311bu, 0x349du, 0x3bb0u, 0x3a63u, + 0x301eu, 0x37d5u, 0x3b2bu, 0x3acdu, 0x31b9u, 0x3512u, 0x3ae6u, 0x393eu, + 0x315bu, 0x32c8u, 0x3b7bu, 0x354eu, 0x303cu, 0x33f7u, 0x3bc9u, 0x3999u, + 0x3129u, 0x3543u, 0x3bbau, 0x3863u, 0x3464u, 0x33ebu, 0x3bafu, 0x392du, + 0x3325u, 0x30d7u, 0x3b65u, 0x3853u, 0x32a7u, 0x3576u, 0x3b82u, 0x3736u, + 0x2d0du, 0x3511u, 0x3b73u, 0x3953u, 0x31c6u, 0x3578u, 0x3a01u, 0x37afu, + 0x3502u, 0x35e1u, 0x3b96u, 0x3348u, 0x2d61u, 0x33d6u, 0x3b3du, 0x3760u, + 0x3594u, 0x34f5u, 0x3b88u, 0x3b20u, 0x349cu, 0x3670u, 0x3ae2u, 0x395au, + 0x3803u, 0x38f7u, 0x3b09u, 0x3a3eu, 0x34a5u, 0x32e7u, 0x3b58u, 0x399cu, + 0x35aau, 0x3825u, 0x3a2fu, 0x3a2fu, 0x38bfu, 0x393eu, 0x38d7u, 0x39e9u, + 0x3870u, 0x3204u, 0x3b09u, 0x33feu, 0x3550u, 0x347bu, 0x3a92u, 0x3707u, + 0x3553u, 0x3a3au, 0x36a8u, 0x3a01u, 0x38eau, 0x3945u, 0x3939u, 0x34c2u, + 0x35c5u, 0x3801u, 0x3856u, 0x34ebu, 0x34f3u, 0x36bfu, 0x385du, 0x3829u, + 0x37d3u, 0x384du, 0x3828u, 0x383au, 0x3557u, 0x380bu, 0x38beu, 0x349bu, }; diff --git a/cnn_v3/tools/weights.js b/cnn_v3/tools/weights.js index 753eb5e..bebb3f5 100644 --- a/cnn_v3/tools/weights.js +++ b/cnn_v3/tools/weights.js @@ -1,4 +1,4 @@ 'use strict'; // Auto-generated by export_cnn_v3_weights.py --html — do not edit by hand. -const CNN_V3_WEIGHTS_B64='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'; -const CNN_V3_FILM_MLP_B64='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'; +const CNN_V3_WEIGHTS_B64='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'; +const CNN_V3_FILM_MLP_B64='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'; diff --git a/cnn_v3/training/gen_test_vectors.py b/cnn_v3/training/gen_test_vectors.py index 3f81247..96b175a 100644 --- a/cnn_v3/training/gen_test_vectors.py +++ b/cnn_v3/training/gen_test_vectors.py @@ -193,8 +193,8 @@ def dec1_forward(bn, enc1, w, gamma, beta): def dec0_forward(dec1, enc0, w, gamma, beta): """ - NearestUp2x(dec1) + cat(enc0_skip) → Conv(16->4, 3x3, zero-pad) + FiLM + ReLU + sigmoid - → rgba16float (full-res, final output). + NearestUp2x(dec1) + cat(enc0_skip) → Conv(16->4, 3x3, zero-pad) + FiLM + sigmoid + → rgba16float (full-res, final output). No ReLU before sigmoid. dec1: (hH, hW, 8) f32 — half-res enc0: (H, W, 8) f32 — full-res enc0 skip """ @@ -219,8 +219,8 @@ def dec0_forward(dec1, enc0, w, gamma, beta): for kx in range(3): wv = get_w(w, wo, o * DEC0_IN * 9 + i * 9 + ky * 3 + kx) s += wv * fp[ky:ky+H, kx:kx+W, i] - # FiLM + ReLU + sigmoid (matches WGSL dec0 shader) - v = np.maximum(0.0, gamma[o] * s + beta[o]) + # FiLM + sigmoid (matches WGSL dec0 shader — no ReLU before sigmoid) + v = gamma[o] * s + beta[o] out[:, :, o] = 1.0 / (1.0 + np.exp(-v.astype(np.float64))).astype(np.float32) return np.float16(out).astype(np.float32) # rgba16float boundary diff --git a/cnn_v3/training/train_cnn_v3.py b/cnn_v3/training/train_cnn_v3.py index e48f684..fa0d2e2 100644 --- a/cnn_v3/training/train_cnn_v3.py +++ b/cnn_v3/training/train_cnn_v3.py @@ -10,8 +10,7 @@ Architecture (enc_channels=[8,16]): enc1 Conv(8→16, 3×3) + FiLM + ReLU + pool2 H/2×W/2 2× rgba32uint (16ch split) bottleneck Conv(16→16, 3×3, dilation=2) + ReLU H/4×W/4 2× rgba32uint (16ch split) dec1 upsample×2 + cat(enc1) Conv(32→8) + FiLM H/2×W/2 rgba32uint (8ch) - dec0 upsample×2 + cat(enc0) Conv(16→4) + FiLM H×W rgba16float (4ch) - output sigmoid → RGBA + dec0 upsample×2 + cat(enc0) Conv(16→4) + FiLM + sigmoid H×W rgba16float (4ch) FiLM MLP: Linear(5→16) → ReLU → Linear(16→72) 72 = 2 × (γ+β) for enc0(8) enc1(16) dec1(8) dec0(4) @@ -93,9 +92,9 @@ class CNNv3(nn.Module): torch.cat([F.interpolate(x, scale_factor=2, mode='nearest'), skip1], dim=1) ), gd1, bd1)) - x = F.relu(film_apply(self.dec0( + x = film_apply(self.dec0( torch.cat([F.interpolate(x, scale_factor=2, mode='nearest'), skip0], dim=1) - ), gd0, bd0)) + ), gd0, bd0) return torch.sigmoid(x) diff --git a/doc/COMPLETED.md b/doc/COMPLETED.md index a3a988c..203c27a 100644 --- a/doc/COMPLETED.md +++ b/doc/COMPLETED.md @@ -36,6 +36,10 @@ Completed task archive. See `doc/archive/` for detailed historical documents. ## March 2026 +- [x] **CNN v3 training bug fixes (2026-03-27)** — Two bugs blocking convergence: + 1. **dec0 ReLU before sigmoid**: `sigmoid(relu(x))` constrains output to [0.5,1.0] — network could never produce dark pixels. Removed `F.relu` in `train_cnn_v3.py` and `max(0.0,…)` in `cnn_v3_dec0.wgsl`. Output range now [0,1]. Test vectors regenerated via `gen_test_vectors.py --header`. 36/36 tests pass, parity max_err=4.88e-4. + 2. **FiLM MLP not used at inference**: `set_film_params()` used hardcoded heuristics instead of the trained MLP. Added `CNNv3FilmMlp` struct + `load_film_mlp()` to `cnn_v3_effect.h/.cc`. MLP auto-loaded from `ASSET_WEIGHTS_CNN_V3_FILM_MLP` at construction; `set_film_params()` runs `Linear(5→16)→ReLU→Linear(16→72)` CPU-side. Falls back to identity if not loaded. + - [x] **CNN v3 shadow pass debugging** — Fixed 5 independent bugs in `gbuf_shadow.wgsl` + `gbuffer_effect.cc`: 1. **Camera Y-inversion**: `mat4::perspective` negates Y for post-process chain; fixed with `proj.m[5] = -proj.m[5]` in `upload_scene_data` + `WGPUFrontFace_CCW` on raster pipeline. 2. **Shadow formula**: replaced `shadowWithStoredDistance` (20 steps, bounded) with 64-step IQ soft shadow (`res = min(res, 8.0*d/t)`, unbounded march). diff --git a/workspaces/main/weights/cnn_v3_film_mlp.bin b/workspaces/main/weights/cnn_v3_film_mlp.bin index 06c65c9..86708a4 100644 Binary files a/workspaces/main/weights/cnn_v3_film_mlp.bin and b/workspaces/main/weights/cnn_v3_film_mlp.bin differ diff --git a/workspaces/main/weights/cnn_v3_weights.bin b/workspaces/main/weights/cnn_v3_weights.bin index 584803e..d9bac22 100644 Binary files a/workspaces/main/weights/cnn_v3_weights.bin and b/workspaces/main/weights/cnn_v3_weights.bin differ -- cgit v1.2.3