使用PyTorch实现手写数字识别功能

2025-03-24 14:50

本文主要是介绍使用PyTorch实现手写数字识别功能,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《使用PyTorch实现手写数字识别功能》在人工智能的世界里,计算机视觉是最具魅力的领域之一,通过PyTorch这一强大的深度学习框架,我们将在经典的MNIST数据集上,见证一个神经网络从零开始学会识...

当计算机学会“看”数字

在人工智能的世界里,计算机视觉是最具魅力的领域之一。通过PyTorch这一强大的深度学习框架,我们将在经典的MNIST数据集上,见证一个神经网络从零开始学会识别数字的全过程。本文将以通俗易懂的方式,带你走进这个看似神秘实则充满逻辑的美妙世界。

搭建开发环境

在开始训练之前,我们需要准备好三个基础要素:腾讯云HAI,腾讯云HAI,腾讯云HAI。导入必要的工具库:

import torch  # 深度学习框架核心
import torch.nn as nn  # 神经网络模块
from torchvision import datasets, transforms  # 数据处理利器

MNIST数据集解析

1. 认识手写数字数据库

MNIST数据集包含6万张训练图片和1万张测试图片,每张都是28x28像素的灰度图。这些数字由美国高中生和人口普查局员工书写,构成了计算机视觉领域的"Hello World"。

2. 数据预处理的艺术

原始图片需要经过精心处理才能被模型理解:

transform = transforms.Compose([
    transforms.ToTensor(),  # 将图像转换为数值矩阵
    transforms.Normalize((0.1307,), (0.3081,))  # 标准化处理
])

3. 可视化的重要性

通过Matplotlib展示样本图片,我们能直观感受数据的特征:

plt.imshow(images[0].squeeze(), cmap='gray')
plt.title(f'Label: {labels[0]}')

神经网络设计

1. 网络结构蓝图

我们设计一个全连接网络(FCN),其结构如同人类神经系统的简化版:

class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten()  # 将图片展开为向量
        self.fc1 = nn.Linear(28*28, 128)  # 第一隐藏层
        self.fc2 = nn.Linear(128, 64)    # 第二隐藏层
        self.fc3 = nn.Linear(64, 10)     # 输出层
        self.dropout = nn.Dropout(0.5)   # 正则化装置
  • 神经元数量的选择需要平衡学习能力与过拟合风险
  • Dropout层像随机关闭部分神经元,防止模型"死记硬背"

2. 信息传递机制

前向传播模拟人脑的信息处理过程:ReLU激活函数如同神经元的开关,决定是否传递信号。

def forward(self, x):
    x = self.flatten(x)  # 展平操作:将图片变为784维向量
    x = torch.relu(self.fc1(x))  # 通过第一个全连接层
    x = self.dropout(x)         # 随机屏蔽部分神经元
    x = torch.relu(self.fc2(x))  # 第二个全连接层
    return self.fc3(China编程x)          # 最终输出10个数字的概率

让模型学会思考

1. 配置学习参数

  • 损失函数:交叉熵损失(CrossEntropyLoss),衡量预测与真实的差距
  • 优化:Adam优化器,智能调节学习步伐的导航员
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

2. 训练循环解析

每个epoch都是一次完整的学习轮回:

def train(epoch):
    model.train()  # 切换至训练模式
    for BATch_idx, (data, target) in enumerate(train_loader):
        optimizer.zero_grad()  # 清空之前的梯度
        output = model(data)    # 前向传播
        loss = criterion(output, target)  # 计算损失值
        loss.backward()         # 反向传播求梯度
        optimizer.step()        # 更新网络参数
  • 梯度清零避免不同批次数据的干扰
  • 反向传播就像纠错老师,沿着计算链修正参数

完整代码示例

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision

from torchvision import transforms
import matplotlib.pyplot as plt

# 2. 数据准备
# 定义数据预处理:转换为Tensor并标准化(MNIST的均值和标准差)
transfoChina编程rm = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))
])

# 加载训练集和测试集
train_dataset = torchvision.datasets.MNIST(
    root='./data', 
    train=True,
    download=True,
    transform=transform
)

test_dataset = torchvision.datasets.MNIST(
    root='./data',
    train=False,
    transform=transform
)

# 创建数据加载器
train_loader = torch.utils.data.DataLoader(
    train_dataset,

    batch_size=64,
    shuffle=True
)

test_loader = torch.utils.data.DataLoader(
    test_dataset,
    batch_size=1000,
    shuffle=False
)

# 查看数据集信息
print(f'Train samples: {len(train_dataset)}')
print(f'Test samples: {len(test_dataset)}')

# 可视化样本
images, labels = next(iter(train_loader))
plt.imshow(images[0].squeeze(), cmap='gray')
plt.title(f'Label: {labels[0]}')
plt.show()

# 3. 定义神经网络模型
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.flatten = nn.Flatten()
        self.fc1 = nn.Linear(28*28, 128)
        self.fc2 = nn.Linear(128, 64)
        self.fc3 = nn.Linear(64, 10)
        self.dropout = nn.Dropout(0.5)
        
    def forward(self, x):
        x = self.flatten(x)
        x = torch.relu(self.fc1(x))
        x = self.dropout(x)
        x = torch.relu(self.fc2(x))
        x = self.fc3(x)
        return x

model = Net()
print(model)

# 4. 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()

optimizer = optim.Adam(model.parameters(), lr=0.001)


# 5. 训练模型
def train(epoch):

    model.train()
    running_loss = 0.0
    for batch_idx, (data, target) in enumerate(train_loader):
        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()
        

        running_loss += loss.item()
        if batch_idx % 100 == 99:

            print(f'Epoch: {epoch+1}, Batch: {batch_idx+1}, Loss: {running_loss/100:.3f}')
            running_loss = 0.0

# 6. 测试模型

def test():
    model.eval()
    correct = 0
    total = 0
    with torch.no_grad():
        for data, target in test_loader:
            outputs = model(data)
            _, predicted = torch.max(outputs.data, 1)
            total += target.size(0)
            correct += (predicted == target).sum().item()
    
    accuracy = 100 * correct / total
    print(f'Test Accuracy: {accuracy:.2f}%')
    return accuracy

# 7. 执行训练和测试

epochs = 5
for epoch in range(epochs):
    train(epoch)
    test()

# 8.编程 保存模型
torch.save(model.state_dict(), 'mnist_model.pth')

使用PyTorch实现手写数字识别功能

针对1-9数字的测试

# 扩展测试函数,增加按数字统计的功能

def detailed_test():
    model.eval()
    class_correct = [0] * 10  # 存储每个数字的正确计数
    class_total = [0] * 10    # 存储每个数字的总样本数
    
    with torch.no_grad():
        for images, labels in test_loader:
            outputs = model(images)
            _, predicted = torch.max(outputs, 1)
            
            # 遍历每个预测结果
            for label, prediction in zip(labels, predicted):
                class_total[label] += 1
                if label == prediction:
                    class_correct[label] += 1


    # 打印每个数字的准确率
    print("{:^10} | {:^10} | {:^10}".format("数字", "正确数", "准确率"))
    print("-"*33)

    for i in range(10):
        acc = 100 * class_correct[i] / class_total[i]
        print("{:^10} | {:^10} | {:^10.2f}%".format(i, class_correct[i], acc))
    
    # 可视化错误案例
    wrong_examples = []

    for images, labels in test_loader:
        outputs = model(images)
        _, predicted = torch.max(outputs, 1)
        mask = predicted != labels
        wrong_examples.extend(zip(images[mask], labels[mask], predicted[mask]))
    
    # 随机展示3个错误样本

    fig, axes = plt.subplots(1, 3, figsize=(12,4))

    for ax, (img, true, pred) in zip(axes, wrong_examples[:3]):
        ax.imshow(img.squeeze(), cmap='gray')

        ax.set_title(f'True: {true}\nPred: {pred}')
        ax.axis('off')
    plt.show()

# 执行详细测试
detailed_test()

使用PyTorch实现手写数字识别功能

PyTorch vs TensorFlow 深度对比

1. 核心架构差异

特性PyTorchTensorFlow
计算图动态图(即时执行)静态图(需预先定义)
调试便利性支持标准python调试工具需要特殊工具(tfdbg)
API设计更接近Python原生语法自成体系的API风格
移动端部署支持但生态较弱通过TF Lite有成熟解决方案

2. 相同功能的代码对比

以定义全连接层为例:

# PyTorch版
import torch.nn as nn
layer = nn.Linear(in_features=784, out_features=128)

# TensorFlow版
from tensorflow.keras.layers import Dense
layer = Dense(units=128, input_dim=784)

3. 训练流程对比

PyTorch训练循环

for epoandroidch in range(epochs):
    for data, labels in train_loader:
        optimizer.zero_grad()
        outputs = model(data)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

TensorFlow训练流程

model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')
model.fit(train_dataset, epochs=epochs)  # 自动完成训练循环

