PyTorch入门实战:从环境搭建到MNIST手写数字识别的完整指南
2026/9/9 7:48:56 网站建设 项目流程

刚开始用PyTorch那会儿,我真是被各种概念绕得晕头转向。tensorautogradnn.Module,每个词单独看都懂,合在一起就不知道该怎么下手。尤其是看到教程里那一长串训练代码,第一反应就是“这玩意儿到底是怎么跑起来的”。但等到第十天,当你把环境搭好、把张量运算弄明白、亲手跑通一个手写数字识别,那种“原来如此”的感觉确实很爽。

这篇文章就当作你学习PyTorch的“Day 10”总结。我不会堆砌文档式的概念,而是把我从零开始折腾的路径、踩过的坑、以及现在回头看得出的经验,全部拆开揉碎讲给你听。内容包括环境搭建的完整流程、核心组件的运行逻辑、一个可以直接跑起来的实战项目,还有新手最容易卡住的报错合集。适合刚学完Python基础、想踏入深度学习大门,或者已经在用TensorFlow想换个框架看看的人。

1. 整体设计思路:为什么是PyTorch,以及它到底解决了什么问题

在动手写代码之前,先聊聊框架选型这件事。很多人一上来就纠结“PyTorch和TensorFlow到底选哪个”,其实这个问题的答案在过去几年已经变得非常清晰了。PyTorch在学术圈和工业界的地位,从Arxiv论文占比、GitHub star数、Kaggle竞赛方案分布就能看出来,它已经成了深度学习默认的“第一语言”。TensorFlow依然在特定场景有它的优势,但对于绝大多数个人学习和中小规模项目来说,PyTorch的灵活性和直观性是无可替代的。

1.1 动态计算图:写起来就像写普通Python代码

PyTorch最核心的设计哲学是“动态计算图”。这意味着你的模型结构是逐行执行、逐行构建的,而不是先定义好整个图再传入数据。举个例子,你在写模型的前向传播时,可以直接用Python的if语句控制流程,可以根据张量的形状动态调整操作,甚至可以随时打印中间结果调试。这在处理循环神经网络、变长序列时特别舒服。

对比之下,TensorFlow 1.x时代的静态图模式,你得先把计算图“雕刻”好,再通过Session去执行,调试体验相当痛苦。虽然TensorFlow 2.x也默认启用了动态模式,但从生态和习惯来看,PyTorch的这种方式更贴近Python开发者原有的思维习惯。

1.2 自动求导机制:深度学习不用再手动算梯度

深度学习训练的本质,就是通过反向传播计算损失函数对每个参数的梯度,然后用梯度下降法更新参数。如果没有自动求导框架,你得手动推导每个矩阵运算的梯度公式,写出来不仅是体力活,还特别容易出错。

PyTorch的autograd机制把这个过程完全自动化了。只要张量设置了requires_grad=True,每次执行运算时,PyTorch都会记录下这张“计算图”。当你调用loss.backward()时,梯度信息就会自动沿着图反向传播到每个叶节点张量。

用生活化的类比来说,这就像你在手机地图上导航,规划好的路线就是计算图。每次经过一个路口(即一次张量运算),地图都会记录。当你需要知道自己在这个路口该往哪转(即求偏导)时,系统直接根据记录的路线告诉你结果,不需要你重新跑一遍全程去计算。

1.3 生态与社区:你要的模块基本都有人帮你写好了

PyTorch的生态有多丰富?从图像处理的torchvision,到自然语言处理的transformers,再到图神经网络的PyTorch Geometric,几乎每个细分领域都有官方或社区维护的高质量库。这意味着你不需要从零实现每一个细节,遇到问题时通过搜索引擎或官方文档很快能找到类似场景的解决方案。

对于一个“Day 10”阶段的初学者来说,生态成熟带来的直接好处是学习成本低、坑少、范例多。

2. 环境搭建全流程:从零到能跑通GPU训练

很多人学PyTorch的第一步就被环境卡住了,装了半天不是版本不匹配,就是装上之后没法用GPU。这里我按实际操作的顺序,把环境搭建的完整流程走一遍,并且把关键的选择逻辑讲清楚。

2.1 版本选型和对应关系:别再什么最新装什么了

