只要模型是一層一層的,並使用AD/BP算法,就能稱作 BP神經網絡。RBF 神經網絡是其中一個特例。本文主要包括以下內容:
- 什么是徑向基函數
- RBF神經網絡
- RBF神經網絡的學習問題
- RBF神經網絡與BP神經網絡的區別
- RBF神經網絡與SVM的區別
- 為什么高斯核函數就是映射到高維區間
- 前饋網絡、遞歸網絡和反饋網絡
- 完全內插法
一、什么是徑向基函數
1985年,Powell提出了多變量插值的徑向基函數(RBF)方法。徑向基函數是一個取值僅僅依賴於離原點距離的實值函數,也就是Φ(x)=Φ(‖x‖),或者還可以是到任意一點c的距離,c點稱為中心點,也就是Φ(x,c)=Φ(‖x-c‖)。任意一個滿足Φ(x)=Φ(‖x‖)特性的函數Φ都叫做徑向基函數,標准的一般使用歐氏距離(也叫做歐式徑向基函數),盡管其他距離函數也是可以的。最常用的徑向基函數是高斯核函數 ,形式為 k(||x-xc||)=exp{- ||x-xc||^2/(2*σ)^2) } 其中x_c為核函數中心,σ為函數的寬度參數 , 控制了函數的徑向作用范圍。
二、RBF神經網絡
RBF神將網絡是一種三層神經網絡,其包括輸入層、隱層、輸出層。從輸入空間到隱層空間的變換是非線性的,而從隱層空間到輸出層空間變換是線性的。流圖如下:

RBF網絡的基本思想是:用RBF作為隱單元的“基”構成隱含層空間,這樣就可以將輸入矢量直接映射到隱空間,而不需要通過權連接。當RBF的中心點確定以后,這種映射關系也就確定了。而隱含層空間到輸出空間的映射是線性的,即網絡的輸出是隱單元輸出的線性加權和,此處的權即為網絡可調參數。其中,隱含層的作用是把向量從低維度的p映射到高維度的h,這樣低維度線性不可分的情況到高維度就可以變得線性可分了,主要就是核函數的思想。這樣,網絡由輸入到輸出的映射是非線性的,而網絡輸出對可調參數而言卻又是線性的。網絡的權就可由線性方程組直接解出,從而大大加快學習速度並避免局部極小問題。
徑向基神經網絡的激活函數可表示為:
![]()
其中xp為第p個輸入樣本,ci為第i個中心點,h為隱含層的結點數,n是輸出的樣本數或分類數。徑向基神經網絡的結構可得到網絡的輸出為:

當然,采用最小二乘的損失函數表示:

三、RBF神經網絡的學習問題
求解的參數有3個:基函數的中心、方差以及隱含層到輸出層的權值。
(1)自組織選取中心學習方法:
第一步:無監督學習過程,求解隱含層基函數的中心與方差
第二步:有監督學習過程,求解隱含層到輸出層之間的權值
首先,選取h個中心做k-means聚類,對於高斯核函數的徑向基,方差由公式求解:
![]()
cmax為所選取中心點之間的最大距離。
隱含層至輸出層之間的神經元的連接權值可以用最小二乘法直接計算得到,即對損失函數求解關於w的偏導數,使其等於0,可以化簡得到計算公式為:

