目 录CONTENT

文章目录
AI

深度学习:Miniconda + PyTorch + MNIST

TalentQ
2026-05-20 / 0 评论 / 0 点赞 / 3 阅读 / 0 字

目标

  1. 在 Linux + GTX 950M 上用 Miniconda 配置 PyTorch 环境

  2. 掌握 torch.nnDataLoadertorch.no_grad()、模型保存/加载

  3. 训练一个全连接网络(MLP)并在 MNIST 上达到约 97% 准确率

  4. 确保代码能在你的 GTX 950M(4GB,支持 CUDA 11.4)上运行

为什么使用 Miniconda?

  • 轻量:仅几百 MB,不会像 Anaconda 那样占用 3~5 GB 磁盘空间

  • 灵活:只安装你真正需要的包,环境干净

1. 环境配置步骤(Miniconda + PyTorch)

1.1 安装 Miniconda

终端执行:

# 下载 Miniconda 安装脚本(Linux x86_64)
wget -c https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh

# 运行安装脚本
bash Miniconda3-latest-Linux-x86_64.sh

# 按提示操作:按 Enter 阅读协议,输入 yes 同意,默认安装路径即可,最后问是否初始化 conda 时选 yes

安装完成后,关闭并重新打开终端,或执行 source ~/.bashrc,然后测试:

conda --version   # 应显示版本号,如 26.3.2

1.2 创建专用环境(避免污染 base)

conda create -n dl_learning python=3.11 -y
conda activate dl_learning

1.3 安装 PyTorch(先 CPU 版本验证,后续可升级到 GPU)

首先执行 nvidia-smi 查看显卡和驱动信息:

我的驱动已经升级到 CUDA 13.0(驱动版本 582.53),完全兼容目前所有主流 PyTorch 版本(无论使用 CUDA 11.8、12.x 还是未来更新的版本)。GTX 950M 虽然计算能力 5.0 稍老,但驱动足够新,因此可以放心使用 PyTorch 官方提供的 CUDA 12.x 预编译包,兼容性和性能都比 11.x 更好。

1.3.1 CPU 版本(仅使用 CPU 训练,不调用 GPU):

  • 适用场景:只想快速验证代码逻辑,或暂时不想用 GPU。

  • 特点:安装包小,无需 CUDA 驱动支持,但训练慢。

pip install torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 --index-url https://download.pytorch.org/whl/cpu

1.3.2 GPU 版本(使用你的 GPU 加速,推荐)

pip install torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 --index-url https://download.pytorch.org/whl/cu124

重要:CPU 和 GPU 版本不要混装在同一个环境中。如果你先装了 CPU 版,想换 GPU 版,请先用 pip uninstall torch torchvision torchaudio 卸载,再重新安装 GPU 版。

1.4 验证安装

import torch
print(torch.__version__)          # 例如 2.5.1+cpu 或 2.5.1+cu124
print(torch.cuda.is_available())  # 若安装 CPU 版本,应显示 False;若安装 GPU 版本且驱动正常,应显示 True

2. PyTorch 核心组件必学

在写代码前,先快速过一遍以下核心概念(每个都将在后面的完整代码中出现)。

组件

作用

示例

torch.nn.Module

所有神经网络的基类,自定义网络需继承它

class MyNet(nn.Module):

nn.Linear

全连接层(线性变换)

self.fc = nn.Linear(784, 128)

nn.ReLU / nn.LogSoftmax

激活函数 / 输出层变换

x = F.relu(x)

DataLoader

批量加载数据,支持自动打乱、多线程

DataLoader(dataset, batch_size=64, shuffle=True)

torch.no_grad()

禁用梯度计算,常用于评估/推理

with torch.no_grad():

模型保存/加载

torch.save(state, path) / model.load_state_dict(state_dict)

3. 完整实验:全连接网络在 MNIST 上分类

3.1 导入库

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np

# 检查设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")

3.2 加载 MNIST 数据集

transform = transforms.Compose([
    transforms.ToTensor(),          # 将 PIL 图像或 numpy 数组转为 Tensor,并归一化到 [0,1]
    transforms.Normalize((0.1307,), (0.3081,))  # MNIST 均值和标准差(预计算好的)
])

train_dataset = datasets.MNIST('./data', train=True, download=True, transform=transform)
test_dataset  = datasets.MNIST('./data', train=False, download=True, transform=transform)

batch_size = 64
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader  = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

说明:第一次运行会自动下载 MNIST 到 ./data 文件夹,约 11 MB。

3.3 定义全连接网络(MLP)

