PyTorch踩坑记

网友投稿 800 2022-10-08

PyTorch踩坑记

PyTorch踩坑记

PyTorch踩坑记

前言

自己刚开始使用深度学习框架做事情的时候,选择了最容易入门的​​Keras​​​。Keras是在其它深度学习框架(谷歌的​​TensorFlow​​​,微软的​​CNTK​​​以及​​Theano​​)的基础上,抽象了底层实现的差异,提供的更高层的API接口。说说Keras的好处吧!个人觉得Keras最吸引人的地方就是API接口的设计特别人性化,对于样本的训练,结果的测试都有一种使用传统机器学习库的感觉;函数式接口设计使得深度网络的时候特别容易,简直就像在玩乐高。如果有人想入门深度学习,我一定也会推荐Keras。

后来,我为什么转到​​PyTorch​​​呢?因为PyTorch大部分框架是基于Python实现的(虽然底层也有C代码),PyTorch提供了很简单的接口使得​​tensor​​​和NumPy中的​​ndarray​​互相转换,这样基于NumPy的各种库我们也可以直接拿来使用。当然,这不是最重要的。我选择PyTorch的原因是因为:第一,基于Python实现,而不是像其它库一样只是提供了一个Python的调用接口而已。这样对于深度框架的调试就特别容易,如果你使用TensorFlow或者Keras,底层的实现都是C/C++,无法很好地进行底层的调试;第二,PyTorch使用动态图,而TensorFlow这样的框架使用静态图。这就是说当你使用TensorFlow框架编译一个深度模型,模型就是固定的,不容易改变,而PyTorch的动态图提供了更多的灵活性,特别是对RNN网络。所以,我在PyTorch脱离了Beta版本(0.4)以后,我果断转到了PyTorch,开始了新的学习之旅。

下面记录的是我在使用PyTorch遇到的一些问题及其解决方案:

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​​激活函数,而激活函数层不需要反向传播,所以是没问题的;而我自己设计的网络中后面还有别的层,所以就不能这样写了。

Input type and weight type should be the same

这个问题是我将代码移植到GPU上运行时遇到的问题,报错如下:​​RuntimeError: Input type (CUDAFloatTensor) and weight type (CPUFloatTensor) should be the same​​

有人可能说,这个简单!这是你的输入数据在GPU上,而模型参数不在GPU上,使用​​to()​​​方法将模型复制到GPU上即可。非也,我这里说的不是个问题。当然,如果有人遇到这个错误了,第一要检查的是你是不是使用​​to()​​​或者​​cuda()​​方法将模型搬运到GPU上去了。

我的代码已经使用​​to()​​将模型复制到GPU上去了,为什么还会有这个问题呢?通过两天的调试,我发现我的模型大部分参数是位于GPU上的,而模型中的一些层却在CPU上,所以导致了这个问题。

注:在调试程序的时候怎么查看模型是否在GPU上呢?使用如下函数可以进行测试:​​next(model.parameters()).is_cuda​​

我后来发现,是我在设计ResNet的时候使用了​​list​​​存储我的残差层导致的。如果在定义模型的时候,使用普通的​​list​​​存储的模型层,PyTorch提供的​​to()​​​方法是不会将对应的层复制到GPU上去的。解决办法也很简单,使用​​torch.nn.ModuleList​​容器来存储就好了。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:分享小程序API的认证方式实例(小程序api接口怎么用)
下一篇:微信小程序用户自定义模版的功能实现(微信小程序功能模块设计)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~