首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >pytorch中F.normalize的毕业生很奇怪

pytorch中F.normalize的毕业生很奇怪
EN

Stack Overflow用户
提问于 2020-07-10 19:57:13
回答 1查看 1.1K关注 0票数 1

pytorch中F.normalize的梯度几乎为零。

python3和pytorch==1.3.0中的代码:

代码语言:javascript
复制
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()

输出:

代码语言:javascript
复制
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工作得很好。

我的代码有什么问题吗?

已尝试

代码语言:javascript
复制
x_norm = x / torch.sqrt((x[0, 0]**2 + x[0, 1]**2))

同样的结果。

我试过CUDA,同样的。

我尝试了以下代码,用y_norm替换了x_norm

代码语言:javascript
复制
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()

输出:

代码语言:javascript
复制
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放在代码中间:

代码语言:javascript
复制
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()

输出

代码语言:javascript
复制
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
EN

回答 1

Stack Overflow用户

发布于 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。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62833828

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档