0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ガウス動径基底関数(Gaussian RBF)による回帰分析の3次元拡張

0
Last updated at Posted at 2026-06-14

はじめに

本稿では,前回の記事で示した1次元ガウス動径基底関数(Gaussian Radial Basis Function, Gaussian RBF)回帰を,2次元入力・1次元出力の3次元問題へと拡張した実装について述べる.

真の関数として $z = \sin(|\mathbf{x}|)$(リング状のsin関数)を採用し,観測データへの適合を試みる.
また,本手法の位置付けを明確にするため,線形回帰との比較,過学習の問題,および高次元への拡張時に生じる計算量の課題についても論じる.

gaussian_rbf_3d.png


1. 線形回帰との比較

1.1 線形回帰の限界

線形回帰は,予測値を入力変数の線形結合として表現する.

$$
\hat{z} = w_0 + w_1 x_1 + w_2 x_2
$$

このモデルは超平面しか表現できず,$z = \sin(|\mathbf{x}|)$ のような非線形かつリング状の複雑な関数形状には原理的に適合できない.

多項式回帰によって非線形性を導入することは可能であるが,基底関数が大域的に定義されるため,局所的なパターンの変化への対応が困難である.

1.2 ガウスRBFが解決すること

ガウスRBFは,各データ点を中心とした局所的なガウス関数を重ね合わせることで予測値を構成する.

$$
\hat{z}(\mathbf{x}) = \sum_{p=1}^{N} a_p \exp\left(-\frac{|\mathbf{x} - \mathbf{x}_p|^2}{2\sigma_p^2}\right)
$$

各基底関数は中心 $\mathbf{x}_p$ の近傍でのみ大きな値をとり,離れるにつれて指数的に減衰する.
この局所性により,複雑な非線形関数形状を柔軟に表現することができる.


2. 理論的背景

2.1 2次元等方性ガウス基底関数

2次元入力 $\mathbf{x} = (x_1, x_2)^\top$ に対するガウス基底関数を,等方性(方向によらず一定の幅を持つ)として次式で定義する.

$$
\phi_p(\mathbf{x}) = a_p \exp\left(-\frac{|\mathbf{x} - \mathbf{x}_p|^2}{2\sigma_p^2}\right)
$$

ここで,

$$|\mathbf{x} - \mathbf{x}_p|^2
$$

はユークリッド距離の二乗であり,$a_p$ は振幅,$\sigma_p$ は幅を示す.

2.2 損失関数

$N$ 個のデータ点に対する平均二乗誤差(MSE)を損失関数として定義する.

$$
E(\mathbf{a}, \boldsymbol{\sigma}) = \frac{1}{N} \sum_{i=1}^{N} \left(z_i - \hat{z}(\mathbf{x}_i)\right)^2
$$

2.3 最急降下法によるパラメータ更新

数値微分(前進差分)を用いて偏微分を近似し,最急降下法によってパラメータを更新する.

$$
a_p \leftarrow a_p - \alpha \frac{\partial E}{\partial a_p}, \qquad
\sigma_p \leftarrow \sigma_p - \alpha \frac{\partial E}{\partial \sigma_p}
$$

$$
\frac{\partial E}{\partial a_p} \approx \frac{E(\ldots, a_p + h, \ldots) - E(\ldots, a_p, \ldots)}{h}
$$


3. 過学習について

ガウスRBFはモデルの自由度が高く,過学習(overfitting)のリスクを伴う.
過学習とは,モデルが学習データのノイズまで記憶してしまい,未知データへの汎化性能が低下する現象である.

本実装では,各データ点に1つずつ基底関数を配置しており,パラメータ数はデータ点数 $N$ の2倍($a_p, \sigma_p$ それぞれ $N$ 個)に達する.
データ点数と同数の基底関数を用いた場合,十分な反復回数のもとでは各データ点を通過するような曲面を生成することも原理的に可能であり,過学習が生じやすい状況にある.

過学習を抑制するための代表的な手法として,以下が挙げられる.

  • 正則化:損失関数に $L_2$ ノルムペナルティ項を加え,パラメータの過度な増大を抑制する
  • 基底関数数の削減:全データ点ではなく,代表点のみを中心として基底関数を配置する
  • 早期終了(Early Stopping):検証データの損失が増加し始めた段階で学習を打ち切る

4. 高次元への拡張と計算量の課題

4.1 次元の呪い(Curse of Dimensionality)

入力の次元数 $D$ が増加すると,入力空間を均一にカバーするために必要な基底関数の数は指数的に増加する.
例えば,各次元に $k$ 個の基底関数を配置する場合,必要な総数は $k^D$ となる.

