機器學習(神經網絡)

一、感知機(單個神經元)

感知機是基本的處理元素。它具有輸入(其輸入可以來自外部輸入,也可以來自其他感知機)。與每個輸入xi 相關聯的

是一個鏈接權重(突觸權重)wi,而輸出y在最簡單的情況下是這些輸入的加權和(也可以是其他類型)

如上圖所示就是一個簡單的感知機。接收n個帶權重的信號,將總輸入值與閥值θ進行比較,通過激活函數f(*)產生輸出;

二、激活函數

傳統的激活函數是將輸入值映射到0到1上的輸出,如階躍函數、Sigmoid函數、tanh函數、ReLU函數:

階躍函數 sgn(x)

圖像不連續且不光滑,sgn(x)=1,x≥0 反之爲0

Sigmoid函數 sigmoid(x)

圖像光滑平坦,但在x趨於∞時導數爲0;

sigmoid(x)= 1 / ( 1+e^(-x) )

tanh函數 tanh(x)

值域在-1到1之間,圖像連續可導。

tanh(x)= [ e^x - e^(-x) ] / [ e^x + e^(-x) ]

ReLU函數 ReLU(x)

在小於0的部分導數值爲0,在大於0的部分導數值爲常數k;

ReLU(x) = max( 0,kx )

單層感知機網絡(包含輸入層和輸出層) 

只包含輸入和輸出兩層,用於解決線性可分問題。

訓練過程基本思想:(正向傳播,反向更新)

1)正向計算模型預測值a; 2)比較預測值a與真實值之間的差異(作差); 3)利用差值求解(更新)參數;

實戰—利用單層感知機實現(與  或  非問題)

import numpy as np            #導入numpy數據包
from matplotlib import pyplot as plt    #導pyplot
datasetX= np.array(
    [[0,0,1],[0,1,1],[1,0,1],[1,1,1]]
)                             #數據集X:前兩列爲x1和x2,最後一列爲b
datasetY=np.array([0,1,1,1])    #數據集Y
np.random.seed(1)
w=np.random.random((1,3))        #係數(參數)

def sigmoid(x):
    return 1/(1+np.exp(-x))    #sigmoid函數

rate = 0.02                    #學習率
step = 1000                    #學習步長
for i in range(step):
    sum=np.dot(w,datasetX.T)
    error=sigmoid(sum)-datasetY
    w=w-rate*np.dot(error,datasetX)

#繪製圖像
X=np.array([-0.2,0.55])
print(w)
plt.scatter(0,0,c='blue')        #以或問題爲例子
plt.scatter([0,1,1],[1,0,1],c='r')
plt.plot(X,-(w[0][0]*X+w[0][2])/w[0][1],c='black')
plt.show()

運行結果:

    或問題訓練圖像;(源碼以或問題爲例)

    與問題訓練圖像 (改數據集和繪製區間即可);

    非問題訓練圖像,結合三幅圖像與實際分類大體一致。

異或不同爲1相同爲0,可以結合或問題和與問題進行求解;

下面我們推到爲什麼可以通過此種方式求解參數:(結合下圖的變化過程)

X爲列向量(x1,x2,....,xn-1,1)^T ,Y爲輸出結果這裏爲單神經元故Y爲常數(0,1),W爲(1 X n)的矩陣;

Z=WX,A = f (Z) (這裏的 f就爲激活函數),這裏定義誤差函數爲 L( A,y )= - ylnA - (1-y)ln( 1-A );(越小越好)

要結合梯度下降算法我們需要求解 △w並根據 w=w-α△w實現對w的更新。已知誤差函數L我們可以求得其對A的偏導數

爲 - ( y/A )+( 1-y )/( 1 - A )【化簡整理的 ( A - y ) / ( 1 - A )A】,結合鏈式法則我們可以求得 △w=(A-y)*x

所以得出:wi = wi - α( A - y )xi;(注:這裏的α爲學習率,通常取值爲0.01,0.02,0.03等)

結合或問題的實例,X爲(3,4)矩陣,y爲(1,4)矩陣,W爲(1,3)矩陣(其導數與其維數相同)

W=W - α(A - y)X,這裏的X爲X的轉置(4,3)矩陣。

顯然只用一個神經元構造的網絡職能解決線性問題,對於非線性問題單層模型無法解決。

三、多層前饋神經網絡

多層前饋神經網絡,也稱爲多層感知機,包含輸入層(input layer)、隱含層(hidden layer)、輸出層(output layer)

位於隱含層和輸出層的神經元具有激活函數,通常輸入層僅接受輸入數據不具備處理功能。

多層神經網絡可以解決“非線性”問題,相比單個神經元處理特徵數據效果更好。

