前一阶段一直在准备毕业论文和软设的考试,终于忙完了,接着学习PyTorch,这篇博客主要讲述,如何利用PyTorch搭建简单的CNN网络来识别mnist数据集。
搭建CNN网络的主要步骤如下:
1、导入库文件
2、数据处理
3、下载数据集
4、构建DataLoader
5、构建模型
6、构建损失
7、构建优化器
8、训练模型
9、测试模型
这也是我这一篇文章的目录,这也是pytorch搭建模型的一个基本流程。
import torch
import numpy
from torchvision import transforms#处理图像
from torchvision import datasets#处理数据集
from torch.utils.data import DataLoader#加载数据集
import torch.nn.functional as F #导入激活函数
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
#进行图像处理函数
transform = transforms.Compose([
transforms.ToTensor(),#转化成Tensor
transforms.Normalize((0.1307,),(0.3081,))#归一化处理 (x-u)/s
])
关于数据处理这一模块,自己还不是很理解,之后可能会写一写关于transforms的一些知识点。
pytorch提供了下载数据集的接口,可以利用datasets直接下载数据集。
#利用DataLoader下载数据集
train_dataset = datasets.MNIST(
root='../dataset/mnist',#下载之后保存的文件路径
download=False,#是否下载
train=True,#是否是训练集
transform = transform#对数据及逆行处理
)
test_dataset = datasets.MNIST(
root='../dataset/mnist',
download=False,
train=False,
transform= transform
)
关键点在于传入四个参数,root,download,train,tranform,分别代表数据保存文件路径、是否下载(若本地没有数据集,传入值为True)、是否是训练集、数据处理方式。
根据上一步的dataset数据集构造DataLoader,代码如下,这些操作都是固定的,以后训练其他数据也是这种模式。
#利用datasets构造数据集
#规范化之后的训练集
train_loader = DataLoader(
dataset=train_dataset,
batch_size=64,
shuffle=True
)
#规范化之后的测试集
test_loader = DataLoader(
dataset=test_dataset,
batch_size=64,
shuffle=True
)
构建完DataLoader之后,就可以任意加载一张图片,看看效果是什么样的。
#显示数据集
for i, (images, labels) in enumerate(train_loader):
print(i)#下标
print(images)#64个图片 是1*64*28*28
print(labels)#64个图片对应的label 1*64
plt.imshow(images[1].resize(28,28))
plt.show()
break
这段代码中,最最最最重要的就是在面对一个不知道的数据集时,如何知道它的大小是什么样的,train_loader是由image和label两个数据构成,打印结果如下:
label的值如下图所示。
在做完这些准备工作之后,就可以构建CNN网络模型,采用两层卷积层,卷积核采用10*1*5*5和20*10*5*5,池化层采用最大池化,最后在拼接一个全连接层。
#构建CNN模型
class Net(torch.nn.Module):
def __init__(self):
super(Net,self).__init__()
self.conv1 = torch.nn.Conv2d(1,10,kernel_size=5)
self.conv2 = torch.nn.Conv2d(10,20,kernel_size=5)
self.pooling = torch.nn.MaxPool2d(2)
self.fc1 = torch.nn.Linear(320,10)
def forward(self,x):
#每次训练取多少元素
batch_size = x.size(0)
#先做Relu在做pooling
x = self.pooling(F.relu(self.conv1(x)))
x = self.pooling(F.relu(self.conv2(x)))
x = x.view(batch_size,-1)
x = self.fc1(x)
return x
model = Net()
criterion = torch.nn.CrossEntropyLoss()
注意点:当采用这个损失函数时,不要再构建网络最后加上softmax函数
#构建优化器
optimizer = torch.optim.SGD(model.parameters(),lr=0.01,momentum=0.5)
def train(epoch):
running_loss = 0
#batch_idx batch的下标
#datas 数据,1*batch_size*28*28 label
for batch_idx,datas in enumerate(train_loader,0):
inputs,targets = datas
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs,targets)
loss.backward()
optimizer.step()
running_loss += loss.item()
#输出300次的平均损失
if batch_idx % 300 == 299:
print('[%d,%5d] loss:%.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
running_loss = 0
代码中最后部分是每计算300次的batch就输出300次平均的loss,这样便于查看模型的训练情况。
#测试模型
def test():
correct = 0
total = 0
with torch.no_grad():
for data in test_loader:
image,label = data
output = model(image)
# _代表最大的元素 pre代表索引 索引本质就代表了预测元素值
_,pre = torch.max(output.data,dim=1)
total += label.size(0)
correct += (pre==label).sum().item()
print('准确率为:%d %%'%(100*correct/total))
看了这个代码,觉得别人写的代码模型是真的好,我自己肯定写不来这样的代码,先模仿,再创新吧!
所有的代码整合:
import torch
import numpy
from torchvision import transforms#处理图像
from torchvision import datasets#处理数据集
from torch.utils.data import DataLoader#加载数据集
import torch.nn.functional as F #导入激活函数
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
#进行图像处理函数
transform = transforms.Compose([
transforms.ToTensor(),#转化成Tensor
transforms.Normalize((0.1307,),(0.3081,))#归一化处理 (x-u)/s
])
#利用DataLoader下载数据集
train_dataset = datasets.MNIST(
root='../dataset/mnist',#下载之后保存的文件路径
download=False,#是否下载
train=True,#是否是训练集
transform = transform#对数据及逆行处理
)
test_dataset = datasets.MNIST(
root='../dataset/mnist',
download=False,
train=False,
transform= transform
)
#利用datasets构造数据集
#规范化之后的训练集
train_loader = DataLoader(
dataset=train_dataset,
batch_size=64,
shuffle=True
)
#规范化之后的测试集
test_loader = DataLoader(
dataset=test_dataset,
batch_size=64,
shuffle=True
)
# #显示数据集
# for i, (images, labels) in enumerate(train_loader):
# print(i)#下标
# print(images)#64个图片 是1*64*28*28
# print(labels)#64个图片对应的label 1*64
# plt.imshow(images[1].resize(28,28))
# plt.show()
# break
#构建CNN模型
class Net(torch.nn.Module):
def __init__(self):
super(Net,self).__init__()
self.conv1 = torch.nn.Conv2d(1,10,kernel_size=5)
self.conv2 = torch.nn.Conv2d(10,20,kernel_size=5)
self.pooling = torch.nn.MaxPool2d(2)
self.fc1 = torch.nn.Linear(320,10)
def forward(self,x):
#每次训练取多少元素
batch_size = x.size(0)
#先做Relu在做pooling
x = self.pooling(F.relu(self.conv1(x)))
x = self.pooling(F.relu(self.conv2(x)))
x = x.view(batch_size,-1)
x = self.fc1(x)
return x
#构建模型
model = Net()
#构建损失
criterion = torch.nn.CrossEntropyLoss()
#构建优化器
optimizer = torch.optim.SGD(model.parameters(),lr=0.01,momentum=0.5)
#训练模型
#用所有数据训练10次
def train(epoch):
running_loss = 0
#batch_idx batch的下标
#datas 数据,1*batch_size*28*28 label
for batch_idx,datas in enumerate(train_loader,0):
inputs,targets = datas
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs,targets)
loss.backward()
optimizer.step()
running_loss += loss.item()
#输出300次的平均损失
if batch_idx % 300 == 299:
print('[%d,%5d] loss:%.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
running_loss = 0
#测试模型
def test():
correct = 0
total = 0
with torch.no_grad():
for data in test_loader:
image,label = data
output = model(image)
# _代表最大的元素 pre代表索引 索引本质就代表了预测元素值
_,pre = torch.max(output.data,dim=1)
total += label.size(0)
correct += (pre==label).sum().item()
print('准确率为:%d %%'%(100*correct/total))
if __name__ == '__main__':
for epoch in range(3):
#训练一次全部的数据 就测试一次准确率
train(epoch)
test()
训练结果如下:
综上所述,模型的预测结果已经不错。接下来开始学习比较经典的网络模型。