PointRend模块的提出是为了解决Mask预测时候对于原图或feature map上的像素的过采样和欠采样问题。这个问题的核心在于,由于2d图像本身是以栅格化的形式保存图像,那么网络在预测Mask的时候,不可避免地会将所有像素都有同等地位地进行预测,而实际上我们更希望的是网络集中预测在物体边缘部分的地方,而物体内部则不需要过多地预测,那么前者就是欠采样,后者则是过采样。
PointRend方法的思路借鉴于计算机图形学中理论,将图像分割任务当做是一个渲染问题,并提出了PointRend神经网络模块。该模块能够通过迭代细分算法,自适应选取位置进行基于点分割预测。这一模块可以应用在已有的实例分割和语义分割的模型上,从而增强预测Mask的精细度和降低,并能让分割输出更高的分辨率。
计算机图形学中渲染是讲一个三维的模型显示到一个二维的均匀网格的像素图上。虽然输出是均匀网格的数据,但是其背后的物理模型是连续表示的,通过一定的方法,可以计算出这个物体上的各种物理遮挡、属性表现出来的颜色、性状等。
将一个图像的分割任务的真实分割Mask,当做是某个连续模型(即渲染中的实际三维模型)的遮挡图(在这里是假设也是连续的),而输出的Mask则是渲染的以二维均匀网格表示的图形。上述的连续模型就是网络中输出的feature map,而feature map的连续性可以通过插值的方式(文中使用二次线性插值)近似的到各个位置的值来近似。在这里则使用一个小型的参数化函数进行得到的feature map上(插值后得到的)逐像素的计算预测值,相当于渲染中对每个像素点值的物理或几何计算方法(如光线追踪).总体上,Mask在整个过程中如同渲染一样,从粗糙到精细的一个过程。
根据上面思路,PointRend模块组成:
接下来将会详细叙述上面三个主要组成部分的工作方法。
PointRend的核心在于如何选取点,处于物体边缘的点,高频域的点需要重点关注。
预测过程中的选取点:在输出达到目标分辨率前,重复以下循环:
训练过程中的选取点:如果按照预测过程中的方式为训练point head选取点,其会导致引入了迭代环节,从而影响BP算法的实现,所以训练时选取的是非迭代方式的随机采样选取点。这一随机取样遵循:偏向选取不确定的部分,同时在较为确定的部分有一定采样。假设需要选取 N N N个点给point head进行训练。具体步骤为:
选取点后,通过双线性插值方式从featrue map得到feature vector,其中feature map可以是单张,也可以是多张,或FPN对应的位置,然后concatenate一起。
但是,这样操作存在两个问题:
基于上述的考虑,可以从网络中加入粗糙的分割预测,如果通道传递的是不同类别的语义信息,那么粗糙分割预测则提供了全局性的上下信息。这样的粗糙的分割预测可以由如轻量化的Mask RCNN网络得到。
在Facebook的detectron2实现中,这一过程在detectron2/projects/PointRend/point_rend/point_featrues.py的point-sample函数中实现,使用的的是(除开加入粗糙的分割预测部分id_sample(input, grid, mode=‘bilinear’, padding_mode=‘zeros’, align_corners=None)函数,源码如下所示:
def point_sample(input, point_coords, **kwargs):"""A wrapper around :function:id_sample` to support 3D point_coords tensors.Unlike :function:id_sample` it assumes `point_coords` to lie inside[0, 1] x [0, 1] square.Args:input (Tensor): A tensor of shape (N, C, H, W) that contains features map on a H x W grid.point_coords (Tensor): A tensor of shape (N, P, 2) or (N, Hgrid, Wgrid, 2) that contains[0, 1] x [0, 1] normalized point coordinates.Returns:output (Tensor): A tensor of shape (N, C, P) or (N, C, Hgrid, Wgrid) that containsfeatures for points in `point_coords`. The features are obtained via bilinearinterplation from `input` the same way as :function:id_sample`."""add_dim = Falseif point_coords.dim() == 3:add_dim = Truepoint_coords = point_coords.unsqueeze(2)output = F.grid_sample(input, 2.0 * point_coords - 1.0, **kwargs)#hereif add_dim:output = output.squeeze(3)return output
在pytorch文档中id_sample(input, grid, mode=‘bilinear’, padding_mode=‘zeros’, align_corners=None)的作用是根据给定的input的值,使用grid中提供的位置计算output。具体而言到4D的数据,有
输入
对于每一个输出位置 o u t p u t [ n , : , h , w ] output[n,:,h,w] output[n,:,h,w]由输入的二维向量 g r i d [ n , h , w ] grid[n,h,w] grid[n,h,w]决定 i n p u t input input的位于 ( x , y ) (x,y) (x,y)的像素,这个像素将会使用某种插值方式得到输出 o u t p u t [ n , : , h , w ] output[n,:,h,w] output[n,:,h,w],而插值方式取决于函数参数中的mode选项,默认为双线性插值方式。
值得注意的是, g r i d grid grid中的需要采样像素的位置表示方式是使用 i n p u t input input中空间维度的归一化后得到的值,也就是说它 x , y x,y x,y的范围为 [ − 1 , 1 ] [-1,1] [−1,1],例如如果 x = − 1 , y = − 1 x=-1,y=-1 x=−1,y=−1,那么这个采样点应该是 i n p u t input input的最左上角的像素。假如超出了范围 [ − 1 , 1 ] [-1,1] [−1,1]的话,由函数参数padding_mode决定其值。
但pytorch没有说明是怎么计算的方法,其实,这一操作是来自论文Spatial Transformer Networks(.02025, Max Jaderberg. from Google)。接下来叙说是如何进行计算的。
Spatial Transformer Networks提出了一种让各种神经网络结构得到处理空间变换的的能力的方法,而这种变换是可以根据每个样本设计,而且不需要增添任何标记,能够动态地将图片或feature map变换,让有了这一空间变换模块的网络不仅能从图片中选取最相关区域,而且能将这些区域变换为能让后继网络更简单处理的输出。效果如下图所示:
spatial transformer是一个可微的模块,用于在前馈时给feature map作空间变换,而变换是根据特定输入而定的。输入可以是单张或多张map,而输出为单张map。spatial transfomer可分为三部分,根据计算顺序分别为:
可以其中变换写作矩阵形式(具体查看论文),或者是下式
V i c = ∑ n H ∑ m W U n m c k ( x i s − m ; Φ x ) k ( y i s − n ; Φ y ) ∀ i ∈ [ 1 … H ′ W ′ ] ∀ c ∈ [ 1 … C ] V_{i}^{c}=sum_{n}^{H} sum_{m}^{W} U_{n m}^{c} kleft(x_{i}^{s}-m ; Phi_{x}right) kleft(y_{i}^{s}-n ; Phi_{y}right) forall i inleft[1 ldots H^{prime} W^{prime}right] forall c in[1 ldots C] Vic=n∑Hm∑WUnmck(xis−m;Φx)k(yis−n;Φy)∀i∈[1…H′W′]∀c∈[1…C]
其中 Φ x Phi_{x} Φx和 Φ y Phi_{y} Φy为generic sampling kernel k ( . ) k(.) k(.)的参数,这个 k ( . ) k(.) k(.)定义了图形插值方式(如双线性插值方法), U n m c U_{n m}^{c} Unmc为输入通道c位置 ( n , m ) (n,m) (n,m)的值, V i c V_{i}^{c} Vic为输出通道c上序列号i的像素值。下面的图可以比较直观地看出变换进行的操作,说明看原文的图注。
回到PointRend中,可以看出,Spatial Transformer的第一步已经被自适应取点取代,而后续中步骤则由pytorch中的id_sample所计算,而grid_sample中的参数mode则决定了Spatial Transformer第三步中generic sampling kernel,在PointRend中也就是双线性插值。最终产生了根据PointRend中自适应选点后变换的feature map。
得到了Point-wise表示的特征后,将其输入到简单的MLP(Multi-layer Perceptron)中进行label预测。MLP的权重是各个点都共享的。在本文实现中使用的是和R-CNN相似的两层1024宽的隐藏层,预测每一类的输出。
如果有理解错误,请多多包涵。
本文发布于:2024-02-04 14:52:11,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170709756956536.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |