感知器的定義
下面是一個(gè)感知器:

Paste_Image.png
可以看到,一個(gè)感知器有如下組成部分:
- 輸入權(quán)值 一個(gè)感知器可以接收多個(gè)輸入,每個(gè)輸入上有一個(gè)權(quán)值,此外還有一個(gè)偏置項(xiàng),就是上圖中的。
- 激活函數(shù) 感知器的激活函數(shù)可以有很多選擇,比如我們可以選擇下面這個(gè)階躍函數(shù)來作為激活函數(shù):

Paste_Image.png
- 輸出 感知器的輸出由下面這個(gè)公式來計(jì)算

Paste_Image.png
事實(shí)上,感知器不僅僅能實(shí)現(xiàn)簡(jiǎn)單的布爾運(yùn)算。它可以擬合任何的線性函數(shù),任何線性分類或線性回歸問題都可以用感知器來解決。
感知器訓(xùn)練法則
A)初始化權(quán)向量w=(w0,w1,…,wn),將權(quán)向量的每個(gè)值賦一個(gè)隨機(jī)值。
B)對(duì)于每個(gè)訓(xùn)練樣例,首先計(jì)算其預(yù)測(cè)輸出:

Paste_Image.png
C)當(dāng)預(yù)測(cè)值不等于真實(shí)值時(shí)則利用如下公式修改權(quán)向量:

各符號(hào)含義:

D)重復(fù)B)和C),直到訓(xùn)練集中沒有被錯(cuò)分的樣例。
算法分析:
若某個(gè)樣例被錯(cuò)分了,假如目標(biāo)輸出t為-1,結(jié)果感知器o輸出為1,此時(shí)為了讓感知器輸出-1,需要將wx減小以輸出-1,而在x的值不變的情況下只能減小w的值,這時(shí)通過在原來w后面添加(t-o)x=即可減小w的值(t-o<0, x>0)。
通過逐步調(diào)整w的值,最終感知器將會(huì)收斂到能夠?qū)⑺杏?xùn)練集正確分類的程度,但前提條件是訓(xùn)練集線性可分。若訓(xùn)練集線性不可分,則上述過程不會(huì)收斂,將無限循環(huán)下去。
感知器的代碼實(shí)現(xiàn)
class Perception(object):
def _int_(self,input_num,activator):
'''
初始化感知器
'''
self.activator = activator;
#權(quán)重向量初始化為0
self.weights = [0.0 for _ in range(input_num]
#偏置項(xiàng)初始化為0
self.bias = 0.0
def _str_(self):
#打印學(xué)習(xí)到的權(quán)重、偏置項(xiàng)
return 'weight\t:%s\nbias\t:%f\n' %(self.weight,self.bias)
def prefict(self,input_vec):
#輸入向量,輸出感知器計(jì)算結(jié)果
# 把input_vec[x1,x2,x3...]和weights[w1,w2,w3,...]打包在一起
# 變成[(x1,w1),(x2,w2),(x3,w3),...]
# 然后利用map函數(shù)計(jì)算[x1*w1, x2*w2, x3*w3]
# 最后利用reduce求和
return self.activator(
reduce(lambda: a,b:a+b,map(lambda x,w:x*w,zip(input_vec,self.weights)),0.0)+self.bias)
# 這里reduce中的0.0就是reduce計(jì)算結(jié)果的初始值,其他是在0基礎(chǔ)上累加的
def train(self,input_vec,labels,interation,rate):
#輸入訓(xùn)練數(shù)據(jù):一組向量,與每個(gè)向量對(duì)應(yīng)的label,以及訓(xùn)練輪數(shù)
for i in range(iteration):
self._one_interation(input_vec,labels,rate)
def _one_interation(self,input_vec,labels,rate):
#一次迭代把所有訓(xùn)練數(shù)據(jù)過一遍
# 把輸入和輸出打包在一起,成為樣本的列表[(input_vec, label), ...]
# 而每個(gè)訓(xùn)練樣本是(input_vec, label)
samples = zip(input_vec,labels)
#對(duì)每個(gè)樣本按照感知器規(guī)則更新權(quán)重
for (input_vec,label) in samles:
#計(jì)算感知器當(dāng)前權(quán)重下的輸出
out = self.predict(input_vec)
#更新權(quán)重
self._update_weights(input_vec,output,label,rate)
def _update_wights(self,input_vec,output,label,rate):
#按照感知器規(guī)則更新權(quán)重
# 把input_vec[x1,x2,x3,...]和weights[w1,w2,w3,...]打包在一起
# 變成[(x1,w1),(x2,w2),(x3,w3),...]
# 然后利用感知器規(guī)則更新權(quán)重
delta = label - output
self.wights = map(
lambda:(x,w):w+rate*delta*x,
zip(input_vec,self.weights))
#更新bias
self.bias+=rate*delta