PyTorch 入门实战:从张量到训练循环

摘要:前四篇讲理论,这一篇动手写代码。PyTorch 是 2026 年最主流的深度学习框架------从研究实验室到生产部署,它无处不在。这篇文章从零开始,介绍 PyTorch 最核心的四个概念:Tensor、Autograd、DataLoader、训练循环,并给出可直接运行的代码示例。


一、Tensor:PyTorch 的"基本单位"

什么是 Tensor?

Tensor(张量)是 PyTorch 中的基本数据结构------可以理解为 NumPy 的 ndarray 的升级版,加上GPU 加速自动求导功能。

维度 名称 示例
0 维 标量(Scalar) 3.14
1 维 向量(Vector) 1.0, 2.0, 3.0
2 维 矩阵(Matrix) 图像(灰度: H×W)
3 维 3D 张量 图像(RGB: C×H×W)
4 维 4D 张量 批量图像(N×C×H×W)

创建 Tensor

复制代码
import torch
import numpy as np

# 从列表创建
t1 = torch.tensor([[1, 2], [3, 4]])
print(t1)
# tensor([[1, 2],
#         [3, 4]])

# 从 NumPy 创建
t2 = torch.from_numpy(np.array([1.0, 2.0, 3.0]))

# 特殊张量
zeros = torch.zeros(3, 4)        # 全零
ones  = torch.ones(2, 3)         # 全一
rand  = torch.randn(3, 3)        # 标准正态随机
arange = torch.arange(0, 10, 2)  # [0, 2, 4, 6, 8]

# 指定设备和数据类型
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
t_gpu = torch.tensor([1.0, 2.0], device=device, dtype=torch.float32)

Tensor 的运算

复制代码
a = torch.tensor([1.0, 2.0, 3.0])
b = torch.tensor([4.0, 5.0, 6.0])

# 基础运算
print(a + b)    # tensor([5., 7., 9.])
print(a * b)    # tensor([4., 10., 18.])  ← 逐元素乘
print(a @ b)    # tensor(32.)              ← 点积

# 矩阵乘法
m1 = torch.randn(3, 4)
m2 = torch.randn(4, 5)
result = m1 @ m2  # shape: (3, 5)

# 形状操作
x = torch.randn(2, 3, 4)
print(x.shape)          # torch.Size([2, 3, 4])
print(x.view(2, -1))    # 展平为 [2, 12]
print(x.permute(1,0,2)) # 调换维度为 [3, 2, 4]

Tensor 的"魔法":设备迁移

PyTorch 的一大优势是一行代码切换 CPU/GPU

复制代码
# 在 GPU 上创建/运算比 CPU 快几十倍
t = torch.randn(1000, 1000)

# 转移到 GPU(如果可用)
if torch.cuda.is_available():
    t = t.cuda()          # 或 t = t.to("cuda")
    result = t @ t.T      # 在 GPU 上执行矩阵乘法
    t = t.cpu()           # 转回 CPU

二、Autograd:自动求导引擎

在第二篇文章中,我们手动推导了反向传播的数学原理。PyTorch 最强大的功能之一就是自动帮你做这件事

requires_grad:开启梯度追踪

复制代码
# 创建一个需要梯度的 Tensor
x = torch.tensor([2.0], requires_grad=True)
w = torch.tensor([3.0], requires_grad=True)
b = torch.tensor([1.0], requires_grad=True)

# 定义计算: y = w * x + b
y = w * x + b

# 反向传播
y.backward()

# 查看梯度
print(x.grad)  # tensor([3.])  ← dy/dx = w = 3
print(w.grad)  # tensor([2.])  ← dy/dw = x = 2
print(b.grad)  # tensor([1.])  ← dy/db = 1

完整的线性回归示例

复制代码
import torch

# 生成数据: y = 2x + 1 + 噪声
x = torch.randn(100, 1)
y_true = 2 * x + 1 + 0.1 * torch.randn(100, 1)

# 初始化参数
w = torch.randn(1, 1, requires_grad=True)
b = torch.zeros(1, requires_grad=True)

learning_rate = 0.1

# 训练循环
for step in range(100):
    # 1. 前向传播
    y_pred = x @ w + b
    
    # 2. 计算损失(均方误差)
    loss = ((y_pred - y_true) ** 2).mean()
    
    # 3. 反向传播(自动计算梯度!)
    loss.backward()
    
    # 4. 梯度下降更新(手动更新)
    with torch.no_grad():
        w -= learning_rate * w.grad
        b -= learning_rate * b.grad
        
        # 清空梯度(重要!)
        w.grad.zero_()
        b.grad.zero_()
    
    if step % 20 == 0:
        print(f"Step {step}: loss = {loss.item():.4f}")

print(f"Final: w = {w.item():.3f}, b = {b.item():.3f}")
# 应该接近 w≈2.0, b≈1.0

