目录
感知器原理
如图,感知器中每个输入都有对应的权重,感知器在预测时:
输入向量
i
n
p
u
t
s
⃗
=
(
x
1
,
x
2
,
.
.
.
,
x
n
)
\vec{inputs}=(x_1,x_2,...,x_n)
inputs=(x1,x2,...,xn)
输出带权和
w
e
i
g
h
t
_
s
u
m
=
w
0
+
x
1
×
w
1
+
x
2
×
w
2
+
.
.
.
+
x
n
×
w
n
=
w
0
+
∑
i
=
1
n
(
x
i
×
w
i
)
weight\_sum=w_0+x_1×w_1+x_2×w_2+...+x_n×w_n=w_0+\sum_{i=1}^n (x_i×w_i)
weight_sum=w0+x1×w1+x2×w2+...+xn×wn=w0+i=1∑n(xi×wi)
其中即偏置bias
令权重也为一个向量,即weights,记为w,则带权和可写为:
w
e
i
g
h
t
e
d
_
s
u
m
=
w
0
+
i
n
p
u
t
s
⃗
⋅
w
⃗
weighted\_sum=w_0+\vec{inputs}·\vec{w}
weighted_sum=w0+inputs⋅w
最后的输出结果只需把带权和放入激活函数即可:
o
u
t
p
u
t
=
f
(
w
e
i
g
h
t
e
d
_
s
u
m
)
=
f
(
w
0
+
i
n
p
u
t
s
⃗
⋅
w
⃗
)
output=f(weighted\_sum)=f(w_0+\vec{inputs}·\vec{w})
output=f(weighted_sum)=f(w0+inputs⋅w)
激活函数有很多,例如一些阶跃函数,tanh函数,sigmoid函数等等
那么训练模型时就得想办法确定权重向量weights和偏置数bias,具体见如下代码方法和步骤
代码方法和步骤
一、感知器代码原理解析
1.训练感知器,通过Perceptron类中的train(self, input_vecs, labels, iteration, rate)
方法。
其中input_vecs为输入训练向量,labels为输入训练向量的标签向量,iteration为迭代次数,rate为学习率。每次迭代执行一次_one_iteration(self, input_vecs, labels, rate)
,可以理解为一个Epoch。
2.一次迭代中,将输入向量和标签用zip()函数打包在一起成为一个zip object,例如:
[([1, 1], 1), ([0, 0], 0), ([1, 0], 1), ([0, 1], 1)]
对其中的每个(input_vec,label),调用模型的predict()预测输入input_vec的output,再调用模型的_update_weights(input_vec, output, label, rate)
更新输入向量对应的权重和模型整体的偏置bias。
3.权重向量w0初始为[0.0]*维度(在与或函数中维度为2即w0初始为[0.0,0.0] ),在_update_weights()函数中,首先计算出此次迭代的损失值deltak= label – output,即标签和预测值之差,不失为一个朴素的损失函数;再对权重向量weights(记为w)做如下处理:(学习率rate记为r)
对于输入向量集input_vecs中的每一个向量
i
n
p
u
t
_
v
e
c
k
input\_vec_k
input_veck:
VectorOp.element_add(self.weights, VectorOp.scala_multiply(input_vec, rate * delta))
w
k
⃗
=
w
k
−
1
⃗
+
i
n
p
u
t
k
⃗
×
(
r
×
δ
k
)
,
k
=
1
,
2
,
…
,
n
\vec{w_k}=\vec{w_{k-1}}+\vec{input_k}×(r×δ_k ) ,k=1,2,…,n
wk=wk−1+inputk×(r×δk),k=1,2,…,n
其中n为迭代次数iteration
4.模型预测函数predict(input_vec)
传入一个输入向量input_vec,令 input_vec点乘模型权重weights再加上模型偏置bias,如下:
VectorOp.dot(input_vec, self.weights) + self.bias
得到的值传入模型的激活函数activator(x)
,本次模型使用的激活函数为一个阶跃函数:
f
(
x
)
=
{
1
for
x
>
0
0
for
x
<
=
0
f(x)=\left\{ \begin{array}{rcl} 1& \text{for}& x>0 \\ 0 & \text{for} & x<=0 \end{array}\right.
f(x)={10forforx>0x<=0
最后激活函数返回的值作为这次predict(input_vec)的返回值返回。
f
(
V
i
⋅
W
+
B
i
a
s
)
f(V_i \cdot W + Bias)
f(Vi⋅W+Bias)
二、训练感知器实现or函数
1. 代码
from __future__ import print_function
from functools import reduce
class VectorOp(object):
@staticmethod
def dot(x, y):
return reduce(lambda a, b: a + b, VectorOp.element_multiply(x, y), 0.0)
@staticmethod
def element_multiply(x, y):
return list(map(lambda x_y: x_y[0] * x_y[1], zip(x, y)))
@staticmethod
def element_add(x, y):
return list(map(lambda x_y: x_y[0] + x_y[1], zip(x, y))) #lambda 即匿名函数
@staticmethod
def scala_multiply(v, s):
return map(lambda e: e * s, v)
class Perceptron(object):
def __init__(self, input_num, activator):
self.activator = activator
self.weights = [-1.0] * input_num # 初始化权重
print("init weights")
print(self.weights)
self.bias = 0.0
def __str__(self):
return 'weights\t:%s\nbias\t:%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)
# print(list(samples))
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
#print("=============\ndelta=%.1f"%delta)
#print("updating,VectorOp.scala_multiply(input_vec, rate * delta):")
#print(list(VectorOp.scala_multiply(input_vec, rate * delta)))
#print("\nVectorOp.element_add(self.weights, VectorOp.scala_multiply(input_vec, rate * delta)):")
#print(list(VectorOp.element_add(self.weights, VectorOp.scala_multiply(input_vec, rate * delta))))
self.weights = VectorOp.element_add(
self.weights, VectorOp.scala_multiply(input_vec, rate * delta))
self.bias += rate * delta
def predict(self, input_vec):
return self.activator(
VectorOp.dot(input_vec, self.weights) + self.bias)
def f(x):
return 1 if x > 0 else 0
def get_training_dataset():
# and函数的输入训练向量
input_vecs = [[1, 1], [0, 0], [1, 0], [0, 1]]
labels = [1, 0, 0, 0]
return input_vecs, labels
def get_or_training_dataset():
# or函数的输入训练向量
input_vecs = [[1, 1], [0, 0], [1, 0], [0, 1]]
labels = [1, 0, 1, 1]
return input_vecs, labels
def train_and_perception():
p = Perceptron(2, f)
input_vecs, labels = get_training_dataset()
p.train(input_vecs, labels, 10, 0.1)
return p
def train_or_perception():
p = Perceptron(2, f)
input_vecs, labels = get_or_training_dataset()
p.train(input_vecs, labels,0, 0.1) # 输入向量,标签,迭代次数,学习率
return p
if __name__ == '__main__':
#and_perception = train_and_perception()
#print(and_perception)
# and测试
#print( '1 and 1 = %d' % and_perception.predict([1, 1]))
#print( '1 and 0 = %d' % and_perception.predict([1, 0]))
#print( '0 and 1 = %d' % and_perception.predict([0, 1]))
#print( '0 and 0 = %d' % and_perception.predict([0, 0]))
or_perception = train_or_perception()
print(or_perception)
# or测试
print('1 or 1 = %d' % or_perception.predict([1, 1]))
print('1 or 0 = %d' % or_perception.predict([1, 0]))
print('0 or 1 = %d' % or_perception.predict([0, 1]))
print('0 or 0 = %d' % or_perception.predict([0, 0]))