你的第一个神经网络:用PyTorch/Keras实现手写数字识别

你的第一个神经网络:用PyTorch/Keras实现手写数字识别

你是否曾好奇人工智能是如何"看懂"手写数字的?在本教程中,我们将从零开始,带你构建你的第一个神经网络模型,使用深度学习框架 PyTorch 或 Keras,在经典的 MNIST 手写数字数据集上进行训练与测试。无论你是深度学习的新手,还是希望巩固基础知识,这篇指南都将帮助你理解数据预处理、模型搭建、训练流程和性能评估等核心步骤。只需几十行代码,你就能亲手打造一个准确率超过 95% 的数字识别器------让我们一起迈出 AI 编程的第一步!

一、为什么选择手写数字识别作为入门?

手写数字识别(MNIST 数据集)是深度学习领域的"Hello World",它完美平衡了学习门槛和实战价值:

  • 数据友好:MNIST 包含 7 万张 28×28 像素的手写数字图片(6 万训练集 + 1 万测试集),无需复杂的数据集采集和清洗;
  • 逻辑清晰:核心目标是"分类",输出仅 0-9 十个类别,容易理解模型的输入输出逻辑;
  • 效果直观:训练后能直接输入手写数字图片验证结果,成就感拉满;
  • 技术通用:涉及的"数据预处理-模型搭建-训练-评估"全流程,是所有深度学习项目的通用范式。

二、环境准备

在开始编码前,先搭建基础环境(建议使用 Anaconda 管理环境):

bash 复制代码
# 创建并激活虚拟环境
conda create -n mnist_demo python=3.9
conda activate mnist_demo

# 安装依赖(二选一,PyTorch 或 Keras)
# PyTorch 版本(适配CPU/GPU,自动匹配系统)
pip3 install torch torchvision matplotlib numpy
# Keras 版本(基于TensorFlow)
pip install tensorflow keras matplotlib numpy

三、PyTorch 实现方案(新手友好版)

3.1 完整代码

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
import numpy as np

# 1. 数据预处理:加载并标准化MNIST数据集
# 定义数据转换(转张量 + 标准化)
transform = transforms.Compose([
    transforms.ToTensor(),  # 将图片转为张量,像素值归一化到0-1
    transforms.Normalize((0.1307,), (0.3081,))  # MNIST数据集的均值和标准差
])

# 加载训练集和测试集
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root='./data', train=False, download=True, 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)

# 2. 搭建简单的神经网络
class SimpleNN(nn.Module):
    def __init__(self):
        super(SimpleNN, self).__init__()
        # 输入层(28×28=784个像素)→ 隐藏层1 → 隐藏层2 → 输出层(10个类别)
        self.fc1 = nn.Linear(784, 128)  # 全连接层1:784→128
        self.fc2 = nn.Linear(128, 64)   # 全连接层2:128→64
        self.fc3 = nn.Linear(64, 10)    # 输出层:64→10

    def forward(self, x):
        # 展平输入:(batch_size, 1, 28, 28) → (batch_size, 784)
        x = x.view(-1, 784)
        # 隐藏层激活(ReLU:非线性变换,让模型能学习复杂特征)
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        # 输出层不激活(后续用CrossEntropyLoss,内置Softmax)
        x = self.fc3(x)
        return x

# 3. 初始化模型、损失函数、优化器
model = SimpleNN()
criterion = nn.CrossEntropyLoss()  # 交叉熵损失(分类任务专用)
optimizer = optim.Adam(model.parameters(), lr=0.001)  # Adam优化器,学习率0.001

# 4. 训练模型
def train_model(model, train_loader, criterion, optimizer, epochs=5):
    model.train()  # 切换到训练模式
    for epoch in range(epochs):
        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()
            # 每100个批次打印一次进度
            if batch_idx % 100 == 99:
                print(f'Epoch {epoch+1}/{epochs}, Batch {batch_idx+1}, Loss: {running_loss/100:.4f}')
                running_loss = 0.0
    print('训练完成!')

# 训练5轮(epochs)
train_model(model, train_loader, criterion, optimizer, epochs=5)

# 5. 测试模型准确率
def test_model(model, test_loader):
    model.eval()  # 切换到评估模式(禁用Dropout等训练特有的层)
    correct = 0
    total = 0
    with torch.no_grad():  # 禁用梯度计算,加速推理
        for data, target in test_loader:
            output = model(data)
            # 取预测概率最大的类别作为结果
            _, predicted = torch.max(output.data, 1)
            total += target.size(0)
            correct += (predicted == target).sum().item()
    accuracy = 100 * correct / total
    print(f'测试集准确率: {accuracy:.2f}%')
    return accuracy

# 执行测试
test_accuracy = test_model(model, test_loader)

# 6. 可视化预测结果(选一张测试集图片验证)
def show_prediction(model, test_dataset, idx=0):
    model.eval()
    # 获取单张图片和标签
    image, label = test_dataset[idx]
    # 添加batch维度(模型要求输入是批量)
    image = image.unsqueeze(0)
    # 预测
    with torch.no_grad():
        output = model(image)
        _, predicted = torch.max(output, 1)
    
    # 可视化
    plt.imshow(image.squeeze().numpy(), cmap='gray')
    plt.title(f'真实标签: {label}, 预测标签: {predicted.item()}')
    plt.axis('off')
    plt.show()

# 展示第10张测试图片的预测结果
show_prediction(model, test_dataset, idx=10)

