來源:http://blog.csdn.net/zouxy09/article/details/13297881算法
一、徑向基函數網絡
徑向基函數(Radical Basis Function,RBF)方法是Powell在1985年提出的。所謂徑向基函數,其實就是某種沿徑向對稱的標量函數。一般定義爲空間中任一點x到某一中心c之間歐氏距離的單調函數,可記做k(||x-c||),其做用每每是局部的,即當x遠離c時函數取值很小。例如高斯徑向基函數:dom
當年徑向基函數的誕生主要是爲了解決多變量插值的問題。能夠看下面的圖。具體的話是先在每一個樣本上面放一個基函數,圖中每一個藍色的點是一個樣本,而後中間那個圖中綠色虛線對應的,就表示的是每一個訓練樣本對應一個高斯函數(高斯函數中心就是樣本點)。而後假設真實的擬合這些訓練數據的曲線是藍色的那根(最右邊的圖),若是咱們有一個新的數據x1,咱們想知道它對應的f(x1)是多少,也就是a點的縱座標是多少。那麼由圖能夠看到,a點的縱座標等於b點的縱座標加上c點的縱座標。而b的縱座標是第一個樣本點的高斯函數的值乘以一個大點權值獲得的,c的縱座標是第二個樣本點的高斯函數的值乘以另外一個小點的權值獲得。而其餘樣本點的權值全是0,由於咱們要插值的點x1在第一和第二個樣本點之間,遠離其餘的樣本點,那麼插值影響最大的就是離得近的點,離的遠的就沒什麼貢獻了。因此x1點的函數值由附近的b和c兩個點就能夠肯定了。拓展到任意的新的x,這些紅色的高斯函數乘以一個權值後再在對應的x地方加起來,就能夠完美的擬合真實的函數曲線了。函數
2、徑向基網絡學習
到了1988年, Moody和 Darken提出了一種神經網絡結構,即RBF神經網絡,屬於前向神經網絡類型,它可以以任意精度逼近任意連續函數,特別適合於解決分類問題。測試
RBF網絡的結構與多層前向網絡相似,它是一種三層前向網絡。輸入層由信號源結點組成;第二層爲隱含層,隱單元數視所描述問題的須要而定,隱單元的變換函數是RBF徑向基函數,它是對中心點徑向對稱且衰減的非負非線性函數;第三層爲輸出層,它對輸入模式的做用做出響應。從輸人空間到隱含層空間的變換是非線性的,而從隱含層空間到輸出層空間變換是線性的。優化
RBF網絡的基本思想是:用RBF做爲隱單元的「基」構成隱含層空間,這樣就可將輸入矢量直接(即不須要經過權鏈接)映射到隱空間。根據Cover定理,低維空間不可分的數據到了高維空間會更有可能變得可分。換句話來講,RBF網絡的隱層的功能就是將低維空間的輸入經過非線性函數映射到一個高維空間。而後再在這個高維空間進行曲線的擬合。它等價於在一個隱含的高維空間尋找一個能最佳擬合訓練數據的表面。這點與普通的多層感知機MLP是不一樣的。spa
當RBF的中心點肯定之後,這種映射關係也就肯定了。而隱含層空間到輸出空間的映射是線性的,即網絡的輸出是隱單元輸出的線性加權和,此處的權即爲網絡可調參數。因而可知,從整體上看,網絡由輸人到輸出的映射是非線性的,而網絡輸出對可調參數而言卻又是線性的。這樣網絡的權就可由線性方程組直接解出,從而大大加快學習速度並避免局部極小問題。.net
從另外一個方面也能夠這樣理解,多層感知器(包括BP神經網絡)的隱節點基函數採用線性函數,激活函數則採用Sigmoid函數或硬極限函數。而RBF網絡的隱節點的基函數採用距離函數(如歐氏距離),並使用徑向基函數(如Gaussian函數)做爲激活函數。徑向基函數關於n維空間的一箇中心點具備徑向對稱性,並且神經元的輸入離該中心點越遠,神經元的激活程度就越低。隱節點的這一特性常被稱爲「局部特性」。設計
3、RBF網絡的設計與求解
RBF的設計主要包括兩個方面,一個是結構設計,也就是說隱藏層含有幾個節點合適。另外一個就是參數設計,也就是對網絡各參數進行求解。由上面的輸入到輸出的網絡映射函數公式能夠看到,網絡的參數主要包括三種:徑向基函數的中心、方差和隱含層到輸出層的權值。到目前爲止,出現了不少求解這三種參數的方法,主要能夠分爲如下兩大類:
一、方法一:
經過非監督方法獲得徑向基函數的中心和方差,經過監督方法(最小均方偏差)獲得隱含層到輸出層的權值。具體以下:
(1)在訓練樣本集中隨機選擇h個樣本做爲h個徑向基函數的中心。更好的方法是經過聚類,例如K-means聚類獲得h個聚類中心,將這些聚類中心當成徑向基函數的h箇中心。
(2)RBF神經網絡的基函數爲高斯函數時,方差可由下式求解:
式中cmax 爲所選取中心之間的最大距離,h是隱層節點的個數。擴展常數這麼計算是爲了不徑向基函數太尖或太平。
(3)隱含層至輸出層之間神經元的鏈接權值能夠用最小均方偏差LMS直接計算獲得,計算公式以下:(計算僞逆)(d是咱們期待的輸出值)
二、方法二:
採用監督學習算法對網絡全部的參數(徑向基函數的中心、方差和隱含層到輸出層的權值)進行訓練。主要是對代價函數(均方偏差)進行梯度降低,而後修正每一個參數。具體以下:
(1)隨機初始化徑向基函數的中心、方差和隱含層到輸出層的權值。固然了,也能夠選用方法一中的(1)來初始化徑向基函數的中心。
(2)經過梯度降低來對網絡中的三種參數都進行監督訓練優化。代價函數是網絡輸出和指望輸出的均方偏差:
而後每次迭代,在偏差梯度的負方向已必定的學習率調整參數。
4、代碼實現:
一、第一種方法
第一種方法在zhangchaoyang的博客上面有C++的實現,只是上面針對的是標量的數據(輸入和輸出都是一維的)。而在Matlab中也提供了第一種方法的改進版(呵呵,我的以爲,你們能夠在Matlab中運行open newrb查看下源代碼)。
Matlab提供的一個函數是newrb()。它有個技能就是能夠自動增長網絡的隱層神經元數目直到均方差知足咱們要求的精度或者神經元數數目達到最大(也就是咱們提供的樣本數目,當神經元數目和咱們的樣本數目一致時,rbf網絡此時的均方偏差爲0)爲止。它使用方法也能簡單:
rbf = newrb(train_x, train_y);
output = rbf(test_x);
直接把訓練樣本給它就能夠獲得一個rbf網絡了。而後咱們把輸入給它就能夠獲得網絡的輸出了。
二、第二種方法
第二種方法在zhangchaoyang的博客上面也有C++的實現,只是上面針對的仍是標量的數據(輸入和輸出都是一維的)。但我是作圖像的,網絡須要接受高維的輸入,並且在Matlab中,向量的運算要比for訓練的運算要快不少。因此我就本身寫了個能夠接受向量輸入和向量輸出的經過BP算法監督訓練的版本。BP算法能夠參考這裏:BackpropagationAlgorithm ,主要是計算每層每一個節點的殘差就能夠了。另外,個人代碼是能夠經過梯度檢查的,但在某些訓練集上面,代價函數值卻會隨着迭代次數上升,這就很奇怪了,而後下降了學習率仍是同樣。但在某些簡單點的訓練集上面仍是能夠工做的,雖然訓練偏差也挺大的(沒有徹底擬合訓練樣本)。因此你們若是發現代碼裏面有錯誤的部分,還望你們告知下。
主要代碼見下面:
learnRBF.m
[cpp] view plain copy
%// This is a RBF network trained by BP algorithm
%// Author : zouxy
%// Date : 2013-10-28
%// HomePage : http://blog.csdn.net/zouxy09
%// Email : zouxy09@qq.com
close all; clear; clc;
%%% ************************************************
%%% ************ step 0: load data ****************
display('step 0: load data...');
% train_x = [1 2 3 4 5 6 7 8]; % each sample arranged as a column of train_x
% train_y = 2 * train_x;
train_x = rand(5, 10);
train_y = 2 * train_x;
test_x = train_x;
test_y = train_y;
%% from matlab
% rbf = newrb(train_x, train_y);
% output = rbf(test_x);
%%% ************************************************
%%% ******** step 1: initialize parameters ********
display('step 1: initialize parameters...');
numSamples = size(train_x, 2);
rbf.inputSize = size(train_x, 1);
rbf.hiddenSize = numSamples; % num of Radial Basis function
rbf.outputSize = size(train_y, 1);
rbf.alpha = 0.1; % learning rate (should not be large!)
%% centre of RBF
for i = 1 : rbf.hiddenSize
% randomly pick up some samples to initialize centres of RBF
index = randi([1, numSamples]);
rbf.center(:, i) = train_x(:, index);
end
%% delta of RBF
rbf.delta = rand(1, rbf.hiddenSize);
%% weight of RBF
r = 1.0; % random number between [-r, r]
rbf.weight = rand(rbf.outputSize, rbf.hiddenSize) * 2 * r - r;
%%% ************************************************
%%% ************ step 2: start training ************
display('step 2: start training...');
maxIter = 400;
preCost = 0;
for i = 1 : maxIter
fprintf(1, 'Iteration %d ,', i);
rbf = trainRBF(rbf, train_x, train_y);
fprintf(1, 'the cost is %d \n', rbf.cost);
curCost = rbf.cost;
if abs(curCost - preCost) < 1e-8
disp('Reached iteration termination condition and Termination now!');
break;
end
preCost = curCost;
end
%%% ************************************************
%%% ************ step 3: start testing ************
display('step 3: start testing...');
Green = zeros(rbf.hiddenSize, 1);
for i = 1 : size(test_x, 2)
for j = 1 : rbf.hiddenSize
Green(j, 1) = green(test_x(:, i), rbf.center(:, j), rbf.delta(j));
end
output(:, i) = rbf.weight * Green;
end
disp(test_y);
disp(output);
trainRBF.m
[cpp] view plain copy
function [rbf] = trainRBF(rbf, train_x, train_y)
%%% step 1: calculate gradient
numSamples = size(train_x, 2);
Green = zeros(rbf.hiddenSize, 1);
output = zeros(rbf.outputSize, 1);
delta_weight = zeros(rbf.outputSize, rbf.hiddenSize);
delta_center = zeros(rbf.inputSize, rbf.hiddenSize);
delta_delta = zeros(1, rbf.hiddenSize);
rbf.cost = 0;
for i = 1 : numSamples
%% Feed forward
for j = 1 : rbf.hiddenSize
Green(j, 1) = green(train_x(:, i), rbf.center(:, j), rbf.delta(j));
end
output = rbf.weight * Green;
%% Back propagation
delta3 = -(train_y(:, i) - output);
rbf.cost = rbf.cost + sum(delta3.^2);
delta_weight = delta_weight + delta3 * Green';
delta2 = rbf.weight' * delta3 .* Green;
for j = 1 : rbf.hiddenSize
delta_center(:, j) = delta_center(:, j) + delta2(j) .* (train_x(:, i) - rbf.center(:, j)) ./ rbf.delta(j)^2;
delta_delta(j) = delta_delta(j)+ delta2(j) * sum((train_x(:, i) - rbf.center(:, j)).^2) ./ rbf.delta(j)^3;
end
end
%%% step 2: update parameters
rbf.cost = 0.5 * rbf.cost ./ numSamples;
rbf.weight = rbf.weight - rbf.alpha .* delta_weight ./ numSamples;
rbf.center = rbf.center - rbf.alpha .* delta_center ./ numSamples;
rbf.delta = rbf.delta - rbf.alpha .* delta_delta ./ numSamples;
end
green.m
[plain] view plain copy
function greenValue = green(x, c, delta)
greenValue = exp(-1.0 * sum((x - c).^2) / (2 * delta^2));
end
5、代碼測試
首先,我測試了一維的輸入,須要擬合的函數很簡單,就是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代碼還能夠改善的,可是不失爲一篇學習的好文。