このファイルは v1 完成までの開発記録。プロジェクト紹介・利用案内は
../README.mdを参照。設計の全文はdesign.md、数学リファレンスはmath-notes.md、授業進行プランはlesson-plans.md。
大学情報系学部・初学者向けに、ニューラルネットワークの forward / backward / update を ノード 1 つずつの粒度で観察できる GUI シミュレータ。配布物は単一 HTML で、ブラウザで開くだけで動く (v1)。
以下は v1 完成までのフェーズ別ログ + UI/UX 調整の記録。後追いで触る人がコードを読むときの「なぜそうなっているか」の参考。
| フェーズ | 内容 | 状態 |
|---|---|---|
| P0 | 設計書 | 完了 (docs/design.md) |
| P1 | 純計算 (rng, model, datasets) + NumPy 参照実装 + 数値一致テスト | 完了 |
| P2 | view.js の静的描画 + Forward 1 回実行 + 式の展開 (Forward 時) | 完了 |
| P3 | Forward / Backward アニメーション + Backward 式展開 | 完了 |
| P4 | Update / 学習ループ / Loss 曲線 | 完了 |
| P5 | 決定境界 / Lesson 定義 | 完了 |
| P6 | 単一 HTML への bundle / オフライン検証 | 完了 |
P6 で動くもの (P5 に加え):
tools/bundle.py を追加。src/index.html の <link rel="stylesheet"> と
<script type="module" src="./js/controller.js"> を、style.css 本体と
src/js/*.js を依存順 (rng → datasets → lessons → model → view → controller)
に連結したインラインブロックに差し替えて build/nn_sim.html に書き出す。
外部依存なし (Python 標準ライブラリのみ・CDN 参照なし)。import 文を削除し export を剥がす方式。
ファイルをまたぐトップレベル名の衝突は build 時点で検出して中断する
(現時点では view.js 側の fmtSigned を fmtSignedShort に改名して回避)。build/nn_sim.html はサーバ不要。file:// で直接開いて
Forward / Backward / Update / Loss / 決定境界 / Lesson1〜Lesson8 まで全機能動作。tests/py/test_bundle.py が make bundle 成果物の健全性
(サイズ上限 / 外部参照が残っていない / モジュール順 / 主要な宣言の存在 等)
を 7 項目自動チェック。単一 HTML を生成するには:
make bundle # → build/nn_sim.html (単一 HTML)
Noise σ と N を UI から指定でき、設計書 §6.6 / §8 の要請どおり
freshDataRng で rngData を毎回サブシードから作り直すので
「同じ seed + 同じ σ → 同じ分布」が保たれる。Speed スライダで 0 (アニメなし) ~
3× までリアルタイム切り替え。0× で Forward / Backward の粒と Update
パルスを全部スキップするので、Run 時の学習が高速モードになる。prompt() が開き、現在値を
直接書き換えられる (設計書 §8:「わざと大きい値に振る」デモ用)。
編集後は Forward / Backward の結果が陳腐化するので phase を idle に戻し、
決定境界も新しい重みで即再描画。model.js に isNetDiverged(net) を
追加し、a / z / W / b / dL_* のいずれかに NaN / Inf が現れた時点で
検出。Forward / Backward / Update / 1 Step / Run の直後にこれが真だと、
state.diverged = true にして Forward 系ボタンを一斉に disabledReset / Reset to Lesson のいずれかを押すと state.diverged が false に
戻り、ボタンも再度使えるようになる。
手描き 2D 2 クラス
(DRAW_2D) を追加。これを選ぶと決定境界タブに [-1, 1] × [-1, 1] の
キャンバスが出て、
を置ける。点は state.drawPoints に貯まって通常 Reset では消えず、
そのまま 1 Step / Run で学習できる。Reset to Lesson を押すと明示的に
クリアされる (Lesson の想定データと混ざらないように)。
datasets.js 側では BUILTIN.DRAW_2D を deterministic: true, userDrawn: true
として登録し、make(_rng, { points }) で渡された点の deep-copy を返す。
Export JSON /
Import JSON ボタンを追加。Export は現在のネット (sizes / activations /
loss / lr / seed / initScheme / dataset / W / b / drawPoints) を
nn-simulator/v1 形式の JSON としてダウンロードする
(ファイル名は nn-sim_{sizes}_seed{seed}_{timestamp}.json)。Import は
ファイル選択ダイアログを開き、createNet + loadWeights で復元した
あと UI フィールドも書き戻す。これにより「学習の途中状態を保存して
別の日に続きから実行」「Lesson7 で収束した状態を配布してみんなで
決定境界を観察」といった授業オペレーションが可能になる。
model.js レベルのラウンドトリップ (snapshot → JSON.stringify →
JSON.parse → createNet + loadWeights → forward が一致) は
tests/js/test_export_roundtrip.test.mjs で float64 精度まで検証済み。src/js/lessons.js の Lesson1〜Lesson8 で、hint と 3 つの checks を「UI のどこを見るか (例: w はエッジ中央、b は青バッジ)」「どう操作するか (例: ダブルクリックで書き換え、Forward → Backward → Update の順に押す)」「数式記号は何を指しているか (例: dL/dw, dL/db, δ, φ’ の意味)」の 3 層構造に書き直した。Lesson セレクタから選んだ瞬間に右パネル「レッスン」タブにそのまま表示される。バンドルサイズは 147 KB → 156 KB に増えたので、サイズ予算 (tools/bundle.py の SIZE_BUDGET_BYTES と tests/py/test_bundle.py のアサート、設計書 §10) を 150 KB → 175 KB に引き上げ。src/js/controller.js から src/js/explain.js に切り出し。
controller 側は renderExplain() が ui.explainBody.innerHTML =
renderExplainHtml(state) を呼ぶだけの薄いラッパになり、1000 行近く
縮んだ (2193 → 1262 行)。DOM 触りは controller、純 string-building は
explain、という責務分離になったので、数式表記を調整したいときに
controller のイベント配線を開かずに済む。バンドラの依存順も
view.js → explain.js → controller.js に更新済み。P5 で動くもの (P4 に加え):
Lesson<n> で統一。LINEAR_1D (y = 2x の 5 点) と SIGMOID_1D (σ(x) の 5 点) を追加。P4 で動くもの (P3 に加え):
update()。P3 で動くもの (P2 に加え):
P2 で動くもの:
ローカルで動作確認するには:
make serve # → http://localhost:8000/ でブラウザから開く
uv 0.11+初回:
uv sync # Python 依存 (numpy, pytest) を .venv に揃える
node --version # v20 以上であることを確認
make test # JS + Python の全テストを一括実行
make test-js # tests/js/*.test.mjs を node --test で
make test-py # tests/py を uv run pytest で
make fixtures # tests/fixtures/*.json を NumPy 参照実装から再生成
現時点で Python 16 件 (うち P6 バンドラ 7 件) / JS 55 件 のテストが通っている状態。
prompt/ プロジェクト総則 (既存前提)
docs/design.md 設計書 (最新版)
docs/math-notes.md 画面で展開される数式の定義・導出リファレンス
docs/lesson-plans.md Lesson1〜8 を授業で進行する際のプラン
src/js/ JS 純計算 (rng, model, datasets) + view/explain/controller
src/index.html UI エントリ (P2 以降)
tests/py/ NumPy 参照実装 + pytest
tests/js/ node:test ベースの JS 単体テスト
tests/fixtures/ 参照実装が生成する共通フィクスチャ (JSON)
tools/bundle.py 単一 HTML 生成スクリプト (make bundle から呼ばれる)
build/nn_sim.html 配布用単一 HTML (make bundle が生成, .gitignore 対象)
Makefile 開発タスク一覧 (make help)
pyproject.toml uv が管理する Python 依存
main.py は uv init が残したスキャフォルド。本プロジェクトでは使わないので削除して構わない (権限の都合で自動削除しなかった)。