感知器的两种实现

周海汉 /文 2017-05-31
2017-05-31

感知器的两种实现方式

1. 每一行样本循环进行处理(Stochastic Gradient Descent, SGD)

随机梯度下降,对每一行样本, 计算其参数w, 一次迭代全部样本.并在处理每个样本时逐步调整参数w. 这种方式最自然, 但参数会有反复.效率最低.

# perceptron 感知器
# 周海汉 2017.5.21

import numpy as np

# 感知器
class Perceptron:
    '''感知器 y=f(x*w+b),x为输入,w为权重,b为偏置量,f为激活函数, 一般有sigmoid,relu,sgn,tanh'''
    def __init__(self, eta, n_iter):
        '''
        eta: 迭代率
        n_iter: 迭代次数
        '''
        self.eta = eta
        self.n_iter = n_iter
        
    def fit(self, x, y):
        '''
        x: 训练数据,二维数组.[sample,feature], sample表示训练用数据数目, feature表示特征数
        y: 目标结果标签数据,一维向量. [label], 长度和samples值一样
        w: 权重向量, [weight] , 包含偏置量w0, 长度为feature值+1
        errors: 记录迭代错误
        '''
        
        # 修改输入训练数组, 添加x0为[1,...,1], 方便和w0相乘, 计算偏置量
        x_ = np.insert(x,0,np.ones(x.shape[0]),axis=1)
        self.w = np.ones(x.shape[1] + 1)
        self.errors = []
        for i in range(self.n_iter):
            print("========i:{}=====".format(i))
            for xrow, target in zip(x_,y):
                # 计算迭代量, 该值为标量, eta * (y_train - y_predict)
                print("xrow,target:",xrow,target)
                print("out:",self.predict(xrow))
                compare = target - self.predict(xrow)
                update = self.eta * compare 
                print("error c:",compare)
                print("deta w:",update*xrow)

                # w[i] = w[i] + update
                self.w += update*xrow
                print("self.w:",self.w)
                #print("compare:{}".format(compare))

                error = compare 

                self.errors.append(error)
    
    def net_input(self, xrow):
        '''
        y = w0*1 + w1*x1 + ... + wn*xn
        '''        
        return self.w.dot(xrow)
    
    def predict(self, xrow):
        '''
        计算迭代值, 返回0,1
        '''
        return np.where(self.net_input(xrow)>=0.0,1,0)
    
    def check(self,x,y):
        '''
        检验错误率
        '''
        errors=[]
        x_ = np.insert(x,0,np.ones(x.shape[0]),axis=1)
        for xrow, target in zip(x_,y):
            compare = target - self.predict(xrow)
            print('predict:{},target:{}'.format(self.predict(xrow),target))
            errors.append(int(compare > 0.01))
        
        print(errors)
            
def test():
    # 训练 布尔与的参数
    train=np.array([[0,1,0],[0,0,0],[1,0,0],[1,1,1]])
    test = np.array([[0,1,0],[1,1,1]])
    p = Perceptron(0.1,10)
    p.fit(train[:,:2],train[:,2])
    print(p.w)
    print(p.errors)
    
    p.check(test[:,:2],test[:,2])
    p.check(train[:,:2],train[:,2])
    
    

test()            

2. 采用全部样本进行矩阵训练(Batch Gradient Descent,BGD)

批梯度下降法,这种方式效率更高. 但矩阵操作直观性降低. 如果样本很大, 会导致内存加载问题. 本实现也很方便改造为mini-batch方式. 即训练时每次只加载小批数量的数据. 并逐渐调节参数.

# perceptron 感知器
# 周海汉 2017.5.21

import numpy as np

# 感知器
class Perceptron:
    '''感知器 y=f(x*w+b),x为输入,w为权重,b为偏置量,f为激活函数, 一般有sigmoid,relu,sgn,tanh'''
    def __init__(self, eta, n_iter):
        '''
        eta: 迭代率
        n_iter: 迭代次数
        '''
        self.eta = eta
        self.n_iter = n_iter
        
    def fit(self, x, y):
        '''
        x: 训练数据,二维数组.[sample,feature], sample表示训练用数据数目, feature表示特征数
        y: 目标结果标签数据,一维向量. [label], 长度和samples值一样
        w: 权重向量, [weight] , 包含偏置量w0, 长度为feature值+1
        costs: 记录迭代代价, 代价应该越来越小
        '''
        
        # 修改输入训练数组, 添加x0为[1,...,1], 方便和w0相乘, 计算偏置量
        x_ = np.insert(x,0,np.ones(x.shape[0]),axis=1)
        self.w = np.ones(x_.shape[1])
        print("x:",x_)
        print("y:",y)
        print("x.T:",x_.T)
        print("self.w:",self.w)
        #w = np.ones(x_.shape[1] * x_.shape[0]).reshape(x_.shape[0],x_.shape[1])
        #print("w:",w)
        self.costs = []
        for i in range(self.n_iter):
            print("=======ith {} train =======".format(i))
            # 计算输出值, 该值为和sample数相同长度的一维向量
            output = self.predict(x_)
            
            print("output:",output)
            
            # 误差 为 一维向量
            errors = y - output
            
            print("errors:",errors)
            # 计算损失函数, 也为一维向量, 长度为样本数 eta * x *(y_train - y_predict) 为每一个样本的deta w
            # x.T 表示每一个feature的值,和误差相乘, 得到一维向量,长度为 feature 数 +1
            print("x.T:\n",x_.T)
            detaw = self.eta * x_.T.dot(errors)
            
            print("deta w:",detaw)
            self.w += detaw
             
            #print("w:",w)
            #print("w.sum:",w.sum(axis=0))
            #self.w = w.sum(axis=0)/x_.shape[0]
            print("s w:",self.w)
            cost = (errors**2).sum()/2.0
            self.costs.append(cost)
            
        print("costs:",self.costs)
            

    def net_input(self, x):
        '''
        y(i) = w0*1 + w1*x1(i) + ... + wn*xn(i)
        
        i 表示第i个sample
        
        返回sample长度的一维输出向量
        '''        
        return np.dot(x, self.w)
    
    def activate(self,x):
        '''激活函数, 直接使用原值'''
        return self.net_input(x)
    
    def predict(self,x):
        '''
        预测函数, 返回0,1
        '''
        return np.where(self.activate(x)>=0.0,1,0)
    
    def check(self,x,y):
        '''
        检验错误率
        '''
        errors=[]
        x_ = np.insert(x,0,np.ones(x.shape[0]),axis=1)
        for xrow, target in zip(x_,y):
            print("xrow,target:",xrow,target)
            
            error = target - self.predict(xrow)
            print('predict:{},target:{}'.format(self.predict(xrow),target))
            errors.append(int(error > 0.01))
        
        print("check errors:",errors)
            
def test():
# 训练 布尔与的参数
    train=np.array([[0,1,0],[0,0,0],[1,0,0],[1,1,1]])
    test = np.array([[0,1,0],[1,1,1]])
    p = Perceptron(0.1,20)
    p.fit(train[:,:2],train[:,2])
    print(p.w)
    print(p.costs)
    
    p.check(test[:,:2],test[:,2])
    p.check(train[:,:2],train[:,2])
    
    
test()            

参考


如非注明转载, 均为原创. 本站遵循知识共享CC协议,转载请注明来源