4. 性能对比(MNIST示例)

指标PyTorch(CPU)TensorFlow(CPU)
训练时间/epoch~45秒~50秒
内存占用~800MB~1GB
测试准确率97.8-98.2%97.5-98.0%

工具的本质

PyTorch与TensorFlow的差异,本质上是灵活性规范性的不同追求。就像画家选择画笔,PyTorch提供的是自由挥洒的水彩,TensorFlow则是精准可控的钢笔。理解它们的特性差异,根据项目需求选择合适的工具,才是提升开发效率的关键。无论是哪个框架,最终目标都是将数学公式转化为智能的力量。

以上就是使用PyTorch实现手写数字识别功能的详细内容,更多关于PyTorch手写数字识别的资料请关注编程javascript栈(www.chinasem.cn)其它相关文章!

这篇关于使用PyTorch实现手写数字识别功能的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153919

相关文章

Nginx中配置使用非默认80端口进行服务的完整指南

《Nginx中配置使用非默认80端口进行服务的完整指南》在实际生产环境中,我们经常需要将Nginx配置在其他端口上运行,本文将详细介绍如何在Nginx中配置使用非默认端口进行服务,希望对大家有所帮助... 目录一、为什么需要使用非默认端口二、配置Nginx使用非默认端口的基本方法2.1 修改listen指令

Redis实现分布式锁全过程

《Redis实现分布式锁全过程》文章介绍Redis实现分布式锁的方法,包括使用SETNX和EXPIRE命令确保互斥性与防死锁,Redisson客户端提供的便捷接口,以及Redlock算法通过多节点共识... 目录Redis实现分布式锁1. 分布式锁的基本原理2. 使用 Redis 实现分布式锁2.1 获取锁

Python WebSockets 库从基础到实战使用举例

《PythonWebSockets库从基础到实战使用举例》WebSocket是一种全双工、持久化的网络通信协议,适用于需要低延迟的应用,如实时聊天、股票行情推送、在线协作、多人游戏等,本文给大家介... 目录1. 引言2. 为什么使用 WebSocket?3. 安装 WebSockets 库4. 使用 We

Linux实现查看某一端口是否开放

《Linux实现查看某一端口是否开放》文章介绍了三种检查端口6379是否开放的方法:通过lsof查看进程占用,用netstat区分TCP/UDP监听状态,以及用telnet测试远程连接可达性... 目录1、使用lsof 命令来查看端口是否开放2、使用netstat 命令来查看端口是否开放3、使用telnet

python中的显式声明类型参数使用方式

《python中的显式声明类型参数使用方式》文章探讨了Python3.10+版本中类型注解的使用,指出FastAPI官方示例强调显式声明参数类型,通过|操作符替代Union/Optional,可提升代... 目录背景python函数显式声明的类型汇总基本类型集合类型Optional and Union(py

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

使用SpringBoot+InfluxDB实现高效数据存储与查询

《使用SpringBoot+InfluxDB实现高效数据存储与查询》InfluxDB是一个开源的时间序列数据库,特别适合处理带有时间戳的监控数据、指标数据等,下面详细介绍如何在SpringBoot项目... 目录1、项目介绍2、 InfluxDB 介绍3、Spring Boot 配置 InfluxDB4、I

基于Java和FFmpeg实现视频压缩和剪辑功能

《基于Java和FFmpeg实现视频压缩和剪辑功能》在视频处理开发中,压缩和剪辑是常见的需求,本文将介绍如何使用Java结合FFmpeg实现视频压缩和剪辑功能,同时去除数据库操作,仅专注于视频处理,需... 目录引言1. 环境准备1.1 项目依赖1.2 安装 FFmpeg2. 视频压缩功能实现2.1 主要功

使用Java读取本地文件并转换为MultipartFile对象的方法

《使用Java读取本地文件并转换为MultipartFile对象的方法》在许多JavaWeb应用中,我们经常会遇到将本地文件上传至服务器或其他系统的需求,在这种场景下,MultipartFile对象非... 目录1. 基本需求2. 自定义 MultipartFile 类3. 实现代码4. 代码解析5. 自定

使用Python实现无损放大图片功能

《使用Python实现无损放大图片功能》本文介绍了如何使用Python的Pillow库进行无损图片放大,区分了JPEG和PNG格式在放大过程中的特点,并给出了示例代码,JPEG格式可能受压缩影响,需先... 目录一、什么是无损放大?二、实现方法步骤1:读取图片步骤2:无损放大图片步骤3:保存图片三、示php