Backbone(res50+FPN)部分
C2-C5的bloc个数分别为3,4,6,3,C2-C5尺寸是否减半由它们的第一个block的第一个conv的stride(分别为1,2,2,2)决定,其他的所有的stride都为1,因此,C2尺寸保持不变,C3-C5减半

layer1-4对应resnet50 C2-C5

FPN的上采样通过线性插值实现

RPN部分
-
RPNHEAD的输出只有3个不同的ratio,scale是一样的,可能是因为FPN不同的特征层已经有不同的size
AnchorGenerator
以第一个feature map尺寸(208,200)为例,它相对(832,800)stirde是4,基本的先验框为[0,0,3,3],变换3种ratio,1种scale,得到3个base_anchors,shape = (3, 4),中心点保持不变。
-
计算base_anchors的 [x1,y1,x2,y2] 偏移量的组合。由于anchor的x1和x2偏移量肯定相同,y同理,便化简为了 [x,y] 偏移量的组合。
从0开始以stride为步长取200个值,即[0, 4, ..., 796],
从0开始以stride为步长取208个值,即[0, 4, ..., 828],共有200*208种偏移量组合如下图所示,最后得到的shape=(41600, 4)
base_anchors+偏移,即shape(1,3,4) + shape(41600, 1, 4),得到shape(41600, 3, 4),然后reshape为(124800, 4),此时得到了所有先验框的坐标
RPN postprocessor
- 把RPNHead的objectness的输出通过sigmoid归一化到 0-1,按概率大小选出前2000(pre_nms_top_n)个先验框(x1, y1, x2, y2)和RPNHead的regression映射(对应FasterRcnn公式2中的
)。然后把先验框转化为 中心点+宽高 的格式,和regression映射利用FasterRcnn公式2得到建议框proposals(x,y,w,h),再转化为(x1, y1, x2, y2)的格式
- 2000个proposals经过分割,防止建议框超过图像边缘,再对宽高进行限制,防止建议框过小,然后经过nms(0.7)筛选,筛选后的个数最大是2000(post_nms_top_n)个,那么我筛选后可能得到了1061个建议框
- 注意1061得到的是一个特征图的建议框个数,我们会把5个特征图的建议框合并起来,假设是4146个,也就是一张img总共的建议框个数。再根据objectness选出前1000(fpn_post_nms_top_n)个建议框
RPNLossComputation
- 为了便于描述,去掉了batch维度。把AnchorGenerator输出的5个特征层的所有anchor进行合并,得到(166257,4)个anchor,假设输入的img的label有14个gt_boxes,它们之间计算iou,会得到(14,166257)个iou结果
- 经过class Matcher,得到shape=(16657)的张量matched_idxs,取值可以为-1(表示负样本),-2(无关样本),以及
(表示这个anchor是第x个gt_boxes的正样本)
- 通过
matched_targets = target[matched_idxs.clamp(min=0)]得到所有anchor对应的gt_boxes,将负样本和无关样本的anchor对应到第一个gt_boxes,matched_targets的shape为(166257,4) - 第一步的(166257,4)个anchor box和matched_targets的(166257,4)个groundtruth box经过FasterRcnn公式2得到regression_targets
- 通过matched_idxs可以得到shape相同的labels张量,取值可以为1(正样本),0(负样本), -1(无关样本和尺寸超过img边缘的anchor)
- 在labels张量中随机选取256个anchor的正负样本(ratio=1:1)随后参与训练,得到这些样本的index
- 在regression_targets和RPNHead输出的box_regression中选出256个训练样本中的正样本计算smooth_L1_loss,返回box_loss
- 在labels和objectness中选出256个训练样本计算二分类的交叉熵损失,返回objectness_loss
Matcher
- anchor和所有gt_boxes的最大 iou<0.3时,anchor为负样本
- anchor和所有gt_boxes的最大 iou>=0.3 & iou<0.7时,anchor为无关样本
- 剩下的则为正样本,此为正样本选取规则(2)。但这时不能保证所有的gt_boxes都有匹配的正样本anchor,比如某个gt_boxes和所有anchor的 iou 都小于0.3。此时就需要正样本选取规则(1),对于每个gt_boxes,把和它iou最大的anchor(可能有多个)置为正样本,即使它的iou<0.3
CombinedROIHeads部分

