Python 如何计算二阶雅可比矩阵?

Python 如何计算二阶雅可比矩阵?,python,pytorch,gradient,Python,Pytorch,Gradient,我有一个神经网络,它在计算向量量u。我想计算关于输入x,单个元素的一阶和二阶雅可比矩阵 有人知道在PyTorch怎么做吗?下面是我的项目中的代码片段: 导入火炬 导入torch.nn作为nn 品级(火炬nn模块): 定义初始化(自,层:列表): 超级(PINN,self)。\uuuu init\uuuuu() self.linears=nn.ModuleList([]) 对于i,枚举中的dim(层[:-2]): self.linears.append(nn.Linear(dim,layers[i

我有一个神经网络,它在计算向量量
u
。我想计算关于输入
x
,单个元素的一阶和二阶雅可比矩阵

有人知道在PyTorch怎么做吗?下面是我的项目中的代码片段:

导入火炬
导入torch.nn作为nn
品级(火炬nn模块):
定义初始化(自,层:列表):
超级(PINN,self)。\uuuu init\uuuuu()
self.linears=nn.ModuleList([])
对于i,枚举中的dim(层[:-2]):
self.linears.append(nn.Linear(dim,layers[i+1]))
self.linears.append(nn.ReLU())
self.linears.append(nn.Linear(层[-2],层[-1]))
def前进(自身,x):
对于self.Linear中的图层:
x=层(x)
返回x
然后,我实例化我的网络:

n_in = 1
units = 50
q = 500

pinn = PINN([n_in, units, units, units, q+1])
pinn
返回

PINN(
  (linears): ModuleList(
    (0): Linear(in_features=1, out_features=50, bias=True)
    (1): ReLU()
    (2): Linear(in_features=50, out_features=50, bias=True)
    (3): ReLU()
    (4): Linear(in_features=50, out_features=50, bias=True)
    (5): ReLU()
    (6): Linear(in_features=50, out_features=501, bias=True)
  )
)
然后我计算FO和SO雅可比矩阵

x = torch.randn(1, requires_grad=False)

u_x = torch.autograd.functional.jacobian(pinn, x, create_graph=True)
print("First Order Jacobian du/dx of shape {}, and features\n{}".format(u_x.shape, u_x)

u_xx = torch.autograd.functional.jacobian(lambda _: u_x, x)
print("Second Order Jacobian du_x/dx of shape {}, and features\n{}".format(u_xx.shape, u_xx)
返回

First Order Jacobian du/dx of shape torch.Size([501, 1]), and features
tensor([[-0.0310],
        [ 0.0139],
        [-0.0081],
        [-0.0248],
        [-0.0033],
        [ 0.0013],
        [ 0.0040],
        [ 0.0273],
        ...
        [-0.0197]], grad_fn=<ViewBackward>)
如果不依赖于
x
,那么
u\u xx
不应该是
None
向量吗


提前感谢@jodag在他的评论中提到,
ReLU
为空或线性,其梯度为常数(除了
0
,这是一个罕见的事件),因此其二阶导数为零。我将激活函数改为
Tanh
,这最终允许我计算雅可比矩阵两次

最后的代码是

import torch
import torch.nn as nn

class PINN(torch.nn.Module):
    
    def __init__(self, layers:list):
        super(PINN, self).__init__()
        self.linears = nn.ModuleList([])
        for i, dim in enumerate(layers[:-2]):
            self.linears.append(nn.Linear(dim, layers[i+1]))
            self.linears.append(nn.Tanh())
        self.linears.append(nn.Linear(layers[-2], layers[-1]))
        
    def forward(self, x):
        for layer in self.linears:
            x = layer(x)
        return x
        
    def compute_u_x(self, x):
        self.u_x = torch.autograd.functional.jacobian(self, x, create_graph=True)
        self.u_x = torch.squeeze(self.u_x)
        return self.u_x
    
    def compute_u_xx(self, x):
        self.u_xx = torch.autograd.functional.jacobian(self.compute_u_x, x)
        self.u_xx = torch.squeeze(self.u_xx)
        return self.u_xx

然后用
x调用
compute\u\u xx(x)
PINN
的一个实例执行
compute\u\u xx(x)
操作。require\u grad
设置为
True
将我带到那里。如何消除torch.autograd.functional.jacobian引入的无用尺寸,还有待理解,尽管…

二阶雅可比矩阵被称为,可以使用PyTorch的内置函数轻松计算:

torch.autograd.functional.hessian(函数,输入)

你检查过torch.autograd.functional.jacobian()吗?我检查过了,我很轻松地得到了一阶jacobian,但我不知道如何计算二阶。我得到一个
0
值,考虑到我拥有的网络,这很奇怪。有没有一种方法可以可视化Pytork动态生成的图形?考虑到您的网络是由linear和relu组成的,这两种网络几乎处处都有恒定的梯度,因此输出w.r.t.的二阶导数处处为零并不奇怪。对我来说,这似乎是正确的。是的,我确实明白了,但还没有花时间回答我自己!无论如何谢谢@jodag。我用一个
nn.Tanh
替换了那些,得到了第二级。尽管如此,我发现跟踪图表中填充的内容相当困难。计算雅可比矩阵两次是很棘手的。出于某种原因,
torch.autograd.functional.jacobian
添加了无用的维度。我还没有计算出它。@aixyok广义雅可比矩阵应该有形状(输出形状x输入形状),所以第一个雅可比矩阵是(501 x 1),因为输入x的大小是1,输出pinn的大小是501。二阶Jacobain(又名Hessian)将是(501 x 1 x 1),因为输出u_x的大小为501 x 1,输入x的大小为1。如果需要,您可以在计算二阶雅可比矩阵之前,先
.flant()
ux。
import torch
import torch.nn as nn

class PINN(torch.nn.Module):
    
    def __init__(self, layers:list):
        super(PINN, self).__init__()
        self.linears = nn.ModuleList([])
        for i, dim in enumerate(layers[:-2]):
            self.linears.append(nn.Linear(dim, layers[i+1]))
            self.linears.append(nn.Tanh())
        self.linears.append(nn.Linear(layers[-2], layers[-1]))
        
    def forward(self, x):
        for layer in self.linears:
            x = layer(x)
        return x
        
    def compute_u_x(self, x):
        self.u_x = torch.autograd.functional.jacobian(self, x, create_graph=True)
        self.u_x = torch.squeeze(self.u_x)
        return self.u_x
    
    def compute_u_xx(self, x):
        self.u_xx = torch.autograd.functional.jacobian(self.compute_u_x, x)
        self.u_xx = torch.squeeze(self.u_xx)
        return self.u_xx