パーセプトロンとは?仕組みと学習アルゴリズムをわかりやすく解説

パーセプトロン(Perceptron)は、1957年にFrank Rosenblattによって提案された、最も基本的な線形分類モデルです。ニューラルネットワークの原点とも言える手法であり、現代の深層学習の礎となっています。

本記事では、パーセプトロンの数学的な定義から学習アルゴリズムの導出、そしてPythonでのスクラッチ実装までを解説します。

本記事の内容

  • パーセプトロンの定義と幾何学的な意味
  • 学習アルゴリズム(重みの更新則)の導出
  • 収束定理
  • Pythonでのスクラッチ実装と可視化

前提知識

この記事を読む前に、以下の概念を理解しておくと読みやすくなります。

  • ベクトルの内積の基本
  • 線形代数の基礎(超平面の概念)

パーセプトロンとは

パーセプトロンは、入力 $\bm{x} \in \mathbb{R}^d$ を2つのクラス($+1$ または $-1$)に分類する線形分類器です。

イメージとしては、$d$ 次元空間に1つの超平面(決定境界)を引いて、データを2つの領域に分けるモデルです。

パーセプトロンの出力は次のように定義されます。

$$ \begin{equation} \hat{y} = \text{sign}(\bm{w}^T \bm{x} + b) \end{equation} $$

ここで、

  • $\bm{w} \in \mathbb{R}^d$:重みベクトル
  • $b \in \mathbb{R}$:バイアス項
  • $\text{sign}(a)$:$a > 0$ なら $+1$、$a \leq 0$ なら $-1$ を返す符号関数

決定境界は $\bm{w}^T \bm{x} + b = 0$ で定義される超平面です。

幾何学的な理解

2次元の場合を考えてみましょう。重みベクトル $\bm{w} = (w_1, w_2)^T$ に対して、決定境界は

$$ \begin{equation} w_1 x_1 + w_2 x_2 + b = 0 \end{equation} $$

という直線です。

重みベクトル $\bm{w}$ はこの直線に垂直な方向を向いています。$\bm{w}$ の方向側が正のクラス($+1$)、逆側が負のクラス($-1$)に対応します。

データ点 $\bm{x}$ から決定境界までの符号付き距離は次のようになります。

$$ \begin{equation} \text{距離} = \frac{\bm{w}^T \bm{x} + b}{\|\bm{w}\|} \end{equation} $$

正しく分類されたデータ点では $y_i(\bm{w}^T \bm{x}_i + b) > 0$ が成り立ちます。

学習アルゴリズムの導出

パーセプトロンの学習は、誤分類されたデータ点を使って重みを更新していくシンプルなアルゴリズムです。

損失関数

パーセプトロンの損失関数は、誤分類されたデータ点に対する「マージン」の合計として定義されます。

$$ \begin{equation} L(\bm{w}, b) = -\sum_{i \in \mathcal{M}} y_i(\bm{w}^T \bm{x}_i + b) \end{equation} $$

ここで $\mathcal{M}$ は誤分類されたデータ点の集合です。$y_i(\bm{w}^T \bm{x}_i + b) < 0$ であるため、$L \geq 0$ です。全てのデータが正しく分類されれば $L = 0$ になります。

勾配の計算

損失関数の勾配を計算します。

$$ \begin{align} \frac{\partial L}{\partial \bm{w}} &= -\sum_{i \in \mathcal{M}} y_i \bm{x}_i \\ \frac{\partial L}{\partial b} &= -\sum_{i \in \mathcal{M}} y_i \end{align} $$

更新則

確率的勾配降下法(SGD)の考え方で、誤分類されたデータ点を1つずつ選んで更新します。

$$ \begin{align} \bm{w} &\leftarrow \bm{w} + \eta \, y_i \bm{x}_i \\ b &\leftarrow b + \eta \, y_i \end{align} $$

ここで $\eta > 0$ は学習率です。

この更新の直感的な意味を考えてみましょう。

  • 正のクラス($y_i = +1$)が誤って負と分類された場合: $\bm{w}$ に $\bm{x}_i$ を加えることで、$\bm{w}^T \bm{x}_i$ の値が増加し、正しい方向に修正される
  • 負のクラス($y_i = -1$)が誤って正と分類された場合: $\bm{w}$ から $\bm{x}_i$ を引くことで、$\bm{w}^T \bm{x}_i$ の値が減少し、正しい方向に修正される

パーセプトロンの学習アルゴリズム

  1. $\bm{w} = \bm{0}$, $b = 0$ で初期化
  2. 訓練データをランダムに並べ替える
  3. 各データ点 $(\bm{x}_i, y_i)$ について: – $y_i(\bm{w}^T \bm{x}_i + b) \leq 0$(誤分類)ならば:
    • $\bm{w} \leftarrow \bm{w} + \eta \, y_i \bm{x}_i$
    • $b \leftarrow b + \eta \, y_i$
  4. 誤分類がなくなる(または最大反復回数に達する)まで手順2-3を繰り返す

収束定理

パーセプトロンの重要な理論的性質として、収束定理があります。

定理: 訓練データが線形分離可能であれば、パーセプトロンの学習アルゴリズムは有限回の更新で収束する。

