参考自:参考文档
1、相关概念
1、感知器即为神经网络的一个神经元
2、构造图:
其中x为输入值
w为权值(其中w0为偏置项)
从weighted sum到step function的过程称为激活函数
最终结果为输出
3、感知器迭代训练
感知器训练算法:将权重项和偏置项初始化为0,然后,利用下面的感知器规则迭代的修改wi和b,直到训练完成。
其中:
每次从训练数据中取出一个样本的输入向量,使用感知器计算其输出,再根据上面的规则来调整权重。每处理一个样本就调整一次权重。经过多轮迭代后(即全部的训练数据被反复处理多轮),就可以训练出感知器的权重,使之实现目标函数。
提出问题:
1、为什么需要w矩阵
感知机可以如下理解,寻找一个超平面,在该平面的两侧分别标记为两类,即+1和-1。以二维图展示如下:以x1+x2-2=0直线分割成两部分,直线上面为正,下面为负。
w为x1和x2的系数,根据系数不断调整此线性函数可以决定出正负边界
另外,w也可以理解为每个x的权重,即每个x对最终结果影响的大小
2、激活函数的意义?
线性变换太简单(只是加权偏移),限制了对复杂任务的处理能力。没有激活函数的神经网络就是一个线性回归模型。激活函数做的非线性变换可以使得神经网络处理非常复杂的任务。例如,我们希望我们的神经网络可以对语言翻译和图像分类做操作,这就需要非线性转换。同时,激活函数也使得反向传播算法变的可能。因为,这时候梯度和误差会被同时用来更新权重和偏移。没有可微分的线性函数,这就不可能了。
简而言之就是加入非线性的因素,解决线性函数无法解决的问题,比如本次实现and函数,其无法使用线性进行模拟,但是可以使用线性函数计算的结果,加上激活函数来进行分类。
2、预先知识
(1)Python lambda:
x,y:x+y 意思为 输入x,y 输出(x+y)
(2)Python3中对上述式子进行了修改
输入的x,y改为了x_y 其中x_y[0] 为x,x_y[1]为y
(3)Python 中reduce取自:functools
含义:
from functools import reduce
def add(x, y) : # 两数相加
return x + y
sum1 = reduce(add, [1,2,3,4,5]) # 计算列表和:1+2+3+4+5
sum2 = reduce(lambda x, y: x+y, [1,2,3,4,5]) # 使用 lambda 匿名函数
print(sum1)
print(sum2)
reduce可以有三个参数,第三个是初始值
def reduce(function, sequence, initial=None):
3、实现感知器
根据上述公式,我们可以发现,感知器是根据预期结果与判断结果输出的差值进行不断更新的
1、首先初始化感知器,将其输入值和激活函数进行定义(注意激活函数的类型)
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
2、通过输入值、预期结果、迭代次数和学习速率对感知器进行训练
def train(self, input_vecs, labels, iteration, rate):
'''
输入训练数据:一组向量、与每个向量对应的label;以及训练轮数、学习率
'''
for i in range(iteration):
self._one_iteration(input_vecs, labels, rate)
3、定义每次迭代函数(通过输入值、输出值、学习率更新权重及偏置项)即实现上述一中的第三点
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
self.weights = map(
lambda x_w: x_w[1] + rate * delta * x_w[0],
zip(input_vec, self.weights))
# 更新bias
self.bias += rate * delta
4、输出训练结果(偏置项及权重)
def __str__(self):
'''
打印学习到的权重、偏置项
'''
return 'weights\t:%s\nbias\t:%f\n' % (self.weights, self.bias)
5、利用训练好的网络进行使用,输入值然后将其进行输出
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求和
return self.activator(
reduce(lambda a_b:a_b[0]+a_b[1],
map(lambda x_w:x_w[0]*x_w[1],
zip(input_vec, self.weights))
, 0.0) + self.bias)
4、自己实现的感知器
# Python TR
# Time:2021/1/5 9:52 下午
#object表示Perceptron继承自object
from functools import reduce
class self_Perceptron(object):
#需要初始化激活函数、weights、偏置项
def __init__(self,input_num,activation):
self.weights = [0.0 for _ in range(input_num)]
self.activation = activation
self.bias = 0.0
def __str__(self):
return "weights:\t%s\nbias:\t%f\n" % (list(self.weights), self.bias)
def add_num(self,a,b):
return a+b
def multi_num(self,a,b):
return a*b
def predict(self,input_vec):
multi = map(self.multi_num,input_vec,self.weights)#将两个向量中的对应元素相乘
res = reduce(self.add_num,multi,0.0)#求向量中的所有元素的和
return self.activation(res+self.bias)
def train(self,input_vec,labels,iters,rate):
for i in range(iters):
self.train_once(input_vec,labels,rate)
def train_once(self,input_vec,labels,rate):
samples = zip(input_vec,labels)
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):
delta = label-output
for i in range(len(self.weights)):
self.weights[i] = self.weights[i]+rate*delta*input_vec[i]
self.bias = self.bias+delta*rate