[Pytorch系列-38]: 工具集 - torchvision预定义模型的两种模式model.train和model.eval的表面和本质区别
Posted 文火冰糖的硅基工坊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Pytorch系列-38]: 工具集 - torchvision预定义模型的两种模式model.train和model.eval的表面和本质区别相关的知识,希望对你有一定的参考价值。
作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客
本文网址:https://blog.csdn.net/HiWangWenBing/article/details/121176467
目录
第1章 为什么需要讨论model.train()和model.eval的区别。
第1章 为什么需要讨论model.train()和model.eval的区别。
1.1 利用torchvision.model预定义的模型
在前面的文章中,我们都在探讨如何手工搭建卷积神经网络,训练网络模型。
很显然,对于一些知名的模型,手工搭建的效率较低,且容易出错。
因此,利用pytorch提供的搭建好的知名模型,是一个不错的选择。
1.2 预定义模型的定义:定义模型非常方便!
(1)案例1
# 2-3 使用torchvision.models定义神经网络
net_a = models.alexnet(num_classes = 10)
print(net_a)
AlexNet( (features): Sequential( (0): Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2)) (1): ReLU(inplace=True) (2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False) (3): Conv2d(64, 192, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2)) (4): ReLU(inplace=True) (5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False) (6): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (7): ReLU(inplace=True) (8): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (9): ReLU(inplace=True) (10): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (11): ReLU(inplace=True) (12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False) ) (avgpool): AdaptiveAvgPool2d(output_size=(6, 6)) (classifier): Sequential( (0): Dropout(p=0.5, inplace=False) (1): Linear(in_features=9216, out_features=4096, bias=True) (2): ReLU(inplace=True) (3): Dropout(p=0.5, inplace=False) (4): Linear(in_features=4096, out_features=4096, bias=True) (5): ReLU(inplace=True) (6): Linear(in_features=4096, out_features=10, bias=True) ) )
(2)案例2:
net_b = models.vgg16(num_classes = 10)
print(net_b)
VGG( (features): Sequential( (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU(inplace=True) (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU(inplace=True) (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (6): ReLU(inplace=True) (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (8): ReLU(inplace=True) (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (11): ReLU(inplace=True) (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (13): ReLU(inplace=True) (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (15): ReLU(inplace=True) (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (18): ReLU(inplace=True) (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (20): ReLU(inplace=True) (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (22): ReLU(inplace=True) (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (25): ReLU(inplace=True) (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (27): ReLU(inplace=True) (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (29): ReLU(inplace=True) (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) ) (avgpool): AdaptiveAvgPool2d(output_size=(7, 7)) (classifier): Sequential( (0): Linear(in_features=25088, out_features=4096, bias=True) (1): ReLU(inplace=True) (2): Dropout(p=0.5, inplace=False) (3): Linear(in_features=4096, out_features=4096, bias=True) (4): ReLU(inplace=True) (5): Dropout(p=0.5, inplace=False) (6): Linear(in_features=4096, out_features=10, bias=True) ) )
1.3 预定义模型的两种模式
预定义模型支持两种工作模式
- model.train:适用于训练模式
- model.eval:适用于预测模式
第2章 两种模式的区别
2.1 代码执行结果的区别
(1)train模式
# 2-4 定义网络预测输出
# 测试网络是否能够工作
print("定义测试数据")
input = torch.randn(1, 3, 224, 224)
print(input.shape)
print("")
net_a.train() #设置在训练模式,不设置,模式为训练模式
print("net_a的输出方法1:")
out = net_a(input)
print(out.shape)
print(out)
print("")
print("net_a的输出方法2:")
out = net_a.forward(input)
print(out)
定义测试数据 torch.Size([1, 3, 224, 224]) net_a的输出方法1: torch.Size([1, 10]) tensor([[ 1.3295e-02, 3.6363e-05, 9.0679e-04, 2.2399e-03, 2.4310e-03, -6.0430e-03, -9.2381e-03, -8.3501e-03, -7.8011e-03, -7.4917e-03]], grad_fn=<AddmmBackward>) net_a的输出方法2: tensor([[ 0.0195, -0.0109, -0.0017, -0.0027, 0.0131, -0.0014, -0.0212, -0.0030, -0.0114, -0.0041]], grad_fn=<AddmmBackward>)
备注:
连续两次的预测结果是不完全一样的。
(2)评估模式
# 2-4 定义网络预测输出
# 测试网络是否能够工作
print("定义测试数据")
input = torch.randn(1, 3, 224, 224)
print(input.shape)
print("")
net_a.eval() #设置在训练模式,不设置,模式为训练模式
print("net_a的输出方法1:")
out = net_a(input)
print(out.shape)
print(out)
print("")
print("net_a的输出方法2:")
out = net_a.forward(input)
print(out)
定义测试数据 torch.Size([1, 3, 224, 224]) net_a的输出方法1: torch.Size([1, 10]) tensor([[ 0.0106, -0.0096, 0.0060, 0.0017, 0.0017, -0.0004, -0.0031, -0.0126, -0.0078, -0.0079]], grad_fn=<AddmmBackward>) net_a的输出方法2: tensor([[ 0.0106, -0.0096, 0.0060, 0.0017, 0.0017, -0.0004, -0.0031, -0.0126, -0.0078, -0.0079]], grad_fn=<AddmmBackward>)
备注:
连续两次的预测结果是完全一样的!
(3)train模式预eval模式的区别
- model.train:连续两次的预测结果是不完全一样的。
- model.eval:连续两次的预测结果是完全一样的!
为什么呢?
2.2 train模式与eval模式的本质区别
(1)根本原因
对于一些含有BatchNorm、Dropout等层的模型,model.train()和model.eval()的区别主要在于Batch Normalization和Dropout两层的处理上不同。
(2)train模式
如果模型中有BN层(Batch Normalization)和 Dropout,需要在训练时添加model.train(),启用 Batch Normalization 和 Dropout的特殊处理的功能。
model.train()是保证BN层能够用到每一批数据的均值和方差。
对于Dropout,model.train()是随机取一部分网络连接来训练更新参数,导致在该模式下,每次预测,使用的网络参数连接不尽相同。这就导致,每次预测输出的结果不完全一样。
备注:
至于Dropout和Batch Normalization,请查看相关的文档,文本不再叙述。
(3)eval模式
如果模型中有BN层(Batch Normalization)和Dropout,在测试时添加model.eval()。关闭 Batch Normalization 和 Dropout的功能。
model.eval()是保证BN层能够用全部训练数据的均值和方差,即测试过程中要保证BN层的均值和方差不变。
对于Dropout,model.eval()是利用到了所有网络连接,即不进行随机舍弃神经元。
第3章 函数原型说明
torch.nn — PyTorch 1.10.0 documentationhttps://pytorch.org/docs/stable/nn.html?highlight=module%20eval#torch.nn.Module.eval
3.1 model.train(mode=True)
3.2 model.eval (mode=True)
第4章 源码解析
4.1 model.train(mode=True)
def train(self, mode=True):
r"""Sets the module in training mode.
This has any effect only on certain modules. See documentations of
particular modules for details of their behaviors in training/evaluation
mode, if they are affected, e.g. :class:`Dropout`, :class:`BatchNorm`,
etc.
Returns:
Module: self
"""
self.training = mode
for module in self.children():
module.train(mode)
return self
4.2 model.eval (mode=True)
def eval(self):
return self.train(False)
作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客
本文网址:https://blog.csdn.net/HiWangWenBing/article/details/121176467
以上是关于[Pytorch系列-38]: 工具集 - torchvision预定义模型的两种模式model.train和model.eval的表面和本质区别的主要内容,如果未能解决你的问题,请参考以下文章
[Pytorch系列-42]:工具集 - torchvision常见预训练模型的下载地址
[Pytorch系列-43]:工具集 - torchvision预训练模型参数的导入(以ResNet为例)
[Pytorch系列-47]:工具集 - torchvision.transforms.Normalize和ToSensor的深入详解
[Pytorch系列-39]:工具集 - torchvision搭建AlexNet/VGG/Resnet等网络并训练CFAR10分类数据