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