pytorch之in-place operation #含义 #代码示例 #两种情况不能使用inplace operation

一、in-place含义

in-place operation在pytorch中是指改变一个tensor的值的时候,不经过复制操作,而是直接在原来的内存上改变它的值。可以称之为“原地操作符”。

注意:PyTorch操作inplace版本都有后缀"_", 例如y.add_(x),x.copy_(y),x.t_()

python里面的+=*=也是in-place operation

如果你使用了in-place operation而没有报错的话,那么你可以确定你的梯度计算是正确的。

二、in-place代码示例

import torch

x = torch.rand(5, 3)
y = torch.rand(5, 3)

# 加法形式一:+
print(x + y)

# 加法形式二:add
print(torch.add(x, y))
# add还可指定输出
result = torch.empty(5, 3)
torch.add(x, y, out=result)
print(result)

# 加法形式三:inplace
y.add_(x) # adds x to y
print(y)

三、在pytorch中, 有两种情况不能使用inplace operation

1、对于requires_grad=True的叶子张量(leaf tensor) 不能使用 inplace operation

2、对于在求梯度阶段需要用到的张量不能使用 inplace operation

第一种情况: requires_grad=True 的 leaf tensor

import torch

w = torch.FloatTensor(10) # w 是个 leaf tensor
w.requires_grad = True    # 将 requires_grad 设置为 True
w.normal_()               # 执行这句话就会报错

在这里插入图片描述
报错信息为:
RuntimeError: a leaf Variable that requires grad has been used in an in-place operation.
——在inplace operation中使用了需要grad的叶子变量

对比:requires_grad=False 的 leaf tensor

import torch

w = torch.FloatTensor(10) # w 是个 leaf tensor
# 默认requires_grad=False
print(w)
print(w.normal_())   

在这里插入图片描述
附1: pytorch函数之torch.normal()

  • Returns a Tensor of random numbers drawn from separate normal distributions who’s mean and standard deviation are given.
  • 官网给出的解释,意思返回一个张量,张量里面的随机数是从相互独立的正态分布中随机生成的。

第二种情况: 求梯度阶段需要用到的张量

import torch
x = torch.FloatTensor([[1., 2.]])    # print(x.shape)--> torch.Size([1, 2])
w1 = torch.FloatTensor([[2.], [1.]]) # torch.Size([2, 1])
w2 = torch.FloatTensor([3.]) # torch.Size([1])

w1.requires_grad = True
w2.requires_grad = True

d = torch.matmul(x, w1)  # tensor([[4.]], grad_fn=<MmBackward>) torch.Size([1, 1])
f = torch.matmul(d, w2)  # tensor([12.], grad_fn=<MvBackward>) torch.Size([1])
d[:] = 1 # 因为这句,代码会报错
f.backward()

在这里插入图片描述
报错信息为:
RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation
——梯度计算所需的变量之一已通过in-place operation进行了修改
原因:
f=matmul(d,w2)fw2=g(d)f=\operatorname{matmul}(d, w 2),\frac{\partial f}{\partial w 2}=g(d)

  • 在计算ff的时候,dd是等于某个值的,ff对于w2w 2的导数是和这时候的dd值相关的;
  • 但是计算完ff之后,dd的值变了,这就会导致f.backward()对于w2w 2的导数计算出错因而报错;
  • 造成这个问题的主要原因是:在执行 f = torch.matmul(d, w2)时,pytorch的反向求导机制保存了dd,为了之后的反向求导计算。

这样修改就没有问题了:
在改变dd之后再对ff进行运算操作
在这里插入图片描述
附1: f.backward(),默认只对w2w 2求梯度原因:
f.backward(parameters)接受的参数parameters必须要和f的大小一模一样,然后作为f的系数传回去。
如果设定只传入dd,报错如下:
在这里插入图片描述
附2: pytorch函数之torch.matmul()
矩阵相乘有torch.mm和torch.matmul两个函数。其中前一个是针对二维矩阵,后一个是高维。当torch.mm用于大于二维时将报错。


参考链接:https://zhuanlan.zhihu.com/p/38475183

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章