首页 > 其他分享 >pytorch中MultiScaleRoIAlign及MultiScaleRoIPooling实现

pytorch中MultiScaleRoIAlign及MultiScaleRoIPooling实现

时间:2024-07-21 21:26:27浏览次数:13  
标签:area IoU shape MultiScaleRoIPooling rois pytorch MultiScaleRoIAlign self size

文章目录


ROI pooling及ROI Align原理介绍

ROI Pooling

RoI Pooling用于将任意尺寸感兴趣区域的特征图,都转换为具有固定尺寸 H×W 的小特征图。其原理是将roi区域投影到特征图上得到hxw的特征图再将其划分成HxW网格,每个格子大小近似为h/H x w/W的子窗口,然后将每个子窗口中的值最大池化到相应的输出网格单元中。
步骤1,输入一个固定大小8x8的feature map。
在这里插入图片描述
步骤2,roi感兴趣区域在feature map上投影之后对应的位置坐标:(左上角,右下角坐标)依次为(0,3),(7,8)。
在这里插入图片描述
步骤3、将ROI区域划分为2x2的网格。
在这里插入图片描述
步骤4、对每个网格进行max pooling。

在这里插入图片描述

ROI Align

RoI Align用于将任意尺寸感兴趣区域的特征图,都转换为具有固定尺寸 H×W 的小特征图。其原理是将roi区域投影到特征图上得到hxw的特征图再将其划分成HxW网格,每个格子大小近似为h/W x w/W的子窗口,然后将每个子窗口中的值通过双线性插值得到当前区域的输出值。

步骤1,输入一个固定大小8x8的feature map。
在这里插入图片描述
步骤2、roi感兴趣区域在feature map上投影之后对应的位置坐标:(左上角,右下角坐标)依次为(0,3),(7,8)。
在这里插入图片描述
步骤3、在每个网格采样四个点,用红色x表示其中心位置。
在这里插入图片描述
步骤4、每个网格中的四个红色x的值,通过双线性插值计算。(具体的双线性插值计算过程可参考 详解 Mask-RCNN 中的 “RoIAlign” 作用 / 双线性插值的方法)
在这里插入图片描述
步骤5、对每个网格中四个值进行平均后,得到ROI Align的结果。
在这里插入图片描述

代码解析

代码主体使用的是B站up主霹雳吧啦Wz的Faster R-CNN代码。本文所使用的完整代码开源链接如下(Faster R-CNN)。本文新增的代码主要位于network_files/roi_function.py中。

使用方式

network_files/faster_rcnn_framework.py中修改如下代码即可切换使用ROI Pooling和ROI Align。

class FasterRCNN(FasterRCNNBase):
	....
       #  Multi-scale RoIAlign pooling
       if box_roi_pool is None:
           box_roi_pool = MultiScaleRoIAlign(
               featmap_names=['0', '1', '2', '3'],  # 在哪些特征层进行roi Align
               output_size=[7, 7],
               sampling_ratio=2)
           # box_roi_pool = MultiScaleRoIPooling(
           #     featmap_names=['0', '1', '2', '3'],  # 在哪些特征层进行roi pooling
           #     output_size=[7, 7]
           # )

MultiScaleRoIOperation代码解析

network_files/roi_function.py有三个类:父类MultiScaleRoIOperation,两个子类MultiScaleRoIPoolingMultiScaleRoIAlign。因为MultiScaleRoIPoolingMultiScaleRoIAlign除在计算roipoolroialign时有所不同,其余处理环节均一致。所以本文主要介绍MultiScaleRoIOperation该类的实现。

初始化部分

class MultiScaleRoIOperation(nn.Module):
    def __init__(self, featmap_names, output_size, sampling_ratio=None, method='align'):
        super(MultiScaleRoIOperation, self).__init__()
        assert all([type(featmap_name) == type('') for featmap_name in featmap_names]), \
            'featmap_name must be a str type.'
        self.method = method
        if method == 'align':
            assert type(sampling_ratio) in [int, float], 'sampling_ratio must be int or float when method is align'
            self.sampling_ratio = sampling_ratio
        self.featmap_names = featmap_names
        self.output_size = output_size

