ディープラーニングの基礎:パーセプトロン完全理解ガイド!単純から多層まで

AI

「ディープラーニングって結局何なの?」 「ニューラルネットワークの仕組みがよく分からない」 「XOR問題って何が問題なの?」

パーセプトロンはすべての深層学習の原点です。

1957年に発明されたこのシンプルなモデルが、 今日のChatGPTや画像認識AIの 基礎になっているんです。

この記事を読めば、 単純パーセプトロンから多層パーセプトロン(MLP)まで、 ディープラーニングの本質が理解できます!


スポンサーリンク

パーセプトロンとは?生物の神経細胞を模倣

基本概念:人工ニューロン

【生物のニューロン】
樹状突起 → 細胞体 → 軸索 → 出力

【人工ニューロン(パーセプトロン)】
入力(x) → 重み(w) → 総和 → 活性化関数 → 出力(y)

パーセプトロンの動作:

  1. 複数の入力を受け取る
  2. それぞれに重みを掛ける
  3. 総和を計算
  4. しきい値と比較
  5. 0または1を出力

数式で表すと(簡単に)

出力 = {
  1 (w1*x1 + w2*x2 + b > 0の場合)
  0 (それ以外)
}

w: 重み(weight)
x: 入力(input)
b: バイアス(bias)

単純パーセプトロンの実装

Pythonでゼロから実装

import numpy as np
import matplotlib.pyplot as plt

class SimplePerceptron:
    def __init__(self, learning_rate=0.1, epochs=10):
        """
        単純パーセプトロンの初期化
        learning_rate: 学習率
        epochs: 学習回数
        """
        self.learning_rate = learning_rate
        self.epochs = epochs
        self.weights = None
        self.bias = None
        
    def activate(self, x):
        """活性化関数(ステップ関数)"""
        return 1 if x >= 0 else 0
    
    def predict(self, X):
        """予測"""
        linear_output = np.dot(X, self.weights) + self.bias
        return np.array([self.activate(x) for x in linear_output])
    
    def fit(self, X, y):
        """学習"""
        n_samples, n_features = X.shape
        
        # 重みとバイアスの初期化
        self.weights = np.zeros(n_features)
        self.bias = 0
        
        # 学習ループ
        for epoch in range(self.epochs):
            for idx, x_i in enumerate(X):
                # 予測値の計算
                linear_output = np.dot(x_i, self.weights) + self.bias
                y_predicted = self.activate(linear_output)
                
                # 重みの更新(パーセプトロンの学習規則)
                update = self.learning_rate * (y[idx] - y_predicted)
                self.weights += update * x_i
                self.bias += update
                
            print(f'Epoch {epoch+1}/{self.epochs} 完了')

AND演算の学習

# ANDゲートの学習
def test_and_gate():
    # 訓練データ
    X = np.array([[0, 0],
                  [0, 1],
                  [1, 0],
                  [1, 1]])
    y = np.array([0, 0, 0, 1])  # AND演算の出力
    
    # パーセプトロンの学習
    perceptron = SimplePerceptron(learning_rate=0.1, epochs=10)
    perceptron.fit(X, y)
    
    # 結果の確認
    predictions = perceptron.predict(X)
    print("入力 -> 予測 (正解)")
    for i in range(len(X)):
        print(f"{X[i]} -> {predictions[i]} ({y[i]})")
    
    # 決定境界の可視化
    visualize_decision_boundary(perceptron, X, y, "ANDゲート")

test_and_gate()

OR演算の学習

# ORゲートの学習
def test_or_gate():
    X = np.array([[0, 0],
                  [0, 1],
                  [1, 0],
                  [1, 1]])
    y = np.array([0, 1, 1, 1])  # OR演算の出力
    
    perceptron = SimplePerceptron(learning_rate=0.1, epochs=10)
    perceptron.fit(X, y)
    
    predictions = perceptron.predict(X)
    print("ORゲートの学習結果:")
    for i in range(len(X)):
        print(f"{X[i]} -> {predictions[i]} ({y[i]})")

XOR問題:単純パーセプトロンの限界

なぜXORは学習できない?

