简介
Region Propsal Network由任少卿等人提出,通过深度卷积网络从特征图上生产候选区域(Proposals),极大地提升了执行速度,并实现了端到端的训练。RPN也是Faster R-CNN的第一阶段框架,虽然距提出已有6年的时间,但是其中的基本机理对今天的目标检测任务仍有很大的启发意义,也适合新手作为入门的第一个项目。其后的Cascade R-CNN、Libra R-CNN等算法也对RPN中存在的问题进行了改进。
我虽然接触目标检测已有3年,但对Faster R-CNN的理解不过全面。趁着空闲时间,将代码过一遍,增强自己的理解。代码大部分来自B站博主WZMIAOMIAO。博主的水平很高,请大家多关注。我对他的代码进行了轻微的改进,配合自己对RPN的理解,在此记录,以备后用。
上图是我自己画的RPN训练流程图。写这篇博客的时候还没有阅读FR中RPN之后的代码。流程中对Proposals进行NMS的流程可能有一些问题。后续发现问题会对文章进行改进。
按照流程图的计算流程,将图像输入骨干网络。图像需先经过预处理。处理主要对图像的尺寸进行调整。将不同尺寸的图像限定到统一尺寸进行批量处理,而统一尺寸需要考虑两个问题:1)图像的长宽限定到多大尺寸;2)不同比例的图像如何进行统一。
def _resize_image(image, self_min_size, self_max_size):
# type: (Tensor, float, float) -> Tensor
im_shape = torch.tensor(image.shape[-2:])
min_size = float(torch.min(im_shape)) # 获取高宽中的最小值
max_size = float(torch.max(im_shape)) # 获取高宽中的最大值
scale_factor = self_min_size / min_size # 根据指定最小边长和图片最小边长计算缩放比例
# 如果使用该缩放比例计算的图片最大边长大于指定的最大边长
if max_size * scale_factor > self_max_size:
scale_factor = self_max_size / max_size # 将缩放比例设为指定最大边长和图片最大边长之比
# interpolate利用插值的方法缩放图片
# image[None]操作是在最前面添加batch维度[C, H, W] -> [1, C, H, W]
# bilinear只支持4D Tensor
image = torch.nn.functional.interpolate(
image[None], scale_factor=scale_factor, mode="bilinear", recompute_scale_factor=True,
align_corners=False)[0]
return image
提前设定图像边长的最大最小值为(600, 400)。计算图像最短边与设定最短边的比。求得的比与图像长边相乘。若超出设定的图像最长边,则求图像长边与最大长边的比。之后按比例插值得到缩放图像。Ground Truth照此处理。
经过缩放后,能够保证图像内容大致在同一区间,但具体数字还存在差异。之后统计同一批次图像的最大边,将缩放后的图像填充至同一尺寸,进行后续处理。需要注意的是,如果最大边长不能被下采样倍数整出,需要将边长放大至下采样的整数倍。
# 分别计算一个batch中所有图片中的最大channel, height, width
max_size = self.max_by_axis([list(img.shape) for img in images])
stride = float(size_divisible)
# max_size = list(max_size)
# 将height向上调整到stride的整数倍
max_size[1] = int(math.ceil(float(max_size[1]) / stride) * stride)
# 将width向上调整到stride的整数倍
max_size[2] = int(math.ceil(float(max_size[2]) / stride) * stride)
# [batch, channel, height, width]
batch_shape = [len(images)] + max_size
# 创建shape为batch_shape且值全部为0的tensor
batched_imgs = images[0].new_full(batch_shape, 0)
for img, pad_img in zip(images, batched_imgs):
# 将输入images中的每张图片复制到新的batched_imgs的每张图片中,对齐左上角,保证bboxes的坐标不变
# 这样保证输入到网络中一个batch的每张图片的shape相同
# copy_: Copies the elements from src into self tensor and returns self
pad_img[: img.shape[0], : img.shape[1], : img.shape[2]].copy_(img)
return batched_imgs
例如输入图像尺寸为375×500。约定的最大最小边为(600, 400)。图像最短边与约定最小边的比值为400/375=1.06。再使用1.06乘以图像的另一条边的长度500,得到放缩后的最大边长533。同时533没有超出约定最大边长600。最终插值得到的图像尺寸为(400, 533)。之后将图像填充至最大下采样倍数的整数倍。骨干网络下采样倍数为32倍,则应将图像填充至 ⌈ l e n g t h / 32 ⌉ × 32 \lceil length/32 \rceil ×32 ⌈length/32⌉×32,填充后的图像尺寸为(416, 544)。