summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-13 23:40:30 +0100
committerskal <pascal.massimino@gmail.com>2026-02-13 23:40:30 +0100
commit25044d63057cdb134cc3930bb67b178cff1aebb4 (patch)
treebf00411b0af159ef090dc9cffbd8c6dd793f1cff
parent87a27bf022d7fba68e3a945ee29c854c6e1ae2d7 (diff)
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 <noreply@anthropic.com>
-rw-r--r--checkpoints/checkpoint_epoch_10.pthbin36475 -> 36475 bytes
-rw-r--r--checkpoints/checkpoint_epoch_15.pthbin36475 -> 36475 bytes
-rw-r--r--checkpoints/checkpoint_epoch_20.pthbin36475 -> 36475 bytes
-rw-r--r--checkpoints/checkpoint_epoch_25.pthbin36475 -> 36475 bytes
-rw-r--r--checkpoints/checkpoint_epoch_30.pthbin36475 -> 36475 bytes
-rw-r--r--checkpoints/checkpoint_epoch_35.pthbin36475 -> 36475 bytes
-rw-r--r--checkpoints/checkpoint_epoch_40.pthbin36475 -> 36475 bytes
-rw-r--r--checkpoints/checkpoint_epoch_45.pthbin36475 -> 36475 bytes
-rw-r--r--checkpoints/checkpoint_epoch_5.pthbin36453 -> 36453 bytes
-rw-r--r--checkpoints/checkpoint_epoch_50.pthbin36475 -> 36475 bytes
-rw-r--r--checkpoints/checkpoint_epoch_55.pthbin36475 -> 36475 bytes
-rw-r--r--checkpoints/checkpoint_epoch_60.pthbin36475 -> 36475 bytes
-rw-r--r--checkpoints/checkpoint_epoch_65.pthbin36475 -> 36475 bytes
-rw-r--r--checkpoints/checkpoint_epoch_70.pthbin36475 -> 36475 bytes
-rw-r--r--checkpoints/checkpoint_epoch_75.pthbin36475 -> 36475 bytes
-rw-r--r--doc/CNN_V2_DEBUG_TOOLS.md12
-rw-r--r--test_white_253.pngbin0 -> 79 bytes
-rw-r--r--test_white_255.pngbin0 -> 79 bytes
-rw-r--r--tools/cnn_v2_test/index.html3
-rw-r--r--training/diagnose_255_to_253.md69
-rwxr-xr-xtraining/test_viz_precision.py38
21 files changed, 120 insertions, 2 deletions
diff --git a/checkpoints/checkpoint_epoch_10.pth b/checkpoints/checkpoint_epoch_10.pth
index d50a6b2..e0430c2 100644
--- a/checkpoints/checkpoint_epoch_10.pth
+++ b/checkpoints/checkpoint_epoch_10.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_15.pth b/checkpoints/checkpoint_epoch_15.pth
index 0c25f1b..faa7036 100644
--- a/checkpoints/checkpoint_epoch_15.pth
+++ b/checkpoints/checkpoint_epoch_15.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_20.pth b/checkpoints/checkpoint_epoch_20.pth
index 057a448..a9fc937 100644
--- a/checkpoints/checkpoint_epoch_20.pth
+++ b/checkpoints/checkpoint_epoch_20.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_25.pth b/checkpoints/checkpoint_epoch_25.pth
index 3d9cadb..6c6bb7a 100644
--- a/checkpoints/checkpoint_epoch_25.pth
+++ b/checkpoints/checkpoint_epoch_25.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_30.pth b/checkpoints/checkpoint_epoch_30.pth
index e6923ec..c93379a 100644
--- a/checkpoints/checkpoint_epoch_30.pth
+++ b/checkpoints/checkpoint_epoch_30.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_35.pth b/checkpoints/checkpoint_epoch_35.pth
index 75a3b1b..17a3b7b 100644
--- a/checkpoints/checkpoint_epoch_35.pth
+++ b/checkpoints/checkpoint_epoch_35.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_40.pth b/checkpoints/checkpoint_epoch_40.pth
index e90b3ed..9a8c9aa 100644
--- a/checkpoints/checkpoint_epoch_40.pth
+++ b/checkpoints/checkpoint_epoch_40.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_45.pth b/checkpoints/checkpoint_epoch_45.pth
index d35833e..736c5ea 100644
--- a/checkpoints/checkpoint_epoch_45.pth
+++ b/checkpoints/checkpoint_epoch_45.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_5.pth b/checkpoints/checkpoint_epoch_5.pth
index d81e6bb..bd585e4 100644
--- a/checkpoints/checkpoint_epoch_5.pth
+++ b/checkpoints/checkpoint_epoch_5.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_50.pth b/checkpoints/checkpoint_epoch_50.pth
index ed4ead8..1e7fe7f 100644
--- a/checkpoints/checkpoint_epoch_50.pth
+++ b/checkpoints/checkpoint_epoch_50.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_55.pth b/checkpoints/checkpoint_epoch_55.pth
index a663241..89ef0a9 100644
--- a/checkpoints/checkpoint_epoch_55.pth
+++ b/checkpoints/checkpoint_epoch_55.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_60.pth b/checkpoints/checkpoint_epoch_60.pth
index 3493964..8d197b5 100644
--- a/checkpoints/checkpoint_epoch_60.pth
+++ b/checkpoints/checkpoint_epoch_60.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_65.pth b/checkpoints/checkpoint_epoch_65.pth
index 0ee39ff..5be6d68 100644
--- a/checkpoints/checkpoint_epoch_65.pth
+++ b/checkpoints/checkpoint_epoch_65.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_70.pth b/checkpoints/checkpoint_epoch_70.pth
index 305189d..7b29e17 100644
--- a/checkpoints/checkpoint_epoch_70.pth
+++ b/checkpoints/checkpoint_epoch_70.pth
Binary files differ
diff --git a/checkpoints/checkpoint_epoch_75.pth b/checkpoints/checkpoint_epoch_75.pth
index 60eacf0..d26dfde 100644
--- a/checkpoints/checkpoint_epoch_75.pth
+++ b/checkpoints/checkpoint_epoch_75.pth
Binary files 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
--- /dev/null
+++ b/test_white_253.png
Binary files differ
diff --git a/test_white_255.png b/test_white_255.png
new file mode 100644
index 0000000..4f5920c
--- /dev/null
+++ b/test_white_255.png
Binary files 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")