入力次元 $D$ 各軸の点数 $k$ 基底関数数 $k^D$
1 10 10
2 10 100
3 10 1,000
5 10 100,000
10 10 $10^{10}$

本実装では $D=2$,$k=5$ として合計 $N=25$ 個の基底関数を用いているが,次元が増えるにつれて計算コストは急増する.

4.2 ガウス過程回帰への発展

上記の次元の呪いを回避するために考えられたのが,**ガウス過程回帰(Gaussian Process Regression, GPR)**である.
ガウス過程回帰は,データ点間の類似度をカーネル関数によって直接定義し,予測分布をベイズ推定の枠組みで求める手法である.
基底関数を明示的に配置する必要がなく,かつ予測の不確かさも同時に推定できる点において,本手法の自然な発展として位置付けられる.


5. Pythonによる実装

5.1 コード全文

"""
ガウス動径基底関数(Gaussian RBF)による回帰分析の3次元拡張
  入力: (x1, x2) ∈ R²
  出力: z ∈ R
  真の関数: z = sin(sqrt(x1² + x2²))  (リング状のsin関数)
"""

import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
from mpl_toolkits.mplot3d import Axes3D

# 乱数シード・定数
np.random.seed(42)

L   = 2          # 入力領域 [-L, L]^2
N1D = 5          # 1辺のデータ点数  → 合計 N = N1D² 点
num = N1D ** 2   # データ点の総数

# データ生成 (2次元グリッド)
x1_1d = np.linspace(-L, L, N1D)
x2_1d = np.linspace(-L, L, N1D)
X1_grid, X2_grid = np.meshgrid(x1_1d, x2_1d)
X_data = np.column_stack([X1_grid.ravel(), X2_grid.ravel()])  # shape (num, 2)

def true_func(X):
    r = np.sqrt(X[:, 0]**2 + X[:, 1]**2)
    return np.sin(r)

noise_std = 0.05
Z_data = true_func(X_data) + noise_std * np.random.randn(num)

# ガウス基底関数(2次元等方性)
def gauss2d(a, sigma, x0, X):
    diff = X - x0
    r2   = np.sum(diff**2, axis=1)
    return a * np.exp(-r2 / (2 * sigma**2))

# 損失関数(MSE)
def predict(A_ary, Sigma_ary, X):
    y_hat = np.zeros(len(X))
    for p in range(num):
        y_hat += gauss2d(A_ary[p], Sigma_ary[p], X_data[p], X)
    return y_hat

def error(A_ary, Sigma_ary):
    y_hat = predict(A_ary, Sigma_ary, X_data)
    return np.mean((Z_data - y_hat)**2)

# 最急降下法(数値微分)
h          = 1.0e-5
alpha      = 0.05
iterations = 300

A_ary     = np.ones(num)
Sigma_ary = np.ones(num)
error_history = []

for itr in range(iterations):
    for p in range(num):
        A_ary2      = A_ary.copy()
        A_ary2[p]  += h
        d_err_A     = (error(A_ary2, Sigma_ary) - error(A_ary, Sigma_ary)) / h

        Sigma_ary2     = Sigma_ary.copy()
        Sigma_ary2[p] += h
        d_err_Sigma    = (error(A_ary, Sigma_ary2) - error(A_ary, Sigma_ary)) / h

        A_ary[p]     -= alpha * d_err_A
        Sigma_ary[p] -= alpha * d_err_Sigma
        # sigma の符号制約(正値を保証)
        Sigma_ary[p]  = max(abs(Sigma_ary[p]), 1e-6)

    err = error(A_ary, Sigma_ary)
    error_history.append(err)
    if (itr + 1) % 50 == 0:
        print(f"  iter {itr+1:4d} / {iterations}  MSE = {err:.6f}")

# 可視化
Ngrid = 50
xx1 = np.linspace(-L, L, Ngrid)
xx2 = np.linspace(-L, L, Ngrid)
XX1, XX2 = np.meshgrid(xx1, xx2)
X_eval   = np.column_stack([XX1.ravel(), XX2.ravel()])

ZZ_pred  = predict(A_ary, Sigma_ary, X_eval).reshape(Ngrid, Ngrid)
ZZ_true  = true_func(X_eval).reshape(Ngrid, Ngrid)

fig = plt.figure(figsize=(18, 5))

ax1 = fig.add_subplot(131, projection='3d')
ax1.plot_surface(XX1, XX2, ZZ_true, cmap='viridis', alpha=0.7)
ax1.set_title("真の関数\n$z = \\sin(\\|\\mathbf{x}\\|)$")
ax1.set_xlabel("$x_1$"); ax1.set_ylabel("$x_2$"); ax1.set_zlabel("$z$")

