用感知機(Perceptron)實現邏輯AND功能的Python3代碼


 

之所以寫這篇隨筆,是因為參考文章(見文尾)中的的代碼是Python2的,放到Python3上無法運行,我花了些時間debug,並記錄了調試經過。

參考文章中的代碼主要有兩處不兼容Python3,一個是lambda函數的使用,另一個是map()的使用。

  

先放我修改調試后的代碼和運行結果,再記錄調試經過。

源代碼:

  1 #coding=utf-8
  2 
  3 from functools import reduce  # for py3
  4 
  5 class Perceptron(object):
  6     def __init__(self, input_num, activator):
  7         '''
  8         初始化感知器,設置輸入參數的個數,以及激活函數。
  9         激活函數的類型為double -> double
 10         '''
 11         self.activator = activator
 12         # 權重向量初始化為0
 13         self.weights = [0.0 for _ in range(input_num)]
 14         # 偏置項初始化為0
 15         self.bias = 0.0
 16     def __str__(self):
 17         '''
 18         打印學習到的權重、偏置項
 19         '''
 20         return 'weights\t:%s\nbias\t:%f\n' % (self.weights, self.bias)
 21 
 22 
 23     def predict(self, input_vec):
 24         '''
 25         輸入向量,輸出感知器的計算結果
 26         '''
 27         # 把input_vec[x1,x2,x3...]和weights[w1,w2,w3,...]打包在一起
 28         # 變成[(x1,w1),(x2,w2),(x3,w3),...]
 29         # 然后利用map函數計算[x1*w1, x2*w2, x3*w3]
 30         # 最后利用reduce求和
 31 
 32         #list1 = list(self.weights)
 33         #print ("predict self.weights:", list1)
 34 
 35         
 36         return self.activator(
 37             reduce(lambda a, b: a + b,
 38                    list(map(lambda tp: tp[0] * tp[1],   # HateMath修改
 39                        zip(input_vec, self.weights)))
 40                 , 0.0) + self.bias)
 41     def train(self, input_vecs, labels, iteration, rate):
 42         '''
 43         輸入訓練數據:一組向量、與每個向量對應的label;以及訓練輪數、學習率
 44         '''
 45         for i in range(iteration):
 46             self._one_iteration(input_vecs, labels, rate)
 47 
 48     def _one_iteration(self, input_vecs, labels, rate):
 49         '''
 50         一次迭代,把所有的訓練數據過一遍
 51         '''
 52         # 把輸入和輸出打包在一起,成為樣本的列表[(input_vec, label), ...]
 53         # 而每個訓練樣本是(input_vec, label)
 54         samples = zip(input_vecs, labels)
 55         # 對每個樣本,按照感知器規則更新權重
 56         for (input_vec, label) in samples:
 57             # 計算感知器在當前權重下的輸出
 58             output = self.predict(input_vec)
 59             # 更新權重
 60             self._update_weights(input_vec, output, label, rate)
 61 
 62     def _update_weights(self, input_vec, output, label, rate):
 63         '''
 64         按照感知器規則更新權重
 65         '''
 66         # 把input_vec[x1,x2,x3,...]和weights[w1,w2,w3,...]打包在一起
 67         # 變成[(x1,w1),(x2,w2),(x3,w3),...]
 68         # 然后利用感知器規則更新權重
 69         delta = label - output
 70         self.weights = list(map( lambda tp: tp[1] + rate * delta * tp[0], zip(input_vec, self.weights)) ) # HateMath修改
 71 
 72         # 更新bias
 73         self.bias += rate * delta
 74 
 75         print("_update_weights() -------------")
 76         print("label - output = delta:" ,label, output, delta)
 77         print("weights ", self.weights)
 78         print("bias", self.bias)
 79  
 80 
 81 
 82 
 83 
 84 def f(x):
 85     '''
 86     定義激活函數f
 87     '''
 88     return 1 if x > 0 else 0
 89 
 90 def get_training_dataset():
 91     '''
 92     基於and真值表構建訓練數據
 93     '''
 94     # 構建訓練數據
 95     # 輸入向量列表
 96     input_vecs = [[1,1], [0,0], [1,0], [0,1]]
 97     # 期望的輸出列表,注意要與輸入一一對應
 98     # [1,1] -> 1, [0,0] -> 0, [1,0] -> 0, [0,1] -> 0
 99     labels = [1, 0, 0, 0]
