Pytorch Autograd дает разные градиенты при использовании .clamp вместо torch.relu - PullRequest
4 голосов
/ 10 марта 2020

Я все еще работаю над пониманием системы автограда PyTorch. Одна вещь, с которой я борюсь, это понять, почему .clamp(min=0) и nn.functional.relu() имеют разные обратные проходы.

Это особенно запутанно, поскольку .clamp используется эквивалентно relu в уроках PyTorch, например как https://pytorch.org/tutorials/beginner/pytorch_with_examples.html#pytorch -nn .

Я обнаружил это при анализе градиентов простого полностью связного net с одним скрытым слоем и активацией relu (линейной в выходном слое).

Насколько я понимаю, вывод следующего кода должен быть просто нулями. Я надеюсь, что кто-то может показать мне, что мне не хватает.

import torch
dtype = torch.float

x = torch.tensor([[3,2,1],
                  [1,0,2],
                  [4,1,2],
                  [0,0,1]], dtype=dtype)

y = torch.ones(4,4)

w1_a = torch.tensor([[1,2],
                     [0,1],
                     [4,0]], dtype=dtype, requires_grad=True)
w1_b = w1_a.clone().detach()
w1_b.requires_grad = True



w2_a = torch.tensor([[-1, 1],
                     [-2, 3]], dtype=dtype, requires_grad=True)
w2_b = w2_a.clone().detach()
w2_b.requires_grad = True


y_hat_a = torch.nn.functional.relu(x.mm(w1_a)).mm(w2_a)
y_a = torch.ones_like(y_hat_a)
y_hat_b = x.mm(w1_b).clamp(min=0).mm(w2_b)
y_b = torch.ones_like(y_hat_b)

loss_a = (y_hat_a - y_a).pow(2).sum()
loss_b = (y_hat_b - y_b).pow(2).sum()

loss_a.backward()
loss_b.backward()

print(w1_a.grad - w1_b.grad)
print(w2_a.grad - w2_b.grad)

# OUT:
# tensor([[  0.,   0.],
#         [  0.,   0.],
#         [  0., -38.]])
# tensor([[0., 0.],
#         [0., 0.]])
# 
...