ML–XOR问题
感知器对线性可分或近似线性可分数据有很好的效果,但对于线性不可分数据的效果不理想.Minsky在1969年出版的<>中用详细的数学证明了感知器无法解决XOR(异或)分类问题.而我们要说的XOR问题
正是线性不可分的
一.基本的逻辑运算
1.AND运算
x1 | x2 | AND |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
2.OR运算
x1 | x2 | OR |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
3.XOR运算
x1 | x2 | OR |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
注意:XOR=OR-AND
4.异或问题
x1 | x2 | AND | OR | XOR |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
将上表的结果可视化,其中圆点表示0,方块表示1.AND,OR,NAND问题都是线性可分,但XOR是线性不可分
from IPython.display import Image
Image(filename="./data/1.png",width=500)
二.XOR问题的实质
1.XOR问题的产生
根据定义,线性模型将产生某种类型的线性(2D线,3D线平面或直线且缺乏曲线的高维表面)功能
Image(filename="./data/3.png",width=500)
在上图中,点x̄y和xȳ是应由XOR函数作为"True"或"1"发出信号的输入.挑战在于,XOR是一个非线性函数,意味着x̄y和xȳ不能与xy和x̄ȳ线性分离
Image(filename="./data/4.png",width=500)
如果XOR函数有效地分离出x̄y和xȳ,那么函数是什么样的?
Image(filename="./data/5.png",width=500)
Image(filename="./data/6.png",width=500)
如上图所示,XOR及XNOR在布尔函数中是唯一的,因为它们不能用单行捕获
下面描绘14个线性布尔函数中的每一个
Image(filename="./data/7.png",width=500)
2.XOR问题的解决
感知器
感知器包括单层输入单元-包括一个偏置单元-和单个输出单元,这里,偏置单元用虚线圆圈表示,而其他单元用蓝色圆圈表示。有两个非偏置输入单元表示XOr的两个二进制输入值。可以包括任意数量的输入单元
Image(filename="./data/8.png",width=500)
感知器是一种前馈网络,这意味着产生输出的过程(称为前向传播)在一个方向上从输入层流向输出层。输入层中的单元之间没有连接。相反,输入层中的所有单元都直接连接到输出单元
前向传播过程的简化说明是输入值X1和X2以及偏置值1乘以它们各自的权重W0…W2,并解析为输出单元
多层感知机
此问题的解决方案是通过添加额外的单元层而不是直接访问外部世界(称为隐藏层)来扩展到单层体系结构之外.另一种称为多层感知器(MLP)的前馈网络
Image(filename="./data/9.png",width=500)
反向传播
反向传播算法首先将前向传播过程输出的实际值与预期值进行比较,然后向后移动通过网络,在一个方向上稍微调整每个权重,以减小误差的大小。前向和后向传播在每个输入组合上重新运行数千次,直到网络可以使用前向传播准确地预测可能输入的预期输出
三.Tensorflow解决XOR
1.模型构思
a).确定网络结构
Image(filename="./data/11.png",width=500)
上图左边为详细结构,右边为向量式结构
b).确定输入
输入数据中有两个特征:x1,x2,共4个样本.分别为[0,0]T,[1,0]T.取x1,x2两列,每行代表一个样本,每个样本x都是一个向量,如果用矩阵表示就是:
c).激活函数
确定隐含层及初始化权重矩阵W,w.隐含层主要确定激活函数.这里我们采用整流线性激活函数:g(z)=max{0,z}
初始化以下矩阵:
输入层到隐含层的权重矩阵:
偏移量为:
隐含层到输出层的权重矩阵:
偏移量为:
b2=0
Image(filename="./data/12.png",width=500)
2.Tensorflow实现XOR
a).明确输入数据,目标数据
b)确定网络架构
c)确定几个函数
激活函数还是使用ReLU函数,代价函数使用MSE,优化器使用Adam自适应算法
d).初始化权重和偏移量等参数
初始化权重和偏移量,只有随机取些较小值即可,无须考虑一些特殊值,最终这些权重值或偏移量,会在循环迭代中不断更新.随机生成权重初始化数据,生成的数据符合正态分布
e)源代码
import tensorflow as tf
import numpy as np
# 定义输入与目标值
X=np.array([[0,0],[0,1],[1,0],[1,1]])
Y=np.array([[0],[1],[1],[0]])
# 定义占位符
x=tf.placeholder(tf.float32,[None,2])
y=tf.placeholder(tf.float32,[None,1])
# 初始化权重
w1=tf.Variable(tf.random_normal([2,2]))
w2=tf.Variable(tf.random_normal([2,1]))
# 定义偏移量
b1=tf.Variable([0.1,0.1])
b2=tf.Variable(0.1)
# 激活函数
h=tf.nn.relu(tf.matmul(x,w1)+b1)
# 输出层
out=tf.matmul(h,w2)+b2
# 定义代价函数
loss=tf.reduce_mean(tf.square(out-y))
# 利用Adam自适应优化函数
train=tf.train.AdamOptimizer(0.15).minimize(loss)
with tf.Session() as session:
session.run(tf.global_variables_initializer())
for i in range(2000):
session.run(train,feed_dict={x:X,y:Y})
loss_=session.run(loss,feed_dict={x:X,y:Y})
if i%200==0:
print("Step:%d,Loss:%.3f"%(i,loss_))
print("X:%r"%X)
print("Pred:%r"%session.run(out,feed_dict={x:X}))
Step:0,Loss:0.277
Step:200,Loss:0.000
Step:400,Loss:0.000
Step:600,Loss:0.000
Step:800,Loss:0.000
Step:1000,Loss:0.000
Step:1200,Loss:0.000
Step:1400,Loss:0.000
Step:1600,Loss:0.000
Step:1800,Loss:0.000
X:array([[0, 0],
[0, 1],
[1, 0],
[1, 1]])
Pred:array([[-8.351956e-04],
[ 9.974783e-01],
[ 9.967382e-01],
[-8.351956e-04]], dtype=float32)