如何使用 PyTorch 计算神经网络中输入的输出梯度?

Sun*_*ong 7 gradient neural-network pytorch

我有一个训练有素的网络。我想计算输出与输入的梯度。通过查询 PyTorch 文档,torch.autograd.grad可能会有用。所以,我使用以下代码:

    x_test = torch.randn(D_in,requires_grad=True)
    y_test = model(x_test)
    d = torch.autograd.grad(y_test, x_test)[0]
Run Code Online (Sandbox Code Playgroud)

model是神经网络。x_test是大小的输入D_iny_test一个标量输出。我想将计算结果与数值差异进行比较scipy.misc.derivative。所以,我通过设置一个索引来计算偏导数。

    idx = 3
    x_test = torch.randn(D_in,requires_grad=True)
    y_test = model(x_test)
    print(x_test[idx].item())
    d = torch.autograd.grad(y_test, x_test)[0]
    print(d[idx].item())
    def fun(x):
        x_input = x_test.detach()
        x_input[idx] = x
        with torch.no_grad():
            y = model(x_input)
        return y.item()
    x0 = x_test[idx].item()
    print(x0)
    print(derivative(fun, x0, dx=1e-6))
Run Code Online (Sandbox Code Playgroud)

但我得到了完全不同的结果。由 计算的梯度torch.autograd.grad-0.009522666223347187,而由计算的梯度scipy.misc.derivative-0.014901161193847656

计算上有什么问题吗?还是我用torch.autograd.grad错了?

den*_*ger 2

事实上,您给出的代码很可能是完全正确的。让我通过将您重定向到有关反向传播的一些背景信息来解释这一点,或者更确切地说,在本例中是自动微分(AutoDiff)。

许多包的具体实现都是基于 AutoGrad,这是一种获取函数/图的精确导数的常用技术。它可以通过本质上“反转”前向计算过程来计算原子功能块的分段导数(例如加法、减法、乘法、除法等),然后“将它们链接在一起”来实现这一点。我在这个问题
的更详细的答案中解释了 AutoDiff 及其细节。

相反,scipy的导数函数只是使用有限差分来近似该导数。您可以获取附近点处的函数结果,然后根据这些点的函数值差异计算导数。这就是为什么您会看到两个梯度略有不同,因为这可能是实际导数的不准确表示。