Visualizer: shift buttons and all-nets answer line; page with augmented net B
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e5d50c8d65
commit
27279ab242
2 changed files with 504 additions and 3 deletions
44
viz/app.html
44
viz/app.html
|
|
@ -109,7 +109,7 @@ table.conf td { color: var(--fg); }
|
|||
<header>
|
||||
<div>
|
||||
<h1>Колонки AltAI</h1>
|
||||
<p class="lead">Как сеть mnist-learn на нейронах AltAI узнаёт цифру. Картинка превращается в спайки, 784 пикселя заряжают входные нейроны, и первая колонка, дошедшая до порога, голосует за свою цифру.</p>
|
||||
<p class="lead">Как сеть mnist-learn на нейронах AltAI узнаёт цифру. Картинка превращается в спайки, 784 пикселя заряжают входные нейроны, и первая колонка, дошедшая до порога, голосует за свою цифру. Кнопки сдвига двигают картинку на пиксель: так видно, насколько сеть держится за точное положение цифры.</p>
|
||||
</div>
|
||||
<div class="stack" style="gap:6px">
|
||||
<span class="label">Сеть</span>
|
||||
|
|
@ -126,6 +126,14 @@ table.conf td { color: var(--fg); }
|
|||
<span class="note" id="srcnote">Нарисуйте цифру</span>
|
||||
</div>
|
||||
<p class="note">Рисунок уменьшается до 28×28 и перерисовывается тонкой линией, как в MNIST: размер и толщина вашего штриха не важны.</p>
|
||||
<div class="row" role="group" aria-label="Сдвинуть картинку на 1 пиксель">
|
||||
<span class="label">Сдвиг</span>
|
||||
<button class="btn" id="sh-left" aria-label="Влево">←</button>
|
||||
<button class="btn" id="sh-right" aria-label="Вправо">→</button>
|
||||
<button class="btn" id="sh-up" aria-label="Вверх">↑</button>
|
||||
<button class="btn" id="sh-down" aria-label="Вниз">↓</button>
|
||||
<span class="mono note" id="shiftlabel">0, 0</span>
|
||||
</div>
|
||||
<span class="label">Тестовые картинки MNIST</span>
|
||||
<div class="gallery" id="gallery"></div>
|
||||
</div>
|
||||
|
|
@ -160,6 +168,7 @@ table.conf td { color: var(--fg); }
|
|||
<span style="--c: var(--spike-soft)">спайкал раньше</span>
|
||||
<span style="--c: var(--muted)">справа: голоса колонки</span>
|
||||
</div>
|
||||
<p class="note" id="allnets"></p>
|
||||
<p class="note" id="inhibnote"></p>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -170,7 +179,7 @@ table.conf td { color: var(--fg); }
|
|||
<h2>Чему научилась колонка</h2>
|
||||
<div class="seg" id="digits" role="group" aria-label="Цифра"></div>
|
||||
</div>
|
||||
<p class="note">Каждый квадрат — веса одного нейрона колонки к 784 пикселям. Оранжевое возбуждает нейрон, синее тормозит. В исходной сети все нейроны колонки одинаковые; с разбросом стартовых весов каждый учит свой вариант написания.</p>
|
||||
<p class="note">Каждый квадрат — веса одного нейрона колонки к 784 пикселям. Оранжевое возбуждает нейрон, синее тормозит. Благодаря разбросу стартовых весов каждый нейрон колонки учит свой вариант написания.</p>
|
||||
<div id="mapblocks" class="stack"></div>
|
||||
</div>
|
||||
<div class="panel stack">
|
||||
|
|
@ -305,10 +314,39 @@ function play() {
|
|||
}
|
||||
function stop() { clearInterval(timer); timer = null; $("play").textContent = "▶ Пуск"; }
|
||||
|
||||
function setImage(img, label, note) { image = img; imageLabel = label; $("srcnote").textContent = note; recompute(); if (!timer) { step = -1; play(); } }
|
||||
// --- shift: the source image moves by whole pixels, empty edge fills with black ---
|
||||
let baseImage = null, shift = [0, 0];
|
||||
function shifted(img, dx, dy) {
|
||||
const out = new Uint8Array(PIX);
|
||||
for (let y = 0; y < 28; y++) for (let x = 0; x < 28; x++) { const sx = x - dx, sy = y - dy; if (sx >= 0 && sx < 28 && sy >= 0 && sy < 28) out[y * 28 + x] = img[sy * 28 + sx]; }
|
||||
return out;
|
||||
}
|
||||
function applyShift() {
|
||||
if (!baseImage) return;
|
||||
image = shifted(baseImage, ...shift);
|
||||
$("shiftlabel").textContent = `${shift[0]}, ${shift[1]}`;
|
||||
showOnDraw(image); recompute(); if (!timer) { step = -1; play(); }
|
||||
}
|
||||
[["sh-left", -1, 0], ["sh-right", 1, 0], ["sh-up", 0, -1], ["sh-down", 0, 1]].forEach(([id, dx, dy]) => {
|
||||
$(id).onclick = () => { shift = [Math.max(-4, Math.min(4, shift[0] + dx)), Math.max(-4, Math.min(4, shift[1] + dy))]; applyShift(); };
|
||||
});
|
||||
|
||||
function setImage(img, label, note) {
|
||||
baseImage = img; image = img; imageLabel = label; shift = [0, 0]; $("shiftlabel").textContent = "0, 0";
|
||||
$("srcnote").textContent = note; recompute(); if (!timer) { step = -1; play(); }
|
||||
}
|
||||
function renderAllNets() {
|
||||
if (models.length < 2) { $("allnets").textContent = ""; return; }
|
||||
$("allnets").textContent = "Итог всех сетей: " + models.map(m => {
|
||||
const v = (m === model ? trace : simulate(image, m))[STEPS - 1].votes, a = argmax(v);
|
||||
const mark = imageLabel === null || a < 0 ? "" : a === imageLabel ? " ✓" : " ✗";
|
||||
return `${m.name} — ${a < 0 ? "нет ответа" : a}${mark}`;
|
||||
}).join(" · ");
|
||||
}
|
||||
function recompute() {
|
||||
if (!image) return;
|
||||
trace = simulate(image, model);
|
||||
renderAllNets();
|
||||
firstWinner = -1;
|
||||
for (const s of trace) { const j = s.fired.indexOf(1); if (j >= 0) { firstWinner = j; break; } }
|
||||
digit = firstWinner >= 0 ? Math.floor(firstWinner / model.col) : (imageLabel ?? digit);
|
||||
|
|
|
|||
463
viz/aug_viz.html
Normal file
463
viz/aug_viz.html
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Reference in a new issue