具体的には、データのマージン $\gamma = \min_i y_i(\bm{w}^{*T} \bm{x}_i + b^*)$ と入力の最大ノルム $R = \max_i \|\bm{x}_i\|$ を用いて、更新回数は高々

$$ \begin{equation} \frac{R^2}{\gamma^2} \end{equation} $$

回であることが証明されています。ただし、データが線形分離可能でない場合は収束しません。

Pythonでの実装

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)

class Perceptron:
    """パーセプトロン分類器"""

    def __init__(self, learning_rate=1.0, max_iter=1000):
        self.lr = learning_rate
        self.max_iter = max_iter
        self.w = None
        self.b = None
        self.errors_per_epoch = []

    def fit(self, X, y):
        """学習"""
        n_samples, n_features = X.shape
        self.w = np.zeros(n_features)
        self.b = 0.0
        self.errors_per_epoch = []

        for epoch in range(self.max_iter):
            errors = 0
            # データをシャッフル
            indices = np.random.permutation(n_samples)
            for i in indices:
                # 予測
                score = np.dot(self.w, X[i]) + self.b
                y_pred = 1 if score > 0 else -1
                # 誤分類なら更新
                if y_pred != y[i]:
                    self.w += self.lr * y[i] * X[i]
                    self.b += self.lr * y[i]
                    errors += 1
            self.errors_per_epoch.append(errors)
            if errors == 0:
                print(f"エポック {epoch + 1} で収束しました")
                break

    def predict(self, X):
        """予測"""
        scores = X @ self.w + self.b
        return np.where(scores > 0, 1, -1)

# 線形分離可能なデータの生成
n = 100
X_pos = np.random.randn(n // 2, 2) + np.array([2, 2])
X_neg = np.random.randn(n // 2, 2) + np.array([-2, -2])
X = np.vstack([X_pos, X_neg])
y = np.array([1] * (n // 2) + [-1] * (n // 2))

# 学習
model = Perceptron(learning_rate=1.0, max_iter=100)
model.fit(X, y)

# 精度
y_pred = model.predict(X)
accuracy = np.mean(y_pred == y)
print(f"分類精度: {accuracy:.4f}")
print(f"重み: w = {model.w}, b = {model.b:.4f}")

# 可視化
fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# 左: 決定境界
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.linspace(x_min, x_max, 200),
                     np.linspace(y_min, y_max, 200))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)

axes[0].contourf(xx, yy, Z, alpha=0.2, cmap='RdBu')
axes[0].scatter(X[y == 1, 0], X[y == 1, 1], c='blue', marker='o',
               edgecolors='k', s=30, label='Class +1')
axes[0].scatter(X[y == -1, 0], X[y == -1, 1], c='red', marker='x',
               s=30, label='Class -1')

# 決定境界の直線
if model.w[1] != 0:
    x_line = np.linspace(x_min, x_max, 100)
    y_line = -(model.w[0] * x_line + model.b) / model.w[1]
    axes[0].plot(x_line, y_line, 'k-', linewidth=2, label='Decision boundary')

# 重みベクトルの表示
origin = np.array([0, 0])
axes[0].quiver(*origin, *model.w, color='green', scale=10,
              width=0.01, label='Weight vector w')

axes[0].set_xlabel('$x_1$')
axes[0].set_ylabel('$x_2$')
axes[0].set_title('Perceptron Decision Boundary')
axes[0].legend(loc='upper left')

# 右: エポックごとの誤分類数
axes[1].plot(range(1, len(model.errors_per_epoch) + 1),
            model.errors_per_epoch, 'o-', color='steelblue', markersize=5)
axes[1].set_xlabel('Epoch')
axes[1].set_ylabel('Number of Misclassifications')
axes[1].set_title('Convergence of Perceptron')
axes[1].set_ylim(bottom=0)

plt.tight_layout()
plt.show()

左のグラフでは、パーセプトロンが学習した決定境界(黒い直線)と重みベクトル(緑の矢印)を示しています。重みベクトルが決定境界に垂直であることが確認できます。右のグラフでは、エポックごとの誤分類数が0に収束する様子が見られます。

パーセプトロンの限界

パーセプトロンには重要な限界があります。

  • 線形分離不可能なデータに対応できない: XOR問題に代表されるように、直線(超平面)で分離できないデータには収束しない
  • マージンを最大化しない: 線形分離可能な場合でも、得られる決定境界は一意ではなく、最適とは限らない

これらの限界を克服するために、多層パーセプトロン(ニューラルネットワーク)やサポートベクターマシン(SVM)が発展しました。

まとめ

本記事では、パーセプトロンについて解説しました。

  • パーセプトロンは $\hat{y} = \text{sign}(\bm{w}^T \bm{x} + b)$ で定義される線形分類器である
  • 学習は誤分類データに対する重みの更新 $\bm{w} \leftarrow \bm{w} + \eta y_i \bm{x}_i$ で行われる
  • 線形分離可能なデータに対しては、有限回の更新で収束することが保証される
  • 線形分離不可能な問題には対応できないという限界がある

次のステップとして、以下の記事も参考にしてください。