RBF神经网络理论与实现
Posted 机器学习理论与算法实践
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RBF神经网络理论与实现相关的知识,希望对你有一定的参考价值。
前言
最近发现有挺多人喜欢径向基函数(Radial Basis Function,RBF
)神经网络,其实它就是将RBF
作为神经网络层间的一种连接方式而已。这里做一个简单的描述和找了个代码解读。
国际惯例,参考博客:
-
维基百科径向基函数[1]
-
《模式识别与智能计算——matlab 技术实现第三版》第 6.3 章节
-
《matlab 神经网络 43 个案例分析》第 7 章节
-
tensorflow2.0 实现 RBF[2]
理论
基本思想
用RBF
作为隐单元的“基”构成隐藏层空间,隐藏层对输入矢量进行变换,将低维的模式输入数据变换到高维空间内,使得在低维空间内的线性不可分问题在高维空间内线性可分。
详细一点就是用RBF
的隐单元的“基”构成隐藏层空间,这样就可以将输入矢量直接(不通过权连接)映射到隐空间。当 RBF 的中心点确定以后,这种映射关系也就确定 了。而隐含层空间到输出空间的映射是线性的(注意这个地方区分一下线性映射和非线性映射的关系),即网络输出是隐单元输出的线性加权和,此处的权即为网络可调参数。
径向基神经网络的节点激活函数采用径向基函数,定义了空间中任一点到某一中心点的欧式距离的单调函数。
我们通常使用的函数是高斯函数:
在《Phase-Functioned Neural Networks for Character Control》论文代码中有提到很多径向基函数:
kernels = {
'multiquadric': lambda x: np.sqrt(x**2 + 1),
'inverse': lambda x: 1.0 / np.sqrt(x**2 + 1),
'gaussian': lambda x: np.exp(-x**2),
'linear': lambda x: x,
'quadric': lambda x: x**2,
'cubic': lambda x: x**3,
'quartic': lambda x: x**4,
'quintic': lambda x: x**5,
'thin_plate': lambda x: x**2 * np.log(x + 1e-10),
'logistic': lambda x: 1.0 / (1.0 + np.exp(-np.clip(x, -5, 5))),
'smoothstep': lambda x: ((np.clip(1.0 - x, 0.0, 1.0))**2.0) * (3 - 2*(np.clip(1.0 - x, 0.0, 1.0)))
}
下图是径向基神经元模型
径向基函数的激活函数是以输入向量和权值向量(注意此处的权值向量并非隐藏层到输出层的权值,具体看下面的径向基神经元模型结构)之间的距离||dist||作为自变量的,图中的 b 为阈值,用于调整神经元的灵敏度。径向基网络的激活函数的一般表达式为
下图是以高斯核为径向基函数的神经元模型:
对应到激活函数表达式:
其中 X 代表输入向量,C 代表权值,为高斯函数的中心, 是高斯函数的方差,可以用来调整影响半径(仔细想想高斯函数中 和 调整后对函数图的影响);当权值和输入向量的距离越小,网络的输出不断递增,输入向量越靠近径向基函数的中心,隐层节点产生的输出越大。也就是说径向基函数对输入信号在局部产生响应,输入向量与权值距离越远,隐层输出越接近 0,再经过一层线性变换映射到最终输出层,导致输出层也接近 0。
结构
RBF 是具有单隐层的三层前向网络。
-
第一层为输入层,由信号源节点组成。
-
第二层为隐藏层,隐藏层节点数视所描述问题的需要而定,隐藏层中神经元的变换函数即径向基函数是对中心点径向对称且衰减的非负线性函数,该函数是局部响应函数,具体的局部响应体现在其可见层到隐藏层的变换是通过径向基函数计算,跟其它的网络不同。以前的前向网络变换函数都是全局响应的函数。
-
第三层为输出层,是对输入模式做出的响应。
输入层仅仅起到传输信号作用,输入层和隐含层之间可以看做连接权值为 1 的连接,输出层与隐含层所完成的任务是不同的,因而他们的学习策略也不同。输出层是对线性权进行调整,采用的是线性优化策略,因而学习速度较快;而隐含层是对激活函数(格林函数,高斯函数,一般取后者)的参数进行调整,采用的是非线性优化策略,因而学习速度较慢。
参数
径向基函数需要两组参数:
-
基函数中心 -
方差(宽度)
隐层到输出层只需要一组参数:
-
权值
优点
-
逼近能力,分类能力和学习速度等方面都优于 BP 神经网络 -
结构简单、训练简洁、学习收敛速度快、能够逼近任意非线性函数 -
克服局部极小值问题。原因在于其参数初始化具有一定的方法,并非随机初始化。
缺点
-
如果中心点是样本中的数据,就并不能反映出真实样本的状况,那么输入到隐层的映射就是不准确的 -
如果使用有监督学习,函数中心是学习到的,但是如果中心点选取不当,就会导致不收敛。
各层的计算
首先初始化参数:中心、宽度、权值
不同隐含层神经元的中心应有不同的取值,并且与中心的对应宽度能够调节,使得不同的输入信息特征能被不同的隐含层神经元最大的反映出来,在实际应用时,一个输入信息总是包含在一定的取值范围内。
中心
-
方法 1
《模式识别与智能计算》中介绍了一种方法:将隐含层各神经元的中心分量的初值,按从小到大等间距变化,使较弱的输入信息在较小的中心附近产生较强的响应。间距的大小可由隐藏层神经元的个数来调节。好处是能够通过试凑的方法找到较为合理的隐含层神经元数,并使中心的初始化尽量合理,不同的输入特征更为明显地在不同的中心处反映出来,体现高斯核的特点:
其中 p 为隐层神经元总个数,j 为隐层神经元索引,i 为输入神经元索引, 是训练集中第 i 个特征所有输入信息的最小值, 为训练集中第 i 个特征所有输入信息的最大值。
-
方法 2 《43 案例分析》中介绍的是 Kmean 使用方法,就是传统的算法,先随机选 k 个样本作为中心,然后按照欧氏距离对每个样本分组,再重新确定聚类中心,再不断重复上面的步骤,直到最终聚类中心变化在一定范围内。
宽度
宽度向量影响着神经元对输入信息的作用范围:宽度越小,相应隐含层神经元作用函数的形状越窄,那么处于其他神经元中心附近的信息在该神经元出的响应就越小;就跟高斯函数图像两边的上升下降区域的宽度一样。所以按照高斯的想法,一般就是计算与中心的距离(df是影响系数)了:
当然也可以用《43 案例分析》里面说的,利用中心之间的最大距离 去计算,其中 h 是聚类中心个数:
输入层到隐层的计算
直接套入到选择的径向基函数中:
其中 就是第 j 个隐层神经元对应的中心向量,由隐层第 j 个神经元所连接的输入层所有神经元的中心分量构成,即 ; 为隐层第 j 个神经元的宽度向量,与 对应, 越大,隐层对输入向量的影响范围就越大,而且神经元间的平滑程度就更好。
隐层到输出层的计算
就是传统的神经网络里面,把核函数去掉,变成了线性映射关系:
其中 k 是输出层神经元个数。
权重迭代
直接使用梯度下降法训练,中心、跨度、权重都通过学习来自适应调节更新。
其中 为学习率, 为损失函数,一般就是均方差。
训练步骤
-
先初始化中心、宽度、最后一层权重 -
计算损失,如果在接受范围内,停止训练 -
利用梯度更新的方法更新中心、宽度、权重 -
返回第二步
代码实现
有大佬利用keras
实现过基于Kmeans
的高斯 RBF 神经网络层,代码戳这里[3]
首先利用sklearn
里面的库构建一个K-means
层
from keras.initializers import Initializer
from sklearn.cluster import KMeans
class InitCentersKMeans(Initializer):
""" Initializer for initialization of centers of RBF network
by clustering the given data set.
# Arguments
X: matrix, dataset
"""
def __init__(self, X, max_iter=100):
self.X = X
self.max_iter = max_iter
def __call__(self, shape, dtype=None):
assert shape[1] == self.X.shape[1]
n_centers = shape[0]
km = KMeans(n_clusters=n_centers, max_iter=self.max_iter, verbose=0)
km.fit(self.X)
return km.cluster_centers_
构建 RBF 层的时候,第一层初始化使用上面的Kmeans
初始化
self.centers = self.add_weight(name='centers',
shape=(self.output_dim, input_shape[1]),
initializer=self.initializer,
trainable=True)
第二层用一个线性加权的层
self.betas = self.add_weight(name='betas',
shape=(self.output_dim,),
initializer=Constant(
value=self.init_betas),
# initializer='ones',
trainable=True)
计算时候,巧妙的利用了宽度计算公式和输出层的计算公式:
def call(self, x):
C = K.expand_dims(self.centers)
H = K.transpose(C-K.transpose(x))
return K.exp(-self.betas * K.sum(H**2, axis=1))
可以看原作者的代码[4],作者是用于二维数据的拟合;
也可以看我的代码,基于原作者代码,做的二维数据分类
后记
RBF 可以用于插值、分类;在论文《Phase-Functioned Neural Networks for Character Control》还用来更改地形,也就是说图形、图像通用,说明还是蛮重要的。这里主要介绍了一下理论,后续再去做扩展性研究。
参考资料
维基百科径向基函数: https://en.wikipedia.org/wiki/Radial_basis_function
[2]tensorflow2.0实现RBF: https://github.com/PetraVidnerova/rbf_for_tf2
[3]戳这里: https://github.com/PetraVidnerova
[4]代码: https://github.com/PetraVidnerova/rbf_keras
以上是关于RBF神经网络理论与实现的主要内容,如果未能解决你的问题,请参考以下文章
基于BP/RBF神经网络的在线信道估计均衡算法matlab仿真