ROI pooling代码阅读 - forward过程

先来说一下ROI pooling在做什么吧,对于猫咪或者狗所在区域,我希望能够提取该区域的特征,但是这两块区域不一样大,我又希望能够获取一样长的特征,这样方便后面的接全连接层(全连接层对于输入的大小要求固定),于是就有了这样一个需求,对于不同的区域(我们称之为rois),得到相同的特征
做法:将roi区域划分成一个N*N(一般为7*7)的方格,在每个方格内取该方格的最大值,来代表该区域的特征
于是就有了这样一个接口

cv::Mat2d roi_pooling(vector<int> &rois,cv::Mat2d &imgs){
  //return 7*7*3的一块区域
}

但是我们是在特征图上做的,并且每次传一个batch的rois(B*5)的tensor,(batch_id,x1,y1,x2,y2)

这样我们便可以得到roi 区域的特征图

在这里插入图片描述

cv::Mat2d roi_pooling(vector<int> &rois,cv::Mat2d &imgs){
  //return 7*7*3的一块区域
  //为了简便,使用输入图像为灰度图(单通道图)
  float w=rois[1]-rois[0];
  float w_bin=w/7;
  float  h=rois[3]-rois[2];
  float h_bin=h/7;
  cv::Mat feature = cv::Mat::zeros(7,7,CV_8UC1);
  for(int i=0;i<7;i++){
    for(int j=0;j<7;j++){
      float startx=rois[0]+i*w_bin;
      float endx=rois[0]+(i+1)*w_bin;
      float starty=rois[2]+j*h_bin;
      float endy=rois[2]+(j+1)*h_bin;
      int max_value=0;
      for(int m=floor(startx);m<ceil(endx);m++){
        for(int n=floor(starty);n<ceil(endy);n++){
          feature[i][j]=max(feature[i][j],imgs[m][n]);
        }
      }
    }
  }
}

上述过程我们便完成了特征图roi pooling的基本实现,但是在实际过程中,我们处理会略有不同,主要体现在三点
1.特征不再是1-dim,而是C-dim,这样外层循环需要多套一层
2.使用CUDA加速,外面的三层循环,就是上述代码的7*7和1提到的C维度都分配给不同的CUDA线程执行
3.不再是对Mat操作,而是对裸数据,即数据操作,需要自己计算数据偏执

下面是对应的CUDA forward代码

