A more complete example from here:
optimizer.zero_grad()
loss, hidden = model(data, hidden, targets)
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), args.clip)
optimizer.step()
Answer from Rahul on Stack OverflowA more complete example from here:
optimizer.zero_grad()
loss, hidden = model(data, hidden, targets)
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), args.clip)
optimizer.step()
clip_grad_norm (which is actually deprecated in favor of clip_grad_norm_ following the more consistent syntax of a trailing _ when in-place modification is performed) clips the norm of the overall gradient by concatenating all parameters passed to the function, as can be seen from the documentation:
The norm is computed over all gradients together, as if they were concatenated into a single vector. Gradients are modified in-place.
From your example it looks like that you want clip_grad_value_ instead which has a similar syntax and also modifies the gradients in-place:
clip_grad_value_(model.parameters(), clip_value)
Another option is to register a backward hook. This takes the current gradient as an input and may return a tensor which will be used in-place of the previous gradient, i.e. modifying it. This hook is called each time after a gradient has been computed, i.e. there's no need for manually clipping once the hook has been registered:
for p in model.parameters():
p.register_hook(lambda grad: torch.clamp(grad, -clip_value, clip_value))
Not as neat as np.clip, but you can use torch.max and torch.min:
In [1]: x
Out[1]:
tensor([[0.9752, 0.5587, 0.0972],
[0.9534, 0.2731, 0.6953]])
Setting the lower and upper bound per column
l = torch.tensor([[0.2, 0.3, 0.]])
u = torch.tensor([[0.8, 1., 0.65]])
Note that the lower bound l and upper bound u are 1-by-3 tensors (2D with singleton dimension). We need these dimensions for l and u to be broadcastable to the shape of x.
Now we can clip using min and max:
clipped_x = torch.max(torch.min(x, u), l)
Resulting with
tensor([[0.8000, 0.5587, 0.0972],
[0.8000, 0.3000, 0.6500]])
For anyone, who is having the same problem like me a few minutes ago:
For about two years it is also possible to have column-dependent bounds in torch.clamp (see PR):
In: x = torch.randn(2, 3)
print(x)
Out: tensor([[-0.2069, 1.4082, 0.2615],
[0.6478, 0.0883, -0.7795]])
Setting a lower and upper bound:
lower = torch.Tensor([[-1., 0., 0.]])
upper = torch.Tensor([[0., 1., 1.]])
Now you can simply use torch.clamp as follows:
In: clamped_x = torch.clamp(x, min=lower, max=upper)
print(clamped_x)
Out: tensor([[-0.2069, 1.0000, 0.2615],
[0.0000, 0.0883, 0.0000]])
I hope that helps :)