用 PyTorch 实战入门深度学习:一个项目小白的成长日记

CtrlC工程师
2025-06-29 12:09
阅读 313

引言:一次让我焦虑到失眠的项目任务

引言:一次让我焦虑到失眠的项目任务

去年我还在一家中型电商公司做算法工程师,老板突然给我派了个新任务:“你来做个图像分类系统,能自动识别我们平台上的商品图片属于什么类别。”听起来好像很常规,但当时我的知识储备还停留在传统的机器学习模型(比如 SVM、随机森林),对深度学习只在书上和教程里摸过皮毛。于是,我决定从头学起,选择 PyTorch 这个框架作为切入点。

说实话,最开始那几天我真的一点头绪都没有,看着网上的资料感觉都是“会的人写给会的人看的”,完全看不懂那些代码到底是怎么训练模型的。但为了不拖团队后腿,也只能硬着头皮啃,边查文档边试错。这篇笔记,其实就是记录我当时那段痛苦又充实的学习过程,希望能帮到像我一样的初学者少走些弯路。


我们的第一个实战目标:商品图像分类

我们的第一个实战目标:商品图像分类

项目背景很简单——公司每天有几千张用户上传的商品图片,手动分类效率低、出错率高,急需一个能自动将图片分门别类的系统。我们需要做的,就是根据现有的商品数据(带标签)来训练一个图像分类模型,准确地预测新上传图片的类别,比如“衣服”、“电子产品”、“日用品”等等。

我们准备了一个包含 10 万张商品图的小型数据集,分为 50 个类别。图片尺寸大小不一,格式也混杂,有些甚至模糊不清。这其实是一个很现实的问题,在真实工作中,数据总是不完美的。


初识 PyTorch:为什么选它?

在技术选型阶段,我也调研了 TensorFlow 和 Keras,但最终还是决定尝试 PyTorch。主要是因为:

  • 动态计算图(Dynamic Computation Graph) 更容易调试,适合新手理解流程
  • 社区活跃度高,很多论文代码直接使用 PyTorch,学习成本低
  • 调试友好,打印中间变量更方便
  • 和 Python 的契合更好,不像静态图那样需要预先定义结构

不过刚上手的时候,我还是被 PyTorch 的几个概念搞得晕头转向,比如 Tensornn.ModuleDataloader 等等。但我后来发现,只要结合代码边学边练,这些概念很快就能融会贯通。


第一步:搭建你的第一个神经网络

安装和准备环境

安装 PyTorch 其实很简单,我推荐大家去官网 https://pytorch.org/ 自己选版本,比如我那时候是用的如下命令:

pip install torch torchvision torchaudio

其中:

  • torch 是主库
  • torchvision 提供了很多预训练模型和常用数据集(如 CIFAR、ImageNet)
  • torchaudio 处理音频数据的,虽然这个项目没用上,但先装上省得以后麻烦

简单数据加载与预处理

我们的第一步是从本地硬盘读取数据,这里我使用了 PyTorch 的 DatasetDataLoader 类:

from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
import os
from PIL import Image

class CustomImageDataset(Dataset):
    def __init__(self, root_dir, transform=None):
        self.root_dir = root_dir
        self.transform = transform
        self.classes = sorted(os.listdir(root_dir))
        self.class_to_idx = {cls: idx for idx, cls in enumerate(self.classes)}
        
        self.image_paths = []
        for class_name in self.classes:
            class_path = os.path.join(self.root_dir, class_name)
            for img_name in os.listdir(class_path):
                self.image_paths.append((os.path.join(class_path, img_name), self.class_to_idx[class_name]))

    def __len__(self):
        return len(self.image_paths)

    def __getitem__(self, idx):
        image_path, label = self.image_paths[idx]
        image = Image.open(image_path).convert('RGB')
        
        if self.transform:
            image = self.transform(image)
            
        return image, label

然后是数据增强和变换:

transform_train = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor(),
])
dataset = CustomImageDataset(root_dir='data/train', transform=transform_train)
loader = DataLoader(dataset, batch_size=64, shuffle=True)

这部分花了我不少时间,尤其是路径处理这一块,经常遇到文件夹名混乱、部分子目录为空等问题。建议大家一开始先用 print 输出中间变量看看有没有问题,不要怕麻烦。


模型构建:从零开始写网络 or 借鉴大佬的预训练模型?

一开始我是想自己写个小 CNN 网络练手,于是写了这样一个简单的结构:

import torch.nn as nn

class SimpleCNN(nn.Module):
    def __init__(self, num_classes=50):
        super(SimpleCNN, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 16, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Conv2d(16, 32, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        
        self.classifier = nn.Sequential(
            nn.Linear(32 * 56 * 56, 512),
            nn.ReLU(),
            nn.Linear(512, num_classes)
        )

    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size(0), -1)
        x = self.classifier(x)
        return x

跑了几轮之后我发现准确率卡在 50% 左右,根本没提升。这时候我才意识到,作为一个小数据集(只有 10 万张图),想要从零训练一个高性能 CNN 是很困难的,参数量太大,很容易过拟合或者收敛慢。

于是我就改用了 PyTorch 提供的预训练模型,比如 ResNet:

import torchvision.models as models

model = models.resnet18(pretrained=True)
for param in model.parameters():
    param.requires_grad = False  # 冻结前面层

# 替换最后一层输出为 50 类
model.fc = nn.Linear(model.fc.in_features, 50)

这样就省去了大量训练时间,而且效果也好多了。如果你的数据集不大,一定要优先考虑使用预训练模型做迁移学习!


损失函数、优化器与训练循环

PyTorch 的 API 设计真的非常友好,损失函数和优化器都封装得很好:

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.fc.parameters(), lr=1e-3)  # 只训练最后的 fc 层

