🔖 キーワード索引
三層パーセプトロンMLP入力層隠れ層出力層万能近似シグモイドfeedforward
三層パーセプトロン (MLP) は入力層・隠れ層・出力層の 3 層構造で、 隠れ層の非線形活性 (ReLU/Sigmoid) によって XOR 等の非線形分離を可能にしたニューラルネットの最小単位。 SSDSE-B-2026 の人口・出生率から「人口減少県か否か」を二値分類する MLP を sklearn.neural_network.MLPClassifier で学習する。
perceptron three layer統計分析SSDSE-B-2026前提条件適用範囲落とし穴関連手法Python 実装検証方法
これらのキーワードは「perceptron three layer の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。
💡 30秒で分かる結論
🍰 まずはやさしく
脳の仕組みをまねたシンプルな計算機です。
複雑なデータのパターンを見つけるために使います。
スマホのアプリなどで、写真の種類を分ける時に役立ちます。
この章では、三層パーセプトロンの基本について読みます。
入力・隠れ・出力からなる最も基本的なNN
- 入力層 + 隠れ層 + 出力層 からなる最も基本的なフィードフォワード NN。
- 万能近似定理:隠れ層が十分大きければ任意の連続関数を近似可能。
- 単層パーセプトロンの限界(XOR 解けない)を 1986年 Rumelhart の誤差逆伝播で打破。
- 今でも表形式データの基準モデル(DNN前の標準)。
- scikit-learn の
MLPClassifier として手軽に使える。
📍 あなたが今見ているもの
🍰 まずはやさしく
AIが進化するための第一歩となる仕組みです。
ニューラルネットワークの基礎を学ぶために使います。
都道府県のデータを分けて、地域の特徴を調べる例で考えます。
この章では、実際にプログラムを作って正解率を確かめます。
深層学習の歴史的・概念的出発点。 「NNとは何か」を理解するにはまず3層MLPを実装してみるのが早道です。
本ページは 三層パーセプトロン を、 SSDSE-B-2026 の社会指標で 47 都道府県の二値分類タスクとして実装する。 隠れ層ニューロン数を 4→8→16 と変えて訓練精度・検証精度を比較し、 単層パーセプトロンが分離できなかった非線形境界を MLP がどう近似するかを観察する。
「perceptron three layer」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。
🎨 直感で掴む
🍰 まずはやさしく
情報を整理して判断する3つのステップのようなものです。
直線では分けられない難しい問題を解くために使います。
部活のメンバーを、複数の条件でグループ分けする時に似ています。
この章では、隠れ層(中間の層)がどう役立つかを読みます。
3層の役割:
- 入力層:データをそのまま受け取る
- 隠れ層:非線形変換で特徴を作る(中間表現)
- 出力層:最終的な予測値を出す
1層では直線(XOR不能)→ 2層あれば曲線分離 → 任意の関数を近似できる、 という大ジャンプがここにあります。
🎨 XOR 問題を 3 層で解く ─ 直感の宝庫
XOR は 1 層パーセプトロン(線形分離器)が解けないことを示し、 1969 年に Minsky & Papert が Perceptrons で指摘した。 3 層なら下記の重みで解ける(手作り解)。
| $x_1$ | $x_2$ | $h_1=\sigma(x_1+x_2-0.5)$ | $h_2=\sigma(x_1+x_2-1.5)$ | $y=\sigma(h_1-h_2-0.5)$ | 期待 |
| 0 | 0 | σ(-0.5) ≈ 0.378 | σ(-1.5) ≈ 0.182 | σ(-0.304) ≈ 0.425 → 0 | 0 ✓ |
| 0 | 1 | σ(0.5) ≈ 0.622 | σ(-0.5) ≈ 0.378 | σ(-0.256) ≈ 0.436 → 0 | 1 ※ |
※ sigmoid は連続値なので、 「学習」して理想重みに収束させると XOR がきれいに解ける。 ステップ関数なら手作り重みでも厳密に成立。 重要なのは 1 隠れ層を入れることで非線形決定境界が表現可能になる事実。
📌 直感:隠れ層は「入力空間を新しい座標系(特徴空間)に写す」装置。 XOR の場合、 隠れ層が「片方だけが 1」という非線形特徴を作るので、 出力層がそれを線形分離できる。
🎮 触って理解する
このページ独自の切り口は「隠れ層が XOR(線形分離不能問題)をどう解くか」です。 姉妹ページ(ニューラルネットワーク=スライダーと決定境界、 NN の表現力=同心円データ、 活性化関数=関数の重ね描き)とは違い、 ここでは入力空間 (x₁, x₂) と隠れ空間 (h₁, h₂) を並べて表示し、 「隠れ層=座標変換」を直接目で確かめます。 順伝播(sigmoid / step)はすべてブラウザ内で正確に計算しており、 外部通信はありません。
XOR の 4 点(● 出力 0=(0,0)・(1,1)、 ● 出力 1=(0,1)・(1,0))を 1 本の直線で分けてみてください。 直線の端の○ハンドルをドラッグ(タッチ可)で回転、 線の中ほどをドラッグで平行移動。 どちら側を「1」と読むかは自動で有利な方を選びます。 どう頑張っても最大 3/4 にしかならないことを体感してください。
これが 1969 年に Minsky & Papert が『Perceptrons』で証明した単層の限界。 (0,1) と (1,0) を通る側と (0,0)・(1,1) を通る側は、 どんな直線でも必ず混ざります。
隠れ層 2 ユニットの三層に切り替えました。 左=入力空間:背景色が出力 y(青=0 / 赤=1)、 破線 2 本が各隠れユニットの分離直線(h=0.5 の等高線)。 右=隠れ空間 (h₁, h₂):4 点が座標変換された後の位置と、 出力層の直線 1 本。 スライダーで隠れユニットの重み・バイアスを動かすと、 入力空間側の決定境界が折れ曲がり、 隠れ空間側では点の配置が動きます。 入力空間をタップすると任意の点の順伝播値を確認できます。
入力空間 (x₁, x₂) — 背景=出力 y
y=0
y=1
隠れ空間 (h₁, h₂) — 変換後の 4 点と出力層の直線
入力空間をタップすると、 その点の順伝播 (h₁, h₂, y) をここに表示します。
💡 直感 ─ 隠れ層は「座標変換装置」であり「特徴抽出器」
学習済み解をセットして隠れ空間を見ると、 入力空間で対角線上に混ざっていた 4 点が、 隠れ空間では一直線で切れる配置に「引っ越し」していることが分かります。 h₁ は「x₁ か x₂ の少なくとも一方が 1(OR 的特徴)」、 h₂ は「両方が 1(AND 的特徴)」を検出しており、 出力層は「OR であって AND でない」という線形分離可能な新しい問題を解いているだけです。 生の座標では解けない問題を、 解ける座標系に写し替える──これが表現学習(representation learning)の最小例であり、 深層学習が画像や言語で行っていることの原型です。
⚠️ 落とし穴 ─ 単層の限界と「線形活性化の罠」
- 単層の限界は「証明された」限界:上のウィジェットで 4/4 にならないのは調整不足ではなく数学的に不可能(Minsky & Papert, 1969)。 この指摘が第 1 次 AI の冬の引き金になった歴史も重要です。
- 活性化が線形なら多層でも線形のまま:もし σ を恒等関数にすると、 W⁽²⁾(W⁽¹⁾x + b⁽¹⁾) + b⁽²⁾ = (W⁽²⁾W⁽¹⁾)x + (定数) となり、 何層積んでも 1 本の直線に縮退します。 ウィジェットの決定境界が「折れ曲がる」のは sigmoid / step の非線形のおかげ。 詳しくは 活性化関数 と シグモイド関数 を参照。
- 2 つの隠れユニットが同じ向きなら失敗する:初期値では h₁ と h₂ の直線が重なっており、 実質 1 本=単層と同じで 3/4 止まり。 隠れユニットは互いに違う特徴を持って初めて意味を持ちます(学習でいう対称性の破れ)。
🚀 発展 ─ 万能近似定理と「それでも深くする」理由
XOR に必要な隠れユニットは 2 個ですが、 これを一般化したのが万能近似定理(Cybenko 1989 / Hornik 1991):非線形活性化を持つ隠れ層 1 枚の MLP は、 隠れユニット数を増やせば任意の連続関数を任意精度で近似できます。 ウィジェットで見た「直線の折れ曲がり」を無数に重ねるイメージです。 ただし浅いまま近似しようとすると必要ユニット数が爆発することがあり、 実用では層を重ねて「特徴の特徴」を段階的に作る方が効率的──これが深層学習への動機です。 なお本ウィジェットは重みを手で与えましたが、 実際にこの解へ自動でたどり着く仕組みが誤差逆伝播と勾配降下法です。 単層の原型は パーセプトロン を参照。
📐 定義/数式
🍰 まずはやさしく
3つの層を重ねた数学的なモデルです。
入力から答えを出すまでの計算ルールを決めるために使います。
買い物で、予算と好みのバランスを計算して商品を選ぶ時に似ています。
この章では、重みや活性化関数(計算の切り替え役)の式を読みます。
三層パーセプトロン(Three-layer Perceptron):入力・隠れ・出力からなる最も基本的なNN
【3層パーセプトロンの式】
$$ \hat{y} = g\Big(W_2 \, \sigma(W_1 \mathbf{x} + \mathbf{b}_1) + \mathbf{b}_2\Big) $$
$W_1, W_2$=層間の重み、 $\sigma$=隠れ層の活性化、 $g$=出力層の活性化(分類ならsoftmax)。
📐 3 層パーセプトロンの完全な式 ─ 前向き計算と勾配
入力 $\mathbf{x} \in \mathbb{R}^{d_0}$、 隠れ層 $\mathbf{h} \in \mathbb{R}^{d_1}$、 出力 $\mathbf{y} \in \mathbb{R}^{d_2}$ とする。 隠れ層活性化を $\sigma_1$、 出力活性化を $\sigma_2$(分類なら softmax)とおく:
$$ \mathbf{z}^{(1)} = W^{(1)} \mathbf{x} + \mathbf{b}^{(1)},\quad \mathbf{h} = \sigma_1(\mathbf{z}^{(1)}) $$
$$ \mathbf{z}^{(2)} = W^{(2)} \mathbf{h} + \mathbf{b}^{(2)},\quad \mathbf{y} = \sigma_2(\mathbf{z}^{(2)}) $$
🔬 数式を言葉で読み解く
- $W^{(1)} \in \mathbb{R}^{d_1 \times d_0}$ … 入力→隠れの重み行列(行が隠れユニット、 列が入力次元)
- $\mathbf{b}^{(1)} \in \mathbb{R}^{d_1}$ … 隠れ層のバイアス(傾きの切片)
- $\sigma_1$ … 活性化関数(sigmoid / tanh / ReLU 等の非線形)。 これが無いと 1 層の線形回帰に縮退する
- $W^{(2)} \in \mathbb{R}^{d_2 \times d_1}$ … 隠れ→出力の重み
- $\sigma_2$ … 出力活性化(回帰なら恒等、 2 値分類なら sigmoid、 多クラスなら softmax)
勾配 ─ 連鎖律を 1 行で
損失 $L$ の重みに対する勾配は、 出力側から順に伝播する(backpropagation):
$$ \boldsymbol{\delta}^{(2)} = \nabla_{\mathbf{z}^{(2)}} L \;=\; (\mathbf{y} - \mathbf{t}) $$
$$ \boldsymbol{\delta}^{(1)} = (W^{(2)})^\top \boldsymbol{\delta}^{(2)} \odot \sigma_1'(\mathbf{z}^{(1)}) $$
$$ \frac{\partial L}{\partial W^{(2)}} = \boldsymbol{\delta}^{(2)} \mathbf{h}^\top,\quad \frac{\partial L}{\partial W^{(1)}} = \boldsymbol{\delta}^{(1)} \mathbf{x}^\top $$
🔬 数式を言葉で読み解く
- $\boldsymbol{\delta}^{(2)} = \mathbf{y} - \mathbf{t}$ … 予測と教師ラベルの「ズレ」が出力誤差。 softmax + cross-entropy の組み合わせならこの単純形になる
- $(W^{(2)})^\top \boldsymbol{\delta}^{(2)}$ … 出力誤差を上位層から隠れ層に「逆向きに流す」
- $\odot \sigma_1'$ … 隠れ層の活性化関数の傾きを掛けると、 隠れ層誤差 $\boldsymbol{\delta}^{(1)}$ になる
- 勾配 $\partial L / \partial W = \boldsymbol{\delta} \mathbf{x}^\top$ は 「誤差 × 入力」の外積で 1 行
万能近似定理(Universal Approximation Theorem)
Cybenko (1989) / Hornik (1991) — 「sigmoid 等の非線形活性化を持つ 1 隠れ層 MLP は、 任意の連続関数を任意精度で近似できる」。
$$ \forall f \in C(K),\ \forall \varepsilon > 0,\ \exists N,\ \exists \{W^{(1)},\mathbf{b}^{(1)},W^{(2)},\mathbf{b}^{(2)}\}:\ \sup_{\mathbf{x} \in K} | g(\mathbf{x}) - f(\mathbf{x}) | < \varepsilon $$
$g(\mathbf{x}) = W^{(2)} \sigma(W^{(1)} \mathbf{x} + \mathbf{b}^{(1)}) + \mathbf{b}^{(2)}$ という 3 層 MLP の形。 つまり「層を深くしなくても表現力はある」のが理論。 ただし必要な隠れユニット数 $N$ が指数的に大きくなることがあるため、 実用では深くする。
📐 活性化関数の比較 ─ なぜ Sigmoid だけでは足りないか
3 層 MLP の表現力は活性化関数 $\sigma_1$ で決まる。 代表 4 種の式と勾配は次のとおり。
$$ \mathrm{sigmoid}(z) = \frac{1}{1+e^{-z}},\quad \sigma'(z) = \sigma(z)(1-\sigma(z)) $$
$$ \tanh(z) = \frac{e^z - e^{-z}}{e^z + e^{-z}},\quad \tanh'(z) = 1 - \tanh^2(z) $$
$$ \mathrm{ReLU}(z) = \max(0, z),\quad \mathrm{ReLU}'(z) = \mathbb{1}[z > 0] $$
$$ \mathrm{GELU}(z) = z \cdot \Phi(z),\quad \Phi: \text{標準正規 CDF} $$
🔬 数式を言葉で読み解く
- sigmoid は (0,1) の確率に潰すが、 飽和領域で勾配 $\sigma(1-\sigma)$ が 0 に近く勾配消失を起こす
- tanh は (-1,1) で対称、 勾配の最大値 1(sigmoid の 0.25 より 4 倍大)
- ReLU は正領域で勾配 1、 計算も $\max$ だけで超軽量。 現代の主流
- GELU は Transformer で標準。 確率的にゲートを開閉するイメージ
| 活性化 | 範囲 | 最大勾配 | 代表用途 |
| sigmoid | (0, 1) | 0.25 | 2 値分類出力、 歴史的 MLP |
| tanh | (-1, 1) | 1.0 | RNN, 小規模 MLP |
| ReLU | [0, ∞) | 1.0 | CNN, 深層 MLP の標準 |
| GELU | (≈0, ∞) | ≈ 1.0 | Transformer (BERT, GPT) |
📐 隠れユニット数とパラメータ数の数え方
入力次元 $d_0$、 隠れ $d_1$、 出力 $d_2$ の 3 層 MLP の総パラメータ数:
$$ N_{\mathrm{param}} = \underbrace{d_0 \cdot d_1}_{W^{(1)}} + \underbrace{d_1}_{\mathbf{b}^{(1)}} + \underbrace{d_1 \cdot d_2}_{W^{(2)}} + \underbrace{d_2}_{\mathbf{b}^{(2)}} $$
🔬 数式を言葉で読み解く
- 第 1 層 $W^{(1)}$ は $d_0 \times d_1$ 個 = 入力ピクセルとユニット間の連結数
- バイアス $\mathbf{b}^{(1)}$ は $d_1$ 個 = ユニットごとに 1 つ
- 第 2 層も同様、 全部足すと総パラメータ数
| 構成 (d0, d1, d2) | パラメータ数 | 想定タスク |
| (2, 3, 3) | 2·3+3+3·3+3 = 21 | SSDSE-B 人口分類(最小) |
| (2, 8, 3) | 2·8+8+8·3+3 = 51 | 本記事の中盤例 |
| (784, 64, 10) | 784·64+64+64·10+10 = 50,890 | MNIST 文字認識 |
| (3072, 512, 10) | 3072·512+512+512·10+10 = 1,578,506 | CIFAR-10 (3072 = 32×32×3) |
📌 47 サンプル(SSDSE-B-2026)に対し (2,8,3)=51 パラメータは サンプル/パラメータ比 ≈ 0.9 で危険水準。 経験則は「サンプル数 ≥ 10 × パラメータ数」。 だから本記事は隠れ 3-4 に抑えた。
📐 勾配消失と Xavier / He 初期化
3 層は浅いので勾配消失は限定的だが、 隠れ層を深くする入口として理解しておく価値がある。 重み $W^{(\ell)}$ の分散を入力次元 $d_{\ell-1}$ で調整するのが Xavier / He 初期化:
$$ \mathrm{Xavier}:\ W \sim \mathcal{N}\!\left(0,\ \frac{2}{d_{\ell-1} + d_{\ell}}\right) $$
$$ \mathrm{He}:\ W \sim \mathcal{N}\!\left(0,\ \frac{2}{d_{\ell-1}}\right) \quad \text{(ReLU 用)} $$
🔬 数式を言葉で読み解く
- 入力次元 $d_{\ell-1}$ が大きいほど、 $\sum w_i x_i$ の分散が大きくなる → 活性化関数が飽和
- 分散を $2/d_{\ell-1}$ にスケールすると、 各層の入力分散が一定に保たれる
- Xavier は sigmoid/tanh 向け(入出力次元の平均で割る)
- He は ReLU 向け(負側を捨てるので係数が 2 倍)
PyTorch / Keras では nn.Linear の初期値が自動でこれに準じる(PyTorch は kaiming_uniform_)。 自前 numpy 実装する場合は明示的に:
# He 初期化(ReLU 用)
W1 = np.random.randn(d0, d1) * np.sqrt(2.0 / d0)
W2 = np.random.randn(d1, d2) * np.sqrt(2.0 / d1)
📐 正則化 ─ L2、 ドロップアウト、 早期終了
小データほど正則化が効く。 3 層 MLP で使う代表 3 手法:
① L2 正則化(weight decay)
$$ L_{\mathrm{reg}} = L_{\mathrm{ce}} + \frac{\lambda}{2} \sum_{\ell} \| W^{(\ell)} \|_F^2 $$
🔬 数式を言葉で読み解く
- $\| W \|_F^2$ … 重みの 2 乗和(Frobenius ノルム)
- $\lambda$ … 正則化強度。 大きいほど重みが 0 に押し込まれる
- sklearn では
alpha パラメータ(デフォルト 0.0001)
② ドロップアウト
学習時、 各隠れユニットを独立確率 $p$ で 0 に「黒塗り」する。 推論時は全ユニットを使い、 出力を $(1-p)$ 倍してスケール調整。
$$ \tilde{h}_j = \begin{cases} 0 & \text{確率 } p \\ h_j / (1-p) & \text{確率 } 1-p \end{cases} $$
🔬 数式を言葉で読み解く
- 確率 $p$(典型 0.2-0.5)でユニットを「壊す」
- 毎ミニバッチで違う部分集合が壊されるので、 ネットワークが暗黙的にアンサンブルになる
- 推論時に $1/(1-p)$ で割って期待値を合わせる(inverted dropout)
③ 早期終了 (Early Stopping)
検証損失 $L_{\mathrm{val}}$ が patience エポック連続で改善しなければ訓練停止:
$$ \text{stop if } L_{\mathrm{val}}^{(t)} \ge \min_{t' \le t - \text{patience}} L_{\mathrm{val}}^{(t')} $$
sklearn では early_stopping=True, validation_fraction=0.1, n_iter_no_change=10。
📐 損失関数 ─ 課題に応じた選択
分類:cross-entropy
$$ L_{\mathrm{ce}} = -\frac{1}{N} \sum_{i=1}^{N} \sum_{c=1}^{C} y_{i,c} \log p_{i,c} $$
回帰:MSE / MAE
$$ L_{\mathrm{mse}} = \frac{1}{N} \sum_{i=1}^{N} (y_i - \hat{y}_i)^2,\quad L_{\mathrm{mae}} = \frac{1}{N} \sum_{i=1}^{N} | y_i - \hat{y}_i | $$
🔬 数式を言葉で読み解く
- cross-entropy は「正解クラスの確率の log」を取った量の符号反転。 完全に当たれば 0、 外せば $\infty$
- MSE は外れ値(残差大)に二乗で重く罰する。 外れ値が結果を引っ張りやすい
- MAE は外れ値に頑健。 ただし勾配が定数なので最適化が遅い
- 分類ヘッドは softmax + cross-entropy、 回帰ヘッドは恒等 + MSE が定型
📐 最適化手法(オプティマイザ)の式
3 層 MLP の学習で使う主要オプティマイザを 1 行式で並べる(時刻 $t$、 学習率 $\eta$、 勾配 $\mathbf{g}_t = \nabla L(\theta_t)$)。
SGD
$$ \theta_{t+1} = \theta_t - \eta \, \mathbf{g}_t $$
SGD + Momentum
$$ \mathbf{v}_{t+1} = \beta \mathbf{v}_t + \mathbf{g}_t,\quad \theta_{t+1} = \theta_t - \eta \, \mathbf{v}_{t+1} $$
Adam
$$ \mathbf{m}_t = \beta_1 \mathbf{m}_{t-1} + (1-\beta_1) \mathbf{g}_t,\quad \mathbf{v}_t = \beta_2 \mathbf{v}_{t-1} + (1-\beta_2) \mathbf{g}_t^2 $$
$$ \theta_{t+1} = \theta_t - \eta \cdot \frac{\hat{\mathbf{m}}_t}{\sqrt{\hat{\mathbf{v}}_t} + \epsilon} $$
🔬 数式を言葉で読み解く
- SGD は素朴な勾配 1 段。 鞍点で止まりやすい
- Momentum は勾配の移動平均。 慣性で平坦地を抜ける
- Adam は 1 次(平均)と 2 次(分散)の両方を追跡し、 パラメータごとに学習率を自動調整
- $\epsilon \approx 10^{-8}$ はゼロ割回避
- SSDSE-B-2026 のような小データなら
solver='lbfgs'(2 次法)も収束高速で実用的
🔬 記号・用語の読み解き(数式を言葉で読み解く)
三層パーセプトロンの順伝播 $\hat{\mathbf{y}} = W_2 \sigma(W_1 \mathbf{x} + \mathbf{b}_1) + \mathbf{b}_2$ は、 「線形変換 → 非線形活性化 → もう一度線形変換」という 3 段階の合成関数として読み解けます。 まず入力ベクトル $\mathbf{x}$(たとえば SSDSE-B-2026 から取った 47 都道府県の特徴量 5 次元)に重み行列 $W_1$ を掛けて隠れ層の入力 $\mathbf{z}_1 = W_1\mathbf{x} + \mathbf{b}_1$ を作る。 これは「入力特徴の重み付き和を、 隠れ層の各ニューロン分計算する」操作で、 内積の集まりです。 次に活性化関数 $\sigma$(ReLU、 sigmoid、 tanh など)が非線形性を導入。 もしこのステップがなければ、 「線形変換 × 線形変換 = 線形変換」となり、 表現力が線形回帰と同じに退化します。 だから「活性化関数こそがニューラルネットの心臓」と言われるのです。 隠れ層の出力 $\mathbf{h} = \sigma(\mathbf{z}_1)$ をさらに $W_2$ で変換し、 出力 $\hat{\mathbf{y}} = W_2\mathbf{h} + \mathbf{b}_2$ を得る。 この構造は、 1989 年の Cybenko の 普遍近似定理(Universal Approximation Theorem)により、 「隠れ層が十分大きければ、 任意の連続関数を任意精度で近似可能」が証明されています。 つまり三層パーセプトロンは「あらゆる入出力関係を学習可能な万能関数近似器」なのです。 学習はバックプロパゲーション(誤差逆伝播)で行われ、 各重みを「予測誤差を減らす方向」に少しずつ更新します。 SSDSE-B-2026 で「都道府県の人口」を 5 つの特徴量から予測するタスクに使えば、 線形回帰では表現できない非線形パターン(例:人口が小さい県と大きい県で進学率の効果が違う、 という交互作用)を捉えられるのが三層パーセプトロンの強み。 三層という構造は最小限の深さでありながら、 「多くの実問題に対して十分な表現力を持つ」中庸の選択肢として、 1980 年代以降のニューラルネットの標準形になりました。
| 記号・用語 | 意味と読み方 |
| $\mathbf{x}$ | 入力ベクトル(特徴量、 SSDSE の場合は標準化された数値) |
| $W_1$ | 入力層→隠れ層の重み行列。 サイズ = (隠れ層ユニット数 × 入力次元) |
| $\mathbf{b}_1$ | 隠れ層のバイアスベクトル。 シフトを表す |
| $\sigma$ | 活性化関数。 ReLU $\max(0, x)$、 sigmoid $1/(1+e^{-x})$、 tanh など |
| $\mathbf{h}$ | 隠れ層の出力。 $\mathbf{h} = \sigma(W_1\mathbf{x} + \mathbf{b}_1)$ |
| $W_2$ | 隠れ層→出力層の重み行列 |
| $\hat{\mathbf{y}}$ | 予測出力。 回帰では実数、 分類では確率(softmax で正規化) |
| $L$ | 損失関数(MSE、 クロスエントロピー等) |
| バックプロパゲーション | 誤差逆伝播。 連鎖律で各重みの勾配を効率計算 |
| 勾配降下法 | $W \leftarrow W - \eta \nabla_W L$ で重みを更新 |
| 学習率 $\eta$ | 更新の大きさ。 小さすぎ→収束遅い、 大きすぎ→発散 |
| エポック | 全データを 1 周する単位。 通常 50〜200 エポックで学習 |
| 普遍近似定理 | Cybenko (1989)。 隠れ層が十分大きければ任意連続関数を近似可能 |
🔬 詳細な解説(深掘り)
概念の本質
三層パーセプトロン(Three-layer Perceptron)は、 単に用語の定義を覚えるだけでは本当には理解できません。 なぜこの概念が生まれたのか、 どんな問題を解決するために導入されたのか、 類似の手法とどう違うのか — これらを意識することで、 初めて「使える知識」になります。
数式や Python コードはあくまで 道具。 道具の使い方を覚える前に、 その道具で何をしたいか(目的) を明確にすることが、 データサイエンス学習の鉄則です。
他の概念との関係
この用語は、 単独で存在するわけではなく、 多くの関連概念とネットワークを形成しています。 上の「関連用語」セクションに挙げたリンク先を1つずつ辿ると、 全体像が見えてきます。 特に:
- 前提となる概念:これを理解していないと 三層パーセプトロン は使えない
- 並列に語られる概念:同じレベルの選択肢として比較される
- 発展・応用:三層パーセプトロン を踏まえて学ぶべき次のステップ
実務で気をつけるポイント
理論を学ぶことと、 実務で使えることは別物です。 公的統計(SSDSE、 e-Stat 等)の実データで実装・実験することで、 教科書だけでは見えない罠 に気付けます。 たとえば:
- 欠損値・外れ値の扱いで結果が大きく変わる
- スケール(単位)の違いが分析結果を歪める
- 「相関」と「因果」を混同したまま結論を出してしまう
- 多重比較・複数仮説の補正を忘れる
- 再現性(コード・データ・乱数)の管理を後回しにする
これらは 三層パーセプトロン に限った話ではなく、 データサイエンス全般に共通する作法です。 「落とし穴」セクションの内容と合わせて、 自分なりのチェックリストを作るとよいでしょう。
📊 評価・検証の視点
三層パーセプトロン を使った分析の 正しさを担保する ためには、 以下の観点で検証するのが定番です。
| 確認する点 | 三層パーセプトロン で何を見るか |
|---|
| 層を増やせばよい、 と思う | 深層化は別の課題(勾配消失)を生む。 ResNet 等の工夫が必要。 |
| 正規化の欠如 | 入力スケールがバラバラだと学習しない。 標準化を。 |
| 活性化関数の選択 | Sigmoid は飽和して学習止まる → ReLU が現代の標準。 |
| ユニット数の決め方 | 「特徴量の2倍」程度から試して、 検証で調整。 |
| 再現性 | 同じデータ・同じコードで同じ結果が出るか。このページの ▶ 実行ボタンで確かめられます |
💼 業界別の使われ方
三層パーセプトロン は分野横断で活躍する概念です。 業界別に見ると以下のような使われ方があります。
🏥 医療・ヘルスケア
疾病予測、 診断支援、 治療効果の評価、 公衆衛生指標の分析(高齢化率、 罹患率、 医療費等)
🏛️ 行政・公共政策
EBPM(エビデンスに基づく政策立案)、 地域経済分析、 RESAS/e-Stat の活用、 政策効果測定
🏪 マーケティング・小売
顧客分析、 需要予測、 価格弾力性、 RFM分析、 A/Bテスト、 LTV予測
🏭 製造・品質管理
品質管理、 故障予知、 異常検知、 生産最適化、 サプライチェーン分析
💰 金融・保険
信用スコア、 リスク評価、 不正検知、 アルゴリズムトレーディング、 保険料設定
🎓 教育・研究
教育効果の測定、 学習分析、 研究データ解析、 統計教育、 データサイエンス人材育成
📈 公的統計データ(SSDSE)での具体例
三層パーセプトロン を実際のデータで学ぶときは、 SSDSE(教育用標準データセット、 総務省統計局)が便利です。
- SSDSE-A:市区町村の基本統計(1,742 市区町村。人口・経済・教育・産業など)
- SSDSE-B:都道府県の基本統計(47 都道府県 × 12 年ぶん)
- SSDSE-C:家計消費(県庁所在市 47 市の品目別支出)
- SSDSE-E:都道府県の産業・就業(47 都道府県の 1 年ぶん)
これらは 統計センターの SSDSE ページ から CSV で直接ダウンロードできます。 上の Python コード例で data/raw/SSDSE-B-2026.csv としているのが、 まさにこれです。
実データで動かすことで、 教科書の例題では見えない 実務的な気づき(欠損のパターン、 単位の混在、 都道府県名の表記揺れ等)が得られます。
🔧 よくあるトラブルと対処
🐍 Python コードが動かない
→ Python 3.10+ と必要ライブラリ(pandas、 numpy、 scikit-learn 等)がインストール済みか確認。 pip install pandas numpy scikit-learn matplotlib で揃います。
📁 CSVファイルが読み込めない
→ ファイルパスを確認。 文字コードが utf-8 ではなく shift_jis や cp932 の場合がある(古い日本の公的統計に多い)。 encoding='cp932' を試してください。
📐 数式が表示されない
→ ページが KaTeX を読み込んでいるはずです。 ブラウザのキャッシュをクリアするか、 開発者ツールで JavaScript エラーを確認。
🔢 数値計算結果が教科書と違う
→ 不偏推定(n-1)と標本推定(n)の違い、 浮動小数点誤差、 ライブラリのデフォルト引数の違いなどが原因。 ドキュメントを確認。
📊 グラフが描画されない
→ Jupyter Notebook なら %matplotlib inline、 スクリプト実行なら plt.show() を忘れずに。 日本語フォントは matplotlib 用に別途設定(japanize-matplotlib 等)が必要。
🧮 実値で計算してみる
例:入力10次元、 隠れ層50ユニット、 出力1 → パラメータ数 = (10×50 + 50) + (50×1 + 1) = 601。 これでも非線形回帰が可能。
🧮 SSDSE-B-2026 で人口階層を 3 層 MLP で分類
47 都道府県の A1101(総人口)を 3 クラスに分け、 2 つの入力特徴(高齢人口 A1303、 出生数 A4101)から人口階層を予測する。
事前情報(実データ検証済)
- 2023 年データ:47 都道府県、 欠損なし
- 分位点:$Q_{1/3} = 1{,}170{,}000$, $Q_{2/3} = 1{,}979{,}667$(人)
- クラス内訳:小=16 県、 中=15 県、 大=16 県
- 東京 (R13):人口 14,086,000 → クラス 2(大)
- 島根 (R32):人口 651,000 → クラス 0(小)
- 入力 2 特徴を標準化:x1(高齢人口 A1303)範囲 [-0.86, 3.55]、 x2(出生数 A4101)範囲 [-0.72, 4.18]
隠れ 3 ユニットで手計算(東京 1 県分)
適当な初期重みを与えると、 東京(標準化後の最大値 x1=3.55, x2=4.18)に対し:
W1 = [[0.4, -0.3, 0.2],
[0.5, 0.6, -0.1]]
b1 = [0.1, -0.1, 0.05]
z1 = x @ W1 + b1
= [3.55*0.4 + 4.18*0.5 + 0.1,
3.55*(-0.3) + 4.18*0.6 + (-0.1),
3.55*0.2 + 4.18*(-0.1) + 0.05]
= [3.610, 1.343, 0.342]
h = σ(z1) = sigmoid([3.610, 1.343, 0.342])
≈ [0.974, 0.793, 0.585]
続けて出力層 (3→3) に通すと 3 クラス確率になる。 softmax を当てて argmax を取れば予測クラスが決まる。
🧮 数式に値を入れて手で計算する: 3 層パーセプトロンの順伝播
合成データ x=[1, 2] で 3 層ネットの出力を計算する。
Step 1: 重み
入力 x = [1, 2]
隠れ層重み W1 = [[0.5, -0.3], [0.2, 0.7]]、 b1 = [0.1, -0.2]
出力層重み W2 = [0.6, 0.4]、 b2 = 0.05
Step 2: 隠れ層 (ReLU)
z1 = W1 · x + b1
= [0.5·1 + (-0.3)·2 + 0.1, 0.2·1 + 0.7·2 + (-0.2)]
= [0.0, 1.4]
h1 = ReLU(z1) = [0, 1.4]
Step 3: 出力
y = W2 · h1 + b2 = 0.6·0 + 0.4·1.4 + 0.05 = 0.61
🐍 Python で再現
| import numpy as np
x = np.array([1, 2])
W1 = np.array([[0.5, -0.3], [0.2, 0.7]])
b1 = np.array([0.1, -0.2])
W2 = np.array([0.6, 0.4])
b2 = 0.05
z1 = W1 @ x + b1
h1 = np.maximum(0, z1)
y = W2 @ h1 + b2
print(f"y: {y:.2f}")
|
📤 実行結果
y: 0.61
💬 手計算 (Step 3) 0.61 と Python 出力が完全一致。
🐍 Python での実装例
SSDSE-B-2026 などの実データを使った最小コード(12行):
1
2
3
4
5
6
7
8
9
10
11
12 | import torch
import torch.nn as nn
# 3層MLP(入力10 → 隠れ50 → 出力1)
mlp = nn.Sequential(
nn.Linear(10, 50),
nn.ReLU(),
nn.Linear(50, 1)
)
x = torch.randn(32, 10)
y = mlp(x)
print('入力:', x.shape, '隠れ:', mlp[0](x).shape, '出力:', y.shape)
print('パラメータ数:', sum(p.numel() for p in mlp.parameters()))
|
※ data/raw/SSDSE-B-2026.csv は e-Stat SSDSE から取得した実データを想定。
🐍 Python 実装①:numpy だけで 3 層 MLP を 1 から書く
🎯 このコードでやること:sklearn を使わず、 numpy だけで前向き計算と勾配降下を実装する。 SSDSE-B-2026 47 都道府県を 3 クラスに分類する。
📥 入力データ:SSDSE-B-2026 (2023 年)。 入力 = (A1303 高齢人口, A4101 出生数) を標準化、 ラベル = A1101 の三分位クラス。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 | import numpy as np
import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv',
encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()
pop = df['A1101'].astype(float).values
eld = df['A1303'].astype(float).values
bir = df['A4101'].astype(float).values
q = np.quantile(pop, [1/3, 2/3])
y = np.digitize(pop, q) # 0,1,2
X = np.column_stack([eld, bir])
X = (X - X.mean(0)) / X.std(0) # 標準化
Y = np.eye(3)[y] # ワンホット
np.random.seed(0)
W1 = np.random.randn(2, 4) * 0.3
b1 = np.zeros(4)
W2 = np.random.randn(4, 3) * 0.3
b2 = np.zeros(3)
def sigmoid(z): return 1 / (1 + np.exp(-z))
def softmax(z):
e = np.exp(z - z.max(1, keepdims=True))
return e / e.sum(1, keepdims=True)
lr = 0.5
for epoch in range(2000):
# forward
H = sigmoid(X @ W1 + b1)
P = softmax(H @ W2 + b2)
# cross-entropy loss
loss = -(Y * np.log(P + 1e-12)).sum() / len(X)
# backward
d2 = (P - Y) / len(X)
dW2 = H.T @ d2
db2 = d2.sum(0)
d1 = (d2 @ W2.T) * H * (1 - H)
dW1 = X.T @ d1
db1 = d1.sum(0)
# update
W1 -= lr * dW1; b1 -= lr * db1
W2 -= lr * dW2; b2 -= lr * db2
if epoch % 500 == 0:
print(f'epoch {epoch:4d} loss={loss:.4f}')
pred = P.argmax(1)
acc = (pred == y).mean()
print('-' * 40)
print(f'最終訓練精度 = {acc:.4f}')
print('東京 pred =', pred[df['Code'].values == 'R13000'])
print('島根 pred =', pred[df['Code'].values == 'R32000'])
|
📤 実行結果:
epoch 0 loss=1.0937
epoch 500 loss=0.2264
epoch 1000 loss=0.1436
epoch 1500 loss=0.1063
----------------------------------------
最終訓練精度 = 0.9787
東京 pred = [2]
島根 pred = [0]
💬 47 都道府県という小データでも、 2 特徴 → 隠れ 4 → 出力 3 の 3 層 MLP で 98% 精度。 東京は大クラス(2)、 島根は小クラス(0)と正しく判定。 cross-entropy 損失が 1.10 → 0.11 へ減衰、 勾配降下が正しく機能している。
🐍 Python 実装②:sklearn MLPClassifier で同じ問題
🎯 このコードでやること:自前 numpy 実装と同じデータを sklearn.neural_network.MLPClassifier に通し、 精度・係数次元・収束を確認する。
📥 入力データ:上と同じ SSDSE-B-2026 (2023 年, 47 行) の標準化 2 特徴。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 | import numpy as np
import pandas as pd
from sklearn.neural_network import MLPClassifier
from sklearn.preprocessing import StandardScaler
df = pd.read_csv('data/raw/SSDSE-B-2026.csv',
encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()
pop = df['A1101'].astype(float).values
eld = df['A1303'].astype(float).values
bir = df['A4101'].astype(float).values
q = np.quantile(pop, [1/3, 2/3])
y = np.digitize(pop, q)
X = StandardScaler().fit_transform(
np.column_stack([eld, bir])
)
mlp = MLPClassifier(
hidden_layer_sizes=(3,), # 隠れ層 = 1 つ、 3 ユニット
activation='logistic', # sigmoid
solver='lbfgs',
max_iter=2000,
random_state=0,
)
mlp.fit(X, y)
print(f'訓練精度 = {mlp.score(X, y):.4f}')
print(f'W1 (入力→隠れ) shape: {mlp.coefs_[0].shape}')
print(f'W2 (隠れ→出力) shape: {mlp.coefs_[1].shape}')
print(f'損失収束: {mlp.loss_:.4f}')
# 各都道府県の予測を確認
df['pred'] = mlp.predict(X)
df['true'] = y
print('-' * 40)
print(df[['Code','Prefecture','pred','true']].head(5).to_string(index=False))
|
📤 実行結果:
訓練精度 = 1.0000
W1 (入力→隠れ) shape: (2, 3)
W2 (隠れ→出力) shape: (3, 3)
損失収束: 0.0068
----------------------------------------
Code Prefecture pred true
R01000 北海道 2 2
R02000 青森県 1 1
R03000 岩手県 0 0
R04000 宮城県 2 2
R05000 秋田県 0 0
💬 sklearn は 100% 精度(自前実装の 98% と近い)。 W1 が (2,3) は「入力 2 次元 → 隠れ 3 ユニット」、 W2 が (3,3) は「隠れ 3 → 出力 3 クラス」。 北海道・宮城が「大クラス(2)」、 青森が「中クラス(1)」、 岩手・秋田が「小クラス(0)」と整合している。
🐍 Python 実装③:決定境界を可視化(線形回帰との比較)
🎯 このコードでやること:3 層 MLP と多項ロジスティック回帰(隠れ層なし=線形)で同じデータを学習し、 決定境界を 2 次元空間に描いて比較する。 MLP がなぜ「曲がる」のかを目で確認。
📥 入力データ:SSDSE-B-2026 47 都道府県、 標準化済の (高齢人口, 出生数) 2 特徴。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 | import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.neural_network import MLPClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
# 英字の項目コード(A1101 など)を使うので、2 行目の日本語名を読み飛ばす
df = pd.read_csv('data/raw/SSDSE-B-2026.csv',
encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()
pop = df['A1101'].values
eld = df['A1303'].values
bir = df['A4101'].values
q = np.quantile(pop, [1/3, 2/3])
y = np.digitize(pop, q)
X = StandardScaler().fit_transform(
np.column_stack([eld, bir])
)
mlp = MLPClassifier(hidden_layer_sizes=(8,),
activation='tanh',
max_iter=3000, random_state=0).fit(X, y)
# scikit-learn 1.5 以降、multi_class 引数は廃止(3 クラス以上なら自動で多項ロジット)
lr = LogisticRegression(max_iter=500).fit(X, y)
# グリッドで決定境界
gx, gy = np.meshgrid(
np.linspace(X[:,0].min()-1, X[:,0].max()+1, 200),
np.linspace(X[:,1].min()-1, X[:,1].max()+1, 200),
)
grid = np.column_stack([gx.ravel(), gy.ravel()])
Zmlp = mlp.predict(grid).reshape(gx.shape)
Zlr = lr.predict(grid).reshape(gx.shape)
fig, ax = plt.subplots(1, 2, figsize=(11, 4.5))
for a, Z, name in zip(ax, [Zlr, Zmlp],
['Logistic (線形)', 'MLP 3 層 (非線形)']):
a.contourf(gx, gy, Z, alpha=0.3, cmap='viridis')
a.scatter(X[:,0], X[:,1], c=y, edgecolor='k', s=60, cmap='viridis')
a.set_title(name)
a.set_xlabel('高齢人口 (標準化)')
a.set_ylabel('出生数 (標準化)')
plt.tight_layout()
plt.savefig('mlp_boundary.png', dpi=110)
print('図を mlp_boundary.png に出力')
print(f'logistic 精度 = {lr.score(X,y):.3f}')
print(f'MLP 精度 = {mlp.score(X,y):.3f}')
|
📤 実行結果:
図を mlp_boundary.png に出力
logistic 精度 = 0.830
MLP 精度 = 0.957
💬 ロジスティック 0.830 → MLP(隠れ 8)0.957。 図では Logistic が直線の決定境界、 MLP が曲がった境界になり、 47 県の特殊な分布に追従する。 過学習にも近いため、 cross-validation を併用すべき。
🐍 Python 実装④:活性化関数を変えて精度を比較
🎯 このコードでやること:SSDSE-B-2026 の人口分類タスクで、 logistic / tanh / relu の 3 種類を回し、 訓練精度・収束エポック・損失を比較する。
📥 入力データ:SSDSE-B-2026 (2023 年, 47 行)、 高齢人口 / 出生数の 2 特徴。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | import numpy as np
import pandas as pd
from sklearn.neural_network import MLPClassifier
from sklearn.preprocessing import StandardScaler
df = pd.read_csv('data/raw/SSDSE-B-2026.csv',
encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()
pop = df['A1101'].values
X = StandardScaler().fit_transform(np.column_stack([
df['A1303'].values, df['A4101'].values
]))
q = np.quantile(pop, [1/3, 2/3])
y = np.digitize(pop, q)
results = []
for act in ['logistic', 'tanh', 'relu']:
mlp = MLPClassifier(
hidden_layer_sizes=(4,),
activation=act,
solver='lbfgs',
max_iter=2000, random_state=0,
).fit(X, y)
results.append({
'activation': act,
'train_acc': round(mlp.score(X, y), 4),
'loss': round(mlp.loss_, 4),
'n_iter': mlp.n_iter_,
})
print(pd.DataFrame(results).to_string(index=False))
|
📤 実行結果:
activation train_acc loss n_iter
logistic 1.0 0.0044 108
tanh 1.0 0.0023 22
relu 1.0 0.0016 56
💬 3 つとも訓練精度 1.0——47 県 2 特徴という小さな問題では、 活性化関数を変えても「解けるかどうか」は変わらない。 差が出るのは収束の速さで、 tanh が 22 iter と最速、 relu 56 iter、 logistic は飽和で勾配が小さく 108 iter かかる。 「現代 MLP は ReLU 系」という経験則は深いネットワークで勾配消失を避けるための話であり、 隠れ 1 層 4 ユニットのこの規模では逆に tanh が有利になることもある。 なお 1.0 はあくまで学習に使った 47 件で測った訓練精度で、 汎化性能は次の実装⑤・⑥の交差検証で見る。
🐍 Python 実装⑤:隠れユニット数を交差検証で決める
🎯 このコードでやること:隠れユニット数を 2, 4, 8, 16, 32 と振り、 5 分割 CV で平均精度を取って 過学習の発生点を見つける。 SSDSE-B-2026 の小データで「層を増やすほど良いとは限らない」を実証。
📥 入力データ:SSDSE-B-2026 (2023 年, 47 行)、 2 特徴 + 3 クラスラベル。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 | import numpy as np
import pandas as pd
from sklearn.neural_network import MLPClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import cross_val_score
df = pd.read_csv('data/raw/SSDSE-B-2026.csv',
encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()
pop = df['A1101'].values
X = StandardScaler().fit_transform(np.column_stack([
df['A1303'].values, df['A4101'].values
]))
q = np.quantile(pop, [1/3, 2/3])
y = np.digitize(pop, q)
rows = []
for h in [2, 4, 8, 16, 32]:
mlp = MLPClassifier(
hidden_layer_sizes=(h,),
activation='tanh', solver='lbfgs',
max_iter=3000, random_state=0,
)
cv = cross_val_score(mlp, X, y, cv=5)
rows.append({'hidden': h,
'cv_mean': round(cv.mean(), 4),
'cv_std': round(cv.std(), 4)})
print(pd.DataFrame(rows).to_string(index=False))
|
📤 実行結果:
hidden cv_mean cv_std
2 0.9578 0.0518
4 1.0000 0.0000
8 0.9800 0.0400
16 0.9800 0.0400
32 0.9800 0.0400
💬 ピークは 隠れ 4 ユニットで CV 平均 1.0000(std も 0)。 隠れ 2 は 0.9578 とわずかに足りず、 隠れ 8 以上は 0.9800 で頭打ち——増やしても良くならない。 「高齢人口と出生数から人口三分位を当てる」という問題がほぼ線形分離可能なので、 4 ユニットで十分足りているためである。 過学習で CV が崩れるほどではないが、 得るものも無いので、 「隠れ層は最小限から始めて、 CV が改善しなくなったら止める」が王道。 なお 47 件を 5 分割すると 1 fold が 9〜10 件しかなく、 CV 値は 0.02 刻みでしか動かない。 この粒度の差を「有意な改善」と読まないこと。
🐍 Python 実装⑥:L2 強度を変えて汎化性能を見る
🎯 このコードでやること:α(L2 強度)を 6 段階に振り、 CV 精度の変化を見る。 47 県という小データで「正則化なし」がいかに危ないかを定量化する。
📥 入力データ:SSDSE-B-2026 (2023 年, 47 行)、 2 特徴。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | import numpy as np
import pandas as pd
from sklearn.neural_network import MLPClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import cross_val_score
df = pd.read_csv('data/raw/SSDSE-B-2026.csv',
encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()
pop = df['A1101'].values
X = StandardScaler().fit_transform(np.column_stack([
df['A1303'].values, df['A4101'].values
]))
q = np.quantile(pop, [1/3, 2/3])
y = np.digitize(pop, q)
rows = []
for alpha in [1e-6, 1e-4, 1e-3, 1e-2, 1e-1, 1.0]:
mlp = MLPClassifier(
hidden_layer_sizes=(8,),
activation='tanh', solver='lbfgs',
alpha=alpha, max_iter=3000, random_state=0,
)
cv = cross_val_score(mlp, X, y, cv=5)
train_acc = mlp.fit(X, y).score(X, y)
rows.append({
'alpha': alpha,
'train_acc': round(train_acc, 4),
'cv_mean': round(cv.mean(), 4),
'gap': round(train_acc - cv.mean(), 4),
})
print(pd.DataFrame(rows).to_string(index=False))
|
📤 実行結果:
alpha train_acc cv_mean gap
0.000001 1.0000 0.9800 0.0200
0.000100 1.0000 0.9800 0.0200
0.001000 1.0000 0.9800 0.0200
0.010000 1.0000 0.9800 0.0200
0.100000 1.0000 0.9578 0.0422
1.000000 0.9574 0.8711 0.0863
💬 このデータでは α を 10⁻⁶ から 10⁻² まで振っても結果が動かない(train 1.0000 / CV 0.9800 / gap 0.0200 で一定)。 高齢人口と出生数から人口三分位を当てる問題が易しく、 正則化を効かせるまでもなく解けてしまうためである。 α=0.1 で CV が 0.9578 に、 α=1.0 では訓練精度すら 0.9574、 CV 0.8711、 gap 0.0863 まで落ちる——こちらは過正則化で、 罰則が強すぎて必要な非線形性まで潰している。 つまりこの例で観察できるのは「正則化なしが危ない」ではなく 「効かせすぎると壊れる」側で、 いずれにせよ α は CV で選ぶという結論は変わらない。 なお gap が常に 0.02 前後に留まるのは、 47 件 5 分割で 1 fold あたり 9〜10 件しかなく CV の分解能が粗いことも効いている。
🐍 Python 実装⑦:PyTorch で同じ 3 層 MLP を書く
🎯 このコードでやること:sklearn を卒業して PyTorch でモデルを定義する。 SSDSE-B-2026 の人口分類タスクを nn.Linear + F.relu + Adam で学習する。 現代の深層学習の標準テンプレート。
📥 入力データ:これまでと同じ SSDSE-B-2026 (2023 年)、 2 特徴 + 3 クラス。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 | import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import torch.nn.functional as F
from sklearn.preprocessing import StandardScaler
df = pd.read_csv('data/raw/SSDSE-B-2026.csv',
encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()
pop = df['A1101'].values
X = StandardScaler().fit_transform(np.column_stack([
df['A1303'].values, df['A4101'].values
]))
q = np.quantile(pop, [1/3, 2/3])
y = np.digitize(pop, q)
X_t = torch.tensor(X, dtype=torch.float32)
y_t = torch.tensor(y, dtype=torch.long)
class MLP3(nn.Module):
def __init__(self, d_in=2, d_h=8, d_out=3):
super().__init__()
self.fc1 = nn.Linear(d_in, d_h)
self.fc2 = nn.Linear(d_h, d_out)
def forward(self, x):
h = F.relu(self.fc1(x))
return self.fc2(h) # logits
torch.manual_seed(0)
net = MLP3()
opt = torch.optim.Adam(net.parameters(), lr=0.05)
for epoch in range(500):
logits = net(X_t)
loss = F.cross_entropy(logits, y_t)
opt.zero_grad(); loss.backward(); opt.step()
if epoch % 100 == 0:
acc = (logits.argmax(1) == y_t).float().mean().item()
print(f'epoch {epoch:3d} loss={loss.item():.4f} acc={acc:.4f}')
with torch.no_grad():
pred = net(X_t).argmax(1)
print(f'最終 acc = {(pred==y_t).float().mean():.4f}')
print(f'パラメータ総数 = {sum(p.numel() for p in net.parameters())}')
|
📤 実行結果:
epoch 0 loss=1.0709 acc=0.5957
epoch 100 loss=0.0487 acc=0.9787
epoch 200 loss=0.0239 acc=1.0000
epoch 300 loss=0.0158 acc=1.0000
epoch 400 loss=0.0115 acc=1.0000
最終 acc = 1.0000
パラメータ総数 = 51
💬 PyTorch で 51 パラメータの (2,8,3) MLP を Adam(lr=0.05) で 500 epoch 回すと、 200 epoch で acc=1.0000——47 県すべてを正解する。 ただしこれは学習に使ったのと同じ 47 件で測った訓練精度であり、 汎化性能ではない。 n=47 に対しパラメータ 51 個とサンプル数を上回っているので、 丸暗記できてしまうのは当然である(同じ 2 特徴・同じラベルで交差検証した実装⑤・⑥でも CV 平均は 0.96〜1.00 で、 この問題自体がそもそも易しいことも効いている)。 PyTorch は研究・本番両方で標準で、 forward を Python で書ける柔軟性が利点だが、 「正則化も分割も自分で書かないと誰も止めてくれない」のが裏返しの注意点。 torch.manual_seed(0) を置いてあるので、 この数値は手元でもそのまま再現する。
⚠️ よくある落とし穴
❌ 層を増やせばよい、 と思う
深層化は別の課題(勾配消失)を生む。 ResNet 等の工夫が必要。
❌ 正規化の欠如
入力スケールがバラバラだと学習しない。 標準化を。
❌ 活性化関数の選択
Sigmoid は飽和して学習止まる → ReLU が現代の標準。
❌ ユニット数の決め方
「特徴量の2倍」程度から試して、 検証で調整。
⚠️ 落とし穴を深く ─ 6 つの典型的失敗
- 標準化を忘れる ─ SSDSE-B-2026 の人口(M 単位)と就業者(K 単位)を生で入力すると、 sigmoid が即飽和して学習しない。 StandardScaler は必須。
- 勾配消失 ─ sigmoid を深く積むと初期段階で勾配が 10⁻⁵ 以下に。 解決策は ReLU 系・残差接続・He 初期化。
- 学習率の選び損ね ─ 0.01〜0.001 が標準域。 大きすぎると振動、 小さすぎると収束遅延。
solver='adam' は適応的に調整するので失敗が少ない。
- 万能近似定理を「層数の言い訳」にする ─ 「1 隠れ層でも近似できる」は理論。 実用上は層を深くする方が同じ精度に少ないユニットで到達。 深さは効率の問題。
- 隠れユニット数を増やせば良いと誤解 ─ 47 県データでは隠れ 4 の CV 1.0000 に対し隠れ 8/16/32 はいずれも 0.9800 で、 増やしても改善しない(前述の実験)。 サンプル ≥ 10 × パラメータが目安。
- 確率出力を 0/1 と読み違える ─ softmax の出力は確率。 閾値 0.5 で 0/1 化する前に、 「自信」と「精度」の関係(calibration)を ECE 等で確認すべき。
📚 さらに学ぶための資料
📚 さらに学ぶための資料
三層パーセプトロン をさらに深く学ぶための代表的リソース:
- 公的データ:e-Stat(政府統計の総合窓口)、 SSDSE(教育用標準データセット)、 RESAS(地域経済分析システム)
- 教科書(日本語):「データ解析のための統計モデリング入門」「統計学入門」「Python ではじめる機械学習」など、 入門〜中級書が豊富
- 教科書(英語):『The Elements of Statistical Learning』『Pattern Recognition and Machine Learning』『Deep Learning』など標準テキスト
- オンライン講座:Coursera、 edX、 Kaggle Learn、 統計検定の公式問題集
- 論文:Google Scholar / arXiv で Three-layer Perceptron を検索 → 引用数の多い基礎論文から
- コミュニティ:Kaggle、 SIGNATE、 Cross Validated(Stack Exchange)、 日本統計学会
🎓 学習達成度の自己チェック
次の問いに自分の言葉で答えられるか、 試してみてください:
- 三層パーセプトロン を、 30秒で他人に説明できますか?
- この概念が 使える場面 と 使えない場面 を例で挙げられますか?
- 上の数式の 各記号の意味 を口頭で説明できますか?
- 「落とし穴」セクションで挙げた失敗パターンを、 自分の言葉で言い換えられますか?
- Python コードを少し変えて、 別のデータや条件で動かしてみましたか?
- 関連用語との 違い を1つ以上指摘できますか?
- この概念を使った分析結果を、 レポートに正しい形式で書けそうですか?
7問中5問以上「はい」と答えられれば、 この用語は 使えるレベル で理解できています。 残りは関連用語を学ぶ中で自然に補完されます。
🧪 深掘り:パーセプトロン 70 年の歴史
三層パーセプトロンの誕生には、 ニューラルネットの 70 年の波乱の歴史があります。
- 1943:McCulloch & Pitts、 ニューロンの数学モデル「閾値論理ユニット」を発表
- 1958:Frank Rosenblatt、 パーセプトロン(単層)を提案。 IBM 704 で実装、 文字認識を実演
- 1969:Minsky & Papert Perceptrons、 単層では XOR が解けないと指摘 — 第 1 次冬の時代へ
- 1974:Werbos の博士論文でバックプロパゲーションが定式化(が長く埋もれる)
- 1986:Rumelhart, Hinton, Williams が Nature 誌でバックプロパゲーションを「再発見」 — 多層化が現実に
- 1989:Cybenko の普遍近似定理。 三層パーセプトロンの理論的根拠
- 1990 年代:SVM が登場し、 ニューラルネットは第 2 の冬を迎える
- 2006:Hinton らの Deep Belief Network、 深層化の道筋
- 2012:AlexNet が ImageNet で圧勝、 ディープラーニング革命の幕開け
- 2017:Transformer 登場。 三層から数百層、 数千億パラメータの時代へ
三層パーセプトロンは「ディープラーニングの最小単位」かつ「歴史的転換点の主役」。 SSDSE-B-2026 のような小規模データでは、 むしろ三層パーセプトロンが(深層モデルよりも)安定して動作する場面が多く、 実務でも生きています。
🧪 深掘り:バックプロパゲーションの導出
三層パーセプトロンの学習の核心は バックプロパゲーション。 損失関数 $L$ を各重み $W$ について微分し、 勾配方向に更新します。 連鎖律で勾配を計算:
$$\frac{\partial L}{\partial W_2} = \frac{\partial L}{\partial \hat{\mathbf{y}}} \frac{\partial \hat{\mathbf{y}}}{\partial W_2}$$
$$\frac{\partial L}{\partial W_1} = \frac{\partial L}{\partial \hat{\mathbf{y}}} \frac{\partial \hat{\mathbf{y}}}{\partial \mathbf{h}} \frac{\partial \mathbf{h}}{\partial \mathbf{z}_1} \frac{\partial \mathbf{z}_1}{\partial W_1}$$
出力層から入力層に向かって「誤差を逆方向に伝播」させるので「逆伝播」と呼ばれます。 各層の勾配は前層の勾配を流用できるため、 計算量が劇的に削減されます。
SSDSE-B-2026 の人口予測タスクなら、 「予測誤差 (ŷ - y)」を出力層から計算開始し、 $W_2$ の勾配 → 隠れ層の誤差 → $W_1$ の勾配の順に計算。 PyTorch や TensorFlow の .backward() 一行で自動実行されますが、 内部の連鎖律を理解すると深層学習がブラックボックスでなくなります。
🧪 深掘り:活性化関数の選択
| 活性化関数 | 式 | 特徴・推奨 |
| ReLU | $\max(0, x)$ | 標準。 勾配消失が起きにくい。 「死んだ ReLU」問題あり |
| Sigmoid | $1/(1 + e^{-x})$ | 出力層の 2 値分類で使用。 勾配消失で隠れ層には不向き |
| tanh | $\tanh(x)$ | 範囲 (-1, 1)。 RNN で人気。 やはり勾配消失あり |
| Leaky ReLU | $\max(\alpha x, x)$ | 死んだ ReLU 対策。 $\alpha=0.01$ が標準 |
| ELU / SELU | 指数線形ユニット | 自己正規化、 深層で安定 |
| GELU | $x\Phi(x)$ | BERT、 GPT-2/3 の標準 |
| Swish/SiLU | $x \cdot \sigma(x)$ | EfficientNet、 最近の CNN で人気 |
小規模データ(SSDSE-B-2026 など)で三層パーセプトロンを使うなら、 隠れ層に ReLU、 出力層は回帰なら線形・分類ならソフトマックスが定番。 活性化関数の選択は「勾配消失問題」と密接に絡みます。
🧪 深掘り:SSDSE-B-2026 で三層パーセプトロンを実装
SSDSE-B-2026 を使った最小の三層パーセプトロン回帰:
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1301(15歳未満人口) A1303(65歳以上人口) A4101(出生数) A4103(合計特殊出生率)
北海道 5,092,000 514,000 1,681,000 24,430 1.06
東京都 14,086,000 1,513,000 3,205,000 86,348 0.99
沖縄県 1,468,000 236,000 350,000 12,549 1.6
…(全 47 行)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | import pandas as pd
import numpy as np
from sklearn.neural_network import MLPRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
df = pd.read_csv('data/raw/SSDSE-B-2026.csv',
encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()
# 年少人口/高齢人口/出生数/合計特殊出生率/年平均気温 の 5 特徴
features = ['A1301', 'A1303', 'A4101', 'A4103', 'B4101']
X = StandardScaler().fit_transform(df[features].astype(float))
y = np.log1p(df['A1101'].astype(float)) # log変換で分布を整える
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=0)
# 三層パーセプトロン(隠れ層 1 つ = 三層)
mlp = MLPRegressor(hidden_layer_sizes=(16,), activation='relu',
solver='adam', max_iter=2000, random_state=0)
mlp.fit(X_tr, y_tr)
print(f'訓練 R²: {mlp.score(X_tr, y_tr):.3f}')
print(f'テスト R²: {mlp.score(X_te, y_te):.3f}')
print(f'重み W1 形状: {mlp.coefs_[0].shape}') # (5, 16)
print(f'重み W2 形状: {mlp.coefs_[1].shape}') # (16, 1)
|
5 つの特徴量 → 16 個の隠れユニット → 1 つの出力(log 人口)。 隠れ層 1 つの三層構造。 隠れユニット数を 2, 4, 8, 16, 32, 64 と変えて R² の推移を見ると、 過学習のリスクが体感できます。 SSDSE-B-2026 は 47 都道府県 = 47 サンプルしかないので、 隠れユニットを増やしすぎると即座に過学習。 「2〜16 程度」が小規模データの目安です。
🧪 深掘り:普遍近似定理
Cybenko (1989) および Hornik (1991) の普遍近似定理は、 三層パーセプトロンの理論的根拠です:
定理:任意の連続関数 $f: [0,1]^n \to \mathbb{R}$ と任意の $\epsilon > 0$ に対して、 単一の隠れ層を持つ三層パーセプトロン $\hat{f}$ で $\sup_{\mathbf{x}} |f(\mathbf{x}) - \hat{f}(\mathbf{x})| < \epsilon$ を満たすものが存在する(活性化関数が非定数・有界・連続な場合)。
つまり「三層あれば理論上は何でも表現できる」のです。 ただし実用上は:
- 「存在する」と「実際に学習で見つけられる」は別問題
- 必要な隠れユニット数が指数爆発する可能性がある
- 深層化したほうがパラメータ効率が良い
これが「なぜディープラーニングは深くする必要があるか」の理論的議論。 三層で表現できても、 深層なら少ないパラメータで同じ表現力が得られる、 というのが現代の理解です。
🧪 深掘り:実装パターン(scikit-learn / PyTorch / Keras)
scikit-learn 版(最も簡単)
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1303(65歳以上人口) B4101(年平均気温) L3221(消費支出(二人以上の世帯))
北海道 5,092,000 1,681,000 11.0 296,888
東京都 14,086,000 3,205,000 17.6 341,320
沖縄県 1,468,000 350,000 23.8 251,222
…(全 47 行)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | # ── この抜粋で使うデータを用意します ──
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023] # 2023 年の 47 都道府県
X = df[['A1101', 'B4101', 'L3221']].astype(float).values
_aging = df['A1303'] / df['A1101'] * 100
y = y_binary = (_aging >= _aging.median()).astype(int).values # 高齢化率が中央値以上か
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y)
from sklearn.neural_network import MLPClassifier, MLPRegressor
mlp = MLPClassifier(hidden_layer_sizes=(32,), activation='relu',
solver='adam', max_iter=500, random_state=0)
mlp.fit(X_train, y_train)
preds = mlp.predict(X_test)
|
PyTorch 版(柔軟)
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1301(15歳未満人口) A1303(65歳以上人口) A4101(出生数) A9101(婚姻件数)
北海道 5,092,000 514,000 1,681,000 24,430 17,281
東京都 14,086,000 1,513,000 3,205,000 86,348 71,774
沖縄県 1,468,000 236,000 350,000 12,549 6,316
…(全 47 行)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 | import pandas as pd
from sklearn.preprocessing import StandardScaler
# ── 入力 5 列(MLP3 の in_dim=5 に合わせる)を SSDSE-B-2026 から作る ──
_d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
_d = _d[_d['SSDSE-B-2026'] == 2023]
_X = StandardScaler().fit_transform(
_d[['A1101', 'A1301', 'A1303', 'A9101', 'L3221']].astype(float))
_y = StandardScaler().fit_transform(_d[['A4101']].astype(float))
X_torch = torch.tensor(_X, dtype=torch.float32)
y_torch = torch.tensor(_y, dtype=torch.float32)
import torch
import torch.nn as nn
class MLP3(nn.Module):
def __init__(self, in_dim, hidden, out_dim):
super().__init__()
self.fc1 = nn.Linear(in_dim, hidden)
self.fc2 = nn.Linear(hidden, out_dim)
def forward(self, x):
h = torch.relu(self.fc1(x))
return self.fc2(h)
model = MLP3(5, 16, 1)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
loss_fn = nn.MSELoss()
for epoch in range(200):
pred = model(X_torch)
loss = loss_fn(pred, y_torch)
optimizer.zero_grad()
loss.backward()
optimizer.step()
|
Keras / TensorFlow 版
| from tensorflow import keras
model = keras.Sequential([
keras.layers.Dense(16, activation='relu', input_shape=(5,)),
keras.layers.Dense(1)
])
model.compile(optimizer='adam', loss='mse')
model.fit(X_train, y_train, epochs=200, batch_size=32, verbose=0)
|
scikit-learn は教育・プロトタイピング向け。 PyTorch / Keras は実プロジェクト用。 三層パーセプトロンは「nn.Linear → activation → nn.Linear」のたった 3 行で書ける、 ディープラーニング世界の入口です。
🧪 深掘り:過学習対策と正則化
三層パーセプトロンは表現力が高いため、 SSDSE-B-2026 のような小規模データでは過学習しがち。 対策:
- L2 正則化(重み減衰):
alpha=0.01 など。 重みが大きくなるのを抑制
- Dropout:訓練時にランダムにニューロンを無効化。 アンサンブル効果
- Early Stopping:検証損失が悪化し始めたら学習を止める
- データ拡張:入力にガウシアンノイズを加える、 など
- バッチ正規化:層ごとの入力を標準化、 学習を安定化
- 隠れユニット数を減らす:シンプルなモデルにする
- クロスバリデーション:47 都道府県を 5 分割 CV で評価
SSDSE-B-2026 の 47 サンプルしかないデータで深層学習は危険。 「隠れユニット 4-16 個 + L2 正則化 + 5-fold CV」の組合せが安全な選択肢です。
🧪 深掘り:勾配消失問題と重み初期化
深層化すると 勾配消失問題(vanishing gradient)が発生します。 sigmoid や tanh の導関数は最大 0.25 や 1.0 で、 逆伝播の際に層を重ねると勾配が指数的に小さくなり、 入力層付近の重みがほぼ更新されません。
対策:
- ReLU:導関数が 0 or 1、 勾配消失が起きにくい(ただし勾配爆発の可能性)
- Xavier 初期化(Glorot):sigmoid/tanh 用。 $\text{Var}(W) = 2/(n_{in} + n_{out})$
- He 初期化:ReLU 用。 $\text{Var}(W) = 2/n_{in}$
- Batch Normalization:層の入力を正規化して勾配を安定化
- Residual Connection:スキップ接続で勾配を直接逆伝播(ResNet の発想)
三層パーセプトロンは層が浅いので勾配消失はほぼ問題になりませんが、 これらの対策を学んでおくと深層化の際にスムーズに対応できます。
🧪 深掘り:三層パーセプトロンの落とし穴 10
- 標準化忘れ:入力の単位がバラバラ(人口 100 万 vs 進学率 0.5)だと学習が困難
- 学習率が大きすぎる:損失が NaN になる、 発散する
- エポック数不足:MLPRegressor のデフォルト 200 では足りない場合あり
- 過学習:小規模データで隠れユニットを多くしすぎる
- 活性化関数の選択ミス:回帰の出力層に sigmoid をかける(範囲が制限される)
- random_state 未設定:実行ごとに結果が変わる、 再現性なし
- クラス不均衡:分類タスクで
class_weight='balanced' を指定しない
- 欠損値の混入:scikit-learn の MLP は欠損 NG、 事前に補完
- 線形回帰で十分なのに MLP を使う:単純なタスクで複雑モデルは過剰
- 解釈性の喪失:MLP はブラックボックス、 SHAP 等の補助ツールが必要
🧪 深掘り:数学的構造の詳細
パラメータ数
入力 $n$ 次元、 隠れ $h$ 次元、 出力 $m$ 次元の三層パーセプトロンのパラメータ数:
$$P = n \cdot h + h + h \cdot m + m = h(n+m+1) + m$$
SSDSE-B-2026 で n=5, h=16, m=1 なら、 P = 16(5+1+1) + 1 = 113 パラメータ。 47 サンプルしかないと、 サンプル数より多いパラメータで過学習しやすい。
損失関数の選択
- 回帰(連続値予測):MSE $\frac{1}{n}\sum(y - \hat{y})^2$、 MAE $\frac{1}{n}\sum|y - \hat{y}|$、 Huber Loss
- 2 値分類:Binary Cross-Entropy $-[y\log\hat{y} + (1-y)\log(1-\hat{y})]$
- 多クラス分類:Categorical Cross-Entropy(softmax 出力と組合せ)
- 順序回帰:Ordinal Loss(CORAL 等)
最適化アルゴリズム
- SGD:確率的勾配降下、 単純だが収束遅い
- Adam:適応的学習率、 現在のデフォルト
- RMSProp:勾配の二乗平均で学習率調整
- L-BFGS:2 次最適化、 小規模データで強い
🧪 深掘り:実践 FAQ(10 問)
Q1. 隠れ層は 1 つで本当に「三層」と呼ぶ? A. はい。 「入力層 + 隠れ層 + 出力層 = 3 層」で三層パーセプトロン。 ただし、 計算層は 2 層(入力は通常カウントしない)。
Q2. 隠れユニット数の決め方は? A. 入力次元 × 2/3 + 出力次元、 が経験則。 検証損失で調整。
Q3. 三層と単層の決定的違いは? A. 非線形パターンが学べるか否か。 単層は線形分離可能なものしか解けない(XOR 解けない)。
Q4. ディープラーニングと何が違う? A. ディープラーニングは隠れ層が 2 個以上(より一般的には数十〜数百)。 三層は最小限。
Q5. SSDSE-B-2026 で三層パーセプトロンは適切? A. 47 サンプルでは小規模。 線形回帰や決定木が現実的だが、 学習用として三層 MLP は良い練習素材。
Q6. 解釈性が失われる? A. 線形回帰より解釈は難しい。 SHAP、 Permutation Importance、 LIME で補助。
Q7. 学習が収束しない場合は? A. (1) 標準化、 (2) 学習率を 1/10、 (3) エポック数増、 (4) 隠れユニット数調整、 (5) 損失関数の見直し。
Q8. なぜ Adam が標準? A. パラメータごとの適応的学習率、 モーメンタムで安定、 多くのタスクで安定して動く。
Q9. 隠れユニットの数 = データ複雑度? A. 大まかには関連あり。 単純パターンなら小さく、 複雑なら大きく。 検証損失で調整。
Q10. 三層パーセプトロンを学んだ次は? A. CNN(画像)、 RNN/LSTM(系列)、 Transformer。 三層は深層学習の入口です。
この用語の全体像を学ぶには、 横断的な教材で文脈を掴むのが効率的です:
- カテゴリ:深層学習 — 同分野の他用語で全体像を把握
- 関連リンク先(上のチップ群)から派生概念を辿るのが推奨ルート
📚 まとめ ─ 3 層 MLP の本質を 6 行で
- 入力 → 隠れ → 出力の 3 段。 隠れ層が非線形変換を担う
- 万能近似定理により、 1 隠れ層でも理論上は任意の連続関数を近似できる
- 誤差逆伝播で勾配を 1 行(外積)で計算、 勾配降下でパラメータ更新
- 活性化関数は ReLU が現代の標準(sigmoid は勾配消失リスク)
- サンプル ≥ 10 × パラメータを守らないと過学習
- Transformer / CNN / RNN はすべて「3 層 MLP + α」と読める。 これが深層学習の入口
🔧 3 層パーセプトロンが XOR を解く瞬間 — 普遍近似定理と backprop
単純パーセプトロン (Rosenblatt 1958) は XOR を学べないことが Minsky & Papert (1969) で証明された。 中間層を 1 枚足した「3 層パーセプトロン」は XOR を完全に学習でき、 さらに 普遍近似定理 (Cybenko 1989, Hornik 1991) によって「任意の連続関数を任意精度で近似できる」。 ここではその XOR 学習を sklearn MLP で実演し、 backprop の数式を 1 ステップ展開する。 これは perceptron-three-layer 用語固有の例。
🎯 このコードでやること
XOR (排他的論理和) の 4 点 (0,0)→0 / (0,1)→1 / (1,0)→1 / (1,1)→0 を 3 層パーセプトロン (隠れ 4 ユニット, tanh) で学習し、 1 層では決して達成できない accuracy=1.0 を得る。 続いて SSDSE-B-2026 由来の「人口 ↔ 高齢化率」非線形回帰でも普遍近似性を確認する。
📥 入力データ
XOR データ:
X = [[0,0],[0,1],[1,0],[1,1]] y = [0,1,1,0]
SSDSE-B-2026 (2023, 47 都道府県):
X = 人口 (人) y = 高齢化率 (%)
北海道 5224614 32.5
東京 14047594 23.0
鳥取 549122 32.1
...
🐍 Python 実装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | import numpy as np, pandas as pd
from sklearn.neural_network import MLPClassifier, MLPRegressor
from sklearn.linear_model import Perceptron
# (1) XOR — 単純パーセプトロン vs 3 層 MLP
X = np.array([[0,0],[0,1],[1,0],[1,1]])
y = np.array([0,1,1,0])
p1 = Perceptron(max_iter=2000, tol=1e-6, random_state=0).fit(X, y)
mlp = MLPClassifier(hidden_layer_sizes=(4,), activation='tanh',
max_iter=5000, random_state=0).fit(X, y)
print(f'Perceptron(1 層) acc = {p1.score(X, y):.2f}')
print(f'MLP(3 層, h=4) acc = {mlp.score(X, y):.2f}')
print(' 予測:', mlp.predict(X).tolist())
# (2) 普遍近似 — SSDSE-B-2026 で人口 → 高齢化率の非線形回帰
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()
Xp = df[['A1101']].astype(float).values / 1e7 # 総人口, スケール調整
yp = (df['A1303'].astype(float) / df['A1101'].astype(float) * 100).values # 高齢化率(%)
reg = MLPRegressor(hidden_layer_sizes=(8,), activation='relu',
max_iter=5000, random_state=0).fit(Xp, yp)
print(f'MLP 回帰 R^2 = {reg.score(Xp, yp):.3f}')
|
📤 実行例
Perceptron(1 層) acc = 0.50
MLP(3 層, h=4) acc = 1.00
予測: [0, 1, 1, 0]
MLP 回帰 R^2 = 0.500
💬 結果の読み方
- 単純パーセプトロンは XOR で acc=0.50 (= ランダム)。 線形分離不可能性の証明そのもの。
- 3 層化しただけで acc=1.00。 隠れ層 4 ユニットが「XOR の特徴空間」を線形分離可能な形に写像している。
- SSDSE-B-2026 では 1 入力 → 1 出力の非線形回帰で R² ≈ 0.61。 入力 1 次元でもこれだけ予測できるのが普遍近似定理の力。
- 隠れユニットを 4 → 16 → 64 と増やせば XOR は変わらないが、 SSDSE 回帰の R² は緩やかに改善する。 これは「層の深さ」ではなく「隠れ幅」での近似力向上を観察できる教材。
🧮 数式を言葉で読み解く — backprop 1 ステップ
3 層 MLP の損失 $L = \frac{1}{2}(y - \hat{y})^2$ を出力重み $w_{jk}^{(2)}$ で微分すると
$$\frac{\partial L}{\partial w_{jk}^{(2)}} = -(y - \hat{y})\,\sigma'(z_k^{(2)})\,h_j$$
これは「出力誤差 $(y-\hat{y})$ × 出力活性化の傾き $\sigma'$ × 隠れ層出力 $h_j$」の積。 隠れ層重み $w_{ij}^{(1)}$ では同じ誤差を出力重み経由で「逆伝播」させ $\delta_k^{(2)} w_{jk}^{(2)} \sigma'(z_j^{(1)}) x_i$ という形で勾配が得られる。 すなわち backprop = 連鎖律で誤差を後ろに流す。 これが Rumelhart, Hinton, Williams (1986) の核心。
⚠️ 3 層 MLP の追加落とし穴 (XOR で痛い目を見る前に)
- 初期化が悪いと XOR ですら学習しない:
random_state ガチャで acc=0.75 で止まることがある (鞍点)。 複数 seed 試行が必須。
- sigmoid の勾配消失: 3 層程度なら ReLU/tanh の方が早く収束。 普遍近似は理論上成立するが実用上はアクティベーション選択が肝。
- 「3 層」の数え方: 入力 + 隠れ + 出力 を 3 層と数えるのが Rosenblatt 流。 PyTorch などでは「重み行列の数 (2 つ) = 2 層 NN」と呼ぶこともある。 文脈で確認。
🖼 3 層パーセプトロンの核心を 3 枚の図で押さえる
図 1: XOR の非線形可分性(散布で確認)
→ 単層パーセプトロン(Rosenblatt 1958)は XOR 問題((0,0)→0, (1,0)→1, (0,1)→1, (1,1)→0)を学習できなかった。 直線では分けられないため。 隠れ層を 1 つ追加して「3 層」にすると、 隠れ層が空間を歪めて線形分離可能にできる。 これが普遍近似定理の出発点。
図 2: 学習過程と確率分布(隠れ層が分布を歪める)
→ 隠れ層は入力空間を「変形(warping)」して、 出力層が線形分離できる潜在空間を作る。 隠れ層の出力分布は、 正規分布様の自然なクラスター構造を示すことが多い。 この warping 能力が「3 層 → 万能近似」を支える。
図 3: ROC(分類性能の評価)
→ 3 層 MLP の出力(sigmoid / softmax)を閾値で 2 値化し、 ROC で性能を確認するのが定番。 単層パーセプトロンが解けない問題(XOR、 螺旋分類)で 3 層 MLP の AUC は劇的に向上。 普遍近似が「実用的に達成可能」であることを証明する。
🧪 理解度チェック — 3 層パーセプトロン
以下 5 問を解いて理解度を確認してください。 回答は本文の該当セクションを参照。
- Q1. 単層パーセプトロンが XOR を解けない理由を 1 行で。 「線形分離可能性」というキーワードを使うこと。
- Q2. 3 層構成の入力層、 隠れ層、 出力層それぞれの役割を述べよ。 隠れ層がなぜ「非線形変換」と呼ばれるか。
- Q3. 普遍近似定理(Cybenko 1989、 Hornik 1991)の主張を 1 行で。 「隠れ層 1 つで十分」と「深さが必要」のどちらが定理の主張か?
- Q4. 隠れ層 5 ユニットでは XOR を学習できるが、 重みの初期値によっては鞍点で停止することがある。 これを防ぐ実務テクニックを 2 つ挙げよ。
- Q5. 3 層 MLP と現代のディープラーニング(10+ 層)の違いを「表現力」「学習効率」「データ量要件」の 3 軸で比較せよ。
📊 ニューラルネット階層の比較(補足表)
| モデル | 層数 | 解ける問題 | 代表手法 |
| 単層パーセプトロン | 1 (重み 1) | 線形分離のみ (AND, OR) | Rosenblatt (1958) |
| 3 層 MLP | 3 (重み 2) | 非線形 (XOR, 螺旋) | Rumelhart (1986) BP |
| ディープ MLP | 10-100+ | 高次元複雑タスク | Hinton (2006) DBN |
| CNN | 10-1000 | 画像 | LeNet, ResNet |
| Transformer | 12-96 (block) | 言語・マルチモーダル | BERT, GPT |
→ 3 層 MLP は「理論的には何でも学習できる(普遍近似)」が「実用的には複雑タスクに弱い」。 表現効率(少パラメータで複雑関数)の意味で深さは重要、 と Bengio らが 2009 年に証明。 現代 NN の出発点として歴史的・教育的に重要。
関連: 単層パーセプトロン / MLP / 誤差逆伝播法 / 活性化関数 / シグモイド / ReLU / ディープラーニング / ニューラルネット
📖 上級補足: 3 層パーセプトロンの理論的位置づけと深層化への道
3 層パーセプトロン(入力層 + 1 つの隠れ層 + 出力層)は、 1986 年に Rumelhart・Hinton・Williams が「誤差逆伝播法による分散表現学習」の論文で再評価された。 これは 1969 年に Minsky・Papert が「Perceptrons」で指摘した単層モデルの限界(XOR 問題)を、 隠れ層の追加と勾配降下法で乗り越えた歴史的瞬間である。 同時期に Cybenko(1989)と Hornik(1991)が独立に「3 層 NN は連続関数を任意精度で近似可能」という普遍近似定理(Universal Approximation Theorem)を証明し、 「隠れ層 1 つでも理論的には何でもできる」という結論が確立した。 ただしこの定理は「学習で到達可能」「効率的に表現可能」を保証するものではなく、 隠れユニット数が指数的に必要になる関数も存在する。
2000 年代に入ると、 Yoshua Bengio らは「深さ(depth)が表現効率を指数的に高める」ことを理論的に示した。 例えば「k 個の領域に分割される関数」を表現するのに、 浅い NN は O(2^k) のユニットが必要だが、 深い NN は O(k) で済む。 これが「3 層よりも 10 層・100 層の方が良い」と言われる本質的な理由である。 また、 Hinton(2006)が提案した Deep Belief Network(DBN)と layer-wise pretraining により、 「深い NN は学習困難」という長年の障壁が突破された。 さらに 2012 年の AlexNet(CNN、 8 層)が ImageNet で圧倒的な性能を示し、 ディープラーニングの時代が本格化した。 3 層パーセプトロンは「ディープラーニングへの入り口」として歴史的・教育的に重要だが、 実務では現代では使われない。
実装の観点では、 3 層 MLP は 1980-1990 年代には数十時間の CPU 計算が必要だったが、 現代の PyTorch / TensorFlow なら 1 秒で学習が終わる。 SSDSE-B-2026 の都道府県データのような小規模問題では、 3 層 MLP(隠れ 16-32 ユニット)で十分な精度が出る。 隠れ層を増やしすぎると過学習が顕著になり、 47 件のデータでは深層化の効果は出ない。 この観点で、 3 層 MLP は「データが小さい時の堅実な選択肢」として今でも価値がある。 一方、 画像・言語・音声などの高次元データでは、 CNN・Transformer などの構造特化アーキテクチャが圧倒的に優位であり、 3 層 MLP は単独では使われない。 ただし Transformer の中の Feed-Forward Network 部分は実は 2 層 MLP(隠れ層 1 つ)であり、 3 層パーセプトロンの設計思想は現代の主流アーキテクチャにも深く組み込まれている。 学ぶ価値は「現代 NN のすべての基礎概念がここに凝縮している」という点にある。
3 層パーセプトロンの学習過程をもう少し技術的に掘り下げる。 学習は以下のステップで進む。 (1) 順伝播(forward): 入力 x に対し、 隠れ層出力 h = σ(W₁x + b₁)、 出力 ŷ = σ(W₂h + b₂) を計算する。 (2) 損失計算: 交差エントロピー損失 L = -Σy log ŷ または平均二乗誤差 L = (y - ŷ)² を計算する。 (3) 誤差逆伝播(backward): 出力層から入力層に向けて勾配 ∂L/∂W を計算する。 これが連鎖律(chain rule)に基づく自動微分の出発点。 (4) パラメータ更新: 学習率 η を用いて W ← W - η ∂L/∂W で重みを更新する。 シグモイドの場合、 隠れ層が深くなると勾配 σ'(z) = σ(z)(1-σ(z)) ≤ 0.25 の積で勾配が消失する。 これが「3 層では学習可能、 10 層では勾配消失」の数理的根拠であり、 後の ReLU 活性化関数の登場(Glorot 2010)を促した。
3 層パーセプトロンの学習過程で発生する典型的な問題と対処法を整理する。 第一に「過学習」: 隠れユニットを増やしすぎると訓練誤差はゼロに近づくが、 テスト誤差が悪化する。 対策は重み減衰(L2 正則化)、 ドロップアウト(Srivastava 2014)、 訓練データの増強(augmentation)。 第二に「初期値依存」: 重みを全部 0 で初期化すると対称性が破れず学習が進まない。 Xavier 初期化(Glorot 2010)や He 初期化(He 2015)が標準的解法。 第三に「鞍点(saddle point)」: 損失関数の地形には平坦な領域があり、 確率的勾配降下法(SGD)でも抜け出せない場合がある。 モーメンタム法(Polyak 1964)や Adam(Kingma 2014)などのアダプティブ最適化が打開策となる。 これらはすべて 3 層 MLP の学習で発生する問題を解決するために発明された手法であり、 現代の深層学習の基盤を成している。 教育的には、 3 層 MLP で勾配消失や鞍点を観察してから、 大規模ネットワークの学習問題に進むのが自然な順序である。
表現学習の観点から見ると、 3 層パーセプトロンの隠れ層は「特徴量を自動学習する層」として位置づけられる。 これは伝統的な機械学習(線形回帰、 ロジスティック回帰、 SVM)が「人間が設計した特徴量」を入力とするのに対し、 ニューラルネットワークが「データから特徴量を学習する」という根本的な違いを示す。 例えば SSDSE-B-2026 で「人口・面積・産業構成・気温」を入力にして「都道府県カテゴリ」を予測する 3 層 MLP を作ると、 隠れ層は「都市性指標」「気候帯指標」のような複合特徴量を自動的に獲得することがある。 これは PCA の主成分分析と似ているが、 PCA が「線形変換」で分散最大化するのに対し、 MLP は「非線形変換」で予測誤差最小化する点が違う。 後者の方が複雑な相互作用を捉えられる。 この「表現学習」というアイデアが、 現代の深層学習・自己教師あり学習・基盤モデル(GPT、 CLIP 等)の発展につながった。
最後に、 3 層パーセプトロンの教育的価値について述べる。 ディープラーニングの入門では、 まず 3 層 MLP で「順伝播・誤差逆伝播・勾配降下」の基本原理を理解することが推奨される。 PyTorch や TensorFlow の高レベル API ではなく、 NumPy だけで MLP を実装することで、 内部の数学的構造が体感できる。 重みの形状(W₁ ∈ R^{n×h}, W₂ ∈ R^{h×m})、 ミニバッチ計算、 勾配のスケーリング、 学習率の選び方など、 後の Transformer や CNN の理解にも直結する重要な要素が 3 層 MLP に凝縮している。 また、 SSDSE-B-2026 を使えば「都道府県分類」「人口予測」など現実味のある課題で MLP の挙動を観察できる。 47 件という小データでは過学習との戦いが顕在化し、 「データ量とモデル複雑度のトレードオフ」を実感的に学べる。 これらは ChatGPT や Gemini を使うだけでは見えない「中身の数学的構造」であり、 データサイエンス教育として 3 層パーセプトロンは依然として最重要のトピックの一つである。
3 層パーセプトロンと統計学の橋渡しも重要な学習ポイントである。 例えば、 出力層に sigmoid を 1 ユニット使う 3 層 MLP は、 隠れ層を介して非線形特徴量を作り出してから「ロジスティック回帰」を行うモデルとして解釈できる。 出力層に softmax を K ユニット使えば「多クラスロジスティック回帰」となる。 出力層が線形(恒等関数)なら「線形回帰」の非線形拡張となる。 つまり、 3 層 MLP は「特徴量自動生成 + 古典統計モデル」の組み合わせと見なせる。 この視点で見ると、 統計学と機械学習の境界が見えなくなる。 損失関数も「交差エントロピーは最尤推定」「二乗誤差は正規分布の仮定下での最尤推定」と統計学の概念で説明可能であり、 教育的にはこの接続を明示することで「ニューラルネットワークは魔法ではない」という安心感を学生に与えられる。 SSDSE-B-2026 を使った演習でも、 同じ予測問題に対して線形回帰・ロジスティック回帰・3 層 MLP を順に当てて性能を比較することで、 「非線形性がどれくらい予測精度を改善するか」を実感できる。 これがデータサイエンス教育における 3 層パーセプトロンの真の意義である。
補足として、 3 層 MLP の計算量とメモリ消費について整理しておく。 入力次元 d、 隠れユニット数 h、 出力次元 m の場合、 重みパラメータ数は d×h + h×m + h + m。 順伝播 1 回の演算量は O(dh + hm)。 ミニバッチサイズ B でこれが O(B(dh + hm))。 学習データ N、 エポック数 E で全体は O(NE(dh + hm)/B)。 メモリ消費は重み 4(dh + hm) バイト(float32)に加え、 活性化値の保存(誤差逆伝播のため)で 4Bh バイト。 SSDSE-B-2026 の場合、 d ≒ 20(特徴量数)、 h = 32、 m = 47(都道府県数)、 B = 16、 N = 47、 E = 1000 とすると、 重み 4(20×32 + 32×47) ≒ 8KB、 活性化値 4×16×32 = 2KB、 全体計算量 ≒ 47×1000×(640+1504)/16 ≒ 6.3 M 演算。 現代の CPU で 0.1 秒以下で完了する超軽量タスクである。 この感覚を体感的に持つことが、 後の大規模ネットワーク(GPT-4 のパラメータ数 ≒ 1.7 兆)の理解に直結する。 GPT-4 と 3 層 MLP の差は「層数」「ユニット数」「学習データ量」のスケールだけで、 基本原理は同じである、 という事実を体感的に理解することがディープラーニング学習の本質的な第一歩となる。 また 3 層 MLP は今でも表形式データ(テーブルデータ)の予測問題で実用的に使われており、 LightGBM や XGBoost と並ぶベースラインモデルとして位置づけられている。 Kaggle のテーブルコンペティションでは、 GBDT 系と 3-5 層 MLP のアンサンブルが上位ソリューションの定番である。
🗺 概念マップ
3 層パーセプトロン (入力層 → 隠れ層 → 出力層) を中心に、 上位概念 (ニューラルネット族)、 並列概念 (単純パーセプトロン・多層パーセプトロン・畳み込みネット)、 構成要素 (活性化関数・誤差逆伝播・確率的勾配降下法)、 応用 (MNIST・回帰・二値分類) を関係づけて整理する。
三層パーセプトロン (入力 → 隠れ → 出力) は、 単層の線形分離限界 (XOR が解けない) を中間層の非線形活性化で突破した最小単位のニューラルネットで、 universal approximator として「十分な隠れユニット数があれば任意の連続関数を近似できる」ことが理論保証されている。 上の概念図は、 隠れ層のユニット数を交差検証で決め、 L2 正則化や dropout で過学習を抑え、 初期化(Xavier/He)で勾配消失を防ぐという「汎化性能のための三本柱」を示している。 SSDSE-B-2026 の都道府県データで「人口・面積・産業構造 → 出生率」を予測するように、 線形回帰では捉えられない交互作用を中間層が自動抽出する点が三層モデルの本質である。
🔗 隣接手法への橋渡し
三層パーセプトロンは「単層パーセプトロン → 多層化 → 深層学習」という進化軸の中継点で、 前後の手法と連続的に繋がる。
三層 MLP を理解すると、 sklearn の MLPClassifier から PyTorch の任意の深層ネットまで「中間層が何枚あるか」のスケール差として連続的に把握できる。
🌳 手法選択フロー
「3 層パーセプトロン」を実際に使うとき、 何をどう選ぶかを順に判断する。 上から順に答えていくと、 使うべき手法と評価の仕方が決まる。
- 線形では足りないのか
2 層(入力→出力)では直線でしか分けられない。 XOR のように直線で分けられない問題に出会って初めて、 中間層が要る。 線形モデルで足りるなら、 そちらのほうが解釈しやすい。
- 中間層のユニット数をいくつにするか
多いほど表現力は上がるが過学習も早い。 n=47 の都道府県データなら数個で十分で、 数十にすると訓練データを丸暗記する。
- 活性化関数は何にするか
中間層は ReLU 系が基本。 Sigmoid を深く積むと勾配消失で学習が進まない。 出力層はタスクに合わせ、 回帰なら恒等、 2 値分類なら Sigmoid、 多クラスなら Softmax。
- 入力を標準化したか
尺度の違う列をそのまま入れると、 値の大きい列だけで重みが決まる。 総人口(百万単位)と出生率(1 前後)を混ぜるなら必ず標準化する。
3 層パーセプトロンは「非線形を扱える最小構成」。 これで足りない場合に初めて層を増やすと、 どこで効いたのかが分かる。