tensorflow PyTorch backward函数出现RuntimeError

afdcj2ne  于 2023-11-21  发布在  其他
关注(0)|答案(1)|浏览(190)

我试图在PyTorch中计算一个变量的grad。然而,有一个RuntimeError告诉我,输出和grad的形状必须相同。然而,在我的情况下,输出和grad的形状不能相同。下面是我的代码复制:

import numpy as np
import torch
from torch.autograd import Variable as V

ne = 3
m, n = 79, 164
G = np.random.rand(m, n).astype(np.float64)
w = np.random.rand(n, n).astype(np.float64)
z = -np.random.rand(n).astype(np.float64)

G = V(torch.from_numpy(G))
w = V(torch.from_numpy(w))
z = V(torch.from_numpy(z), requires_grad=True)
e, v = torch.symeig(torch.diag(2 * z - torch.sum(w, dim=1)) + w, eigenvectors=True, upper=False)
ssev = torch.sum(torch.pow(e[-ne:] * v[:, -ne:], 2), dim=1)
out = torch.sum(torch.matmul(G, ssev.reshape((n, 1))))
out.backward(z)
print(z.grad)

字符串
错误信息:RuntimeError: Mismatch in shape: grad_output[0] has a shape of torch.Size([164]) and output[0] has a shape of torch.Size([])
TensorFlow中也允许类似的计算,我可以成功地得到我想要的梯度:

import numpy as np
import tensorflow as tf

m, n = 79, 164
G = np.random.rand(m, n).astype(np.float64)
w = np.random.rand(n, n).astype(np.float64)
z = -np.random.rand(n).astype(np.float64)

def tf_function(z, G, w, ne=3):
    e, v = tf.linalg.eigh(tf.linalg.diag(2 * z - tf.reduce_sum(w, 1)) + w)
    ssev = tf.reduce_sum(tf.square(e[-ne:] * v[:, -ne:]), 1)
    return tf.reduce_sum(tf.matmul(G, tf.expand_dims(ssev, 1)))

z, G, w = [tf.convert_to_tensor(_, dtype=tf.float64) for _ in (z, G, w)]
z = tf.Variable(z)
with tf.GradientTape() as g:
    g.watch(z)
    out = tf_function(z, G, w)
print(g.gradient(out, z).numpy())


我的tensorflow版本是2.0,PyTorch版本是1.14.0。我使用的是Python3.6.9。在我看来,当输出和变量具有不同形状时计算梯度是非常合理的,我不认为我犯了任何错误。有人能帮助我解决这个问题吗?我真的很感激!

ilmyapht

ilmyapht1#

首先,你不需要使用numpy然后转换为Variable第二,当你写out.backward(z)时,你传递z作为outgradient,即out.backward(gradient=z),可能是由于误解“out.backward(z)计算z的梯度,即dout/dz“。相反,对于某个函数f,此参数意味着gradient = d[f(out)]/dout(例如损失函数),它是用于计算vector-Jacobian productdout/dz * df/dout的Tensor。因此,你得到这个错误的原因是因为你的out(及其梯度df/dout)是标量(零维Tensor),z是大小为n的Tensor,导致形状不匹配。
为了解决这个问题,正如你自己已经发现的,只需将out.backward(z)替换为out.backward(),这相当于out.backward(gradient=torch.tensor(1.)),因为在你的例子中,out是标量,f(out) = out,所以d[f(out)]/dout = d(out)/d(out) = tensor(1.)。如果你的out是非标量Tensor,那么out.backward()就不起作用了,你必须使用out.backward(torch.ones(out.shape))(再次假设f(out) = out)。在任何情况下,如果你需要将gradient传递给out.backward(),请确保它与out具有相同的形状。

相关问题