📚 背景知識(読んでから問題へ)
なぜGBDTでは足りないのか
GBDTは「人間が意味のある特徴量を作ってあげれば」非常に強力ですが、生の画像ピクセルや生の文章を渡されると途端に無力です。1枚の画像は数万〜数百万個のピクセル値の羅列にすぎず、GBDTはその「並び」に隠れた意味(輪郭・質感・単語の並び順)をうまく学習できません。ニューラルネットワークは、層を重ねることで「生データ → 単純な特徴 → 複雑な特徴 → 予測」という変換を自動的に学習する仕組みです。これが画像・テキスト・音声で圧倒的な強さを発揮する理由です。
| 項目 | GBDT(Phase 4) | ニューラルネットワーク(Phase 5) |
|---|---|---|
| 得意なデータ | 表形式(数値・カテゴリ) | 画像・テキスト・音声・系列データ |
| 特徴量 | 人間が設計(Aggregation・TargetEncoding等) | データから自動的に学習(表現学習) |
| 基本単位 | 決定木 | ニューロン(パーセプトロン) |
| 学習法 | 勾配ブースティング(木を順に追加) | 誤差逆伝播(重みを繰り返し微調整) |
| 主要ライブラリ | LightGBM・XGBoost・CatBoost | PyTorch(Day 111から本格導入) |
パーセプトロン: ニューラルネットワークの最小単位。複数の入力を受け取り重み付き合計を計算し、活性化関数を通して1つの出力を返す「1個の判断ユニット」
重み・バイアス: 各入力の重要度(重み)と判断の基準点をずらす調整値(バイアス)。線形回帰の係数・切片と同じ役割
活性化関数: 重み付き合計に「曲がり」を加える関数(sigmoid・ReLU等)。これがないと何層重ねても直線(線形)にしかならない
順伝播: 入力から出力へ、層を順番に計算していく処理
逆伝播: 出力の誤差を、どのニューロンがどれだけ「悪かったか」を遡って計算し、重みを修正するための情報を作る処理
🗂️ 今日使うデータ: XOR(排他的論理和)
今日は実データの代わりに、ニューラルネットワークの本質を最小構成で示す「XOR問題」を使います。データはたった4行、しかしニューラルネット研究の歴史を左右した重要な例です。
| カラム | 型 | 説明 |
|---|---|---|
x1 | int(0 or 1) | 入力1 |
x2 | int(0 or 1) | 入力2 |
y | int(0 or 1) | 正解ラベル = x1 XOR x2(どちらか片方だけ1のときに1) |
| x1 | x2 | y |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
📐 線形分離可能性を視覚的に理解する
左は OR ゲート(1本の直線できれいに分けられる)、右は XOR ゲート(どんな直線を引いても必ず誤分類が出る)。同じ「2入力・2値分類」でも構造が根本的に違うことを見比べてください。
(0,0),(1,1) は対角線上、`y=1` 2点 (0,1),(1,0) ももう一方の対角線上に位置します。1本の直線は平面を2つの半分に分けるだけなので、対角に並ぶ2点を同じ側に、もう一方の対角2点を反対側に、同時に分けることは幾何学的に不可能です。理論上の上限は4点中3点(75%)までしか正解できません。🎯 問題
💡 ヒント
タスク1・2は「新しい概念」というより「Phase 2で習ったことの言い換え」です。ロジスティック回帰の数式 sigmoid(w1*x1 + w2*x2 + b) をそのままパーセプトロンの図に当てはめてみてください。タスク2は、XORの4点を実際に紙やこのページの図で見比べると直感的に分かります。
- タスク3-1:
w = np.random.uniform(-2, 2, size=2)、b = np.random.uniform(-2, 2)を何千回も試し、step(X @ w + b)の正解率の最大値を記録する - タスク3-2: 隠れ層の2ユニットに OR と NAND(NOT AND)の役割を持たせ、出力層でその2つを AND する、と XOR が作れる(
OR(h1) AND NAND(h2) = XOR) - 活性化関数は
sigmoid(gain * z)でgainを大きくすると、階段関数(0か1かをくっきり分ける関数)に近づく
import numpy as np X = np.array([[0,0],[0,1],[1,0],[1,1]]) y = np.array([0,1,1,0]) def step(z): return (z > 0).astype(int) # --- 単層パーセプトロン: ランダム探索で最高正解率を確認 --- rng = np.random.default_rng(42) best_acc = 0 for _ in range(5000): w = rng.uniform(-2, 2, size=2) b = rng.uniform(-2, 2) pred = step(X @ w + b) acc = (pred == y).mean() best_acc = max(best_acc, acc) print(f"単層パーセプトロンの最高正解率: {best_acc:.2f}") # --- 隠れ層ありネットワーク: 手設計の重みでXORを解く --- def sigmoid(z, gain=20): return 1 / (1 + np.exp(-gain * z)) W1 = np.array([[1, -1], [1, -1]]) # h1=OR用, h2=NAND用 b1 = np.array([-0.5, 1.5]) W2 = np.array([1, 1]) # 出力=AND(h1,h2) b2 = -1.5 def forward(X): h = sigmoid(X @ W1 + b1) return sigmoid(h @ W2 + b2) pred = forward(X) print("2層ネットワークの予測:", np.round(pred, 2))
✅ 模範解答
タスク1: ロジスティック回帰 ⇔ パーセプトロン 対応表
| ロジスティック回帰の用語 | パーセプトロンの用語 | 役割 |
|---|---|---|
| 係数(coefficient) | 重み(weight) | 各入力の重要度を表す数値 |
| 切片(intercept) | バイアス(bias) | 判断の基準点をずらす調整値 |
| シグモイド関数 | 活性化関数(activation function) | 重み付き合計を0〜1の確率に変換 |
sigmoid(w1x1+...+wnxn+b) | 1個のニューロンの出力 | 入力から出力までの一連の計算 |
| 予測確率(0〜1) | ニューロンの活性化値 | そのニューロンが「どれだけ強く発火しているか」 |
タスク2: XORが線形分離不可能な理由
XORの4点を平面に置くと、y=0 の2点 (0,0),(1,1) が左下と右上の対角、y=1 の2点 (0,1),(1,0) が左上と右下の対角に位置します。1本の直線は平面を2つの半分(半平面)に分けるだけなので、どの直線を引いても対角線上にある2点は必ず反対側に来てしまい、同じラベルの2点を同時に同じ側へ揃えることは幾何学的に不可能です(理論上の上限は4点中3点=75%)。この「曲がった境界線」を作るために、隠れ層と非線形の活性化関数が必要になります。
タスク3: コード実装
import numpy as np X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) y = np.array([0, 1, 1, 0]) # XOR def step(z): return (z > 0).astype(int) # ====== 3-1. 単層パーセプトロン: ランダム探索で最高正解率を確認 ====== rng = np.random.default_rng(42) best_acc = 0 best_wb = None for _ in range(5000): w = rng.uniform(-2, 2, size=2) b = rng.uniform(-2, 2) pred = step(X @ w + b) acc = (pred == y).mean() if acc > best_acc: best_acc = acc best_wb = (w, b) print(f"単層パーセプトロンの最高正解率(5000通り試行): {best_acc:.2f}") # 出力例: 0.75 → どれだけ探しても100%には到達しない(理論上の上限どおり) # ====== 3-2. 隠れ層ありネットワーク: 手設計の重みでXORを100%解く ====== def sigmoid(z, gain=20): # gainを大きくして階段関数に近似(学習後の重みの動きを模倣) return 1 / (1 + np.exp(-gain * z)) # 隠れ層: h1 = OR(x1,x2), h2 = NAND(x1,x2) W1 = np.array([[1, -1], [1, -1]]) # 列0: h1(OR)用, 列1: h2(NAND)用 b1 = np.array([-0.5, 1.5]) # 出力層: out = AND(h1, h2) W2 = np.array([1, 1]) b2 = -1.5 def forward(X): h = sigmoid(X @ W1 + b1) # 隠れ層の出力 out = sigmoid(h @ W2 + b2) # 出力層の出力 return out pred_prob = forward(X) pred_label = (pred_prob > 0.5).astype(int) print("XOR予測確率:", np.round(pred_prob, 3)) print("XOR予測ラベル:", pred_label) print("正解率:", (pred_label == y).mean()) # 出力例: [0.001 0.999 0.999 0.001] → [0 1 1 0] → 正解率 1.0
タスク4: バックプロパゲーションの比喩
🕸️ 今日組み立てたネットワークの構造
h1が「OR」、h2が「NAND」という単純なパターンをそれぞれ学習(今回は手設計)し、出力層がその2つを「AND」で組み合わせることで、単層では表現できなかったXORが再現できる。これが「層を重ねるほど複雑な表現ができる」というディープラーニングの最小の実例。
📊 正解率で見る「単層」と「多層」の差
🪜 Step-by-Step 解説
1ロジスティック回帰=1個のニューロンと捉え直す
# Phase 2で書いたロジスティック回帰の予測式 prob = 1 / (1 + np.exp(-(w1*x1 + w2*x2 + b)))
2XORの4点を図で確認する(線形分離不可能性)
X = np.array([[0,0],[0,1],[1,0],[1,1]]) y = np.array([0,1,1,0])
3単層パーセプトロンの限界を数値で体感する
best_acc = 0 for _ in range(5000): w = rng.uniform(-2, 2, size=2) b = rng.uniform(-2, 2) acc = (step(X @ w + b) == y).mean() best_acc = max(best_acc, acc)
4隠れ層で「OR」と「NAND」を作り、出力層で「AND」する
h = sigmoid(X @ W1 + b1) # h1=OR(x1,x2), h2=NAND(x1,x2) out = sigmoid(h @ W2 + b2) # out=AND(h1,h2) = XOR(x1,x2)
OR AND NAND という2つの単純な論理演算の組み合わせで表現できます。隠れ層が「単純なパターン」を作り、出力層がそれらを「組み合わせる」ことで、単層では不可能だった複雑な境界線を再現できます。これがディープラーニングの「層を重ねるほど複雑な表現ができる」という考え方の最小の実例です。5この先、重みは「手設計」ではなく「学習」で決める
🧮 数学・統計の補足(文系向け)
🏆 Kaggleでの実践的な使い方
よく使われるコンペカテゴリ: ☐ 表形式データ(Tabular) / ☑ 自然言語処理(NLP) / ☑ 画像認識(CV) / ☑ 時系列(Time Series)
🖼️ CNN(Day 121〜)
ピクセルから直接学習
Petfinder・Plant Pathology等の画像コンペで、ピクセルの並びから輪郭・質感などの特徴を自動抽出する。
📝 BERT系(Day 116〜)
文脈を理解する
Jigsaw・US Patent Phrase Matching等のNLPコンペで、単語の並びや文脈をTransformerが捉える。
🔗 GBDT×NNアンサンブル
Stackingの発展形
数値・カテゴリが非常に多く複雑な相互作用を持つ場合、GBDTとNNを組み合わせると単体より強くなることがある。
⚠️ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 |
|---|---|---|
| ニューラルネットワークはGBDTの完全上位互換だと思う | 「ディープラーニング=最新・最強」というイメージ先行 | Tabularデータでは今もGBDTが優位なことが多い。NNが強いのは画像・テキスト・音声など「生の非構造化データ」 |
| 活性化関数はなくても層を重ねれば複雑な表現ができると思う | 線形代数の直感がまだない | 活性化関数(非線形性)がなければ、何層重ねても数学的には1層の線形変換と等価になる |
| 誤差逆伝播は「新しいアルゴリズム」だと身構える | 数式の見た目が複雑 | やっていることは連鎖律(掛け算の繰り返し)。Phase 2の勾配降下法の延長線上の概念 |
| XORのような単純な例に実用性がないと思う | トイ問題に見える | 「単層で解けない・多層なら解ける」という最小の反例として、なぜ深さが必要かを理解する上で最も重要な例。歴史的にもNN研究の停滞と復活の分岐点になった問題 |
| パーセプトロン=ニューラルネットワーク全体だと思う | 用語が似ている | パーセプトロンは「ニューロン1個」の名称。ニューラルネットワークはそれを多数組み合わせたネットワーク全体を指す |
🚀 次のステップ
- 発展: 今回は重みを手設計しましたが、
W1, b1, W2, b2をランダム初期化し、勾配降下法で少しずつ更新するコード(バックプロパゲーションの自作実装)を書いて、XORの正解率が0.5前後から徐々に1.0に近づく過程を確認してみましょう - 次回予告: Day 111 — PyTorch入門①(Tensor・自動微分の仕組み)。今日手計算で行った順伝播・誤差逆伝播を、PyTorchが
loss.backward()の一行でどう自動化しているかを学ぶ
Phase 5 の学習マップ(全20テーマ予定)
本日(Day 110)は「1-5 DL基礎」の1テーマ目。Phase 4で培った評価指標・CV・過学習対策の土台の上に、ニューラルネットワークという新しい武器を積み上げ、Master ランク(Gold + Bronze×2)を目指す。
🟣 Phase 5(紫帯)スタート! GBDTで培った土台の上に、ニューラルネットワークという新しい武器を積み上げていきます。
📝 自己評価(解いた後に記入)
自分の回答・気づき・メモ: