深度学习-代码实现1 感知机

本文介绍了感知机的基本原理及其解决线性分类问题的能力,并通过Python代码实现了感知机的学习过程,详细展示了训练过程及参数调整方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引用了:http://blog.youkuaiyun.com/qq_31456593/article/details/71335926

感知机是一个线性的分类器,不能解决非线性的分类问题比如说异或问题

下面是一个典型的感知机:


四个变量,对应四个权重,表示每个变量的重要程度,其中一个变量是作为bias存在的,

其input值始终为1,权重w0 = bias = -threshold

经过加权和之后,需要一个激励函数(activator)将值映射到{0,1}上

下面是使用阶跃函数作为activator

注意这里w0*x0其实那个threshold,不在不等式左边


如果我们将那个input值始终为1的变元代表的移动到等式的的左边可以得到


之后我们能得到真正的阶跃函数作为激励函数的表达式


我们不难发现一个训练好的感知机的组成为:


如何训练这个感知机呢?

1. 初始化感知机的参数,权值

2. 确定好迭代次数iteration和学习率rate

    使用标注好的训练数据的二元组(input_vecs,labels)

    1)使用predict函数计算出output

    2)使用update_coeff更新参数

    更新参数的方法为其中

为学习率,是训练样本的实际值,就是label,是感知机的输出值,上面更新参数的方法就是gradient descend

我背的的代码:

# encoding: utf-8

# 在类中自己的属性一定要加self,跟java一样
# 类自己的方法,在类中实现时,也要加self,表示作用于自己

class honor_perceptron(object):
    def __init__(self, input_num, activator):
        # 属性有三个,漏了activator,其实activator才是传进去的!
        self.weights = [0.0 for _ in range(input_num)]
        self.bias = 0.0
        self.activator = activator

    def __str__(self):
        return 'weights:%s\tbias:%f\n' % (self.weights, self.bias)

    def train(self,input_vecs,labels,iteration,rate):
        for i in range(iteration):
            self._one_iteration(input_vecs,labels,rate)

    def _one_iteration(self,input_vecs,labels,rate):
        samples = zip(input_vecs,labels)
        for (input_vec,label) in samples:
            output = self.predict(input_vec)
            self._update_weights(input_vec,output,label,rate)

    def predict(self,input_vec):
        # 这里忘记代到activator里面了
        # lambda表达式的括号确实有关系
        # reduce累加,累乘的时候lambda表达式不要括号
        return self.activator(reduce(lambda x, y:x+y,
                                     map(lambda (x, w):x*w,
                                         zip(input_vec,self.weights)),
                                     0.0)+self.bias)


    def _update_weights(self,input_vec,output,label,rate):
        delta = label - output
        self.weights = map(lambda(x,w):w + rate*delta*x,zip(input_vec,self.weights))
        self.bias +=  rate*delta


def f(x):
    return 1 if x>0 else 0

def get_train_dataset():
    input_vecs = [[1, 1],[1, 0],[0, 1],[0, 0]]
    labels = [1, 0, 0, 0]
    return (input_vecs,labels)

def train_and_perceptron():
    (input_vecs, labels) = get_train_dataset()
    # 下面犯了两个错误 1.没有初始化就想训练 2.p不需要初始化不需要指定类型
    # honor_perceptron p = p,train(input_vecs,labels,10,0.1)

    # 应该是
    p = honor_perceptron(2, f)

    p.train(input_vecs,labels,10,0.1)

    return p

if __name__ == '__main__':
    p = train_and_perceptron()

    print p

    print '1 and 1 = %d' % p.predict([1, 1])
    print '1 and 0 = %d' % p.predict([1, 0])
    print '0 and 1 = %d' % p.predict([0, 1])
    print '0 and 0 = %d' % p.predict([0, 0])

我抄的代码:

# encoding: utf-8

'''
我遇到的初级错误,函数名和for后面不写冒号:
还有main函数不会写
if __name__ == '__main__'
'''


# python继承object表示新式类
class My_perceptron(object):
    def __init__(self,input_num,activator):
        '''
        初始化感知机
        :param input_num: 输入参数的个数
        :param activator: 激活函数
        '''

        '''python self先理解为this吧
        python中的self就相当于C++中的this指针
        也就是指向对象本身的指针
        self.name = name 就是当前对象的成员变量name赋值为name。
        '''
        self.activator = activator
        # for _ in range(...)里的_其实就是一个不想起名字的变量而已
        self.weights = [0.0 for _ in range(input_num)]
        self.bias = 0.0
    def __str__(self):
        '''
        :return: 学习得到的权重
        '''
        return 'finally: weights\t:%s\nbias\t:%f\n' % (self.weights,self.bias)

    # 标注好的input_vecs和label,迭代次数iteration,学习率learning rate
    def train(self,input_vecs,labels,iteration,rate):
        for i in range(iteration):
            self._one_iteration(input_vecs,labels,rate)
            print '%dth iteration: weights\t:%s\nbias\t:%f\n' % (i+1, self.weights,self.bias)


    # 这样命名可能是突出这个是私有的方法吧
    def _one_iteration(self,input_vecs,labels,rate):
        '''
        每一次迭代,更新参数
        '''
         # 把输入的样本和标签打包,形成的元组对应起来
        samples = zip(input_vecs,labels)

        # 对每个样本根据感知机的规则进行更新权重
        # 1.把input_vec传进去,计算output 2.利用output和input和标签label还有rate更新参数(weights和bias)
        for (input_vec,label) in samples:
            # 1.
            output = self.predict(input_vec)
            # 2.
            self._update_weights(input_vec,output,label,rate)

    def predict(self,input_vec):
        # python在对多个变量组成的表达式的时候常用 先zip 然后前面lambda 放在map里面
        return self.activator(
            reduce(lambda x,y:x+y,
                      map(lambda (x,w):x*w,
                          zip(input_vec,self.weights))
                   0.0) + self.bias)
        # 上面的0.0估计是为了把整数转化浮点数,以防万一

    def _update_weights(self,input_vec,output,label,rate):
        # delta_w_i = rate * delta * input_vec_i

        delta = label - output

        # 你要懂打包的实质,一般情况下都是将多元的东西打包(表达式里面带有i的变元)
        self.weights = map(lambda (w,x):w + rate * delta * x, zip(self.weights, input_vec))

        # 写完之后犯的错误:这个是+=而不是=,公式是核心千万不能写错哦
        self.bias  += rate * delta



# 定义激活函数
# 注意python中条件表达式的写法
def f(x):
    return 1 if x>0 else 0

# 标注好的数据直接灌进去
def get_train_dataset():
    input_vecs = [[1, 1], [1, 0], [0, 1], [0, 0]]
    labels = [1, 0, 0, 0]
    return input_vecs, labels

def train_and_perception():
    # 创建感知机
    p = My_perceptron(2, f);

    # 获得训练数据集
    (input_vecs,labels) = get_train_dataset()

    # 训练感知机
    # 问题:为什么无论怎么调学习率,都是第四次收敛了???
    p.train(input_vecs, labels, 10, 0.001)

    return p
if __name__  == '__main__':
    # 训练感知机
    and_perceptron = train_and_perception()

    # 输出训练之后的参数
    print and_perceptron

    #测试
    print '1 and 1 = %d' % and_perceptron.predict([1, 1])
    print '1 and 0 = %d' % and_perceptron.predict([1, 0])
    print '0 and 1 = %d' % and_perceptron.predict([0, 1])
    print '0 and 0 = %d' % and_perceptron.predict([0, 0])

原来的代码:
# encoding: utf-8
class Perceptron(object):
    def __init__(self, input_num, activator):
        '''
        初始化感知器,设置输入参数的个数,以及激活函数。
        激活函数的类型为double -> double
        '''
        self.activator = activator
        # 权重向量初始化为0
        self.weights = [0.0 for _ in range(input_num)]
        # 偏置项初始化为0
        self.bias = 0.0
    def __str__(self):
        '''
        打印学习到的权重、偏置项
        '''
        return 'weights\t:%s\nbias\t:%f\n' % (self.weights, self.bias)
    def predict(self, input_vec):
        '''
        输入向量,输出感知器的计算结果
        '''
        # 把input_vec[x1,x2,x3...]和weights[w1,w2,w3,...]打包在一起
        # 变成[(x1,w1),(x2,w2),(x3,w3),...]
        # 然后利用map函数计算[x1*w1, x2*w2, x3*w3]
        # 最后利用reduce求和

        # reduce实例,容易实现累加,累乘,其实就是把一个函数作用于第一个个第二个得到的结果作为第一个,然后一直这样下去。。
        xx = reduce(lambda x,y:x+y,[1,2,4,5])


        return self.activator(
            reduce(lambda a, b: a + b,
                   map(lambda (x, w): x * w,
                       zip(input_vec, self.weights))
                , 0.0) + self.bias)
    def train(self, input_vecs, labels, iteration, rate):
        '''
        输入训练数据:一组向量、与每个向量对应的label;以及训练轮数、学习率
        '''
        for i in range(iteration):
            self._one_iteration(input_vecs, labels, rate)
    def _one_iteration(self, input_vecs, labels, rate):
        '''
        一次迭代,把所有的训练数据过一遍
        '''
        # 把输入和输出打包在一起,成为样本的列表[(input_vec, label), ...]
        # 而每个训练样本是(input_vec, label)
        samples = zip(input_vecs, labels)
        # 对每个样本,按照感知器规则更新权重
        # 这里的input_vec就是单个的[1,1],[1,0]什么的,因为遍历了嘛
        for (input_vec, label) in samples:
            # 计算感知器在当前权重下的输出
            output = self.predict(input_vec)
            # 更新权重
            self._update_weights(input_vec, output, label, rate)
    def _update_weights(self, input_vec, output, label, rate):
        '''
        按照感知器规则更新权重
        '''
        # 把input_vec[x1,x2,x3,...]和weights[w1,w2,w3,...]打包在一起
        # 变成[(x1,w1),(x2,w2),(x3,w3),...]
        # 然后利用感知器规则更新权重
        delta = label - output
        # lambda表达式的用法:lambda+输入变量(必须用括号括起来)+冒号+输出的变量
        # map的用法:map(函数,作用函数的输入变量),返回函数的输出
        # map和lambda结合使用效率很高

        # 这个weight本身就是一个二维的,因此
        self.weights = map(
            lambda (x, w): w + rate * delta * x,
            zip(input_vec, self.weights))
        # 更新bias
        self.bias += rate * delta

def f(x):
    '''
    定义激活函数f
    '''
    return 1 if x > 0 else 0
def get_training_dataset():
    '''
    基于and真值表构建训练数据
    '''
    # 构建训练数据
    # 输入向量列表
    input_vecs = [[1,1], [0,0], [1,0], [0,1]]
    # 期望的输出列表,注意要与输入一一对应
    # [1,1] -> 1, [0,0] -> 0, [1,0] -> 0, [0,1] -> 0
    labels = [1, 0, 0, 0]
    return input_vecs, labels
def train_and_perceptron():
    '''
    使用and真值表训练感知器
    '''
    # 创建感知器,输入参数个数为2(因为and是二元函数),激活函数为f
    p = Perceptron(2, f)
    # 训练,迭代10轮, 学习速率为0.1
    input_vecs, labels = get_training_dataset()
    p.train(input_vecs, labels, 10, 0.1)
    #返回训练好的感知器
    return p
if __name__ == '__main__':
    # 训练and感知器
    and_perception = train_and_perceptron()
    # 打印训练获得的权重
    print and_perception
    # 测试
    print '1 and 1 = %d' % and_perception.predict([1, 1])
    print '0 and 0 = %d' % and_perception.predict([0, 0])
    print '1 and 0 = %d' % and_perception.predict([1, 0])
    print '0 and 1 = %d' % and_perception.predict([0, 1])

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值