聊聊PyTorch中eval和no_grad的关系

首先这两者有着本质上区别

model.eval()是用来告知model内的各个layer采取eval模式工作。这个操作主要是应对诸如dropout和batchnorm这些在训练模式下需要采取不同操作的特殊layer。训练和测试的时候都可以开启。

torch.no_grad()则是告知自动求导引擎不要进行求导操作。这个操作的意义在于加速计算、节约内存。但是由于没有gradient,也就没有办法进行backward。所以只能在测试的时候开启。

所以在evaluate的时候,需要同时使用两者。

model = ...
dataset = ...
loss_fun = ...

# training
lr=0.001
model.train()
for x,y in dataset:
 model.zero_grad()
 p = model(x)
 l = loss_fun(p, y)
 l.backward()
 for p in model.parameters():
  p.data -= lr*p.grad

# evaluating
sum_loss = 0.0
model.eval()
with torch.no_grad():
 for x,y in dataset:
  p = model(x)
  l = loss_fun(p, y)
  sum_loss += l
print('total loss:', sum_loss)

另外no_grad还可以作为函数是修饰符来用,从而简化代码。

def train(model, dataset, loss_fun, lr=0.001):
 model.train()
 for x,y in dataset:
  model.zero_grad()
  p = model(x)
  l = loss_fun(p, y)
  l.backward()
  for p in model.parameters():
   p.data -= lr*p.grad

@torch.no_grad()
def test(model, dataset, loss_fun):
 sum_loss = 0.0
 model.eval()
 for x,y in dataset:
  p = model(x)
  l = loss_fun(p, y)
  sum_loss += l
 return sum_loss

# main block:
model = ...
dataset = ...
loss_fun = ...

# training
train()
# test
sum_loss = test()
print('total loss:', sum_loss)

补充:pytorch中model.train、model.eval以及torch.no_grad的用法

1、model.train()

启用 BatchNormalization 和 Dropout

model.train() 让model变成训练模式,此时 dropout和batch normalization的操作在训练起到防止网络过拟合的问题

2、model.eval()

不启用 BatchNormalization 和 Dropout

model.eval(),pytorch会自动把BN和DropOut固定住,而用训练好的值。不然的话,一旦test的batch_size过小,很容易就会被BN层导致所生成图片颜色失真极大

训练完train样本后,生成的模型model要用来测试样本。在model(test)之前,需要加上model.eval(),否则的话,有输入数据,即使不训练,它也会改变权值。这是model中含有batch normalization层所带来的的性质。

对于在训练和测试时为什么要这样做,可以从下面两段话理解:

在训练的时候, 会计算一个batch内的mean 和var, 但是因为是小batch小batch的训练的,所以会采用加权或者动量的形式来将每个batch的 mean和var来累加起来,也就是说再算当前的batch的时候,其实当前的权重只是占了0.1, 之前所有训练过的占了0.9的权重,这样做的好处是不至于因为某一个batch太过奇葩而导致的训练不稳定。

好,现在假设训练完成了, 那么在整个训练集上面也得到了一个最终的”mean 和var”, BN层里面的参数也学习完了(如果指定学习的话),而现在需要测试了,测试的时候往往会一张图一张图的去测,这时候没有batch而言了,对单独一个数据做 mean和var是没有意义的, 那么怎么办,实际上在测试的时候BN里面用的mean和var就是训练结束后的mean_final 和 val_final. 也可说是在测试的时候BN就是一个变换。所以在用pytorch的时候要注意这一点,在训练之前要有model.train() 来告诉网络现在开启了训练模式,在eval的时候要用”model.eval()”, 用来告诉网络现在要进入测试模式了.因为这两种模式下BN的作用是不同的。

3、torch.no_grad()

这条语句的作用是:在测试时不进行梯度的计算,这样可以在测试时有效减小显存的占用,以免发生显存溢出(OOM)。

这条语句通常加在网络预测的那条代码上。

4、pytorch中model.eval()和“with torch.no_grad()区别

两者区别

在PyTorch中进行validation时,会使用model.eval()切换到测试模式,在该模式下,

主要用于通知dropout层和batchnorm层在train和val模式间切换

在train模式下,dropout网络层会按照设定的参数p设置保留激活单元的概率(保留概率=p); batchnorm层会继续计算数据的mean和var等参数并更新。

在val模式下,dropout层会让所有的激活单元都通过,而batchnorm层会停止计算和更新mean和var,直接使用在训练阶段已经学出的mean和var值。

