PyTorch搭建全连接神经网络求解二分类问题
在求解线性回归问题的时候,我们已经学习了如何使用梯度下降算法来不断更新权重矩阵,使误差函数不断减小,这一节我们将使用PyTorch搭建一个简单的神经网络来求解二分类问题。
本文的Jupyter Notebook代码可以在这里找到。文末也附上了可以运行的.py文件的代码
import numpy as np
import matplotlib.pyplot as plt
import torch
from sklearn.datasets import make_circles
生成训练集
X,Y=make_circles(n_samples=1000,factor=0.2,noise=0.1) #生成二维平面上的一些点,和这些点的标签
print("X shape:",X.shape)
plt.scatter(X[:,0],X[:,1],c=Y) #查看生成的数据
X shape: (1000, 2)
<matplotlib.collections.PathCollection at 0x18fd706e5e0>
构建神经网络
我们要搭建的神经网络如下图:
其中中间的一层(即隐藏层)的激活函数为Relu函数。
class neural_net(torch.nn.Module): #继承torch.nn.Module构建自己的网络
def __init__(self):
super(neural_net, self).__init__()
self.layer1 = torch.nn.Linear(2, 4) #隐藏层
# self.layer2 = torch.nn.Linear(4, 4) #这里还可以再加一个隐藏层,调试的时候可以试试把这行注释取消了,看看训练效果怎样
self.layer_out = torch.nn.Linear(4, 2) #输出层
def forward(self, input):
#第一个隐藏层
out = self.layer1(input)
out = torch.relu(out) #隐藏层的激活函数设置成Relu函数
# #第二个隐藏层
# out = self.layer2(out)
# out = torch.relu(out)
#输出层
out = self.layer_out(out) #输出层直接输出
return out
net = neural_net() #从自己的网络实例化一个对象
print(net) #查看网络信息
neural_net(
(layer1): Linear(in_features=2, out_features=4, bias=True)
(layer_out): Linear(in_features=4, out_features=2, bias=True)
)
格式化数据
把numpy格式的数组转换成torch格式的张量
X = torch.from_numpy(X).type(torch.FloatTensor)
Y = torch.from_numpy(Y).type(torch.LongTensor)
取消下面的注释可以把神经网络和数据搬到GPU上训练,如何配置GPU可以参考这篇文章
#net.cuda()
#X = X.cuda()
#Y = Y.cuda()
print("X.device:", X.device) #查看数据在CPU上还是GPU上
print("Y.device:", Y.device)
X.device: cpu
Y.device: cpu
开始训练
import time
optimizer = torch.optim.SGD(net.parameters(), lr = 0.03) #设置梯度下降的算法为SGD算法,学习率为0.03。SGD使随机梯度下降
loss_func = torch.nn.CrossEntropyLoss() #设置损失函数为交叉熵函数
t0 = time.time_ns()
#跑5000步梯度下降
loss = 0
for i in range(5000):
Y_hat = net(X) #前馈过程
loss = loss_func(Y_hat, Y) #计算损失函数
#反向传播计算梯度并更新权重
optimizer.zero_grad()
loss.backward()
optimizer.step()
#每隔1000步打印一下loss的值
if i%1000 == 0:
print("step=",i, "loss=", loss.data.item())
t1 = time.time_ns()
print("in the end loss=", loss.data.item())
print("running time=%dms" %((t1-t0)/1000000))
step= 0 loss= 0.7381522059440613
step= 1000 loss= 0.27246278524398804
step= 2000 loss= 0.06931144744157791
step= 3000 loss= 0.031707875430583954
step= 4000 loss= 0.020208552479743958
in the end loss= 0.01475528534501791
running time=3519ms
查看训练结果
生成一些均匀分布在测试集范围内的点,直观的看到哪些区域的点会被分成哪一类
X = 2*np.random.rand(1000, 2) - 1
X = torch.from_numpy(X).type(torch.FloatTensor)
Y = net.forward(X).detach().numpy() #前馈计算输出
Y_color = []
for y in Y:
Y_color.append(0 if y[0] > y[1] else 1)
plt.scatter(X.T[0], X.T[1], c=Y_color)
<matplotlib.collections.PathCollection at 0x18fd713fcd0>
生成测试集,看看训练好的模型在测试集上的表现怎样(loss值)
X,Y=make_circles(n_samples=1000,factor=0.2,noise=0.16) #生成测试集,相比训练集,这里噪声调的稍大了一些
X = torch.from_numpy(X).type(torch.FloatTensor)
Y = torch.from_numpy(Y).type(torch.LongTensor)
Y_hat = net.forward(X) #前馈计算测试集的输出
loss = loss_func(Y_hat, Y) #查看测试集上的loss值
print("loss on test:",loss.data.item())
#图形化
Y_color = []
for y in Y_hat.detach().numpy():
Y_color.append(0 if y[0] > y[1] else 1)
plt.scatter(X[:,0],X[:,1],c=Y_color)
loss on test: 0.0439218208193779
<matplotlib.collections.PathCollection at 0x18fd72ed880>
全部代码
上面的代码可以依次复制到Jupyter Notebook上运行,下面的代码可以在py文件里运行
import numpy as np
import matplotlib.pyplot as plt
import torch
from sklearn.datasets import make_circles
import time
class neural_net(torch.nn.Module): #继承torch.nn.Module构建自己的网络
def __init__(self):
super(neural_net, self).__init__()
self.layer1 = torch.nn.Linear(2, 4) #隐藏层
# self.layer2 = torch.nn.Linear(4, 4) #这里还可以再加一个隐藏层,调试的时候可以试试把这行注释取消了,看看训练效果怎样
self.layer_out = torch.nn.Linear(4, 2) #输出层
def forward(self, input):
#第一个隐藏层
out = self.layer1(input)
out = torch.relu(out) #隐藏层的激活函数设置成Relu函数
# #第二个隐藏层
# out = self.layer2(out)
# out = torch.relu(out)
#输出层
out = self.layer_out(out) #输出层直接输出
return out
def make_train_data():
X,Y=make_circles(n_samples=1000,factor=0.2,noise=0.1) #生成二维平面上的一些点,和这些点的标签
plt.scatter(X[:,0],X[:,1],c=Y) #查看生成的数据
X = torch.from_numpy(X).type(torch.FloatTensor)
Y = torch.from_numpy(Y).type(torch.LongTensor)
return X, Y
def train(X, Y, net):
optimizer = torch.optim.SGD(net.parameters(), lr = 0.03) #设置梯度下降的算法为SGD算法,学习率为0.03。SGD使随机梯度下降
global loss_func
loss_func = torch.nn.CrossEntropyLoss() #设置损失函数为交叉熵函数
t0 = time.time_ns()
loss = 0
for i in range(5000):
Y_hat = net(X) #前馈过程
loss = loss_func(Y_hat, Y) #计算损失函数
#反向传播计算梯度并更新权重
optimizer.zero_grad()
loss.backward()
optimizer.step()
#每隔1000步打印一下loss的值
if i%1000 == 0:
print("step=",i, "loss=", loss.data.item())
t1 = time.time_ns()
return loss.data.item(), t1-t0
def show_result1():
X,Y=make_circles(n_samples=1000,factor=0.2,noise=0.16) #生成测试集,相比训练集,这里噪声调的稍大了一些
X = torch.from_numpy(X).type(torch.FloatTensor)
Y = torch.from_numpy(Y).type(torch.LongTensor)
Y_hat = net.forward(X) #前馈计算测试集的输出
loss = loss_func(Y_hat, Y) #查看测试集上的loss值
print("loss on test:",loss.data.item())
#图形化
Y_color = []
for y in Y_hat.detach().numpy():
Y_color.append(0 if y[0] > y[1] else 1)
plt.scatter(X[:,0],X[:,1],c=Y_color)
def show_result2():
X = 2*np.random.rand(1000, 2) - 1
X = torch.from_numpy(X).type(torch.FloatTensor)
Y = net.forward(X).detach().numpy() #前馈计算输出
Y_color = []
for y in Y:
Y_color.append(0 if y[0] > y[1] else 1)
plt.scatter(X.T[0], X.T[1], c=Y_color)
global train_X, train_Y #训练集
global net #神经网络
global loss_func #损失函数
if __name__ == "__main__":
#生成测试集
plt.subplot(1,3,1)
plt.title("train data")
train_X, train_Y = make_train_data()
#创建神经网络
net = neural_net()
print(net) #查看网络信息
#开始训练
loss, t = train(train_X, train_Y, net)
print("in the end loss=", loss)
print("running time=%dms" %(t/1000000))
#显示训练结果1
plt.subplot(1,3,2)
plt.title("test data")
show_result1()
#显示训练结果2
plt.subplot(1,3,3)
plt.title("for all point")
show_result2()
plt.show()