1. 概要
1.1 目的
本文書は、ブラウザ上で動作するインタラクティブ・ニューラルネットワーク学習ビジュアライザ
neural_network.html の詳細設計を記述する。
XOR問題を題材に、3層フィードフォワードNNの順伝播・逆伝播をフルスクラッチ実装し、
Canvas上にリアルタイムで可視化する。
1.2 スコープ
| 項目 | 内容 |
|---|---|
| 対象ファイル | neural_network.html(単一ファイル、外部依存なし) |
| 実行環境 | モダンブラウザ(Chrome / Edge / Firefox / Safari) |
| 技術スタック | HTML5 + CSS3 + Vanilla JavaScript(ES6+) |
| 外部ライブラリ | なし(ゼロ依存) |
1.3 機能一覧
| ID | 機能 | 説明 |
|---|---|---|
| F-01 | ネットワーク構築 | 隠れ層ニューロン数(2〜12)をスライダーで動的変更 |
| F-02 | 活性化関数切替 | Sigmoid / Tanh / ReLU を選択可能 |
| F-03 | 学習率調整 | 0.01〜1.00 をスライダーで制御 |
| F-04 | 自動学習 | requestAnimationFrame ループで毎フレーム20エポック実行 |
| F-05 | ステップ実行 | 1エポックずつ手動実行 |
| F-06 | テスト推論 | XOR 4パターンの入力を選択して出力を確認 |
| F-07 | リアルタイム描画 | ノード・重み結線・パーティクルをCanvas描画 |
| F-08 | ツールチップ | ノードホバーで重み・バイアス・出力値を表示 |
| F-09 | 活性化関数説明モーダル | 数式・グラフ・特徴をタブ形式で表示 |
| F-10 | ログ出力 | 生成・学習のマイルストーンをテキストログ表示 |
2. システム構成図
本システムは単一HTMLファイルに全コードが格納されたクライアントサイドアプリケーションである。
graph TB
subgraph Browser["🌐 ブラウザ"]
direction TB
subgraph HTML_File["neural_network.html"]
direction LR
HTML["HTML
DOM構造"] CSS["CSS
スタイル定義"] JS["JavaScript
ロジック全体"] end subgraph JS_Modules["JavaScript モジュール構成"] direction TB NN["NeuralNetwork
クラス"] Renderer["Canvas
レンダラー"] UI["UIイベント
ハンドラ"] Modal["モーダル
コントローラ"] GraphDraw["活性化関数
グラフ描画"] end subgraph APIs["ブラウザ API"] Canvas2D["Canvas 2D API"] RAF["requestAnimationFrame"] DOMAPI["DOM API"] end HTML_File --> JS_Modules NN --> Renderer UI --> NN UI --> Modal Modal --> GraphDraw Renderer --> Canvas2D Renderer --> RAF UI --> DOMAPI end User(("👤 ユーザー")) --> Browser
DOM構造"] CSS["CSS
スタイル定義"] JS["JavaScript
ロジック全体"] end subgraph JS_Modules["JavaScript モジュール構成"] direction TB NN["NeuralNetwork
クラス"] Renderer["Canvas
レンダラー"] UI["UIイベント
ハンドラ"] Modal["モーダル
コントローラ"] GraphDraw["活性化関数
グラフ描画"] end subgraph APIs["ブラウザ API"] Canvas2D["Canvas 2D API"] RAF["requestAnimationFrame"] DOMAPI["DOM API"] end HTML_File --> JS_Modules NN --> Renderer UI --> NN UI --> Modal Modal --> GraphDraw Renderer --> Canvas2D Renderer --> RAF UI --> DOMAPI end User(("👤 ユーザー")) --> Browser
図2-1: システム全体構成図
📌 設計方針
外部CDN・ビルドツール・フレームワークを一切使用せず、1ファイルで完結させる。
HTMLを開くだけで即座に動作し、オフライン環境でも利用可能。
3. ニューラルネットワーク アーキテクチャ
3.1 ネットワーク構造
3層フィードフォワードネットワーク(入力層 → 隠れ層 → 出力層)を採用する。
graph LR
subgraph Input["入力層 (2)"]
x1(("x₁"))
x2(("x₂"))
end
subgraph Hidden["隠れ層 (2〜12)"]
h1(("h₁"))
h2(("h₂"))
h3(("h₃"))
h4(("h₄"))
hN(("…"))
end
subgraph Output["出力層 (1)"]
y(("ŷ"))
end
x1 -- "wIH[0][0]" --> h1
x1 -- "wIH[0][1]" --> h2
x1 -- "wIH[0][2]" --> h3
x1 -- "wIH[0][3]" --> h4
x1 --> hN
x2 -- "wIH[1][0]" --> h1
x2 -- "wIH[1][1]" --> h2
x2 -- "wIH[1][2]" --> h3
x2 -- "wIH[1][3]" --> h4
x2 --> hN
h1 -- "wHO[0]" --> y
h2 -- "wHO[1]" --> y
h3 -- "wHO[2]" --> y
h4 -- "wHO[3]" --> y
hN --> y
図3-1: ネットワークトポロジー(隠れ層4ノードの例)
3.2 層仕様
| 層 | ノード数 | 活性化関数 | パラメータ |
|---|---|---|---|
| 入力層 | 2(固定) | なし(恒等写像) | なし |
| 隠れ層 | 2〜12(可変) | Sigmoid / Tanh / ReLU(選択式) | wIH[2][H], bH[H] |
| 出力層 | 1(固定) | Sigmoid(固定) | wHO[H], bO |
3.3 パラメータ数
計算式
隠れ層ノード数を H とすると:
入力→隠れ 重み : 2 × H
隠れバイアス : H
隠れ→出力 重み : H
出力バイアス : 1
──────────────────
合計パラメータ : 4H + 1
| H | 2 | 4 | 8 | 12 |
|---|---|---|---|---|
| パラメータ数 | 9 | 17 | 33 | 49 |
3.4 重み初期化
全重み・バイアスを U(-1, 1) の一様乱数で初期化する。
const rand = () => Math.random() * 2 - 1;
4. クラス設計
classDiagram
class NeuralNetwork {
+int hSize
+string actName
+Function act
+Function dact
+float~~ wIH
+float~ bH
+float~ wHO
+float bO
+int epoch
+float loss
+init() void
+forward(x0, x1) ForwardResult
+train(data, lr) void
}
class ForwardResult {
+float~ hOut
+float out
}
class Renderer {
+resize() void
+draw() void
+nodePositions() Position~~
+weightColor(w) string
}
class UIController {
+createNN() void
+startTraining() void
+stopTraining() void
+trainLoop() void
+runForward(inp) void
+updateStats() void
+log(msg) void
}
class ModalController {
+open() void
+close() void
+switchTab(name) void
+drawAllGraphs() void
+drawActGraph() void
}
NeuralNetwork --> ForwardResult : returns
UIController --> NeuralNetwork : owns
UIController --> Renderer : triggers
UIController --> ModalController : opens
Renderer --> NeuralNetwork : reads state
図4-1: クラス図
4.1 NeuralNetwork クラス
| メソッド | 引数 | 戻り値 | 説明 |
|---|---|---|---|
constructor | hiddenSize, activationName | ― | インスタンス生成・init()呼出 |
init() | ― | void | 全パラメータをランダム初期化 |
forward(x0, x1) | x0: float, x1: float | {hOut, out} | 順伝播を実行し各層の出力を返す |
train(data, lr) | data, lr: float | void | 全データで1エポック分の学習を実行 |
4.2 プロパティ詳細
| プロパティ | 型 | 形状 | 説明 |
|---|---|---|---|
wIH | float[][] | [2][H] | 入力→隠れ層の重み行列 |
bH | float[] | [H] | 隠れ層のバイアスベクトル |
wHO | float[] | [H] | 隠れ→出力層の重みベクトル |
bO | float | scalar | 出力層のバイアス |
act / dact | Function | ― | 活性化関数とその導関数 |
5. 順伝播(Forward Propagation)
flowchart LR
A["入力 x₁, x₂"] --> B["線形変換 z_j"]
B --> C["活性化 h_j = act(z_j)"]
C --> D["線形変換 z_o"]
D --> E["Sigmoid σ(z_o)"]
E --> F["出力 ŷ"]
style A fill:#1a3a5a,color:#fff
style C fill:#3a1a5a,color:#fff
style E fill:#5a1a3a,color:#fff
style F fill:#1a5a3a,color:#fff
図5-1: 順伝播データフロー
5.1 隠れ層の計算
for (let j = 0; j < H; j++) {
let z = wIH[0][j] * x0 + wIH[1][j] * x1 + bH[j];
hOut[j] = act(z); // act = sigmoid | tanh | relu
}
5.2 出力層の計算
let zO = bO;
for (let j = 0; j < H; j++) zO += wHO[j] * hOut[j];
const out = sigmoid(zO); // 出力層は常にSigmoid
6. 逆伝播(Backpropagation)
flowchart RL
L["損失 E"] --> dO["出力δ"]
dO --> dW2["wHO 更新"]
dO --> dH["隠れδ"]
dH --> dW1["wIH 更新"]
dH --> dB1["bH 更新"]
dO --> dB2["bO 更新"]
style L fill:#5a1a1a,color:#fff
style dO fill:#5a3a1a,color:#fff
style dH fill:#3a1a5a,color:#fff
図6-1: 逆伝播による勾配の流れ
6.1 誤差と出力層の勾配
const err = target - out; // 誤差
totalLoss += err * err; // 二乗誤差 (MSE用)
const dO = err * dsigmoid(out); // 出力層δ
6.2 隠れ層への勾配伝播
for (let j = 0; j < H; j++) {
dH[j] = dO * wHO[j] * dact(hOut[j]);
}
6.3 パラメータ更新
for (let j = 0; j < H; j++) {
wHO[j] += lr * dO * hOut[j]; // 隠れ→出力 重み
wIH[0][j] += lr * dH[j] * x0; // 入力→隠れ 重み (x₁側)
wIH[1][j] += lr * dH[j] * x1; // 入力→隠れ 重み (x₂側)
bH[j] += lr * dH[j]; // 隠れバイアス
}
bO += lr * dO; // 出力バイアス
⚠ 注意: オンライン学習
本実装ではミニバッチではなく、各サンプルごとに即座に重みを更新するオンラインSGD方式を採用。
4サンプル(XOR全パターン)を1巡すると1エポックとしてカウントする。
7. 活性化関数
| 名称 | 関数 f(x) | 導関数 f'(x) | 出力範囲 | 0中心 |
|---|---|---|---|---|
| Sigmoid | 1 / (1 + e⁻ˣ) | f(x)·(1−f(x)) | (0, 1) | ✗ |
| Tanh | tanh(x) | 1 − f(x)² | (−1, 1) | ✓ |
| ReLU | max(0, x) | x>0 ? 1 : 0 | [0, ∞) | ✗ |
7.1 関数選択ロジック
function getAct(name) {
if (name === 'tanh') return [tanhAct, dtanh];
if (name === 'relu') return [relu, drelu];
return [sigmoid, dsigmoid]; // デフォルト
}
📌 設計判断: 出力層の固定
出力層は常にSigmoidを使用する。XOR問題の正解ラベルが {0, 1} であるため、
出力を [0, 1] に制限する必要がある。隠れ層のみ活性化関数の切替を適用する。
8. シーケンス図
8.1 自動学習フロー
sequenceDiagram
actor User as ユーザー
participant UI as UIController
participant NN as NeuralNetwork
participant R as Renderer
participant C as Canvas
User->>UI: 学習開始ボタン押下
activate UI
UI->>UI: training = true
UI->>UI: trainLoop開始
loop 毎フレーム rAF
loop 20回
UI->>NN: train(XOR, lr)
activate NN
loop 各サンプル x4
NN->>NN: forward
NN->>NN: 誤差δ計算
NN->>NN: 重み更新
end
NN-->>UI: epoch++ loss更新
deactivate NN
end
UI->>UI: updateStats
UI->>R: draw
activate R
R->>R: nodePositions計算
R->>C: clearRect
R->>C: 結線描画
R->>C: パーティクル描画
R->>C: ノード描画
R-->>UI: 描画完了
deactivate R
end
User->>UI: 停止ボタン押下
UI->>UI: training = false
deactivate UI
図8-1: 自動学習シーケンス図
8.2 テスト推論フロー
sequenceDiagram
actor User as ユーザー
participant UI as UIController
participant NN as NeuralNetwork
participant D as DOM
User->>UI: XOR入力パターン選択
activate UI
UI->>UI: selectedInput設定
UI->>NN: forward(x0, x1)
activate NN
NN->>NN: 隠れ層計算
NN->>NN: 出力層計算
NN-->>UI: hOut, out
deactivate NN
UI->>D: predResult更新
UI->>UI: draw呼出
deactivate UI
図8-2: テスト推論シーケンス図
8.3 活性化関数モーダル表示フロー
sequenceDiagram
actor User as ユーザー
participant UI as UIController
participant M as ModalController
participant GC as GraphCanvas
User->>UI: ?ボタン押下
activate UI
UI->>M: open
activate M
M->>M: 現在の活性化関数タブ選択
M->>M: modal show
M->>GC: drawAllGraphs
activate GC
GC->>GC: sigmoid描画
GC->>GC: tanh描画
GC->>GC: relu描画
GC-->>M: 完了
deactivate GC
deactivate M
deactivate UI
User->>M: タブ切替
activate M
M->>M: 表示タブ切替
M->>GC: drawAllGraphs
deactivate M
User->>M: 閉じる
M->>M: modal hide
図8-3: モーダル表示シーケンス図
9. 状態遷移図
stateDiagram-v2
[*] --> Idle : ページロード createNN
Idle --> Training : 学習開始押下
Idle --> Idle : リセット押下
Idle --> Idle : 1ステップ押下
Idle --> Idle : テスト入力選択
Training --> Idle : 停止押下
Training --> Idle : リセット押下
Training --> Training : 毎フレーム train+draw
state Training {
[*] --> LoopFrame
LoopFrame --> Train20 : rAF
Train20 --> UpdateUI : stats更新
UpdateUI --> Draw : 描画
Draw --> LoopFrame : 次フレーム
}
図9-1: アプリケーション状態遷移図
10. UIコンポーネント構成
graph TB
subgraph Page["HTMLページ"]
Header["header - タイトル"]
Container["div.container - Flexboxレイアウト"]
ModalOv["div.modal-overlay - モーダル背景"]
Foot["footer"]
end
subgraph Container
CW["div.canvas-wrap - NNキャンバス"]
Panel["div.panel - 右パネル"]
end
subgraph CW
NNC["canvas#nnCanvas"]
end
subgraph Panel
CA["card: アーキテクチャ"]
CT["card: テスト入力"]
CC["card: トレーニング"]
CL["card: ログ"]
end
subgraph ModalOv
MH["ヘッダー + 閉じるボタン"]
TB["タブバー Sigmoid/Tanh/ReLU"]
TS["tab: Sigmoid"]
TT["tab: Tanh"]
TR["tab: ReLU"]
end
Header --> Container
Container --> Foot
CA -.->|?ボタン| ModalOv
図10-1: UIコンポーネントツリー
10.1 レスポンシブ対応
| ブレークポイント | レイアウト |
|---|---|
| 861px 以上 | Canvas (flex:1) + Panel (320px) の横並び |
| 860px 以下 | Canvas → Panel の縦積み |
11. Canvas 描画仕様
11.1 描画レイヤー順序
| Z順 | レイヤー | 説明 |
|---|---|---|
| 1 (背面) | 結線 | 入力→隠れ、隠れ→出力の全結合線 |
| 2 | パーティクル | 信号伝達を示すアニメーション粒子 |
| 3 | ノード (Glow) | RadialGradient によるグロー効果 |
| 4 (前面) | ノード (Circle + Label) | 円形ノード・ラベル・数値 |
11.2 結線の色・太さルール
| 重みの符号 | 色 | 太さ |
|---|---|---|
| 正 (w > 0) | Cyan rgba(0,210,255,α) | min(4, |w| × 1.5 + 0.3) |
| 負 (w < 0) | Red rgba(255,80,80,α) |
αは |tanh(w)| × 0.7 + 0.1 で算出。重みの絶対値が大きいほど色が濃く、線が太くなる。
11.3 パーティクルアニメーション
| 方向 | 色 | 周期 | 条件 |
|---|---|---|---|
| 入力→隠れ | Cyan | 2000ms | lastForward が存在 |
| 隠れ→出力 | Magenta | 2000ms (位相+1000ms) | 同上 |
11.4 高DPI対応
dpr = window.devicePixelRatio || 1;
canvas.width = W * dpr;
canvas.height = H * dpr;
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
11.5 ノード配置アルゴリズム
function nodePositions() {
// padX=100, padY=60 の余白を確保し
// 各層を X 方向に等間隔配置
// 各層内のノードを Y 方向に均等分配
const x = padX + (usableW / 2) * layerIndex;
const y = padY + (usableH / (nodeCount + 1)) * (nodeIndex + 1);
}
12. データ仕様
12.1 学習データ(XOR)
| x₁ | x₂ | target (XOR) |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
const XOR = [[0,0,0], [0,1,1], [1,0,1], [1,1,0]];
12.2 損失関数
平均二乗誤差(MSE)を使用する。
loss = (1/N) × Σ (target - output)²
= (1/4) × Σ (target_i - ŷ_i)²
12.3 収束判定
本実装では明示的な収束判定は設けず、ユーザーが Loss 値を目視確認して停止する設計。 典型的には Loss < 0.001 で実用的に収束とみなせる。
13. イベント一覧
| 要素 | イベント | 処理内容 |
|---|---|---|
#hiddenSize | input | 表示値更新 |
#hiddenSize | change | 停止→NN再生成→再描画 |
#activation | change | 停止→NN再生成→再描画 |
#lr | input | 学習率の表示値更新 |
#btnTrain | click | 学習ループ開始 |
#btnStop | click | 学習ループ停止 |
#btnReset | click | 停止→NN再生成→再描画 |
#btnStep | click | 1エポック実行→ログ出力 |
.input-grid div | click | テスト入力選択→forward→再描画 |
#btnActInfo | click | モーダルを開き現在の関数タブを選択 |
#modalClose | click | モーダルを閉じる |
.modal-overlay | click | 背景クリックでモーダルを閉じる |
.tab-btn | click | タブ切替→グラフ再描画 |
#nnCanvas | mousemove | ノード判定→ツールチップ表示 |
#nnCanvas | mouseleave | ツールチップ非表示 |
window | resize | Canvas リサイズ→再描画 |
14. 非機能要件
| 項目 | 要件 | 実現手段 |
|---|---|---|
| パフォーマンス | 60fps での描画を目標 | requestAnimationFrame + Canvas 2D |
| 互換性 | 主要4ブラウザ対応 | ES6 + 標準API のみ使用 |
| ポータビリティ | 単一ファイルで動作 | 外部依存ゼロ、インラインCSS/JS |
| オフライン | ネットワーク不要で動作 | CDN不使用(本体) |
| 高DPI対応 | Retinaディスプレイ対応 | devicePixelRatio によるCanvas拡縮 |
| レスポンシブ | モバイル〜デスクトップ対応 | Flexbox + メディアクエリ |
| アクセシビリティ | キーボード操作可能 | ネイティブ button / select 要素を使用 |
15. 用語集
| 用語 | 説明 |
|---|---|
| フィードフォワード | 信号が入力→出力の一方向にのみ流れるネットワーク構造 |
| バックプロパゲーション | 出力の誤差を逆方向に伝播させ、勾配降下法でパラメータを更新する学習アルゴリズム |
| エポック | 全学習データを1巡する学習単位 |
| SGD | 確率的勾配降下法。1サンプルずつ勾配を計算してパラメータを更新する最適化手法 |
| MSE | 平均二乗誤差。予測値と正解値の差の二乗の平均 |
| XOR問題 | 線形分離不可能な問題の代表例。隠れ層なしでは解けない |
| 勾配消失 | 逆伝播時に勾配が層を遡るほど小さくなり学習が進まなくなる現象 |
| Dying ReLU | ReLUで負の入力が続くとニューロンが恒常的に0を出力し回復しない現象 |