RBF神经网络理论与实现

前言

最近发现有挺多人喜欢径向基函数(Radial Basis Function,RBF)神经网络,其实它就是将RBF作为神经网络层间的一种连接方式而已。这里做一个简单的描述和找了个代码解读。
之前也写过一篇,不过排版不好看,可以戳这里跳转

国际惯例,参考博客:

  • 维基百科径向基函数

  • 《模式识别与智能计算——matlab技术实现第三版》第6.3章节

  • 《matlab神经网络43个案例分析》第7章节

  • tensorflow2.0实现RBF

  • numpy的实现

理论

基本思想

RBF作为隐单元的“基”构成隐藏层空间,隐藏层对输入矢量进行变换,将低维的模式输入数据变换到高维空间内,使得在低维空间内的线性不可分问题在高维空间内线性可分。

详细一点就是用RBF的隐单元的“基”构成隐藏层空间,这样就可以将输入矢量直接(不通过权连接)映射到隐空间。当RBF的中心点确定以后,这种映射关系也就确定 了。而隐含层空间到输出空间的映射是线性的(注意这个地方区分一下线性映射和非线性映射的关系),即网络输出是隐单元输出的线性加权和,此处的权即为网络可调参数。

径向基神经网络的节点激活函数采用径向基函数,定义了空间中任一点到某一中心点的欧式距离的单调函数。

我们通常使用的函数是高斯函数:
ϕ(r)=e−(ϵr)2\phi(r) = e^{-(\epsilon r)^2} ϕ(r)=e(ϵr)2
在《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为阈值,用于调整神经元的灵敏度。径向基网络的激活函数的一般表达式为
R(∥dist∥)=e−∥dist∥R(\parallel dist \parallel) = e^{-\parallel dist \parallel} R(dist)=edist
下图是以高斯核为径向基函数的神经元模型:

在这里插入图片描述

对应到激活函数表达式:
R(xp−ci)=exp⁡(−12σ2∥xp−ci∥2)R(x_p-c_i)=\exp{\left(-\frac{1}{2\sigma^2}\parallel x_p - c_i \parallel^2 \right)} R(xpci)=exp(2σ21xpci2)
其中X代表输入向量,C代表权值,为高斯函数的中心,σ\sigmaσ是高斯函数的方差,可以用来调整影响半径(仔细想想高斯函数中cccσ\sigmaσ调整后对函数图的影响);当权值和输入向量的距离越小,网络的输出不断递增,输入向量越靠近径向基函数的中心,隐层节点产生的输出越大。也就是说径向基函数对输入信号在局部产生响应,输入向量与权值距离越远,隐层输出越接近0,再经过一层线性变换映射到最终输出层,导致输出层也接近0。

结构

RBF是具有单隐层的三层前向网络。

在这里插入图片描述

  • 第一层为输入层,由信号源节点组成。

  • 第二层为隐藏层,隐藏层节点数视所描述问题的需要而定,隐藏层中神经元的变换函数即径向基函数是对中心点径向对称且衰减的非负线性函数,该函数是局部响应函数,具体的局部响应体现在其可见层到隐藏层的变换是通过径向基函数计算,跟其它的网络不同。以前的前向网络变换函数都是全局响应的函数。

  • 第三层为输出层,是对输入模式做出的响应。

输入层仅仅起到传输信号作用,输入层和隐含层之间可以看做连接权值为1的连接,输出层与隐含层所完成的任务是不同的,因而他们的学习策略也不同。输出层是对线性权进行调整,采用的是线性优化策略,因而学习速度较快;而隐含层是对激活函数(格林函数,高斯函数,一般取后者)的参数进行调整,采用的是非线性优化策略,因而学习速度较慢。

参数

径向基函数需要两组参数:

  • 基函数中心
  • 方差(宽度)

隐层到输出层只需要一组参数:

  • 权值

优点

  • 逼近能力,分类能力和学习速度等方面都优于BP神经网络
  • 结构简单、训练简洁、学习收敛速度快、能够逼近任意非线性函数
  • 克服局部极小值问题。原因在于其参数初始化具有一定的方法,并非随机初始化。