# XORゲートの問題
def test_xor_gate():
    X = np.array([[0, 0],
                  [0, 1],
                  [1, 0],
                  [1, 1]])
    y = np.array([0, 1, 1, 0])  # XOR演算の出力
    
    perceptron = SimplePerceptron(learning_rate=0.1, epochs=100)
    perceptron.fit(X, y)
    
    predictions = perceptron.predict(X)
    print("XORゲートの学習結果(失敗):")
    for i in range(len(X)):
        print(f"{X[i]} -> {predictions[i]} ({y[i]})")
    
    # 線形分離不可能!

XOR問題の本質:

  • AND、ORは直線で分離可能(線形分離可能)
  • XORは直線では分離不可能(非線形)
  • 単層では解決不可能→多層化が必要

多層パーセプトロン(MLP)で解決

2層ニューラルネットワークの実装

class MultiLayerPerceptron:
    def __init__(self, input_dim, hidden_dim, output_dim, learning_rate=0.1):
        """
        多層パーセプトロン(2層)
        input_dim: 入力層のサイズ
        hidden_dim: 隠れ層のサイズ
        output_dim: 出力層のサイズ
        """
        # 重みの初期化(Xavierの初期化)
        self.W1 = np.random.randn(input_dim, hidden_dim) * np.sqrt(2.0 / input_dim)
        self.b1 = np.zeros((1, hidden_dim))
        self.W2 = np.random.randn(hidden_dim, output_dim) * np.sqrt(2.0 / hidden_dim)
        self.b2 = np.zeros((1, output_dim))
        
        self.learning_rate = learning_rate
        
    def sigmoid(self, x):
        """シグモイド活性化関数"""
        return 1 / (1 + np.exp(-np.clip(x, -500, 500)))
    
    def sigmoid_derivative(self, x):
        """シグモイド関数の導関数"""
        return x * (1 - x)
    
    def forward(self, X):
        """順伝播"""
        self.z1 = np.dot(X, self.W1) + self.b1
        self.a1 = self.sigmoid(self.z1)
        self.z2 = np.dot(self.a1, self.W2) + self.b2
        self.a2 = self.sigmoid(self.z2)
        return self.a2
    
    def backward(self, X, y, output):
        """逆伝播"""
        m = X.shape[0]
        
        # 出力層の誤差
        self.output_error = y - output
        self.output_delta = self.output_error * self.sigmoid_derivative(output)
        
        # 隠れ層の誤差
        self.z1_error = self.output_delta.dot(self.W2.T)
        self.z1_delta = self.z1_error * self.sigmoid_derivative(self.a1)
        
        # 重みとバイアスの更新
        self.W1 += X.T.dot(self.z1_delta) * self.learning_rate / m
        self.b1 += np.sum(self.z1_delta, axis=0, keepdims=True) * self.learning_rate / m
        self.W2 += self.a1.T.dot(self.output_delta) * self.learning_rate / m
        self.b2 += np.sum(self.output_delta, axis=0, keepdims=True) * self.learning_rate / m
    
    def train(self, X, y, epochs):
        """学習"""
        for epoch in range(epochs):
            output = self.forward(X)
            self.backward(X, y, output)
            
            if epoch % 1000 == 0:
                loss = np.mean(np.square(y - output))
                print(f'Epoch {epoch}, Loss: {loss:.4f}')
        
    def predict(self, X):
        """予測"""
        output = self.forward(X)
        return (output > 0.5).astype(int)

XOR問題を解く

# XOR問題を多層パーセプトロンで解決
def solve_xor_with_mlp():
    X = np.array([[0, 0],
                  [0, 1],
                  [1, 0],
                  [1, 1]])
    y = np.array([[0], [1], [1], [0]])  # XOR
    
    # 多層パーセプトロンの作成と学習
    mlp = MultiLayerPerceptron(input_dim=2, hidden_dim=4, output_dim=1, learning_rate=0.5)
    mlp.train(X, y, epochs=5000)
    
    # 予測
    predictions = mlp.predict(X)
    print("\nXOR問題の解決(多層パーセプトロン):")
    for i in range(len(X)):
        print(f"{X[i]} -> {predictions[i][0]} (正解: {y[i][0]})")
    
    # 精度
    accuracy = np.mean(predictions == y)
    print(f"精度: {accuracy * 100:.0f}%")

solve_xor_with_mlp()

活性化関数の種類と特徴

主要な活性化関数

import numpy as np
import matplotlib.pyplot as plt