各个输入参数为:

featmap_names=['0', '1', '2', '3'] # 在哪些特征层进行roi Align, 
# ‘0’对应下图的P2, ‘1’对应下图的P3, ‘2'对应下图的P4, ‘3’对应下图的P5, 'pool'对应下图的P6
# 图片引用自B站up主霹雳吧啦Wz的FPN结构详解(https://www.bilibili.com/video/BV1dh411U7D9)
output_size=[7, 7] #输出的7x7网格大小
sampling_ratio=2 #对于ROI Align操作每个小网格采样的点数


前向传播部分

def forward(self, features, rois, image_shape):
        """
        Arguments:
            features (Dict[Tensor]): FPN feature maps
            rois (List[Tensor[N, 4]]): proposal boxes
            image_shape (Tuple[H, W]): image shape
        Returns:
            Tensor:
                Pooled features
        """
        filtered_features = self._filter_inputs(features, self.featmap_names)
        rois = self._convert_to_roi_format(rois)

        scales = self._setup_scales(filtered_features, image_shape)
		
		# 计算features在FPN上所处的层级(2, 3, 4, 5)
        lvl_min = -torch.log2(torch.tensor(scales[0], dtype=torch.float32)).item()
        lvl_max = -torch.log2(torch.tensor(scales[-1], dtype=torch.float32)).item()
		# 通过(https://arxiv.org/pdf/1612.03144v2)论文中给出的公式,计算每一个roi区域落入的FPN的层级
		# k=\lfloor k_0+\log_2(\sqrt{wh}/224)\rfloor
        k0 = 4
        box_area = (rois[:, 4] - rois[:, 2]) * (rois[:, 3] - rois[:, 1])
        k = torch.floor(k0 + torch.log2(torch.sqrt(box_area) / 224))
        k = torch.clamp(k, lvl_min, lvl_max) - lvl_min
		# 定义最终的输出格式shape:[1024, 256, 7, 7]
        all_level_pooled_feature = torch.zeros([len(rois), filtered_features[0].shape[1], *self.output_size],
                                               dtype=filtered_features[0].dtype, device=rois.device)
        # 使用torchvision.ops.roi_align, roi_pool计算结果
        for idx, (featmap_in_level, scale) in enumerate(zip(filtered_features, scales)):
            mask_in_level = (k == idx)
            rois_in_level = rois[mask_in_level]
            if self.method == 'pooling':
                pooled_feature = roi_pool(featmap_in_level, rois_in_level, output_size=self.output_size,
                                          spatial_scale=scale)
            elif self.method == 'align':
                pooled_feature = roi_align(featmap_in_level, rois_in_level, output_size=self.output_size,
                                           spatial_scale=scale, sampling_ratio=self.sampling_ratio)
            all_level_pooled_feature[mask_in_level] = pooled_feature

        return all_level_pooled_feature

典型输入参数为(以batch_size=2为例):

features={
	'0': Tensor_shape:(2, 256, 200, 304)
	'1': Tensor_shape:(2, 256, 100, 152)
	'2': Tensor_shape:(2, 256, 50, 76)
	'3': Tensor_shape:(2, 256, 25, 38)
	'pool': Tensor_shape:(2, 256, 13, 19)
}
image_shapes=[(800, 1201), (800, 1066)]
rois=[Tensor_shape:(512, 4), Tensor_shape:(512, 4)]

辅助函数部分

@staticmethod
def _filter_inputs(x, featmap_names):
	'''
		通过featmap_names筛选输入的OrderedDict x, 输出为list[Tensor]。
	'''
    x_filtered = []
    for k, v in x.items():
        if k in featmap_names:
            x_filtered.append(v)
    return x_filtered
    
