【问题标题】:PyTorch most efficient Jacobian/Hessian calculationPyTorch 最有效的 Jacobian/Hessian 计算
【发布时间】:2022-03-30 14:15:38
【问题描述】:

我正在寻找通过 Pytorch 获取函数的雅可比行列式的最有效方法,到目前为止,我提出了以下解决方案:

# Setup
def func(X):
    return torch.stack((X.pow(2).sum(1),
                        X.pow(3).sum(1),
                        X.pow(4).sum(1)),1)  

X = Variable(torch.ones(1,int(1e5))*2.00094, requires_grad=True).cuda()
# Solution 1:
t = time()
Y = func(X)
J = torch.zeros(3, int(1e5))

for i in range(3):
    J[i] = grad(Y[0][i], X, create_graph=True, retain_graph=True, allow_unused=True)[0]

print(time()-t)
>>> Output: 0.002 s
# Solution 2:
def Jacobian(f,X):
    X_batch = Variable(X.repeat(3,1), requires_grad=True)
    f(X_batch).backward(torch.eye(3).cuda(), retain_graph=True)
    return X_batch.grad

t = time()
J2 = Jacobian(func,X)
print(time()-t)
>>> Output: 0.001 s

由于在第一个解决方案中使用循环与在第二个解决方案中似乎没有太大区别,我想问是否还有更快的方法来计算 pytorch 中的雅可比行列式。

然后我的另一个问题也是关于计算 Hessian 的最有效方法。

最后,有人知道在 TensorFlow 中是否可以更轻松或更高效地完成类似的事情?

【问题讨论】:

    标签: python deep-learning pytorch linear-algebra calculus


    【解决方案1】:

    最有效的方法可能是使用 PyTorch 自己的内置函数:

    torch.autograd.functional.jacobian(func, x)
    torch.autograd.functional.hessian(func, x)
    

    【讨论】:

      【解决方案2】:

      functorch 可以进一步加快计算速度。例如,此代码来自 functorch docs 用于批量雅可比计算(Hessian 也适用):

      batch_size = 64
      Din = 31
      Dout = 33
      
      weight = torch.randn(Dout, Din)
      print(f"weight shape = {weight.shape}")
      bias = torch.randn(Dout)
      
      def predict(weight, bias, x):
          return F.linear(x, weight, bias).tanh()
      
      x = torch.randn(batch_size, Din)
      compute_batch_jacobian = vmap(jacrev(predict, argnums=2), in_dims=(None, None, 0))
      batch_jacobian0 = compute_batch_jacobian(weight, bias, x)
      

      【讨论】:

        【解决方案3】:

        我有一个类似的问题,我通过手动定义雅可比行列式(手动计算导数)解决了这个问题。对于我的问题,这是可行的,但我可以想象并非总是如此。与第二种解决方案相比,计算时间加快了我的机器 (cpu) 上的某些因素。

        # Solution 2
        def Jacobian(f,X):
            X_batch = Variable(X.repeat(3,1), requires_grad=True)
            f(X_batch).backward(torch.eye(3).cuda(),  retain_graph=True)
            return X_batch.grad
        
        %timeit Jacobian(func,X)
        11.7 ms ± 130 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
        
        # Solution 3
        def J_func(X):
            return torch.stack(( 
                         2*X,
                         3*X.pow(2),
                         4*X.pow(3)
                          ),1)
        
        %timeit J_func(X)
        539 µs ± 24.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
        

        【讨论】:

        • 但是如果我们有一个神经网络,就不可能手动编写 jacobian
        • 这不是问题,你错了。神经网络是由数学运算组成的函数,因此您可以手动编写雅可比函数。我在研究中使用了它,这是迄今为止我发现在训练时计算许多雅可比矩阵的最有效方法。
        猜你喜欢
        • 2023-01-24
        • 2020-12-12
        • 2019-07-01
        • 2017-04-29
        • 2021-02-18
        • 2021-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多