深度学习——卷积神经网络实现手写数字识别

一、准备工作

导入所需的依赖库:

python 复制代码
# import torch
# print(torch.__version__)
 
'''
 MNIST包含70000张手写数字图像:60000用于训练,10000用于测试
 图像是灰度的,28×28像素的,并且居中的,以减少预处理和加快运行
'''
import torch
from torch import nn    #导入神经网络模块
from torch.utils.data import DataLoader  #数据包管理工具,打包数据
from torchvision import  datasets  #封装了很多与图像相关的模型,数据集
from torchvision.transforms import ToTensor  #数据转换,张量,将其他类型的数据转换为tensor张量,numpy array

torch:PyTorch 的核心包,提供张量运算和深度学习构建的基础。

nn:神经网络模块,用于搭建层结构(卷积层、全连接层等)。

DataLoader:数据加载器,可以自动打包数据,支持批量读取。

datasets:提供常用的数据集(如 MNIST、CIFAR10)。

ToTensor:将图片转换为张量格式,方便神经网络使用。

二、加载数据集

python 复制代码
'''下载训练数据集(包含训练图片+标签)'''
training_data = datasets.MNIST(
    root="data", 
    train=True, 
    download=True, 
    transform=ToTensor(), 
)   
 
'''下载测试数据集(包含测试图片+标签)'''
test_data = datasets.MNIST(
    root="data", 
    train=False, 
    download=True, 
    transform=ToTensor(), 
)   
print(len(training_data))

三、数据可视化(非必须)

python 复制代码
from matplotlib import  pyplot as plt
figure = plt.figure()
for i in range(9):
    img,label = training_data[i+59000]
    figure.add_subplot(3,3,i+1)
    plt.title(label)
    plt.axis("off")
    plt.imshow(img.squeeze(),cmap='gray')
    a = img.squeeze()
plt.show()

四、创建数据加载器

python 复制代码
train_dataloader = DataLoader(training_data, batch_size=64)  # 是一个类,现在初始化了,但没开始打包,训练开始才打包
test_dataloader = DataLoader(test_data, batch_size=64)
for X, y in test_dataloader:
    print(f"Shape of X [N, C, H, W]: {X.shape}")  # N:批次大小, C:通道数(灰度图为1), H:高度, W:宽度
    print(f"Shape of y: {y.shape} {y.dtype}")     # 标签的形状和数据类型
    break

device = ("cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu")
print(f"using{device} device")

train_dataloader = DataLoader(training_data, batch_size=64)表示现在是一个类,初始化了,但没开始打包,训练开始才打包

batch_size=64:每次从数据集中读取 64 张图片作为一个批次

for X, y in test_dataloader:

print(f"Shape of X [N, C, H, W]: {X.shape}") # N:批次大小, C:通道数(灰度图为1), H:高度, W:宽度

print(f"Shape of y: {y.shape} {y.dtype}") # 标签的形状和数据类型

break # 只查看一个批次

上述代码是用来查看加载器中一个批次的数据形状

五、选择运行设备

选择选用CPU或者GPU

python 复制代码
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using {device} device")
  • cuda:表示选择使用 NVIDIA GPU。

  • mps:Apple M 系列芯片的 GPU。

  • cpu:若电脑种没有 GPU,则使用 CPU

六、定义卷积神经网络(CNN)

python 复制代码
''' 定义神经网络  类的继承这种方式'''
class CNN(nn.Module): 
    def __init__(self):   
        super(CNN,self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(1,16,3,1,1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2),
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(16, 16, 3, 1, 1),
            nn.ReLU(),
            nn.Conv2d(16, 32, 3, 1, 1),
            nn.ReLU(),
            nn.Conv2d(32, 32, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2), )
        self.conv3 = nn.Sequential(
            nn.Conv2d(32, 64, 3, 1, 1),
            nn.ReLU(),
            nn.Conv2d(64, 64, 3, 1, 1),
            nn.ReLU(),
        )
        self.out = nn.Linear(64*7*7,10)
 
    def forward(self,x):  
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)  
        x = x.view(x.size(0), -1) 
        output = self.out(x)
        return output
 
