来源:http://blog.csdn.net/zouxy09/article/details/13297881

1、径向基函数

径向基函数(Radical Basis Function,RBF)方法是Powell在1985年提出的。所谓径向基函数,其实就是某种沿径向对称的标量函数。通常定义为空间中任一点x到某一中心c之间欧氏距离的单调函数,可记作k(||x-c||),其作用往往是局部的,即当x远离c时函数取值很小。例如高斯径向基函数:

当年径向基函数的诞生主要是为了解决多变量插值的问题。可以看下面的图。具体的话是先在每个样本上面放一个基函数,图中每个蓝色的点是一个样本,然后中间那个图中绿色虚线对应的,就表示的是每个训练样本对应一个高斯函数(高斯函数中心就是样本点)。然后假设真实的拟合这些训练数据的曲线是蓝色的那根(最右边的图),如果我们有一个新的数据x1,我们想知道它对应的f(x1)是多少,也就是a点的纵坐标是多少。那么由图可以看到,a点的纵坐标等于b点的纵坐标加上c点的纵坐标。而b的纵坐标是第一个样本点的高斯函数的值乘以一个大点权值得到的,c的纵坐标是第二个样本点的高斯函数的值乘以另一个小点的权值得到。而其他样本点的权值全是0,因为我们要插值的点x1在第一和第二个样本点之间,远离其他的样本点,那么插值影响最大的就是离得近的点,离的远的就没什么贡献了。所以x1点的函数值由附近的b和c两个点就可以确定了。拓展到任意的新的x,这些红色的高斯函数乘以一个权值后再在对应的x地方加起来,就可以完美的拟合真实的函数曲线了。

二、径向基网络

到了1988年, Moody和 Darken提出了一种神经网络结构,即RBF神经网络,属于前向神经网络类型,它能够以任意精度逼近任意连续函数,特别适合于解决分类问题。

RBF网络的结构与多层前向网络类似,它是一种三层前向网络。输入层由信号源结点组成;第二层为隐含层,隐单元数视所描述问题的需要而定,隐单元的变换函数是RBF径向基函数,它是对中心点径向对称且衰减的非负非线性函数;第三层为输出层,它对输入模式的作用作出响应。从输人空间到隐含层空间的变换是非线性的,而从隐含层空间到输出层空间变换是线性的。

RBF网络的基本思想是:用RBF作为隐单元的“基”构成隐含层空间,这样就可将输入矢量直接(即不需要通过权连接)映射到隐空间。根据Cover定理,低维空间不可分的数据到了高维空间会更有可能变得可分。换句话来说,RBF网络的隐层的功能就是将低维空间的输入通过非线性函数映射到一个高维空间。然后再在这个高维空间进行曲线的拟合。它等价于在一个隐含的高维空间寻找一个能最佳拟合训练数据的表面。这点与普通的多层感知机MLP是不同的。

当RBF的中心点确定以后,这种映射关系也就确定了。而隐含层空间到输出空间的映射是线性的,即网络的输出是隐单元输出的线性加权和,此处的权即为网络可调参数。由此可见,从总体上看,网络由输人到输出的映射是非线性的,而网络输出对可调参数而言却又是线性的。这样网络的权就可由线性方程组直接解出,从而大大加快学习速度并避免局部极小问题。

从另一个方面也可以这样理解,多层感知器(包括BP神经网络)的隐节点基函数采用线性函数,激活函数则采用Sigmoid函数或硬极限函数。而RBF网络的隐节点的基函数采用距离函数(如欧氏距离),并使用径向基函数(如Gaussian函数)作为激活函数。径向基函数关于n维空间的一个中心点具有径向对称性,而且神经元的输入离该中心点越远,神经元的激活程度就越低。隐节点的这一特性常被称为“局部特性”。

三、RBF网络的设计与求解

RBF的设计主要包括两个方面,一个是结构设计,也就是说隐藏层含有几个节点合适。另一个就是参数设计,也就是对网络各参数进行求解。由上面的输入到输出的网络映射函数公式可以看到,网络的参数主要包括三种:径向基函数的中心、方差和隐含层到输出层的权值。到目前为止,出现了很多求解这三种参数的方法,主要可以分为以下两大类:

1、方法一:

通过非监督方法得到径向基函数的中心和方差,通过监督方法(最小均方误差)得到隐含层到输出层的权值。具体如下:

(1)在训练样本集中随机选择h个样本作为h个径向基函数的中心。更好的方法是通过聚类,例如K-means聚类得到h个聚类中心,将这些聚类中心当成径向基函数的h个中心。