@staticmethod
def _convert_to_roi_format(rois):
	'''
		rois的形状从[Tensor_shape:(512, 4), Tensor_shape:(512, 4)]变为Tensor_shape[1024, 5]。
		其中rois[:, 0]为[0, 0, 0, ...., 1, 1, 1]。
	'''
    rois = [
        torch.cat([torch.full((roi.shape[0], 1), batch_idx, device=roi.device), roi], dim=1)
        for batch_idx, roi in enumerate(rois)]
    rois = torch.cat(rois, dim=0)
    return rois
    
@staticmethod
def _get_scales(feature, image_size):
	'''
		计算feature的高宽相比于image_size的缩放倍数,例如 2^(-2)
	'''
    size = feature.shape[-2:]
    scales = []
    for s1, s2 in zip(size, image_size):
        scale = float(s1) / float(s2)
        scale = 2 ** (float(torch.tensor(scale).log2().round()))
        scales.append(scale)
    return scales[0]
    
def _setup_scales(self, features, image_shapes):
	'''
		计算得到每一feature的高宽相比于max(image_shapes)的缩放倍数,例如 2^(-2), 2^(-3), 2^(-4), 2^(-5)
	'''
    max_w = 0
    max_h = 0
    for shape in image_shapes:
        max_h = max(shape[0], max_h)
        max_w = max(shape[1], max_w)
    input_size = (max_h, max_w)

    scales = [self._get_scales(feat, input_size) for feat in features]
    return scales

MultiScaleRoIPooling代码解析

method=pooling,调用父类MultiScaleRoIOperationforward方法。

class MultiScaleRoIPooling(MultiScaleRoIOperation):
    def __init__(self, featmap_names, output_size):
        super(MultiScaleRoIPooling, self).__init__(featmap_names, output_size, method='pooling')

    def forward(self, features, rois, image_shape):
        """
        Arguments:
            features (Dict[Tensor]): FPN feature maps
            rois (List[Tensor[N, 4]]): proposal boxes
            image_shape (Tuple[H, W]): image shape
        Returns:
            Tensor:
                Pooled features
        """
        return super().forward(features, rois, image_shape)

MultiScaleRoIAlign代码解析

method=align,调用父类MultiScaleRoIOperationforward方法。

class MultiScaleRoIAlign(MultiScaleRoIOperation):
    def __init__(self, featmap_names, output_size, sampling_ratio):
        super(MultiScaleRoIAlign, self).__init__(featmap_names, output_size,
                                                 sampling_ratio=sampling_ratio, method='align')

    def forward(self, features, rois, image_shape):
        """
        Arguments:
            features (Dict[Tensor]): FPN feature maps
            rois (List[Tensor[N, 4]]): proposal boxes
            image_shape (Tuple[H, W]): image shape
        Returns:
            Tensor:
                aligned features
        """
        return super().forward(features, rois, image_shape)

结果

最后在拥有四块NVIDIA GeForce RTX 3080的机器上进行实验,导入fasterrcnn_resnet50_fpn_coco.pth权重,在Pascal Voc2007+2012的train+val集上训练微调,Pascal Voc2007 test集上验证。微调至第10轮。训练参数如下:

Namespace(data_path='../../PASCAL_VOC_2012/data/', device='cuda', num_classes=20, batch_size=8, start_epoch=0, epochs=20, workers=8, lr=0.02, momentum=0.9, weight_decay=0.0001, lr_step_size=8, lr_steps=[7, 12], lr_gamma=0.1, print_freq=20, output_dir='./multi_train', resume='', aspect_ratio_group_factor=3, test_only=False, world_size=4, dist_url='env://', sync_bn=True, amp='True', rank=0, gpu=0, distributed=True, dist_backend='nccl')

验证集上的coco指标如下:
ROI Pooling

IoU metric: bbox
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.569
 Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.867
 Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.648
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.304
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.453
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.613
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.470
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.663
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.670
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.456
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.574
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.705

ROI Align

IoU metric: bbox
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.582
 Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.870
 Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.651
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.333
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.465
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.625
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.479
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.678
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.686
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.478
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.589
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.719

本文的完整代码链接如下(Faster R-CNN),如果觉得本文对你有用,记得点赞加收藏噢