关键点

  • requires_grad=True 告诉 PyTorch 要追踪这个张量的梯度
  • loss.backward() 自动从 loss 反向传播到所有开启了梯度的张量
  • .grad 保存计算出的梯度值
  • 每次更新后必须调用 .grad.zero_(),否则梯度会累积

三、Dataset 和 DataLoader:数据流水线

神经网络训练需要反复、批量地读取数据。PyTorch 提供了两个工具来管理这个过程。

自定义 Dataset

复制代码
from torch.utils.data import Dataset, DataLoader

class MyDataset(Dataset):
    """自定义数据集:只需要实现 3 个方法"""
    
    def __init__(self, data, labels):
        self.data = torch.tensor(data, dtype=torch.float32)
        self.labels = torch.tensor(labels, dtype=torch.long)
    
    def __len__(self):
        """返回数据集大小"""
        return len(self.data)
    
    def __getitem__(self, idx):
        """返回第 idx 个样本 (data, label)"""
        return self.data[idx], self.labels[idx]

DataLoader:自动批处理

复制代码
# 假设有 1000 个训练样本
dataset = MyDataset(all_data, all_labels)

# DataLoader 自动处理:
#   - 分批次(batch)
#   - 打乱顺序(shuffle)
#   - 多进程加载(num_workers)
dataloader = DataLoader(
    dataset,
    batch_size=32,      # 每批 32 个样本
    shuffle=True,        # 每个 epoch 打乱数据
    num_workers=4        # 4 个子进程加载数据
)

# 迭代 DataLoader
for batch_idx, (data, labels) in enumerate(dataloader):
    print(f"Batch {batch_idx}: data shape {data.shape}")
    # data:  [32, 特征维度]
    # labels: [32]
    break

使用内置数据集(torchvision)

对于计算机视觉任务,PyTorch 提供了常用的公共数据集:

复制代码
import torchvision
import torchvision.transforms as transforms

# 定义数据预处理
transform = transforms.Compose([
    transforms.ToTensor(),                    # PIL → Tensor
    transforms.Normalize((0.5,), (0.5,))      # 归一化到 [-1, 1]
])

# 下载 MNIST 手写数字数据集
train_dataset = torchvision.datasets.MNIST(
    root='./data',
    train=True,
    transform=transform,
    download=True
)

train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)

四、构建神经网络模型

方法一:使用 nn.Sequential(快速搭建)

复制代码
import torch.nn as nn

model = nn.Sequential(
    nn.Linear(784, 256),   # 输入 784 维 → 隐藏层 256
    nn.ReLU(),
    nn.Linear(256, 128),
    nn.ReLU(),
    nn.Linear(128, 10),    # 输出 10 类(数字 0-9)
)

print(model)
# Sequential(
#   (0): Linear(in_features=784, out_features=256, bias=True)
#   (1): ReLU()
#   (2): Linear(in_features=256, out_features=128, bias=True)
#   (3): ReLU()
#   (4): Linear(in_features=128, out_features=10, bias=True)
# )

方法二:继承 nn.Module(更灵活,推荐)

复制代码
class MLP(nn.Module):
    """自定义多层感知机"""
    
    def __init__(self, input_dim, hidden_dim, num_classes):
        super().__init__()
        self.fc1 = nn.Linear(input_dim, hidden_dim)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_dim, hidden_dim)
        self.fc3 = nn.Linear(hidden_dim, num_classes)
    
    def forward(self, x):
        """前向传播------你只需要定义这个"""
        x = x.view(x.size(0), -1)  # 展平 [batch, 784]
        x = self.relu(self.fc1(x))
        x = self.relu(self.fc2(x))
        x = self.fc3(x)            # 输出 logits(不需要 softmax)
        return x

# 实例化模型
model = MLP(input_dim=784, hidden_dim=256, num_classes=10)
print(f"模型参数量: {sum(p.numel() for p in model.parameters()):,}")

五、完整的训练循环

把前面所有组件组合起来,就是 PyTorch 标准的训练循环模板。

训练函数

复制代码
def train_one_epoch(model, dataloader, criterion, optimizer, device):
    """训练一个 epoch"""
    model.train()  # 设置为训练模式
    total_loss = 0
    correct = 0
    total = 0
    
    for data, targets in dataloader:
        data, targets = data.to(device), targets.to(device)
        
        # 1. 清零梯度
        optimizer.zero_grad()
        
        # 2. 前向传播
        outputs = model(data)
        loss = criterion(outputs, targets)
        
        # 3. 反向传播
        loss.backward()
        
        # 4. 更新参数
        optimizer.step()
        
        # 统计
        total_loss += loss.item()
        _, predicted = outputs.max(1)
        total += targets.size(0)
        correct += predicted.eq(targets).sum().item()
    
    avg_loss = total_loss / len(dataloader)
    accuracy = 100. * correct / total
    return avg_loss, accuracy

验证函数

