【问题标题】:Clarification of a Faster R-CNN torchvision implementationFaster R-CNN torchvision 实现的说明
【发布时间】:2021-03-26 01:49:46
【问题描述】:

我正在研究 torchvision 的 Faster R-CNN 实现的 source code,我遇到了一些我不太了解的事情。也就是说,假设我想创建一个 Faster R-CNN 模型,而不是在 COCO 上预训练,在 ImageNet 上预训练主干,然后只获得主干,我执行以下操作:

plain_backbone = fasterrcnn_resnet50_fpn(pretrained=False, pretrained_backbone=True).backbone.body

这与herehere 所示的主干设置方式一致。但是,当我通过模型传递图像时,结果与我直接设置 resnet50 所获得的结果不对应。即:

# Regular resnet50, pretrained on ImageNet, without the classifier and the average pooling layer
resnet50_1 = torch.nn.Sequential(*(list(torchvision.models.resnet50(pretrained=True).children())[:-2]))
resnet50_1.eval()
# Resnet50, extract from the Faster R-CNN, also pre-trained on ImageNet
resnet50_2 = fasterrcnn_resnet50_fpn(pretrained=False, pretrained_backbone=True).backbone.body
resnet50_2.eval()
# Loading a random image, converted to torch.Tensor, rescalled to [0, 1] (not that it matters)
image = transforms.ToTensor()(Image.open("random_images/random.jpg")).unsqueeze(0)
# Obtaining the model outputs
with torch.no_grad():
    # Output from the regular resnet50
    output_1 = resnet50_1(image)
    # Output from the resnet50 extracted from the Faster R-CNN
    output_2 = resnet50_2(image)["3"]
    # Their outputs aren't the same, which I would assume they should be
    np.testing.assert_almost_equal(output_1.numpy(), output_2.numpy())

期待你的想法!

【问题讨论】:

  • 我也验证了这一点!两者似乎都从同一个检查点加载权重,但输出不同。将主干包裹在resnet50_2 中的IntermediateLayerGetter 类可能是造成这种情况的原因,不过,我还没有进行更多调查。
  • 是的,这就是我感到困惑的地方。 IntermediateLayerGetter 是一个包装器,可以根据我的理解轻松获取层的输出。但是,让我知道你发现了什么:)

标签: python pytorch resnet torchvision faster-rcnn


【解决方案1】:

这是因为 fasterrcnn_resnet50_fpn 使用自定义规范化层 (FrozenBatchNorm2d) 而不是默认的 BatchNorm2D。它们非常相似,但我怀疑微小的数值差异会导致问题。

如果你指定与标准 resnet 使用相同的规范化层,它将通过检查:

import torch
import torchvision
from torchvision.models.detection.faster_rcnn import fasterrcnn_resnet50_fpn
import numpy as np
from torchvision.ops import misc as misc_nn_ops

# Regular resnet50, pretrained on ImageNet, without the classifier and the average pooling layer
resnet50_1 = torch.nn.Sequential(*(list(torchvision.models.resnet50(pretrained=True, norm_layer=misc_nn_ops.FrozenBatchNorm2d).children())[:-2]))
resnet50_1.eval()
# Resnet50, extract from the Faster R-CNN, also pre-trained on ImageNet
resnet50_2 = fasterrcnn_resnet50_fpn(pretrained=False, pretrained_backbone=True).backbone.body
resnet50_2.eval()
# am too lazy to get a real image
image = torch.ones((1, 3, 224, 224))
# Obtaining the model outputs
with torch.no_grad():
    # Output from the regular resnet50
    output_1 = resnet50_1(image)
    # Output from the resnet50 extracted from the Faster R-CNN
    output_2 = resnet50_2(image)["3"]
    # Passes
    np.testing.assert_almost_equal(output_1.numpy(), output_2.numpy())

【讨论】:

  • 好收获。作为记录,您能否详细说明 BatchNorm 和 FrozenBatchNorm 之间的区别?顺便说一句,我现在接受你的回答。
  • @gorjan FrozenBatchNorm 是用纯 PyTorch 实现的 here,而 BatchNorm 是用 C++ 实现的。我认为 FrozenBatchNorm 存在的唯一原因是他们希望 BN 保持eval 模式,并且不以用户所需的最少工作量更新其参数。输出中的任何差异都应该只是数字上的并且(我相信)不是实质性的。
  • 刚刚找到官方解释here
猜你喜欢
  • 2020-07-24
  • 2021-04-27
  • 1970-01-01
  • 1970-01-01
  • 2020-02-10
  • 1970-01-01
  • 1970-01-01
  • 2018-01-03
  • 1970-01-01
相关资源
最近更新 更多