Instantly share code, notes, and snippets.

# apaszke/jacobian_hessian.py

Last active April 3, 2024 03:40
Show Gist options
• Save apaszke/226abdf867c4e9d6698bd198f3b45fb7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters

### slerman12 commented Apr 18, 2020

Is there a reason why you use grad_y instead of just indexing `flat_y[i]` in the autograd?

### jalane76 commented Apr 19, 2020

Hello, I am relatively new to PyTorch and came across your Hessian function. It is much more elegant than some Hessian code from an academic paper that I am trying to reproduce. I've put together a toy example, but keep getting the error

RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [2]] is at version 4; expected version 3 instead. Hint: the backtrace further above shows the operation that failed to compute its gradient. The variable in question was changed in there or anywhere later. Good luck!

I've been scouring the docs and googling, but for the life of me I can't figure out what I'm doing wrong. Any help you could offer would be greatly appreciated!

Here is my code:

``````import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np

torch.set_printoptions(precision=20, linewidth=180)

def jacobian(y, x, create_graph=False):
jac = []
flat_y = y.reshape(-1)
for i in range(len(flat_y)):

def hessian(y, x):
return jacobian(jacobian(y, x, create_graph=True), x)

def f(x):
return x * x

np.random.seed(435537698)

num_dims = 2
num_samples = 3

X = [np.random.uniform(size=num_dims) for i in range(num_samples)]

mean = torch.Tensor(np.mean(X, axis=0))

cov = torch.Tensor(np.cov(X, rowvar=False))

hessian_matrices = hessian(f(mean), mean)
print('hessian: \n{}\n\n'.format(hessian_matrices))
``````

The output with anomaly detection turned on is here:

RuntimeError Traceback (most recent call last)
in ()
67
---> 69 hessian_matrices = hessian(f(mean), mean)
70 print('hessian: \n{}\n\n'.format(hessian_matrices))

2 frames
in hessian(y, x)
45 print('--> hessian()')
46 j = jacobian(y, x, create_graph=True)
---> 47 return jacobian(j, x)
48
49 def f(x):

in jacobian(y, x, create_graph)
29
32

155 return Variable._execution_engine.run_backward(
--> 157 inputs, allow_unused)
158
159

RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [2]] is at version 4; expected version 3 instead. Hint: the backtrace further above shows the operation that failed to compute its gradient. The variable in question was changed in there or anywhere later. Good luck!

Finally, I'm running my code in a Google Colab notebook with PyTorch 1.4 if that makes a difference.

Thanks!

### jalane76 commented Apr 20, 2020

I did manage to get the code to run now. I made a "simplification" that broke it.

``````def f(x):
return x * x * torch.arange(4, dtype=torch.float)
``````

While mine was:

``````def f(x):
return x * x
``````

I've since fixed it to:

``````def f(x):
return x * x  * torch.ones_like(x)
``````

and it works like a charm. @apaszke any idea why that is the case?

### el-hult commented Apr 20, 2020

I did manage to get the code to run now. I made a "simplification" that broke it.

``````def f(x):
return x * x * torch.arange(4, dtype=torch.float)
``````

While mine was:

``````def f(x):
return x * x
``````

I've since fixed it to:

``````def f(x):
return x * x  * torch.ones_like(x)
``````

and it works like a charm. @apaszke any idea why that is the case?

you can switch `torch.ones_like(x)` to `1` and it still works...

### Ronnypetson commented Jun 26, 2020

Hello Adam! How could I give credit to you if I use this code? Can it be a doc-string in documentation, paper citation or something?

Now the function `torch.autograd.functional.jacobian` can do the same thing, I think.

``````
def jacobian(y, x, create_graph=False):
# xx, yy = x.detach().numpy(), y.detach().numpy()
jac = []
flat_y = y.reshape(-1)
for i in range(len(flat_y)):

def hessian(y, x):
return jacobian(jacobian(y, x, create_graph=True), x)

def f(xx):
# y = x * x * torch.arange(4, dtype=torch.float)
matrix = torch.tensor([[0.2618, 0.2033, 0.7280, 0.8618],
[0.1299, 0.6498, 0.6675, 0.0527],
[0.3006, 0.9691, 0.0824, 0.8513],
y = torch.einsum('ji, i -> j', (matrix, xx))
return y

if __name__ == "__main__":
# matrix = torch.rand(4, 4, requires_grad=True)
# print(matrix)
print(jacobian(f(x), x))
# print(hessian(f(x, matrix), x))
``````

output

``````        [0.1299, 0.6498, 0.6675, 0.0527],
[0.3006, 0.9691, 0.0824, 0.8513],
[[0.2618 0.2033 0.728  0.8618]
[0.1299 0.6498 0.6675 0.0527]
[0.3006 0.9691 0.0824 0.8513]
[0.7914 0.2796 0.3717 0.9483]]```
``````

### AjinkyaBankar commented May 12, 2021

Hi,
I want to find a Hessian matrix for the loss function of the pre-trained neural network with respect to the parameters of the network. How can I use this method? Can someone please share an example? Thanks.

### maryamaliakbari commented Oct 25, 2021

Hi,
I want to find a Hessian matrix for the loss function of the pre-trained neural network with respect to the parameters of the network. How can I use this method? Can someone please share an example? Thanks.

Hi,
I am looking for the same thing. Could you figure out how we can do it?