pytorch模型加载跑测试集和训练过程中跑测试集结果不一致的问题?

前馈网络使用with torch.no_grad()和model.eval()比较

问题描述

将训练好的模型拿来做inference,发现显存被占满,无法进行后续操作,但按理说不应该出现这种情况。

 RuntimeError: CUDA out of memory. 
Tried to allocate 128.00 MiB (GPU 0; 7.93 GiB total capacity; 6.94 GiB already allocated; 10.56 MiB free; 7.28 GiB reserved in total by PyTorch)

解决方案 经过排查代码,发现做inference时,各模型虽然已经设置为eval()模式,但是并没有取消网络生成计算图这一操作,这就导致网络在单纯做前向传播时也生成了计算图,从而消耗了大量显存。

所以,将模型前向传播的代码放到with torch.no_grad()下,就能使pytorch不生成计算图,从而节省不少显存

 with torch.no_grad():
     # 代码块
     outputs = model(inputs)
     # 代码块

经过修改,再进行inference就没有遇到显存不够的情况了。此时显存占用显著降低,只占用5600MB左右(3卡)。

model.eval()和torch.no_grad()比较:

model.eval()

  • 使用model.eval()切换到测试模式,不会更新模型的k,b参数

  • 通知dropout层和batchnorm层在train和val中间进行切换在。train模式,dropout层会按照设定的参数p设置保留激活单元的概率(保留概率=p,比如keep_prob=0.8),batchnorm层会继续计算数据的mean和var并进行更新。在val模式下,dropout层会让所有的激活单元都通过,而batchnorm层会停止计算和更新mean和var,直接使用在训练阶段已经学出的mean和var值!

  • model.eval()不会影响各层的gradient计算行为,即gradient计算和存储与training模式一样,只是不进行反向传播!(backprobagation),即只设置了model.eval()pytorch依旧会生成计算图,占用显存,只是不使用计算图来进行反向传播。

torch.no_grad()

首先从requires_grad讲起:

requires_grad

在pytorch中,tensor有一个requires_grad参数,如果设置为True,则反向传播时,该tensor就会自动求导,并且保存在计算图中。tensor的requires_grad的属性默认为False,若一个节点(叶子变量:自己创建的tensor)requires_grad被设置为True,那么所有依赖它的节点requires_grad都为True(即使其他相依赖的tensor的requires_grad = False)

当requires_grad设置为False时,反向传播时就不会自动求导了,也就不会生成计算图,而GPU也不用再保存计算图,因此大大节约了显存或者说内存。

with torch.no_grad

在该模块下,所有计算得出的tensor的requires_grad都自动设置为False。

即使一个tensor(命名为x)的requires_grad = True,在with torch.no_grad计算,由x得到的新tensor(命名为w-标量)requires_grad也为False,且grad_fn也为None,即不会对w求导。例子如下所示:

 x = torch.randn(10, 5, requires_grad = True)
 y = torch.randn(10, 5, requires_grad = True)
 z = torch.randn(10, 5, requires_grad = True)
 with torch.no_grad():
     w = x + y + z
     print(w.requires_grad)
     print(w.grad_fn)
 print(w.requires_grad)
 ​
 False
 None
 False

也就是说,在with torch.no_grad结构中的所有tensor的requires_grad属性会被强行设置为false,如果前向传播过程在该结构中,那么inference过程中都不会产生计算图,从而节省不少显存。

reference:with torch.no_grad():显著减少测试时显存占用_落歌439的博客-CSDN博客

但是?又出问题pytorch模型加载跑测试集和训练过程中跑测试集结果不一致的问题?

虽然利用model.val()可以使得结果和训练时结果相似,但是误差相比训练时的测试还是有一定影响!(视情况而定),如何让他们的结果彻底相同呢?

解决方案:

保存训练完成的神经网络模型,来尝试跑了下测试集的结果,发现效果很差,和训练网络时跑测试集的结果不一样。查了些资料,发现是先eval()再测试数据的问题:

错误写法:

 .....
 model = torch.load('model.pkl')
 model.eval()    #先eval
 x = model.forward(a)  #然后传递数据进行测试
 .....
 ​

改进:

 .....
 model = torch.load('model.pkl')
 x = model.forward(a)  
 model.eval() 
 .....
 ​

上面的方法其实有问题,当初测单个数据的时候正确了,但是用for循环测大量数据的时候会出问题,例如:

错误写法:

 model = torch.load('model.pkl')
 for i in range(1,100)
     a = load_data..  #导入数据
     x = model.forward(a)  
     model.eval() 

正确写法是不需要model.eval():

 model = torch.load('model.pkl')
 for i in range(1,100)
     a = load_data..  #导入数据
     x = model.forward(a)  

这个小问题真的致命,让我一度怀疑我的数据有问题,但结果证明数据是没问题的!

  • 11
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
当你构建好PyTorch模型训练完成后,需要把模型保存下来以备后续使用。这时你需要学会如何加载这个模型,以下是PyTorch模型加载方法的汇总。 ## 1. 加载整个模型 ```python import torch # 加载模型 model = torch.load('model.pth') # 使用模型进行预测 output = model(input) ``` 这个方法可以轻松地加载整个模型,包括模型的结构和参数。需要注意的是,如果你的模型是在另一个设备上训练的(如GPU),则需要在加载时指定设备。 ```python # 加载模型到GPU device = torch.device('cuda') model = torch.load('model.pth', map_location=device) ``` ## 2. 加载模型参数 如果你只需要加载模型参数,而不是整个模型,可以使用以下方法: ```python import torch from model import Model # 创建模型 model = Model() # 加载模型参数 model.load_state_dict(torch.load('model.pth')) # 使用模型进行预测 output = model(input) ``` 需要注意的是,这个方法只能加载模型参数,而不包括模型结构。因此,你需要先创建一个新的模型实例,并确保它的结构与你保存的模型一致。 ## 3. 加载部分模型参数 有时候你只需要加载模型的部分参数,而不是全部参数。这时你可以使用以下方法: ```python import torch from model import Model # 创建模型 model = Model() # 加载部分模型参数 state_dict = torch.load('model.pth') new_state_dict = {} for k, v in state_dict.items(): if k.startswith('layer1'): # 加载 layer1 的参数 new_state_dict[k] = v model.load_state_dict(new_state_dict, strict=False) # 使用模型进行预测 output = model(input) ``` 这个方法可以根据需要选择加载模型的部分参数,而不用加载全部参数。 ## 4. 加载其他框架的模型 如果你需要加载其他深度学习框架(如TensorFlow)训练模型,可以使用以下方法: ```python import torch import tensorflow as tf # 加载 TensorFlow 模型 tf_model = tf.keras.models.load_model('model.h5') # 将 TensorFlow 模型转换为 PyTorch 模型 input_tensor = torch.randn(1, 3, 224, 224) tf_output = tf_model(input_tensor.numpy()) pytorch_model = torch.nn.Sequential( # ... 构建与 TensorFlow 模型相同的结构 ) pytorch_model.load_state_dict(torch.load('model.pth')) # 使用 PyTorch 模型进行预测 pytorch_output = pytorch_model(input_tensor) ``` 这个方法先将 TensorFlow 模型加载到内存中,然后将其转换为 PyTorch 模型。需要注意的是,转换过程可能会涉及到一些细节问题,因此可能需要进行一些额外的调整。 ## 总结 PyTorch模型加载方法有很多,具体要根据实际情况选择。在使用时,需要注意模型结构和参数的一致性,以及指定正确的设备(如GPU)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心之所向521

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值