RBF神經網絡理論與實現

前言

最近發現有挺多人喜歡徑向基函數(Radial Basis Function,RBF)神經網絡,其實它就是將RBF作爲神經網絡層間的一種連接方式而已。這裏做一個簡單的描述和找了個代碼解讀。
之前也寫過一篇,不過排版不好看,可以戳這裏跳轉

國際慣例,參考博客:

理論

基本思想

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 ( ∥ d i s t ∥ ) = e − ∥ d i s t ∥ R(\parallel dist \parallel) = e^{-\parallel dist \parallel} R(dist)=edist
下圖是以高斯核爲徑向基函數的神經元模型:

在這裏插入圖片描述

對應到激活函數表達式:
R ( x p − c i ) = exp ⁡ ( − 1 2 σ 2 ∥ x p − c i ∥ 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 σ是高斯函數的方差,可以用來調整影響半徑(仔細想想高斯函數中 c c c σ \sigma σ調整後對函數圖的影響);當權值和輸入向量的距離越小,網絡的輸出不斷遞增,輸入向量越靠近徑向基函數的中心,隱層節點產生的輸出越大。也就是說徑向基函數對輸入信號在局部產生響應,輸入向量與權值距離越遠,隱層輸出越接近0,再經過一層線性變換映射到最終輸出層,導致輸出層也接近0。

結構

RBF是具有單隱層的三層前向網絡。

在這裏插入圖片描述

  • 第一層爲輸入層,由信號源節點組成。

  • 第二層爲隱藏層,隱藏層節點數視所描述問題的需要而定,隱藏層中神經元的變換函數即徑向基函數是對中心點徑向對稱且衰減的非負線性函數,該函數是局部響應函數,具體的局部響應體現在其可見層到隱藏層的變換是通過徑向基函數計算,跟其它的網絡不同。以前的前向網絡變換函數都是全局響應的函數。

  • 第三層爲輸出層,是對輸入模式做出的響應。

輸入層僅僅起到傳輸信號作用,輸入層和隱含層之間可以看做連接權值爲1的連接,輸出層與隱含層所完成的任務是不同的,因而他們的學習策略也不同。輸出層是對線性權進行調整,採用的是線性優化策略,因而學習速度較快;而隱含層是對激活函數(格林函數,高斯函數,一般取後者)的參數進行調整,採用的是非線性優化策略,因而學習速度較慢。

參數

徑向基函數需要兩組參數:

  • 基函數中心
  • 方差(寬度)

隱層到輸出層只需要一組參數:

  • 權值

優點

  • 逼近能力,分類能力和學習速度等方面都優於BP神經網絡
  • 結構簡單、訓練簡潔、學習收斂速度快、能夠逼近任意非線性函數
  • 克服局部極小值問題。原因在於其參數初始化具有一定的方法,並非隨機初始化。

缺點

  • 如果中心點是樣本中的數據,就並不能反映出真實樣本的狀況,那麼輸入到隱層的映射就是不準確的
  • 如果使用有監督學習,函數中心是學習到的,但是如果中心點選取不當,就會導致不收斂。

各層的計算

首先初始化參數:中心、寬度、權值

不同隱含層神經元的中心應有不同的取值,並且與中心的對應寬度能夠調節,使得不同的輸入信息特徵能被不同的隱含層神經元最大的反映出來,在實際應用時,一個輸入信息總是包含在一定的取值範圍內。

中心

  • 方法1

    《模式識別與智能計算》中介紹了一種方法:將隱含層各神經元的中心分量的初值,按從小到大等間距變化,使較弱的輸入信息在較小的中心附近產生較強的響應。間距的大小可由隱藏層神經元的個數來調節。好處是能夠通過試湊的方法找到較爲合理的隱含層神經元數,並使中心的初始化儘量合理,不同的輸入特徵更爲明顯地在不同的中心處反映出來,體現高斯核的特點:
    c j i = min ⁡ i + max ⁡ i − min ⁡ i 2 p + ( j − 1 ) max ⁡ i − min ⁡ i p c_{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 i maxi是訓練集中第i個特徵所有輸入信息的最小值,$\max i $爲訓練集中第i個特徵所有輸入信息的最大值。

  • 方法2
    《43案例分析》中介紹的是Kmean使用方法,就是傳統的算法,先隨機選k個樣本作爲中心,然後按照歐氏距離對每個樣本分組,再重新確定聚類中心,再不斷重複上面的步驟,直到最終聚類中心變化在一定範圍內。

寬度

寬度向量影響着神經元對輸入信息的作用範圍:寬度越小,相應隱含層神經元作用函數的形狀越窄,那麼處於其他神經元中心附近的信息在該神經元出的響應就越小;就跟高斯函數圖像兩邊的上升下降區域的寬度一樣。按照《模式識別與智能計算》,計算有點像標準差的計算(但是此處原文沒有帶平方,不過我覺得應該帶上,詳細可以查閱這個YouTube視頻,不帶平方,萬一出現負數是無法求根的):
d j i = d f 1 N ∑ k = 1 N ( x i k − c j i ) 2 d_{ji}= d_f\sqrt{\frac{1}{N}\sum_{k=1}^N(x_i^k-c_{ji})^2} dji=dfN1k=1N(xikcji)2
當然也可以用《43案例分析》裏面說的,利用中心之間的最大距離 c m a x c_{max} cmax去計算,其中h是聚類中心個數:
d = c m a x 2 h d = \frac{c_{max}}{\sqrt{2h}} d=2h cmax


輸入層到隱層的計算

直接套入到選擇的徑向基函數中:
z j = exp ⁡ ( − ∣ ∣ X − C j D j ∣ ∣ 2 ) z_j = \exp\left(- \left|\left|\frac{X-C_j}{D_j} \right|\right|^2\right) zj=exp(DjXCj2)
其中 C j C_j Cj就是第j個隱層神經元對應的中心向量,由隱層第j個神經元所連接的輸入層所有神經元的中心分量構成,即 C j = [ C j 1 , C j 2 , ⋯   , C j n ] C_j = [C_{j1},C_{j2},\cdots,C_{jn}] Cj=[Cj1,Cj2,,Cjn] D j D_j Dj爲隱層第j個神經元的寬度向量,與 C j C_j Cj對應, D j D_j Dj越大,隱層對輸入向量的影響範圍就越大,而且神經元間的平滑程度就更好。

隱層到輸出層的計算

就是傳統的神經網絡裏面,把核函數去掉,變成了線性映射關係:
y k = ∑ j = 1 p w k j z j y_k = \sum_{j=1}^p w_{kj}z_j yk=j=1pwkjzj
其中k是輸出層神經元個數。

權重迭代

直接使用梯度下降法訓練,中心、寬度、權重都通過學習來自適應調節更新。
在這裏插入圖片描述

其中 η \eta η爲學習率, E E E爲損失函數,一般就是均方差。

訓練步驟

  • 先初始化中心、寬度、最後一層權重
  • 計算損失,如果在接受範圍內,停止訓練
  • 利用梯度更新的方法更新中心、寬度、權重
  • 返回第二步

代碼實現

有大佬利用keras實現過基於Kmeans的高斯RBF神經網絡層,代碼戳這裏

首先利用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))

但是此處我覺得有問題,這裏的寬度向量好像沒有體現出來,所以我重寫了一個:

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/D
     return K.exp(-self.betas * K.sum(H**2, axis=1))

可以看原作者的代碼,作者是用於二維數據的擬合;

也可以看我的代碼,基於原作者代碼,做的二維數據分類

在這裏插入圖片描述
小點爲訓練集,大圓點爲測試集

後記

RBF可以用於插值、分類;在論文《Phase-Functioned Neural Networks for Character Control》還用來更改地形,也就是說圖形、圖像通用,說明還是蠻重要的。這裏主要介紹了一下理論,後續再去做擴展性研究。

完整的python腳本實現放在微信公衆號的簡介中描述的github中,有興趣可以去找找,同時文章也同步到微信公衆號中,有疑問或者興趣歡迎公衆號私信。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章