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 领域的坚实步伐。