pytorch中F.normalize的梯度几乎为零。
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的梯度是零?'x.grad‘给出了相同的结果。
根据链式法则,我认为结果应该是-1,1*2,0=-2,0。
实际上,当我在整个网络中使用上面的代码时,grad工作得很好。
我的代码有什么问题吗?
已尝试
x_norm = x / torch.sqrt((x[0, 0]**2 + x[0, 1]**2))同样的结果。
我试过CUDA,同样的。
我尝试了以下代码,用y_norm替换了x_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.t())替换z = x_norm.mm(y_norm.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发布于 2020-07-10 21:02:50
z的梯度就是它的导数,也就是1。
x_norm的梯度是在(1; 0)中计算的mm(x_norm)的梯度。也就是说,如果是x_norm = (x; y),它的梯度是2 * (x; y),这给出了(2; 0) in (1; 0)。
接下来,因为你有一个常量(x / norm(x)) * (x / norm(x))^T = 1,所以x的梯度为零。
编辑:你有以下等式:

取一个常量的梯度得到0。
https://stackoverflow.com/questions/62833828
复制相似问题