缺点

  • 如果中心点是样本中的数据,就并不能反映出真实样本的状况,那么输入到隐层的映射就是不准确的
  • 如果使用有监督学习,函数中心是学习到的,但是如果中心点选取不当,就会导致不收敛。

各层的计算

首先初始化参数:中心、宽度、权值

不同隐含层神经元的中心应有不同的取值,并且与中心的对应宽度能够调节,使得不同的输入信息特征能被不同的隐含层神经元最大的反映出来,在实际应用时,一个输入信息总是包含在一定的取值范围内。

中心

  • 方法1

    《模式识别与智能计算》中介绍了一种方法:将隐含层各神经元的中心分量的初值,按从小到大等间距变化,使较弱的输入信息在较小的中心附近产生较强的响应。间距的大小可由隐藏层神经元的个数来调节。好处是能够通过试凑的方法找到较为合理的隐含层神经元数,并使中心的初始化尽量合理,不同的输入特征更为明显地在不同的中心处反映出来,体现高斯核的特点:
    cji=min⁡i+max⁡i−min⁡i2p+(j−1)max⁡i−min⁡ipc_{ji} = \min i + \frac{\max i-\min i}{2p}+(j-1)\frac{\max i-\min i}{p} cji=mini+2pmaximini+(j1)pmaximini
    其中p为隐层神经元总个数,j为隐层神经元索引,i为输入神经元索引,max⁡i\max imaxi是训练集中第i个特征所有输入信息的最小值,$\max i $为训练集中第i个特征所有输入信息的最大值。

  • 方法2
    《43案例分析》中介绍的是Kmean使用方法,就是传统的算法,先随机选k个样本作为中心,然后按照欧氏距离对每个样本分组,再重新确定聚类中心,再不断重复上面的步骤,直到最终聚类中心变化在一定范围内。

宽度

宽度向量影响着神经元对输入信息的作用范围:宽度越小,相应隐含层神经元作用函数的形状越窄,那么处于其他神经元中心附近的信息在该神经元出的响应就越小;就跟高斯函数图像两边的上升下降区域的宽度一样。按照《模式识别与智能计算》,计算有点像标准差的计算(但是此处原文没有带平方,不过我觉得应该带上,详细可以查阅这个YouTube视频,不带平方,万一出现负数是无法求根的):
dji=df1N∑k=1N(xik−cji)2d_{ji}= d_f\sqrt{\frac{1}{N}\sum_{k=1}^N(x_i^k-c_{ji})^2} dji=dfN1k=1N(xikcji)2
当然也可以用《43案例分析》里面说的,利用中心之间的最大距离cmaxc_{max}cmax去计算,其中h是聚类中心个数:
d=cmax2hd = \frac{c_{max}}{\sqrt{2h}} d=2hcmax

输入层到隐层的计算

直接套入到选择的径向基函数中:
zj=exp⁡(−∣∣X−CjDj∣∣2)z_j = \exp\left(- \left|\left|\frac{X-C_j}{D_j} \right|\right|^2\right) zj=exp(DjXCj2)
其中CjC_jCj就是第j个隐层神经元对应的中心向量,由隐层第j个神经元所连接的输入层所有神经元的中心分量构成,即Cj=[Cj1,Cj2,⋯,Cjn]C_j = [C_{j1},C_{j2},\cdots,C_{jn}]Cj=[Cj1,Cj2,,Cjn]DjD_jDj为隐层第j个神经元的宽度向量,与CjC_jCj对应,DjD_jDj越大,隐层对输入向量的影响范围就越大,而且神经元间的平滑程度就更好。

隐层到输出层的计算

就是传统的神经网络里面,把核函数去掉,变成了线性映射关系:
yk=∑j=1pwkjzjy_k = \sum_{j=1}^p w_{kj}z_j yk=j=1pwkjzj
其中k是输出层神经元个数。

权重迭代

直接使用梯度下降法训练,中心、宽度、权重都通过学习来自适应调节更新。
在这里插入图片描述

其中η\etaη为学习率,EEE为损失函数,一般就是均方差。

训练步骤

  • 先初始化中心、宽度、最后一层权重
  • 计算损失,如果在接受范围内,停止训练
  • 利用梯度更新的方法更新中心、宽度、权重
  • 返回第二步

代码实现

有大佬利用keras实现过基于Kmeans的高斯RBF神经网络层,代码戳这里

首先利用sklearn里面的库构建一个K-means

from keras.initializers import Initializer
from sklearn.cluster import KMeansclass InitCentersKMeans(Initializer):""" Initializer for initialization of centers of RBF networkby clustering the given data set.# ArgumentsX: matrix, dataset"""def __init__(self, X, max_iter=100):self.X = Xself.max_iter = max_iterdef __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))

但是此处我觉得有问题,这里的宽度向量好像没有体现出来,所以我重写了一个:

def call(self, x):C = K.expand_dims(self.centers)XC = K.transpose(K.transpose(x)-C)     D = K.expand_dims(K.sqrt(K.mean(XC**2,axis=0)),0) H = XC/Dreturn K.exp(-self.betas * K.sum(H**2, axis=1))

可以看原作者的代码,作者是用于二维数据的拟合;

也可以看我的代码,基于原作者代码,做的二维数据分类

在这里插入图片描述
小点为训练集,大圆点为测试集

后记

RBF可以用于插值、分类;在论文《Phase-Functioned Neural Networks for Character Control》还用来更改地形,也就是说图形、图像通用,说明还是蛮重要的。这里主要介绍了一下理论,后续再去做扩展性研究。

完整的python脚本实现放在微信公众号的简介中描述的github中,有兴趣可以去找找,同时文章也同步到微信公众号中,有疑问或者兴趣欢迎公众号私信。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246562.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于python和unity交互的卡通角色肢体和表情驱动(深度学习)

前言 最近看到了好多卡通角色的肢体驱动的东东,感觉是时候发挥一下读研时候学的东西了,而且虽然现在不炼丹了,但是还是得保持吃丹的技能。这个项目找了很多很多代码进行测试,最终集成了一个3D姿态估计和人脸关键点提取的代码。 …

OpenCV学习——形态学

前言 继续学习图像里面的形态学知识——结构元、腐蚀、膨胀、开运算、闭运算、击中/不击中变换。以及部分基本形态学算法,包括边界提取、空洞填充、连通分量的提取、凸壳、细化、粗化、骨架、裁剪、形态学重建。 其实就是对冈萨雷斯的《数字图像处理》中第9章节《…

径向基函数RBF三维网格变形

前言 之前写过径向基函数(RBF)神经网络做分类或者拟合。然后挖了个坑说在《Phase-Functioned Neural Networks for Character Control》里面提到了用于做地形编辑,所以这篇博客就是解析一下如何用RBF做网格编辑系统。 参考博客: Noe’s tutorial on d…

OBJ可视化——UV还原(修正)

前言 前面写过一篇obj格式解析的博客,但是这篇文章中可视化的工作是参考PRNet的源码进行的,后来细细思考了一下,有点问题,具体看下面。 问题来源 在PRNet源码的render.py中有个函数render_texture,是作者用于将uv展…

Unity中BVH骨骼动画驱动的可视化理论与实现

前言 找了很久使用BVH到unity中驱动骨骼动画的代码,但是都不是特别好用,自己以前写过,原理很简单,这里记录一下。 理论 初始姿态 在BVH或者其它骨骼动画中,一般涉及到三种姿势:A-pose,T-pos…

卡通驱动项目ThreeDPoseTracker——模型驱动解析

前言 之前解析过ThreeDPoseTracker这个项目中的深度学习模型,公众号有兄弟私信一些问题,我刚好对这个项目实现有兴趣,就分析一波源码,顺便把问题解答一下。 这个源码其实包括很多内容:3D姿态估计,坐标平滑…

卡通驱动项目ThreeDPoseTracker——关键点平滑方案解析

前言 之前对ThreeDPoseTracker的深度学习模型和unity中的驱动方法进行过解析,还有一个比较重要的就是从深度学习模型出来的3D关键点数据会有抖动,在ThreeDPoseTracker源码中有做两次平滑,一部分是卡尔曼滤波,还有一部分是低通滤波…

卡通角色表情驱动系列一

前言 分析完ThreeDPoseTracker来做卡通角色的身体驱动,接下来在卡通驱动领域还有一个是表情驱动。对这个真的是一窍不通啊,只能慢慢看论文了。 国际惯例,参考博客/论文: 《Landmark-guided deformation transfer of template f…

opencv相机标定和人头姿态估计案例

前言 头部驱动除了之前关注的表情驱动外,还有眼球驱动和头部方向驱动。本博客基于opencv官方文档和部分开源代码来研究如何基于人脸关键点获取头部的朝向。 国际惯例,参考博客: opencv:Camera Calibration and 3D Reconstruction opencv:…

卡通角色表情驱动系列二

前言 之前介绍了使用传统算法求解BS系数的表情驱动方法,其中提到过的三种方法之一是基于网格形变迁移做的,那么这篇文章就是对《Deformation Transfer for Triangle Meshes》做表情驱动的解析。 国际惯例,参考博客: 论文原文《…

UE自带重定向原理

UE自带重定向方法验证 核心源码在VS的解决方案中的位置: UE4\Source\Developer\AssetTools\Private\AssetTypeActions\AnimSequence.cpp中第3237行RemapTracksToNewSkeleton函数 跳转方法 AssetTypeActions_AnimationAsset.cpp的RetargetNonSkeletonAnimationHa…

【caffe-Windows】caffe+VS2013+Windows无GPU快速配置教程

前言 首先来一波地址: happynear大神的第三方caffe:http://blog.csdn.net/happynear/article/details/45372231 Neil Z大神的第三方caffe:https://initialneil.wordpress.com/2015/01/11/build-caffe-in-windows-with-visual-studio-2013-…

【caffe-Windows】caffe+VS2013+Windows+GPU配置+cifar使用

前言 国际惯例,先来波地址: CUDA WIN7:链接:http://pan.baidu.com/s/1nvyA3Qp 密码:h0f3 官方网址:https://developer.nvidia.com/cuda-toolkit CUDA WIN10:链接:http://pan.baidu.com/s/1…

【一些网站的收集】包含机器学习深度学习大牛主页等

数学概念部分 旋转矩阵、欧拉角、四元数的比较 欧拉角和四元数的表示 四元数与旋转 B样条曲线 非常好的概率统计学习的主页 误差方差偏差 编程语言学习 C#编程视频 OpenGL编程NeHe OpenGL官网 OpenGL“我叫MT“纯手工3D动画制作之1——基础介绍 【强大】非常好的Op…

Eureka源码分析

Eureka源码分析 Eureka server入口: Spring.factories PS: 意味着如果加载EurekaServerAutoConfiguration成功,需要 ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)需加载成功. 通过Bean注入了很多类 本质上, eureka-server包含很多事件: EurekaInstanceC…

matlab程序中,如何解决矢量长度必须相同的问题

主要原因就是画图的x和y长度不一样,我用一个例子说明。 问题代码: clear all;close all;clc;x 0 : 1: 9;y sin(x);n 2*length(x);yi interpft(y, n);xi 0 : 0.5 : 10;hold on ;plot(x, y ,ro);plot(xi, yi, b.-);plot(x, sin(x),m--);legend(原始…

matlab 功率谱分析函数psd用法

psd简介 PSD(power spectrum analysis)功率谱分析,PSD在给定频带上的积分计算信号在该频带上的平均功率。与均值-平方谱相反,这个光谱中的峰值并没有反映出给定频率的能量。 单边PSD包含了信号的总功率在频率间隔从DC到一半的奈奎斯特速率。双侧PSD包含…

linux tar (打包、压缩、解压)命令

打包程序:tar c: 创建文档t: 列出存档内容x:提取存档f: filename 要操作的文档名v:详细信息 一:打包 打包:是指把文件整合在一起,不压缩 1.将文件打包:tar cf a.tar…

虚拟机添加硬盘扩容

1.设置→添加→硬盘 2.选择磁盘类型 3.开启虚拟机 4.用ls 命令查看:ls /dev/sd* 5.最后就可以对sdb进行分区操作 这里好麻烦,等我有空,在补上! . . .

利用matlab将三维数据画成三维立体图

首先先分析对象。将数据利用matlab画出图,最开始是导入数据,然后处理数据,最后将处理的数据画出来。 所以我将它分为三个步骤。 第一步:导入数据 如果是mat数据。可以直接load如果是txt数据。可以用txtread如果是excel数据。可…