安装PyTorch最忌讳的就是无脑选“最新版”。PyTorch版本、Python版本、CUDA版本三者之间存在严格的配套关系。装错了轻则警告,重则直接无法使用GPU。

这里给你一个截至最近的稳定搭配参考:

PyTorch版本Python版本支持CUDA版本cuDNN建议版本
2.0.x3.8 - 3.1111.7 / 11.88.5+
2.1.x3.8 - 3.1211.8 / 12.18.7+
2.2.x3.8 - 3.1211.8 / 12.18.9+
2.3.x3.8 - 3.1211.8 / 12.18.9+

关于如何确认自己显卡支持的CUDA版本,这里有个常见的误区。不是说你从NVIDIA官网看到自己驱动支持CUDA 12.2,就一定得装12.1的PyTorch版本。PyTorch在安装时会捆绑自己需要的CUDA运行库,它需要的只是驱动支持对应的CUDA版本。所以更准确的判断方法是打开终端执行nvidia-smi,看右上角的CUDA Version。如果是12.x,那装11.8或12.1的PyTorch都没问题。如果是11.x,那建议装11.8的PyTorch版本。

2.2 创建隔离环境:别把系统Python搞乱了

强烈建议你使用conda或venv创建独立的Python环境,而不是直接装在系统Python里。深度学习项目的依赖错综复杂,今天装PyTorch,明天装TensorFlow,后天装spaCy,如果全堆在基础环境里,用不了多久依赖冲突就会让你崩溃。

用conda创建环境的命令如下:

conda create -n pytorch python=3.10 conda activate pytorch

把Python锁定在3.10是一个相对稳健的选择,因为PyTorch官方和大多数第三方库对这个版本的支持都已经非常成熟。创建好环境之后,后续所有操作都在这个环境里进行。

2.3 安装命令的选择:pip还是conda?

这是一个很经典的问题。我的建议是:普通情况用pip,有科学计算依赖需求(比如需要mkl优化)或者网络条件更偏好conda时用conda。实际体验下来,pip在PyTorch安装上更直接,版本选择也更灵活。

以当前主流的CUDA 12.1版本为例,pip安装命令是:

pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121

如果你电脑没有NVIDIA显卡,或者暂时不想用GPU,安装CPU版本即可:

pip install torch torchvision torchaudio

注意,CPU版本和GPU版本的安装包是完全不同的,不要把两个版本混装,不然容易出现“torch.cuda.is_available()返回False但自己明明有显卡”的情况。

国内网络环境下,直接访问PyTorch官方下载源可能会比较慢。这时建议使用国内镜像源,但需要特别提醒的是,直接使用清华源或阿里源安装PyTorch时,通常会拿到CPU版本,因为官方源的GPU版本包并不在镜像站上。所以如果你想装GPU版本,建议还是老老实实从官方源下载。要是速度实在太慢,可以加上--proxy参数临时指定代理,不过这个要根据你自己的网络情况来处理。

2.4 验证安装是否成功:不只是看版本号

安装完成之后,大部分人直接运行python -c "import torch; print(torch.__version__)"就完事了。这只能证明torch装上了,不能证明GPU真的能用。更完整的验证命令是:

python -c "import torch; print(torch.__version__); print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'CPU only')"

如果输出True和你的显卡型号,说明GPU环境配置成功。如果torch.cuda.is_available()返回了False,别急着重装,先看看是不是安装时选错了版本,或者驱动没有更新到位。

2.5 基础张量操作:先让数据在手里流动起来

环境搭建好之后,第一件该练手的事就是张量运算。张量可以理解为多维数组,和NumPy里的ndarray非常相似,区别在于张量能够在GPU上加速计算,并且支持自动求导。

常用操作大概有这些:

import torch # 创建张量 a = torch.tensor([1, 2, 3]) # 直接创建 b = torch.zeros(2, 3) # 全0张量 c = torch.ones(2, 3) # 全1张量 d = torch.randn(2, 3) # 标准正态分布随机数 e = torch.arange(1, 10).reshape(3, 3) # 创建连续序列并改变形状 # 张量属性 print(a.shape, a.dtype, a.device) # 与NumPy互相转换 import numpy as np arr = np.array([1, 2, 3]) tensor_from_np = torch.from_numpy(arr) back_to_np = tensor_from_np.numpy() # 张量运算 x = torch.tensor([1.0, 2.0, 3.0]) y = torch.tensor([4.0, 5.0, 6.0]) print(x + y) # 加法 print(x * y) # 逐元素乘法 print(torch.matmul(x, y)) # 点乘 # 移入GPU if torch.cuda.is_available(): gpu_tensor = x.to('cuda') print(gpu_tensor.device)

