How to get the gradients during evaluation

I need to get the gradients of a model after it was trained, but not really sure how to do it from a learner object, as under the hood no_grad() is being called.

I’ve as input a Tensor image

>>> image.shape
torch.Size([1, 3, 224, 224])

Now when I try to get the gradients as follows:

>>> target = learn_inf.model(image)
>>> target.backward()
>>> target.grads()

I get the following error

RuntimeError                              Traceback (most recent call last)
<ipython-input-132-c19c64c0208c> in <module>()
      1 target = learn_inf.model(image)
----> 2 target.backward()
      3 target.grads()

2 frames
/usr/local/lib/python3.6/dist-packages/torch/ in backward(self, gradient, retain_graph, create_graph)
    193                 products. Defaults to ``False``.
    194         """
--> 195         torch.autograd.backward(self, gradient, retain_graph, create_graph)
    197     def register_hook(self, hook):

/usr/local/lib/python3.6/dist-packages/torch/autograd/ in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables)
     91         grad_tensors = list(grad_tensors)
---> 93     grad_tensors = _make_grads(tensors, grad_tensors)
     94     if retain_graph is None:
     95         retain_graph = create_graph

/usr/local/lib/python3.6/dist-packages/torch/autograd/ in _make_grads(outputs, grads)
     32             if out.requires_grad:
     33                 if out.numel() != 1:
---> 34                     raise RuntimeError("grad can be implicitly created only for scalar outputs")
     35                 new_grads.append(torch.ones_like(out, memory_format=torch.preserve_format))
     36             else:

RuntimeError: grad can be implicitly created only for scalar outputs

What’s the proper way to get the gradients?

I;ve endup getting the gradients as follows:
First I define the helper function that does forward/backward passes then grabs the gradients

def compute_grads(inputs, targets):
  with torch.autograd.set_grad_enabled(True):
    outputs = learn_inf.model(inputs)
    loss = learn_inf.loss_func(outputs, targets)
    grads = inputs.grad
  return grads

Then I prepare the image and expected class like this

image = PILImage.create(imgs[idx])
image = learn_inf.dls.after_item(image)
image = learn_inf.dls.after_batch(image)
compute_grads(image, torch.LongTensor([[1]]))

Wonder if there is a better/cleaer way of doing this?

To make the Image generation easier you can do dls.test_dl(filename) and then grab a batch from it to pass in

(Also I think you can do with_grad to learn.predict?)

You can’t. But you can do with_loss on get_preds, but I think you way is the best way to manually get them :slight_smile:

1 Like

According to the documentation get_preds(with_loss=True) return the losses. You mean on this loss tensor I could call backward() and then have the gradients in the inputs tensor?

I think you could, but I’m not sure. You’d need to call with_input along with it I think.