今天用PyTorch参考《Python深度学习基于PyTorch》搭建了一个简单的神经网络,在这里做一下笔记。
首先附上PyTorch中文文档链接,下面的各接口函数在这里面基本都能查到,宝藏文档,对于像我一样的新手菜鸟特别友好,强推!!!
PyTorch中文文档链接
正文开始:
这是本次搭建神经网络的结构图
此网络包含两个隐藏层,激活函数都为relu函数,最后用torch.max(out,1)找出张量out最大值索引作为预测值。
下面不废话了,直接代码实现
1. 先导入必要的模块
import numpy as np
import torch
#导入PyTorch内置的mnist数据
from torchvision.datasets import mnist
#导入预处理模块
from torchvision import transforms
from torch.utils.data import DataLoader
#导入神经网络工具
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import DataLoader:
该接口主要用来将自定义的数据读取接口的输出或者PyTorch已有的数据读取接口的输入按照batch size封装成Tensor。
2. 定义超参数
#定义后面要用到的超参数
train_batch_size = 64
test_batch_size = 128
#学习率与训练次数
learning_rate = 0.01
nums_epoches = 20
#优化器的时候使用的参数
lr = 0.1
momentum = 0.5
batch_size:相当于每次导入训练的样本量大小(相比较于一次导入完,一次导入一张,需要设置一个合适的量)一般高级算法要注意设置量,简单神经网络不用太过在意。
3.下载数据并对数据进行预处理
#用compose来定意预处理函数
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5],[0.5])])
#下载数据,在工程文件夹里新建一个data文件夹储存下载的数据
train_dataset = mnist.MNIST('./data', train=True, transform=transform, target_transform=None, download=True)
test_dataset = mnist.MNIST('./data', train=False, transform=transform, target_transform=None, download=False)
#数据加载器,组合数据集和采样器,并在数据集上提供单进程或多进程迭代器
train_loader = DataLoader(train_dataset, batch_size=train_batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=test_batch_size, shuffle=False)
把预处理需要用到的东西组合在Compose里面。
transforms.ToTensor()是把一个取值范围是[0,255]的PIL.Image或者shape为(H,W,C)的numpy.ndarray,转换成形状为[C,H,W],取值范围是[0,1.0]的torch.FloadTensor。(这句话我的理解是把数据格式转换成网络里可以使用的数据格式)
transforms.Normalize则是将灰度图像正则化。
4.可视化数据
import matplotlib.pyplot as plt
%matplotlib inline
examples = enumerate(test_loader)
batch_idx,(example_data,example_targets) = next(examples)
fig = plt.figure()
for i in range(6):
plt.subplot(2,3,i+1)
plt.tight_layout()
plt.imshow(example_data[i][0],cmap='gray',interpolation='none')
plt.title("Ground Truth:{}".format(example_targets[i]))
plt.xticks([])
plt.yticks([])
数据可视化这部分我没有仔细看,直接把代码列出,以后如果之后再用到的时候我再单独写一个笔记。
下面是可视化后的结果:
5.构建模型
class CNN(nn.Module):
def __init__(self,in_dim,hidden_1,hidden_2,out_dim):
super(CNN,self).__init__()
self.layer1 = nn.Sequential(nn.Linear(in_dim, hidden_1, bias=True),nn.BatchNorm1d(hidden_1))
self.layer2 = nn.Sequential(nn.Linear(hidden_1,hidden_2,bias=True),nn.BatchNorm1d(hidden_2))
self.layer3 = nn.Sequential(nn.Linear(hidden_2,out_dim))
def forward(self,x):
#注意 F 与 nn 下的激活函数使用起来不一样的
x = F.relu(self.layer1(x))
x = F.relu(self.layer2(x))
x = self.layer3(x)
return x
class torch.nn.Sequential(* args):一个时序容器,Modules 会以他们传入的顺序被添加到容器中,当然,也可以传入一个。
这里我把输入维度input_dim理解为一张图片像素点的个数
**注:**我敲的时候还不知道CNN 跟简单神经网络的区别,所以把这个类名定义为CNN了,大家在实现的时候可以定义为Net。
6.实例化网络
#实例化网络,只考虑使用CPU
model = CNN(28*28,300,100,10)
#定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
#momentum:动量因子有什么用处?
optimizer = optim.SGD(model.parameters(),lr=lr,momentum=momentum)
class torch.nn.CrossEntropyLoss(weight=None, size_average=True):此标准将LogSoftMax和NLLLoss集成到一个类中。当训练一个多类分类器的时候,这个方法是十分有用的。
criterion = nn.CrossEntropyLoss()的参数:
7.训练模型
#开始训练 先定义存储损失函数和准确率的数组
losses = []
acces = []
#测试用
eval_losses = []
eval_acces = []
for epoch in range(nums_epoches):
#每次训练先清零
train_loss = 0
train_acc = 0
#将模型设置为训练模式
model.train()
#动态学习率
if epoch%5 == 0:
optimizer.param_groups[0]['lr'] *= 0.1
for img,label in train_loader:
#例如 img=[64,1,28,28] 做完view()后变为[64,1*28*28]=[64,784]
#把图片数据格式转换成与网络匹配的格式
img = img.view(img.size(0),-1)
#前向传播,将图片数据传入模型中
# out输出10维,分别是各数字的概率,即每个类别的得分
out = model(img)
#这里注意参数out是64*10,label是一维的64
loss = criterion(out,label)
#反向传播
#optimizer.zero_grad()意思是把梯度置零,也就是把loss关于weight的导数变成0
optimizer.zero_grad()
loss.backward()
#这个方法会更新所有的参数,一旦梯度被如backward()之类的函数计算好后,我们就可以调用这个函数
optimizer.step()
#记录误差
train_loss += loss.item()
#计算分类的准确率,找到概率最大的下标
_,pred = out.max(1)
num_correct = (pred == label).sum().item()#记录标签正确的个数
acc = num_correct/img.shape[0]
train_acc += acc
losses.append(train_loss/len(train_loader))
acces.append(train_acc/len(train_loader))
eval_loss = 0
eval_acc = 0
model.eval()
for img,label in test_loader:
img = img.view(img.size(0),-1)
out = model(img)
loss = criterion(out,label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
eval_loss += loss.item()
_,pred = out.max(1)
num_correct = (pred == label).sum().item()
acc = num_correct/img.shape[0]
eval_acc += acc
eval_losses.append(eval_loss/len(test_loader))
eval_acces.append(eval_acc/len(test_loader))
print('epoch:{},Train Loss:{:.4f},Train Acc:{:.4f},Test Loss:{:.4f},Test Acc:{:.4f}'
.format(epoch,train_loss/len(train_loader),train_acc/len(train_loader),
eval_loss/len(test_loader),eval_acc/len(test_loader)))
这是训练后的输出:
epoch:0,Train Loss:0.3494,Train Acc:0.9190,Test Loss:0.1510,Test Acc:0.9550
epoch:1,Train Loss:0.1290,Train Acc:0.9644,Test Loss:0.1037,Test Acc:0.9687
epoch:2,Train Loss:0.0882,Train Acc:0.9756,Test Loss:0.0848,Test Acc:0.9744
epoch:3,Train Loss:0.0676,Train Acc:0.9818,Test Loss:0.0686,Test Acc:0.9778
epoch:4,Train Loss:0.0535,Train Acc:0.9853,Test Loss:0.0569,Test Acc:0.9824
epoch:5,Train Loss:0.0385,Train Acc:0.9906,Test Loss:0.0308,Test Acc:0.9906
epoch:6,Train Loss:0.0345,Train Acc:0.9920,Test Loss:0.0306,Test Acc:0.9911
epoch:7,Train Loss:0.0321,Train Acc:0.9930,Test Loss:0.0301,Test Acc:0.9916
epoch:8,Train Loss:0.0324,Train Acc:0.9931,Test Loss:0.0293,Test Acc:0.9919
epoch:9,Train Loss:0.0304,Train Acc:0.9937,Test Loss:0.0288,Test Acc:0.9921
epoch:10,Train Loss:0.0302,Train Acc:0.9935,Test Loss:0.0282,Test Acc:0.9925
epoch:11,Train Loss:0.0294,Train Acc:0.9937,Test Loss:0.0274,Test Acc:0.9929
epoch:12,Train Loss:0.0289,Train Acc:0.9938,Test Loss:0.0274,Test Acc:0.9931
epoch:13,Train Loss:0.0294,Train Acc:0.9941,Test Loss:0.0274,Test Acc:0.9930
epoch:14,Train Loss:0.0286,Train Acc:0.9944,Test Loss:0.0280,Test Acc:0.9925
epoch:15,Train Loss:0.0289,Train Acc:0.9939,Test Loss:0.0279,Test Acc:0.9924
epoch:16,Train Loss:0.0287,Train Acc:0.9939,Test Loss:0.0277,Test Acc:0.9925
epoch:17,Train Loss:0.0290,Train Acc:0.9937,Test Loss:0.0272,Test Acc:0.9929
epoch:18,Train Loss:0.0295,Train Acc:0.9938,Test Loss:0.0277,Test Acc:0.9924
epoch:19,Train Loss:0.0285,Train Acc:0.9942,Test Loss:0.0275,Test Acc:0.9932
8.可视化训练及测试损失值
plt.title('trainloss')
plt.plot(np.arange(len(losses)),losses)
plt.legend(['Train Loss'],loc='upper right')
可视化训练次数于损失函数值的关系:
end
第一次在CSDN上写笔记,希望可以坚持,慢慢成长。