该模式不会影响各层的gradient计算行为,即gradient计算和存储与training模式一样,只是不进行反传(backprobagation)

而with torch.zero_grad()则主要是用于停止autograd模块的工作,以起到加速和节省显存的作用,具体行为就是停止gradient计算,从而节省了GPU算力和显存,但是并不会影响dropout和batchnorm层的行为。

使用场景

如果不在意显存大小和计算时间的话,仅仅使用model.eval()已足够得到正确的validation的结果;而with torch.zero_grad()则是更进一步加速和节省gpu空间(因为不用计算和存储gradient),从而可以更快计算,也可以跑更大的batch来测试。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • Python深度学习之使用Pytorch搭建ShuffleNetv2

    一.model.py 1.1 Channel Shuffle def channel_shuffle(x: Tensor, groups: int) -> Tensor: batch_size, num_channels, height, width = x.size() channels_per_group = num_channels // groups # reshape # [batch_size, num_channels, height, width] -> [batch_size

  • PyTorch CUDA环境配置及安装的步骤(图文教程)

    Pytorch版本介绍 torch:1.6 CUDA:10.2 cuDNN:8.1.0 ✨安装 NVIDIA 显卡驱动程序 一般 电脑出厂/装完系统 会自动安装显卡驱动 如果有 可直接进行下一步 下载链接 http://www.nvidia.cn/Download/index.aspx?lang=cn 选择和自己显卡相匹配的显卡驱动 下载安装 ✨确认项目所需torch版本 # pip install -r requirements.txt # base ---------------------

  • pytorch 禁止/允许计算局部梯度的操作

    一.禁止计算局部梯度 torch.autogard.no_grad: 禁用梯度计算的上下文管理器. 当确定不会调用Tensor.backward()计算梯度时,设置禁止计算梯度会减少内存消耗.如果需要计算梯度设置Tensor.requires_grad=True 两种禁用方法: 将不用计算梯度的变量放在with torch.no_grad()里 >>> x = torch.tensor([1.], requires_grad=True) >>> with torch.n

  • pytorch 优化器(optim)不同参数组,不同学习率设置的操作

    optim 的基本使用 for do: 1. 计算loss 2. 清空梯度 3. 反传梯度 4. 更新参数 optim的完整流程 cifiron = nn.MSELoss() optimiter = torch.optim.SGD(net.parameters(),lr=0.01,momentum=0.9) for i in range(iters): out = net(inputs) loss = cifiron(out,label) optimiter.zero_grad() # 清空之前

  • pytorch visdom安装开启及使用方法

    安装 conda activate ps pip install visdom 激活ps的环境,在指定的ps环境中安装visdom 开启 python -m visdom.server 浏览器输入红框内的网址 使用 1. 简单示例:一条线 from visdom import Visdom # 创建一个实例 viz=Visdom() # 创建一个直线,再把最新数据添加到直线上 # y x二维两个轴,win 创建一个小窗口,不指定就默认为大窗口,opts其他信息比如名称 viz.line([1,2

  • pytorch_detach 切断网络反传方式

    detach 官方文档中,对这个方法是这么介绍的. detach = _add_docstr(_C._TensorBase.detach, r""" Returns a new Tensor, detached from the current graph. The result will never require gradient. .. note:: Returned Tensor uses the same data tensor as the original on

  • PyTorch 如何将CIFAR100数据按类标归类保存

    few-shot learning的采样 Few-shot learning 基于任务对模型进行训练,在N-way-K-shot中,一个任务中的meta-training中含有N类,每一类抽取K个样本构成support set, query set则是在刚才抽取的N类剩余的样本中sample一定数量的样本(可以是均匀采样,也可以是不均匀采样). 对数据按类标归类 针对上述情况,我们需要使用不同类别放置在不同文件夹的数据集.但有时,数据并没有按类放置,这时就需要对数据进行处理. 下面以CIFAR1

  • PyTorch学习之软件准备与基本操作总结

    一.概述 PyTorch可以认为是一个Python库,可以像NumPy.Pandas一样被调用.PyTorch和NumPy功能是类似的,可以将PyTorch看作用在神经网络(深度学习)里的NumPy,并且加入了GPU支持的NumPy(原生NumPy不支持GPU). 目前,应用最广.热度最高的深度学习框架为PyTorch和TensorFlow.本系列先从PyTorch开始,后面有机会再去弄TersonFlow,还有时间的话,就再去系统回顾下之前学习的Caffe框架. 小结:PyTorch为深度学习

  • pytorch中的nn.ZeroPad2d()零填充函数实例详解

    在卷积神经网络中,有使用设置padding的参数,配合卷积步长,可以使得卷积后的特征图尺寸大小不发生改变,那么在手动实现图片或特征图的边界零填充时,常用的函数是nn.ZeroPad2d(),可以指定tensor的四个方向上的填充,比如左边添加1dim.右边添加2dim.上边添加3dim.下边添加4dim,即指定paddin参数为(1,2,3,4),本文中代码设置的是(3,4,5,6)如下: import torch.nn as nn import cv2 import torchvision f

  • pytorch实现线性回归以及多元回归

    本文实例为大家分享了pytorch实现线性回归以及多元回归的具体代码,供大家参考,具体内容如下 最近在学习pytorch,现在把学习的代码放在这里,下面是github链接 直接附上github代码 # 实现一个线性回归 # 所有的层结构和损失函数都来自于 torch.nn # torch.optim 是一个实现各种优化算法的包,调用的时候必须是需要优化的参数传入,这些参数都必须是Variable x_train = np.array([[3.3],[4.4],[5.5],[6.71],[6.93

  • 浅谈pytorch中的nn.Sequential(*net[3: 5])是啥意思

    看到代码里面有这个 1 class ResNeXt101(nn.Module): 2 def __init__(self): 3 super(ResNeXt101, self).__init__() 4 net = resnext101() # print(os.getcwd(), net) 5 net = list(net.children()) # net.children()得到resneXt 的表层网络 # for i, value in enumerate(net): # print(

  • Pytorch实现全连接层的操作

    全连接神经网络(FC) 全连接神经网络是一种最基本的神经网络结构,英文为Full Connection,所以一般简称FC. FC的准则很简单:神经网络中除输入层之外的每个节点都和上一层的所有节点有连接. 以上一次的MNIST为例 import torch import torch.utils.data from torch import optim from torchvision import datasets from torchvision.transforms import transf

  • PyTorch的Debug指南

    一.ipdb 介绍 很多初学 python 的同学会使用 print 或 log 调试程序,但是这只在小规模的程序下调试很方便,更好的调试应该是在一边运行的时候一边检查里面的变量和方法. 感兴趣的可以去了解 pycharm 的 debug 模式,功能也很强大,能够满足一般的需求,这里不多做赘述,我们这里介绍一个更适用于 pytorch 的一个灵活的 pdb 交互式调试工具. Pdb 是一个交互式的调试工具,集成与 Python 标准库中,它能让你根据需求跳转到任意的 Python 代码断点.查看

  • 如何利用Pytorch计算三角函数

    一.加载库 首先加载torch库,进入python后加载库使用import导入 [import 库名] 二.sin值计算方法 pytorch中的sin计算都是基于tensor的,所以无论单个值还是多个值同时计算sin值,都需要首先将输入量转换为tensor 使用指令: [torch.sin(tensor)] 实例中,使用了计算单个和多个sin值时的情况 三.cos值计算方法 pytorch中的cos计算都是基于tensor的,所以无论单个值还是多个值同时计算cos值,都需要首先将输入量转换为te

  • win10系统配置GPU版本Pytorch的详细教程

    一.安装cuda 1.在英伟达官网下载最新版的cuda驱动 https://developer.nvidia.com/zh-cn/cuda-downloads 都选上就行了,然后一路默认安装 输入nvcc -V查看是否安装成功 二.安装pycuda 1.在控制台中输入pip install pycuda 安装pycuda 2.在环境变量中添加cl.exe 3.测试pycuda是否正常运行 import pycuda.driver as drv import pycuda.tools,pycuda

  • 使用pytorch实现线性回归

    本文实例为大家分享了pytorch实现线性回归的具体代码,供大家参考,具体内容如下 线性回归都是包括以下几个步骤:定义模型.选择损失函数.选择优化函数. 训练数据.测试 import torch import matplotlib.pyplot as plt # 构建数据集 x_data= torch.Tensor([[1.0],[2.0],[3.0],[4.0],[5.0],[6.0]]) y_data= torch.Tensor([[2.0],[4.0],[6.0],[8.0],[10.0]

  • Pytorch实现图像识别之数字识别(附详细注释)

    使用了两个卷积层加上两个全连接层实现 本来打算从头手撕的,但是调试太耗时间了,改天有时间在从头写一份 详细过程看代码注释,参考了下一个博主的文章,但是链接没注意关了找不到了,博主看到了联系下我,我加上 代码相关的问题可以评论私聊,也可以翻看博客里的文章,部分有详细解释 Python实现代码: import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transf

随机推荐