給定樣本數據集D={(x1,y1),(x2,y2),....,(xn,yn)},其中 xi 屬於 d 維空間,yi 屬於 l 維空間;

如上圖所示的兩層神經網絡有d個輸入,hidden層有q個結點,產生l個輸出,由輸入層到hidden層要確定的參數

個數爲 q x d個,由hidden層到輸出層要確定的參數個數爲 l x q個,故總共要求解的參數個數爲 (d + l)q個。

誤差反向傳播算法(BP算法):類似於梯度下降算法,是一種迭代算法,每一次迭代實現對模型參數的更新。

在這裏我們將樣本的誤差(error)定義爲:

兩層神經網絡中出現的符號及含義
X 輸入特徵值(輸入集合) xi 表示輸入層第i個結點對應的輸入
Y 輸出值,yi表示輸出層第i個結點對應的輸出
V

由輸入層到隱層(hidden layer)的參數矩陣

v【ih】表示輸入層 i 結點到隱層 h 結點之間的連接權

W

由隱層(hidden layer)到輸出層的參數矩陣

W【hj】表示隱層 h 結點到輸出層 j 結點之間的連接權

這裏的 i 屬於【1,d】 h 屬於【1,q】 j 屬於【1,l】,不大於對應層

的結點個數且取值都爲正整數

所謂的誤差反向傳播,就是從輸出層開始回退,逐層實現每一層之間的連接權值的更新,更新推導如下:

更新W中對應的參數w【hj】同感知機相同,只需求出△w【hj】即可,結合誤差函數

我們可以得到,下一步只需求解△Ek/△w【hj】,結合鏈式求導法則:

結合Sigmoid函數導數f(x)(1-f(x)),即上式子的中間部分可通過此替換,第三部分爲b【h】可得gj梯度項:

 由此我們可以完成W參數矩陣的更新,下面繼續反向傳播,以類似的方法更新V參數矩陣。

我們只需求解eh即可,這裏的 xi 爲上一層的輸入數據(學習率*梯度項*上一層輸入

誤差反向傳播算法(BP算法)僞代碼:

BP神經網絡的優點與缺點:

優點:實現了一個從輸入到輸出的映射功能,可實現任何複雜非線性映射,網絡能通過學習大量的正確實例

來逐步增強和完善自己。缺點:收斂速度較慢,所得到的結果未必是全局最優解;

實戰:BP神經網絡實現與或非問題:

import numpy as np#導入數據包
from matplotlib import pyplot as plt
from sklearn import datasets

def sigmoid(x):#sigmoid函數
    return 1.0/(1 + np.exp(-x))
def dsigmoid(Z):#sigmoid函數的導數
    return Z*(1-Z)

dataX=np.array([[0,0],[0,1],[1,0],[1,1]])
dataY=np.array([0,1,1,1]).reshape(4,1)#數據集X
learnrate=1                                    #學習率
studystep=2500                                   #最大迭代次數

#初始化網絡結構
inputlayer_size=dataX.shape[1]                  #輸入層結點個數
hiddenlayer_size=inputlayer_size+1              #隱含層結點個數
outputlayer_size=dataY.shape[1]                 #輸出層結點個數

np.random.seed(1)#在0到1之間初始化各矩陣的連接權
V=np.random.random((hiddenlayer_size,inputlayer_size))    #V矩陣的隨機初始化
W=np.random.random((outputlayer_size,hiddenlayer_size))  #W矩陣的隨機初始化

#2-神經網絡層次模型&訓練
for i in range(studystep):
    #正常傳遞求解模型估計參數
    hiddenvalue=sigmoid(np.dot(V,dataX.T))                 #隱藏層輸出值
    outputvalue=sigmoid(np.dot(W,hiddenvalue))             #模型預測值
    g=dsigmoid(outputvalue)*(outputvalue-dataY.T)
    e=dsigmoid(hiddenvalue)*(1-hiddenvalue)*np.dot(W.T,g)  #求解梯度
    W=W-learnrate*np.dot(g,hiddenvalue.T)                  #反向傳遞,最後更新
    V=V-learnrate*np.dot(e,dataX)                          #更新參數W和V

#模型結果預測
predict=sigmoid(np.dot(W,sigmoid(np.dot(V,dataX.T))))
print(predict.T)

這裏以或問題爲例,運行結果如下圖所示:(對於與、非以及異或問題只需修改對應的數據集即可)

總體來說效果還是可以的,當然這僅僅是實現了一個簡單神經網路,還有許多後序問題需要解決

比如在何處取得全局最優解,如何提高模型的速率,以及梯度消失(爆炸)的解決等;

針對全局最優解的求解現有的方法有:隨機梯度下降、模擬退火、遺傳以及蟻羣算法等;

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