pytorch实现CNN处理MNIST手写数据集

pytorch实现CNN处理MNIST手写数据集

pytorch实现CNN处理MNIST手写数据集

  • pytorch实现CNN处理MNIST手写数据集
    • 1、流程
    • 2、训练过程
      • (1)先导入必要的包
      • (2)计算标准差和方差
      • (3)用mini batch的形式导入训练和测试数据
      • (4)定义模型,损失函数、优化函数,学习率,动量等超参数等。
      • (5)定义训练和测试函数
      • (6)迭代进行训练
    • 3、全部代码

1、流程

1、导入数据(torch.utils.data.DataLoader)
在内部定义数据的路径(os.path.join(data_dir, data_name)、对数据进行处理等(transfrom(旋转,totensor,标准化)、batch_size,shuffle等)。
2、定义模型,损失(交叉熵损失nll_loss(log_softmax)或者CrossEntropyLoss()),优化函数,学习率,动量等超参数等。
3、定义训练函数(model.train() ,数据,预测,损失函数,优化,epoch等)
4、定义测试函数(model.eval(),数据,预测,损失函数,衡量标准(Loss、准确率等)
5、迭代运算,几个epoch(此时将数据写入函数)

2、训练过程

在进行MNIST数据分析时,可以自行下载mnist数据,也可以通过torchvision 的 datasets导入数据。
但是一般导入数据较为慢,可自行先下载好数据之后,再进行处理。
百度云自取mnist数据:
https://pan.baidu.com/s/1ZOknxUEmWPTKMveBbw_erg
提取码:8t8e

(1)先导入必要的包

import torch
import numpy as np
import torch.nn as nn
import torch.utils.data
from torchvision import datasets,transforms
import torch.nn.functional as F

(2)计算标准差和方差

在导入必要的包之后,一般需要对数据进行处理(标准化),使得数据的训练更快、更容易收敛。
因为mnist数据集为单通道图像(灰色图像,多通道为RGB图像等),所以此时可以用以下方法计算训练数据集的均值和标准差。

minist_data=datasets.MNIST("./MNIST_data",train=True,download=True,transform=transforms.Compose([transforms.ToTensor(),]))  # 下载数据,如果不存在会自动下载,并将其转化为tensor(若下载好数据此处download为false)
print(minist_data)  # 了解数据的信息
print(minist_data[0][0].shape)  # 了解数据的size,此时为[1,28,28]
# 计算均值和方差(将数据转为numpy格式)
data=[d[0].data.cpu().numpy() for d in minist_data]
mean=np.mean(data)
std=np.std(data)
print(mean,std)

结果
pytorch实现CNN处理MNIST手写数据集_第1张图片

(3)用mini batch的形式导入训练和测试数据

此处导入数据为固定的格式 用(torch.utils.data.DataLoader)

batch_size=32
train_dataloader=torch.utils.data.DataLoader(
    datasets.MNIST("./MNIST_data",train=True,download=False,
    transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((mean,),(std,))])),
    batch_size=batch_size,shuffle=True,pin_memory=True)
test_dataloader=torch.utils.data.DataLoader(
    datasets.MNIST("./MNIST_data",train=False,download=False,
    transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((mean,),(std,))])),
    batch_size=batch_size,shuffle=True,pin_memory=True)

(4)定义模型,损失函数、优化函数,学习率,动量等超参数等。

此处通过类定义模型的内部参数(固定使用class Net(nn.Module))

# 定义卷积神经网络内部的参数
class Net(nn.Module): 
    def __init__(self):
        super(Net,self).__init__() # 继承init
        self.conv1=nn.Conv2d(1,20,5,1)  # 28*28的1通道转为 24*24的20通道的数据
        self.conv2=nn.Conv2d(20,50,5,1)  # 卷积核为5*5 步长为1 输入20通道 输出50通道 
        self.fc1=nn.Linear(4*4*50,500)  
        self.fc2=nn.Linear(500,10)
    def forward(self, x):
        # 开始输入为x=1*28*28
        x=F.relu(self.conv1(x))  # 20*24*24
        x=F.max_pool2d(x,2,2)    # 20*12*12
        x=F.relu(self.conv2(x))  # 50*8*8
        x=F.max_pool2d(x,2,2)    # 50*4*4
        x=x.view(-1,4*4*50)      #reshape 将其转化为一维数据(-1为batch处理的量)用于全连接层
        x=F.relu(self.fc1(x))
        x=self.fc2(x)
        return F.log_softmax(x,dim=1)   # 每个图片归于每一类的概率
# 定义训练的各种参数
device=torch.device("cuda" if torch.cuda.is_available() else "cpu") 
lr=0.01
momentum=0.5
model=Net().to(device)  # 将其弄到GPU上进行训练(速度快,并行)
optimizer=torch.optim.SGD(model.parameters(),lr=lr,momentum=momentum) # 定义优化方法,用SGD方法进行优化
num_epoch=2

(5)定义训练和测试函数

1.训练函数

def train(model,device,train_loader,optimizer,epoch):
    model.train()
    for idx,(data,target) in enumerate(train_loader):   #idx为第几个数据 (data,target)为相应的数据值 enumerate可以自己给数据加索引值,一般均用此方法对数据进行批量处理
        data,target=data.to(device),target.to(device)
        pred=model(data)
        loss=F.nll_loss(pred,target)  # 此时由于先log(softmax),所以和直接使用交叉熵损失函数一样的效果  
        # SGD
        optimizer.zero_grad() # 先将梯度置0,否则在计算过程中,梯度会越来越大
        loss.backward() # 反向计算梯度
        optimizer.step()
        # 打印出损失值
        if idx%100==0:
            print("Train Epoch:{},iteration:{},Loss:{}".format(epoch,idx,loss.item()))

