PyTorch 教程(保姆级教程)

PyTorch 教程:从零开始构建你的第一个深度学习模型

如果你正在学习人工智能或机器学习,那么 PyTorch 一定是你绕不开的工具。它不仅被全球顶尖研究机构广泛采用,也是许多实际项目开发的首选框架。今天,我就带你走进 PyTorch 的世界,用最直观的方式,一步步搭建你人生中的第一个神经网络模型。

别担心,即使你是编程初学者,只要具备基础的 Python 知识,就能跟上节奏。我会用生活化的比喻帮助你理解抽象概念,同时提供可运行的代码示例。整个过程就像搭积木——先学会拼接小块,再逐步组合成复杂的结构。

安装与环境配置

在动手写代码之前,我们得先准备好“工具箱”。PyTorch 的安装非常简单,推荐使用 pip 工具进行安装。

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

注意:如果你的电脑没有 NVIDIA 显卡,或者不想使用 GPU 加速,可以安装 CPU 版本:

pip install torch torchvision torchaudio

安装完成后,我们可以写一个简单的测试代码来验证是否成功:

import torch

print("PyTorch 版本:", torch.__version__)

print("GPU 是否可用:", torch.cuda.is_available())

x = torch.tensor([1.0, 2.0, 3.0])
print("张量 x:", x)

这段代码的作用是:

  • 导入 PyTorch 模块;
  • 打印当前版本,确认安装成功;
  • 检查系统是否支持 GPU(如果支持,训练速度会快很多);
  • 创建一个包含三个数值的张量,这是 PyTorch 中最基本的数据结构。

运行结果应该类似:

PyTorch 版本: 2.1.0
GPU 是否可用: True
张量 x: tensor([1., 2., 3.])

记住:在 PyTorch 中,张量(Tensor)就是数据的载体,它就像是一个可变大小的容器,能装数字、向量、矩阵甚至多维数据。你可以把它想象成一个“智能数组”,不仅能存数据,还能自动记录计算过程,为后续的反向传播做准备。

创建数组与初始化

在深度学习中,我们经常需要生成各种形状的数据。PyTorch 提供了丰富的方法来创建和初始化张量。

常用张量创建方式

import torch

data_list = [[1, 2], [3, 4]]
tensor_from_list = torch.tensor(data_list)
print("从列表创建:", tensor_from_list)

zeros_tensor = torch.zeros(3, 4)  # 3 行 4 列
print("全零张量:", zeros_tensor)

ones_tensor = torch.ones(2, 2)
print("全一张量:", ones_tensor)

rand_tensor = torch.randn(2, 3)
print("随机张量(标准正态分布):", rand_tensor)

eye_tensor = torch.eye(3)
print("单位矩阵:", eye_tensor)

输出示例:

从列表创建: tensor([[1, 2],
                    [3, 4]])
全零张量: tensor([[0., 0., 0., 0.],
                  [0., 0., 0., 0.],
                  [0., 0., 0., 0.]])
全一张量: tensor([[1., 1.],
                  [1., 1.]])
随机张量(标准正态分布): tensor([[ 0.5432, -1.2345,  0.7890],
                                   [-0.1234,  0.4567, -0.8901]])
单位矩阵: tensor([[1., 0., 0.],
                  [0., 1., 0.],
                  [0., 0., 1.]])

💡 小贴士:torch.randn() 生成的是标准正态分布(均值为 0,方差为 1)的随机数,非常适合用于初始化神经网络的权重。

张量属性与操作

张量不仅仅是数据容器,它还自带多种属性和操作方法。

x = torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.float32)

print("形状:", x.shape)           # 输出: torch.Size([2, 3])
print("数据类型:", x.dtype)       # 输出: torch.float32
print("设备位置:", x.device)      # 输出: cpu

x_int = x.long()                  # 转为整数类型
print("转换后类型:", x_int.dtype)

if torch.cuda.is_available():
    x_gpu = x.cuda()
    print("已移动到 GPU:", x_gpu.device)

这些属性让我们能精确控制数据的形态和运行环境,是构建复杂模型的基础。

神经网络的基本构建模块

现在我们来搭建一个最简单的神经网络——全连接网络(Fully Connected Network),它由多个“神经元层”组成,每一层都对输入数据进行线性变换,再通过激活函数引入非线性。

使用 nn.Module 定义模型

import torch
import torch.nn as nn

