From 25044d63057cdb134cc3930bb67b178cff1aebb4 Mon Sep 17 00:00:00 2001 From: skal Date: Fri, 13 Feb 2026 23:40:30 +0100 Subject: CNN v2: Fix Layer 0 visualization scale (was 0.5, now 1.0) Layer 0 output is clamped [0,1], does not need 0.5 dimming. Middle layers (ReLU) keep 0.5 scale for values >1. Co-Authored-By: Claude Sonnet 4.5 --- checkpoints/checkpoint_epoch_10.pth | Bin 36475 -> 36475 bytes checkpoints/checkpoint_epoch_15.pth | Bin 36475 -> 36475 bytes checkpoints/checkpoint_epoch_20.pth | Bin 36475 -> 36475 bytes checkpoints/checkpoint_epoch_25.pth | Bin 36475 -> 36475 bytes checkpoints/checkpoint_epoch_30.pth | Bin 36475 -> 36475 bytes checkpoints/checkpoint_epoch_35.pth | Bin 36475 -> 36475 bytes checkpoints/checkpoint_epoch_40.pth | Bin 36475 -> 36475 bytes checkpoints/checkpoint_epoch_45.pth | Bin 36475 -> 36475 bytes checkpoints/checkpoint_epoch_5.pth | Bin 36453 -> 36453 bytes checkpoints/checkpoint_epoch_50.pth | Bin 36475 -> 36475 bytes checkpoints/checkpoint_epoch_55.pth | Bin 36475 -> 36475 bytes checkpoints/checkpoint_epoch_60.pth | Bin 36475 -> 36475 bytes checkpoints/checkpoint_epoch_65.pth | Bin 36475 -> 36475 bytes checkpoints/checkpoint_epoch_70.pth | Bin 36475 -> 36475 bytes checkpoints/checkpoint_epoch_75.pth | Bin 36475 -> 36475 bytes doc/CNN_V2_DEBUG_TOOLS.md | 12 ++++++- test_white_253.png | Bin 0 -> 79 bytes test_white_255.png | Bin 0 -> 79 bytes tools/cnn_v2_test/index.html | 3 +- training/diagnose_255_to_253.md | 69 ++++++++++++++++++++++++++++++++++++ training/test_viz_precision.py | 38 ++++++++++++++++++++ 21 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 test_white_253.png create mode 100644 test_white_255.png create mode 100644 training/diagnose_255_to_253.md create mode 100755 training/test_viz_precision.py diff --git a/checkpoints/checkpoint_epoch_10.pth b/checkpoints/checkpoint_epoch_10.pth index d50a6b2..e0430c2 100644 Binary files a/checkpoints/checkpoint_epoch_10.pth and b/checkpoints/checkpoint_epoch_10.pth differ diff --git a/checkpoints/checkpoint_epoch_15.pth b/checkpoints/checkpoint_epoch_15.pth index 0c25f1b..faa7036 100644 Binary files a/checkpoints/checkpoint_epoch_15.pth and b/checkpoints/checkpoint_epoch_15.pth differ diff --git a/checkpoints/checkpoint_epoch_20.pth b/checkpoints/checkpoint_epoch_20.pth index 057a448..a9fc937 100644 Binary files a/checkpoints/checkpoint_epoch_20.pth and b/checkpoints/checkpoint_epoch_20.pth differ diff --git a/checkpoints/checkpoint_epoch_25.pth b/checkpoints/checkpoint_epoch_25.pth index 3d9cadb..6c6bb7a 100644 Binary files a/checkpoints/checkpoint_epoch_25.pth and b/checkpoints/checkpoint_epoch_25.pth differ diff --git a/checkpoints/checkpoint_epoch_30.pth b/checkpoints/checkpoint_epoch_30.pth index e6923ec..c93379a 100644 Binary files a/checkpoints/checkpoint_epoch_30.pth and b/checkpoints/checkpoint_epoch_30.pth differ diff --git a/checkpoints/checkpoint_epoch_35.pth b/checkpoints/checkpoint_epoch_35.pth index 75a3b1b..17a3b7b 100644 Binary files a/checkpoints/checkpoint_epoch_35.pth and b/checkpoints/checkpoint_epoch_35.pth differ diff --git a/checkpoints/checkpoint_epoch_40.pth b/checkpoints/checkpoint_epoch_40.pth index e90b3ed..9a8c9aa 100644 Binary files a/checkpoints/checkpoint_epoch_40.pth and b/checkpoints/checkpoint_epoch_40.pth differ diff --git a/checkpoints/checkpoint_epoch_45.pth b/checkpoints/checkpoint_epoch_45.pth index d35833e..736c5ea 100644 Binary files a/checkpoints/checkpoint_epoch_45.pth and b/checkpoints/checkpoint_epoch_45.pth differ diff --git a/checkpoints/checkpoint_epoch_5.pth b/checkpoints/checkpoint_epoch_5.pth index d81e6bb..bd585e4 100644 Binary files a/checkpoints/checkpoint_epoch_5.pth and b/checkpoints/checkpoint_epoch_5.pth differ diff --git a/checkpoints/checkpoint_epoch_50.pth b/checkpoints/checkpoint_epoch_50.pth index ed4ead8..1e7fe7f 100644 Binary files a/checkpoints/checkpoint_epoch_50.pth and b/checkpoints/checkpoint_epoch_50.pth differ diff --git a/checkpoints/checkpoint_epoch_55.pth b/checkpoints/checkpoint_epoch_55.pth index a663241..89ef0a9 100644 Binary files a/checkpoints/checkpoint_epoch_55.pth and b/checkpoints/checkpoint_epoch_55.pth differ diff --git a/checkpoints/checkpoint_epoch_60.pth b/checkpoints/checkpoint_epoch_60.pth index 3493964..8d197b5 100644 Binary files a/checkpoints/checkpoint_epoch_60.pth and b/checkpoints/checkpoint_epoch_60.pth differ diff --git a/checkpoints/checkpoint_epoch_65.pth b/checkpoints/checkpoint_epoch_65.pth index 0ee39ff..5be6d68 100644 Binary files a/checkpoints/checkpoint_epoch_65.pth and b/checkpoints/checkpoint_epoch_65.pth differ diff --git a/checkpoints/checkpoint_epoch_70.pth b/checkpoints/checkpoint_epoch_70.pth index 305189d..7b29e17 100644 Binary files a/checkpoints/checkpoint_epoch_70.pth and b/checkpoints/checkpoint_epoch_70.pth differ diff --git a/checkpoints/checkpoint_epoch_75.pth b/checkpoints/checkpoint_epoch_75.pth index 60eacf0..d26dfde 100644 Binary files a/checkpoints/checkpoint_epoch_75.pth and b/checkpoints/checkpoint_epoch_75.pth differ diff --git a/doc/CNN_V2_DEBUG_TOOLS.md b/doc/CNN_V2_DEBUG_TOOLS.md index 0185dac..b6dc65f 100644 --- a/doc/CNN_V2_DEBUG_TOOLS.md +++ b/doc/CNN_V2_DEBUG_TOOLS.md @@ -102,7 +102,17 @@ Load in HTML tool or cnn_test - output should match input (RGB only, ignoring st ## Known Issues -**Current mismatch:** HTML tool and cnn_test produce different outputs for same input/weights. +### ~~Layer 0 Visualization Scale~~ [FIXED] + +**Issue:** Layer 0 output displayed at 0.5× brightness (divided by 2). + +**Cause:** Line 1530 used `vizScale = 0.5` for all CNN layers, but Layer 0 is clamped [0,1] and doesn't need dimming. + +**Fix:** Use scale 1.0 for Layer 0 output (layerIdx=1), 0.5 only for middle layers (ReLU, unbounded). + +### Remaining Mismatch + +**Current:** HTML tool and cnn_test produce different outputs for same input/weights. **Suspects:** 1. F16 unpacking difference (CPU vs GPU vs JS) diff --git a/test_white_253.png b/test_white_253.png new file mode 100644 index 0000000..d7f25fb Binary files /dev/null and b/test_white_253.png differ diff --git a/test_white_255.png b/test_white_255.png new file mode 100644 index 0000000..4f5920c Binary files /dev/null and b/test_white_255.png differ diff --git a/tools/cnn_v2_test/index.html b/tools/cnn_v2_test/index.html index 3977d9f..73a9f55 100644 --- a/tools/cnn_v2_test/index.html +++ b/tools/cnn_v2_test/index.html @@ -1527,7 +1527,8 @@ class CNNTester { continue; } - const vizScale = layerIdx === 0 ? 1.0 : 0.5; // Static: 1.0, CNN layers: 0.5 (4 channels [0,1]) + // Static features: 1.0, Layer 0: 1.0 (clamped [0,1]), Middle layers: 0.5 (ReLU, can be >1) + const vizScale = (layerIdx === 0 || layerIdx === 1) ? 1.0 : 0.5; const paramsBuffer = this.device.createBuffer({ size: 8, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST diff --git a/training/diagnose_255_to_253.md b/training/diagnose_255_to_253.md new file mode 100644 index 0000000..764d328 --- /dev/null +++ b/training/diagnose_255_to_253.md @@ -0,0 +1,69 @@ +# Diagnosis: 255 → 253 Loss (-2 LSBs) + +## Findings + +### F16 Precision +✅ **No loss:** 1.0 → f16(0x3c00) → 1.0 (exact round-trip) + +### Visualization Scale +⚠️ **Inconsistent:** +- Layer 1 uses `vizScale = 0.5` (line 1530) +- Should render as 128, not 253 +- **User seeing 253 suggests viewing Static Features (scale=1.0), not CNN output** + +### Suspected Issue: Input Alpha Channel + +**Code:** `tools/cnn_v2_test/index.html` line 1233 +```javascript +depthData[i] = pixels[i * 4 + 3] / 255.0; // Alpha from canvas +``` + +**Hypothesis:** Input PNG alpha channel = 253 (not 255) +- Browsers may set alpha < 255 for certain images +- Pre-multiplied alpha corrections +- PNG encoder compression artifacts + +### Test + +**Check input alpha:** +```javascript +// In HTML tool console: +const canvas = document.createElement('canvas'); +canvas.width = tester.image.width; +canvas.height = tester.image.height; +const ctx = canvas.getContext('2d'); +ctx.drawImage(tester.image, 0, 0); +const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); +const alpha = imgData.data[3]; // First pixel alpha +console.log('First pixel alpha:', alpha); +``` + +### Alternative: C++ Reference + +Check if `cnn_test` tool produces same -2 loss: +```bash +# Generate solid white 8×8 test image with alpha=255 +python3 -c " +from PIL import Image +import numpy as np +img = np.ones((8, 8, 4), dtype=np.uint8) * 255 +Image.fromarray(img, 'RGBA').save('test_white_255.png') +print('Created test_white_255.png: all pixels RGBA=(255,255,255,255)') +" + +# Test with HTML tool → check if p3 = 1.0 or 0.9921875 +# Test with cnn_test → compare output +./build/cnn_test test_white_255.png output.png --cnn-version 2 --debug-hex +``` + +### Next Steps + +1. **Verify input:** Check alpha channel of user's input image +2. **Add debug:** Log first pixel RGBA values in HTML tool +3. **Compare:** Run same image through C++ cnn_test +4. **Isolate:** Test with synthetic 255 alpha image + +## Conclusion + +**Most likely:** Input image alpha ≠ 255, already 253 before CNN processing. +**Verify:** User should check input PNG metadata and alpha channel values. diff --git a/training/test_viz_precision.py b/training/test_viz_precision.py new file mode 100755 index 0000000..143f4ea --- /dev/null +++ b/training/test_viz_precision.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +"""Test WebGPU → Canvas → PNG precision loss + +Check if bgra8unorm → 2D canvas → PNG loses 2 LSBs. +""" + +import numpy as np + +# Simulate WebGPU bgra8unorm conversion +# Float [0, 1] → uint8 [0, 255] + +test_values = [ + 1.0, # Perfect white + 0.9999, # Near-white + 254.5/255, # Exactly 254.5 + 253.5/255, # Exactly 253.5 +] + +for val in test_values: + # WebGPU bgra8unorm: round(val * 255) + gpu_u8 = int(np.round(val * 255)) + + # Convert back to normalized + gpu_f32 = gpu_u8 / 255.0 + + # JavaScript canvas getImageData: uint8 + canvas_u8 = int(np.round(gpu_f32 * 255)) + + print(f"Input: {val:.6f} → GPU u8: {gpu_u8} → Canvas: {canvas_u8}") + if canvas_u8 != 255: + print(f" ⚠️ Lost {255 - canvas_u8} LSBs") + +print("\nConclusion:") +print("If WebGPU stores 1.0 as 255, canvas should read 255.") +print("If user sees 253, likely:") +print(" a) Not viewing CNN layer (viewing static features at scale=1.0)") +print(" b) Value in texture is already 253/255 = 0.9921875") +print(" c) F16 storage or unpacking issue") -- cgit v1.2.3