ROIBoxHead
- 输入:1000 +14(fpn_post_nms_top_n + targets)个建议框和img的targets
- 假设输入的img的label有14个gt_boxes,它们之间计算iou,会得到(14,1014)个iou结果
- 经过class Matcher,得到shape=(1014)的张量matched_idxs,取值可以为-1(表示负样本),-2(无关样本),以及
(表示这个proposal是第x个gt_boxes的正样本)
注意:
这里的Macher和RPN的不同,low_threshold和high_threshold都为0.5,并且没有用正样本选取规则(1)
- 通过
matched_targets = target[matched_idxs.clamp(min=0)]得到所有proposal对应的gt_boxes,将负样本和无关样本的proposal对应到第一个gt_boxes,matched_targets的shape为(1014,4) - 第一步的(1014,4)个proposal和matched_targets的(1014,4)个groundtruth box经过FasterRcnn公式2得到 regression_targets
- 通过matched_idxs可以得到shape相同的labels张量,取值可以为0(负样本), -1(无关样本) 以及
(n表示正样本proposal对应的类别,比如coco有81类)
注意:
RPN是二分类,所以 label 张量的正样本是 1,这里是roihead的多分类,所以 label 张量的正样本是 [1,n]
在labels张量中随机选取512个正负样本(ratio=1:3)随后参与训练,得到这些样本的index
根据index从proposals, labels, regression_targets中选出512个对应的值
-
选出的512个proposals和FPN输出的5个特征层(channel都为256)共同送入Pooler类。Pooler类先对proposals进行特征层的映射(通过
POOLER_SCALES参数来确定只考虑哪些level),即每个proposal对应于哪一个特征层;然后把每一个level的特征层和相应的proposal (即roi)送入ROIAlign类,最后得到输出为 (512,256,7,7) 的张量- POI Pooling过程需要两次取整操作
a. 每个ROI的长、宽除以步长,会得到ROI映射到特征图上的尺寸大小。假设原图上的一个ROI大小为 452*452,且映射到了P3特征层,那么它的步长为8,spatial scale=1/8,则在特征图上的感兴趣区域则为 56.5 * 56.5。但是这并不是一个真实的pixel所在的位置,因此这一步会取整为56,0.5的差距反馈到原图就是0.5x8=4个像素的差距。如果是大目标这4的差距可能看不出来,但对于小目标而言差距就比较巨大了。
b. 假设有一个bbox映射到特征图上的坐标为[0,3,7,8],希望得到2x2(7x7不好可视化)的输出,这个bbox的w=7,h=5,如果要等分成四块是做不到的,因此在ROI Pooling中会进行取整。就有了下图看到的h被分割为2,3,w被分割成3,4。这样之后在每一块(称为bin)中做max pooling
-
ROI Align
a. 将bbox区域按输出要求的size进行等分,很可能等分后各顶点落不到真实的像素点上
b. 然后把每个bin中平分四份,每一份取其中心点位置,而中心点位置的像素,采用双线性插值法(距离它最近的4个真实像素点的值加权)进行计算,这样,就会得到四个点的像素值,也就是图二右侧的蓝色点
c. 一个bin内会算出4个新值,在这些新值中取max,作为这个bin的输出值
最后就能得到2x2的输出
- POI Pooling过程需要两次取整操作
(512,256,7,7) 的张量经过两层的MLP,得到一个(512,1024)的向量,再分别经过一个全连接层, 得到 class_logits(512,81) 和 box_regression (512,324)
class_logits 和 labels的512个正负样本计算cross_entropy损失,返回 loss_classifier
在box_regression 和 512个regression_targets 中选出其中的正样本计算smooth_L1_loss,返回 loss_box_reg