这里有个细节值得注意:张量的dtype默认是torch.int64(对于整数)或torch.float32(对于浮点数),但大多数模型计算需要float32float16。如果你的输入数据是double类型的float64,在某些模型操作中可能会报类型不匹配的错误。养成习惯,输入模型前先检查数据dtype。

3. 核心组件拆解:Dataset、nn.Module、autograd怎么协作

环境通了,张量操作也熟手了,接下来就是理解PyTorch的三大核心组件:数据加载(Dataset和DataLoader)、模型构建(nn.Module)、自动求导(autograd)。这三个组件就像流水线上的三个工序:数据准备、模型计算、梯度更新。

3.1 Dataset和DataLoader:把数据管理起来

深度学习训练不能把整个数据集一次性塞进内存,而是需要通过数据集类管理数据,再通过数据加载器进行批量读取和洗牌。

Dataset是一个抽象类,你需要继承它并实现两个方法:__len__返回数据集大小,__getitem__根据索引返回一组数据和对应的标签。DataLoader则负责把Dataset中的样本按批次装载、打乱顺序、多线程并行加载。

举个最简单的自定义例子:

from torch.utils.data import Dataset, DataLoader import torch class MyDataset(Dataset): def __init__(self, data, labels): self.data = data self.labels = labels def __len__(self): return len(self.data) def __getitem__(self, index): x = self.data[index] y = self.labels[index] return x, y # 创建模拟数据 data = torch.randn(100, 3) # 100个样本,每个3个特征 labels = torch.randint(0, 2, (100,)) # 100个二元标签 dataset = MyDataset(data, labels) dataloader = DataLoader(dataset, batch_size=16, shuffle=True, num_workers=2) # 迭代查看批次 for batch_x, batch_y in dataloader: print(batch_x.shape, batch_y.shape) break

batch_size这个参数非常讲究。设太大,GPU显存吃不消;设太小,训练速度慢、梯度更新方向噪声大。经验之谈:从16或32开始,如果显存不足再调小到8或4。shuffle=True在训练阶段很重要,它防止模型学到数据顺序中的假模式;但验证/测试阶段通常shuffle=False,保证评估结果的稳定性。

3.2 nn.Module:模型就是层层叠叠的组件

nn.Module是所有神经网络模块的基类。你看过的各种模型定义,本质上都是继承了这个类,然后在__init__中定义层结构,在forward中定义数据的前向传播逻辑。

一个标准的线性模型定义就像这样:

import torch.nn as nn import torch.nn.functional as F class SimpleNet(nn.Module): def __init__(self): super(SimpleNet, self).__init__() self.fc1 = nn.Linear(3, 128) # 全连接层:3个输入特征 -> 128个隐藏单元 self.fc2 = nn.Linear(128, 2) # 全连接层:128个隐藏单元 -> 2个输出类别 def forward(self, x): x = F.relu(self.fc1(x)) # 激活函数 x = self.fc2(x) return x

这里有几个关键点:

super().__init__()不能漏,否则模块内部的参数注册机制会失效,模型就训练不起来。forward方法决定了数据从输入到输出的路径,PyTorch允许你在这里写任意Python逻辑。

nn.Linear(in_features, out_features)自动创建了权重矩阵和偏置项,并且默认进行了合理的随机初始化。你可能好奇这些权重是怎么被优化的,关键在于模型的parameters()方法会递归收集所有子模块的可训练参数。

3.3 训练循环:三个步骤反复执行

有了数据和模型,训练循环不过是在做一件重复的事:拿一批数据、算预测值、算损失、反向传播、更新参数。标准的训练循环模板如下:

