用BP神经网络解决异或问题
初步的神经网络入门分为三篇
1:神经网络简析
这一篇主要是讲解一下关于用BP神经网络解决异或问题
对于我们的输入
[0,0],[0,1],[1,0],[1,1]
对于我们的输出
0或1
这里我们需要借用上一篇文章的一张图片
构建双层神经网络
#导入numpy
import numpy as np
#先定义训练数据
train_X = np.array([[0,0],[0,1],[1,0],[1,1]])
train_Y = np.array([0,1,1,0])
#线性连接层
class LinearLayer:
def __init__(self, input_D, output_D):
self._W = np.random.normal(0, 0.1, (input_D, output_D))#权值
self._b = np.random.normal(0, 0.1, (1,output_D))#偏置
self._grad_W = np.zeros((input_D,output_D))#权值梯度
self._grad_b = np.zeros((1,output_D))#偏置梯度
def forward(self, X):
return np.matmul(X, self._W) + self._b#前馈传播时,计算每个变量输出
#逆向传播,计算梯度,更新权重和偏置
def backward(self, X, grad):
self._grad_W = np.matmul(X.T, grad)#权值梯度计算
self._grad_b = np.matmul(grad.T, np.ones(X.shape[0]))#偏置梯度计算
return np.matmul(grad, self._W.T)#这里是根据矩阵计算的,所以行和列必须匹配
#更新权值和偏置,learn_rate是学习率
def update(self, learn_rate):
self._W = self._W - self._grad_W * learn_rate
self._b = self._b - self._grad_b * learn_rate
#规则P其实可以是Sigmoid函数
class P:
def __init__(self):
pass
def forward(self, X):
return np.where(X < 0, 0, X)
def backward(self, X, grad):
return np.where(X>0, X, 0) * grad
#创建线性关系1,激活函数,线性关系2
linear1 = LinearLayer(2,3)
p = P()
linear2 = LinearLayer(3,1)
#神经网络模型
model = [linear1, p, linear2]
#预测函数
def predict(model, X):
tmp = X
for layer in model:
tmp = layer.forward(tmp)
return np.where(tmp > 0.5, 1, 0)
print("----------")
result = predict(model, train_X)
#最小均方误差
def MSEloss(train_Y, y):
assert train_Y.shape == y.shape
return np.linalg.norm(train_Y - y) ** 2
#训练网络
for i in range(50000):
#先来前向传播,获取每个值
o0 = train_X
a1 = linear1.forward(o0)
o1 = p.forward(a1)
a2 = linear2.forward(o1)
o2 = a2
#根据前馈算法,来计算loss
y = o2.reshape(o2.shape[0])
loss = MSEloss(train_Y, y)
#反向传播更新参数
grad = (y-train_Y).reshape(result.shape[0], 1)
grad = linear2.backward(o1,grad)
grad = p.backward(a1, grad)
grad = linear1.backward(o0, grad)
learn_rate = 0.001
#更新参数
linear1.update(learn_rate)
linear2.update(learn_rate)
#判断学习是否完成
if i% 200 == 0:
print(loss)
if loss < 0.001:
print("训练完成")
break
print("预测数据1")
print(train_X)
print("预测结果")
print(result)
我们这里可以看到的,除了numpy,其他的都没用,上面这个代码只是让我们更清楚BP算法过程。
甚至MSEloss都是自己写的。不过没有必要,其实pytorch都已经有现成的,我们可以直接用就是
下面就来看看pytorch版本
import torch.nn as nn
import torch.optim as optim
import torch
from torch.autograd import Variable
import numpy as np
#
#
#pytorch
#
#
#先定义训练数据
train_X = np.array([[0,0],[0,1],[1,0],[1,1]])
train_Y = np.array([[0],[1],[1],[0]])
#准备数据
x = torch.from_numpy(train_X).type(torch.FloatTensor)
y = torch.from_numpy(train_Y).type(torch.FloatTensor)
print(x)
print(y)
x = Variable(x)
y = Variable(y)
#模型
class BpNet(nn.Module):
def __init__(self, n_input, n_hiden, n_output):
super(BpNet, self).__init__()
#两层线性模型2-》3-》1
self.hidden = nn.Linear(n_input, n_hiden)
self.out = nn.Linear(n_hiden, n_output)
def forward(self, x):
# x = nn.functional.sigmoid(x)
# x = self.hidden(x)
# x = self.out(nn.functional.sigmoid(x))
#这里使用relu激活函数,没有使用sigmoid
x = self.hidden(x)
x = self.out(nn.functional.relu(x))
return x
#创建模型,两层神经网络
net = BpNet(n_input=2, n_hiden=3, n_output=1)
print(net)
#损失函数
criterion = nn.MSELoss()
#优化器
optimizer = optim.SGD(net.parameters(), lr=0.08)
# plt.ion()
for t in range(10000):
out = net(x)
loss = criterion(out, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(loss)
print(out.size())
print(y.size())
print(out)
print(y)
训练结果,发现有两个接近于0,其他的为1