pyTorch框架使用CNN进行手写数字识别

目录

1.导包

2.torchvision数据处理的方法

3.下载加载手写数字的训练数据集

4.下载加载手写数字的测试数据集

[5. 将训练数据与测试数据 转换成dataloader](#5. 将训练数据与测试数据 转换成dataloader)

6.转成迭代器取数据

7.创建模型

[8. 把model拷到GPU上面去](#8. 把model拷到GPU上面去)

[9. 定义损失函数](#9. 定义损失函数)

[10. 定义优化器](#10. 定义优化器)

[11. 定义训练过程](#11. 定义训练过程)

12.最终运行测试


1.导包

python 复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
python 复制代码
torch.__version__
复制代码
'2.4.1+cu121'
python 复制代码
# 检查GPU是否可用
torch.cuda.is_available()
复制代码
True
python 复制代码
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

device
复制代码
device(type='cuda', index=0)

pytorch中使用GPU进行训练的主要流程注意点:

#1. 把模型转移到GPU上.

#2. 将每一批次的训练数据转移到GPU上.

torchvision 内置了常用的数据集和常见的模型.

#使用pyTorch框架 整迁移学习时,可以从torchvision中加载出来

2.torchvision数据处理的方法

python 复制代码
import torchvision

from torchvision import datasets, transforms

transforms.ToTensor 的作用如下:

1. 把数据转化为tensor

2. 数据的值转化为0到1之间.

3. 会把channel放到第一个维度上.

python 复制代码
# transforms用来做数据增强, 数据预处理等功能的. 
#Compose()可以将很多数据处理的方法组合起来, 用列表来组合
transformation = transforms.Compose([transforms.ToTensor(),])

3.下载加载手写数字的训练数据集

python 复制代码
#下载获取手写数字数据集MNIST  ,获取其中的训练数据集
#train=True表示获取训练数据集
train_ds = datasets.MNIST('./', train=True, transform=transformation, download=True)
python 复制代码
datasets
复制代码
<module 'torchvision.datasets' from 'D:\\anaconda3\\lib\\site-packages\\torchvision\\datasets\\__init__.py'>

4.下载加载手写数字的测试数据集

python 复制代码
# 下载获取 手写数字的 测试数据集
#train=False表示获取测试数据集
test_ds = datasets.MNIST('./', train=False, transform=transformation, download=True)

5. 将训练数据与测试数据 转换成dataloader

python 复制代码
# 将训练数据与测试数据 转换成dataloader
train_dl = torch.utils.data.DataLoader(train_ds, batch_size=64, shuffle=True)   #shuffle=True表示打乱数据
test_dl = torch.utils.data.DataLoader(test_ds, batch_size=256)  #测试数据时,不需要进行反向传播,可以将batch_size的值给大一些

6.转成迭代器取数据

python 复制代码
#可迭代对象 与 迭代器 不同
#train_dl是可迭代对象
#iter()将train_dl可迭代对象的数据 变成 迭代器
#next()从迭代器中取出一批数据
images, labels = next(iter(train_dl))
python 复制代码
#tensorflow中图片的表现形式[batch, hight, width, channel]
# pytorch中图片的表现形式[batch, channel, hight, width]
images.shape
复制代码
torch.Size([64, 1, 28, 28])
python 复制代码
labels  #还没有one_hot编码的
复制代码
tensor([1, 1, 2, 3, 2, 1, 8, 4, 5, 8, 4, 3, 0, 0, 4, 8, 2, 3, 3, 7, 3, 0, 5, 5,
        5, 6, 7, 2, 9, 4, 7, 9, 6, 7, 1, 4, 3, 9, 2, 4, 6, 4, 1, 1, 9, 2, 4, 7,
        7, 6, 2, 6, 8, 1, 3, 5, 4, 7, 5, 0, 6, 0, 9, 1])
python 复制代码
img = images[0]   #取一张图的数据
python 复制代码
img.shape  #一张图数据的形状   #三维数据 不方便可视化
python 复制代码
img = img.numpy()  #可以先将数据转成numpy数据类型, 再进行数据降维,  再进行可视化
python 复制代码
img = np.squeeze(img)  #数据降维,降一个维度,把只有1的维度降掉, 将形状变成(28, 28)
python 复制代码
img.shape
复制代码
(28, 28)
python 复制代码
plt.imshow(img, cmap='gray')   #图片数据可视化

7.创建模型

python 复制代码
class Model(nn.Module):    #继承nn.Module
    def __init__(self):    #重写方法
        super().__init__() #继承父类的方法
        
        #无论经过什么层,batch_size一直保持不变(第一个数)
        
        #第一层卷积层
        #nn.Conv2d(输入的通道数, 自定义输出的通道数=这一层使用的卷积核的个数, 卷积核的大小)
        #输出的通道数=卷积核的个数(神经元个数)
        #nn.Conv2d()参数dilation=1(默认值),表示 不膨胀卷积
        #padding 默认为0
        #卷积核的大小为奇数时,padding=valid, 图片大小= ((原图片大小w - 卷积核的大小F)+ 1) /   步长s (此时步长默认steps = 1)
        self.conv1 = nn.Conv2d(1, 32, 3)# in: 64, 1, 28 , 28 -> out: 64, 32, 26, 26
        #池化层nn.MaxPool2d((卷积核的大小))   ,卷积核的大小可以用元组(2,2)表示,或者直接用一个数2表示   #strip步长默认为2
        #池化层的数值设置一般都一样,可重复使用,创建一次就行
        #卷积核的大小为偶数时,padding=same, 图片大小= 原图片大小w  / 步长s(此时的步长steps默认为2)
        #上一句化 等同于 经过一次池化层,原图片大小减半
        #经过池化层,输入通道数=上一层的输出通道数=上一层使用的卷积核个数
        self.pool = nn.MaxPool2d((2, 2)) # out: 64, 32, 13, 13
#         self.pool = nn.MaxPool2d(2)  #等同于上一行代码
        #第二层卷积核nn.Conv2d(上一层卷积的输出通道数, 自定义在这一层使用的卷积核的个数, 3)
        self.conv2 = nn.Conv2d(32, 64, 3)# in: 64, 32, 13, 13 -> out: 64, 64, 11, 11
        # 再加一层池化操作, in: 64, 64, 11, 11  --> out: 64, 64, 5, 5
        #第一层全连接层(输入通道数=上一层维度形状相乘,自定义输出通道数量=这一层使用的神经元数量)
        self.linear_1 = nn.Linear(64 * 5 * 5, 256)
        #第二层全连接层(输入通道数=上一层输出通道数,自定义输出通道数=问题分类数量(数字识别0~9,共10个数字))
        self.linear_2 = nn.Linear(256, 10)
    
    #定义前向传播
    def forward(self, input):
        #链式调用     #relu激活函数(第一层卷积层)  #调用自定义方法,需要加上self.
        x = F.relu(self.conv1(input))
        x = self.pool(x)           #第二层:池化层
        x = F.relu(self.conv2(x))  #第三层:卷积层,然后+ relu激活函数
        x = self.pool(x)           #第四层:池化层
        # flatten 展平, 进行维度变形
        x = x.view(-1, 64 * 5 * 5)   # (每批次具有64个样本, 特征数量)
        x = F.relu(self.linear_1(x)) #第五层:全连接层+激活函数relu
        x = self.linear_2(x)       #第六层:输出层     #一般会在这一层之后添加一个sigmoid函数,这里没有加,后面需要处理一下
        return x

8. 把model拷到GPU上面去

python 复制代码
model = Model()


# 把model拷到GPU上面去
model.to(device)
复制代码
Model(
  (conv1): Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1))
  (pool): MaxPool2d(kernel_size=(2, 2), stride=(2, 2), padding=0, dilation=1, ceil_mode=False)
  (conv2): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1))
  (linear_1): Linear(in_features=1600, out_features=256, bias=True)
  (linear_2): Linear(in_features=256, out_features=10, bias=True)
)

9. 定义损失函数

python 复制代码
#定义损失函数
loss_fn = torch.nn.CrossEntropyLoss()

10. 定义优化器

python 复制代码
#定义优化器
optimizer = optim.Adam(model.parameters(), lr=0.001)

11. 定义训练过程

python 复制代码
#定义训练过程
def fit(epoch, model, train_loader, test_loader):
    #声明变量
    correct = 0      #预测准确的数量
    total = 0        #总共的样本数量
    running_loss = 0 #每运行一次的累计损失
    
    for x, y in train_loader:
        # 把CPU上的数据放到GPU上去. 
        x, y = x.to(device), y.to(device)
        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        with torch.no_grad():  #不计算梯度求导时
            #计算预测值   #argmax()是取最大值的索引, y_pred是10个预测数字的概率(包含10个概率数值),是二维数据类型   # dim=1表示取第二个维度上的索引:列上
            y_pred = torch.argmax(y_pred, dim=1)
            #计算预测准确的数量,  #.item()表示把sum()求和的聚合运算(bool值会直接用1或0表示)之后的 标量(一个具体的数)取出来
            correct += (y_pred == y).sum().item()
            total += y.size(0)  #总共样本数量
            running_loss += loss.item()  #每运行一次的累计损失
            
    epoch_loss = running_loss / len(train_loader.dataset)  #计算平均损失
    epoch_acc = correct / total  #计算准确率
        
    # 测试过程,不需要计算梯度求导
    test_correct = 0
    test_total = 0
    test_running_loss = 0
    with torch.no_grad():
        for x, y in test_loader:
            x, y = x.to(device), y.to(device)
            y_pred = model(x)
            loss = loss_fn(y_pred, y)
            y_pred = torch.argmax(y_pred, dim=1)
            test_correct += (y_pred == y).sum().item()
            test_total += y.size(0)
            test_running_loss += loss.item()
    test_epoch_loss = test_running_loss / len(test_loader.dataset)
    test_epoch_acc = test_correct / test_total

    print('epoch: ', epoch,
         'loss: ', round(epoch_loss, 3),    #3表示三位小数
         'accuracy: ', round(epoch_acc, 3),
         'test_loss: ', round(test_epoch_loss, 3),
         'test_accuracy: ', round(test_epoch_acc))
    return epoch_loss, epoch_acc, test_epoch_loss, test_epoch_acc

12.最终运行测试

python 复制代码
epochs = 20     #指定运行的次数
train_loss = []
train_acc = []
test_loss = []
test_acc = []
for epoch in range(epochs):
    epoch_loss, epoch_acc, test_epoch_loss, test_epoch_acc = fit(epoch, model, train_dl, test_dl)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    
    test_loss.append(epoch_loss)
    test_acc.append(epoch_acc)
相关推荐
果冻人工智能6 分钟前
如何对LLM大型语言模型进行评估与基准测试
人工智能
摆烂仙君23 分钟前
基于α-β剪枝的含禁手AI五子棋
人工智能·机器学习·剪枝
weixin_4452381238 分钟前
Pytorch|RNN-心脏病预测
人工智能·pytorch·rnn
fantasy_41 小时前
LLM-大语言模型浅谈
人工智能·ai·语言模型·deep learning
嘻嘻哈哈开森1 小时前
从零开始学习模型蒸馏
人工智能·后端
Thomas_Cai1 小时前
Bert论文解析
人工智能·深度学习·nlp·bert·transformer
量子位2 小时前
Llama 4 发布 36 小时差评如潮!匿名员工爆料拒绝署名技术报告
人工智能·llama
HCZJNB2 小时前
泓川证券|外骨骼机器人落地场景丰富 市场空间广阔
人工智能·机器人
量子位2 小时前
LIama 4 发布重夺开源第一!DeepSeek 同等代码能力但参数减一半,一张 H100 就能跑,还有两万亿参数超大杯
人工智能·deepseek
量子位2 小时前
米哈游蔡浩宇新作 iPhone 实机演示:10 分钟就被 AI 小美撩到脸红,她的命运由我拯救
人工智能·aigc