このファイルは Transformer 版の開発記録 (フェーズごと、UI/UX 調整、決定事項など)。プロジェクト紹介・利用案内は
../README.md、設計の全文はdesign.mdを参照。
姉妹プロジェクト nn-anatomy (MLP 版 v1) の哲学を Transformer に拡張した教材。実装は新規だが、思想・テスト方針・bundle 戦略は v1 から継承。
| フェーズ | 内容 | 状態 |
|---|---|---|
| P0 | 設計書 + プロジェクト雛形 | 完了 (v0.3 で hand-crafted preset 方針確定) |
| P1 | matrix.js + tokenizer.js + numpy 参照実装 | 完了 (JS 27 / Python 13 = 40 件、PyTorch 不採用) |
| P2 | tools/build_preset.py + デフォルト preset 構築 | 完了 (Python +23 件、preset 26.1 KB、self-check 16/16) |
| P3 | Tier 1 model.js (forward only) + presets.js inline | 完了 (JS +12 = 39 件、attention fixture と 1e-12 一致、計 75 件) |
| P4 | Tier 1 view.js (静的描画) + pan/zoom + 最小 controller | 完了 (bundle 53.6 KB、Tier 1 が画面に出る) |
| 中間 | レイアウトを上下分割に変更 | 完了 (controls / network / side の縦 3 段、bundle 54.1 KB) |
| P5 | Tier 1 explain.js + cell click/hover + Attention Map 常駐 | 完了 (bundle 72.1 KB、8 種行列の 3 段板書) |
| P6 | Tier 1 Lesson T1-T5 + UI Lesson セレクタ | 完了 (bundle 85.6 KB、JS +8 = 47 件、計 83 件) |
| P7 | Tier 2 (Multi-Head + 残差 + LN + FFN) + Lesson T6-T8 | 未着手 |
| P6 | Tier 1 Lesson T1-T5 + 8 文セレクタ | 未着手 |
| P7 | Tier 2 (Multi-Head + 残差 + LN + FFN) + Lesson T6-T8 | 未着手 |
| P8 | Tier 3 (多 Block + 複数 Preset 切替) + Lesson T9 + ドキュメント完備 | 未着手 |
docs/design.md v0.2 作成 (= forward 専用 + 日本語 vocab + preset ベースの全面書き直し)README.md: プロジェクト紹介、想定する完成像、ロードマップMakefile: serve / test / test-js / test-py / fixtures / train-preset / bundle / cleanpyproject.toml: PyTorch + pytest 依存package.json: ES module 宣言のみ.gitignore: v1 と同等src/js/rng.js: v1 から流用 (PE 生成と内部の決定的乱数のみで使用、学習しない)tools/bundle.py: v1 から流用、出力ファイル名と MODULE_ORDER を Transformer 用に書き換えdocs/ src/js/ tests/js/ tests/py/ tools/ build/ presets/rng.js をそのままコピー).gitignore の方針tools/train_preset.py が repo 開発側のスクリプトで preset を生成する。design.md §14 に残す。src/js/tokenizer.js: 16 語固定 vocab + encode/decode + 8 例文 (SAMPLE_SENTENCES)src/js/matrix.js: matmul / softmax / layerNorm / gelu / transpose ほか、flat-array ベースtests/py/reference.py: numpy で同等計算、float64 で fixture JSON 出力tests/py/test_reference.py: numpy 参照の sanity check (13 件)tests/js/test_tokenizer.test.mjs: vocab 整合性、encode/decode 往復、サンプル文 (12 件)tests/js/test_matrix.test.mjs: numpy fixture と 1e-12 オーダ一致 (15 件)tests/py/reference.py を当初 PyTorch 予定で作っていたが、uv sync が timeout (~200MB の torch CPU 版ダウンロード) したため numpy ベースに切り替えnumpy.var (ddof=0 = 有偏) は PyTorch の F.layer_norm と一致するので、後から PyTorch を再投入することになっても 1e-12 オーダで揃う0.5 * x * (1 + tanh(sqrt(2/π) * (x + 0.044715 * x^3))) で JS / numpy 完全一致tools/build_preset.py (~280 行、numpy のみ): 設計書 §6.9 の表どおりに W_E / W_P / W_Q / W_K / W_V / W_O を書き込み、self-check (8 例文 × 2 関係 = 16 件) が softmax 後 0.5 以上で通ることを検証presets/japanese-mini-v1.json (26.1 KB): デフォルト preset として生成tests/py/test_build_preset.py (~150 行、23 テスト): embedding 各 dim、W_Q/W_K の bond、JSON 構造、parametrize で 8 例文すべての attention pattern を独立テストattention pattern の強さ範囲: 0.78〜0.96 (= 教育的に「明確に注目」と読める)
tools/inline_preset.py: presets/japanese-mini-v1.json を読み込んで src/js/presets.js (ES module、export const DEFAULT_PRESET = {...}) を生成。インデント無しで詰めて書き出すため 26.1 KB → 8.6 KB に圧縮src/js/model.js (~140 行): createTransformer({ preset }) で preset から flat-array 構造体を構築、forward(net, tokens) で Embedding + PE → Q/K/V → scaled dot-product attention → output projection を計算。reset(net) で中間結果クリアtests/py/generate_fixtures.py を拡張: 8 例文を numpy で forward した結果 (X, Q, K, V, scores, attn, attnOut, Y) を tests/fixtures/p3_attention.json に出力tests/js/test_model.test.mjs (~200 行、12 テスト): 構造的テスト (createTransformer / forward / reset / 例外処理) + 8 例文すべての中間結果が numpy fixture と 1e-12 一致 + 主要 attention pattern (美しい→花、私→猫、読む→本) が 0.5 以上net.X[t * d_model + d] のような index 計算でアクセス。ネスト配列より速く、後で WebGPU 化容易blocks[0].W_Q のように管理src/index.html (~80 行): UI scaffold (controls / network / side パネル + タブ)src/style.css (~190 行): 3 領域 grid レイアウト、行列ヒートマップ用のセル / ラベル / pan/zoom コントロールsrc/js/view.js (~280 行): 行列ヒートマップ描画 (signed: 青/赤グラデーション、attn: 青濃淡)、Embed/Q/K/V/Attn/Out タブ切替、SVG viewBox の drag/wheel pan/zoom、Fit/100% ボタンsrc/js/controller.js (~130 行): 最小限のイベント配線 (Sample 切替、Forward、Reset、タブ切替、pan/zoom)src/js/lessons.js src/js/explain.js: P5/P6 用のスタブ (空 export だけ、bundle.py の MODULE_ORDER を満たすため)make bundle で build/nn_sim_transformer.html (53.6 KB) が生成、file:// で開けば Tier 1 の Self-Attention 全 6 行列 (X, Q, K, V, scores, attn, attnOut, Y) がヒートマップとして見える| signed セル色: 青=負 / 白=0 / 赤=正、明度は | v | / | v | _max で正規化。行列ごとに max を取るので、値の絶対値が小さい行列でも違いが見える。 |
| モジュール | 寄与 |
|---|---|
| presets.js (inline preset JSON) | ~9 KB |
| view.js | ~10 KB |
| style.css | ~5 KB |
| model.js | ~4 KB |
| matrix.js | ~3 KB |
| controller.js | ~4 KB |
| その他 (rng, tokenizer, lessons stub, explain stub, index.html) | ~18 KB |
予算 250 KB に対して大幅に余裕がある状態。P5 (explain.js) で式テンプレートが入っても 80-100 KB 程度で収まる見込み。
行列は横長 (5×16 = 800 px) なので、右側 480 px の補助パネルが幅を圧迫していた問題を解消。style.css の grid を 1fr × (auto / 1fr / 320px) に変更し、controls / network / side の縦並びにした。これでメインビューが画面幅をフルに使える。bundle 53.6 → 54.1 KB (+0.5 KB のみ、コメント増分)。
src/js/explain.js (~280 行): 各行列のセルクリック時に表示する 3 段板書 HTML テンプレート
[段1] 一般形 → [段2] 当てはめ → [段3] 数値展開 の 3 段構成view.js 側の修正:
createView(svg, net, { onCellClick }) を追加<rect> に click ハンドラを登録、cursor: pointer 設定cell-selected クラスで強調 (orange ストローク)controller.js 側の修正:
onCellClick({ matrix, row, col }) で state.selection を更新 → renderExplain → 自動で「式の展開」タブにフォーカスrenderAttentionMapHtml(): 補助パネルの「Attention Map」タブに T×T のテーブルとして常駐表示。中央パネルがどのタブを見ていても attention map が常に確認できるstyle.css: 数式表示用 (.math, .mnum, .mop)、選択セル強調 (.cell-selected)、Attention Map テーブル (.attmap-table)e^{score_i,j − max} という形で書くことで、数値安定化テクニックが教育的に伝わる| 寄与 | 増分 |
|---|---|
| explain.js (3 段板書テンプレ) | ~10 KB |
| style.css (式表示・attmap・selected) | ~3 KB |
| controller.js (クリック配線、refresh) | ~1 KB |
| view.js (handlers, setSelection, click) | ~1 KB |
| その他 | ~3 KB |
予算 250 KB 内で大幅余裕。Tier 2 で multi-head + LN + FFN を追加しても 130 KB 程度で収まる見込み。
src/js/lessons.js (~110 行): Lesson T1-T5 を LESSONS 配列 + getLesson(id) で公開
src/index.html: Lesson セレクタを Sample の左に追加 (<select id="lesson">)src/js/controller.js:
LESSONS から <option> を生成onLessonChange(): Sample 切替 + viewTab 切替 + 必要なら自動 Forward + 補助パネル「レッスン」タブを activerenderLessonCard(): hint + checks(3) を補助パネルに描画activateSideTab() / activateViewTab() のヘルパで重複を整理escapeHtml を import (top-level 名前衝突を回避)src/style.css: .lesson-card 用のヒント枠 + checks リスト + white-space: pre-line (将来 \n\n💡 補足 区切りに対応)tests/js/test_lessons.test.mjs (~70 行、8 テスト):
💡 補足 で softmax の集中性 (scores 0.25 vs 4 で attn が大きく変わる) を解説。escapeHtml を explain.js から export: MLP 版 v1 でも同じ問題があった。bundle.py の top-level 名前衝突検出が効いて build 時に検出できたので素直に共有化。| 寄与 | 増分 |
|---|---|
| lessons.js (Lesson T1-T5 hint + checks 計約 9 KB の日本語) | ~9 KB |
| controller.js (Lesson 配線、ヘルパ整理) | ~2 KB |
| index.html (Lesson セレクタ追加) | ~0.3 KB |
| style.css (.lesson-card 関連) | ~1 KB |
| その他 | ~1 KB |
予算 250 KB 内で大幅余裕。Tier 2 (multi-head + LN + FFN + Lesson T6-T8) で +50-70 KB を見込んでも 150-160 KB 程度。
src/js/model.js に multi-head + 残差 + LayerNorm + FFN を追加し、設計書 §6.4-§6.6 の数式に従って forward を拡張。build_preset.py で Tier 2 用の重み (W_Q/W_K/W_V を h=2 に分割、LN の γ/β、FFN の W1/b1/W2/b2) を hand-crafted で構築。view.js に FFN タブと head 切り替え UI を追加。Lesson T6-T8 を作成 (Multi-Head の比較、残差+LN、FFN の knowledge memory 観察)。