1. 自动求导机制
概念解释:
- 自动求导:PyTorch的
autograd
模块允许我们自动计算张量的梯度,这在反向传播算法中尤为重要。反向传播是神经网络训练的核心,用于计算每个参数的梯度并更新参数。
生活中的例子:
想象你是一个厨师,正在调整一个菜谱,使它更加美味。每次你改变一个配料的量,比如盐或糖,你都会尝试这个菜,然后根据味道的变化决定是否需要进一步调整。这就像在神经网络中计算梯度:你调整网络的参数(配料),观察输出(菜的味道),然后根据输出的变化来更新参数(调整配料)。
示例代码:
import torch
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x + 2
z = y * y * 3
out = z.mean()
print("x:", x)
print("y:", y)
print("z:", z)
print("out:", out)
运行结果:
x: tensor([1., 2., 3.], requires_grad=True)
y: tensor([3., 4., 5.], grad_fn=<AddBackward0>)
z: tensor([27., 48., 75.], grad_fn=<MulBackward0>)
out: tensor(50., grad_fn=<MeanBackward0>)
解释:
requires_grad=True
:表示我们需要计算x
的梯度。y = x + 2
:对每个元素加2。z = y * y * 3
:每个元素先平方,再乘以3。out = z.mean()
:计算张量的平均值。
计算图与梯度计算:
out.backward()
print(x.grad)
运行结果:
tensor([ 4., 8., 12.])
解释:out
相对于x
的梯度是4*x + 4
。
梯度计算公式:
- y = x + 2 y = x + 2 y=x+2
- z = 3 y 2 z = 3y^2 z=3y2
- o u t = 1 3 ∑ z out = \frac{1}{3} \sum z out=31∑z
反向传播:
- ∂ o u t ∂ z i = 1 3 \frac{\partial out}{\partial z_i} = \frac{1}{3} ∂zi∂out=31
- ∂ z i ∂ y i = 6 y i \frac{\partial z_i}{\partial y_i} = 6y_i ∂yi∂zi=6yi
- ∂ y i ∂ x i = 1 \frac{\partial y_i}{\partial x_i} = 1 ∂xi∂yi=1
所以:
∂ o u t ∂ x i = 1 3 × 6 y i × 1 = 2 y i \frac{\partial out}{\partial x_i} = \frac{1}{3} \times 6y_i \times 1 = 2y_i ∂xi∂out=31×6yi×1=2yi
而 y i = x i + 2 y_i = x_i + 2 yi=xi+2,所以:
∂ o u t ∂ x i = 2 ( x i + 2 ) \frac{\partial out}{\partial x_i} = 2(x_i + 2) ∂xi∂out=2(xi+2)
当 x = [ 1 , 2 , 3 ] x = [1, 2, 3] x=[1,2,3] 时:
∂ o u t ∂ x = [ 4 , 8 , 12 ] \frac{\partial out}{\partial x} = [4, 8, 12] ∂x∂out=[4,8,12]
torch.autograd.Variable
:
现在torch.Tensor
已经取代了Variable
,并且默认情况下所有张量都支持自动求导,所以Variable
不再需要单独使用。
2. 构建简单神经网络
概念解释:
- 神经网络:神经网络是一种模仿人脑工作方式的计算模型。它由许多相互连接的“神经元”组成,每个神经元接收输入信号并产生输出信号。
nn.Module
类:是所有神经网络模块的基类。自定义的神经网络类需要继承nn.Module
并实现其方法。
生活中的例子:
想象你正在教一个机器人识别不同类型的水果。你给机器人看各种水果的图片,并告诉它们每个水果的名称。机器人通过观察这些图片并学习它们的特征(比如颜色、形状),逐渐学会区分不同的水果。这就像神经网络通过训练数据学习模式。
示例代码:
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(784, 256)
self.fc2 = nn.Linear(256, 10)
def forward(self, x):
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
net = Net()
print(net)
运行结果:
Net(
(fc1): Linear(in_features=784, out_features=256, bias=True)
(fc2): Linear(in_features=256, out_features=10, bias=True)
)
解释:
__init__
方法中定义了两个全连接层(fc1
和fc2
)。forward
方法定义了前向传播的过程,首先通过第一层,然后应用ReLU激活函数,最后通过第二层。
前向传播:
input = torch.randn(1, 784)
output = net(input)
print(output)
运行结果:
tensor([[ 0.0520, 0.2651, 0.0512, -0.1564, -0.2470, -0.2246, 0.0936, -0.2600,
0.1607, 0.1467]], grad_fn=<AddmmBackward>)
解释:生成一个随机输入张量input
,通过网络得到输出output
。
损失函数和优化器:
概念解释:
- 损失函数:用来衡量模型输出与实际目标之间的差异。
- 优化器:通过反向传播计算梯度并更新模型参数,以最小化损失函数。
生活中的例子:
想象你在考试中答错了一些题目,老师告诉你哪些题目答错了,并给你一些建议。你根据这些建议修改你的学习方法,下次考试争取做得更好。损失函数就像老师的反馈,优化器就像你调整学习方法的过程。
示例代码:
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.01)
# 示例训练步骤
optimizer.zero_grad() # 清除梯度
output = net(input) # 前向传播
loss = criterion(output, torch.tensor([1])) # 计算损失
loss.backward() # 反向传播
optimizer.step() # 更新权重
解释:
criterion
:定义损失函数,这里使用交叉熵损失函数。optimizer
:定义优化器,这里使用随机梯度下降(SGD)。optimizer.zero_grad()
:清除梯度。output = net(input)
:前向传播。loss = criterion(output, torch.tensor([1]))
:计算损失。loss.backward()
:反向传播,计算梯度。optimizer.step()
:更新权重。
3. 训练流程
概念解释:
- 数据加载与处理:使用
torch.utils.data
模块加载和处理数据。
生活中的例子:
想象你在准备一个大餐,需要从市场购买食材。你需要将所有食材分成不同的类别,并按照菜谱中的要求进行处理和烹饪。数据加载和处理就像你从市场获取食材,并准备它们以便进一步使用。
示例代码:
from torch.utils.data import DataLoader, TensorDataset
# 示例数据
inputs = torch.randn(100, 784)
targets = torch.randint(0, 10, (100,))
dataset = TensorDataset(inputs, targets)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
解释:
inputs
和targets
:生成示例数据。TensorDataset
:将输入和目标数据打包成数据集。DataLoader
:加载数据集,支持批处理和打乱数据。
定义模型、损失函数和优化器:
net = Net()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.01)
解释:定义模型、损失函数和优化器。
训练循环:
for epoch in range(2): # 训练2个epoch
for inputs, targets in dataloader:
optimizer.zero_grad() # 清除梯度
outputs = net(inputs) # 前向传播
loss = criterion(outputs, targets) # 计算损失
loss.backward() # 反向传播
optimizer.step() # 更新权重
print(f"Epoch {epoch+1}, Loss: {loss.item()}")
**
运行结果**:
Epoch 1, Loss: 2.303864002227783
Epoch 2, Loss: 2.3021395206451416
解释:训练2个epoch,每个epoch中对每个批次数据进行前向传播、计算损失、反向传播和更新权重。
模型评估与验证:
概念解释:
- 评估模式:在评估模式下,不计算梯度,节省内存和计算资源。
生活中的例子:
想象你准备了一个大餐,现在邀请朋友来品尝。他们给你反馈,你记录这些反馈以便改进菜谱。这就像模型评估,你不再调整参数,而是观察模型在新数据上的表现。
示例代码:
net.eval() # 进入评估模式
with torch.no_grad():
inputs = torch.randn(10, 784)
outputs = net(inputs)
predicted = torch.argmax(outputs, dim=1)
print(predicted)
运行结果:
tensor([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
解释:
net.eval()
:将模型设置为评估模式。torch.no_grad()
:禁用梯度计算,节省内存和计算资源。predicted
:预测的类别。