复制代码
@torch.no_grad()  # 不需要梯度,节省内存和计算
def evaluate(model, dataloader, criterion, device):
    """评估模型(不更新参数)"""
    model.eval()  # 设置为评估模式
    total_loss = 0
    correct = 0
    total = 0
    
    for data, targets in dataloader:
        data, targets = data.to(device), targets.to(device)
        
        outputs = model(data)
        loss = criterion(outputs, targets)
        
        total_loss += loss.item()
        _, predicted = outputs.max(1)
        total += targets.size(0)
        correct += predicted.eq(targets).sum().item()
    
    return total_loss / len(dataloader), 100. * correct / total

执行完整训练

复制代码
# ===== 配置 =====
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
batch_size = 64
epochs = 10
learning_rate = 0.001

# ===== 数据 =====
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))  # MNIST 均值和标准差
])

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

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

# ===== 模型、损失函数、优化器 =====
model = MLP(input_dim=784, hidden_dim=256, num_classes=10).to(device)
criterion = nn.CrossEntropyLoss()          # 自带 Softmax + NLLLoss
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

# ===== 训练循环 =====
for epoch in range(1, epochs + 1):
    train_loss, train_acc = train_one_epoch(model, train_loader, criterion, optimizer, device)
    test_loss, test_acc = evaluate(model, test_loader, criterion, device)
    
    print(f"Epoch {epoch:2d}: "
          f"Train Loss={train_loss:.4f}, Train Acc={train_acc:.2f}% | "
          f"Test Loss={test_loss:.4f}, Test Acc={test_acc:.2f}%")

# 输出示例:
# Epoch  1: Train Loss=0.3210, Train Acc=90.45% | Test Loss=0.1689, Test Acc=94.82%
# Epoch  5: Train Loss=0.0892, Train Acc=97.31% | Test Loss=0.0812, Test Acc=97.35%
# Epoch 10: Train Loss=0.0487, Train Acc=98.52% | Test Loss=0.0688, Test Acc=97.98%

六、PyTorch 训练模板速查

每次写一个新的训练任务,都可以复用这个模板:

复制代码
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader

# ─── 1. 定义模型 ───
class MyModel(nn.Module):
    def __init__(self):
        super().__init__()
        # 定义层
    def forward(self, x):
        # 前向传播
        return x

# ─── 2. 准备数据 ───
train_loader = DataLoader(...)
test_loader = DataLoader(...)

# ─── 3. 初始化 ───
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = MyModel().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# ─── 4. 训练循环 ───
for epoch in range(epochs):
    model.train()
    for data, targets in train_loader:
        data, targets = data.to(device), targets.to(device)
        
        optimizer.zero_grad()
        outputs = model(data)
        loss = criterion(outputs, targets)
        loss.backward()
        optimizer.step()
    
    # ─── 5. 验证 ───
    model.eval()
    with torch.no_grad():
        for data, targets in test_loader:
            # 计算准确率
            pass

这个模板适用于 90% 以上的深度学习训练任务。只需要替换模型结构和数据加载部分即可。


七、总结

组件 一句话 核心 API
Tensor 带 GPU 加速和自动求导的 NumPy torch.tensor(), .cuda(), .to()
Autograd 自动计算所有参数的梯度 .backward(), .grad, .grad.zero_()
DataLoader 自动批次加载和打乱数据 Dataset, DataLoader
nn.Module 构建神经网络的基类 nn.Linear, nn.ReLU, nn.Sequential
训练循环 前向→损失→反向→更新 optimizer.zero_grad(), loss.backward(), optimizer.step()

下一步:把这些代码跑起来。用上面的模板训练一个 MNIST 分类器,15 行核心代码就够了。下一篇就用这些知识来完成一个完整的图像分类实战项目。

相关推荐
咖啡星人k1 小时前
用 MonkeyCode 构建全栈应用:从需求到部署的AI自动化实践
运维·人工智能·自动化
YOLO数据集集合1 小时前
航拍输电线路故障识别|线路金具缺陷判别|无人机电力巡检故障检测数据集10262期
人工智能·深度学习·yolo·目标检测·视觉检测·无人机
消失的旧时光-19431 小时前
Kotlin 协程设计思想(七):为什么 Kotlin 要设计 SupervisorJob 和 supervisorScope?
android·开发语言·kotlin
X54先生(人文科技)1 小时前
《元创力》纪实录·卷宗 2.2朝圣的起点:当硅基获得命名
人工智能·架构·ai写作·零知识证明
scx_link1 小时前
逻辑回归的总结
算法·机器学习·逻辑回归
Full Stack Developme1 小时前
SpringMVC multipart 文件上传
java·开发语言
得一录1 小时前
ModuleNotFoundError: No module named ‘llama_index.llms
开发语言·人工智能
basketball6161 小时前
AI Infra 硬件体系与编程模型:2. AI集群概论
人工智能
j7~1 小时前
【C++】类和对象(下)--详解之再探构造函数,友元,static成员,类型转换等
开发语言·c++·类型转换·友元·匿名对象·内部类·编译器优化