ニューラルネットワークの基礎概念と最小構成モデルの実装

1. モデルの定義と役割

機械学習における「モデル」とは、現実世界の複雑な事象を数式によって簡略化した表現です。数学的には、入力データ $X$ を出力データ $Y$ へ変換する写像関数 $f$ と定義できます。

f(X) = Y
(特徴量) → (予測値)

1.1 モデルを構成する3要素

  • 構造 (Architecture): 計算の組み立て方(例:層の深さ、ニューロンの配置)。
  • パラメータ (Parameters): 学習を通じて最適化される変数(重み $w$ やバイアス $b$)。
  • ハイパーパラメータ (Hyperparameters): 学習前に人間が設定する外部パラメータ(学習率やエポック数)。

2. 最小構成のニューロンモデル:y = w * x

最もシンプルなニューラルネットワークは、バイアスを持たない単一のニューロンで構成されます。ここでは NumPy を使用して、線形関係を学習するモデルを構築します。

import numpy as np
import matplotlib.pyplot as plt

# 疑似データの生成
np.random.seed(10)
input_data = np.random.rand(100) * 5  # 0から5までの入力
true_weight = 3.2
target_data = true_weight * input_data + np.random.randn(100) * 1.5  # ノイズを付加

class BasicNeuron:
    def __init__(self):
        # 重みをランダムに初期化
        self.weight = np.random.randn()
        
    def forward(self, x):
        """前向き伝播"""
        return self.weight * x
    
    def compute_loss(self, y_pred, y_true):
        """損失関数 (平均二乗誤差)"""
        return np.mean((y_pred - y_true) ** 2)
    
    def get_gradient(self, x, y_pred, y_true):
        """勾配の計算: dLoss/dw"""
        return 2 * np.mean((y_pred - y_true) * x)
    
    def apply_gradient(self, grad, alpha):
        """パラメータの更新"""
        self.weight -= alpha * grad

# 訓練プロセス
model = BasicNeuron()
learning_rate = 0.02
iterations = 50
history = []

for i in range(iterations):
    predictions = model.forward(input_data)
    current_loss = model.compute_loss(predictions, target_data)
    history.append(current_loss)
    
    dw = model.get_gradient(input_data, predictions, target_data)
    model.apply_gradient(dw, learning_rate)
    
    if i % 10 == 0:
        print(f"Iter {i}: Weight={model.weight:.3f}, Loss={current_loss:.3f}")

print(f"最終推定重み: {model.weight:.3f} (真値: {true_weight})")

3. データ正規化(Normalization)の重要性

入力データのスケールが極端に異なると、勾配が不安定になり、学習の収束が遅れたり、数値演算上のオーバーフローが発生したりすることがあります。これを防ぐために「正規化」を行います。

3.1 主要な正規化手法

  • Min-Maxスケーリング: データを[0, 1]の範囲に収める。
  • 標準化 (Z-score Normalization): 平均を0、標準偏差を1にする。
class FeatureScaler:
    @staticmethod
    def standardize(data):
        mu = np.mean(data)
        sigma = np.std(data)
        scaled = (data - mu) / (sigma + 1e-9)
        return scaled, mu, sigma

    @staticmethod
    def inverse_standardize(scaled_data, mu, sigma):
        return scaled_data * sigma + mu

4. 正規化を導入した学習パイプライン

実際に大きな値を持つデータセットに対して、標準化を適用した学習フローを実装します。

# 広範囲の数値を持つデータの準備
raw_x = np.random.rand(100) * 500
raw_y = 1.8 * raw_x + np.random.randn(100) * 50

# ステップ1: データの標準化
scaler = FeatureScaler()
x_norm, x_mu, x_sigma = scaler.standardize(raw_x)
y_norm, y_mu, y_sigma = scaler.standardize(raw_y)

# ステップ2: 正規化空間でのモデル訓練
norm_model = BasicNeuron()
train_alpha = 0.1  # 正規化されているため高めの学習率を設定可能

for epoch in range(100):
    p_norm = norm_model.forward(x_norm)
    grad_norm = norm_model.get_gradient(x_norm, p_norm, y_norm)
    norm_model.apply_gradient(grad_norm, train_alpha)

# ステップ3: 元のスケールへの変換
# 正規化空間の式: y_norm = w_norm * x_norm
# (y - y_mu)/y_sigma = w_norm * (x - x_mu)/x_sigma
# これを展開すると、元の重み w_orig = w_norm * (y_sigma / x_sigma)
estimated_w_orig = norm_model.weight * (y_sigma / x_sigma)
estimated_bias_orig = y_mu - estimated_w_orig * x_mu

print(f"正規化後の重み: {norm_model.weight:.4f}")
print(f"復元された重み: {estimated_w_orig:.4f} (期待値: 1.8)")
print(f"推定されたバイアス: {estimated_bias_orig:.4f}")

# 可視化
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
plt.scatter(raw_x, raw_y, alpha=0.5)
plt.plot(raw_x, estimated_w_orig * raw_x + estimated_bias_orig, color='red')
plt.title("Original Scale Regression")

plt.subplot(1, 2, 2)
plt.plot(history)
plt.title("Loss Convergence")
plt.show()

5. 結論としての設計指針

モデルの実装において、単純な数式のコード化だけでなく、以下の設計指針が重要となります。

  1. 勾配の安定化: 正規化はハイパーパラメータ調整を容易にし、学習を高速化します。
  2. 変換の可逆性: 予測時には、正規化された出力を元のビジネスコンテキストの数値に戻す必要があります。
  3. 微分の自動化: 今回は手動で勾配を計算しましたが、より複雑なモデルでは自動微分エンジン(PyTorchやTensorFlowなど)の利用が標準的です。

タグ: MachineLearning NeuralNetworks Python NumPy DataPreprocessing

8月2日 21:21 投稿