(2)RBF神经网络的基函数为高斯函数时,方差可由下式求解:

式中cmax 为所选取中心之间的最大距离,h是隐层节点的个数。扩展常数这么计算是为了避免径向基函数太尖或太平。

(3)隐含层至输出层之间神经元的连接权值可以用最小均方误差LMS直接计算得到,计算公式如下:(计算伪逆)(d是我们期待的输出值)

2、方法二:

采用监督学习算法对网络所有的参数(径向基函数的中心、方差和隐含层到输出层的权值)进行训练。主要是对代价函数(均方误差)进行梯度下降,然后修正每个参数。具体如下:

(1)随机初始化径向基函数的中心、方差和隐含层到输出层的权值。当然了,也可以选用方法一中的(1)来初始化径向基函数的中心。

(2)通过梯度下降来对网络中的三种参数都进行监督训练优化。代价函数是网络输出和期望输出的均方误差:

然后每次迭代,在误差梯度的负方向已一定的学习率调整参数。

四、代码实现:

1、第一种方法

第一种方法在zhangchaoyang的博客上面有C++的实现,只是上面针对的是标量的数据(输入和输出都是一维的)。而在Matlab中也提供了第一种方法的改进版(呵呵,个人觉得,大家可以在Matlab中运行open newrb查看下源代码)。

Matlab提供的一个函数是newrb()。它有个技能就是可以自动增加网络的隐层神经元数目直到均方差满足我们要求的精度或者神经元数数目达到最大(也就是我们提供的样本数目,当神经元数目和我们的样本数目一致时,rbf网络此时的均方误差为0)为止。它使用方法也能简单:

rbf = newrb(train_x, train_y);

output = rbf(test_x);

直接把训练样本给它就可以得到一个rbf网络了。然后我们把输入给它就可以得到网络的输出了。

2、第二种方法

第二种方法在zhangchaoyang的博客上面也有C++的实现,只是上面针对的还是标量的数据(输入和输出都是一维的)。但我是做图像的,网络需要接受高维的输入,而且在Matlab中,向量的运算要比for训练的运算要快很多。所以我就自己写了个可以接受向量输入和向量输出的通过BP算法监督训练的版本。BP算法可以参考这里:BackpropagationAlgorithm ,主要是计算每层每个节点的残差就可以了。另外,我的代码是可以通过梯度检查的,但在某些训练集上面,代价函数值却会随着迭代次数上升,这就很奇怪了,然后降低了学习率还是一样。但在某些简单点的训练集上面还是可以工作的,虽然训练误差也挺大的(没有完全拟合训练样本)。所以大家如果发现代码里面有错误的部分,还望大家告知下。

主要代码见下面:

learnRBF.m

[cpp] view plain copy

  1. %// This is a RBF network trained by BP algorithm

  2. %// Author : zouxy

  3. %// Date   : 2013-10-28

  4. %// HomePage : http://blog.csdn.net/zouxy09

  5. %// Email  : zouxy09@qq.com

  6. close all; clear; clc;

  7. %%% ************************************************

  8. %%% ************ step 0: load data ****************

  9. display('step 0: load data...');

  10. % train_x = [1 2 3 4 5 6 7 8]; % each sample arranged as a column of train_x

  11. % train_y = 2 * train_x;

  12. train_x = rand(5, 10);

  13. train_y = 2 * train_x;

  14. test_x = train_x;

  15. test_y = train_y;

  16. %% from matlab

  17. % rbf = newrb(train_x, train_y);

  18. % output = rbf(test_x);

  19. %%% ************************************************

  20. %%% ******** step 1: initialize parameters ********

  21. display('step 1: initialize parameters...');

  22. numSamples = size(train_x, 2);

  23. rbf.inputSize = size(train_x, 1);

  24. rbf.hiddenSize = numSamples;        % num of Radial Basis function

  25. rbf.outputSize = size(train_y, 1);

  26. rbf.alpha = 0.1;  % learning rate (should not be large!)

  27. %% centre of RBF

  28. for i = 1 : rbf.hiddenSize

  29. % randomly pick up some samples to initialize centres of RBF

  30. index = randi([1, numSamples]);

  31. rbf.center(:, i) =  train_x(:, index);

  32. end

  33. %% delta of RBF

  34. rbf.delta = rand(1, rbf.hiddenSize);

  35. %% weight of RBF

  36. r = 1.0; % random number between [-r, r]

  37. rbf.weight = rand(rbf.outputSize, rbf.hiddenSize) * 2 * r - r;

  38. %%% ************************************************

  39. %%% ************ step 2: start training ************

  40. display('step 2: start training...');

  41. maxIter = 400;

  42. preCost = 0;

  43. for i = 1 : maxIter

  44. fprintf(1, 'Iteration %d ,', i);

  45. rbf = trainRBF(rbf, train_x, train_y);

  46. fprintf(1, 'the cost is %d \n', rbf.cost);

  47. curCost = rbf.cost;

  48. if abs(curCost - preCost) < 1e-8

  49. disp('Reached iteration termination condition and Termination now!');

  50. break;

  51. end

  52. preCost = curCost;

  53. end

  54. %%% ************************************************

  55. %%% ************ step 3: start testing ************

  56. display('step 3: start testing...');

  57. Green = zeros(rbf.hiddenSize, 1);

  58. for i = 1 : size(test_x, 2)

  59. for j = 1 : rbf.hiddenSize

  60. Green(j, 1) = green(test_x(:, i), rbf.center(:, j), rbf.delta(j));

  61. end

  62. output(:, i) = rbf.weight * Green;

  63. end

  64. disp(test_y);

  65. disp(output);