(2)直接計算法
隱含層神經元的中心是隨機地在輸入樣本中選取,且中心固定。一旦中心固定下來,隱含層神經元的輸出便是已知的,這樣的神經網絡的連接權就可以通過求解線性方程組來確定。適用於樣本數據的分布具有明顯代表性。
(3)有監督學習算法
通過訓練樣本集來獲得滿足監督要求的網絡中心和其他權重參數,經歷一個誤差修正學習的過程,與BP網絡的學習原理一樣,同樣采用梯度下降法。因此RBF同樣可以被當作BP神經網絡的一種。
參考:http://read.pudn.com/downloads110/sourcecode/others/454289/Paper/pdf/y9935500004.pdf
四、RBF神經網絡與BP神經網絡之間的區別
1、局部逼近與全局逼近:
BP神經網絡的隱節點采用輸入模式與權向量的內積作為激活函數的自變量,而激活函數采用Sigmoid函數。各調參數對BP網絡的輸出具有同等地位的影響,因此BP神經網絡是對非線性映射的全局逼近。
RBF神經網絡的隱節點采用輸入模式與中心向量的距離(如歐式距離)作為函數的自變量,並使用徑向基函數(如Gaussian函數)作為激活函數。神經元的輸入離徑向基函數中心越遠,神經元的激活程度就越低(高斯函數)。RBF網絡的輸出與部分調參數有關,譬如,一個wij值只影響一個yi的輸出(參考上面第二章網絡輸出),RBF神經網絡因此具有“局部映射”特性。
所謂局部逼近是指目標函數的逼近僅僅根據查詢點附近的數據。而事實上,對於徑向基網絡,通常使用的是高斯徑向基函數,函數圖象是兩邊衰減且徑向對稱的,當選取的中心與查詢點(即輸入數據)很接近的時候才對輸入有真正的映射作用,若中心與查詢點很遠的時候,歐式距離太大的情況下,輸出的結果趨於0,所以真正起作用的點還是與查詢點很近的點,所以是局部逼近;而BP網絡對目標函數的逼近跟所有數據都相關,而不僅僅來自查詢點附近的數據。

五、RBF神經網絡與SVM的區別
SVM等如果使用核函數的技巧的話,不太適應於大樣本和大的特征數的情況,因此提出了RBF。
另外,SVM中的高斯核函數可以看作與每一個輸入點的距離,而RBF神經網絡對輸入點做了一個聚類。RBF神經網絡用高斯核函數時,其數據中心C可以是訓練樣本中的抽樣,此時與svm的高斯核函數是完全等價的,也可以是訓練樣本集的多個聚類中心,所以他們都是需要選擇數據中心的,只不過SVM使用高斯核函數時,這里的數據中心都是訓練樣本本身而已。

六、為什么高斯核函數就是映射到高維空間
首先給出高斯核函數的定義公式:

實際上,可以化簡為:

當然通過冪級數展開:
![]()
可以看到,其中X向量會生成類似多項式核展開的形式,譬如原來的參數有x1,x2。映射后,參數包含了x1*x1 ,x1*x2,x2*x2將原來2維映射到3維上了。
七、前饋網絡、遞歸網絡和反饋網絡
前饋網絡一般指前饋神經網絡或前饋型神經網絡。它是一種最簡單的神經網絡,各神經元分層排列。每個神經元只與前一層的神經元相連。接收前一層的輸出,並輸出給下一層,各層間沒有反饋。包括:BP神經網絡、RBF神經網絡等。
遞歸神經網絡(RNN)是兩種人工神經網絡的總稱。一種是時間遞歸神經網絡(recurrent neural network),又名循環神經網絡,包括RNN、LSTM、GRU等;另一種是結構遞歸神經網絡(recursive neural network)。
反饋網絡(Recurrent Network),又稱自聯想記憶網絡,其目的是為了設計一個網絡,儲存一組平衡點,使得當給網絡一組初始值時,網絡通過自行運行而最終收斂到這個設計的平衡點上。包括CHNN、DHNN等。
八、完全內插法
之所以RBF能夠擬合任意函數,可以從內插法的角度去理解。要擬合一個曲線,我們可以通過內插法獲得這個曲線的表達函數,譬如:多項式插值、拉格朗日插值等。RBF 插值是一系列精確插值方法的組合;即表面必須通過每一個測得的采樣值。

對於RBF插值,其特點即為,在輸入數據集中,與中心點距離近的點對映射函數的貢獻最大。
完全內插法即要求所有插值點都經過曲面,由於RBF內插對於每個x都有用到,所以是一種完全內插的形式,存在的問題就是當樣本中包含噪聲時,神經網絡將擬合出一個錯誤的曲面,從而使泛化能力下降。另外,若樣本x的數據遠大於非線性函數φ,該求解變得不穩定,即為解超定方程。因此需要引入正則化方法,正則化的方法即通常加上正則化項。

