感知器
為了理解神經(jīng)網(wǎng)絡(luò)瘤运,我們應(yīng)該先理解神經(jīng)網(wǎng)絡(luò)的組成單元——神經(jīng)元翰撑。神經(jīng)元也叫做感知器罩旋。感知器算法在上個(gè)世紀(jì)50-70年代很流行,也成功解決了很多問題眶诈。并且涨醋,感知器算法也是非常簡單的。
感知器的定義
下圖是一個(gè)感知器:
一個(gè)感知器有如下組成部分:
輸入權(quán)值 一個(gè)感知器可以接收多個(gè)輸入逝撬,每個(gè)輸入上都有一個(gè)權(quán)值w浴骂,此外還有一個(gè)偏置項(xiàng)b
-
激活函數(shù) 感知器的激活函數(shù)可以有很多選擇,比如我們可以選擇下面這個(gè)階躍函數(shù)f來作為激活函數(shù):
輸出 感知器的輸出由下面這個(gè)公式來計(jì)算
我們用一個(gè)簡單的例子來幫助理解
例子:用感知器實(shí)現(xiàn)and函數(shù)
我們設(shè)計(jì)一個(gè)感知器宪潮,讓它來實(shí)現(xiàn)and運(yùn)算溯警。程序員都知道,and是一個(gè)二元函數(shù)(帶有兩個(gè)參數(shù)X1和X2)狡相,下面是它的真值表:
我們令梯轻,而激活函數(shù)就是前面寫出來的階躍函數(shù),這時(shí)谣光,感知器就相當(dāng)于and函數(shù)檩淋。不明白芬为?我們驗(yàn)算一下:
輸入上面真值表的第一行萄金,即,那么根據(jù)公式(1)媚朦,計(jì)算輸出:
例子:用感知器實(shí)現(xiàn)or函數(shù)
同樣氧敢,我們可以用感知器來實(shí)現(xiàn)or運(yùn)算。僅僅需要把偏置項(xiàng)b的值設(shè)置為-0.3就可以了询张。我們驗(yàn)算一下孙乖,下面是or運(yùn)算的真值表:
感知器還能做什么
事實(shí)上,感知器不僅僅能實(shí)現(xiàn)簡單的布爾運(yùn)算。它可以擬合任何的線性函數(shù)唯袄,任何線性分類或線性回歸問題都可以用感知器來解決弯屈。前面的布爾運(yùn)算可以看作是二分類問題,即給定一個(gè)輸入恋拷,輸出0(屬于分類0)或1(屬于分類1)资厉。如下面所示,and運(yùn)算是一個(gè)線性分類問題蔬顾,即可以用一條直線把分類0(false宴偿,紅叉表示)和分類1(true,綠點(diǎn)表示)分開诀豁。
感知器的訓(xùn)練
現(xiàn)在窄刘,你可能困惑前面的權(quán)重項(xiàng)和偏置項(xiàng)的值是如何獲得的呢?這就要用到感知器訓(xùn)練算法:將權(quán)重項(xiàng)和偏置項(xiàng)初始化為0舷胜,然后娩践,利用下面的感知器規(guī)則迭代的修改和,直到訓(xùn)練完成逞带。
編程實(shí)戰(zhàn):實(shí)現(xiàn)感知器
完整代碼
對于程序員來說欺矫,沒有什么比親自動(dòng)手實(shí)現(xiàn)學(xué)得更快了,而且展氓,很多時(shí)候一行代碼抵得上千言萬語穆趴。接下來我們就將實(shí)現(xiàn)一個(gè)感知器。
下面是一些說明:
- 使用python語言遇汞。python在機(jī)器學(xué)習(xí)領(lǐng)域用的很廣泛未妹,而且,寫python程序真的很輕松空入。
- 面向?qū)ο缶幊搪缢C嫦驅(qū)ο笫翘貏e好的管理復(fù)雜度的工具,應(yīng)對復(fù)雜問題時(shí)歪赢,用面向?qū)ο笤O(shè)計(jì)方法很容易將復(fù)雜問題拆解為多個(gè)簡單問題化戳,從而解救我們的大腦。
- 沒有使用numpy埋凯。numpy實(shí)現(xiàn)了很多基礎(chǔ)算法点楼,對于實(shí)現(xiàn)機(jī)器學(xué)習(xí)算法來說是個(gè)必備的工具。但為了降低讀者理解的難度白对,下面的代碼只用到了基本的python(省去您去學(xué)習(xí)numpy的時(shí)間)掠廓。
下面是感知器類的實(shí)現(xiàn),非常簡單甩恼。去掉注釋只有27行蟀瞧,而且還包括為了美觀(每行不超過60個(gè)字符)而增加的很多換行沉颂。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 19-2-14 下午4:13
# @Author : Gavin
# @Site :
# @File : perceptron.py
# @Software: PyCharm
from functools import reduce
import tqdm
class Perception(object):
def __init__(self,input_num,activator):
"""
:param input_num:輸入?yún)?shù)的個(gè)數(shù)
:param activator:激活函數(shù)
"""
self.activator = activator
##權(quán)重向量初始化為0
self.weight = [0.0 for _ in range(input_num)]
##偏置項(xiàng)初始化為0
self.bias = 0.0
def __str__(self):
"""
打印學(xué)習(xí)到的權(quán)重、偏置項(xiàng)
:return:
"""
return 'weights :{} bias :{}'.format(self.weight,self.bias)
def prdict(self,input_vec):
"""
把input_vec[x1,x2,x3...]和weights[w1,w2,w3,....]打包在一起
變?yōu)閇(x1,w1),(x2,w2),....],然后利用map函數(shù)計(jì)算[x1*w1,x2*w2,.....],
最后利用reduce求和
:param input_vec:
:return:
"""
xw = zip(input_vec,self.weight)
xw_map = map(lambda x:x[0]*x[1],xw)
xw_map_sum = reduce(lambda x,y:x+y,xw_map,0.0)
return self.activator(xw_map_sum +self.bias)
def train(self,input_vecs,labels,iteration,rate):
"""
輸入訓(xùn)練數(shù)據(jù):一組向量悦污、與每個(gè)向量對應(yīng)的label;以及訓(xùn)練輪數(shù)铸屉、學(xué)習(xí)率
:param input_vecs: 一組向量
:param labels: 每個(gè)向量對應(yīng)的label
:param iteration: 訓(xùn)練輪數(shù)
:param rate: 學(xué)習(xí)率
:return:
"""
for i in (range(iteration)):
self._one_interation(input_vecs,labels,rate)
def _one_interation(self,input_vecs,labels,rate):
"""
一次迭代,把所有的訓(xùn)練數(shù)據(jù)過一遍
:param input_vecs:
:param labels:
:param rate:
:return:
"""
# 把輸入和輸出打包在一起切端,成為樣本的列表[(input_vec,label),...]
# 而每個(gè)訓(xùn)練樣本是(input_vec,label)
samples = zip(input_vecs, labels)
for (input_vec,label) in samples:
#計(jì)算感知器在當(dāng)前權(quán)重下的輸出
output = self.prdict(input_vec)
#更新權(quán)重
self._update_weights(input_vec,output,label,rate)
def _update_weights(self,input_vec,output,label,rate):
"""
按照感知器規(guī)則更新權(quán)重
:param input_vec:
:param output:
:param label:
:param rate:
:return:
"""
#把input_vec[x1,x2,x3,...]和weights[w1,w2,w3,....]打包在一起抬探,變?yōu)閇(x1,w1),(x2,w2),(x3,w3),....]
xw = zip(input_vec, self.weight)
#利用感知器規(guī)則更新權(quán)重
delta = label - output
self.weight=list(map(lambda x:x[1] + rate * delta * x[0],xw))
#更新bias
self.bias += rate * delta
def fun(x):
if x >0:
a = 1
else:
a = 0
return a
# per = Perception(input_num=3,activator=fun)
# print(per.prdict(input_vec=[0,0]))
#
# print(per)
###################and函數(shù)實(shí)現(xiàn)
def get_training_dataset():
input_vecs = [[1,1], [0,0], [1,0], [0,1]]
# 期望的輸出列表,注意要與輸入一一對應(yīng)
# [1,1] -> 1, [0,0] -> 0, [1,0] -> 0, [0,1] -> 0
labels = [1,0,0,0]
return input_vecs,labels
def train_and_perception():
p = Perception(2,fun)
input_vecs,labels = get_training_dataset()
p.train(input_vecs,labels,10,0.1)
return p
##################or函數(shù)實(shí)現(xiàn)
def get_training_or_dataset():
input_vecs = [[1, 1], [0, 0], [1, 0], [0, 1]]
# 期望的輸出列表帆赢,注意要與輸入一一對應(yīng)
# [1,1] -> 1, [0,0] -> 0, [1,0] -> 1, [0,1] -> 1
labels = [1, 0, 1, 1]
return input_vecs,labels
def train_or_perception():
p = Perception(2,fun)
input_vecs,labels = get_training_or_dataset()
p.train(input_vecs,labels,10,0.1)
return p
if __name__ == '__main__':
###################訓(xùn)練小压、測試and函數(shù)
and_perception = train_and_perception()
##打印訓(xùn)練獲得的權(quán)重
print(and_perception)
##測試
print('1 and 1 ={}'.format(and_perception.prdict([1,1])))
print('1 and 0 ={}'.format(and_perception.prdict([1,0])))
print('0 and 1 ={}'.format(and_perception.prdict([0,1])))
####################訓(xùn)練、測試or函數(shù)
or_perception = train_or_perception()
##打印訓(xùn)練獲得的權(quán)重
print(or_perception)
##測試
print('1 and 1 ={}'.format(or_perception.prdict([1, 1])))
print('1 and 0 ={}'.format(or_perception.prdict([1, 0])))
print('0 and 0 ={}'.format(or_perception.prdict([0, 0])))