当我写到这个标题的时候感觉超级激动,因为一直以为那是一种被束之高阁的技术,哈哈;但是当我读到这一章的时候,感觉还可以。下面介绍一些,相关的概念和术语;
- 阈(yu)值[threshold]:
就是一个限制,如果值超过threshold 神经元就会兴奋,也就是输出正样本1 - sigmoid函数
激活函数,将实数域的取值压缩到(0-1) - M-P神经元
在M-P神经元模型中,神经元接收来自n个其他神经元传递过来的输入信号,再将接收到的输入信号按照某种权重叠加起来,叠加起来的刺激强度S可用公式 S = ∑ i = 1 n w i x i S=\sum_{i=1}^{n}w_{i}x_{i} S=∑i=1nwixi来表示。得到S后,好要与当前神经元的阈值进行比较,然后通过激活函数向外表达输出。 - 感知机
有两层神经元组成的,输入层收到外界输入信号后传递给输出层,输出层是M-P神经元,亦称阈值逻辑单元。如下图所示。有没有感觉,感知机很像线性分类器。
但是,这种双层的感知机,只能进行线性可分的样本,对于线性不可分的数据集 比如说,”异或“,就无法用单个感知机实现;但是,我们可以用两个感知机实现异或。
害,口说无凭,下面从单层感知机学习与门开始实现
分析下问题 :我们有两个输入,然后会有一个输出true or false
有上面的M-p模型可以得知,我们会有一个模型形如:
f
(
x
1
,
x
2
)
=
w
1
∗
x
1
+
w
2
∗
x
2
+
b
f(x_1,x_2)=w_1*x_1+w_2*x_2 +b
f(x1,x2)=w1∗x1+w2∗x2+b
是不是像极了线性分类器,其实 感知机就是一个线性分类器。
我们也可以把x和w写成矩阵的形式
f
(
x
1
,
x
2
)
=
[
x
1
,
x
2
]
[
w
1
,
w
2
]
T
+
b
f(x_1,x_2)=[x_1 ,x_2] [w_1,w_2]^T +b
f(x1,x2)=[x1,x2][w1,w2]T+b
但是,这里的正样本和负样本,是用(1,-1)表示的。之前习惯用1,0 表示。
下面我们写一下数据集,因为与门只有四种可能
data_set=[[1,1,1],
[1,0,-1],
[0,1,-1],
[0,0,-1]]
然后,我们初始化一下w矩阵和系数b
w= [0,0]
b=0
下面进行一次模拟运算
f
(
1
,
1
)
=
[
1
,
1
]
[
0
,
0
]
T
+
0
=
0
f(1,1)=[1 ,1] [0,0]^T +0=0
f(1,1)=[1,1][0,0]T+0=0
我们把0 规定为负样本,而 1,1 应该得到的是正样本;此时,这个系统并没有训练完成,我们要对参数进行修正;修正方案为:
{
w
=
w
+
η
∗
y
i
∗
x
i
b
=
b
+
η
∗
y
i
\begin{cases} w=w+\eta *y_i*x_i \\ b= b+\eta*y_i \end{cases}
{w=w+η∗yi∗xib=b+η∗yi
如果觉得有点看不懂的话,其实可以看这个,设我们预测的结果为Y:
{
w
=
w
+
η
∗
(
Y
)
∗
x
i
b
=
b
+
η
∗
(
y
i
−
Y
)
\begin{cases} w=w+\eta *(Y)*x_i \\ b= b+\eta*(y_i-Y) \end{cases}
{w=w+η∗(Y)∗xib=b+η∗(yi−Y)
用二者的插值来修正,就容易理解了。但是转念一想,Y和
y
i
y_i
yi的取值只能使{-1,1}两个 ,如果他们不相同,也只会差一个2 ,无非就是正负而已
如果预测值是-1 而真实值 是 1 那么这次的差值为 1-(-1)=2
如果预测值是1 而真实值 是 -1 那么这次的差值为 -1-1=-2
也就是说,我们的差值和真实值是同号的,只是差了一个系数。所以我们完全可以用真实值来代替这个差值,只不过是收敛的时间慢一点。
【我有几个疑问】
- 只正w不就行了,为什么一定要b一起修正?
- w和b修正公式的意义是什么?
- 为什么公式要设计成这个样子?
这些疑问都还没有解决,我们要知其然并且知其所以然;
先插个眼,哈哈
下面先说说怎么实现的吧!
肯定先开始写最核心的学习部分了
for k in range(20):# 这种简单的模型20次肯定收敛了
for i in range(data.shape[0]):# 这只是数据集一次循环,我们要循环多次
if y[i]*sign(np.dot(x[i],w)+b)<=0 :
w=w+eta*(y[i]-sign(np.dot(x[i],w)+b))*x[i]
b=b+eta*(y[i]-sign(np.dot(x[i],w)+b))
上面的判断条件很巧妙,如果是正值,且预测准确,那肯定乘积大于零,同理可得同负也是如此,因此只有小于零的时候,两者异号,才会判断出错。
害,其实没啥东西,就是把数据集过一遍,把有问题的数据修正一下,这个有点像梯度下降里面的随机梯度下降法,就是每一个数据进行修正,与之对应的还有batch 和mini-batch.
下面只需要从数据集中提取出,属性列和标签列就可以了
import numpy as np
data_set=[[1,1,1],
[1,0,-1],
[0,1,-1],
[0,0,-1]]
data= np.array(data_set)
# np 有一个花式索引很好用
#逗号前,表示取几行,逗号后,表示取第几列。清晰明了
x=data[:,:-1] # 取全部行 除去最后一列
y=data[:,-1:]# 取全部行的最后一列
现在都准备好了,就差一个测试函数了,就是将两个属性带入到模型中,求出结果
def Test(x1,x2):
x=np.array([x1,x2])
return sign(np.dot(x,w)+b)
#测试
print("1 and 1=",Test(1,1))
print("1 and 0=",Test(1,0))
print("0 and 1=",Test(0,1))
print("0 and 0=",Test(0,0))
#输出
1 and 1= 1
1 and 0= -1
0 and 1= -1
0 and 0= -1
其中或门和非门,只要相应的改动数据集就可以实现了,这里不做赘述。
源代码
# 单个感知机 实现 与或非
import matplotlib.pyplot as plt
import numpy as np
data_set=[[1,1,1],
[1,0,-1],
[0,1,-1],
[0,0,-1]]
data= np.array(data_set)
x=data[:,:-1]
y=data[:,-1:]
w=np.array([1 for i in range(data.shape[1]-1)])
b=1 #偏置
eta=1# 学习率
def sign(p):
return 1 if p>0 else -1
for j in range(5):
for i in range(data.shape[0]):
if y[i]*sign(np.dot(x[i],w)+b)<=0 :
w=w+eta*(y[i]-sign(np.dot(x[i],w)+b))*x[i]
b=b+eta*(y[i]-sign(np.dot(x[i],w)+b))
def Test(x1,x2):
x=np.array([x1,x2])
return sign(np.dot(x,w)+b)
print("1 and 1=",Test(1,1))
print("1 and 0=",Test(1,0))
print("0 and 1=",Test(0,1))
print("0 and 0=",Test(0,0))
下面我们挑战一下高难度的吧,两层感知机,叠加在一起,来实现线性不可分的异或问题。
周老师的这个图,已经给了很大帮助了,我们训练两个感知机,决策边界一上一下,这样正好将数据完整划分。我们需要三个感知机,所以一共有3*3=9 个参数
也许我们可以将他们放入到一个矩阵中形如
[
[w1,w2,b1],
[w3,w4,b2],
[w5,w6,b3],
]
当然也可能有更好的办法,这里只是思考的一部分。那这三个感知机,我们是一起训练呢,还是一个一个训练呢? 肯定是一起训练,可是9个参数 ,可以组成无穷种变化,又该如何下手呢?或者说,如果输出结果不准确,那这三个神经元,主要修正哪一个呢,有权重吗,这些都是问题。研究就是提出问题解决问题的过程,有了这些问题,下面我们去找找资料看看人家是怎么解决的;
看了花书的前馈神经网络,看了B站shuhuai008的白板推到系列(二十三)。得出结论,自己无意间触发了一个大boss,下面我准备单独写一篇文章,记录我攻克这个大boss的过程。