PyTorch 神经网络基础(一文讲透)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
前言
在人工智能领域,PyTorch 是一个不可或缺的工具。它以动态计算图、灵活的 API 设计和高效的计算性能,成为科研与工业界广泛采用的深度学习框架。对于编程初学者和中级开发者而言,掌握 PyTorch 神经网络基础不仅是踏入深度学习领域的关键一步,更是构建复杂模型的重要基石。本文将通过循序渐进的方式,结合实例代码和直观比喻,帮助读者理解 PyTorch 的核心概念与实践方法。
什么是 PyTorch?
PyTorch 是由 Facebook 开发的开源机器学习框架,其核心优势在于动态计算图(Dynamic Computation Graph)。与静态计算图框架(如 TensorFlow 的早期版本)不同,PyTorch 允许在运行时动态调整网络结构,这为调试和实验提供了极大便利。此外,PyTorch 的设计理念更贴近 Python 编程习惯,其张量(Tensor)操作与 NumPy 高度兼容,降低了学习门槛。
PyTorch 的核心组件
- 张量(Tensor):数据存储与计算的基本单元,类似多维数组。
- 自动求导(Autograd):自动计算梯度的机制,支持反向传播算法。
- 神经网络模块(nn.Module):封装了层(Layer)、激活函数、损失函数等组件,简化模型搭建。
- 优化器(Optimizer):实现梯度下降的算法工具,如 SGD、Adam 等。
神经网络基础概念
1. 神经元与层
神经网络由大量**神经元(Neuron)**组成,每个神经元接收输入信号,通过加权求和与激活函数处理后输出结果。例如,一个简单的神经元可以表示为:
$$ y = f(w \cdot x + b) $$
其中,$w$ 是权重,$b$ 是偏置,$f$ 是激活函数。
在 PyTorch 中,神经元通常以“层(Layer)”的形式存在。例如,全连接层(nn.Linear
)将输入张量通过线性变换传递到下一层。
2. 激活函数
激活函数为神经网络引入非线性特性,使其能够拟合复杂函数。常见的激活函数包括:
- ReLU(Rectified Linear Unit):$f(x) = \max(0, x)$,简单高效,适合隐藏层。
- Sigmoid:将输出压缩到 (0, 1),常用于二分类问题的输出层。
- Softmax:将输出转化为概率分布,适用于多分类任务。
3. 损失函数与优化目标
损失函数(Loss Function)衡量模型预测值与真实值的差异。例如,均方误差(MSE)用于回归任务,交叉熵(Cross-Entropy)用于分类任务。优化器通过最小化损失函数,调整模型参数(权重和偏置)。
4. 反向传播与梯度下降
反向传播是神经网络的核心算法,通过链式法则计算损失函数对每个参数的梯度。梯度下降则利用这些梯度逐步调整参数,使模型性能持续提升。
张量(Tensor)基础:PyTorch 的数据载体
张量是 PyTorch 的核心数据结构,类似于 NumPy 的多维数组,但支持 GPU 加速和自动求导。以下是一些常用操作:
创建张量
import torch
tensor = torch.rand(2, 3)
print(tensor)
import numpy as np
numpy_array = np.array([[1, 2], [3, 4]])
tensor_from_numpy = torch.from_numpy(numpy_array)
张量运算
a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])
result = a + b # 输出:tensor([5, 7, 9])
matrix1 = torch.rand(2, 3)
matrix2 = torch.rand(3, 4)
product = torch.mm(matrix1, matrix2) # 输出形状为 2x4 的张量
与 NumPy 的对比
功能 | PyTorch 张量 | NumPy 数组 |
---|---|---|
创建 | torch.tensor() | np.array() |
GPU 支持 | 支持(通过 .to('cuda') ) | 不支持 |
自动求导 | 内置支持(通过 requires_grad ) | 无 |
自动求导(Autograd):反向传播的核心
PyTorch 的 autograd
模块通过记录计算图(Computational Graph),自动计算梯度。以下是一个简单示例:
x = torch.tensor(2.0, requires_grad=True)
y = x ** 2 + 3 * x + 5
y.backward() # 计算 dy/dx
print(x.grad) # 输出梯度:2*x + 3 = 2*2 +3 =7
计算图的比喻
想象一个工厂流水线:
- **输入(x)**是原材料,
- **运算(如平方、乘法)**是加工步骤,
- **输出(y)**是最终产品。
反向传播就像逆向追踪每个步骤对最终结果的影响,计算每个“加工步骤”的贡献(梯度)。
构建第一个神经网络:手写数字识别
任务背景
我们将使用 MNIST 数据集(包含 60,000 张训练图像和 10,000 张测试图像),构建一个简单的全连接神经网络,实现手写数字分类。
步骤 1:准备数据
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
train_dataset = datasets.MNIST(root='./data', train=True,
transform=transform, download=True)
test_dataset = datasets.MNIST(root='./data', train=False,
transform=transform)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False)
步骤 2:定义模型
class SimpleNN(nn.Module):
def __init__(self):
super(SimpleNN, self).__init__()
self.fc1 = nn.Linear(28*28, 128) # 输入层到隐藏层
self.fc2 = nn.Linear(128, 64) # 隐藏层到隐藏层
self.fc3 = nn.Linear(64, 10) # 隐藏层到输出层
self.relu = nn.ReLU()
def forward(self, x):
x = x.view(-1, 28*28) # 展平输入张量
x = self.relu(self.fc1(x))
x = self.relu(self.fc2(x))
x = self.fc3(x)
return x
model = SimpleNN()
步骤 3:训练与优化
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
num_epochs = 5
for epoch in range(num_epochs):
model.train()
for images, labels in train_loader:
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
print(f'Epoch {epoch+1}/{num_epochs}, Loss: {loss.item():.4f}')
步骤 4:评估模型
model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy on test set: {100 * correct / total:.2f}%')
训练过程详解
1. 前向传播(Forward Pass)
模型接收输入数据,通过各层计算预测值。例如,在 SimpleNN
中:
- 输入图像(形状 28×28)被展平为 784 维向量。
- 经过
fc1
层(784 → 128)和 ReLU 激活,提取初步特征。 - 再通过
fc2
层(128 → 64)和 ReLU 激活,进一步抽象特征。 - 最终
fc3
层将特征映射到 10 个类别(数字 0-9)。
2. 损失计算
交叉熵损失函数比较预测概率与真实标签,输出一个标量损失值。例如,若真实标签是数字“3”,而模型预测为“5”,损失值将较大。
3. 反向传播与参数更新
优化器根据损失值的梯度,通过以下步骤调整参数:
- 梯度清零:
optimizer.zero_grad()
避免梯度累积。 - 反向传播:
loss.backward()
计算所有参数的梯度。 - 参数更新:
optimizer.step()
使用梯度和学习率(Learning Rate)更新参数。
4. 超参数与调试技巧
- 学习率(Learning Rate):控制参数更新步长,过大会导致震荡,过小会收敛慢。
- 批次大小(Batch Size):平衡训练速度与内存占用,常用值为 32、64、128。
- 正则化:如 L2 正则化(权重衰减)或 Dropout 层,防止过拟合。
扩展思考:优化与进阶
1. 更复杂的模型结构
可以尝试以下改进:
- 卷积神经网络(CNN):通过
nn.Conv2d
和nn.MaxPool2d
处理图像局部特征。 - 残差连接(Residual Connection):缓解深层网络的梯度消失问题。
2. 数据增强与预处理
transform = transforms.Compose([
transforms.RandomRotation(10),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
3. 模型保存与加载
torch.save(model.state_dict(), 'simple_nn.pth')
model = SimpleNN()
model.load_state_dict(torch.load('simple_nn.pth'))
结论
通过本文,读者应已掌握 PyTorch 神经网络的基础知识,包括张量操作、自动求导、模型构建与训练流程。从简单的全连接网络到实际案例的实现,我们看到 PyTorch 如何将抽象的数学概念转化为可执行的代码。
对于初学者,建议从简单任务入手,逐步尝试更复杂的模型(如 CNN、RNN)和数据集(如 CIFAR-10、ImageNet)。中级开发者则可探索分布式训练、模型压缩等进阶主题。记住,实践是掌握 PyTorch 神经网络基础的最佳方式——动手编写代码,调试模型,观察结果,你将逐步揭开深度学习的神秘面纱!
PyTorch 神经网络基础的学习之旅才刚刚开始,但只要保持好奇心和耐心,你定能在这片充满可能性的领域中收获丰硕成果。