2.测试函数

def test(model,device,test_loader):
    model.eval()
    total_loss=0.
    correct=0.
    with torch.no_grad(): # 测试函数无需计算梯度
        for idx,(data,target) in enumerate(test_loader):
            data,target=data.to(device),target.to(device)
            output=model(data)  # batch_size*10
            total_loss+=F.nll_loss(output,target,reduction="sum").item() # 计算总的损失值
            pred=output.argmax(dim=1) # batch_size*1  # 将数据取最大的概率值
            correct+=pred.eq(target.view_as(pred)).sum().item() # 将预测值和真实值进行比较,此时维度需要设置为一样
        total_loss/=len(test_loader.dataset)  # 计算损失
        acc=correct/len(test_loader.dataset) # 计算准确率
        print("Test loss: {},Accuracy: {}".format(total_loss,acc))

(6)迭代进行训练

# 迭代进行运算 循环几个epoch
for epoch in range(num_epoch):
    train(model,device,train_dataloader,optimizer,epoch)
    test(model, device,test_dataloader)
# 将训练的模型进行保存
torch.save(model.state_dict(),"mnist_cnn.pt")

训练结果:
pytorch实现CNN处理MNIST手写数据集_第2张图片

3、全部代码


import torch
import numpy as np
import torch.nn as nn
import torch.utils.data
from torchvision import datasets,transforms
import torch.nn.functional as F
# 计算均值和方差
minist_data=datasets.MNIST("./MNIST_data",train=True,download=True,transform=transforms.Compose([transforms.ToTensor(),]))  # 下载数据,如果不存在会自动下载,并将其转化为tensor
print(minist_data)
print(minist_data[0][0].shape)
data=[d[0].data.cpu().numpy() for d in minist_data]
mean=np.mean(data)
std=np.std(data)
print("数据的均值为:{},方差为:{}".format(mean,std))
# 定义训练和测试过程
def train(model,device,train_loader,optimizer,epoch):
    model.train()
    for idx,(data,target) in enumerate(train_loader):   #idx为第几个数据 (data,target)为相应的数据值 enumerate可以自己给数据加索引值
        data,target=data.to(device),target.to(device)
        pred=model(data)
        loss=F.nll_loss(pred,target)
        # SGD
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if idx%100==0:
            print("Train Epoch:{},iteration:{},Loss:{}".format(epoch,idx,loss.item()))
def test(model,device,test_loader):
    model.eval()
    total_loss=0.
    correct=0.
    with torch.no_grad():
        for idx,(data,target) in enumerate(test_loader):
            data,target=data.to(device),target.to(device)
            output=model(data)  # batch_size*10
            total_loss+=F.nll_loss(output,target,reduction="sum").item()
            pred=output.argmax(dim=1) # batch_size*1
            correct+=pred.eq(target.view_as(pred)).sum().item()
        total_loss/=len(test_loader.dataset)
        acc=correct/len(test_loader.dataset)
        print("Test loss: {},Accuracy: {}".format(total_loss,acc))
# 定义卷积神经网络内部的参数
class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        self.conv1=nn.Conv2d(1,20,5,1)  # 28*28的1通道转为 24*24的20通道的数据
        self.conv2=nn.Conv2d(20,50,5,1)  # 卷积核为5*5 步长为1 输入20通道 输出50通道
        self.fc1=nn.Linear(4*4*50,500)
        self.fc2=nn.Linear(500,10)
    def forward(self, x):
        # 开始输入为x=1*28*28
        x=F.relu(self.conv1(x))  # 20*24*24
        x=F.max_pool2d(x,2,2)    # 20*12*12
        x=F.relu(self.conv2(x))  # 50*8*8
        x=F.max_pool2d(x,2,2)    # 50*4*4
        x=x.view(-1,4*4*50)      #reshape 将其转化为一维数据(-1为batch处理的量)
        x=F.relu(self.fc1(x))
        x=self.fc2(x)
        return F.log_softmax(x,dim=1)   # 每个图片归于每一类的概率
# 定义训练的各种参数
device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
batch_size=32
lr=0.01
momentum=0.5
model=Net().to(device)
optimizer=torch.optim.SGD(model.parameters(),lr=lr,momentum=momentum)
num_epoch=2
# 批量导入测试数据和训练数据
train_dataloader=torch.utils.data.DataLoader(
    datasets.MNIST("./MNIST_data",train=True,download=True,
    transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((mean,),(std,))])),
    batch_size=batch_size,shuffle=True,pin_memory=True)
test_dataloader=torch.utils.data.DataLoader(
    datasets.MNIST("./MNIST_data",train=False,download=True,
    transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((mean,),(std,))])),
    batch_size=batch_size,shuffle=True,pin_memory=True)
# 迭代进行运算 循环几个epoch
for epoch in range(num_epoch):
    train(model,device,train_dataloader,optimizer,epoch)
    test(model, device,test_dataloader)
# 将训练的模型进行保存
torch.save(model.state_dict(),"mnist_cnn.pt")

torchvision还有一种数据为FashionMNIST,其比MNIST更为复杂,但是其格式和MNIST完全一样 1* 28 *28 ,最后分类也是分为十种类型,也可用于基础深度学习训练。

你可能感兴趣的:(学习笔记)