PyTorch中标量展开式的导数

wribegjk  于 2023-01-02  发布在  其他
关注(0)|答案(2)|浏览(192)

我正在Rust中实现一个非常简单的自动diff库,以扩展我的知识,我几乎所有的东西都在工作,但是当实现负对数似然时,我意识到我对如何处理下面场景的导数有些困惑(我已经在PyTorch中编写了它)。

x = torch.tensor([1, 2, 3], dtype=torch.float32, requires_grads=True)
y = x - torch.sum(x)

我四处看了看,做了实验,但还是有点搞不懂这里到底发生了什么,我知道上面的方程关于x的导数是[-2,-2,-2],但有很多方法可以达到这个结果,当我把方程展开为:

x = torch.tensor([1, 2, 3], dtype=torch.float32, requires_grads=True)
y = torch.exp(x - torch.sum(x))

我完全迷路了,不知道它是怎么导出x的梯度的。
我假设上面的方程被改写成这样:

y = (x - [torch.sum(x), torch.sum(x), torch.sum(x)])

但是我不确定,而且我真的很难找到关于标量被扩展成向量或任何实际发生的事情的信息。如果有人能给我指出正确的方向,那将是太棒了!
如果有帮助的话,我可以包括pytorch计算的上述方程的梯度。

ni65a41a

ni65a41a1#

你的代码在没有任何修改的情况下不能和PyTorch一起工作,因为它没有指定w.r.t到y的渐变是什么。你需要他们调用y.backward()来计算w.r.t到x的渐变。从你的全部结果来看,我认为渐变一定是全1。
“标量扩展”称为broadcasting,正如您已经知道的,只要两个Tensor操作数的形状不匹配,就会执行广播。我猜它的实现方式与PyTorch中的任何其他运算相同,PyTorch知道如何在给定梯度相对于其输出的情况下计算梯度相对于其输入的情况。下面给出了一个简单的示例(a)适用于给定的测试用例;(B)允许我们仍然使用PyTorch的autograd来自动计算梯度(参见PyTorch关于扩展autograd的文档):

class Broadcast(torch.autograd.Function):
    def forward(ctx, x: torch.Tensor, length: int) -> torch.Tensor:
        assert x.ndim == 0, "input must be a scalar tensor"
        assert length > 0, "length must be greater than zero"
        return x.new_full((length,), x.item())

    def backward(ctx, grad: torch.Tensor) -> Tuple[torch.Tensor, None]:
        return grad.sum(), None

现在,通过设置broadcast = Broadcast.apply,我们可以自己调用广播,而不是让PyTorch自动执行。

x = torch.tensor([1., 2., 3.], requires_grad=True)
y = x - broadcast(torch.sum(x), x.size(0))
y.backward(torch.ones_like(y))
assert torch.allclose(torch.tensor(-2.), x.grad)

注意,我不知道PyTorch实际上是如何实现它的,上面的实现只是为了说明如何编写广播操作来实现自动区分,希望这能回答你的问题。

gg58donl

gg58donl2#

首先,参数是requires_grad,而不是require_grads。其次,只能为浮点或复杂dtype要求渐变。
现在,标量加法/乘法(注意,减法/除法可被视为与-ve数相加/与分数相乘)简单地将标量与Tensor的所有元素相加/相乘。因此,

x = torch.tensor([1., 2., 3.], requires_grad=True)
y = x - 1

评估为:

y = tensor([-1.,  0.,  1.], grad_fn=<SubBackward0>)

因此,在你的例子中,torch.sum(x)基本上是一个标量,它是从Tensorx的所有元素中减去的。
如果你对渐变部分更感兴趣,请查看autograd [ref]上的pytorch文档,它说明如下:
用链法则对图进行微分,如果任一Tensor是非标量的(即它们的数据具有多于一个元素)并且需要梯度,则将计算雅可比向量积,在这种情况下,函数额外地需要指定grad_tensors。它应该是匹配长度的序列,其包含雅可比向量积中的“向量”,通常是微分函数的梯度与相应的Tensor(None是不需要梯度Tensor的所有Tensor的可接受值)。

相关问题