diff options
Diffstat (limited to 'tools/cnn_v2_test/index.html')
| -rw-r--r-- | tools/cnn_v2_test/index.html | 72 |
1 files changed, 65 insertions, 7 deletions
diff --git a/tools/cnn_v2_test/index.html b/tools/cnn_v2_test/index.html index ca89fb4..2ec934d 100644 --- a/tools/cnn_v2_test/index.html +++ b/tools/cnn_v2_test/index.html @@ -543,12 +543,10 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) { } } - if (is_output) { - output[c] = clamp(sum, 0.0, 1.0); - } else if (params.is_layer_0 != 0u) { - output[c] = clamp(sum, 0.0, 1.0); // Layer 0: clamp [0,1] + if (is_output || params.is_layer_0 != 0u) { + output[c] = 1.0 / (1.0 + exp(-sum)); // Sigmoid [0,1] } else { - output[c] = max(0.0, sum); // Middle layers: ReLU + output[c] = max(0.0, sum); // ReLU } } @@ -1395,6 +1393,7 @@ class CNNTester { const label = `Layer ${i - 1}`; html += `<button onclick="tester.visualizeLayer(${i})" id="layerBtn${i}">${label}</button>`; } + html += `<button onclick="tester.saveCompositedLayer()" style="margin-left: 20px; background: #28a745;">Save Composited</button>`; html += '</div>'; html += '<div class="layer-grid" id="layerGrid"></div>'; @@ -1526,7 +1525,7 @@ class CNNTester { continue; } - const vizScale = layerIdx === 0 ? 1.0 : 0.5; // Static: 1.0, CNN layers: 0.5 (4 channels [0,1]) + const vizScale = 1.0; // Always 1.0, shader clamps to [0,1] const paramsBuffer = this.device.createBuffer({ size: 8, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST @@ -1618,7 +1617,8 @@ class CNNTester { const layerTex = this.layerOutputs[layerIdx]; if (!layerTex) return; - const vizScale = layerIdx === 0 ? 1.0 : 0.5; + // Always 1.0, shader clamps to [0,1] - show exact layer values + const vizScale = 1.0; const actualChannel = channelOffset + this.selectedChannel; const paramsBuffer = this.device.createBuffer({ @@ -1836,6 +1836,64 @@ class CNNTester { this.setStatus(`Save failed: ${err.message}`, true); } } + + async saveCompositedLayer() { + if (!this.currentLayerIdx) { + this.log('No layer selected for compositing', 'error'); + return; + } + + try { + const canvases = []; + for (let i = 0; i < 4; i++) { + const canvas = document.getElementById(`layerCanvas${i}`); + if (!canvas) { + this.log(`Canvas layerCanvas${i} not found`, 'error'); + return; + } + canvases.push(canvas); + } + + const width = canvases[0].width; + const height = canvases[0].height; + const compositedWidth = width * 4; + + // Create composited canvas + const compositedCanvas = document.createElement('canvas'); + compositedCanvas.width = compositedWidth; + compositedCanvas.height = height; + const ctx = compositedCanvas.getContext('2d'); + + // Composite horizontally + for (let i = 0; i < 4; i++) { + ctx.drawImage(canvases[i], i * width, 0); + } + + // Convert to grayscale + const imageData = ctx.getImageData(0, 0, compositedWidth, height); + const pixels = imageData.data; + for (let i = 0; i < pixels.length; i += 4) { + const gray = 0.299 * pixels[i] + 0.587 * pixels[i + 1] + 0.114 * pixels[i + 2]; + pixels[i] = pixels[i + 1] = pixels[i + 2] = gray; + } + ctx.putImageData(imageData, 0, 0); + + // Save as PNG + const blob = await new Promise(resolve => compositedCanvas.toBlob(resolve, 'image/png')); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `composited_layer${this.currentLayerIdx - 1}_${compositedWidth}x${height}.png`; + a.click(); + URL.revokeObjectURL(url); + + this.log(`Saved composited layer: ${a.download}`); + this.setStatus(`Saved: ${a.download}`); + } catch (err) { + this.log(`Failed to save composited layer: ${err.message}`, 'error'); + this.setStatus(`Compositing failed: ${err.message}`, true); + } + } } const tester = new CNNTester(); |
