自动微分

自动微分

1. 什么是自动微分?

自动微分是深度学习中一个核心的概念,它允许我们高效地计算函数的导数。相较于数值微分和符号微分,自动微分能够在计算图中精确地得到导数,并且计算效率高。

在 PyTorch 中,自动微分是通过 torch.autograd 模块实现的。

2. PyTorch 中的张量和梯度

在 PyTorch 中,张量是基本的数据结构,它与 NumPy 数组非常相似,但有额外的功能,比如支持 GPU 加速和自动微分。

当你创建一个张量时,可以通过设置 requires_grad=True 来指示 PyTorch 需要计算该张量的梯度。

1
2
3
4
import torch

# 创建一个张量并要求计算梯度
x = torch.tensor(2.0, requires_grad=True)

3. 前向传播与计算图

在进行前向传播时,PyTorch 会根据张量的操作创建一个 计算图。每个操作(如加法、乘法)都会记录在计算图中,以便后续的反向传播计算梯度。

1
2
# 定义一个简单的计算
y = x ** 2 + 3 * x + 1 # y = x^2 + 3x + 1

4. 反向传播

一旦得到了结果,就可以通过调用 .backward() 方法来执行反向传播,从而计算要求张量的梯度。

1
2
3
4
5
# 执行反向传播
y.backward()

# 查看梯度
print(x.grad) # 输出 dy/dx,即 y 关于 x 的导数

在上面的情况下,y = x^2 + 3x + 1 的导数是 2*x + 3。当 x=2 时,导数 dy/dx 的值为 2*2 + 3 = 7

5. 多个参数的梯度计算

当模型有多个参数时,自动微分依然可以方便地计算梯度。例如,考虑两个张量:

1
2
3
4
5
6
# 创建两个张量
a = torch.tensor(2.0, requires_grad=True)
b = torch.tensor(3.0, requires_grad=True)

# 定义一个依赖于这两个张量的函数
z = a**2 + 3 * b + a * b # z = a^2 + 3b + ab

进行反向传播后,可以分别获取 ab 的梯度:

1
2
3
4
5
6
# 执行反向传播
z.backward()

# 输出各自的梯度
print(a.grad) # 输出 dz/da
print(b.grad) # 输出 dz/db

6. 清空梯度

在训练神经网络时,每次反向传播都会累加梯度,因此在每次优化步骤之前,需清空梯度。使用 optimizer.zero_grad() 来清空模型参数的梯度。

1
2
3
4
5
6
7
8
9
10
11
12
# 假设我们在使用一个优化器
optimizer = torch.optim.SGD([a, b], lr=0.01)

# 清空梯度
optimizer.zero_grad()

# 计算新一轮的损失和梯度
z = a**2 + 3 * b + a * b
z.backward()

# 更新参数
optimizer.step()

7. 取消梯度跟踪

在某些情况下,我们不希望 PyTorch 跟踪梯度,这可以通过 torch.no_grad() 或者使用 with torch.no_grad(): 上下文管理器来实现,常用于推断阶段。

1
2
3
with torch.no_grad():
# 在这个代码块内不会计算梯度
result = a * b

8. 示例:简单的线性回归

下面是一个使用 PyTorch 自动微分进行线性回归的简化示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import torch

# 生成一些样本数据
x_train = torch.tensor([[1.0], [2.0], [3.0]])
y_train = torch.tensor([[2.0], [3.0], [4.0]])

# 初始化参数
w = torch.tensor([[0.0]], requires_grad=True)
b = torch.tensor([[0.0]], requires_grad=True)

# 学习率
lr = 0.01

# 训练过程
for epoch in range(100):
# 前向传播
y_pred = x_train.mm(w) + b

# 计算损失 (均方误差)
loss = ((y_pred - y_train) ** 2).mean()

# 反向传播
loss.backward()

# 更新参数
with torch.no_grad():
w -= lr * w.grad
b -= lr * b.grad

# 清空梯度
w.grad.zero_()
b.grad.zero_()

# 输出损失
if epoch % 10 == 0:
print(f'Epoch {epoch}, Loss: {loss.item()}')

print(f'学习后的权重: {w.item()}, 偏置: {b.item()}')

在这个示例中,我们进行了线性回归的训练,通过自动微分计算梯度并更新参数。

9. 总结

自动微分是使用 PyTorch 进行深度学习的重要工具,它简化了复杂的梯度计算过程,使得研究者和开发者能够集中精力构建和训练模型。掌握自动微分是深入理解和使用 PyTorch 的基础。

作者

AI教程网

发布于

2024-08-07

更新于

2024-08-10

许可协议