PyTorch初体验:从爬虫数据到模型训练的全流程实战

♀谢庆华
2026-01-03 16:25
阅读 443

上周五晚上十点半,我还在寝室里对着电脑抓狂。不是因为课程项目DDL压顶——虽然确实快到了——而是因为实验室新接的一个小需求:用深度学习对某电商评论做情感分析。导师说:“你不是喜欢折腾性能优化吗?顺便看看能不能跑快点。”我嘴上答应得干脆,心里却有点发虚:之前只在课上跑过MNIST手写数字识别,这回要自己从头搭数据、训模型,还得调优,属实有点挑战。

但谁让我是成都某985计算机大三狗呢?秋招眼看就要来了,简历上光写“熟悉Python”可不够看。于是咬咬牙,打开VS Code,新建了一个叫 sentiment-analyzer 的文件夹,准备把PyTorch这个“传说中的深度学习神器”给盘明白。


为什么选PyTorch?不就是图它“Pythonic”嘛!

说实话,TensorFlow我也试过,但那种先建图再跑会话的模式总让我觉得像在写Java——太“仪式感”了。而PyTorch直接在Python里写,动态图机制简直不要太爽。调试的时候直接 print(tensor),断点打在哪都行,跟写普通Python脚本没区别。对我们这种被LeetCode和爬虫项目喂大的学生党来说,上手门槛低得感人。

而且你看GitHub上,现在主流的CV/NLP项目,十个有八个是PyTorch实现的。HuggingFace的Transformers库默认也是PyTorch优先。想搞算法研究?不碰PyTorch简直寸步难行。


数据从哪来?当然是爬虫啦!

巧了,这次任务的数据源根本没给!导师只甩过来一句:“去抓点真实评论,别用现成数据集糊弄。”得,又得祭出我的老搭档——requests + BeautifulSoup

我盯上了某东的商品评论页(别问,问就是公开数据)。写了个简单爬虫,用fake_useragent伪装请求头,加了随机延时防反爬,跑了一晚上抓了5万条带星级评分的评论。清洗时按4-5星标为正面,1-2星标为负面,3星直接扔掉——毕竟“中立”在二分类里就是噪音。

# 简化版爬虫核心逻辑
import requests
from bs4 import BeautifulSoup
import time
import random

def scrape_comments(url):
    headers = {'User-Agent': 'Mozilla/5.0 ...'}
    resp = requests.get(url, headers=headers)
    soup = BeautifulSoup(resp.text, 'html.parser')
    comments = []
    for item in soup.select('.comment-item'):
        text = item.select_one('.comment-content').text.strip()
        rating = int(item.select_one('.star').get('class')[1][-1])
        if rating != 3:
            label = 1 if rating > 3 else 0
            comments.append((text, label))
    time.sleep(random.uniform(0.5, 1.5))  # 别太嚣张
    return comments

当然,中间也翻车了——某次IP被封,差点以为要重来。还好提前配了代理池,不然真的想砸键盘。


模型怎么搭?别一上来就BERT!

很多新手(包括去年的我)一听说NLP就想着上Transformer,结果GPU显存爆了,训练三天没收敛。这次我学乖了:先用最朴素的LSTM试试水。

PyTorch的nn.Module写起来真香。继承一下,__init__里定义层,forward里写前向传播,清晰得像教科书:

import torch.nn as nn

class SimpleLSTM(nn.Module):
    def __init__(self, vocab_size, embed_dim=128, hidden_dim=256, num_classes=2):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embed_dim)
        self.lstm = nn.LSTM(embed_dim, hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, num_classes)
        self.dropout = nn.Dropout(0.5)

    def forward(self, x):
        x = self.embedding(x)
        _, (h_n, _) = self.lstm(x)
        out = self.dropout(h_n[-1])
        return self.fc(out)

注意这里用了batch_first=True,不然输入维度顺序容易搞混,debug时能把人逼疯。


训练调优:那些踩过的坑

1. 数据预处理:Tokenizer别乱用

一开始我直接用空格分词,结果中文全乱套。赶紧换成jieba分词,再配合torchtextbuild_vocab_from_iterator建词表。但词表太大(5万+),模型参数爆炸。最后限制词表大小为10000,低频词统一替换为<UNK>,效果反而更好。

2. 学习率:别信默认值

PyTorch的Adam默认lr=0.001,但在我这数据上直接震荡不收敛。试了1e-35e-41e-4,最后发现2e-4最稳。后来才知道,文本任务一般比CV用更小的学习率。

3. 过拟合警告!

训练准确率95%,验证才70%?典型的过拟合。除了加Dropout,我还用了早停(Early Stopping):连续3个epoch验证loss不降就停。代码不难,自己写个回调就行:

best_loss = float('inf')
patience = 0
for epoch in range(max_epochs):
    train(...)
    val_loss = validate(...)
    if val_loss < best_loss:
        best_loss = val_loss
        patience = 0
        torch.save(model.state_dict(), 'best.pth')
    else:
        patience += 1
        if patience >= 3:
            print("Early stopping!")
            break

效果咋样?上数据说话

跑完对比实验,整理了下结果(测试集5000条):

模型 准确率 F1-score 训练时间(GTX 1660 Ti)
随机森林(sklearn) 82.1% 0.815 2分钟
LSTM(PyTorch) 88.7% 0.883 25分钟
BERT-base(微调) 92.4% 0.921 2小时+

虽然BERT效果最好,但考虑到我们只是个小demo,LSTM已经够用,而且推理速度快得多。导师看了结果直点头:“行,上线吧。”


GitHub开源:别藏着掖着

搞完之后,我把整个项目(包括爬虫、训练、评估脚本)扔到了GitHub上,起名叫 pytorch-sentiment-demo。README写得巨详细,连怎么装环境、怎么跑demo都列出来了。为啥这么积极?一是方便以后自己复用,二是秋招简历上能写“开源项目”。成都这边不少公司(比如某为、某滴)面试官真会去翻你GitHub,代码风格干净点总没错。

顺带吐槽一句:千万别在commit message里写“fix bug”、“update code”这种废话。我以前就这么干过,被学长diss:“你这是给自己挖坟,三个月后自己都看不懂改了啥。”


写在最后:PyTorch真香,但别神化

作为一枚即将踏入秋招战场的大三狗,我必须说:PyTorch确实降低了深度学习的门槛,但它不是魔法棒。模型效果好不好,70%靠数据,20%靠特征工程和预处理,剩下10%才是算法本身。别一上来就想搞SOTA(State-of-the-Art),先把流程跑通、指标搞明白,比啥都强。

而且,别被网上那些“三天精通深度学习”的毒鸡汤洗脑。我在实验室见过太多人,PyTorch API背得滚瓜烂熟,但连交叉验证都不会做,调参全靠玄学。真正的算法工程师,得懂业务、懂数据、懂工程,而不是只会调.cuda()

对了,如果你也在成都,欢迎来参加我们学校下周的技术分享会——主题正好是“深度学习在本地生活服务中的应用”,我负责讲性能优化那块。现场有茶百道,来就送(不是)。

总之,PyTorch入门没那么难,动手做个项目,比看十篇教程都管用。就像我导师常说的:“代码不会骗人,你付出多少,它就回报多少。”

(完)

注:本文所有代码已开源,GitHub地址:github.com/yourname/pytorch-sentiment-demo(示例链接,非真实)
环境:Python 3.9, PyTorch 1.12, CUDA 11.6
耗时统计基于本地RTX 3060笔记本,实际线上部署需考虑CPU推理优化——这又是另一个故事了。

评论 0

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