import torch.optim as optim model = SimpleNet() criterion = nn.CrossEntropyLoss() # 分类问题用交叉熵损失 optimizer = optim.Adam(model.parameters(), lr=0.001) num_epochs = 10 for epoch in range(num_epochs): running_loss = 0.0 for batch_x, batch_y in dataloader: # 1. 清零梯度 optimizer.zero_grad() # 2. 模型前向计算 outputs = model(batch_x) # 3. 计算损失 loss = criterion(outputs, batch_y) # 4. 反向传播计算梯度 loss.backward() # 5. 更新参数 optimizer.step() running_loss += loss.item() print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {running_loss / len(dataloader):.4f}')

optimizer.zero_grad()这一步很多人容易漏掉。PyTorch会自动累积梯度,如果你不清零,上一次迭代的梯度会和当前梯度叠加,导致参数更新方向严重偏离。正确的顺序是:清零梯度、前向计算、计算损失、反向传播、更新参数,每一步都有它存在的意义。

loss.item()的作用是把包含梯度信息的张量转换为普通的Python浮点数。如果你直接print(loss),输出的会是tensor(0.xxxx, grad_fn=<...>),不仅难看,而且会占用显存资源。

提醒:训练过程中如果loss出现nan,优先检查学习率是否过大,其次是检查数据中是否有异常值(比如包含无穷大或极端的数值)。

4. 实操:从零跑通一个手写数字识别项目

纸上谈兵终觉浅,真正能让“Day 10”这个阶段产生质变的,是一次完整的实战。这里我带你把MNIST手写数字识别从头到尾实现一遍。这个项目堪称深度学习的“Hello World”,内容涵盖了数据加载、网络构建、训练评估的所有核心流程。

4.1 数据准备:用官方数据集直接开练

torchvision内置了MNIST数据集,下载之后使用DataLoader封装即可:

import torch import torchvision import torchvision.transforms as transforms # 数据预处理:把PIL图像转换为Tensor,并归一化到 [-1, 1] transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) # 下载并加载训练集 train_dataset = torchvision.datasets.MNIST( root='./data', # 数据保存路径 train=True, # 是否为训练集 transform=transform, # 数据预处理 download=True # 是否下载 ) # 下载并加载测试集 test_dataset = torchvision.datasets.MNIST( root='./data', train=False, transform=transform, download=True ) train_loader = torch.utils.data.DataLoader( train_dataset, batch_size=64, shuffle=True, num_workers=2 ) test_loader = torch.utils.data.DataLoader( test_dataset, batch_size=64, shuffle=False, num_workers=2 )

数据预处理中的Normalize((0.5,), (0.5,))作用是把像素值从[0, 1]映射到[-1, 1]。为什么要做这一步?因为零中心化的数据能让网络训练更稳定,梯度下降更容易收敛。如果数据是3通道的,则使用Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))

4.2 搭建CNN模型:在__init__里堆层,在forward里串行

MNIST用的是28x28的灰度图,用全连接网络当然也能做,但卷积神经网络(CNN)明显效果更好。这里定义一个简单的两层卷积网络:

import torch.nn as nn import torch.nn.functional as F class MNISTCNN(nn.Module): def __init__(self): super(MNISTCNN, self).__init__() # 卷积层:1通道输入,32个输出通道,卷积核大小3x3 self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1) # 卷积层:32通道输入,64个输出通道,卷积核大小3x3 self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) # 池化层:2x2最大池化 self.pool = nn.MaxPool2d(2, 2) # 全连接层:经过两次卷积和池化后,尺寸为7x7x64,展平后为7*7*64 self.fc1 = nn.Linear(7 * 7 * 64, 128) self.fc2 = nn.Linear(128, 10) # 10个类别 def forward(self, x): x = self.pool(F.relu(self.conv1(x))) # 28x28 -> 14x14 x = self.pool(F.relu(self.conv2(x))) # 14x14 -> 7x7 x = x.view(-1, 7 * 7 * 64) # 展平 x = F.relu(self.fc1(x)) x = self.fc2(x) return x

关于7 * 7 * 64这个数字怎么来的,可以算一下。输入图像是28x28,经过一次3x3、padding=1的卷积,尺寸保持28x28不变;经过一次2x2最大池化,尺寸减半变成14x14;再经过一次同样卷积(尺寸不变)和池化,变成7x7。此时通道数为64,所以展平后的特征维数是7*7*64 = 3136。很多新手在这里算错尺寸,导致后面nn.Linear输入维度不匹配,被报错折磨半天。这个小计算题值得自己手算一遍,以后换网络结构就知道怎么推了。

