1. 程式人生 > >用感知機(Perceptron)實現邏輯AND功能的Python3代碼

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

tar num print 在一起 最終 for %d __init__ 零基礎

之所以寫這篇隨筆,是因為參考文章(見文尾)中的的代碼是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

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