trainRBF.m

[cpp] view plain copy

  1. function [rbf] = trainRBF(rbf, train_x, train_y)

  2. %%% step 1: calculate gradient

  3. numSamples = size(train_x, 2);

  4. Green = zeros(rbf.hiddenSize, 1);

  5. output = zeros(rbf.outputSize, 1);

  6. delta_weight = zeros(rbf.outputSize, rbf.hiddenSize);

  7. delta_center = zeros(rbf.inputSize, rbf.hiddenSize);

  8. delta_delta =  zeros(1, rbf.hiddenSize);

  9. rbf.cost = 0;

  10. for i = 1 : numSamples

  11. %% Feed forward

  12. for j = 1 : rbf.hiddenSize

  13. Green(j, 1) = green(train_x(:, i), rbf.center(:, j), rbf.delta(j));

  14. end

  15. output = rbf.weight * Green;

  16. %% Back propagation

  17. delta3 = -(train_y(:, i) - output);

  18. rbf.cost = rbf.cost + sum(delta3.^2);

  19. delta_weight = delta_weight + delta3 * Green';

  20. delta2 = rbf.weight' * delta3 .* Green;

  21. for j = 1 : rbf.hiddenSize

  22. delta_center(:, j) = delta_center(:, j) + delta2(j) .* (train_x(:, i) - rbf.center(:, j)) ./ rbf.delta(j)^2;

  23. delta_delta(j) = delta_delta(j)+ delta2(j) * sum((train_x(:, i) - rbf.center(:, j)).^2) ./ rbf.delta(j)^3;

  24. end

  25. end

  26. %%% step 2: update parameters

  27. rbf.cost = 0.5 * rbf.cost ./ numSamples;

  28. rbf.weight = rbf.weight - rbf.alpha .* delta_weight ./ numSamples;

  29. rbf.center = rbf.center - rbf.alpha .* delta_center ./ numSamples;

  30. rbf.delta = rbf.delta - rbf.alpha .* delta_delta ./ numSamples;

  31. end

green.m

[plain] view plain copy

  1. function greenValue = green(x, c, delta)

  2. greenValue = exp(-1.0 * sum((x - c).^2) / (2 * delta^2));

  3. end

五、代码测试

首先,我测试了一维的输入,需要拟合的函数很简单,就是y=2x。

train_x = [1 2 3 4 5 6 7 8];

train_y = 2 * train_x;

所以期待的输出就是:

2    4     6     8   10    12    14   16

我代码训练迭代200次后的网络输出是:

2.0042   4.0239    5.9250    8.0214  10.0692   11.9351   14.0179  15.9958

Matlab的newrb的输出是:

2.0000   4.0000    6.0000    8.0000  10.0000   12.0000   14.0000  16.0000

可以看到,Matlab的是完美拟合啊。我的那个还是均方误差还是挺大的。

然后,我测试了高维的输入,训练样本是通过Matlab的rand(5, 10)来得到的,它生成的是5行10列[0 1]之间的随机数。也就是说我们的样本是10个,每个样本的维度是5维。我们测试的也是很简单的函数y=2x。结果如下:

关于这个结果,我也不说什么了。期待大家发现代码里面错误的地方,然后告知下,非常感谢。

以上均为拷贝过来的,博主提供的matlab代码还可以改善的,但是不失为一篇学习的好文。

 