model = CNN().to(device)
print(model)

模型结构说明:

输入1*28*28(64 张图片作为一个批次。故 64*1*28*28)

conv1(一维):卷积 + ReLU + 池化 → 输出 16*14*14

conv2(二维):多层卷积 + ReLU + 池化 → 输出 32*7*7

conv3(三维):卷积层 → 输出 64*7*7

Linear 全连接层:输入 64*7*7,输出 10(对应 0~9 的数字分类)。

七、训练函数

python 复制代码
def train(dataloader,model,loss_fn,optimizer):
    model.train() 
    batch_size_num = 1
    for X,y in dataloader:              
        X,y = X.to(device),y.to(device) 
        pred = model.forward(X)         
        loss = loss_fn(pred,y)          
 
        optimizer.zero_grad()           
        loss.backward()                 
        optimizer.step()                
 
        loss_value = loss.item()        
        if batch_size_num %100 ==0:
            print(f"loss: {loss_value:>7f} [number:{batch_size_num}]")
        batch_size_num += 1
  1. 前向传播:计算预测结果 pred

  2. 计算损失:loss_fn(pred,y)

  3. 反向传播:loss.backward() 计算梯度。

  4. 参数更新:optimizer.step()

八、测试函数

python 复制代码
def Test(dataloader,model,loss_fn):
    size = len(dataloader.dataset)  
    num_batches = len(dataloader)  
    model.eval()        
    test_loss,correct =0,0
    with torch.no_grad():       
        for X,y in dataloader:
            X,y = X.to(device),y.to(device)
            pred = model.forward(X)
            test_loss += loss_fn(pred,y).item() 
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()
    test_loss /= num_batches 
    correct /= size  
    print(f"Test result: \n Accuracy:{(100*correct)}%, Avg loss:{test_loss}")

九、定义损失函数和优化器

python 复制代码
loss_fn = nn.CrossEntropyLoss()  
optimizer = torch.optim.Adam(model.parameters(),lr=0.005) 
  • CrossEntropyLoss:常用于分类任务。

  • Adam 优化器:比 SGD 收敛更快。

十、训练模型和测试

python 复制代码
epochs = 10
for t in range(epochs):
    print(f"epoch {t+1}\n---------------")
    train(train_dataloader,model,loss_fn,optimizer)
print("Done!")
Test(test_dataloader,model,loss_fn)
相关推荐
Shawn_Shawn4 小时前
mcp学习笔记(一)-mcp核心概念梳理
人工智能·llm·mcp
33三 三like6 小时前
《基于知识图谱和智能推荐的养老志愿服务系统》开发日志
人工智能·知识图谱
芝士爱知识a7 小时前
【工具推荐】2026公考App横向评测:粉笔、华图与智蛙面试App功能对比
人工智能·软件推荐·ai教育·结构化面试·公考app·智蛙面试app·公考上岸
腾讯云开发者8 小时前
港科大熊辉|AI时代的职场新坐标——为什么你应该去“数据稀疏“的地方?
人工智能
工程师老罗8 小时前
YoloV1数据集格式转换,VOC XML→YOLOv1张量
xml·人工智能·yolo
yLDeveloper8 小时前
从模型评估、梯度难题到科学初始化:一步步解析深度学习的训练问题
深度学习
Coder_Boy_8 小时前
技术让开发更轻松的底层矛盾
java·大数据·数据库·人工智能·深度学习
啊森要自信8 小时前
CANN ops-cv:面向计算机视觉的 AI 硬件端高效算子库核心架构与开发逻辑
人工智能·计算机视觉·架构·cann
2401_836235868 小时前
中安未来SDK15:以AI之眼,解锁企业档案的数字化基因
人工智能·科技·深度学习·ocr·生活