4.3 训练过程和效果验证:看loss曲线说话

模型定义好,接下来就是标准的训练循环。这里我把训练和测试写在一起,方便你看全流程:

import torch.optim as optim device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = MNISTCNN().to(device) criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) num_epochs = 5 for epoch in range(num_epochs): model.train() running_loss = 0.0 for images, labels in train_loader: images, labels = images.to(device), labels.to(device) optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() * images.size(0) epoch_loss = running_loss / len(train_dataset) # 测试阶段 model.eval() correct = 0 total = 0 with torch.no_grad(): for images, labels in test_loader: images, labels = images.to(device), labels.to(device) outputs = model(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() accuracy = 100 * correct / total print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {epoch_loss:.4f}, Test Accuracy: {accuracy:.2f}%')

注意到model.train()model.eval()这两个切换了吗?这是新手比较容易忽略的细节。虽然这个简单的CNN里没有DropoutBatchNorm层,但实际上PyTorch中有很多层在训练和推理时的行为不一样(比如Dropout在测试时应该关闭,BatchNorm在测试时应该使用统计量),所以养成习惯,训练和测试前都显式切换到对应模式。

理论上,这个简单的CNN在MNIST上训练5轮后,准确率应该能到99%左右。如果你跑出来准确率只有90%以下,我建议优先检查这几件事:数据预处理是否正确、学习率是否设置合理、网络维度是否匹配、有没有使用GPU(如果是CPU训练,5轮会比较慢,但也能跑完)。

4.4 可视化与下一步:把调试变成直观的事

训练完成后,你可以随机抽取几张测试图像看看模型的预测结果:

import matplotlib.pyplot as plt import numpy as np model.eval() dataiter = iter(test_loader) images, labels = next(dataiter) images, labels = images.to(device), labels.to(device) outputs = model(images) _, predicted = torch.max(outputs, 1) # 显示前6张图像及其预测结果 fig, axes = plt.subplots(1, 6, figsize=(12, 4)) for i in range(6): img = images[i].cpu().numpy().squeeze() axes[i].imshow(img, cmap='gray') axes[i].set_title(f'True: {labels[i].item()}, Pred: {predicted[i].item()}') axes[i].axis('off') plt.show()

你还能用torch.nn.functional里的函数做很多事,比如特征图可视化、混淆矩阵绘制等等。这些“额外”的步骤不要小看,它们能帮你快速定位模型表现不佳的原因。

5. 常见问题与排查技巧:新手最常踩的坑,这里帮你提前踩了

这部分内容是我最想分享的,因为很多教训都是在无数次日复一日的报错中总结出来的。每个问题我都尽量给出判断思路和解决路径。

5.1 安装和pip error

问题:pip安装时总报timeout或者连接错误。这个基本是网络问题。建议使用国内镜像源,但要注意装PyTorch GPU版时最好从官方源下载。如果从官方源下载确实太慢,还可以尝试指定镜像源和官方源的组合方案,比如先从镜像站下载CUDA相关的依赖包,再从官方源下载torch主包,但实际操作起来容易搞混,不推荐新手操作。

问题:已经安装了GPU版PyTorch,但torch.cuda.is_available()仍然为False。排查步骤是先用nvidia-smi确认显卡驱动正常,然后看驱动支持的CUDA版本是否与你安装的PyTorch对应。如果是老显卡驱动(比如支持CUDA 10.x),装最新版PyTorch大概率没法用,需要找旧版本。另外,如果conda环境里的cudatoolkit版本和PyTorch要求的不匹配,也会导致GPU不可用。这种情况把cudatoolkit卸载重装为对应版本即可。

5.2 显存相关错误

问题:RuntimeError: CUDA out of memory这是新手最容易撞上的错误之一。官方建议的解决方向包括:把batch_size调小(从32调到16或8)、减小输入图像尺寸、使用torch.no_grad()包裹推理过程、检查是否有不再用的大张量没有释放。