径向基网络(RBF network)的更多相关文章

  1. MATLAB——径向基网络拟合曲线和分类

    1.:.:; rand('state',pi); %指定状态,产生相同的随机数 T=sin(*P)+rand(,length(P)); % 给正弦函数加噪声 plot(P,T,'o') % net=n ...

  2. 径向基(RBF)神经网络python实现

    from numpy import array, append, vstack, transpose, reshape, \ dot, true_divide, mean, exp, sqrt, lo ...

  3. RBF(径向基)神经网络

    只要模型是一层一层的,并使用AD/BP算法,就能称作 BP神经网络.RBF 神经网络是其中一个特例.本文主要包括以下内容: 什么是径向基函数 RBF神经网络 RBF神经网络的学习问题 RBF神经网络与 ...

  4. 机器学习之径向基神经网络(RBF NN)

    本文基于台大机器学习技法系列课程进行的笔记总结. 主要内容如下图所示: 首先介绍一下径向基函数网络的Hypothesis和网络的结构,然后介绍径向基神经网络学习算法,以及利用K-means进行的学习, ...

  5. RBF高斯径向基核函数【转】

    XVec表示X向量.||XVec||表示向量长度.r表示两点距离.r^2表示r的平方.k(XVec,YVec) = exp(-1/(2*sigma^2)*(r^2))= exp(-gamma*r^2) ...

  6. Java - 网络编程(NetWork)

    Java - 网络编程(NetWork)   一.java.net包下的 InetAddress 类的使用:     > 一个 InetAddress 代表着一个IP地址     > 主要 ...

  7. centos7 无法启动网络(service network restart)错误解决办法

    centos7 无法启动网络(service network restart)错误解决办法: (以下方法均为网上COPY,同时感谢原博主分享) systemctl status network.ser ...

  8. 解决React Native使用Fetch API请求网络报Network request failed

    问题来源: 1 . 在测试fetch数据请求时,Xcode9.0以上的无法请求https, 需要在Xcode中加载项目后修改Info.plist的相关配置,具体如下参考 问题及解决方法一模一样,不再重 ...

  9. 残差网络(Residual Network)

    一.背景 1)梯度消失问题 我们发现很深的网络层,由于参数初始化一般更靠近0,这样在训练的过程中更新浅层网络的参数时,很容易随着网络的深入而导致梯度消失,浅层的参数无法更新. 可以看到,假设现在需要更 ...

随机推荐

  1. poj2796 维护区间栈//单调栈

    http://poj.org/problem?id=2796 题意:给你一段区间,需要你求出(在这段区间之类的最小值*这段区间所有元素之和)的最大值...... 例如: 6 3 1 6 4 5 2 以 ...

  2. ligerui_ligerTree_007_ligerTree动态加载节点

    ligerui:ligerTree:动态加载节点: 源码地址:http://download.csdn.net/detail/poiuy1991719/8571255 效果图: 代码:json.txt ...

  3. DBA_Oracle Erp R12中文补丁安装升级(案例)

    2014-07-11 Created By BaoXinjian

  4. 二进制序列化框架easypack发布啦!

    简介 easypack是基于boost.serialization的二进制序列化框架,使用极其方便. Examples 基本类型 int age = 20; std::string name = &q ...

  5. 【Stage3D学习笔记续】山寨Starling(四):渲染代码实现及测试程序

    本章会实现最核心的代码,所以涉及点会比较多,这里会发布一个版本,方便日后的回退查看. 点击下载:https://codeload.github.com/hammerc/hammerc-study-St ...

  6. nodeJS之crypto加密

    前面的话 加密模块提供了 HTTP 或 HTTPS 连接过程中封装安全凭证的方法.也提供了 OpenSSL 的哈希,hmac, 加密(cipher), 解密(decipher), 签名(sign) 和 ...

  7. java学习笔记之String类

    String类总结 String类概述: java.lang.String 类是字符串操作类 String类的常用构造方法: //1.直接赋值 String str= "hellojava& ...

  8. mongodb系列之---副本集配置与说明

    在配置副本集之前,我们先来了解一些关于副本集的知识. 1,副本集的原理 副本集的原理与主从很相似,唯一不同的是,在主节点出现故障的时候,主从配置的从服务器不会自动的变为主服务器,而是要通过手动修改配置 ...

  9. C# 文件绝对路径与相对路径的转换

    class Program { const string CONFIG_PATH = @"C:\SoftWare\Config.xml"; const string IMAGE_P ...

  10. Tree 和ls 的使用

    再次声明:linux下的文件系统采用树的结构实现的 我们 可以安装 Tree 软件 在当前目录下(随便一个当前目录下)输入 tree 命令,我们可以看到整个当前文件目录下的目录以及文件的树状结构,这也 ...