grad_outputs 在 PyTorch 的 torch.autograd.grad 中的含义
Meaning of grad_outputs in PyTorch's torch.autograd.grad
我无法理解 torch.autograd.grad
中 grad_outputs
选项的概念含义。
文档说:
grad_outputs
should be a sequence of length matching output containing the “vector” in Jacobian-vector product, usually the pre-computed gradients w.r.t. each of the outputs. If an output doesn’t require_grad
, then the gradient can be None
).
我觉得这个描述很隐晦。 Jacobian-vector product 究竟是什么意思?我知道 Jacobian 是什么,但不确定 product 它们在这里的意思是什么:逐元素、矩阵乘积,还是其他?我无法从下面的示例中看出。
为什么 "vector" 在引号中?事实上,在下面的例子中,当 grad_outputs
是一个向量时我得到一个错误,但当它是一个矩阵时却没有。
>>> x = torch.tensor([1.,2.,3.,4.], requires_grad=True)
>>> y = torch.outer(x, x)
为什么我们会观察到以下输出;它是如何计算出来的?
>>> y
tensor([[ 1., 2., 3., 4.],
[ 2., 4., 6., 8.],
[ 3., 6., 9., 12.],
[ 4., 8., 12., 16.]], grad_fn=<MulBackward0>)
>>> torch.autograd.grad(y, x, grad_outputs=torch.ones_like(y))
(tensor([20., 20., 20., 20.]),)
但是,为什么会出现这个错误?
>>> torch.autograd.grad(y, x, grad_outputs=torch.ones_like(x))
RuntimeError: Mismatch in shape: grad_output[0]
has a shape of torch.Size([4])
and output[0]
has a shape of torch.Size([4, 4])
.
如果我们以你的例子为例,我们有函数 f
,它接受 x
形 (n,)
的输入并输出 y = f(x)
形 (n, n)
。输入被描述为列向量[x_i]_i for i ∈ [1, n]
,f(x)
被定义为矩阵[y_jk]_jk = [x_j*x_k]_jk for j, k ∈ [1, n]²
.
计算输出相对于输入的梯度通常很有用(或者有时w.r.tf
的参数,这里有none)。不过,在更一般的情况下,我们正在寻找计算 dL/dx
而不仅仅是 dy/dx
,其中 dL/dx
是 L
的偏导数, 计算自y
、w.r.t。 x
.
计算图如下所示:
x.grad = dL/dx <------- dL/dy y.grad
dy/dx
x -------> y = x*xT
然后,如果我们查看 dL/dx
,即通过链式法则等于 dL/dy*dy/dx
。我们有,查看torch.autograd.grad
的界面,有如下对应关系:
outputs
<-> y
,
inputs
<-> x
,以及
grad_outputs
<-> dL/dy
.
看形状:dL/dx
应该和x
有相同的形状(dL/dx
可以称为x
的'gradient') ,而 dy/dx
,雅可比矩阵将是 3 维的。另一方面,dL/dy
,即输入梯度,应该与输出具有相同的形状,即,y
的形状。
我们要计算 dL/dx = dL/dy*dy/dx
。如果我们仔细观察,我们有
dy/dx = [dy_jk/dx_i]_ijk for i, j, k ∈ [1, n]³
因此,
dL/dx = [dL/d_x_i]_i, i ∈ [1,n]
= [sum(dL/dy_jk * d(y_jk)/dx_i over j, k ∈ [1, n]²]_i, i ∈ [1,n]
回到你的例子,这意味着给定的i ∈ [1, n]
:dL/dx_i = sum(dy_jk/dx_i) over j, k ∈ [1,n]²
。如果 i = k
,dy_jk/dx_i = f(x_j*x_k)/dx_i
将等于 x_j
,如果 i = j
,则 x_k
,如果 i = j = k
,则 2*x_i
(因为 i = j = k
的平方 x_i
).这就是说矩阵 y
是对称的...所以结果归结为 2*sum(x_i) over i ∈ [1, n]
这意味着 dL/dx
是列向量 [2*sum(x)]_i for i ∈ [1, n]
。
>>> 2*x.sum()*torch.ones_like(x)
tensor([20., 20., 20., 20.])
回过头来看另一个图形示例,这里在 y
之后添加了一个额外的操作:
x -------> y = x*xT --------> z = y²
如果您查看此图上的 向后传球,您有:
dL/dx <------- dL/dy <-------- dL/dz
dy/dx dz/dy
x -------> y = x*xT --------> z = y²
With dL/dx = dL/dy*dy/dx = dL/dz*dz/dy*dy/dx
实际上是分两个顺序步骤计算的:dL/dy = dL/dz*dz/dy
,然后是 dL/dx = dL/dy*dy/dx
.
我无法理解 torch.autograd.grad
中 grad_outputs
选项的概念含义。
文档说:
grad_outputs
should be a sequence of length matching output containing the “vector” in Jacobian-vector product, usually the pre-computed gradients w.r.t. each of the outputs. If an output doesn’trequire_grad
, then the gradient can beNone
).
我觉得这个描述很隐晦。 Jacobian-vector product 究竟是什么意思?我知道 Jacobian 是什么,但不确定 product 它们在这里的意思是什么:逐元素、矩阵乘积,还是其他?我无法从下面的示例中看出。
为什么 "vector" 在引号中?事实上,在下面的例子中,当 grad_outputs
是一个向量时我得到一个错误,但当它是一个矩阵时却没有。
>>> x = torch.tensor([1.,2.,3.,4.], requires_grad=True)
>>> y = torch.outer(x, x)
为什么我们会观察到以下输出;它是如何计算出来的?
>>> y
tensor([[ 1., 2., 3., 4.],
[ 2., 4., 6., 8.],
[ 3., 6., 9., 12.],
[ 4., 8., 12., 16.]], grad_fn=<MulBackward0>)
>>> torch.autograd.grad(y, x, grad_outputs=torch.ones_like(y))
(tensor([20., 20., 20., 20.]),)
但是,为什么会出现这个错误?
>>> torch.autograd.grad(y, x, grad_outputs=torch.ones_like(x))
RuntimeError: Mismatch in shape:
grad_output[0]
has a shape oftorch.Size([4])
andoutput[0]
has a shape oftorch.Size([4, 4])
.
如果我们以你的例子为例,我们有函数 f
,它接受 x
形 (n,)
的输入并输出 y = f(x)
形 (n, n)
。输入被描述为列向量[x_i]_i for i ∈ [1, n]
,f(x)
被定义为矩阵[y_jk]_jk = [x_j*x_k]_jk for j, k ∈ [1, n]²
.
计算输出相对于输入的梯度通常很有用(或者有时w.r.tf
的参数,这里有none)。不过,在更一般的情况下,我们正在寻找计算 dL/dx
而不仅仅是 dy/dx
,其中 dL/dx
是 L
的偏导数, 计算自y
、w.r.t。 x
.
计算图如下所示:
x.grad = dL/dx <------- dL/dy y.grad
dy/dx
x -------> y = x*xT
然后,如果我们查看 dL/dx
,即通过链式法则等于 dL/dy*dy/dx
。我们有,查看torch.autograd.grad
的界面,有如下对应关系:
outputs
<->y
,inputs
<->x
,以及grad_outputs
<->dL/dy
.
看形状:dL/dx
应该和x
有相同的形状(dL/dx
可以称为x
的'gradient') ,而 dy/dx
,雅可比矩阵将是 3 维的。另一方面,dL/dy
,即输入梯度,应该与输出具有相同的形状,即,y
的形状。
我们要计算 dL/dx = dL/dy*dy/dx
。如果我们仔细观察,我们有
dy/dx = [dy_jk/dx_i]_ijk for i, j, k ∈ [1, n]³
因此,
dL/dx = [dL/d_x_i]_i, i ∈ [1,n]
= [sum(dL/dy_jk * d(y_jk)/dx_i over j, k ∈ [1, n]²]_i, i ∈ [1,n]
回到你的例子,这意味着给定的i ∈ [1, n]
:dL/dx_i = sum(dy_jk/dx_i) over j, k ∈ [1,n]²
。如果 i = k
,dy_jk/dx_i = f(x_j*x_k)/dx_i
将等于 x_j
,如果 i = j
,则 x_k
,如果 i = j = k
,则 2*x_i
(因为 i = j = k
的平方 x_i
).这就是说矩阵 y
是对称的...所以结果归结为 2*sum(x_i) over i ∈ [1, n]
这意味着 dL/dx
是列向量 [2*sum(x)]_i for i ∈ [1, n]
。
>>> 2*x.sum()*torch.ones_like(x)
tensor([20., 20., 20., 20.])
回过头来看另一个图形示例,这里在 y
之后添加了一个额外的操作:
x -------> y = x*xT --------> z = y²
如果您查看此图上的 向后传球,您有:
dL/dx <------- dL/dy <-------- dL/dz
dy/dx dz/dy
x -------> y = x*xT --------> z = y²
With dL/dx = dL/dy*dy/dx = dL/dz*dz/dy*dy/dx
实际上是分两个顺序步骤计算的:dL/dy = dL/dz*dz/dy
,然后是 dL/dx = dL/dy*dy/dx
.