1.RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: balabala...
今天在尝试复现别人论文的过程中出现了以上错误,花了很长时间才解决,看到这篇文章(PyTorch 的 Autograd 链接:https://zhuanlan.zhihu.com/p/69294347)才解答了我的疑问
注:在激活函数Relu和LeakyRelu中将参数inplace设置为True一般情况下并不会影响到反向传播,并且该操作还可以起到有效降低显存的作用
2.RuntimeError: CUDA error: CUBLAS_STATUS_ALLOC_FAILED when calling `cublasCreate(handle)`
别人的博客上说这个错误可能是因为分类数的设定有问题,在仔细核对数据集之后,我发现数据集和label并没有错误,直到在pytorch forums中找到了解决方案,即显存不足,batchsize过大,将batchsize调小之后问题就迎刃而解了。
即该问题与cuda out of menmery(单词可能拼写错了)类似,都可通过降级batchsize解决
3.nn.MSE()和nn.CrossEntropyLoss()
MSE为均方损失函数,常用于回归问题,CEL(CrossEntropyLoss)为交叉熵损失函数,常用于分类问题。
这两者都要求predict和target的shape保持一致,由于我制作的label并没有进行onehot编码,在使用MSE作为损失函数的时候代码报错,而在使用CEL作为损失函数的时候代码正常运行,后来看文章得知CEL会自动将label转化为onehot编码的格式而MSE则不会,并且CEL中内置softmax操作,所以通常情况下在最后一层的全连接层不需要加上softmax操作,
4.nn.Module类ModuleList重复调用问题
import torch
import torch.nn as nn
class net1(nn.Module):
def __init__(self):
super(net1, self).__init__()
self.conv1 = nn.Conv2d(3,64,3,1,1)
self.conv2 = nn.Conv2d(64,64,3,1,1)
def forward(self,x):
x = self.conv1(x)
x = self.conv2(x)
return x
class net2(nn.Module):
def __init__(self):
super(net2, self).__init__()
self.conv1 = nn.Conv2d(3, 64, 3, 1, 1)
self.conv2 = nn.Conv2d(64, 64, 3, 1, 1)
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = self.conv2(x)
x = self.conv2(x)
return x
sum1 = 0
model = net1()
for i in model.parameters():
sum1 += i.numel()
print(model)
print(sum1)
sum2 = 0
model1 = net2()
for i in model1.parameters():
sum2 += i.numel()
print(sum2)
print(model1)#输出为:
net1(
(conv1): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
38720
38720
net2(
(conv1): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
也就是说一个模块是否可以在 forward 函数中被调用多次呢?答案当然是可以的,但是,被调用多次的模块,是使用同一组 parameters 的,也就是它们的参数是共享的,无论之后怎么更新。例子如下,虽然在 forward 中我们用了 self.conv1被调用了三次 ,但是它们只有一组参数。在笔者实现自己的一个idea的时候这个特性起到了关键的作用。因此,如果你不希望模型的多个操作的使用同一组参数,就不要在forward方法中对同一方法进行重复调用。而对于那些没有参数的操作,则可以重复调用,如最大池化,平均池化,不带参数的激活函数,这样可以在一定程度上减少代码量。
4.nn 与 nn.functional
nn.Xxx和nn.functional.xxx的实际功能是相同的,即nn.Conv2d和nn.functional.conv2d 都是进行卷积,nn.Dropout 和nn.functional.dropout都是进行dropout。 运行效率也是近乎相同。
nn.functional.xxx是函数接口,而nn.Xxx是nn.functional.xxx的类封装,并且nn.Xxx都继承于一个共同祖先nn.Module。这一点导致nn.Xxx除了具有nn.functional.xxx功能之外,内部附带了nn.Module相关的属性和方法,例如train(), eval(),load_state_dict, state_dict 等。
两者的差别主要在于:
1调用方式不同:nn.Xxx
需要先实例化并传入参数,然后以函数调用的方式调用实例化的对象并传入输入数据。
2.nn.Xxx
继承于nn.Module
, 能够很好的与nn.Sequential
结合使用, 而nn.functional.xxx
无法与nn.Sequential
结合使用。
3. nn.Xxx不需要你自己定义和管理weight;而nn.functional.xxx需要你自己定义weight,每次调用的时候都需要手动传入weight, 不利于代码复用,nn.XXX对于我们在构建需要网络有很大的便利性.如果在构建网络的过程中使用的全部是
nn.functional.xxx,则在打印模型结构的时候,网络中的结构不会显示出来,但是网络依然是可以训练的,不过不利于模型结构的可视化,因此pytorch官方
推荐:具有学习参数的(例如,conv2d, linear, batch_norm)采用nn.Xxx
方式,没有学习参数的(例如,maxpool, loss func, activation func)等根据个人选择使用nn.functional.xxx
或者nn.Xxx
方式。笔者更喜欢使用nn.Xxx。
reference:
1.PyTorch 的 Autograd 链接:https://zhuanlan.zhihu.com/p/69294347
2.Pytorch常用的交叉熵损失函数CrossEntropyLoss()详解 链接:https://zhuanlan.zhihu.com/p/98785902
3PyTorch 中,nn 与 nn.functional 有什么区别?链接:.https://www.zhihu.com/question/66782101/answer/579393790
4.PyTorch 中的 ModuleList 和 Sequential: 区别和使用场景 链接:https://zhuanlan.zhihu.com/p/64990232