RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation
问题
在用pytorch跑生成对抗网络的时候,出现错误Runtime Error: one of the variables needed for gradient computation has been modified by an inplace operation,特记录排坑记录。
环境
windows10 2004
python 3.7.4
pytorch 1.7.0 + cpu
解决过程
- 尝试一
这段错误代码看上去不难理解,意思为:计算梯度所需的某变量已被一就地操作修改。什么是就地操作呢,举个例子如x += 1就是典型的就地操作,可将其改为y = x + 1。但很遗憾,这样并没有解决我的问题,这种方法的介绍如下。
在网上搜了很多相关博客,大多原因如下:
由于0.4.0把Varible和Tensor融合为一个Tensor,inplace操作,之前对Varible能用,但现在对Tensor,就会出错了。
所以解决方案很简单:将所有inplace操作转换为非inplace操作。如将x += 1换为y = x + 1。
仍然有一个问题,即如何找到inplace操作,这里提供一个小trick:分阶段调用y.backward(),若报错,则说明这之前有问题;反之则说明错误在该行之后。
- 尝试二
在我的代码里根本就没有找到任何inplace操作,因此上面这种方法行不通。自己盯着代码,debug,啥也看不出来,好久......
忽然有了新idea。我的训练阶段的代码如下:
for epoch in range(1, epochs + 1):
for idx, (lr, hr) in enumerate(traindata_loader):
lrs = lr.to(device)
hrs = hr.to(device)
# update the discriminator
netD.zero_grad()
logits_fake = netD(netG(lrs).detach())
logits_real = netD(hrs)
# Label smoothing
real = (torch.rand(logits_real.size()) * 0.25 + 0.85).clone().detach().to(device)
fake = (torch.rand(logits_fake.size()) * 0.15).clone().detach().to(device)
d_loss = bce(logits_real, real) + bce(logits_fake, fake)
d_loss.backward(retain_graph=True)
optimizerD.step()
# update the generator
netG.zero_grad()
# !!!问题出错行
g_loss = contentLoss(netG(lrs), hrs) + adversarialLoss(logits_fake)
g_loss.backward()
optimizerG.step()
判别器loss的backward是正常的,生成器loss的backward有问题。观察到g_loss由两项组成,所以很自然的想法就是删掉其中一项看是否正常。结果为:只保留第一项程序正常运行;g_loss中包含第二项程序就出错。
因此去看了adversarialLoss的代码:
class AdversarialLoss(nn.Module):
def __init__(self):
super(AdversarialLoss, self).__init__()
self.bec_loss = nn.BCELoss()
def forward(self, logits_fake):
# Adversarial Loss
# !!! 问题在这,logits_fake加上detach后就可以正常运行
adversarial_loss = self.bec_loss(logits_fake, torch.ones_like(logits_fake))
return 0.001 * adversarial_loss
看不出来任何问题,只能挨个试。这里只有两个变量:logits_fake和torch.ones_like(logits_fake)。后者为常量,所以试着固定logits_fake,不让其参与训练,程序竟能运行了!
class AdversarialLoss(nn.Module):
def __init__(self):
super(AdversarialLoss, self).__init__()
self.bec_loss = nn.BCELoss()
def forward(self, logits_fake):
# Adversarial Loss
# !!! 问题在这,logits_fake加上detach后就可以正常运行
adversarial_loss = self.bec_loss(logits_fake.detach(), torch.ones_like(logits_fake))
return 0.001 * adversarial_loss
由此知道了被修改的变量是logits_fake。尽管程序可以运行了,但这样做不一定合理。类AdversarialLoss中没有对logits_fake进行修改,所以返回刚才的训练程序中。
for epoch in range(1, epochs + 1):
for idx, (lr, hr) in enumerate(traindata_loader):
lrs = lr.to(device)
hrs = hr.to(device)
# update the discriminator
netD.zero_grad()
logits_fake = netD(netG(lrs).detach())
logits_real = netD(hrs)
# Label smoothing
real = (torch.rand(logits_real.size()) * 0.25 + 0.85).clone().detach().to(device)
fake = (torch.rand(logits_fake.size()) * 0.15).clone().detach().to(device)
d_loss = bce(logits_real, real) + bce(logits_fake, fake)
d_loss.backward(retain_graph=True)
# 这里进行的更新操作
optimizerD.step()
# update the generator
netG.zero_grad()
# !!!问题出错行
g_loss = contentLoss(netG(lrs), hrs) + adversarialLoss(logits_fake)
g_loss.backward()
optimizerG.step()
注意到Discriminator在出错行之前进行了更新操作,因此真相呼之欲出————optimizerD.step()对logits_fake进行了修改。直接将其挪到倒数第二行即可,修改后代码为:
for epoch in range(1, epochs + 1):
for idx, (lr, hr) in enumerate(traindata_loader):
lrs = lr.to(device)
hrs = hr.to(device)
# update the discriminator
netD.zero_grad()
logits_fake = netD(netG(lrs).detach())
logits_real = netD(hrs)
# Label smoothing
real = (torch.rand(logits_real.size()) * 0.25 + 0.85).clone().detach().to(device)
fake = (torch.rand(logits_fake.size()) * 0.15).clone().detach().to(device)
d_loss = bce(logits_real, real) + bce(logits_fake, fake)
d_loss.backward(retain_graph=True)
# update the generator
netG.zero_grad()
g_loss = contentLoss(netG(lrs), hrs) + adversarialLoss(logits_fake)
g_loss.backward()
optimizerD.step()
optimizerG.step()
程序终于正常运行了,耶( •̀ ω •́ )y!
总结
原因:在计算生成器网络梯度之前先对判别器进行更新,修改了某些值,导致Generator网络的梯度计算失败。
解决方法:将Discriminator的更新步骤放到Generator的梯度计算步骤后面。
RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation的更多相关文章
- RuntimeError: one of the variables needed for gradient computation has been modified by an inplace
vgg里面的 ReLU默认的参数inplace=True 当我们调用vgg结构的时候注意 要将inplace改成 False 不然会报错 RuntimeError: one of the variab ...
- one of the variables needed for gradient computation has been modified by an inplace operation: [torch.cuda.FloatTensor [3, 1280, 28, 28]], which is output 0 of LeakyReluBackward1, is at version 2;
RuntimeError: one of the variables needed for gradient computation has been modified by an inplace o ...
- TensorFlow 学习(八)—— 梯度计算(gradient computation)
maxpooling 的 max 函数关于某变量的偏导也是分段的,关于它就是 1,不关于它就是 0: BP 是反向传播求关于参数的偏导,SGD 则是梯度更新,是优化算法: 1. 一个实例 relu = ...
- pytorch .detach() .detach_() 和 .data用于切断反向传播
参考:https://pytorch-cn.readthedocs.io/zh/latest/package_references/torch-autograd/#detachsource 当我们再训 ...
- PyTorch学习笔记及问题处理
1.torch.nn.state_dict(): 返回一个字典,保存着module的所有状态(state). parameters和persistent_buffers都会包含在字典中,字典的key就 ...
- pytorch的自动求导机制 - 计算图的建立
一.计算图简介 在pytorch的官网上,可以看到一个简单的计算图示意图, 如下. import torchfrom torch.autograd import Variable x = Variab ...
- [源码解析]PyTorch如何实现前向传播(2) --- 基础类(下)
[源码解析]PyTorch如何实现前向传播(2) --- 基础类(下) 目录 [源码解析]PyTorch如何实现前向传播(2) --- 基础类(下) 0x00 摘要 0x01 前文回顾 0x02 Te ...
- Coursera Deep Learning 2 Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization - week1, Assignment(Gradient Checking)
声明:所有内容来自coursera,作为个人学习笔记记录在这里. Gradient Checking Welcome to the final assignment for this week! In ...
- 课程二(Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization),第一周(Practical aspects of Deep Learning) —— 4.Programming assignments:Gradient Checking
Gradient Checking Welcome to this week's third programming assignment! You will be implementing grad ...
随机推荐
- linux系统修改不成功/无法修改密码
1.问题描述 新上架的60台浪潮服务器使用某带外装机平台进行统一安装,安装完成后修改用户密码时统一无法修改,使用root账户无法修改其他用户密码,自身根密码也无法修改成功 2.排查问题 因带外装机平台 ...
- Spring学习(一)--Spring的设计与整体架构
之前只是在学校里大概的学习了一下Spring框架的使用以及一些最基本.浅显的原理,并没有做出深入的学习,等到工作之后想提升自己的时候发现所掌握的Spring框架的简直烂如狗屎,为监督自己的学习进度,立 ...
- Spring系列之事务的控制 注解实现+xml实现+事务的隔离等级
Spring系列之事务的控制 注解实现+xml实现 在前面我写过一篇关于事务的文章,大家可以先去看看那一篇再看这一篇,学习起来会更加得心应手 链接:https://blog.csdn.net/pjh8 ...
- 02 sublime text3下配置Python的编译运行环境
内容参考如下文章,加入了自己的干货: https://www.cnblogs.com/huluwahaha/p/7503930.html 在sublime中如何配置Python的编译环境呢? 打开Su ...
- matlab中subplot 在平铺位置创建坐标区
来源:https://ww2.mathworks.cn/help/matlab/ref/subplot.html?searchHighlight=subplot&s_tid=doc_srcht ...
- Java (三)APACHE Commons IO 常规操作
上一篇:Java (二)基于Eclipse配置Commons IO的环境 例1:查看文件.文件夹的长度(大小). 1 import java.io.File; 2 3 import org.apach ...
- docker-创建容器常见选项
1. docker run创建容器常见选项 1.1 创建容器 选项 描述 -i,-interactive 交互式 -t,-tty 分配一个伪终端 -d,-detach 运行容器到后台 -e,-env ...
- 多测师讲解IDE工具python_001.2pycham_安装
PyCharm安装使用教程 Pycharm 是目前 Python 语言最好用的集成开发工具. 下载 Pycharm 载时有两种版本选择 Professional(专业版,收费)和Community(社 ...
- 99%的Android开发不得不面对的三道坎,到底该怎么破?
今年比往年要特殊一些,受疫情的影响,很多公司都出现了裁员现象.以至于最近很多技术同学也在纷纷向我倒苦水. 王鹏便是其中的一员,王鹏之前是在一线城市的一家小型互联网公司做Android应用开发.从毕业实 ...
- 经验分享:计算机 web 浏览器——访问剪切板图片
有时候,我们希望能访问用户的剪切板,来实现一些方便用户的功能:但是另一方面,剪切板里的数据对用户来说又是非常隐私的,所以浏览器在获取信息方面有安全限制,同时也提供访问接口. 当我们需要实现在富文本 ...