PyTorch 自动微分核心:requires

PyTorch 自动微分核心:requires

PyTorch 自动微分核心:requires_grad 属性的避坑指南与替代操作

2025-12-15

在 PyTorch 中,torch.Tensor 是进行计算和存储数据的基本数据结构。requires_grad 是 torch.Tensor 对象的一个布尔属性(True 或 False),它指示 PyTorch 是否应该跟踪在这个张量上进行的所有操作,以便在反向传播(backpropagation)时计算梯度。

True PyTorch 会记录用于计算这个张量的一切,并在 .backward() 调用时计算关于这个张量的梯度。这通常用于模型参数(如权重和偏置)。

False 默认值。梯度不会被计算和存储。这通常用于输入数据和标签。

当一个张量被设置 requires_grad=True 后,对其进行就地修改(in-place operation)可能会破坏自动微分系统的记录,导致错误。

import torch

x = torch.tensor([1.0, 2.0], requires_grad=True)

# 错误:就地修改(In-Place operation),末尾带有下划线 _

x[0] = x[0] + 1.0 # 这是一个赋值操作,通常不会引起 In-Place 错误

x.data.add_(1) # 这是一个**安全的** In-Place 修改(因为操作的是 .data)

x.add_(1) # 错误!对 requires_grad=True 的张量进行 In-Place 操作

loss = x.sum()

# loss.backward() # 执行这行会报错:RuntimeError: a leaf Variable that requires grad is being used in an in-place operation.

使用非就地操作(Out-of-Place operation),即创建一个新的张量来存储结果。

# 推荐方法:非就地操作

x = torch.tensor([1.0, 2.0], requires_grad=True)

# 使用新的张量接收结果

y = x + 1.0

loss = y.sum()

loss.backward()

# 成功计算梯度

print(x.grad)

# tensor([1., 1.])

在进行每一步优化之前,需要将前一步计算的梯度清零。如果忘记清零,新的梯度会和旧的梯度累加,导致错误的更新。

optimizer = torch.optim.SGD([model.parameters()], lr=0.01)

# 第一轮训练

output = model(input)

loss = criterion(output, target)

loss.backward()

optimizer.step()

# 第二轮训练... 忘了清零!

output = model(input)

loss = criterion(output, target)

loss.backward() # 梯度会累加到上一轮的结果上

optimizer.step()

在每一步 loss.backward() 之前,使用 optimizer.zero_grad() 清零梯度。

optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

for data, target in dataloader:

# 关键步骤:清零上一轮的梯度

optimizer.zero_grad()

output = model(data)

loss = criterion(output, target)

loss.backward()

optimizer.step()

有时,你可能不小心使用了 .detach() 或在 with torch.no_grad(): 块中创建了张量,导致它不再连接到计算图,无法计算梯度。

x = torch.tensor([5.0], requires_grad=True)

# 在不跟踪梯度的上下文中创建 y

with torch.no_grad():

y = x * 2 # y.requires_grad 为 False

z = y * 3 # z.requires_grad 也是 False

# z.backward() # 错误!z 不能计算梯度,因为它是从一个 no_grad 张量 y 派生出来的。

确保参与到损失计算的张量,如果需要求导,其派生路径上没有中断梯度的操作。如果你需要复制一个张量并保持梯度连接,请使用 .clone()。

x = torch.tensor([5.0], requires_grad=True)

# 推荐:使用 .clone() 来复制张量,并保持 requires_grad=True (如果原张量是 True)

y = x.clone() * 2 # y.requires_grad 为 True

z = y * 3

z.backward()

# 成功计算梯度

print(x.grad)

# tensor([6.])

在某些情况下,你可能需要临时禁用或启用梯度计算,或安全地修改张量的值。

当你进行推理(Inference)或验证(Validation)时,不需要计算梯度,禁用它可以节省内存和计算时间。

model.eval() # 切换到评估模式(这不会禁用梯度,但会影响某些层如 Dropout/BatchNorm)

with torch.no_grad():

# 在这个块内的所有计算,都不会跟踪梯度

test_output = model(test_input)

test_loss = criterion(test_output, test_target)

# 离开块后,梯度跟踪恢复正常

如果你想修改一个需要梯度的张量(通常是模型参数)的值,而不影响梯度跟踪记录,可以使用 .data 属性。

操作 .data 属性可以剥离张量与计算图的历史连接,使得对 .data 的修改不会被记录在 Autograd 系统中。

x = torch.tensor([1.0, 2.0], requires_grad=True)

print(x.data)

# tensor([1., 2.])

# 安全地进行就地修改

x.data.add_(5.0)

print(x)

# tensor([6., 7.], requires_grad=True)

# x 的值被修改了,但这个修改不会干扰到反向传播

你可以使用 .requires_grad_() 方法(末尾带下划线是就地操作)来改变一个现有张量的 requires_grad 属性。

x = torch.tensor([1.0, 2.0]) # 默认 requires_grad=False

print(x.requires_grad) # False

# 启用梯度跟踪

x.requires_grad_(True)

print(x.requires_grad) # True

# 再次禁用梯度跟踪

x.requires_grad_(False)

print(x.requires_grad) # False

相关推荐

航嘉lw6228
正规beat365app

航嘉lw6228

📅 11-01 👁️ 6428
世界杯欧洲区预选赛圣马力诺VS波黑比分预测足球分析
365体育备用网站

世界杯欧洲区预选赛圣马力诺VS波黑比分预测足球分析

📅 10-06 👁️ 3740
ps怎么把照片调亮
英超365bet体育投注

ps怎么把照片调亮

📅 09-26 👁️ 5241
較字笔画写法
英超365bet体育投注

較字笔画写法

📅 07-13 👁️ 443
xin拼音的字
正规beat365app

xin拼音的字

📅 08-15 👁️ 9806