class SimpleNet(nn.Module):
    def __init__(self, input_size=784, hidden_size=128, output_size=10):
        super(SimpleNet, self).__init__()
        
        # 第一层:输入到隐藏层
        self.fc1 = nn.Linear(input_size, hidden_size)
        
        # 第二层:隐藏层到输出层
        self.fc2 = nn.Linear(hidden_size, output_size)
        
        # 激活函数:ReLU,让网络学会复杂模式
        self.relu = nn.ReLU()
    
    def forward(self, x):
        # 前向传播过程
        x = self.fc1(x)           # 线性变换
        x = self.relu(x)          # 激活函数
        x = self.fc2(x)           # 输出层
        return x

model = SimpleNet(input_size=784, hidden_size=128, output_size=10)

print(model)

输出结果:

SimpleNet(
  (fc1): Linear(in_features=784, out_features=128, bias=True)
  (relu): ReLU()
  (fc2): Linear(in_features=128, out_features=10, bias=True)
)

这个模型就像一条数据流水线:

  • 输入数据(如 784 维的图像像素)进入第一个线性层;
  • 经过 ReLU 激活函数“筛选”出有意义的特征;
  • 再传入第二层,最终输出 10 个分类得分(比如手写数字 0-9)。

模型的前向传播过程

dummy_input = torch.randn(1, 784)  # batch_size=1, features=784

output = model(dummy_input)

print("输出形状:", output.shape)         # 输出: torch.Size([1, 10])
print("输出值:", output)                  # 输出每个类别的得分

这一步就是模型“思考”的过程。它接收原始数据,经过层层计算,输出一个预测结果。

训练流程详解

有了模型,接下来就是训练它。训练的核心是“调整权重”,让模型越来越准。这个过程分为三步:前向传播 → 计算损失 → 反向传播 → 更新参数。

定义损失函数与优化器

criterion = nn.CrossEntropyLoss()

optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

pred = model(dummy_input)          # 前向传播
target = torch.tensor([3])         # 真实标签(假设是数字 3)

loss = criterion(pred, target)
print("损失值:", loss.item())

loss.backward()

optimizer.step()

optimizer.zero_grad()

解释一下:

  • CrossEntropyLoss 将预测概率与真实标签对比,计算误差;
  • SGD 是最基础的优化算法,它根据梯度方向“微调”权重;
  • backward() 是反向传播的关键,它自动计算每个参数对损失的影响;
  • step() 执行更新;
  • zero_grad() 清空梯度,避免下一次训练时叠加。

训练循环模板

num_epochs = 5
for epoch in range(num_epochs):
    # 模拟一个训练批次
    inputs = torch.randn(64, 784)     # 64 个样本,每样本 784 维
    targets = torch.randint(0, 10, (64,))  # 随机标签 0-9

    # 前向传播
    outputs = model(inputs)
    loss = criterion(outputs, targets)

    # 反向传播与更新
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    print(f"Epoch {epoch+1}/{num_epochs}, Loss: {loss.item():.4f}")

这个循环就是模型“学习”的过程。每跑一轮,损失值会逐渐下降,说明模型在不断改进。

实战案例:手写数字识别

我们用一个真实数据集来演示整个流程。这里以 MNIST 手写数字数据集为例,它包含 6 万张训练图像和 1 万张测试图像,每张图是 28x28 像素。

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 = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)

model = SimpleNet(input_size=784, hidden_size=128, output_size=10)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

for epoch in range(3):
    running_loss = 0.0
    for images, labels in train_loader:
        # 展平图像(28x28 -> 784)
        images = images.view(images.size(0), -1)
        
        # 前向传播
        outputs = model(images)
        loss = criterion(outputs, labels)
        
        # 反向传播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        running_loss += loss.item()
    
    print(f"Epoch {epoch+1}, Loss: {running_loss/len(train_loader):.4f}")

运行这个代码,你将在几轮后看到损失值显著下降。这意味着你的模型正在学会识别手写数字。

总结与展望

通过这篇 PyTorch 教程,你已经掌握了构建深度学习模型的核心技能:数据准备、模型定义、前向传播、损失计算、反向传播和参数更新。这些步骤构成了所有神经网络的基础。

虽然我们只实现了一个简单的全连接网络,但它们的原理可以迁移到更复杂的结构中,比如卷积神经网络(CNN)、循环神经网络(RNN)甚至 Transformer。

记住,学习 PyTorch 的关键不是死记硬背 API,而是理解“数据如何流动”、“模型如何学习”、“损失如何引导优化”。当你能用这些思想去解释每行代码时,你就真正掌握了它。

继续动手实践吧!尝试加载自己的数据集,调整网络结构,更换优化器,甚至加入正则化技术。每一步探索,都是通往 AI 领域的坚实步伐。