extern "C"
__global__ void roi_pooling2d_forward_kernel(
    const ${Dtype}* bottom_data, const ${Dtype}* bottom_rois,
${Dtype}* top_data, ${Dtype_ind}* argmax_data) {
CUDA_KERNEL_LOOP(index, ${nthreads}) {
  // pos in output filter
  int pw = index % ${pooled_width};
  int ph = (index / ${pooled_width}) % ${pooled_height};
  int c = (index / ${pooled_width} / ${pooled_height}) % ${channels};
  int num = index / ${pooled_width} / ${pooled_height} / ${channels};
  int roi_batch_ind = bottom_rois[num * 5 + 0];
  int roi_start_w = round(bottom_rois[num * 5 + 1] * ${spatial_scale});
  int roi_start_h = round(bottom_rois[num * 5 + 2] * ${spatial_scale});
  int roi_end_w = round(bottom_rois[num * 5 + 3] * ${spatial_scale});
  int roi_end_h = round(bottom_rois[num * 5 + 4] * ${spatial_scale});
  // Force malformed ROIs to be 1x1
  int roi_width = max(roi_end_w - roi_start_w + 1, 1);
  int roi_height = max(roi_end_h - roi_start_h + 1, 1);
  float bin_size_h = static_cast<float>(roi_height)
      / static_cast<float>(${pooled_height});
  float bin_size_w = static_cast<float>(roi_width)
      / static_cast<float>(${pooled_width});
  int hstart = static_cast<int>(floor(static_cast<float>(ph)
                                          * bin_size_h));
  int wstart = static_cast<int>(floor(static_cast<float>(pw)
                                          * bin_size_w));
  int hend = static_cast<int>(ceil(static_cast<float>(ph + 1)
                                       * bin_size_h));
  int wend = static_cast<int>(ceil(static_cast<float>(pw + 1)
                                       * bin_size_w));
  // Add roi offsets and clip to input boundaries
  hstart = min(max(hstart + roi_start_h, 0), ${height});
  hend = min(max(hend + roi_start_h, 0), ${height});
  wstart = min(max(wstart + roi_start_w, 0), ${width});
  wend = min(max(wend + roi_start_w, 0), ${width});
  bool is_empty = (hend <= hstart) || (wend <= wstart);
  // Define an empty pooling region to be zero
  float maxval = is_empty ? 0 : -1E+37;
  // If nothing is pooled, argmax=-1 causes nothing to be backprop'd
  int maxidx = -1;
  int data_offset = (roi_batch_ind * ${channels} + c) * ${height} * ${width};
  for (int h = hstart; h < hend; ++h) {
    for (int w = wstart; w < wend; ++w) {
      int bottom_index = h * ${width} + w;
      if (bottom_data[data_offset + bottom_index] > maxval) {
        maxval = bottom_data[data_offset + bottom_index];
        maxidx = bottom_index;
      }
    }
  }
  top_data[index] = maxval;
  argmax_data[index] = maxidx;
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RoI Pooling是Faster R-CNN中提出的一种特征提取方法,用于从卷积层特征图中提取感兴趣区域(Region of Interest,简称RoI)的特征表示。RoI Pooling的主要目的是将不同大小的RoI映射为固定大小的特征图,从而方便后续的分类和回归任务。 RoI Pooling过程可以分为以下几个步骤: 1. 对于每个RoI,根据其在原始图像中的坐标信息,在特征图上对应的位置计算出RoI在特征图上的坐标信息。 2. 将RoI在特征图上的坐标信息分别向下取整和向上取整,得到RoI对应的四个顶点在特征图上的坐标信息。 3. 将RoI在特征图上的区域分割为固定大小的子区域,将每个子区域内的特征值进行最大池化操作,得到每个子区域的最大特征值。 4. 将每个子区域的最大特征值作为RoI的特征表示。 下面是RoI Pooling代码实现: ```python import torch.nn.functional as F class RoIPool(nn.Module): def __init__(self, output_size): super(RoIPool, self).__init__() self.output_size = output_size def forward(self, features, rois): batch_size, channels, height, width = features.size() num_rois = rois.size()[0] output = torch.zeros((num_rois, channels, self.output_size, self.output_size)) for i, roi in enumerate(rois): # 计算roi在feature map上的位置 x1, y1, x2, y2 = roi.detach().numpy() roi_width = max(x2 - x1 + 1, 1) roi_height = max(y2 - y1 + 1, 1) x_step = roi_width / self.output_size y_step = roi_height / self.output_size # 计算每个子区域的位置 for h in range(self.output_size): for w in range(self.output_size): x_start = int(x1 + w * x_step) y_start = int(y1 + h * y_step) x_end = int(x_start + x_step) y_end = int(y_start + y_step) x_start = min(max(x_start, 0), width - 1) x_end = min(max(x_end, 0), width - 1) y_start = min(max(y_start, 0), height - 1) y_end = min(max(y_end, 0), height - 1) # 对每个子区域进行最大池化操作 sub_feature = features[:, :, y_start:y_end+1, x_start:x_end+1] output[i, :, h, w] = F.max_pool2d(sub_feature, kernel_size=sub_feature.size()[2:]) return output ``` 该实现中,输入的features是特征图,rois是感兴趣区域的坐标信息。输出的是RoI Pooling后的特征表示。具体实现中,我们首先计算每个RoI在特征图上的位置,然后将每个RoI划分为固定大小的子区域,对每个子区域内的特征值进行最大池化操作,得到每个子区域的最大特征值作为RoI的特征表示。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值