PyTorch_CNN网络搭建_MNIST数据集

上一篇文章搭建了一个简单的神经网络来检测MNIST数据集,今天搭建了一个CNN网络,同样来检测MNIST数据集,下面通过分析代码来记录一下我搭建过程中遇到的问题。

除了网络搭建部分代码外,其余代码与上次代码基本一致。
简单神经网络搭建:PyTorch_简单神经网络搭建_MNIST数据集

1.导入模块

import torch
import torchvision
import numpy as np

#导入图像数据处理函数
from torchvision import datasets,transforms
from torchvision.datasets import mnist
from torch.utils.data import DataLoader

#导入可视化图像函数
import matplotlib.pyplot as plt 

#导入神经网络构建工具
import torch.nn as nn
import torch.optim as optim

2.定义用到的参数

#定义后面要用到的参数
train_batch_size = 512
test_batch_size = 512
#learning_rate = 0.1
num_epoches = 5

定义参数没有用到学习率,因为优化器使用的是Adma。

3.下载数据并对数据进行预处理

#先定义预处理函数
#注意这里由于数据集是灰度图,所以正则化时只有一个通道(R G B),
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5],[0.5])])

#下载minst数据集,注意只在训练集中就下载了,测试集那里download定义为False(默认为False,一般默认就直接不写就行)
data_train = mnist.MNIST('./data', train=True, transform=transform, target_transform=None, download=True)
data_test = mnist.MNIST('./data', train=False, transform=transform, target_transform=None, download=False)

#数据集下载完成后。就要对数据进行装载,利用batch _size来确认每个包的大小,用Shuffle来确认打乱数据集的顺序。
train_loader = DataLoader(data_train, batch_size=train_batch_size, shuffle=True)
test_loader = DataLoader(data_test,batch_size=test_batch_size,shuffle=True)

4.可视化图像

#选取一个区域的数据进行预览
import matplotlib.pyplot as plt
#%matplotlib inline是一个魔法函数(Magic Functions)。
#官方给出的定义是:IPython有一组预先定义好的所谓的魔法函数(Magic Functions)
#你可以通过命令行的语法形式来访问它们。
#使用%matplotlib命令可以将matplotlib的图表直接嵌入到Notebook之中,或者使用指定的界面库显示图表,
#它有一个参数指定matplotlib图表的显示方式。inline表示将图表嵌入到Notebook中。
%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.CNN网络搭建

class CNN(nn.Module):
    def __init__(self):
        super(CNN,self).__init__()
        
        self.conv1 = nn.Sequential(
            #卷积后的图像size:[(W-F+2P)/S + 1 ] * [(W-F+2P)/S + 1] * M
            #F = 3, S = 1, P = 1(保持feature map大小不变)
            nn.Conv2d(1,10, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(10,20,kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            #池化后的图像size:[(W-F)/S + 1 ] * [(W-F)/S + 1] * M
            #F = 2, S = 2(feature map大小减半,channel不变)
            nn.MaxPool2d(kernel_size=2, stride=2),
        )
        
        self.dense = nn.Sequential(
            nn.Linear(14*14*20, 100),
            nn.ReLU(),
            nn.Dropout(p=0.5),
            nn.Linear(100,10),
        )
        
    def forward(self,x):
            x = self.conv1(x)
           # x = view(img.size(0),-1)
            x = x.view(-1,14*14*20)
            out = self.dense(x)
            return out
        
#用CPU运算,参数一定不能设置的太多!!!

注意搭建时可以按照自己的想法搭建,不必照搬,参数不要设置太多,不然程序会一直运行一直算一直没有输出!!!其中卷积层、池化层可以自己定义(比如多定义几个池化,多定义几个卷积),只要相互连接的数据尺寸大小没错就可以。

注意进入Linear()前要设置x的维度/尺寸,确保匹配!!!
还要注意卷积或者池化后的数据尺寸公式:

卷积后的图像size:[(W-F+2P)/S + 1 ] * [(W-F+2P)/S + 1] * M
F = 3, S = 1, P = 1(保持feature map大小不变)

池化后的图像size:[(W-F)/S + 1 ] * [(W-F)/S + 1] * M
F = 2, S = 2(feature map大小减半,channel不变)

6.定义模型

#定义模型
model = CNN()
#损失函数
criterion = nn.CrossEntropyLoss()
#优化器
optimizer = optim.Adam(model.parameters())
print(model)

打印出模型结构:
CNN(
(conv1): Sequential(
(0): Conv2d(1, 10, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU(inplace=True)
(2): Conv2d(10, 20, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): ReLU(inplace=True)
(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(dense): Sequential(
(0): Linear(in_features=3920, out_features=100, bias=True)
(1): ReLU()
(2): Dropout(p=0.5, inplace=False)
(3): Linear(in_features=100, out_features=10, bias=True)
)
)

7.训练并输出准确率

#开始训练 先定义存储损失函数和准确率的数组
losses = []
acces = []
#测试用
eval_losses = []
eval_acces = []
#训练模型
for epoch in range(num_epoches):
    
    train_loss = 0
    train_acc = 0
    #将模型设置为训练模式
    model.train()
    
    for data in train_loader:
        
        img,label = data
       # img,label = Variable(img),Variable(label)
        
        
        #print(img.size())
        #print('--')
        
        out = model(img)
       
        loss = criterion(out,label)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        train_loss += loss
        
        _,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:
        out = model(img)
        loss = criterion(out,label)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        eval_loss += loss
        
        _,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.6811,Train Acc:0.7999,Test Loss:0.1623,Test Acc:0.9505
epoch:1,Train Loss:0.1976,Train Acc:0.9426,Test Loss:0.0714,Test Acc:0.9778
epoch:2,Train Loss:0.1269,Train Acc:0.9632,Test Loss:0.0503,Test Acc:0.9836
epoch:3,Train Loss:0.1013,Train Acc:0.9705,Test Loss:0.0404,Test Acc:0.9864
epoch:4,Train Loss:0.0858,Train Acc:0.9742,Test Loss:0.0335,Test Acc:0.9889

end

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值