3.2 核心代码解释

  • 数据预处理transforms 完成"图片转张量+标准化",DataLoader 实现批量加载和打乱数据,提升训练效率;
  • 模型结构 :3层全连接网络,通过 ReLU 激活函数引入非线性,让模型能学习数字的边缘、形状等特征;
  • 训练流程:核心是"前向传播(算预测)→ 计算损失 → 反向传播(算梯度)→ 优化器更新参数"的循环;
  • 评估环节torch.no_grad() 禁用梯度计算,避免不必要的内存消耗,通过对比预测标签和真实标签计算准确率。

四、Keras 实现方案(更简洁)

4.1 完整代码

python 复制代码
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten
from tensorflow.keras.utils import to_categorical

# 1. 加载并预处理数据
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# 归一化:像素值从0-255缩放到0-1
x_train = x_train / 255.0
x_test = x_test / 255.0

# 标签独热编码(分类任务要求)
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)

# 2. 搭建模型
model = Sequential([
    Flatten(input_shape=(28, 28)),  # 展平:28×28→784
    Dense(128, activation='relu'),  # 隐藏层1:128个神经元,ReLU激活
    Dense(64, activation='relu'),   # 隐藏层2:64个神经元,ReLU激活
    Dense(10, activation='softmax') # 输出层:10个神经元,Softmax激活(输出概率)
])

# 3. 编译模型
model.compile(
    optimizer='adam',  # Adam优化器
    loss='categorical_crossentropy',  # 交叉熵损失
    metrics=['accuracy']  # 监控准确率
)

# 4. 训练模型
history = model.fit(
    x_train, y_train,
    batch_size=64,
    epochs=5,
    validation_split=0.1  # 用10%的训练集做验证
)

# 5. 评估模型
test_loss, test_acc = model.evaluate(x_test, y_test)
print(f'测试集准确率: {test_acc:.2f}%')

# 6. 可视化训练过程
plt.plot(history.history['accuracy'], label='训练准确率')
plt.plot(history.history['val_accuracy'], label='验证准确率')
plt.xlabel('轮次')
plt.ylabel('准确率')
plt.legend()
plt.show()

# 7. 单张图片预测
idx = 10
image = x_test[idx]
# 添加batch维度
image = np.expand_dims(image, axis=0)
# 预测
prediction = model.predict(image)
pred_label = np.argmax(prediction)
true_label = np.argmax(y_test[idx])

# 展示结果
plt.imshow(x_test[idx], cmap='gray')
plt.title(f'真实标签: {true_label}, 预测标签: {pred_label}')
plt.axis('off')
plt.show()

五、常见问题与优化思路

5.1 新手常见问题

  • 准确率不到95%:可增加训练轮次(如epochs=10)、调整学习率(如0.0005)、增大隐藏层神经元数量;
  • 内存不足:减小batch_size(如32),或使用CPU训练;
  • 数据下载慢 :手动下载MNIST数据集放到./data目录。

5.2 进阶优化方向

  • 改用卷积神经网络(CNN):针对图片的空间特征,准确率可提升至99%以上;
  • 数据增强:随机旋转、平移图片,提升模型泛化能力;
  • 正则化:添加Dropout层、L2正则化,避免过拟合;
  • 超参数调优:用网格搜索/随机搜索优化学习率、批次大小等参数。

六、总结

  1. 手写数字识别是深度学习入门的最佳实践,核心流程为"数据预处理→模型搭建→训练→评估";
  2. PyTorch和Keras都能快速实现基础模型,PyTorch更灵活,Keras更简洁;
  3. 基础全连接网络即可达到95%以上的准确率,进阶可改用CNN进一步提升性能。

通过这个小项目,你不仅掌握了神经网络的核心逻辑,也熟悉了深度学习框架的基本用法。接下来不妨尝试修改模型结构、调整参数,甚至用自己手写的数字图片测试模型------动手实践,才是学习AI的最佳方式!

相关推荐
AI即插即用2 小时前
即插即用系列 | AAAI 2025 Mesorch:CNN与Transformer的双剑合璧:基于频域增强与自适应剪枝的篡改定位
人工智能·深度学习·神经网络·计算机视觉·cnn·transformer·剪枝
W.KN12 小时前
深度学习【一】神经网络
人工智能·深度学习·神经网络
奔袭的算法工程师14 小时前
CRN源码详细解析(4)-- 图像骨干网络之DepthNet和ViewAggregation
人工智能·pytorch·深度学习·目标检测·自动驾驶
小Tomkk18 小时前
PyTorch +YOLO + Label Studio + 图像识别 深度学习项目实战 (一)
人工智能·pytorch·yolo
LaughingZhu18 小时前
Product Hunt 每日热榜 | 2026-01-23
人工智能·经验分享·深度学习·神经网络·产品运营
deep_drink19 小时前
【论文精读(二十三)】PointMamba:点云界的“凌波微步”,线性复杂度终结 Transformer 霸权(NeurIPS 2024)
人工智能·深度学习·神经网络·transformer·point cloud
飞Link19 小时前
PyTorch 核心 API 完全手册:从基础张量到模型部署
人工智能·pytorch·python·深度学习·机器学习
一路向阳~负责的男人1 天前
PyTorch / CUDA 是什么?它们的关系?
人工智能·pytorch·python
岑梓铭1 天前
YOLO深度学习(计算机视觉)一很有用!!(进一步加快训练速度的操作)
人工智能·深度学习·神经网络·yolo·计算机视觉