180 lines
No EOL
30 KiB
HTML
180 lines
No EOL
30 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<html lang="ru"><head><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><!-- frame-runtime --><!-- /frame-runtime --><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><style>:root{color-scheme:light;box-sizing:border-box;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}html{scroll-padding-top:env(safe-area-inset-top,0px)}body{margin:0;padding:0;font:14px -apple-system,BlinkMacSystemFont,sans-serif;background:#fff;color:#000}img{max-width:100%}[hidden]:not([hidden=until-found i]){display:none!important}</style></head><body>
|
||
<title>Цифры на «Алтае»</title>
|
||
<meta name="claude:viewport-fit-sides" content="cover">
|
||
|
||
<link rel="stylesheet" href="./fonts.css">
|
||
<style>
|
||
/* Layout: one column of three numbered stages (до / внутри / после) under a sticky network switch; pixel views are always on a dark "scope" ground */
|
||
:root {
|
||
--bg: #F2F4F6; --panel: #FFFFFF; --ink: #16202A; --muted: #586674; --line: #D8DEE4;
|
||
--scope: #0D1318; --scope-dim: #27323C; --spike: #CF5A16; --charge: #137F89; --neg: #B0435A; --good: #2E7D4B; --bad: #B23B3B;
|
||
--spike-on-scope: #F2903F; --charge-on-scope: #38BAC3; --neg-on-scope: #E06A80;
|
||
--f-display: "Rubik", "Trebuchet MS", sans-serif; --f-body: "IBM Plex Sans", "Segoe UI", Arial, sans-serif; --f-mono: "JetBrains Mono", "Courier New", monospace;
|
||
}
|
||
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) {
|
||
--bg: #0E1318; --panel: #161D24; --ink: #E6EBEF; --muted: #95A3AF; --line: #27323C;
|
||
--scope: #080C10; --scope-dim: #222C35; --spike: #F08A3E; --charge: #3DBDC6; --neg: #E07085; --good: #5DBE7C; --bad: #EE6B6B; color-scheme: dark } }
|
||
:root[data-theme="dark"] {
|
||
--bg: #0E1318; --panel: #161D24; --ink: #E6EBEF; --muted: #95A3AF; --line: #27323C;
|
||
--scope: #080C10; --scope-dim: #222C35; --spike: #F08A3E; --charge: #3DBDC6; --neg: #E07085; --good: #5DBE7C; --bad: #EE6B6B; color-scheme: dark }
|
||
* { box-sizing: border-box }
|
||
body { background: var(--bg); color: var(--ink); font: 16px/1.5 var(--f-body); }
|
||
body::before { content: ""; position: fixed; inset: 0 0 auto; height: env(safe-area-inset-top, 0px); z-index: 10; background: var(--bg) }
|
||
.wrap { max-width: 1120px; margin: 0 auto; padding-left: max(16px, env(safe-area-inset-left, 0px)); padding-right: max(16px, env(safe-area-inset-right, 0px)); padding-block: 28px 64px; display: flex; flex-direction: column; gap: 28px }
|
||
h1, h2, h3 { font-family: var(--f-display); font-weight: 600; margin: 0; text-wrap: balance; line-height: 1.15 }
|
||
h1 { font-size: clamp(28px, 4.2vw, 42px) }
|
||
h2 { font-size: 24px }
|
||
h3 { font-size: 17px }
|
||
p { margin: 0 }
|
||
.lead { color: var(--muted); max-width: 68ch; font-size: 17px }
|
||
.mono { font-family: var(--f-mono); font-variant-numeric: tabular-nums }
|
||
.muted { color: var(--muted) }
|
||
.small { font-size: 14px }
|
||
.eyebrow { font-family: var(--f-mono); font-size: 13px; letter-spacing: .08em; text-transform: uppercase; color: var(--spike) }
|
||
.head { display: flex; flex-direction: column; gap: 10px }
|
||
|
||
.switch { position: sticky; top: env(safe-area-inset-top, 0px); z-index: 5; background: var(--bg); padding-block: 8px; display: flex; flex-wrap: wrap; gap: 8px }
|
||
.switch button { flex: 1 1 240px; text-align: left; font: inherit; color: var(--ink); background: var(--panel); border: 1.5px solid var(--line); border-radius: 12px; padding: 10px 14px; cursor: pointer; display: flex; flex-direction: column; gap: 2px }
|
||
.switch button b { font-family: var(--f-display); font-weight: 600; font-size: 16px }
|
||
.switch button span { color: var(--muted); font-size: 14px }
|
||
.switch button[aria-pressed="true"] { border-color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink) }
|
||
button:focus-visible, canvas:focus-visible, input:focus-visible { outline: 2px solid var(--charge); outline-offset: 2px }
|
||
|
||
.panel { background: var(--panel); border: 1px solid var(--line); border-radius: 16px; padding: 20px; display: flex; flex-direction: column; gap: 16px; min-width: 0 }
|
||
.row { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-start }
|
||
.row > * { min-width: 0 }
|
||
.grow { flex: 1 1 280px }
|
||
.btn { font: inherit; font-size: 15px; color: var(--ink); background: var(--bg); border: 1px solid var(--line); border-radius: 10px; padding: 7px 14px; cursor: pointer }
|
||
.btn:hover { border-color: var(--muted) }
|
||
.btn.primary { background: var(--ink); color: var(--panel); border-color: var(--ink) }
|
||
|
||
.pad { width: 280px; max-width: 100%; aspect-ratio: 1; display: block; border-radius: 14px; background: #000; touch-action: none; cursor: crosshair }
|
||
.px { image-rendering: pixelated; background: var(--scope); border-radius: 10px; display: block }
|
||
.fig { display: flex; flex-direction: column; gap: 6px; align-items: flex-start }
|
||
.cap { font-size: 13px; color: var(--muted); max-width: 22ch; line-height: 1.35 }
|
||
.gal { display: flex; flex-wrap: wrap; gap: 5px }
|
||
.gal button { padding: 2px; border: 2px solid var(--line); border-radius: 9px; background: var(--scope); cursor: pointer; line-height: 0 }
|
||
.gal button[aria-pressed="true"] { border-color: var(--spike) }
|
||
.gal canvas { width: 34px; height: 34px; image-rendering: pixelated; border-radius: 5px }
|
||
|
||
.answer { display: grid; grid-template-columns: auto 1fr; gap: 4px 18px; align-items: center }
|
||
.answer .digit { grid-row: span 3; font-family: var(--f-mono); font-size: 84px; font-weight: 600; line-height: 1 }
|
||
.verdict { font-weight: 600 }
|
||
.verdict.ok { color: var(--good) } .verdict.no { color: var(--bad) }
|
||
.facts { display: flex; flex-wrap: wrap; gap: 6px 18px; font-size: 14px; color: var(--muted) }
|
||
.facts b { color: var(--ink); font-family: var(--f-mono); font-weight: 600 }
|
||
|
||
.stage-title { display: flex; align-items: baseline; gap: 12px }
|
||
.stage-title .n { font-family: var(--f-mono); font-size: 14px; color: var(--muted); border: 1px solid var(--line); border-radius: 99px; padding: 1px 9px }
|
||
.flow { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 10px }
|
||
.flow .arrow { align-self: center; color: var(--muted); font-size: 22px; padding-top: 0 }
|
||
|
||
.transport { display: flex; flex-wrap: wrap; align-items: center; gap: 12px }
|
||
.transport input[type=range] { flex: 1 1 200px; accent-color: var(--spike) }
|
||
.story { background: var(--bg); border-radius: 12px; padding: 12px 16px; max-width: 80ch }
|
||
.views { display: grid; grid-template-columns: auto auto minmax(0, 1fr); gap: 20px; align-items: start }
|
||
@media (max-width: 760px) { .views { grid-template-columns: 1fr 1fr } .views > .outs { grid-column: 1 / -1 } }
|
||
.lanes { display: flex; flex-direction: column; gap: 3px; width: 100% }
|
||
.lane { display: grid; grid-template-columns: 18px minmax(60px, 1fr) 64px; gap: 10px; align-items: center; padding: 3px 8px; border-radius: 8px; font-family: var(--f-mono); font-size: 14px }
|
||
.lane.fire { background: color-mix(in srgb, var(--spike) 16%, transparent) }
|
||
.lane.lead { box-shadow: inset 0 0 0 1.5px var(--good) }
|
||
.lane .bar { height: 12px; border-radius: 4px; background: var(--line); position: relative; overflow: hidden }
|
||
.lane .bar i { position: absolute; inset: 0 auto 0 0; background: var(--charge) }
|
||
.lane .bar i.votes { background: var(--spike) }
|
||
.lane .dots { display: flex; gap: 3px; flex-wrap: wrap }
|
||
.lane .dots i { width: 8px; height: 8px; border-radius: 50%; background: var(--spike) }
|
||
.lane b { font-weight: 400; color: var(--muted); text-align: right }
|
||
.colgrid { display: grid; grid-template-columns: 16px auto; gap: 0 6px; align-items: stretch }
|
||
.colgrid .labels { display: grid; grid-template-rows: repeat(10, 1fr); font-family: var(--f-mono); font-size: 12px; color: var(--muted); text-align: right }
|
||
.colgrid .labels span { display: flex; align-items: center; justify-content: flex-end }
|
||
.legend { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 13px; color: var(--muted) }
|
||
.legend span::before { content: ""; display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: -1px; background: var(--c) }
|
||
.ramp { display: inline-block; width: 120px; height: 10px; border-radius: 3px; vertical-align: -1px; margin: 0 6px }
|
||
|
||
.inspect { display: grid; grid-template-columns: auto auto minmax(0, 1fr); gap: 18px; align-items: start; border-top: 1px solid var(--line); padding-top: 16px }
|
||
@media (max-width: 760px) { .inspect { grid-template-columns: 1fr 1fr } .inspect > .txt { grid-column: 1 / -1 } }
|
||
.voters { display: flex; flex-wrap: wrap; gap: 8px }
|
||
.voters button { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 4px; border: 1.5px solid var(--line); border-radius: 10px; background: var(--panel); color: var(--ink); cursor: pointer; font: 12px var(--f-mono) }
|
||
.voters button[aria-pressed="true"] { border-color: var(--spike) }
|
||
.voters canvas { width: 56px; height: 56px; image-rendering: pixelated; border-radius: 6px; background: var(--scope) }
|
||
.spark { width: 100%; max-width: 360px; height: 90px; display: block }
|
||
.after { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px }
|
||
@media (max-width: 760px) { .after { grid-template-columns: 1fr } }
|
||
.cost { display: flex; flex-direction: column; gap: 10px }
|
||
.cost .line { display: grid; grid-template-columns: 1fr auto; gap: 12px; border-bottom: 1px solid var(--line); padding-bottom: 6px; font-size: 15px }
|
||
.cost .line b { font-family: var(--f-mono); font-weight: 600 }
|
||
.train p + p { margin-top: 8px }
|
||
.train ol { margin: 8px 0 0; padding-left: 22px; display: flex; flex-direction: column; gap: 6px; max-width: 80ch }
|
||
@media (prefers-reduced-motion: reduce) { * { transition: none !important } }
|
||
</style>
|
||
|
||
<div class="wrap">
|
||
<header class="head">
|
||
<p class="eyebrow">KNP · AltAI · импульсные сети</p>
|
||
<h1>Как сеть на «Алтае» узнаёт цифру</h1>
|
||
<p class="lead">Нарисуйте цифру или выберите тестовую. Ниже видно всё, что с ней происходит: как обычный процессор готовит картинку, как спайки идут через сеть такт за тактом и как из них получается ответ. Расчёт точный и целочисленный, по тем же правилам, что на чипе.</p>
|
||
</header>
|
||
|
||
<nav class="switch" id="switch" aria-label="Сеть"><button type="button" data-net="snn" aria-pressed="true"><b>Последняя версия: Сеть по тактам</b><span>97,4% на тесте · 8 тактов · обучена на компьютере</span></button><button type="button" data-net="cols" aria-pressed="false"><b>Первая версия: Колонки STDP</b><span>92,2% на тесте · 15 тактов · обучена в KNP</span></button></nav>
|
||
|
||
<section class="panel">
|
||
<div class="row">
|
||
<div class="fig">
|
||
<canvas id="pad" class="pad" width="280" height="280" aria-label="Поле для рисования цифры"></canvas>
|
||
<div class="row" style="gap:10px;align-items:center"><button class="btn" id="clear">Очистить</button><span class="small muted" id="src">Тестовая цифра «3», №381</span></div>
|
||
</div>
|
||
<div class="grow" style="display:flex;flex-direction:column;gap:16px">
|
||
<div class="answer" aria-live="polite">
|
||
<span class="digit" id="ans">3</span>
|
||
<span class="small muted" id="ansNet">Последняя версия: Сеть по тактам</span>
|
||
<span class="verdict ok" id="verdict">верно</span>
|
||
<span class="small muted" id="ansNote">ответ ясен с такта 4 из 8</span>
|
||
</div>
|
||
<div class="facts" id="netFacts"><span>тактов <b>9</b></span><span>входных спайков <b>142</b></span><span>спайков нейронов <b>42</b></span><span>сложений на чипе <b>19 604</b></span></div>
|
||
<div style="display:flex;flex-direction:column;gap:6px">
|
||
<span class="small muted">Тестовые цифры MNIST — сеть их не видела при обучении</span>
|
||
<div class="gal" id="gal" role="group" aria-label="Тестовые цифры"><button type="button" aria-label="Цифра 4, тест №447" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 7, тест №124" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 3, тест №381" aria-pressed="true"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 9, тест №92" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 3, тест №158" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 2, тест №222" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 8, тест №290" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 7, тест №0" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 0, тест №3" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 4, тест №4" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 4, тест №115" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 2, тест №321" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 2, тест №1" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 1, тест №2" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 1, тест №5" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 4, тест №6" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 9, тест №7" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 5, тест №8" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 9, тест №9" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 0, тест №10" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 6, тест №11" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 9, тест №12" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 0, тест №13" aria-pressed="false"><canvas width="28" height="28"></canvas></button><button type="button" aria-label="Цифра 1, тест №14" aria-pressed="false"><canvas width="28" height="28"></canvas></button></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="panel" aria-labelledby="t1">
|
||
<div class="stage-title"><span class="n">1</span><h2 id="t1">До сети: обычный процессор готовит вход</h2></div>
|
||
<p class="muted" id="beforeText">Сеть училась на цифрах определённого вида, поэтому процессор сначала приводит рисунок к нему: вписывает в квадрат 20×20, ставит центр масс в центр поля 28×28, выпрямляет наклон и уменьшает с усреднением, чтобы края стали серыми. Потом каждый пиксель ярче 32 получает момент своего единственного спайка: чем ярче, тем раньше.</p>
|
||
<div class="flow" id="flow"><div class="fig"><canvas width="28" height="28" class="px" aria-label="1. исходная цифра MNIST" style="width: 140px; height: 140px; max-width: 100%;"></canvas><span class="cap">1. исходная цифра MNIST</span></div><span class="arrow" aria-hidden="true">→</span><div class="fig"><canvas width="28" height="28" class="px" aria-label="2. в квадрат 20×20, центр масс в центр" style="width: 140px; height: 140px; max-width: 100%;"></canvas><span class="cap">2. в квадрат 20×20, центр масс в центр</span></div><span class="arrow" aria-hidden="true">→</span><div class="fig"><canvas width="28" height="28" class="px" aria-label="3. наклон выпрямлен" style="width: 140px; height: 140px; max-width: 100%;"></canvas><span class="cap">3. наклон выпрямлен</span></div><span class="arrow" aria-hidden="true">→</span><div class="fig"><canvas width="28" height="28" class="px" aria-label="4. уменьшение с усреднением: вход сети" style="width: 140px; height: 140px; max-width: 100%;"></canvas><span class="cap">4. уменьшение с усреднением: вход сети</span></div><span class="arrow" aria-hidden="true">→</span><div class="fig"><canvas width="28" height="28" class="px" aria-label="Моменты спайков" style="width: 140px; height: 140px; max-width: 100%;"></canvas><span class="cap">5. моменты спайков: яркое стреляет на такте 0, тусклое — на 7-м. Всего 142 спайков</span></div></div>
|
||
</section>
|
||
|
||
<section class="panel" aria-labelledby="t2">
|
||
<div class="stage-title"><span class="n">2</span><h2 id="t2">Внутри сети: такт за тактом</h2></div>
|
||
<div class="transport">
|
||
<button class="btn primary" id="play">▶ Пуск</button>
|
||
<input type="range" id="tick" min="0" max="8" value="0" aria-label="Такт">
|
||
<span class="mono" id="tickLab">такт 8 из 8</span>
|
||
</div>
|
||
<p class="story" id="story">Такт 8, последний. Новых пикселей нет: выходы получают последние спайки скрытого слоя. Выходы получили 1 спайков скрытого слоя с прошлого такта, выстрелили «3». Лидер «3» больше не сменится — ответ ясен уже сейчас.</p>
|
||
<div class="views" id="views"><div class="fig"><span class="cap">784 входа: пиксели, стреляющие сейчас</span><canvas width="28" height="28" class="px" aria-label="Входные спайки на этом такте" style="width: 168px; height: 168px; max-width: 100%;"></canvas></div><div class="fig"><span class="cap">256 скрытых нейронов (нажмите на любой)</span><canvas width="16" height="16" class="px" aria-label="256 скрытых нейронов" tabindex="0" style="width: 168px; height: 168px; max-width: 100%; cursor: pointer;"></canvas></div><div class="fig outs"><span class="cap">10 выходов: заряд до порога 8 и спайки</span><div class="lanes"><div class="lane"><span>0</span><div class="bar" title="заряд 0 из 8"><i style="width:0%"></i></div><div class="dots"><b>0</b></div></div><div class="lane"><span>1</span><div class="bar" title="заряд 1 из 8"><i style="width:12.5%"></i></div><div class="dots"><b>0</b></div></div><div class="lane"><span>2</span><div class="bar" title="заряд 3 из 8"><i style="width:37.5%"></i></div><div class="dots"><i></i><b></b></div></div><div class="lane fire lead"><span>3</span><div class="bar" title="заряд 0 из 8"><i style="width:0%"></i></div><div class="dots"><i></i><i></i><i></i><i></i><i></i><b></b></div></div><div class="lane"><span>4</span><div class="bar" title="заряд 2 из 8"><i style="width:25%"></i></div><div class="dots"><b>0</b></div></div><div class="lane"><span>5</span><div class="bar" title="заряд 3 из 8"><i style="width:37.5%"></i></div><div class="dots"><b>0</b></div></div><div class="lane"><span>6</span><div class="bar" title="заряд 0 из 8"><i style="width:0%"></i></div><div class="dots"><b>0</b></div></div><div class="lane"><span>7</span><div class="bar" title="заряд 4 из 8"><i style="width:50%"></i></div><div class="dots"><i></i><i></i><i></i><b></b></div></div><div class="lane"><span>8</span><div class="bar" title="заряд 3 из 8"><i style="width:37.5%"></i></div><div class="dots"><b>0</b></div></div><div class="lane"><span>9</span><div class="bar" title="заряд 2 из 8"><i style="width:25%"></i></div><div class="dots"><i></i><b></b></div></div></div></div></div>
|
||
<div class="legend" id="legend"><span style="--c: var(--spike-on-scope)">спайк на этом такте</span><span style="--c: var(--charge-on-scope)">заряд нейрона</span><span style="--c: var(--scope-dim)">пиксель уже выстрелил</span></div>
|
||
<div class="inspect" id="inspect"><div class="fig"><span class="cap">Нейрон №112: что он ищет</span><canvas width="28" height="28" class="px" aria-label="Веса нейрона 112" style="width: 168px; height: 168px; max-width: 100%;"></canvas><span class="cap">бирюзовый — вес «+», красный — вес «−»</span></div><div class="fig"><span class="cap">что дала ему эта картинка</span><canvas width="28" height="28" class="px" aria-label="Что этот нейрон получил от картинки" style="width: 168px; height: 168px; max-width: 100%;"></canvas><span class="cap">сумма весов по закрашенным пикселям: +31</span></div><div class="txt" style="display:flex;flex-direction:column;gap:10px"><h3>Нейрон №112: 3 спайков за картинку</h3><p class="small muted">Скрытый нейрон — это детектор кусочка формы. Бирюзовые пиксели заряжают его, красные — разряжают. Набрал 8 — выстрелил и отправил спайк выходам.</p><p class="small"><b>Связи к выходам: </b>0: −2 · 1: +2 · 3: +4 · 4: −1 · 5: −1 · 6: +2 · 7: +2 · 8: −2 · 9: −2</p><div><span class="cap" style="max-width:none">заряд по тактам: растёт, когда приходят веса; дошёл до порога — спайк (оранжевая точка), и порог вычитается. Красный пунктир — сумма за такт оказалась ниже нуля, и заряд обрезан до 0: хранить минус нейрону не разрешено настройкой</span><svg viewBox="0 0 360 110" class="spark" role="img" aria-label="Заряд нейрона по тактам"><line x1="16" x2="344" y1="42.42857142857143" y2="42.42857142857143" stroke="#95A3AF" stroke-dasharray="4 4" stroke-width="1"></line><text x="344" y="38.42857142857143" text-anchor="end" font-size="11" fill="#95A3AF" font-family="JetBrains Mono, monospace">порог 8</text><line x1="16" x2="344" y1="84.71428571428571" y2="84.71428571428571" stroke="#95A3AF" stroke-width="1" opacity="0.5"></line><text x="344" y="96.71428571428571" text-anchor="end" font-size="11" fill="#95A3AF" font-family="JetBrains Mono, monospace">0</text><line x1="303" x2="303" y1="84.71428571428571" y2="90" stroke="#E07085" stroke-width="2" stroke-dasharray="3 3"></line><circle cx="303" cy="90" r="2.5" fill="#E07085"></circle><path d="M8,84.71428571428571 L16,53 L16,53 L57,16 L57,58.285714285714285 L98,53 L98,53 L139,42.42857142857143 L139,84.71428571428571 L180,63.57142857142857 L180,63.57142857142857 L221,58.285714285714285 L221,58.285714285714285 L262,37.142857142857146 L262,79.42857142857143 L303,84.71428571428571 L303,84.71428571428571 L344,84.71428571428571 L344,84.71428571428571" fill="none" stroke="#3DBDC6" stroke-width="2" stroke-linejoin="round"></path><circle cx="57" cy="16" r="4" fill="#F08A3E"></circle><rect x="55" y="2" width="4" height="10" rx="1" fill="#F08A3E"></rect><circle cx="139" cy="42.42857142857143" r="4" fill="#F08A3E"></circle><rect x="137" y="2" width="4" height="10" rx="1" fill="#F08A3E"></rect><circle cx="262" cy="37.142857142857146" r="4" fill="#F08A3E"></circle><rect x="260" y="2" width="4" height="10" rx="1" fill="#F08A3E"></rect><line x1="344" x2="344" y1="0" y2="94" stroke="#E6EBEF" stroke-width="1" opacity="0.35"></line><text x="16" y="107" text-anchor="start" font-size="11" fill="#95A3AF" font-family="JetBrains Mono, monospace">такт 0</text><text x="344" y="107" text-anchor="end" font-size="11" fill="#95A3AF" font-family="JetBrains Mono, monospace">такт 8</text></svg></div><h3>Больше всего за «3» проголосовали</h3><div class="voters"><button type="button" aria-pressed="true" aria-label="Нейрон 112"><canvas width="28" height="28"></canvas><span>№112 +12</span></button><button type="button" aria-pressed="false" aria-label="Нейрон 150"><canvas width="28" height="28"></canvas><span>№150 +8</span></button><button type="button" aria-pressed="false" aria-label="Нейрон 109"><canvas width="28" height="28"></canvas><span>№109 +4</span></button><button type="button" aria-pressed="false" aria-label="Нейрон 168"><canvas width="28" height="28"></canvas><span>№168 +4</span></button><button type="button" aria-pressed="false" aria-label="Нейрон 120"><canvas width="28" height="28"></canvas><span>№120 +2</span></button><button type="button" aria-pressed="false" aria-label="Нейрон 165"><canvas width="28" height="28"></canvas><span>№165 +2</span></button></div></div></div>
|
||
</section>
|
||
|
||
<section class="panel" aria-labelledby="t3">
|
||
<div class="stage-title"><span class="n">3</span><h2 id="t3">После сети: ответ и цена</h2></div>
|
||
<div class="after">
|
||
<div style="display:flex;flex-direction:column;gap:10px"><p id="ruleText">Процессор считает спайки десяти выходных нейронов. Ответ — цифра, чей нейрон выстрелил больше всех; при равенстве — тот, кто выстрелил раньше.</p><div class="lanes" id="final"><div class="lane"><span>0</span><div class="bar"><i class="votes" style="width:0%"></i></div><b>0 сп.</b></div><div class="lane"><span>1</span><div class="bar"><i class="votes" style="width:0%"></i></div><b>0 сп.</b></div><div class="lane"><span>2</span><div class="bar"><i class="votes" style="width:20%"></i></div><b>1 сп.</b></div><div class="lane lead"><span>3</span><div class="bar"><i class="votes" style="width:100%"></i></div><b>5 сп.</b></div><div class="lane"><span>4</span><div class="bar"><i class="votes" style="width:0%"></i></div><b>0 сп.</b></div><div class="lane"><span>5</span><div class="bar"><i class="votes" style="width:0%"></i></div><b>0 сп.</b></div><div class="lane"><span>6</span><div class="bar"><i class="votes" style="width:0%"></i></div><b>0 сп.</b></div><div class="lane"><span>7</span><div class="bar"><i class="votes" style="width:60%"></i></div><b>3 сп.</b></div><div class="lane"><span>8</span><div class="bar"><i class="votes" style="width:0%"></i></div><b>0 сп.</b></div><div class="lane"><span>9</span><div class="bar"><i class="votes" style="width:20%"></i></div><b>1 сп.</b></div></div></div>
|
||
<div class="cost" id="cost"><h3>Сколько работы у чипа</h3><div class="line"><span>входных спайков</span><b>142</b></div><div class="line"><span>спайков нейронов</span><b>42</b></div><div class="line"><span>сложений «спайк → вес»</span><b>19 604</b></div><div class="line"><span>обычная сеть 784→256→10, умножений</span><b>203 264</b></div><p class="small muted">Каждый входной спайк задевает в среднем ≈139 из 256 скрытых нейронов: у остальных вес 0, и такая связь на чипе не создаётся. Поэтому работы примерно 143 × 139 ≈ 20 тыс. сложений.</p></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="panel train" aria-labelledby="t4">
|
||
<h2 id="t4">Как эта сеть обучена</h2>
|
||
<div id="train"><p>Обучена на обычном компьютере (PyTorch), а не в KNP: на чип загружаются готовые целые веса. 55 000 цифр MNIST, 30 эпох (проходов по всем цифрам), около 17 минут на процессоре без видеокарты.</p><ol><li>При обучении сеть считает ровно как чип: 8 тактов, целые веса, порог 8, вычитание порога после спайка, задержка в такт между слоями.</li><li>Спайк — это ступенька, у неё нет производной. При расчёте ошибки ступенька подменяется плавной «горкой» (суррогатный градиент), и сеть понимает, куда сдвигать веса.</li><li>С 9-й эпохи веса округляются до допустимых на чипе 0, ±1, ±2, ±4, и сеть доучивается уже с ними. Плюс небольшой штраф за лишние спайки.</li><li>Половина обучающих цифр перерисована пером постоянной толщины, как мышью, плюс сдвиги и повороты. Поэтому сеть хорошо узнаёт рисунки: 95,9% на перерисованном тесте.</li><li>Лучшая эпоха выбрана на 5000 отложенных цифрах отдельным целочисленным симулятором; тест открыт один раз.</li></ol></div>
|
||
</section>
|
||
</div>
|
||
|
||
|
||
|
||
<script src="./app.js"></script>
|
||
</body></html> |