RBFN
下面我们详细讲解这个实现径向基函数神经网络(RBFN)的代码,并结合数学公式来说明每个部分的作用。
一、RBFN简介
径向基函数神经网络(RBFN)是一种前馈神经网络,通常包含三层:
- 输入层:直接将输入数据传递到隐藏层。
- 隐藏层:由一组径向基函数组成,每个函数都有一个中心(centers)和宽度(sigma)。
- 输出层:线性组合隐藏层的输出,得到最终预测结果。
RBFN的训练过程主要包括:
- 确定径向基函数的中心(通常使用K均值聚类)。
- 计算每个径向基函数的宽度(sigma)。
- 使用最小二乘法或伪逆求解输出层的权重。
二、代码详解
1. 初始化方法 __init__
def __init__(
self,
hidden_shape,
norm_func=functools.partial(np.linalg.norm, ord=2, axis=-1),
):
self.hidden_shape = hidden_shape
self.norm_func = norm_func
self.w = None
self.sigmas = None
self.centers = None
self.proc_id = None
解释:
hidden_shape
:隐藏层的神经元数量,即径向基函数的数量。norm_func
:计算距离的函数,默认为欧氏距离(2-范数)。
2. 计算sigma的函数 _calc_sigmas
def _calc_sigmas(self):
c_ = np.expand_dims(self.centers, 1)
ds = self.norm_func(c_ - self.centers)
sigma = 2 * np.mean(ds, axis=1)
sigma = np.sqrt(0.5) / sigma
return sigma
解释:
- 目的:计算每个径向基函数的宽度(sigma)。
- 步骤:
- 计算中心点之间的距离矩阵:\[\text{ds}_{ij} = \| \text{centers}_i - \text{centers}_j \| \]
- 计算每个中心的平均距离:\[\sigma_i = 2 \times \text{mean}(\text{ds}_{i}) \]
- 调整sigma:\[\sigma_i = \frac{\sqrt{0.5}}{\sigma_i} \]
- 计算中心点之间的距离矩阵:
注意:这里的sigma实际上是高斯函数中的系数,通常高斯函数为:
\[\phi(x) = \exp\left(-\frac{\| x - c \|^2}{2\sigma^2}\right)
\]
但在代码中,高斯函数被实现为:
\[\phi(x) = \exp\left(-(\| x - c \| \cdot \sigma)^2\right)
\]
因此,sigma的计算方式有所不同。
3. 计算插值矩阵的函数 _calc_interpolation_mat
def _calc_interpolation_mat(self, X):
x = np.expand_dims(X, 1)
r = self.norm_func(x - self.centers)
r = r * self.sigmas
return np.exp(-(r**2))
解释:
- 目的:计算隐藏层的输出,即径向基函数的响应。
- 步骤:
- 计算输入数据与每个中心的距离:\[r_{ij} = \| X_i - \text{centers}_j \| \]
- 调整距离:\[r_{ij} = r_{ij} \times \sigma_j \]
- 计算径向基函数的输出:\[\Phi_{ij} = \exp\left(-r_{ij}^2\right) \]
- 计算输入数据与每个中心的距离:
4. 训练模型的函数 fit
def fit(self, X, y):
self.centers = KMeans(n_clusters=self.hidden_shape).fit(X).cluster_centers_
self.sigmas = self._calc_sigmas()
tmp = self._calc_interpolation_mat(X)
X_ = np.c_[np.ones(len(tmp)), tmp]
y = y.reshape((-1, 1))
self.w = np.linalg.pinv(X_) @ y
解释:
- 步骤:
- 使用K均值聚类确定径向基函数的中心:
- \(\text{centers} = \text{KMeans}(n\_clusters=\text{hidden\_shape}).\text{fit}(X).\text{cluster\_centers\_}\)
- 计算每个径向基函数的宽度(sigma):
- 调用
_calc_sigmas
函数。
- 调用
- 计算插值矩阵(隐藏层的输出):
- \(\Phi = \text{\_calc\_interpolation\_mat}(X)\)
- 在插值矩阵前添加偏置项(1列):
- \(X\_ = [\mathbf{1}, \Phi]\)
- 使用最小二乘法计算输出层的权重:
- \(w = (X\_^T X\_)^{-1} X\_^T y\)
- 在代码中使用伪逆求解:\[w = X\_^{+} y \]
- 使用K均值聚类确定径向基函数的中心:
5. 预测函数 predict
def predict(self, X):
if X.ndim == 1:
X = X.reshape((1, -1))
tmp = self._calc_interpolation_mat(X)
X_ = np.c_[np.ones(len(tmp)), tmp]
pre = X_ @ self.w
return pre.reshape((-1, ))
解释:
- 步骤:
- 确保输入数据的维度正确。
- 计算插值矩阵(隐藏层的输出):
- \(\Phi = \text{ \_calc\_interpolation\_mat}(X)\)
- 在插值矩阵前添加偏置项(1列):
- \(X\_ = [\mathbf{1}, \Phi]\)
- 计算输出:
- \(\text{pre} = X\_ w\)
- 返回预测结果。
三、数学公式总结
-
径向基函数的形式:
\[\phi_j(x) = \exp\left(-(\| x - c_j \| \cdot \sigma_j)^2\right) \] -
隐藏层的输出矩阵(插值矩阵):
\[\Phi_{ij} = \phi_j(X_i) \] -
输出层的计算(线性回归):
\[y = X\_ w = [\mathbf{1}, \Phi] w \] -
权重的求解(最小二乘法):
\[w = (X\_^T X\_)^{-1} X\_^T y \]或者使用伪逆:
\[w = X\_^{+} y \]
四、总结
该代码实现了一个简单的径向基函数神经网络,主要步骤包括:
- 使用K均值聚类确定径向基函数的中心。
- 计算每个径向基函数的宽度(sigma)。
- 构建插值矩阵,计算隐藏层的输出。
- 使用伪逆求解输出层的权重,实现线性回归。
- 预测时,计算新的输入数据经过隐藏层和输出层后的结果。
通过以上步骤,我们可以使用RBFN对数据进行拟合和预测。