1.神經(jīng)網(wǎng)絡(luò)前傳——感知機(jī)
感知機(jī)作為神經(jīng)網(wǎng)絡(luò)的起源蜜唾,由Frank Rosenblatt(美國)在1957 年提出患蹂。感知機(jī)的構(gòu)造與神經(jīng)網(wǎng)絡(luò)中的神經(jīng)元類似芝发,理解感知機(jī)的思想對后續(xù)了解神經(jīng)網(wǎng)絡(luò)有很重要的幫助。
感知機(jī)的邏輯形狀類似于生物的神經(jīng)系統(tǒng)坛掠,由神經(jīng)元與神經(jīng)元之間連接構(gòu)成。感知機(jī)的節(jié)點(diǎn)包含激活函數(shù)治筒,用來處理節(jié)點(diǎn)收到的信息(激活函數(shù)詳見附錄)屉栓,類似于神經(jīng)系統(tǒng)的神經(jīng)元;節(jié)點(diǎn)與節(jié)點(diǎn)之間由邊連接耸袜,邊包含權(quán)重等信息友多,類似于神經(jīng)系統(tǒng)中神經(jīng)細(xì)胞的突觸。具體類比如下圖:
每個節(jié)點(diǎn)接收到連接他的相鄰節(jié)點(diǎn)傳來的信息作為輸入堤框,在上圖中神經(jīng)元B接受來自于A1夷陋、A2的輸入x1、x2,在輸入信號分別乘以對應(yīng)邊上的權(quán)重后求和胰锌,如果總和超過某個閾值骗绕,則該神經(jīng)元被激活。這里將這個閾值用表示资昧。感知機(jī)的數(shù)學(xué)公式如下:
NOTE:
感知機(jī)的輸入都有各自的權(quán)重酬土,權(quán)重越大,意味著這個輸入對該神經(jīng)元的狀態(tài)影響越大格带。而后面的神經(jīng)網(wǎng)絡(luò)的學(xué)習(xí)撤缴,就是在不斷調(diào)優(yōu)尋求最佳權(quán)重的過程。
2.用感知機(jī)思想實(shí)現(xiàn)邏輯電路
我們來回顧一下離散數(shù)學(xué)叽唱。這里用感知機(jī)的思想去實(shí)現(xiàn)與門屈呕、或門、與非門棺亭、異或門是為了更切實(shí)的體驗感知機(jī)的思想虎眨,并形象地展現(xiàn)權(quán)重和偏置在神經(jīng)網(wǎng)絡(luò)中作用的作用,最后我們會引入激活函數(shù)的概念,并在下一章“神經(jīng)網(wǎng)絡(luò)”中進(jìn)行詳細(xì)介紹嗽桩。
2.1與門
與門真值表
x1 | x2 | y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
如果我們用代碼實(shí)現(xiàn)邏輯電路與門岳守、或門、與非門碌冶、異或門異常簡單湿痢。但此處我們引入權(quán)重與偏置等概念,使用感知機(jī)的思想實(shí)現(xiàn)與門扑庞、或門譬重、與非門、異或門罐氨。
我們給x1臀规、x2分別乘以各自邊上的權(quán)重再求和,最后加上偏置量等于輸出y岂昭。
與門代碼實(shí)現(xiàn):
import numpy as np
def AND(x1, x2):
x = np.array([x1, x2])
w = np.array([0.5, 0.5])
b = -0.7
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
2.2或門
或門真值表
x1 | x2 | y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
或門代碼實(shí)現(xiàn):
import numpy as np
def OR(x1, x2):
x = np.array([x1, x2])
w = np.array([0.5, 0.5])
b = -0.2
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
2.3與非門
與非門真值表
x1 | x2 | y |
---|---|---|
0 | 0 | 1 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
與非門代碼實(shí)現(xiàn):
import numpy as np
def NAND(x1, x2):
x = np.array([x1, x2])
w = np.array([-0.5, -0.5])
b = 0.7
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
2.3異或門
異或門真值表
x1 | x2 | y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
異或門是比較特殊的邏輯門以现,因為觀察異或門的真值表可以發(fā)現(xiàn),他的true值分布是非線性的约啊。在前面三個邏輯門中邑遏,如果以x1為橫軸,以x2為縱軸恰矩,true值和false值可以用一條直線來區(qū)分開來记盒,以或門為例:
分割true值與false值的線性函數(shù)為:
然而異或門的真值不是以上述這種方式分布,所以用單層感知機(jī)無法實(shí)現(xiàn)異或門外傅。我們在離散數(shù)學(xué)中都學(xué)到過異或門可以通過與門纪吮、或門以及非與門組合實(shí)現(xiàn),因此我們使用多層感知機(jī)來實(shí)現(xiàn)異或門萎胰。
與門代碼實(shí)現(xiàn):
def XOR(x1, x2):
s1 = NAND(x1, x2)
s2 = OR(x1, x2)
y = AND(s1, s2)
return y
此處多層感知機(jī)就是神經(jīng)網(wǎng)絡(luò)的雛形碾盟,每個神經(jīng)元的輸入都有各自不同的權(quán)重,每個神經(jīng)元都有自己的激活函數(shù)以及偏置量技竟。最終的輸出神經(jīng)元就是所要的結(jié)果冰肴。
2.神經(jīng)網(wǎng)絡(luò)
我們已經(jīng)了解了感知機(jī)的基本概念與結(jié)構(gòu),感知機(jī)既有優(yōu)點(diǎn)又有缺點(diǎn)榔组。優(yōu)點(diǎn)是感知機(jī)理解起來簡單容易熙尉,在遇到復(fù)雜問題上,感知機(jī)理論上是可以使用并解決問題的搓扯。但感知機(jī)最最致命的缺點(diǎn)就是所有的權(quán)重需要人工確認(rèn)检痰,例如我們實(shí)現(xiàn)邏輯門時,權(quán)重是由人為確定锨推。在處理簡單問題時铅歼,人工參與確認(rèn)權(quán)重可行公壤,一旦問題復(fù)雜,所用的感知機(jī)神經(jīng)元數(shù)量龐大谭贪,結(jié)構(gòu)復(fù)雜時境钟,人工確認(rèn)權(quán)重就變得困難锦担。因此我們進(jìn)一步探索神經(jīng)網(wǎng)絡(luò)俭识,神經(jīng)網(wǎng)絡(luò)提供了一套機(jī)器自己確定權(quán)重的方法(但并非所有參數(shù)都可以自己自動決定,神經(jīng)網(wǎng)絡(luò)中一些超參數(shù)依舊需要人工確定洞渔。超參數(shù)將會在后續(xù)分享中提及)
這一節(jié)將大致介紹神經(jīng)網(wǎng)絡(luò)套媚。這里我們默認(rèn)神經(jīng)網(wǎng)絡(luò)的權(quán)重已經(jīng)獲取到合適的值。我們僅僅使用神經(jīng)網(wǎng)絡(luò)進(jìn)行分類磁椒。神經(jīng)網(wǎng)絡(luò)每個神經(jīng)元的權(quán)重學(xué)習(xí)將在下一節(jié)分享中詳述堤瘤。
2.1神經(jīng)網(wǎng)絡(luò)圖解
此處我們構(gòu)建一個三層神經(jīng)網(wǎng)絡(luò),用來說明神經(jīng)網(wǎng)絡(luò)的基本結(jié)構(gòu)浆熔。三層神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)如下圖:
神經(jīng)網(wǎng)絡(luò)說明:
層說明:上圖展示的神經(jīng)網(wǎng)絡(luò)為一個三層的神經(jīng)網(wǎng)絡(luò)(實(shí)際上有4層本辐,但是第一層是從0開始算起,因此稱為三層神經(jīng)網(wǎng)絡(luò))圖中由x1,x2組成的神經(jīng)網(wǎng)絡(luò)層是第0層医增,稱作輸入層慎皱,由y1,y2組成的神經(jīng)網(wǎng)絡(luò)層是第3層叶骨,稱作輸出層茫多。夾在中間兩層的是隱藏層。
參數(shù)說明:邊上的w為權(quán)重忽刽,b為每層的偏置量天揖。w是由參數(shù)組成的二維數(shù)組。b是由常數(shù)組成的數(shù)組跪帝,也就是說每一個神經(jīng)元接收到的偏置量可以不一樣今膊。
函數(shù)說明:h(x)為激活函數(shù),激活函數(shù)詳見 附錄 零食一:激活函數(shù)伞剑。
2.2神經(jīng)網(wǎng)絡(luò)的運(yùn)算
總體計算流程:輸入層的神經(jīng)元的輸入值乘以每條邊上的權(quán)重斑唬,然后傳遞給下一個神經(jīng)元,在下一個神經(jīng)元上將各個輸入以及偏置量b求和纸泄,總和為a赖钞。z = h(a),h()為激活函數(shù)聘裁。z作為本神經(jīng)元的輸出傳遞給下一個神經(jīng)元雪营。
- 輸入:輸入層是一系列輸入神經(jīng)元,我們可以將輸入作為一個一維數(shù)組來看待衡便。后續(xù)批處理的時候輸入是分批輸入献起,輸入可以抽象為二元數(shù)組洋访。
- 權(quán)重:權(quán)重可以抽象為二維數(shù)組,權(quán)重二維數(shù)組的第一維的形狀必須和輸入層(上一層的輸出)的第二維的形狀相同谴餐。
- 中間結(jié)果:中間結(jié)果是由上一層的輸入乘以權(quán)重加上偏置計算得出的姻政。可以抽象為一個一維數(shù)組(在批量處理中是二維數(shù)組)具體計算參見 附錄 零食二:矩陣乘法
- 輸出結(jié)果:輸出結(jié)果由一系列輸出層的神經(jīng)元組成岂嗓。根據(jù)不同目標(biāo)會有不同個數(shù)的神經(jīng)元汁展。例如我們在手寫數(shù)字分類的神經(jīng)網(wǎng)絡(luò)中,輸出元有10個厌殉,分別代表0~9的概率食绿。
2.3三層神經(jīng)網(wǎng)絡(luò)的代碼實(shí)現(xiàn)
此處我們將權(quán)重的學(xué)習(xí)跳過,將權(quán)重信息寫死在程序當(dāng)中公罕。權(quán)重的學(xué)習(xí)將放置在后續(xù)的分享當(dāng)中器紧。
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def identity_function(x):
return x
def init_network():
network = {}
network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
network['b1'] = np.array([0.1, 0.2, 0.3])
network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
network['b2'] = np.array([0.1, 0.2])
network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
network['b3'] = np.array([0.1, 0.2])
return network
def forward(network, x):
W1, W2, W3 = network['W1'], network['W2'], network['W3']
b1, b2, b3 = network['b1'], network['b2'], network['b3']
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
z2 = sigmoid(a2)
a3 = np.dot(z2, W3) + b3
y = identity_function(a3)
return y
network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
print(y)
2.4輸出層的設(shè)計
在上面的代碼實(shí)現(xiàn)中我們發(fā)現(xiàn)我們最后使用的identity_function是簡單的只返回輸入x,相當(dāng)于什么也沒做楼眷,這種函數(shù)叫做恒等函數(shù)铲汪。這一小節(jié)我們討論下輸出層的設(shè)計。
神經(jīng)網(wǎng)絡(luò)可以用在分類問題與回歸問題上罐柳,需要根據(jù)不同情況來使用不同的激活函數(shù)掌腰,一般而言,回歸問題用恒等函數(shù)硝清,分類問題用softmax函數(shù)辅斟。
2.4.1softmax函數(shù)
softmax函數(shù)的數(shù)學(xué)表示如下:
說明:假設(shè)輸出層有N個神經(jīng)元,在第k個神經(jīng)元輸出yk芦拿,因為分類問題需要的是每個分類的概率士飒,softmax是一個大于0小于1的分?jǐn)?shù),softmax輸出值的總和為1蔗崎,所以使用softmax作為輸出層的激活函數(shù)來處理分類問題酵幕。
2.4.2softmax函數(shù)的實(shí)現(xiàn)
import numpy as np
def softmax(x):
exp_x = np.exp(x)
sum_exp_x = np.sum(exp_x)
y = exp_x / sum_exp_x
return y
a = np.array([0.3, 2.9, 4.0])
print(softmax(a))
2.4.3softmax中的陷阱
我們來回憶一下的圖像,當(dāng)x趨于0時缓苛,y值趨于負(fù)無窮芳撒。這種情況下計算機(jī)會溢出。如果我們分類函數(shù)用如上的softmax作為輸出層的激活函數(shù)未桥,遇到一個概率判斷很小的分類笔刹,就爆炸了。冬耿。舌菜。那如何避免這個數(shù)學(xué)上的陷阱呢?解決方案非常粗暴簡單亦镶,給分子日月、分母加個不為0的常數(shù)袱瓮。改進(jìn)后的softmax的數(shù)學(xué)表示如下:
說明:分子、分母同時乘以一個不為零的常數(shù)爱咬,運(yùn)算結(jié)果不會改變尺借。經(jīng)過如上變換,只需要給輸出加上一個不為零的常數(shù)即可精拟。為了防止計算機(jī)溢出燎斩。我們減去輸出層的神經(jīng)元最大的輸出項作為C'
2.4.4改進(jìn)后的softmax代碼實(shí)現(xiàn)
import numpy as np
def softmax(x):
c = np.max(x)
exp_x = np.exp(x - c)
sum_exp_x = np.sum(exp_x)
y = exp_x / sum_exp_x
return y
a = np.array([0.3, 2.9, 4.0])
print(softmax(a))
附錄:
附錄附上一些在感知機(jī)中可能需要了解的數(shù)學(xué)知識。如果你的大學(xué)數(shù)學(xué)記憶猶新可以不看這部分附錄串前。如果你和我一樣大學(xué)數(shù)學(xué)全部還給老師的話瘫里,可以在此復(fù)習(xí)一下实蔽。別怕荡碾!所需要的高數(shù)知識非常簡單。
零食一:激活函數(shù)
將輸入信號(多于一個)進(jìn)行一番運(yùn)算轉(zhuǎn)換為輸出信號局装,這種函數(shù)統(tǒng)稱為激活函數(shù)坛吁。我們來看幾個常用激活函數(shù)的例子:
1.階躍函數(shù)
NOTE:
w:邊上的權(quán)重
b:偏置量
說明:
此神經(jīng)元接受兩個輸入信號,x1,x2,兩個輸入信號分別乘以兩條邊上的權(quán)重w1,w1求和再加上偏置量b作為最終階躍函數(shù)判斷的依據(jù)铐尚。如果和小于0則階躍函數(shù)輸出0拨脉,如果和大于0則階躍函數(shù)輸出1。由于最終輸出為0或1宣增,在平面直角坐標(biāo)系中的圖像像臺階一樣玫膀,因此稱之為階躍函數(shù)。
階躍函數(shù)的代碼實(shí)現(xiàn):
import numpy as np
import matplotlib.pylab as plt
def step_function(x):
return np.array(x > 0, dtype=np.int)
X = np.arange(-5.0, 5.0, 0.1)
Y = step_function(X)
plt.plot(X, Y)
plt.ylim(-0.1, 1.1)
plt.show()
階躍函數(shù)圖像:
2.SIGMOD函數(shù)
SIGMOD函數(shù)是神經(jīng)網(wǎng)絡(luò)中較為常用的一個激活函數(shù)爹脾,SIGMOD函數(shù)的數(shù)學(xué)表示如下:
NOTE:
w:邊上的權(quán)重
b:偏置量
相對于階躍函數(shù)帖旨,SIGMOD函數(shù)曲線更加平滑,而且范圍也是在(0,1)之間灵妨,SIGMOD函數(shù)在神經(jīng)網(wǎng)絡(luò)之中有很特殊的意義解阅。在某些場景下SIGMOD函數(shù)的輸出更符合需求,例如我們需要求各個輸出神經(jīng)元對應(yīng)的概率泌霍。在這種情況下货抄,我們需要的是一個0到1之間的實(shí)數(shù),而非0/1的二元輸出朱转。
SIGMOD函數(shù)的代碼實(shí)現(xiàn):
import numpy as np
import matplotlib.pylab as plt
def sigmoid(x):
return 1 / (1 + np.exp(-x))
X = np.arange(-5.0, 5.0, 0.1)
Y = sigmoid(X)
plt.plot(X, Y)
plt.ylim(-0.1, 1.1)
plt.show()
SIGMOD函數(shù)的圖像:
3.ReLU函數(shù)
在激活函數(shù)的發(fā)展史中SIGMOD函數(shù)很早就開始使用了蟹地。但是近期則主要使用ReLU函數(shù)。(Rectified Linear Unit)
ReLU函數(shù)的數(shù)學(xué)表示如下:
ReLU函數(shù)的代碼實(shí)現(xiàn):
import numpy as np
import matplotlib.pylab as plt
def relu(x):
return np.maximum(0, x)
x = np.arange(-5.0, 5.0, 0.1)
y = relu(x)
plt.plot(x, y)
plt.ylim(-1.0, 5.5)
plt.show()
ReLU函數(shù)的圖像:
零食二:矩陣乘法
理論說的再好不如例子一個藤为,我們舉個來說明矩陣乘法怎么算怪与。
我們定義二維矩陣A, B
A = {[2,4],[2,6],[5,6]}
矩陣A的形狀為3×2
B = {[1,2,3],[4,5,6]}
矩陣A的形狀為2×3
說明:矩陣的形狀被乘數(shù)為第一維元素的個數(shù),乘數(shù)為第二維元素的個數(shù)凉蜂。如果兩個二維矩陣相乘琼梆,必須保證第一個矩陣的第二維形狀與第二個矩陣第一維的形狀相等性誉。在上述例子中為2 = 2,如果不相等則矩陣不可乘茎杂。
矩陣A乘以B記做A·B错览,我們用矩陣S表示(S = A·B)。S的形狀為第一個矩陣的第一維的形狀×第二個矩陣的第二維的形狀煌往,即shape(S) = 3×3倾哺,具體運(yùn)算規(guī)則如下:
S[0][0] = A[0][0]×B[0][0] + A[0][1]×B[1][0] = 2×1 + 4×4 = 17
S[0][1] = A[0][0]×B[0][1] + A[0][1]×B[1][1] = 2×2 + 4×5 = 24
S[0][2] = A[0][0]×B[0][2] + A[0][1]×B[1][2] = 2×3 + 4×6 = 30
S[1][0] = A[1][0]×B[0][0] + A[1][1]×B[1][0] = 2×1 + 6×4 = 26
……
S[2][2] = A[2][0]×B[0][2] + A[2][1]×B[1][2] = 5×3 + 6×6 = 51
最終結(jié)果為:
S = {[17,24,30],[26,34,42],[29,40,51]}
Reference:
[1]齋藤康毅., 2016, Deep Learning from Scratch, Tokyo: O'Reilly Japan, Inc.
[2]耿素云.,1998, 離散數(shù)學(xué).第2分冊,集合論與圖論, 北京: 北京大學(xué)出版社.
[3]李響初., 2012, 數(shù)字電路基礎(chǔ)與應(yīng)用, 北京: 機(jī)械工業(yè)出版社.