感知機(jī)(Perceptron)
一種簡(jiǎn)單的感知機(jī)結(jié)構(gòu)如下圖所示菜谣,由三個(gè)輸入節(jié)點(diǎn)和一個(gè)輸出節(jié)點(diǎn)構(gòu)成惭缰,三個(gè)輸入節(jié)點(diǎn)x1浪南,x2,x3分別代表一個(gè)輸入樣本x的三個(gè)特征值漱受;w1络凿,w2,w3分別代表三個(gè)特征值對(duì)應(yīng)的權(quán)重昂羡;b為偏置項(xiàng)絮记;輸出節(jié)點(diǎn)中的z和o分別代表線性變換后的輸出值和非線性變換后的輸出值。
其中映射函數(shù)為激活函數(shù)虐先,下面列幾個(gè)常見(jiàn)的激活函數(shù):
函數(shù)名 | 函數(shù)表達(dá)式 | 導(dǎo)數(shù) |
---|---|---|
經(jīng)常用其構(gòu)成的 損失函數(shù)的導(dǎo)數(shù): |
神經(jīng)網(wǎng)絡(luò)(Neural Network)
神經(jīng)網(wǎng)絡(luò)基本結(jié)構(gòu)
神經(jīng)網(wǎng)絡(luò)與感知機(jī)類(lèi)似怨愤,但是它的節(jié)點(diǎn)更加復(fù)雜,下圖是一個(gè)含有1層隱藏層的神經(jīng)網(wǎng)絡(luò)蛹批,也是一種最簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)撰洗,我們可以看到這個(gè)神經(jīng)網(wǎng)絡(luò)的輸入層有2個(gè)節(jié)點(diǎn),隱藏層有3個(gè)節(jié)點(diǎn)腐芍,輸出層有1個(gè)節(jié)點(diǎn)差导。我們可以認(rèn)為神經(jīng)網(wǎng)絡(luò)由多個(gè)感知機(jī)構(gòu)成。我們以下圖所示結(jié)構(gòu)為例猪勇,實(shí)現(xiàn)一個(gè)可以進(jìn)行數(shù)據(jù)分類(lèi)的神經(jīng)網(wǎng)絡(luò)设褐。
假設(shè)我們有N個(gè)樣本,對(duì)于每一個(gè)樣本來(lái)說(shuō)泣刹,都有兩個(gè)特征值助析,對(duì)于這樣的每一個(gè)樣本都滿足公式2,公式中帶小括號(hào)的上標(biāo)代表神經(jīng)網(wǎng)絡(luò)的層數(shù)椅您,
為相鄰兩層兩個(gè)節(jié)點(diǎn)之間的權(quán)重系數(shù)外冀,其中的
代表前一層的第
個(gè)節(jié)點(diǎn),
代表后一層的第
個(gè)節(jié)點(diǎn)襟沮。
我們可以用矩陣形式改寫(xiě)公式2:
公式2中為輸入矩陣,
為隱藏層偏置矩陣,
為輸入層到隱藏層的權(quán)重矩陣开伏,
為隱藏層到輸出層的權(quán)重矩陣膀跌,
為輸出層偏置矩陣,
為輸出矩陣(結(jié)果預(yù)測(cè)矩陣)固灵,
捅伤,
矩陣維度為
,
矩陣維度為
巫玻。
神經(jīng)網(wǎng)絡(luò)損失函數(shù)
我們這里用改寫(xiě)的方差公式作為神經(jīng)網(wǎng)絡(luò)預(yù)測(cè)分類(lèi)結(jié)果的損失函數(shù)丛忆,正確的分類(lèi)結(jié)果矩陣記為:
根據(jù)梯度下降法,我們需要求損失函數(shù)的梯度仍秤,梯度下降法的實(shí)現(xiàn)可以看這里熄诡。損失函數(shù)可以表示為
的形式(類(lèi)似地,
诗力,
)凰浮,由于
是我們需要訓(xùn)練的參數(shù),所以我們需要分別求
對(duì)
的梯度(這里涉及到矩陣的求導(dǎo)苇本,見(jiàn)附錄)袜茧。
根據(jù)梯度下降法,我們?cè)谇笸晏荻纫院蟀暾枰挛覀兊膮?shù)值笛厦,這里以為例:
由公式6可以看出,的梯度矩陣應(yīng)該與
維度相同俺夕,即
與
維度相同裳凸,因此
應(yīng)該為1。所以我們?cè)诰幊虝r(shí)應(yīng)該一個(gè)樣本一個(gè)樣本的訓(xùn)練啥么,而不是
個(gè)樣本一起訓(xùn)練登舞。當(dāng)
時(shí),公式5可以簡(jiǎn)化為:
按照上述思路進(jìn)行編程悬荣,這里隱藏層激活函數(shù)選擇sigmoid函數(shù)菠秒,輸出層激活函數(shù)選擇tanh函數(shù),得到分類(lèi)結(jié)果的錯(cuò)誤率為0.01~0.06氯迂,當(dāng)隱藏層和輸出層激活函數(shù)都選擇tanh函數(shù)時(shí)践叠,錯(cuò)誤率更低。下圖為錯(cuò)誤率為0.025時(shí)的分類(lèi)結(jié)果圖嚼蚀。我們可以看到圖中有5個(gè)數(shù)據(jù)點(diǎn)分類(lèi)錯(cuò)誤禁灼。
局限性
由于我們是一個(gè)樣本一個(gè)樣本訓(xùn)練的,所以我們得到的參數(shù)也是和這些樣本一一對(duì)應(yīng)的轿曙,因此這個(gè)模型無(wú)法畫(huà)出決策邊界弄捕,也無(wú)法預(yù)測(cè)新的數(shù)據(jù)僻孝,預(yù)測(cè)新的數(shù)據(jù)好像是應(yīng)該對(duì)訓(xùn)練好的參數(shù)進(jìn)行插值,但是我看別人沒(méi)有那么做的守谓,可能這樣不大好穿铆。
附錄
神經(jīng)網(wǎng)絡(luò)代碼
# -*- encoding=utf-8 -*-
__Author__ = "stubborn vegeta"
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from matplotlib.colors import ListedColormap
class neuralNetwork(object):
def __init__(self, X, Y, inputLayer, outputLayer, hiddenLayer=3,learningRate=0.01, epochs=10):
"""
learningRate:學(xué)習(xí)率
epochs:訓(xùn)練次數(shù)
inputLayer:輸入層節(jié)點(diǎn)數(shù)
hiddenLayer:隱藏層節(jié)點(diǎn)數(shù)
outputLayer:輸出層節(jié)點(diǎn)數(shù)
"""
self.learningRate = learningRate
self.epochs = epochs
self.inputLayer = inputLayer
self.hiddenLayer = hiddenLayer
self.outputLayer = outputLayer
self.X = X
self.Y = Y
self.lenX,_ = np.shape(self.X)
s=np.random.seed(0)
# W1:輸入層與隱藏層之間的權(quán)重;W2:隱藏層與輸出層之間的權(quán)重斋荞;B1:隱藏層各節(jié)點(diǎn)的偏置項(xiàng)荞雏;B2:輸出層各節(jié)點(diǎn)的偏置項(xiàng)
self.W1 = np.array(np.random.random([self.inputLayer, self.hiddenLayer])*0.5) #2*3
self.B1 = np.array(np.random.random([self.lenX,self.hiddenLayer])*0.5) #200*3
self.W2 = np.array(np.random.random([self.hiddenLayer, self.outputLayer])*0.5) #3*1
self.B2 = np.array(np.random.random([self.lenX,self.outputLayer])*0.5) #200*1
def activationFunction(self, funcName:str, X):
"""
激活函數(shù)
sigmoid: 1/1+e^(-z)
tanh: [e^z-e^(-z)]/[e^z+e^(-z)]
softmax: e^zi/sum(e^j)
"""
switch = {
"sigmoid": 1/(1+np.exp(-X)),
"tanh": np.tanh(X),
# "softmax": np.exp(X-np.max(X))/np.sum(np.exp(X-np.max(X)), axis=0)
}
return switch[funcName]
def activationFunctionGrad(self, funcName:str, X):
"""
激活函數(shù)的導(dǎo)數(shù)
"""
switch = {
"sigmoid": np.exp(-X)/(1+np.exp(-X))**2,
"tanh": 1-(np.tanh(X)**2),
# "softmax": np.exp(X-np.max(X))/np.sum(np.exp(X-np.max(X)), axis=0)
}
return switch[funcName]
def train(self, funcNameH:str, funcNameO:str):
"""
funcNameH: 隱藏層激活函數(shù)
funcNameO: 輸出層激活函數(shù)
"""
for i in range(0,self.epochs):
j = np.random.randint(self.lenX)
x = np.array([self.X[j]])
y = np.array([self.Y[j]])
b1 = np.array([self.B1[j]])
b2 = np.array([self.B2[j]])
# 前向傳播
zHidden = x.dot(self.W1)+b1
z1 = self.activationFunction(funcNameH, zHidden) #1*3
zOutput = z1.dot(self.W2)+b2
z2 = self.activationFunction(funcNameO, zOutput) #1*1
# 反向傳播
dW2 = (z2-y)*(z1.T*self.activationFunctionGrad(funcNameO,zOutput))
db2 = (z2-y)*self.activationFunctionGrad(funcNameO,zOutput)
dW1 = (z2-y)*(self.activationFunctionGrad(funcNameO,zOutput)*self.W2.T)*(x.T.dot(self.activationFunctionGrad(funcNameH,zHidden)))
db1 = (z2-y)*(self.activationFunctionGrad(funcNameO,zOutput)*self.W2.T)*self.activationFunctionGrad(funcNameH,zHidden)
#更新參數(shù)
self.W2 -= self.learningRate*dW2
self.B2[j] -= self.learningRate*db2[0]
self.W1 -= self.learningRate*dW1
self.B1[j] -= self.learningRate*db1[0]
return 0
def predict(self, xNewData, funcNameH:str, funcNameO:str):
X = xNewData #200*2
N,_ = np.shape(X)
yPredict = []
for j in range(0,N):
x = np.array([X[j]])
b1 = np.array([self.B1[j]])
b2 = np.array([self.B2[j]])
# 前向傳播
zHidden = x.dot(self.W1)+b1
z1 = self.activationFunction(funcNameH, zHidden) #1*3
zOutput = z1.dot(self.W2)+b2
z2 = self.activationFunction(funcNameO, zOutput) #1*1
z2 = 1 if z2>0.5 else 0
yPredict.append(z2)
return yPredict,N
if __name__ == "__main__":
X,Y = datasets.make_moons(200, noise=0.15)
neural_network = neuralNetwork (X=X, Y=Y, learningRate=0.2, epochs=1000, inputLayer=2, hiddenLayer=3, outputLayer=1)
funcNameH = "sigmoid"
funcNameO = "tanh"
neural_network.train(funcNameH=funcNameH,funcNameO=funcNameO)
yPredict,N = neural_network.predict(xNewData=X,funcNameH=funcNameH,funcNameO=funcNameO)
print("錯(cuò)誤率:", sum((Y-yPredict)**2)/N)
colormap = ListedColormap(['royalblue','forestgreen']) # 用colormap中的顏色表示分類(lèi)結(jié)果
plt.subplot(1,2,1)
plt.scatter(X[:,0],X[:,1],s=40, c=Y, cmap=colormap)
plt.xlabel("x")
plt.ylabel("y")
plt.title("Standard data")
plt.subplot(1,2,2)
plt.scatter(X[:,0],X[:,1],s=40, c=yPredict, cmap=colormap)
plt.xlabel("x")
plt.ylabel("y")
plt.title("Predicted data")
plt.show()
感知機(jī)結(jié)構(gòu)圖代碼
digraph network{
edge[fontname="Monaco"]
node[fontname="Monaco"]
rankdir=LR
b[shape=plaintext]
x1->"z|o"[label=w1]
x2->"z|o"[label=w2]
x3->"z|o"[label=w3]
b->"z|o"
{rank=same;b;"z|o"}
}
神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)圖代碼
digraph network{
edge[fontname="Monaco"]
node[fontname="Monaco",shape=circle]
rankdir=LR
subgraph cluster_1{
color = white
fontname="Monaco"
x1,x2;
label = "Input Layer";
}
subgraph cluster_2{
color = white
fontname="Monaco"
h3,h1,h2;
label = "Hidden Layer";
}
subgraph cluster_3{
// rank=same
color = white
fontname="Monaco"
o;
label = "Output Layer";
}
x1->h1
x1->h2
x1->h3
x2->h1
x2->h2
x2->h3
rank=same;h1;h2;h3
h1->o
h2->o
h3->o
}