【发布时间】:2020-07-10 11:57:12
【问题描述】:
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 为零? 'x.grad' 给出相同的结果。
根据链式法则,我认为结果应该是[-1, 1]*[2, 0]=[-2, 0]。
实际上,当我在整个网络中使用上面的代码时,grad 工作正常。
我的代码有什么问题吗?
试过
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
【问题讨论】:
标签: python pytorch backpropagation