def plot_activation_functions():
    x = np.linspace(-5, 5, 100)
    
    fig, axes = plt.subplots(2, 3, figsize=(12, 8))
    
    # ステップ関数
    step = np.where(x >= 0, 1, 0)
    axes[0, 0].plot(x, step)
    axes[0, 0].set_title('ステップ関数')
    axes[0, 0].grid(True)
    
    # シグモイド関数
    sigmoid = 1 / (1 + np.exp(-x))
    axes[0, 1].plot(x, sigmoid)
    axes[0, 1].set_title('シグモイド関数')
    axes[0, 1].grid(True)
    
    # tanh関数
    tanh = np.tanh(x)
    axes[0, 2].plot(x, tanh)
    axes[0, 2].set_title('tanh関数')
    axes[0, 2].grid(True)
    
    # ReLU関数
    relu = np.maximum(0, x)
    axes[1, 0].plot(x, relu)
    axes[1, 0].set_title('ReLU関数')
    axes[1, 0].grid(True)
    
    # Leaky ReLU
    leaky_relu = np.where(x > 0, x, 0.01 * x)
    axes[1, 1].plot(x, leaky_relu)
    axes[1, 1].set_title('Leaky ReLU')
    axes[1, 1].grid(True)
    
    # Softmax(2クラスの例)
    exp_x = np.exp(x - np.max(x))
    softmax = exp_x / exp_x.sum()
    axes[1, 2].plot(x, softmax)
    axes[1, 2].set_title('Softmax(例)')
    axes[1, 2].grid(True)
    
    plt.tight_layout()
    plt.show()

# 活性化関数の比較表
print("""
活性化関数の特徴:

| 関数 | 範囲 | 特徴 | 用途 |
|------|------|------|------|
| ステップ | {0,1} | 単純、微分不可 | 古典的パーセプトロン |
| シグモイド | (0,1) | 滑らか、勾配消失 | 2値分類の出力層 |
| tanh | (-1,1) | 0中心、勾配消失 | 隠れ層(RNN等) |
| ReLU | [0,∞) | 計算簡単、勾配消失なし | 現代のDNNの標準 |
| Softmax | (0,1) | 確率分布 | 多クラス分類の出力層 |
""")

TensorFlow/Kerasでの実装

モダンな実装方法

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

# 単純パーセプトロン(1層)
def create_simple_perceptron():
    model = keras.Sequential([
        layers.Dense(1, activation='sigmoid', input_shape=(2,))
    ])
    return model

# 多層パーセプトロン(MLP)
def create_mlp():
    model = keras.Sequential([
        layers.Dense(8, activation='relu', input_shape=(2,)),
        layers.Dense(4, activation='relu'),
        layers.Dense(1, activation='sigmoid')
    ])
    return model

