为什么我收到“运行时错误:尝试再次向后浏览图表”?

问题描述 投票:0回答:1

我的代码:

import torch
import random


image_width, image_height = 128, 128

def apply_ellipse_mask(img, pos, axes):
    r = torch.arange(image_height)[:, None]
    c = torch.arange(image_width)[None, :]
    val_array = ((c - pos[0]) ** 2) / axes[0] ** 2 + ((r - pos[1]) ** 2) / axes[1] ** 2
    mask = torch.where((0.9 < val_array) & (val_array < 1), torch.tensor(1.0), torch.tensor(0.0))

    return img * (1.0 - mask) + mask


random.seed(0xced)

sphere_radius = image_height / 3
sphere_position = torch.tensor([image_width / 2, image_height / 2 ,0], requires_grad=True)

ref_image = apply_ellipse_mask(torch.zeros(image_width, image_height, requires_grad=True), sphere_position, [sphere_radius, sphere_radius, sphere_radius])

ellipsoid_pos = torch.tensor([sphere_position[0], sphere_position[1], 0], requires_grad=True)
ellipsoid_axes = torch.tensor([image_width / 3 + (random.random() - 0.5) * image_width / 5, image_height / 3 + (random.random() - 0.5) * image_height / 5, image_height / 2], requires_grad=True)

optimizer = torch.optim.Adam([ellipsoid_axes], lr=0.1)
criterion = torch.nn.MSELoss()
for _ in range(100):

    optimizer.zero_grad()
    current_image = torch.zeros(image_width, image_height, requires_grad=True)
    current_image = apply_ellipse_mask(current_image, ellipsoid_pos, ellipsoid_axes)

    loss = criterion(current_image, ref_image)
    loss.backward()
    print(_, loss)
    optimizer.step()

错误:

运行时错误:尝试第二次向后浏览图表(或者在释放张量后直接访问保存的张量)。当您调用 .backward() 或 autograd.grad() 时,保存的图表中间值将被释放。如果您需要第二次向后浏览图表或者需要在向后调用后访问保存的张量,请指定retain_graph=True。

为什么它会尝试第二次向后浏览同一张图?我是否可以在释放张量后直接访问保存的张量?

python pytorch
1个回答
2
投票

您已经创建了很多叶子节点(需要梯度的变量),包括:

ref_image = apply_ellipse_mask(torch.zeros(image_width, image_height, requires_grad=True), sphere_position, [sphere_radius, sphere_radius, sphere_radius])

创建一个叶节点(带有

torch.zeros(image_width, image_height, requires_grad=True)
)并应用一些计算,以便获得计算图。但是每次迭代你都会重用结果。您不会在每次迭代时重新计算它,因此您会尝试多次向后返回同一个图。唯一应该具有
require_grad = True
的是您优化的参数。

您遇到了可微分性问题

您试图通过计算掩码将梯度流向

ellipsoid_axes
,但掩码的计算在
axes
中不可微分(无论如何它都会返回0-1)。您应该使用某种 sigmoid 来使蒙版变得“软”。

关于您的

apply_ellipse_mask
功能

这更多的是注释,因为这段代码仍然会导致相同的错误。避免使用 PyTorch 使用这样的 for 循环,因为它们很慢。相反,你可以写:

def apply_ellipse_mask(img, pos, axes):
    r = torch.arange(image_height)[:, None]
    c = torch.arange(image_width)[None, :]
    val_array = ((c - pos[0])**2) / axes[0]**2 + ((r - pos[1])**2) / axes[1]**2
    mask = torch.where(0.9 < val < 1, torch.tensor(1.0),  torch.tensor(0.0))

    return img * (1.0 - mask) + mask
© www.soinside.com 2019 - 2024. All rights reserved.