pytorch实战图像分类-mnist手写数字数据集

前言

用了太多的现成的网络结构,感觉自己在深度学习这一块只会用别人的结构,对模型的搭建啥的这一块都没多大经验,所以写下这篇博客,记录下自己尝试搭建模型的开始。

代码解析

1.我们用的是pytorch深度学习框架,数据集就用经典的mnist数据集。首先导入包
import numpy as np
import torch
#导入pytorch内置mnist数据
from torchvision.datasets import mnist
#导入数据预处理模块
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
#导入nn及优化器
import torch.nn.functional as F
import torch.optim as optim
from torch import nn
import matplotlib.pyplot as plt
#这是可视化模型结构的
from fvcore.nn import parameter_count_table

2.定义一些超参数

#定义超参数
#批次量
train_batch_size=64
test_batch_size=128
num_epoches=50
#学习率
lr=0.01
#动量
momentum=0.5

3.加载mnist数据集,笔者这里已经下载过mnist数据集,所以download设置为False,没有下载的话要改成True先下载数据集。

#下载数据和预处理
#定义预处理函数,预处理依次放在compose函数里
transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5],[0.5])])
#下载数据,并且预处理
train_dataset=mnist.MNIST('./data',train=True,transform=transform,download=False)
test_dataset=mnist.MNIST('./data',train=False,transform=transform)

#dataloader是一个可迭代对象,像迭代器一样使用
train_loader=DataLoader(train_dataset,batch_size=train_batch_size,shuffle=True)
test_loader=DataLoader(test_dataset,batch_size=test_batch_size,shuffle=False)

4.搭建模型,这里的使用的是卷积神经网络,笔者定义了两种卷积,一种是普通的卷积层,一种是深度可分离卷积。深度可分离卷积简单来说就是先用一个和普通卷积层同样大小的卷积核,保持通道数不变,然后再用一个1*1的卷积进行通道数的调整,。这样使用深度可分离卷积不仅可以保存良好的特征提取效果,还能大大减少参数量。不过这好像对于笔者这里搭建的小网络结构影响也不是很大,使用深度可分离卷积也只是笔者的情怀。这里笔者也给出了使用普通卷积层和深度可分离卷积层的模型参数情况供大家参考。

#定义普通3*3卷积模块

def conv2d_dn(inp,out,s=1):
    return nn.Sequential(
        nn.Conv2d(inp,out,3,s,1,bias=False),
        nn.BatchNorm2d(out),
        nn.ReLU6()
    )
# | name               | #elements or shape   |
# |:-------------------|:---------------------|
# | model              | 0.4M                 |
# |  layer1            |  0.4K                |
# |   layer1.0         |   0.4K               |
# |    layer1.0.0      |    0.3K              |
# |    layer1.0.1      |    64                |
# |  layer2            |  18.6K               |
# |   layer2.0         |   18.6K              |
# |    layer2.0.0      |    18.4K             |
# |    layer2.0.1      |    0.1K              |
# |  layer3            |  0.4M                |
# |   layer3.0         |   0.4M               |
# |    layer3.0.weight |    (128, 3136)       |
# |    layer3.0.bias   |    (128,)            |
# |  layer4            |  1.3K                |
# |   layer4.0         |   1.3K               |
# |    layer4.0.weight |    (10, 128)         |
# |    layer4.0.bias   |    (10,)             |

#定义深度可分离卷积模块
def conv2d_dw(inp,out,s=1):
    return nn.Sequential(nn.Conv2d(inp,inp,3,s,groups=inp,bias=False,padding=1),
                         nn.BatchNorm2d(inp),
                         nn.ReLU6(),

                         nn.Conv2d(inp,out,1,1,0,bias=False),
                         nn.BatchNorm2d(out),
                         nn.ReLU6())

# | name               | #elements or shape   |
# |:-------------------|:---------------------|
# | model              | 0.4M                 |
# |  layer1            |  0.1K                |
# |   layer1.0         |   0.1K               |
# |    layer1.0.0      |    9                 |
# |    layer1.0.1      |    2                 |
# |    layer1.0.3      |    32                |
# |    layer1.0.4      |    64                |
# |  layer2            |  2.5K                |
# |   layer2.0         |   2.5K               |
# |    layer2.0.0      |    0.3K              |
# |    layer2.0.1      |    64                |
# |    layer2.0.3      |    2.0K              |
# |    layer2.0.4      |    0.1K              |
# |  layer3            |  0.4M                |
# |   layer3.0         |   0.4M               |
# |    layer3.0.weight |    (128, 3136)       |
# |    layer3.0.bias   |    (128,)            |
# |  layer4            |  1.3K                |
# |   layer4.0         |   1.3K               |
# |    layer4.0.weight |    (10, 128)         |
# |    layer4.0.bias   |    (10,)             |


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.layer1=nn.Sequential(conv2d_dn(1,32,1),nn.MaxPool2d((2,2),2),nn.Dropout(0.3))
        self.layer2=nn.Sequential(conv2d_dn(32,64,1),nn.MaxPool2d((2,2),2),nn.Dropout(0.3))
        self.layer3=nn.Sequential(nn.Linear(3136,128))
        self.layer4 = nn.Sequential(nn.Linear(128, 10))

    def forward(self,x):
        x=self.layer1(x)
        x=self.layer2(x)
        x=x.view(-1,7*7*64)
        x=self.layer3(x)
        x=F.relu(x)
        x=self.layer4(x)
        return x

5.下面进行训练

#实例化网络
#检测是否有可用的GPU,有则使用,否则使用cpu
device=torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)
#实例化网络
model=Net()
model.to(device)
#可视化模型参数
# print(parameter_count_table(model))

#定义损失函数和优化器
criterion=nn.CrossEntropyLoss()
optimizer=optim.SGD(model.parameters(),lr=lr,momentum=momentum)

#训练模型
#开始训练
losses=[]
acces=[]
eval_losses=[]
eval_acces=[]

for epoch in range(num_epoches):
    print("开始第{}批次".format(epoch+1))
    train_loss=0
    train_acc=0
    model.train()
    #动态修改学习参数学习率
    if epoch%5==0:
        optimizer.param_groups[0]['lr']*=0.1
        print("学习率:{}".format(optimizer.param_groups[0]['lr']))
    for img,label in train_loader:
        img=img.to(device)
        label=label.to(device)
        #前向传播
        out=model(img)
        loss=criterion(out,label)
        #反向传播
        optimizer.zero_grad()
        loss.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.to(device)
        label = label.to(device)
        out = model(img)
        loss = criterion(out, label)
        # 记录误差
        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+1,
                                                                                                    train_loss / len(
                                                                                                        train_loader),
                                                                                                    train_acc / len(
                                                                                                        train_loader),
                                                                                                    eval_loss / len(
                                                                                                        test_loader),
                                                                                                    eval_acc / len(
                                                                                                        test_loader)))


6.可视化损失和准确率

#可视化化训练及测试损失值
fig1=plt.figure()
plt.plot(np.arange(num_epoches),losses)
plt.legend(['Train Loss'],loc='upper right')

fig2=plt.figure()
plt.plot(np.arange(num_epoches),acces)
plt.legend(['Train ACC'],loc='upper right')

fig3=plt.figure()
plt.plot(np.arange(num_epoches),eval_losses)
plt.legend(['Test Loss'],loc='upper right')

fig4=plt.figure()
plt.plot(np.arange(num_epoches),eval_acces)
plt.legend(['Test ACC'],loc='upper right')

plt.show()
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追天一方

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值