Pytorch何时能够使用inplace操作

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

有时为了节省内存,比如ReLu单元,我们可以使用inplace=True来将output tensor 覆盖在input tensor的内存位置上。但是从pytorch中的autograd的视角来看,依然将会追踪到两个不同的tensor,只不过是这两个tensor在内存中处于同一个位置如果在反向传播中,需要使用原来的output tensor, 那么在之后的计算过程中,不能对这个tensor做inplace操作,否则反向传播过程中就会报错

RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation error

例子1

The difference is that in the resnet there is a batchnorm between the conv and the relu.
The conv operation need it’s output to be able to compute the backward pass. The batchnorm operations does not need it’s output to compute the backward pass.
So the operation that comes just after batchnorm is allowed to make changes inplace, while an operation coming just after a conv is not.

When you do x = self.relu(x) you basically assign to the python variable x the tensor returned by the self.relu operation. It happens that sometimes, this tensor is the same as the input one (if you have the inplace option enabled). 

结论:只有那些在反向传播过程中不需要使用到的tensor才能做inplace操作,否则不能。

 例子2

In-place operation

这个问题是在我设计一个残差网络(ResNet)的时候遇到的,报错如下:RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation.

我是参考了PyTorch官方的ResNet实现来设计我自己的网络的。其实,问题主要出在forward()函数中的out += residual这句代码。

我们首先来看一下+=这个操作符,这是一个原位操作符因为+=是对out张量直接进行的+操作,就是说执行完+=操作以后原来out指向的那个张量已经改变了。如果使用out = out + residual会有什么不同呢?这个操作是将out和residual相加,然后将结果赋值给out变量。在这个过程中原来out变量指向的那个张量并没有被修改。

那么问题来了,为什么PyTorch官方的实现中,使用+=的写法没有问题,而我自己代码中这样写就有问题了呢?这是因为官方的ResNet中forward()函数中进行相加赋值操作以后就是一个relu激活函数,而relu激活函数反向传播不需要原始输出值,所以是没问题的;而我自己设计的网络中后面还有别的层,所以就不能这样写了。

例子3

Why relu(inplace=True) does not give error in official resnet.py but it gives error in my code?

The difference is that in the resnet there is a batchnorm between the conv and the relu.
The conv operation need it’s output to be able to compute the backward pass. The batchnorm operations does not need it’s output to compute the backward pass.
So the operation that comes just after batchnorm is allowed to make changes inplace, while an operation coming just after a conv is not.

When you do x = self.relu(x) you basically assign to the python variable x the tensor returned by the self.relu operation. It happens that sometimes, this tensor is the same as the input one (if you have the inplace option enabled).

 

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

转自自https://blog.csdn.net/u012436149/article/details/80819523

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.


很多人可能会有疑问, 模型的参数就是 requires_grad=true 的 leaf tensor, 那么模型参数的初始化应该怎么执行呢? 如果看一下 nn.Module._apply() 的代码, 这问题就会很清楚了

w.data = w.data.normal() # 可以使用曲线救国的方法来初始化参数

 

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值