Merge branch 'worktree-agent-a1105760' into worktree-agent-acf82828

This commit is contained in:
w1n5t0n 2026-04-03 17:23:04 +01:00
commit 2d2cabe159
2 changed files with 58 additions and 17 deletions

View file

@ -914,6 +914,9 @@ async function init() {
updateStatus(); updateStatus();
}, },
saveState: () => saveState(), saveState: () => saveState(),
evalLoss: () => iml.evalLoss(),
inferBatch: (points) => iml.inferBatch(points),
getLayerStats:() => iml.getLayerStats(),
}; };
} }

View file

@ -10,8 +10,9 @@
* - variance: output variance -> saturation (shows "interesting" vs "flat") * - variance: output variance -> saturation (shows "interesting" vs "flat")
* - divergence: difference from center point output (how each region diverges) * - divergence: difference from center point output (how each region diverges)
* *
* Performance: 16x16 = 256 inferences at ~20us each = ~5ms. * Performance: 16x16 = 256 inferences. When inferBatchFn is provided,
* Throttled to max 5 updates/sec by default. * all points are evaluated in a single WASM call. Falls back to per-point
* inferFn (~20us each = ~5ms). Throttled to max 5 updates/sec by default.
* *
* @module input-heatmap * @module input-heatmap
*/ */
@ -107,6 +108,9 @@ export class InputHeatmap {
* @param {object} [options] * @param {object} [options]
* @param {object} [options.zoomWindow] - { x1, y1, x2, y2 } in [0,1] space * @param {object} [options.zoomWindow] - { x1, y1, x2, y2 } in [0,1] space
* @param {number} [options.resolution] - override resolution for this update * @param {number} [options.resolution] - override resolution for this update
* @param {function} [options.inferBatchFn] - (inputPoints: number[][]) => number[][]
* Batch inference: takes array of [x,y] pairs, returns array of output arrays.
* When provided, used instead of per-point inferFn for better performance.
*/ */
update(inferFn, options = {}) { update(inferFn, options = {}) {
if (!this._enabled) return; if (!this._enabled) return;
@ -117,10 +121,44 @@ export class InputHeatmap {
const res = clamp(options.resolution ?? this._resolution, MIN_RESOLUTION, MAX_RESOLUTION); const res = clamp(options.resolution ?? this._resolution, MIN_RESOLUTION, MAX_RESOLUTION);
const zw = options.zoomWindow || { x1: 0, y1: 0, x2: 1, y2: 1 }; const zw = options.zoomWindow || { x1: 0, y1: 0, x2: 1, y2: 1 };
const inferBatchFn = options.inferBatchFn || null;
// Sample grid // Sample grid
const grid = new Float32Array(res * res); const grid = new Float32Array(res * res);
const outputs = []; let outputs;
if (inferBatchFn) {
// ---- Batch path: build all input points, call once ----
const needsCenter = this._colorMode === 'divergence';
const points = [];
// If divergence mode, first point is the center
if (needsCenter) {
const cx = (zw.x1 + zw.x2) / 2;
const cy = (zw.y1 + zw.y2) / 2;
points.push([cx, cy]);
}
// Grid points
for (let gy = 0; gy < res; gy++) {
for (let gx = 0; gx < res; gx++) {
const inputX = zw.x1 + (gx + 0.5) / res * (zw.x2 - zw.x1);
const inputY = zw.y1 + (gy + 0.5) / res * (zw.y2 - zw.y1);
points.push([inputX, inputY]);
}
}
const allOutputs = inferBatchFn(points);
if (needsCenter) {
this._centerOutput = allOutputs[0];
outputs = allOutputs.slice(1);
} else {
outputs = allOutputs;
}
} else {
// ---- Per-point fallback path ----
outputs = [];
// Pre-compute center output for divergence mode // Pre-compute center output for divergence mode
if (this._colorMode === 'divergence') { if (this._colorMode === 'divergence') {
@ -132,13 +170,13 @@ export class InputHeatmap {
// Collect all outputs for normalization // Collect all outputs for normalization
for (let gy = 0; gy < res; gy++) { for (let gy = 0; gy < res; gy++) {
for (let gx = 0; gx < res; gx++) { for (let gx = 0; gx < res; gx++) {
// Map grid cell to input space
const inputX = zw.x1 + (gx + 0.5) / res * (zw.x2 - zw.x1); const inputX = zw.x1 + (gx + 0.5) / res * (zw.x2 - zw.x1);
const inputY = zw.y1 + (gy + 0.5) / res * (zw.y2 - zw.y1); const inputY = zw.y1 + (gy + 0.5) / res * (zw.y2 - zw.y1);
const out = inferFn([inputX, inputY]); const out = inferFn([inputX, inputY]);
outputs.push(out); outputs.push(out);
} }
} }
}
// Reduce outputs to scalar values based on color mode // Reduce outputs to scalar values based on color mode
let minVal = Infinity; let minVal = Infinity;