ax2 = fig.add_subplot(132, projection='3d')
ax2.plot_surface(XX1, XX2, ZZ_pred, cmap='plasma', alpha=0.7)
ax2.scatter(X_data[:, 0], X_data[:, 1], Z_data, color='blue', s=30, zorder=5, label="学習データ")
ax2.set_title("Gaussian RBF 回帰\n(3次元拡張)")
ax2.set_xlabel("$x_1$"); ax2.set_ylabel("$x_2$"); ax2.set_zlabel("$z$")
ax2.legend(loc='upper right', fontsize=8)

ax3 = fig.add_subplot(133)
ax3.plot(range(1, iterations + 1), error_history, color='green')
ax3.set_title("損失関数の履歴(MSE)")
ax3.set_xlabel("反復回数")
ax3.set_ylabel("MSE")
ax3.set_yscale('log')
ax3.grid(True)

plt.suptitle("ガウス動径基底関数(Gaussian RBF)による回帰分析の3次元拡張",
             fontsize=13, y=1.02)
plt.tight_layout()
plt.savefig("gaussian_rbf_3d.png", dpi=130, bbox_inches='tight')
plt.show()

5.2 実装上のポイント

データ生成

X_data = np.column_stack([X1_grid.ravel(), X2_grid.ravel()])
Z_data = true_func(X_data) + noise_std * np.random.randn(num)

$[-2,2]^2$ の領域に $5 \times 5 = 25$ 点のグリッドを配置し,各点での $\sin(|\mathbf{x}|)$ の値に標準偏差 $0.05$ のノイズを加算する.
入力データを (N, 2) の行列としてまとめることで,後続の演算をベクトル化できる.

2次元ガウス基底関数

def gauss2d(a, sigma, x0, X):
    diff = X - x0          # (M, 2)
    r2   = np.sum(diff**2, axis=1)   # (M,)
    return a * np.exp(-r2 / (2 * sigma**2))

1次元版との本質的な差異は,距離計算を $|x - x_0|^2$ から $|\mathbf{x} - \mathbf{x}_0|^2$ へ拡張した点のみである.
np.sum(diff**2, axis=1) によって各評価点のユークリッド距離の二乗を一括計算し,ベクトル化された出力を返す.

$\sigma_p$ の符号制約

Sigma_ary[p] = max(abs(Sigma_ary[p]), 1e-6)

$\sigma_p$ はガウス関数の幅であり,正値である必要がある.
最急降下法の更新によって $\sigma_p$ が負値をとりうるため,絶対値を取ることで正値性を保証し,さらに $10^{-6}$ を下限として数値的な不安定性を防ぐ.


6. 実験条件

パラメータ 値
入力次元 $D$ 2
グリッド分割数 $N_{1D}$ 5
データ点数 $N$ 25
入力領域 $[-2, 2]^2$
真の関数 $z = \sin(|\mathbf{x}|)$
ノイズ標準偏差 0.05
反復回数 300
学習率 $\alpha$ 0.05
数値微分刻み幅 $h$ $10^{-5}$
初期パラメータ $(a_p, \sigma_p)$ すべて 1.0

7. 実験結果

以下の3パネルのグラフを出力する.

  1. 真の関数 $z = \sin(|\mathbf{x}|)$:同心円状の波形を持つ曲面
  2. 学習済み予測曲面:Gaussian RBF回帰により推定された曲面と学習データ点(青点)
  3. 損失関数の履歴:反復に伴うMSEの減少(対数スケール)

gaussian_rbf_3d.png

損失関数の履歴グラフより,MSEが反復とともに単調に減少していることが確認できる.
また,予測曲面は真の関数のリング状の形状を概ね再現しており,ガウスRBFが2次元非線形回帰に有効であることが示された.


8. まとめ

本稿で述べた内容を以下に整理する.

観点 要点
線形回帰との違い 線形回帰は超平面しか表現できないが,ガウスRBFは局所的な基底関数の重ね合わせによって複雑な非線形曲面を表現できる
過学習 モデルの自由度が高いため,正則化・基底関数数の削減・早期終了などの対策が必要である
計算量の課題 入力次元が増加すると必要な基底関数数が指数的に増加する(次元の呪い)
発展手法 上記の課題を回避するためにガウス過程回帰が提案されている

1次元から2次元への拡張は,ユークリッド距離の定義を変更するだけで自然に実現できる.
この汎用性こそが,RBFカーネルが様々な機械学習手法の基礎として広く用いられている理由の一つである.


参考文献・関連記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?