【问题标题】:torch.optim returns "ValueError: can't optimize a non-leaf Tensor" for multidimensional tensortorch.optim 为多维张量返回“ValueError:无法优化非叶张量”
【发布时间】:2020-09-03 04:24:48
【问题描述】:

我正在尝试使用torch.optim.adam 优化场景顶点的平移。它是 redner 教程系列中的一段代码,在初始设置下运行良好。它尝试通过将所有顶点移动相同的值translation 来优化场景。这是原始代码:

vertices = []
for obj in base:
    vertices.append(obj.vertices.clone())

def model(translation):
    for obj, v in zip(base, vertices):
        obj.vertices = v + translation
    # Assemble the 3D scene.
    scene = pyredner.Scene(camera = camera, objects = objects)
    # Render the scene.
    img = pyredner.render_albedo(scene)
    return img

# Initial guess
# Set requires_grad=True since we want to optimize them later

translation = torch.tensor([10.0, -10.0, 10.0], device = pyredner.get_device(), requires_grad=True)

init = model(translation)
# Visualize the initial guess

t_optimizer = torch.optim.Adam([translation], lr=0.5)

我尝试修改代码,以便计算每个顶点的单独平移。为此,我对上面的代码进行了以下修改,使translation 的形状从torch.Size([3]) 变为torch.Size([43380, 3])

# translation = torch.tensor([10.0, -10.0, 10.0], device = pyredner.get_device(), requires_grad=True)
translation = base[0].vertices.clone().detach().requires_grad_(True)
translation[:] = 10.0

这引入了ValueError: can't optimize a non-leaf Tensor。你能帮我解决这个问题吗?

PS:很抱歉,我对这个主题很陌生,我想尽可能全面地陈述这个问题。

【问题讨论】:

    标签: optimization pytorch tensor


    【解决方案1】:

    什么是叶变量?

    叶变量是位于图表开头的变量。这意味着 Autograd 引擎跟踪的任何操作都没有创建该变量(这就是它被称为叶变量的原因)。在优化神经网络的过程中,我们希望更新叶变量,例如模型权重、输入等。

    所以为了能够给优化器提供张量,它们应该遵循上面叶变量的定义。

    几个例子。

    a = torch.rand(10, requires_grad=True)
    

    这里,a 是一个叶变量。

    a = torch.rand(10, requires_grad=True).double()
    

    这里,a 不是叶变量,因为它是由将浮点张量转换为双张量的操作创建的。

    a = torch.rand(10).requires_grad_().double() 
    

    这相当于前面的公式:a 不是叶变量。

    a = torch.rand(10).double() 
    

    这里,a 不需要渐变,也没有创建它的操作(由 Autograd 引擎跟踪)。

    a = torch.rand(10).doube().requires_grad_() 
    

    这里,a 需要 grad 并且没有创建它的操作:它是一个叶变量,可以提供给优化器。

    a = torch.rand(10, requires_grad=True, device="cuda") 
    

    这里,a 需要 grad 并且没有创建它的操作:它是一个叶变量,可以提供给优化器。

    上面的解释是从这个discussion thread借来的。


    因此,在您的情况下,translation[:] = 10.0 操作使 translation 成为非叶变量。一个潜在的解决方案是:

    translation = base[0].vertices.clone().detach()
    translation[:] = 10.0
    translation = translation.requires_grad_(True)
    

    在最后一条语句中,您设置了requires_grad,因此,现在将对其进行跟踪和优化。

    【讨论】:

    • 感谢您的反馈,但这并不能消除我的错误!
    • doube() 应该加倍吗?
    【解决方案2】:

    只能优化叶张量。叶张量是在图的开头创建的张量,即图中没有跟踪生成它的操作。换句话说,当您使用requires_grad=True 对张量应用任何操作时,它会跟踪这些操作以便稍后进行反向传播。您不能将这些中间结果之一提供给优化器。

    一个例子更清楚地表明:

    weight = torch.randn((2, 2), requires_grad=True)
    # => tensor([[ 1.5559,  0.4560],
    #            [-1.4852, -0.8837]], requires_grad=True)
    
    weight.is_leaf # => True
    
    result = weight * 2
    # => tensor([[ 3.1118,  0.9121],
    #            [-2.9705, -1.7675]], grad_fn=<MulBackward0>)
    # grad_fn defines how to do the back propagation (kept track of the multiplication)
    
    result.is_leaf # => False
    

    本例中的 result 无法优化,因为它不是叶张量。同样,在您的情况下,translation 不是叶张量,因为您在创建它之后执行的操作:

    translation[:] = 10.0
    translation.is_leaf # => False
    

    这有grad_fn=&lt;CopySlices&gt;,因此它不是叶子,你不能将它传递给优化器。为避免这种情况,您必须从中创建一个与图表分离的新张量。

    # Not setting requires_grad, so that the next operation is not tracked
    translation = base[0].vertices.clone().detach()
    translation[:] = 10.0
    # Now setting requires_grad so it is tracked in the graph and can be optimised
    translation = translation.requires_grad_(True)
    

    您在这里真正要做的是创建一个新的张量,其填充值为 10.0,其大小与顶点张量相同。使用torch.full_like 可以更轻松地实现这一点

    translation = torch.full_like(base[0],vertices, 10.0, requires_grad=True)
    

    【讨论】:

      猜你喜欢
      • 2021-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-11
      • 2022-09-29
      • 2018-01-26
      相关资源
      最近更新 更多