问题:同一块显存,别人能跑我的程序却跑不了。大概率是你代码里有张量停留在GPU上没有释放,比如将loss保存到list里每个epoch都append一次。用nvidia-smi看到显存占用只增不减时,多半就是这个问题。另外,如果用的是PyTorch Lightning之类的封装框架,它会默认申请整个GPU的显存,不方便其他程序共用。

5.3 模型和训练相关错误

问题:RuntimeError: mat1 and mat2 shapes cannot be multiplied这是张量维度不匹配的问题。多数出现在nn.Linear的输入维度和上一层输出对不上。解决思路是打印一下传入全连接层之前的张量shape,print(x.shape),然后根据实际shape调整nn.Linear的第一个参数。

问题:训练loss一直在降,但测试准确率很低。这大概率是过拟合。对于MNIST这种简单数据集,如果网络过大或训练轮数过多,就可能在测试集上效果变差。解决办法是增加数据增强(transforms.RandomCrop等)、加入Dropout层、或者减小模型容量。

问题:loss值一开始就很大(比如跟上梯度爆炸一样)。排查顺序是检查输入数据是否归一化、检查标签是否正确(有没有超出类别数)、检查学习率是否过大(lr=0.1大概率会炸),最后再检查网络初始化和梯度剪裁。

这里我给出一张速查表,方便以后遇到问题快速对照:

常见报错/现象直接原因优先排查方向
CUDA out of memory显存不足调小batch_size,释放无用张量
mat shapes cannot be multiplied维度不匹配打印每层输出shape,检查view展平逻辑
Expected tensor for argument #1 'input' to have the same dimension数据维度不对检查是否为单通道输入、图像尺寸是否符合网络预期
loss is nan梯度异常检查学习率、数据是否有NaN/Inf、是否除以了0
训练loss下降但验证集不降过拟合加数据增强、Dropout、早停
准确率一直在10%左右(10分类)模型没学到东西检查标签是否错位、数据预处理是否有误、模型是否太大/太小

5.4 调试的小技巧:让问题自己露出马脚

我个人的调试习惯是“分段打印”。模型前向传播时,在每一层后面打印输出tensor的形状,这样一旦维度对不上,立刻就能定位是哪一层出了问题。只盯着最后的报错信息,很多时候等于盲人摸象。

另一个技巧是先用一个小数据集(比如几百条样本)跑通全流程,再放到完整数据上训练。这样可以快速验证模型逻辑——如果模型在小数据上都学不好,那可能模型结构本身就有问题;如果在小数据上能过拟合,再上全量数据效果往往也不会太差。这个“先小后大”的思路能帮你在几分钟内完成一轮完整的代码验证,而不是每次都要等十分钟训练结束才报错。

6. 把学习链路延续下去:从Day 10到更远的下一个里程碑

当你成功跑通MNIST,你已经掌握了深度学习最基本也是最核心的工作流:数据、模型、损失、优化器、循环。接下来的学习方向我个人经验是这样的。

第一,先把分类问题吃透,然后尝试一个回归问题,体会损失函数的变化(从交叉熵到均方误差)带来的差异。第二,用PyTorch实现一个基础的全连接网络,然后换成CNN试试,直观感受参数共享带来的效果变化。第三,可以尝试自己实现一个token级别的语言模型,用nn.LSTMnn.TransformerEncoder做文本预测。第四,关注社区和论文,去读一些经典模型的源码,比如ResNet、Transformer,把代码和原理解析对照着看。

进阶工具方面,可以逐步接触torch.utils.tensorboard做训练可视化,用torch.distributed做多卡训练,或者用onnx导出模型部署。

但这一切都有一个前提:你要持续写代码,持续踩坑。不要急于求成,把每个报错都当成一次学习机会。我自己当时做完MNIST以后,紧接着就去改了一个Kaggle上的花分类数据集,那个过程让我对图像分类的整套流程熟悉了很多。现在回头想,Day 10正是那个“从看教程到自己动手”的关键转折点。

最后分享一个我养成的习惯:每次跑完一个模型,都顺手记录一下当时的参数选择、loss曲线、准确率、遇到的问题,哪怕只是几行字。坚持一段时间,你会发现自己从“照猫画虎”变成“胸有成竹”,遇到新问题时已经开始有自己的判断和解决方案了。祝你在PyTorch这条路上走远、走稳、走开心。

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

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

立即咨询