深度学习实验从0到1:PyTorch环境搭建与MNIST实战
2026/9/8 9:29:32 网站建设 项目流程

简介:一套从0到1的大学深度学习课程实验源码,基于PyTorch框架与Python语言编写,覆盖机器学习基础、前馈神经网络FNN等核心实验,适合计算机、数学、电子信息等专业课程设计、期末大作业和毕设参考,也可供初学深度学习的开发者对照调试。压缩包共90个文件,以53个Python源码文件为主体,另含MNIST数据集、配置文件(xml)、实验效果图(png)及说明文档等,整体大小约119MB,目录按实验章节划分,便于定位到对应任务的实现,目前已有42人学习浏览。源码提供手动实现与PyTorch实现两种版本,例如线性回归、FNN网络,以及Momentum、RMSprop、Adam等多种优化器和L2正则化对比;readme与可视化图片可帮助核对实验思路和输出结果。资源内还包含从数据处理、模型构建到结果展示的完整示例,代码结构清晰并带注释,读者可直接修改运行,结合真实任务快速验证效果,深入理解深度学习模型从建模、训练、评估到预测的完整流程,是课设、毕设与项目起步阶段高效复用的实操素材。 当初选深度学习这门课的时候,我以为课件里的代码都在,照着敲一遍交作业就行。结果第一周就卡在环境安装上,PyTorch 装了好几天,GPU 版本和 CPU 版本来回折腾,最后连个 MNIST 都没跑出来。这门课的实验,难的不是算法本身,而是从零开始把环境、数据、模型、训练、可视化这条链路完整走通。这篇就讲清楚我如何从 0 到 1 完成大学深度学习课程实验源码,选择 PyTorch 框架 + Python 语言的完整路径,包含环境搭建、代码拆解、踩坑记录以及让实验报告拿高分的可视化技巧。适合正在上深度学习课、需要独立完成实验的同学,也适合想快速上手 PyTorch 的初学者。

1. 环境搭建:别让版本问题拖垮实验进度

我见过太多同学在环境上耗掉一周,最后兴趣全无。原因非常统一:一上来就装最新的。Python 出了 3.12 就装 3.12,PyTorch 一有新版本就升级,结果各种包互相不兼容,报错信息堆成山,最后还是乖乖装回旧版本。课程实验的第一原则是稳定能用,不是版本最新。

1.1 版本选型的参考数据

先说结论,这套实验源码用的版本组合是我的主力配置,踩过坑之后固定下来,之后再也没有换过:

组件推荐版本说明
Python3.8 ~ 3.10兼容性最好,3.10 以下装 torch 从来不缺轮子
PyTorch2.0 ~ 2.3功能稳定,教程多,社区解决方案丰富
torchvision与 torch 同版本必须配套,否则会报 undefined symbol 类错误
CUDA11.8 或 12.1覆盖大多数显卡驱动,课程实验完全够用

Python 3.8 看起来老,但它是深度学习生态兼容性最稳的版本。很多课程配套的参考代码基于旧版本 PyTorch 编写,Python 太新反而会触发各种兼容性报错。GPU 版 CUDA 也不需要追新,11.8 到现在依旧是 PyTorch 官方默认支持最成熟的版本之一。

1.2 用 Conda 建虚拟环境而不是直接装在基础环境

直接在系统 Python 里装深度学习库,是拿自己的电脑做实验的大忌。装坏了要重装系统 Python,代价极高。用 Anaconda 或 Miniconda 创建独立虚拟环境,装坏了直接删掉重建,不伤根。

conda create -n dl python=3.9 conda activate dl pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

很多人不理解为什么用 pip 而不是 conda 直接装 torch。原因在于 PyTorch 官方对 pip 的版本控制最及时,conda 源里的 torch 更新往往滞后,而且 CPU 和 GPU 版本选择不直观。pip 指定--index-url能明确安装带 CUDA 的版本,不会出现明明有 GPU 却装成 CPU 版的情况。

1.3 是否必须用 GPU:MNIST 用 CPU 也行

不少同学为没有好显卡焦虑,其实大可不必。MNIST 手写数字识别这类课程实验,图像只有 28×28,数据量 6 万张,CPU 训练 10 个 epoch 也就几分钟。GPU 在这种小任务上的加速优势不明显,反而会引入 CUDA 配置问题。

你只需要在代码开头留一行设备判断,自动适配运行环境:

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

这样在教室电脑和宿舍电脑都能运行。真正的 GPU 需求出现在后续课程会用到的 CIFAR-10、ImageNet 子集或者目标检测任务,那时候再考虑 GPU 环境不迟。

2. MNIST 实验的三板斧:数据、模型、训练循环

第一个实验基本都是 MNIST 手写数字识别,把一张 28×28 像素的灰度图输入模型,输出 0 到 9 之间的数字类别。这是深度学习界的 Hello World,也是从 0 到 1 必过的坎。

2.1 数据加载:Dataset 和 DataLoader

深度学习训练不是把整份数据一次性塞进内存,而是通过 Dataset 管理样本、通过 DataLoader 按批次迭代。PyTorch 的 torchvision 包自带 MNIST 数据集,省去了自己下载和解析的步骤,但这里面的细节很多。