class MLP(nn.Module):
    def __init__(self):
        super(MLP, self).__init__()
        # 输入 28*28 = 784,输出 10 个类别
        self.fc1 = nn.Linear(28*28, 512)
        self.fc2 = nn.Linear(512, 256)
        self.fc3 = nn.Linear(256, 10)
        self.dropout = nn.Dropout(0.2)   # 防止过拟合

    def forward(self, x):
        x = x.view(x.size(0), -1)        # 展平:从 (batch,1,28,28) -> (batch,784)
        x = F.relu(self.fc1(x))
        x = self.dropout(x)
        x = F.relu(self.fc2(x))
        x = self.dropout(x)
        x = self.fc3(x)                  # 最后一层不激活,因为 CrossEntropyLoss 自带 softmax
        return x

model = MLP().to(device)
print(model)

3.4 定义损失函数和优化器

criterion = nn.CrossEntropyLoss()        # 适合多分类,内部融合了 LogSoftmax + NLLLoss
optimizer = optim.Adam(model.parameters(), lr=0.001)

3.5 训练函数

def train(epoch):
    model.train()   # 启用 dropout 等训练专用层
    total_loss = 0
    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()                 # 更新参数
        
        total_loss += loss.item()
        if batch_idx % 200 == 0:
            print(f'Train Epoch: {epoch} [{batch_idx * len(data)}/{len(train_loader.dataset)} '
                  f'({100. * batch_idx / len(train_loader):.0f}%)]\tLoss: {loss.item():.6f}')
    avg_loss = total_loss / len(train_loader)
    print(f'====> Epoch {epoch} Average loss: {avg_loss:.4f}')

3.6 测试函数(使用 torch.no_grad()

def test():
    model.eval()    # 关闭 dropout 等
    test_loss = 0
    correct = 0
    with torch.no_grad():   # 禁用梯度计算,节省显存和计算
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            test_loss += criterion(output, target).item()  # 累计损失
            pred = output.argmax(dim=1, keepdim=True)      # 取最大概率的类别
            correct += pred.eq(target.view_as(pred)).sum().item()
    
    test_loss /= len(test_loader)
    accuracy = 100. * correct / len(test_loader.dataset)
    print(f'Test set: Average loss: {test_loss:.4f}, Accuracy: {correct}/{len(test_loader.dataset)} ({accuracy:.2f}%)\n')
    return accuracy

3.7 训练并保存模型

epochs = 10
best_acc = 0
for epoch in range(1, epochs + 1):
    train(epoch)
    acc = test()
    # 保存最佳模型
    if acc > best_acc:
        best_acc = acc
        torch.save(model.state_dict(), 'best_mnist_mlp.pth')
        print(f"Saved new best model with accuracy {acc:.2f}%")

print(f"Training finished. Best accuracy: {best_acc:.2f}%")

模型保存torch.save(model.state_dict(), 'best_mnist_mlp.pth') 仅保存可学习参数(字典)。后续加载使用 model.load_state_dict(torch.load('best_mnist_mlp.pth'))

3.8 加载模型并预测单张图片(示例)

# 加载最佳模型
model.load_state_dict(torch.load('best_mnist_mlp.pth', map_location=device))
model.eval()

# 取测试集中第一张图片
test_iter = iter(test_loader)
images, labels = next(test_iter)
img = images[0].unsqueeze(0).to(device)   # 增加 batch 维度

with torch.no_grad():
    output = model(img)
    pred = output.argmax(dim=1).item()
    true_label = labels[0].item()

print(f"Predicted: {pred}, True label: {true_label}")

# 显示图片(若在 WSL2 中无 GUI,可跳过)
# plt.imshow(images[0].squeeze(), cmap='gray')
# plt.title(f'Pred: {pred}, True: {true_label}')
# plt.show()

4. 结果与讨论

预期结果

  • 在 CPU 上训练 10 个 epoch 大约需要 2~3 分钟(GTX 950M 上 GPU 加速约 30 秒)。

  • 测试准确率通常可达 97% ~ 98%(全连接网络在 MNIST 上的上限约为 98.5%)。

关键问题自查

问题

解决方案

torch.cuda.is_available() 返回 False

检查 Windows 端 NVIDIA 驱动是否安装;PyTorch 是否为 GPU 版本;WSL2 是否正常加载驱动(nvidia-smi

显存不足(OOM)

减小 batch_size(如 32 或 16);使用更小网络(如 256→128)

数据下载慢

手动下载 MNIST 并放置到 ./data 目录,或使用镜像源

5. 下一步预告

第1周:CNN 博客

  • 将全连接网络替换为 LeNet-5 或简单 CNN

  • 学习卷积层、池化层、特征图可视化

  • 在 CIFAR-10 数据集上训练并观察效果

在此之前,请确保你已经能完整跑通本文的所有代码,并理解每一行的作用。

6. 参考资料

  1. PyTorch 官方教程:60分钟入门

  2. MNIST 数据集介绍

  3. Miniconda 官方文档

博客后记:本文的完整代码可以在你的 GTX 950M 上直接运行。建议你将此博客作为自己实验笔记的开端,后续每个模型都写出类似的“可复现实验报告”。欢迎在评论区留下你训练得到的最高准确率!


0

评论区