1. 程式人生 > >《Python神經網路程式設計》1.4節蟲子分類器的實現

《Python神經網路程式設計》1.4節蟲子分類器的實現

最近在看這本書,覺得裡面蟲子分類器也值得試試實現,因為這個方法已經包含了神經網路的核心思想。

以下是實現的過程。

按照《Python神經網路程式設計》(非同步圖書出版)第一章蟲子分類器訓練的過程,模仿書中第二章的3層神經網路的實現過程,來構建一個可執行的蟲子分類器。

首先,構造出來分類器的框架,包含訓練和查詢.

In [ ]:

class BugClassifier:
    def __init__(self):
        pass
    
    def train(self, target_bug_size, target_bug):
        pass
    
    def query(self, input_bug_size):
        pass

蟲子分類器,核心是一個線性函式,分類器的主要引數就是其斜率,同時也包括了訓練過程中的學習率。 由於書中已經預設了蟲子和線形分類器的關係,所以需要把這個關係對應的修正量也預設好。 例如瓢蟲線上形函式下面,毛蟲在上面。在查詢時,也需要根據這個關係來做分類的結論。 另外因此可以得到一個推論:該分類器並不需要就蟲子和線形函式的位置關係進行學習(這算是已知的知識)。

In [ ]:

class BugClassifier:
    def __init__(self, coefficient, learning_rate, corrections):
        self.coefficient = coefficient # 初始係數
        self.learning_rate = learning_rate # 學習率
        self.corrections = corrections # 預定義的根據蟲類的計算值修正量
    
    def train(self, target_bug_size, target_bug):
        pass
    
    def query(self, input_bug_size):
        pass
    
# 測試程式碼
bc = BugClassifier(0.25, 0.5, 
                   {'瓢蟲':{'修正量':0.1, '關係':lambda c,t:c>t and True or False}, 
                    '毛蟲':{'修正量':-0.1, '關係':lambda c,t:c<t and True or False}})

訓練的過程,核心思路就是利用訓練資料來計算,得到與目標之間的誤差。 再利用誤差來反向傳播到對核心引數(分類器所使用的線形函式的斜率係數)的調整, 調整的步伐,則是依據初始化時設定的學習率。

In [6]:

class BugClassifier:
    def __init__(self, coefficient, learning_rate, corrections):
        self.coefficient = coefficient # 初始係數
        self.learning_rate = learning_rate # 學習率
        self.corrections = corrections # 預定義的根據蟲類的計算值修正量
    
    def feedforward(self, width):
        ''' 前饋函式,此處是利用輸入的寬度乘以分類器內部係數計算出來輸出的長度 '''
        return width * self.coefficient
    
    def feedback(self, width, error):
        ''' 反饋函式,此處是利用輸入的寬度和輸出的誤差來反向調節分類器內部係數 '''
        self.coefficient += self.learning_rate * (error / width)
        
    def train(self, target_bug_size, target_bug):
        target_bug_width = target_bug_size[0]
        target_bug_length = target_bug_size[1]
        computed_bug_length = self.feedforward(target_bug_width)
        # 誤差計算。誤差計算時,需要根據蟲子分類和線形函式的預設關係來修正目標值
        error = (target_bug_length + self.corrections[target_bug]['修正量']) - computed_bug_length
        # 反饋誤差
        self.feedback(target_bug_width, error)
    
    def query(self, input_bug_size):
        pass

# 測試程式碼
bc = BugClassifier(0.25, 0.5, 
                   {'瓢蟲':{'修正量':0.1, '關係滿足?':lambda c,t:c>t and True or False}, 
                    '毛蟲':{'修正量':-0.1, '關係滿足?':lambda c,t:c<t and True or False}})
bc.train([3.0, 1.0], '瓢蟲')
print('訓練第一個樣本後的斜率:', bc.coefficient)
bc.train([1.0, 3.0], '毛蟲')
print('訓練第二個樣本後的斜率:', bc.coefficient)
訓練第一個樣本後的斜率: 0.30833333333333335
訓練第二個樣本後的斜率: 1.6041666666666667

可以看到,兩次訓練的結果,和書上例子展示的結果一樣,因此程式碼是正確的。

查詢的過程,則是利用已經訓練好的分類器,對比分類器計算的分界線值與目標值的大小, 並結合預設的關係滿足謂詞,例如分界線值>目標值,則為瓢蟲;分界線值<目標值,則為毛蟲,來給出分類的結果。

In [13]:

class BugClassifier:
    def __init__(self, coefficient, learning_rate, corrections):
        self.coefficient = coefficient # 初始係數
        self.learning_rate = learning_rate # 學習率
        self.corrections = corrections # 預定義的根據蟲類的計算值修正量
    
    def feedforward(self, width):
        ''' 前饋函式,此處是利用輸入的寬度乘以分類器內部係數計算出來輸出的長度 '''
        return width * self.coefficient
    
    def feedback(self, width, error):
        ''' 反饋函式,此處是利用輸入的寬度和輸出的誤差來反向調節分類器內部係數 '''
        self.coefficient += self.learning_rate * (error / width)
        
    def train(self, target_bug_size, target_bug):
        target_bug_width = target_bug_size[0]
        target_bug_length = target_bug_size[1]
        computed_bug_length = self.feedforward(target_bug_width)
        # 誤差計算。誤差計算時,需要根據蟲子分類和線形函式的預設關係來修正目標值
        error = (target_bug_length + self.corrections[target_bug]['修正量']) - computed_bug_length
        # 反饋誤差
        self.feedback(target_bug_width, error)
    
    def query(self, input_bug_size):
        input_bug_width = input_bug_size[0]
        input_bug_length = input_bug_size[1]
        computed_bug_length = self.feedforward(input_bug_width)
        for bug, correction in self.corrections.items():
            if correction['關係滿足?'](computed_bug_length, input_bug_length):
                return bug # 只有可能屬於一種分類,因此立即返回

# 測試程式碼
bc = BugClassifier(0.25, 0.5, 
                   {'瓢蟲':{'修正量':0.1, '關係滿足?':lambda c,t:c>t and True or False}, 
                    '毛蟲':{'修正量':-0.1, '關係滿足?':lambda c,t:c<t and True or False}})
bc.train([3.0, 1.0], '瓢蟲')
print('訓練第一個樣本後的斜率:', bc.coefficient)
bc.train([1.0, 3.0], '毛蟲')
print('訓練第二個樣本後的斜率:', bc.coefficient)
test_case_1 = [2.8, 0.9]
print('輸入:', test_case_1, ' 識別結果:', bc.query(test_case_1))
訓練第一個樣本後的斜率: 0.30833333333333335
訓練第二個樣本後的斜率: 1.6041666666666667
輸入: [2.8, 0.9]  識別結果: 瓢蟲

可以看到,分類成功了!