在使用RBF神經網絡實現函數逼近中,筆者介紹了使用 Matlab 訓練RBF神經網絡。本博客將介紹使用 tensorflow 訓練RBF神經網絡。代碼資源見:RBF案例(更新版)
一些具體的逼近示例見:https://blog.csdn.net/m0_37602827/article/details/103099972
這幾天,筆者在尋找 tensorflow 中 RBF 官方案例,沒找到,又看了一些博客,發現這些博客或不能逼近多元函數,或不能批量訓練。於是,自己手撕了一下代碼。
RBF神經網絡中需要求解的參數有4個:基函數的中心和方差、隱含層到輸出層的權值和偏值。
RBF 神經網絡的關鍵在於中心的選取,一般有如下三種方法:
直接計算法:直接通過先驗經驗固定中心,並計算方差,再通過有監督學習得到其他參數
自組織學習法:先通過k-means等聚類算法求出中心(無監督學習),並計算方差,再通過有監督學習得到其他參數
有監督學習法:直接通過有監督學習求出所有參數
在直接計算法和自組織學習法中,方差的計算公式如下:
其中 Cmax 表示 h 個中心間的最大距離。
本博客主要介紹后兩種中心計算方法實現 RBF 神經網絡。
筆者工作空間如下:
2 RBF神經網絡實現
2.1 自組織學習選取RBF中心
RBF_kmeans.py
import tensorflow as tf
import numpy as np
from sklearn.cluster import KMeans
class RBF:
#初始化學習率、學習步數
def __init__(self,learning_rate=0.002,step_num=10001,hidden_size=10):
self.learning_rate=learning_rate
self.step_num=step_num
self.hidden_size=hidden_size
#使用 k-means 獲取聚類中心、標准差
def getC_S(self,x,class_num):
estimator=KMeans(n_clusters=class_num,max_iter=10000) #構造聚類器
estimator.fit(x) #聚類
c=estimator.cluster_centers_
n=len(c)
s=0;
for i in range(n):
j=i+1
while j<n:
t=np.sum((c[i]-c[j])**2)
s=max(s,t)
j=j+1
s=np.sqrt(s)/np.sqrt(2*n)
return c,s
#高斯核函數(c為中心,s為標准差)
def kernel(self,x,c,s):
x1=tf.tile(x,[1,self.hidden_size]) #將x水平復制 hidden次
x2=tf.reshape(x1,[-1,self.hidden_size,self.feature])
dist=tf.reduce_sum((x2-c)**2,2)
return tf.exp(-dist/(2*s**2))
#訓練RBF神經網絡
def train(self,x,y):
self.feature=np.shape(x)[1] #輸入值的特征數
self.c,self.s=self.getC_S(x,self.hidden_size) #獲取聚類中心、標准差
x_=tf.placeholder(tf.float32,[None,self.feature]) #定義placeholder
y_=tf.placeholder(tf.float32,[None,1]) #定義placeholder
#定義徑向基層
z=self.kernel(x_,self.c,self.s)
#定義輸出層
w=tf.Variable(tf.random_normal([self.hidden_size,1]))
b=tf.Variable(tf.zeros([1]))
yf=tf.matmul(z,w)+b
loss=tf.reduce_mean(tf.square(y_-yf))#二次代價函數
optimizer=tf.train.AdamOptimizer(self.learning_rate) #Adam優化器
train=optimizer.minimize(loss) #最小化代價函數
init=tf.global_variables_initializer() #變量初始化
with tf.Session() as sess:
sess.run(init)
for epoch in range(self.step_num):
sess.run(train,feed_dict={x_:x,y_:y})
if epoch>0 and epoch%500==0:
mse=sess.run(loss,feed_dict={x_:x,y_:y})
print(epoch,mse)
self.w,self.b=sess.run([w,b],feed_dict={x_:x,y_:y})
def kernel2(self,x,c,s): #預測時使用
x1=np.tile(x,[1,self.hidden_size]) #將x水平復制 hidden次
x2=np.reshape(x1,[-1,self.hidden_size,self.feature])
dist=np.sum((x2-c)**2,2)
return np.exp(-dist/(2*s**2))
def predict(self,x):
z=self.kernel2(x,self.c,self.s)
pre=np.matmul(z,self.w)+self.b
return pre
2.2 有監督學習選取RBF中心
RBF_Supervised.py
import numpy as np
import tensorflow as tf
class RBF:
#初始化學習率、學習步數
def __init__(self,learning_rate=0.002,step_num=10001,hidden_size=10):
self.learning_rate=learning_rate
self.step_num=step_num
self.hidden_size=hidden_size
#高斯核函數(c為中心,s為標准差)
def kernel(self,x,c,s): #訓練時使用
x1=tf.tile(x,[1,self.hidden_size]) #將x水平復制 hidden次
x2=tf.reshape(x1,[-1,self.hidden_size,self.feature])
dist=tf.reduce_sum((x2-c)**2,2)
return tf.exp(-dist/(2*s**2))
#訓練RBF神經網絡
def train(self,x,y):
self.feature=np.shape(x)[1] #輸入值的特征數
x_=tf.placeholder(tf.float32,[None,self.feature]) #定義placeholder
y_=tf.placeholder(tf.float32,[None,1]) #定義placeholder
#定義徑向基層
c=tf.Variable(tf.random_normal([self.hidden_size,self.feature]))
s=tf.Variable(tf.random_normal([self.hidden_size]))
z=self.kernel(x_,c,s)
#定義輸出層
w=tf.Variable(tf.random_normal([self.hidden_size,1]))
b=tf.Variable(tf.zeros([1]))
yf=tf.matmul(z,w)+b
loss=tf.reduce_mean(tf.square(y_-yf))#二次代價函數
optimizer=tf.train.AdamOptimizer(self.learning_rate) #Adam優化器
train=optimizer.minimize(loss) #最小化代價函數
init=tf.global_variables_initializer() #變量初始化
with tf.Session() as sess:
sess.run(init)
for epoch in range(self.step_num):
sess.run(train,feed_dict={x_:x,y_:y})
if epoch>0 and epoch%500==0:
mse=sess.run(loss,feed_dict={x_:x,y_:y})
print(epoch,mse)
self.c,self.s,self.w,self.b=sess.run([c,s,w,b],feed_dict={x_:x,y_:y})
def kernel2(self,x,c,s): #預測時使用
x1=np.tile(x,[1,self.hidden_size]) #將x水平復制 hidden次
x2=np.reshape(x1,[-1,self.hidden_size,self.feature])
dist=np.sum((x2-c)**2,2)
return np.exp(-dist/(2*s**2))
def predict(self,x):
z=self.kernel2(x,self.c,self.s)
pre=np.matmul(z,self.w)+self.b
return pre
3 案例
3.1 一元函數逼近
待逼近函數:
(1)自組織學習選取RBF中心
test_kmeans.py
import numpy as np
import matplotlib.pyplot as plt
from RBF_kmeans import RBF
#待逼近的函數
def fun(x):
return x*x+2*x*np.sin(x)-np.exp(-x)/10
#生成樣本
def generate_samples():
n=150 #樣本點個數
wideX=0.03 #橫軸噪聲的寬度
wideY=0.5 #縱軸噪聲寬度
t=np.linspace(-5,5,n).reshape(-1,1) #橫軸理想值
u=fun(t) #縱軸理想值
noisyX=np.random.uniform(-wideX,wideX,n).reshape(n,-1) #橫軸噪聲
noisyY=np.random.uniform(-wideY,wideY,n).reshape(n,-1) #縱軸噪聲
x=t+noisyX #橫軸實際值
y=u+noisyY #縱軸實際值
return t,u,x,y
t,u,x,y=generate_samples()
rbf=RBF(0.003,20001,4) #學習率
rbf.train(x,y)
pre=rbf.predict(t)
plt.plot(x,y,'+')
plt.plot(t,u)
plt.plot(t,pre)
plt.legend(['dot','real','pre'],loc='upper left')
自組織學習選取RBF中心
(2)有監督學習選取RBF中心
test_Supervised.py
import numpy as np
import matplotlib.pyplot as plt
from RBF_Supervised import RBF
#待逼近的函數
def fun(x):
return x*x+2*x*np.sin(x)-np.exp(-x)/10
#生成樣本
def generate_samples():
n=150 #樣本點個數
wideX=0.03 #橫軸噪聲的寬度
wideY=0.5 #縱軸噪聲寬度
t=np.linspace(-5,5,n).reshape(-1,1) #橫軸理想值
u=fun(t) #縱軸理想值
noisyX=np.random.uniform(-wideX,wideX,n).reshape(n,-1) #橫軸噪聲
noisyY=np.random.uniform(-wideY,wideY,n).reshape(n,-1) #縱軸噪聲
x=t+noisyX #橫軸實際值
y=u+noisyY #縱軸實際值
return t,u,x,y
t,u,x,y=generate_samples()
rbf=RBF(0.003,20001,4) #學習率
rbf.train(x,y)
pre=rbf.predict(t)
plt.plot(x,y,'+')
plt.plot(t,u)
plt.plot(t,pre)
plt.legend(['dot','real','pre'],loc='upper left')
有監督學習選取RBF中心
3.2 二元函數逼近
待逼近函數:
(1)自組織學習選取RBF中心
test_kmeans2.py
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from RBF_kmeans import RBF
#待逼近的函數
def fun(t):
x1=(t+0.5*np.pi)*np.sin(t+0.5*np.pi)
x2=(t+0.5*np.pi)*np.cos(t+0.5*np.pi)
y=1.5*t
x=np.append(x1,x2,1)
return x,y
#生成樣本
def generate_samples():
n=200 #樣本點個數
wideX=0.6 #水平方向噪聲的寬度
wideY=1 #縱軸噪聲寬度
t=np.linspace(0,10*np.pi,n).reshape(-1,1) #橫軸理想值
u,v=fun(t) #縱軸理想值
noisyX=np.random.uniform(-wideX,wideX,u.shape).reshape(n,-1) #水平方向噪聲
noisyY=np.random.uniform(-wideY,wideY,n).reshape(n,-1) #縱軸噪聲
x=u+noisyX #橫軸實際值
y=v+noisyY #縱軸實際值
return u,v,x,y
u,v,x,y=generate_samples()
rbf=RBF(0.02,20001,10) #學習率
rbf.train(x,y)
pre=rbf.predict(u)
ax=plt.figure().gca(projection='3d')
ax.plot(x[:,0],x[:,1],y[:,0],'+')
ax.plot(u[:,0],u[:,1],v[:,0])
ax.plot(u[:,0],u[:,1],pre[:,0])
plt.legend(['dot','real','pre'],loc='upper left')
plt.show()
自組織學習選取RBF中心
(2)有監督學習選取RBF中心
test_Supervised2.py
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from RBF_Supervised import RBF
#待逼近的函數
def fun(t):
x1=(t+0.5*np.pi)*np.sin(t+0.5*np.pi)
x2=(t+0.5*np.pi)*np.cos(t+0.5*np.pi)
y=1.5*t
x=np.append(x1,x2,1)
return x,y
#生成樣本
def generate_samples():
n=200 #樣本點個數
wideX=0.6 #水平方向噪聲的寬度
wideY=1 #縱軸噪聲寬度
t=np.linspace(0,10*np.pi,n).reshape(-1,1) #橫軸理想值
u,v=fun(t) #縱軸理想值
noisyX=np.random.uniform(-wideX,wideX,u.shape).reshape(n,-1) #水平方向噪聲
noisyY=np.random.uniform(-wideY,wideY,n).reshape(n,-1) #縱軸噪聲
x=u+noisyX #橫軸實際值
y=v+noisyY #縱軸實際值
return u,v,x,y
u,v,x,y=generate_samples()
rbf=RBF(0.02,20001,10) #學習率
rbf.train(x,y)
pre=rbf.predict(u)
ax=plt.figure().gca(projection='3d')
ax.plot(x[:,0],x[:,1],y[:,0],'+')
ax.plot(u[:,0],u[:,1],v[:,0])
ax.plot(u[:,0],u[:,1],pre[:,0])
plt.legend(['dot','real','pre'],loc='upper left')
plt.show()
有監督學習選取RBF中心
通過實驗可以看到:無論是一元函數逼近還是二元函數逼近,在隱藏層神經元個數、學習率、學習步數相同的情況下,有監督學習法都比自組織學習法效果好。
————————————————
版權聲明:本文為CSDN博主「little_fat_sheep」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/m0_37602827/article/details/103099972
