文章目录
- 一、in-place含义
- 二、in-place代码示例
- 三、在pytorch中, 有两种情况不能使用inplace operation
- 第一种情况: requires_grad=True 的 leaf tensor
- 第二种情况: 求梯度阶段需要用到的张量
一、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.backward()
对于的导数计算出错因而报错; - 造成这个问题的主要原因是:在执行
f = torch.matmul(d, w2)
时,pytorch的反向求导机制保存了,为了之后的反向求导计算。
这样修改就没有问题了:
在改变之后再对进行运算操作
附1: f.backward(),默认只对求梯度原因:
f.backward(parameters)
接受的参数parameters
必须要和f
的大小一模一样,然后作为f
的系数传回去。
如果设定只传入,报错如下:
附2: pytorch函数之torch.matmul()
矩阵相乘有torch.mm和torch.matmul两个函数。其中前一个是针对二维矩阵,后一个是高维。当torch.mm用于大于二维时将报错。
参考链接:https://zhuanlan.zhihu.com/p/38475183