Градус F.normalize в pytorch странный - PullRequest
1 голос
/ 10 июля 2020

Степень F.normalize в pytorch почти равна нулю.

Коды в python3 & pytorch == 1.3.0:

import torch
import torch.nn.functional as F

x = torch.autograd.Variable(torch.Tensor([[1, 0]]), requires_grad=True)
x_norm = F.normalize(x, dim=-1)
z = x_norm.mm(x_norm.t())
print('x_norm', x_norm)
print('z', z)

x.register_hook(lambda g: print(g))
x_norm.register_hook(lambda g: print(g))
z.register_hook(lambda g: print(g))
z.backward()

Вывод:

x_norm tensor([[1., 0.]], grad_fn=<DivBackward0>)
z tensor([[1.]], grad_fn=<MmBackward>)
tensor([[1.]])                      # z grad
tensor([[2., 0.]])                  # x_norm grad
tensor([[0., 0.]])                  # x grad

Почему градус х равен нулю? 'x.grad' дает тот же результат.

Согласно правилу цепочки, я думаю, результат должен быть [-1, 1] * [2, 0] = [- 2, 0].

На самом деле, когда я использую приведенные выше коды во всей сети, градиент работает нормально.

Что-то не так с моими кодами?

Пробовал

x_norm = x / torch.sqrt((x[0, 0]**2 + x[0, 1]**2))

Тот же результат.

Пробовал CUDA, то же самое.

Пробовал следующие коды, заменяя x_norm на y_norm:

import torch
import torch.nn.functional as F

x = torch.autograd.Variable(torch.Tensor([[1, 0]]), requires_grad=True)
y = torch.autograd.Variable(torch.Tensor([[2, 0]]), requires_grad=True)
x_norm = F.normalize(x, dim=-1)
y_norm = F.normalize(y, dim=-1)
z = x_norm.mm(y_norm.t())

y.register_hook(lambda g: print(g))
x.register_hook(lambda g: print(g))
x_norm.register_hook(lambda g: print(g))
z.register_hook(lambda g: print(g))
z.backward()

Вывод:

tensor([[1.]])                      # z grad
tensor([[2., 0.]])                  # x_norm grad
tensor([[0., 0.]])                  # y grad
tensor([[0., 0.]])                  # x grad

Однако, если я заменю z = x_norm.mm(y_norm.t()) на z = x_norm.mm(y.t()), y будет иметь ненулевое значение, а x - нет.

Также попытался поставить F.normalize в середине кодов:

import torch
import torch.nn.functional as F

#x = torch.autograd.Variable(torch.randn(1, 2), requires_grad=True)
x = torch.autograd.Variable(torch.Tensor([[1,0]]), requires_grad=True).cuda()                                                                                            y = torch.autograd.Variable(torch.Tensor([[2,0]]), requires_grad=True).cuda()
x1 = x * 2
x1_norm = F.normalize(x1, dim=-1)                                                                                                                                         

print('x1', x1)
z = x1_norm.mm(y.t())
print('x1_norm', x1_norm)
print('z', z)
y.register_hook(lambda g: print('y', g))
x.register_hook(lambda g: print('x', g))
x1.register_hook(lambda g: print('x1', g))
x1_norm.register_hook(lambda g: print('x1_norm', g))
z.register_hook(lambda g: print('z', g))
z.backward()

Вывод

x1 tensor([[2., 0.]], device='cuda:0', grad_fn=<MulBackward0>)
x1_norm tensor([[1., 0.]], device='cuda:0', grad_fn=<DivBackward0>)
z tensor([[2.]], device='cuda:0', grad_fn=<MmBackward>)
z grad tensor([[1.]], device='cuda:0')            # z grad
x1_norm grad tensor([[2., 0.]], device='cuda:0')  # (x*2)_norm grad
x1 grad tensor([[0., 0.]], device='cuda:0')       # x*2 grad
y grad tensor([[1., 0.]], device='cuda:0')        # y grad
x grad tensor([[0., 0.]], device='cuda:0')        # x grad

1 Ответ

0 голосов
/ 10 июля 2020

Градиент z - это просто его производная, то есть 1.

Градиент x_norm - это градиент mm(x_norm), вычисленный в (1; 0). То есть, если x_norm = (x; y), его градиент равен 2 * (x; y), что дает (2; 0) в (1; 0).

Далее, поскольку у вас есть (x / norm(x)) * (x / norm(x))^T = 1, который является константой, градиент x равно нулю.

EDIT: у вас есть следующее уравнение:

латексное уравнение

Взяв градиент константы, получаем 0.

...