from torch.utils.data import DataLoader from torchvision import datasets, transforms transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) train_dataset = datasets.MNIST( root='./data', train=True, download=True, transform=transform ) train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)

很多人直接ToTensor()就完事,不做归一化也能跑,但效果会差一些。MNIST 官方数据集的像素均值和标准差分别是 0.1307 和 0.3081,这两个常数是公开的,直接用即可。归一化能让像素值分布接近标准正态分布,模型收敛速度更快。

shuffle=True也很关键。如果不打乱训练数据的顺序,模型会先反复看同一类数字,再去学另一类,损失曲线会呈现明显的阶梯状下降,影响收敛稳定性。测试集不需要 shuffle,但评估时要用torch.no_grad(),否则测试过程也会计算梯度,白白浪费显存和算力。

2.2 模型搭建:先从全连接网络开始

课程实验不建议一上来就直接写 CNN,虽然卷积网络准确率更高,但全连接网络的结构更简单,更容易理解前向传播、反向传播和梯度更新的完整流程。先把基础链路跑通,再去追求精度更有成就感。

import torch.nn as nn import torch.nn.functional as F class MLP(nn.Module): def __init__(self): super().__init__() self.fc1 = nn.Linear(28 * 28, 256) self.fc2 = nn.Linear(256, 128) self.fc3 = nn.Linear(128, 10) def forward(self, x): x = x.view(x.size(0), -1) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) return self.fc3(x)

forward里面的x.view(x.size(0), -1)是把 28×28 的图像展平成 784 维的向量,因为全连接网络只能接收一维特征输入。中间隐藏层的维度 256 和 128 是经验值,不需要教科书式的推导,后续课程会学自动确定网络结构的算法,现阶段照常用即可。

激活函数选择 ReLU 而不是 sigmoid 或 tanh,是因为 ReLU 能有效缓解深层网络中的梯度消失问题,计算也更简单。课程实验报告里如果能写出这一层的选择理由,比大篇幅抄概念的含金量高很多。

2.3 训练循环的标准范式

PyTorch 的训练循环几乎是固定写法,只要理解了这段代码,后面所有模型基本都是同一个套路。

import torch.optim as optim model = MLP().to(device) optimizer = optim.Adam(model.parameters(), lr=0.001) criterion = nn.CrossEntropyLoss() for epoch in range(10): for batch_idx, (data, target) in enumerate(train_loader): data, target = data.to(device), target.to(device) optimizer.zero_grad() output = model(data) loss = criterion(output, target) loss.backward() optimizer.step()

这个循环里每一步都有存在的理由。optimizer.zero_grad()是清空上一批次的梯度,如果不做,梯度会在多个 batch 之间累积,导致参数更新混乱。loss.backward()计算当前批次的梯度,optimizer.step()根据梯度更新网络权重。这三个操作顺序固定,少一个都不对。

损失函数用CrossEntropyLoss,它在 PyTorch 里已经内置了 Softmax 操作,所以模型最后一层直接输出原始 logits 即可,不需要手动加 Softmax。这个细节在课程答疑时很多人都搞错过,他们手动加了一层 Softmax 再传入交叉熵损失,导致梯度计算不稳定。

训练结束后,用测试集评估模型准确率:

correct = 0 total = 0 model.eval() with torch.no_grad(): for data, target in test_loader: data, target = data.to(device), target.to(device) output = model(data) pred = output.argmax(dim=1) correct += (pred == target).sum().item() total += target.size(0) print(f"Accuracy: {100 * correct / total:.2f}%")

注意model.eval()torch.no_grad()的区别,前者主要影响 Dropout 和 BatchNorm 这类训练期和测试期行为不同的层,后者是彻底关闭梯度计算,两者配合才能得出可靠的测试结果。

3. 训练过程中最常见的五个问题排查

跑通基础代码只是第一步,真正调模型才会遇见各种问题。下面五个问题是我在课程实验和帮同学排查时出现频率最高的,每个都有明确的定位方法和解决路径。

3.1 损失不下降:学习率的设置问题

现象是训练了好几个 epoch,loss 一直卡在 2.3 附近不动。这种情况九成是学习率设置不合理,要么太大导致参数在最优解附近反复横跳,要么太小导致参数更新幅度微乎其微。

定位方法:打印每个 epoch 的 loss,观察变化趋势。如果 loss 来回抖动,说明学习率过大;如果 loss 始终平平稳稳看不清下降,说明学习率过小。Adam 优化器的默认学习率是0.001,这个值在大多数小规模实验中表现良好,但遇到收敛慢的情况可以按 10 倍规律调整:0.001 -> 0.0001 或 0.01,一次只动一个方向,不要同时改多个超参数。

3.2 训练集效果好,测试集一塌糊涂:过拟合

训练准确率高到 99%,测试准确率却只有 85%,基本可以判定是过拟合。模型把训练集中每张图像的特征细节记住了,但没有学到数字类别的本质规律,一遇到新的样本就露馅。

应对手段按效果排序:

  1. 加入 Dropout 层,在全连接层之间随机丢弃部分神经元,迫使模型学习更鲁棒的特征
  2. 早停,当验证集准确率连续几个 epoch 不提升时直接结束训练
  3. 数据增强,对图像做随机旋转、平移等变换,扩充数据量

这些方法不冲突,可以叠加使用。实验报告里如果能同时给出

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询