# XOR問題を解く
def train_xor_keras():
    # データ準備
    X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
    y = np.array([0, 1, 1, 0])
    
    # モデル作成
    model = create_mlp()
    
    # コンパイル
    model.compile(optimizer='adam',
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    
    # 学習
    history = model.fit(X, y, epochs=500, verbose=0)
    
    # 評価
    predictions = model.predict(X)
    predictions = (predictions > 0.5).astype(int)
    
    print("Keras/TensorFlowでのXOR学習結果:")
    for i in range(len(X)):
        print(f"{X[i]} -> {predictions[i][0]} (正解: {y[i]})")
    
    # モデルの構造を表示
    model.summary()

実践的な応用例

1. 画像分類(MNIST)

from tensorflow.keras.datasets import mnist
from tensorflow.keras.utils import to_categorical

def mnist_mlp():
    # データの読み込み
    (X_train, y_train), (X_test, y_test) = mnist.load_data()
    
    # データの前処理
    X_train = X_train.reshape(60000, 784) / 255.0
    X_test = X_test.reshape(10000, 784) / 255.0
    y_train = to_categorical(y_train, 10)
    y_test = to_categorical(y_test, 10)
    
    # MLPモデル
    model = keras.Sequential([
        layers.Dense(128, activation='relu', input_shape=(784,)),
        layers.Dropout(0.2),
        layers.Dense(64, activation='relu'),
        layers.Dropout(0.2),
        layers.Dense(10, activation='softmax')
    ])
    
    model.compile(optimizer='adam',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    
    # 学習
    history = model.fit(X_train, y_train,
                        batch_size=128,
                        epochs=10,
                        validation_split=0.1,
                        verbose=1)
    
    # 評価
    test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
    print(f'テスト精度: {test_acc:.4f}')

2. 回帰問題

from sklearn.datasets import make_regression
from sklearn.preprocessing import StandardScaler

def regression_mlp():
    # 回帰データの生成
    X, y = make_regression(n_samples=1000, n_features=10, noise=10)
    
    # 標準化
    scaler = StandardScaler()
    X = scaler.fit_transform(X)
    
    # MLPモデル(回帰用)
    model = keras.Sequential([
        layers.Dense(64, activation='relu', input_shape=(10,)),
        layers.Dense(32, activation='relu'),
        layers.Dense(16, activation='relu'),
        layers.Dense(1)  # 回帰なので活性化関数なし
    ])
    
    model.compile(optimizer='adam',
                  loss='mse',
                  metrics=['mae'])
    
    # 学習
    model.fit(X, y, epochs=50, batch_size=32, 
              validation_split=0.2, verbose=0)
    
    print("回帰モデルの学習完了")

パーセプトロンからディープラーニングへ

発展の歴史

1957年:単純パーセプトロン(Rosenblatt)
  ↓ 線形分離可能な問題のみ
1969年:XOR問題の指摘(Minsky & Papert)
  ↓ 第1次AIの冬
1986年:誤差逆伝播法(Rumelhart)
  ↓ 多層化が可能に
2006年:深層学習(Hinton)
  ↓ 事前学習で深い層も学習可能に
2012年:AlexNet(画像認識革命)
  ↓ GPU活用、ReLU、Dropout
現在:Transformer、GPT、拡散モデル

現代のディープラーニングとの関係

# 現代的な深層ニューラルネットワーク
def create_deep_network():
    model = keras.Sequential([
        # 畳み込み層(CNN)
        layers.Conv2D(32, 3, activation='relu', input_shape=(28, 28, 1)),
        layers.MaxPooling2D(2),
        
        # 全結合層(パーセプトロンの多層版)
        layers.Flatten(),
        layers.Dense(128, activation='relu'),
        layers.Dropout(0.5),
        layers.Dense(10, activation='softmax')
    ])
    
    return model

print("""
パーセプトロンは今も生きている!

- Dense層 = 多層パーセプトロン
- CNN = 局所的なパーセプトロン
- RNN = 時系列パーセプトロン
- Transformer = アテンション付きパーセプトロン

基本は同じ:重み付き和 → 活性化関数
""")

よくある質問と誤解

Q:パーセプトロンとニューラルネットワークの違いは?

print("""
A:パーセプトロンはニューラルネットワークの一種

- 単純パーセプトロン = 1層のニューラルネットワーク
- 多層パーセプトロン(MLP) = 2層以上のニューラルネットワーク
- ディープニューラルネットワーク = 多層のMLP

すべて「パーセプトロン」が基本単位!
""")

Q:なぜReLUが人気なの?

# ReLUの利点を実証
def compare_activations():
    # 勾配消失問題の比較
    x = np.linspace(-10, 10, 1000)
    
    # シグモイドの勾配
    sigmoid = 1 / (1 + np.exp(-x))
    sigmoid_grad = sigmoid * (1 - sigmoid)
    
    # ReLUの勾配
    relu_grad = np.where(x > 0, 1, 0)
    
    print("x=5での勾配:")
    print(f"シグモイド: {sigmoid_grad[750]:.6f}")  # ほぼ0
    print(f"ReLU: {relu_grad[750]:.6f}")  # 1のまま
    
    # ReLUは深い層でも勾配が消えない!

まとめ:パーセプトロンマスターへの道

基本を理解:

  • 重み付き和 + 活性化関数
  • 線形分離の限界
  • 多層化で非線形問題を解決

実装スキル:

  • NumPyでゼロから実装
  • TensorFlow/Kerasで実用化
  • 適切な活性化関数の選択

応用力:

  • 分類問題への適用
  • 回帰問題への適用
  • 現代的なDNNへの発展

パーセプトロンはすべての深層学習の基礎です。

この基本を理解することで、 最新のAI技術も本質的に理解できるようになります!

まずは簡単なXOR問題から始めて、 徐々に複雑なネットワークに挑戦していきましょう!


コメント

タイトルとURLをコピーしました