标签:area,IoU,shape,MultiScaleRoIPooling,rois,pytorch,MultiScaleRoIAlign,self,size
From: https://blog.csdn.net/m0_57300975/article/details/140574528

相关文章

  • pytorch学习(八)Dataset加载分类数据集
    我们之前用torchvision加载了pytorch的网络数据集,现在我们用Dataset加载自己的数据集,并且使用DataLoader做成训练数据集。图像是从网上下载的,网址是点这里,标签是图像文件夹名字。下载完成后作为自己的数据集。1.加载自己的数据集的思路  1)要完成继承自Dataset的类的构......
  • 【PyTorch】图像多分类项目
    【PyTorch】图像二分类项目【PyTorch】图像二分类项目-部署【PyTorch】图像多分类项目【PyTorch】图像多分类项目部署多类图像分类的目标是为一组固定类别中的图像分配标签。目录加载和处理数据搭建模型定义损失函数定义优化器训练和迁移学习用随机权重进行训......
  • 安装pytorch(torch)
    建议换源,可以下载速度很快,这里使用的是清华源需要GPU训练,如果没有,自行选择英伟达版本下载修改源,C盘——>user(用户)——>个人用户(自己命名的用户名),找到.condarc,用记事本打开,修改为:channels:-defaultsshow_channel_urls:truedefault_channels:-https://mirro......
  • PyTorch 中 nn.Conv2d()
    nn.Conv2d() 是PyTorch中用于定义二维卷积层(Convolutionallayer)的函数,它属于 torch.nn 模块,该模块包含了构建神经网络所需的所有构建块。二维卷积层是卷积神经网络(CNN)中最基本也是最重要的组件之一,广泛用于图像和视频处理、自然语言处理等领域。nn.Conv2d() 函数的基本语......
  • PyTorch 中 loss.grad_fn 解释
    在PyTorch中,loss.grad_fn属性是用来访问与loss张量相关联的梯度函数的。这个属性主要出现在使用自动微分(automaticdifferentiation)时,特别是在构建和训练神经网络的过程中。当你构建一个计算图(computationalgraph)时,PyTorch会跟踪所有参与计算的操作(比如加法、乘法、激活函数等),......
  • Pytorch的GPU版本安装
    本文的显卡是NVIDIAGeForceRTX3060LaptopGPU,安装环境是CUDA11.1+CUDNN11.1torch1.9.0+cu111torchvision0.10.0+cu111torchaudio==0.9.0 在安装之前先要知道自己的显卡支持什么CDUA版本右键点击进入NVIDIA控制面板选择帮助——系统信息——组件这里可以看出......
  • PyTorch和CUDA版本对应关系
    转自:截至2022.8.19结论:10.2和11.3能兼容大部分版本的pytorch官网链接:https://pytorch.org/get-started/previous-versions/注意:注意低版本的pytorch是否支持更高版本的cuda。(高版本的pytorch一般能兼容低版本cuda)例如:你需要1.7.0的pytorch,那么cuda只能11.0及以下。官方......
  • 基于 CNN(二维卷积Conv2D)+LSTM 实现股票多变量时间序列预测(PyTorch版)
    前言系列专栏:【深度学习:算法项目实战】✨︎涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对抗网络、门控循环单元、长短期记忆......
  • 使用Pytorch中从头实现去噪扩散概率模型(DDPM)
    扩散模型通常是一种生成式深度学习模型,它通过学习去噪过程来创建数据。扩散模型有许多变体,其中最流行的是条件文本模型,能够根据提示生成特定的图像。某些扩散模型(如Control-Net)甚至能将图像与某些艺术风格融合。在本文中,我们将构建基础的无条件扩散模型,即去噪扩散概率模型(DDPM)。......
  • Pytorch模型文件`*.pt`与`*.pth` 的保存与加载
    1.*.pt文件.pt文件保存的是模型的全部,在加载时可以直接赋值给新变量model=torch.load("filename.pt")。具体操作:(1).模型的保存torch.save(model,"Path/filename.pt")(2).模型的加载model=torch.load("filename.pt")注意:torch.load()的参数使用字符串参数。2..p......