100     return input_vecs, labels 
101     
102 def train_and_perceptron():
103     '''
104     使用and真值表訓練感知器
105     '''
106     # 創建感知器,輸入參數個數為2(因為and是二元函數),激活函數為f
107     p = Perceptron(2, f)
108     # 訓練,迭代10輪, 學習速率為0.1
109     input_vecs, labels = get_training_dataset()
110     p.train(input_vecs, labels, 10, 0.1)
111     #返回訓練好的感知器
112     return p
113 
114 if __name__ == '__main__': 
115     # 訓練and感知器
116     and_perception = train_and_perceptron()
117     # 打印訓練獲得的權重
118 
119     # 測試
120     print (and_perception)
121     print ('1 and 1 = %d' % and_perception.predict([1, 1]))
122     print ('0 and 0 = %d' % and_perception.predict([0, 0]))
123     print ('1 and 0 = %d' % and_perception.predict([1, 0]))
124     print ('0 and 1 = %d' % and_perception.predict([0, 1]))

 

 

 

運行輸出:

======================== RESTART: F:\桌面\Perceptron.py ========================
_update_weights() -------------
label - output = delta: 1 0 1
weights  [0.1, 0.1]
bias 0.1
_update_weights() -------------
label - output = delta: 0 1 -1
weights  [0.1, 0.1]
bias 0.0
_update_weights() -------------
label - output = delta: 0 1 -1
weights  [0.0, 0.1]
bias -0.1
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.0, 0.1]
bias -0.1
_update_weights() -------------
label - output = delta: 1 0 1
weights  [0.1, 0.2]
bias 0.0
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias 0.0
_update_weights() -------------
label - output = delta: 0 1 -1
weights  [0.0, 0.2]
bias -0.1
_update_weights() -------------
label - output = delta: 0 1 -1
weights  [0.0, 0.1]
bias -0.2
_update_weights() -------------
label - output = delta: 1 0 1
weights  [0.1, 0.2]
bias -0.1
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.1
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.1
_update_weights() -------------
label - output = delta: 0 1 -1
weights  [0.1, 0.1]
bias -0.2
_update_weights() -------------
label - output = delta: 1 0 1
weights  [0.2, 0.2]
bias -0.1
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.2, 0.2]
bias -0.1
_update_weights() -------------
label - output = delta: 0 1 -1
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 1 1 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 1 1 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 1 1 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 1 1 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 1 1 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 1 1 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
_update_weights() -------------
label - output = delta: 0 0 0
weights  [0.1, 0.2]
bias -0.2
weights    :[0.1, 0.2]
bias    :-0.200000

1 and 1 = 1
0 and 0 = 0
1 and 0 = 0
0 and 1 = 0

 

可以看到,最后訓練出來的權重是 [0.1, 0.2],偏置 -0.2,根據感知機模型得到公式:f(x, y) = 0.1x + 0.2y -0.2

 

可以看到是個三維平面,這個平面實現了對樣本中4個三維空間點分類。

 

調試經過:

1. lambda表達式的使用

第38和第70行中,原適用於Python2.7的代碼無法正常運行,提示 invalid syntax。貌似是Python3中,在lambda表達式中使用元組的方式和Python2.7不一樣。

我改了一下代碼,語法問題沒有了,可是預測結果不正常。於是就打印map()函數的返回值,試圖調試。

 

2. 打印map()函數返回的對象

參見 https://www.cnblogs.com/lyy-totoro/p/7018597.html 的代碼,先轉為list再打印。

 list1 = list(data)

print(list1)

 打印輸出表明,訓練的值明顯不對,到底是哪里的問題?

 

3. 真相【小】白

https://segmentfault.com/a/1190000000322433

關鍵句:在Python3中,如果不在map函數前加上list,lambda函數根本就不會執行。

於是加上list,就變成了最終的代碼,工作正常。

只是“lambda函數根本就不會執行”這句,我沒考證過,所以說真相小白。

  

 

原文鏈接:

零基礎入門深度學習(1) - 感知器

 https://www.zybuluo.com/hanbingtao/note/433855


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM