机器学习 —— 感知机分类算法

# -*- coding: utf-8 -*-

import random
import queue
from time import sleep
from threading import Thread
import numpy as np

''' A binary linear classifier '''
class Perceptron(object):
    
    def __init__(self, eta):
        ''' init the param vector [w1, w2, bias] and build training data,
            where bias is set to '1' for all samples. '''
        self.w = [1.0] * 3
        # learning rate
        self.eta = eta
        self.data = self.buildData(False)
        self.error_pattern_queue = queue.Queue()
        self.optimizer = Optimizer(self.error_pattern_queue)
        self.optimizer.start()
    
    ''' if sepratable is 'false', return unsepratble sample data
        , sepratble otherwise. '''
    def buildData(self, sepratble = True):
        if sepratble:
            return [(1,1,1,1),(2,3,1,1),(2,1,1,-1),(3,2,1,-1)]
        else:
            return [(1,1,1,-1),(2,3,1,1),(2,1,1,1),(3,2,1,-1)]

    ''' print the builded sample data'''
    def viewData(self):
        for x1, x2, bias, t in self.data:
            print("%s, %s, %s, %s" % (x1, x2, bias, t))

    ''' train the perceptron by using gradient descend. '''          
    def train(self):
        iter_num= 0
        while True:
            print('Epoch: %s, w = (%s, %s, %s)' % (iter_num, self.w[0], self.w[1], self.w[2]))
            # search error patterns
            for s in self.data:
                if np.dot(self.w, s[0:3]) * s[3] <= 0:
                    self.error_pattern_queue.put(s)
            self.error_pattern_queue.put('Done')

            while not self.optimizer.is_compute_finish:
                sleep(0.001)
            if self.optimizer.delta_loss == [0.0] * 3:
                break

            # update 'w'
            self.w = list(map(lambda x,y: x + y * self.eta, self.w, self.optimizer.delta_loss))
            self.optimizer.reset()
            iter_num += 1


''' A thread being responsible for updating the 'w' vector '''
class Optimizer(Thread):
    def __init__(self, error_pattern_queue):
        super(Optimizer, self).__init__()
        self.error_pattern_queue = error_pattern_queue
        self.is_compute_finish = False
        self.delta_loss = [0.0] * 3
        
    def reset(self):
        self.delta_loss = [0.0] * 3
        self.is_compute_finish = False
        
    def run(self):
        while True:
            s = self.error_pattern_queue.get()
            if s == 'Done':
                self.is_compute_finish = True
                continue
            if s[3] == 1:
                self.delta_loss = list(map(lambda x1,x2: x1 + x2, self.delta_loss, s[0:3]))
            else:
                self.delta_loss = list(map(lambda x1,x2: x1 - x2, self.delta_loss, s[0:3]))
    
def main():
    pt = Perceptron(1.0)
    pt.train()

if __name__ == '__main__':
    main()

 

几点说明

    1、Perceptron构造函数将待求解参数进行初始化,其中将偏置bias设为1,并构造训练数据(注意:  如果sepratble设为False, 则将构造一个线性不可分数据集),最后启动梯度下降执行线程,与train()方法并行执行(注意:  此处无需将所有误分类模式找到后再进行计算梯度,而是以流式计算的方式进行,即发现一个误分类模式便开始更新梯度)。

    2、实验发现,将学习率eta设置为很大的值(如1000)和 一般大小的值(如10)的迭代次数是相同的(在两个不同的线性可分数据集上均观察到此现象),但理论解释尚未弄清,希望对此有研究的大神们给出相关解释。

    3、感知机仅能用于二分类,且对线性不可分数据无能无力,因为感知机本质上学习的是一个线性分类函数(参数分量与样本分量一一对应,为线性函数)。

    4、感知机训练出的最终模型由参数的初始化以及学习率共同决定。

你可能感兴趣的:(机器学习,神经网络,Python)