接下来是训练代码的核心部分(简化版):

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

num_epochs = 10
for epoch in range(num_epochs):
    model.train()
    total_loss = 0
    correct = 0
    total_samples = 0

    for images, labels in loader:
        images, labels = images.to(device), labels.to(device)
        outputs = model(images)
        loss = criterion(outputs, labels)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        _, predicted = torch.max(outputs.data, 1)
        correct += (predicted == labels).sum().item()
        total_samples += labels.size(0)
        total_loss += loss.item()

    print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {total_loss:.4f}, Accuracy: {correct / total_samples * 100:.2f}%")

这段训练代码是我最早写出来的完整版本之一,虽然看起来有点粗糙,但能跑起来就已经是一个飞跃了!


踩过的坑:从显存爆炸到梯度消失,都是成长路上的坎儿

下面是一些我在训练过程中踩过的坑和解决办法,希望对你有帮助:

💥 显存炸了怎么办?

刚开始我不懂如何控制 batch size,一股脑设成 128,结果直接爆显存(GPU 内存不够)。后来学会了查看当前显存占用情况:

nvidia-smi

然后调整 batch_size,一般从 16、32 开始试,特别是如果你用的是大模型(比如 ResNet-101 或以上),batch_size 不要超过 32。

🔁 训练不收敛?检查学习率设置!

有一次我跑了十几轮准确率还是不到 20%,后来才发现是因为学习率设成了 0.1,太大了!Adam 优化器本身对学习率比较敏感,我后来改成 lr=1e-3 效果就好多了。

🧠 准确率卡住不动?可能是冻结层策略不对!

刚开始我把 ResNet 所有层都 freeze 掉了,只训练最后一个全连接层,结果发现验证集准确率一直在 70% 上下浮动,很难突破。后来我尝试解冻一部分卷积层重新微调,准确率一下提到了 85%。

# 解冻部分层
ct = 0
for child in model.children():
    ct += 1
    if ct < 7:  # 解冻前七层
        for param in child.parameters():
            param.requires_grad = True

最终效果:一个简单却实用的商品分类器诞生

经过两轮迭代,我的模型终于稳定下来了,最终在测试集上达到了约 87% 的准确率。虽然没有达到 SOTA,但对于一个小公司来说已经足够用了。我们把这个模型部署在了服务器上,配合前端页面,实现了一个简易的商品分类后台系统。

上线之后用户反馈很好,分类错误明显减少,人工审核工作量下降了 60% 左右。最让我感动的是有一天同事说:“最近图片标注的差错率比以前少了好多,是你做了啥吗?”那一刻我觉得之前熬的夜都值了。


经验总结:PyTorch 入门的几点建议

如果你也在学习 PyTorch,或者刚刚开始接触深度学习,这里有几点我自己的心得可以分享给你:

📚 理论要配实践,动手才是王道

很多人喜欢先把所有原理搞清楚再去写代码,我刚开始也是这样。但后来发现,不如一边查文档一边敲代码来得快。很多时候,你看不懂的理论,跑一遍代码就知道是什么意思了。

📊 数据质量决定上限,模型只是逼近这个上限的方式

我在项目初期花了不少时间清洗数据:剔除重复样本、统一图像尺寸、删掉一些噪声太大的图片。结果训练速度更快了,模型效果也有提升。

⚡ 技术选型不要太追求“高级”

虽然 Transformer、ViT 现在很火,但在中小项目中还是以实用为主。ResNet、MobileNet 这些经典模型依然非常好用,而且社区资源丰富,文档多、例子多,容易上手。

🛠️ 工具链要跟上:用 Jupyter 快速验证 + TensorBoard 查看训练曲线

Jupyter Notebook 是调试的好伙伴,你可以一行行跑代码,观察输出。如果配合 TensorBoard 使用,还能实时查看 loss 和 accuracy 曲线,非常直观。

📖 官方文档和示例一定要看

PyTorch 的官方文档写得很详细,尤其是 torchvision.models 这部分,里面有各种预训练模型的使用说明。另外还有个 GitHub 仓库叫 pytorch/vision,里面有很多实际案例可以直接复制粘贴。


结语:AI 就是不断试错、不断改进的过程

回望这段 PyTorch 学习之路,我最大的感受就是:技术本身并不难,真正难的是面对未知时的坚持和信心

我曾经也怀疑过自己适不适合做算法这条路,也曾因为连续几周调不好一个模型而焦虑不已。但现在回头看,正是这些跌跌撞撞的经历,才让我逐步建立了扎实的技术基础和独立解决问题的能力。

希望这篇文章能成为你旅程中的一个小灯塔,告诉你:即使你是零基础,也可以从一个真实项目出发,一步步走进深度学习的世界。记住,不要怕犯错,也不要怕慢,只要你不放弃,总有一天你会笑着说出“我训练出了第一个好模型!”

最后送你一句话:“代码不会骗人,数据也不会骗人,唯一会骗你的,可能只有你自己半途而废的心。”

Happy coding,欢迎一起探索 AI 的无限可能!

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