图像resize的时候需要指定一个max_size和min_size,优先把原图的短边resize到min_size, 如果此时图片的长边超过了max_size则转而把原图的长边resize到max_size. 实际resize后的图像尺寸计算如下:
def get_size(self, image_size): # always rescale accorting to the short edge and size w, h = image_size size = self.min_size if self.scale_jittering: size = self.min_size_random_group[np.random.randint(self.group_size)] max_size = self.max_size if max_size is not None: min_original_size = float(min((w, h))) max_original_size = float(max((w, h))) if max_original_size / min_original_size * size > max_size: size = int(round(max_size * min_original_size / max_original_size)) if (w <= h and w == size) or (h <= w and h == size): return (h, w) if w < h: ow = size oh = int(size * h / w) else: oh = size ow = int(size * w / h) # print('size:', (oh, ow)) return (oh, ow)nms 非极大值抑制
将多个框体按照置信度排序选出置信度最大的框体,删除剩余框体与该框体IoU大于阈值的框体。(这一步确定了一个物体的框体,并删除了其他可能重复预测的框体)重复步骤ii,直至处理完所有框体soft nms
生成anchor 对于backbone输出的每一个特征图(Resnet 有5个),RPN输出一个 cls_logit(H/n,W/n,3) 和一个bbox_pred(H/n,W/n,3x4). 其中3代表3个不同长宽比的anchor(eg0.5,1,2),n代表对于原图的缩放倍数(分别为4,8,16,32,64)
生成proposals 对5种不同尺度的特征图,都执行以下操作
取出置信度前pre_nms_top_n的anchors;(eg pre_nms_top_n=2000)根据regression结果和anchor坐标,计算出proposals坐标执行一次NMS(第一次),并限制proposals最大个数为post_nms_top_n收集5个特征分支的proposals,选择置信度最高的fpn_post_nms_top_n个最后再把真实的gt-box加入到proposals中为所有anchor制作label
(前景标签为1) :与gt最大IoU超过high_threshold=0.7的anchor 与gt IoU最大的anchor(有可能最大的IoU没有超过阈值,通过该规则将其捡回来)满足以下条件的anchor设置为负标签0(背景标签为1):与gt最大IoU小于low_threshold=0.3的anchor其他与gt最大IoU介于阈值之间的(0.3,0.7)记为其他类,不算损失。再计算anchor与对应gt的回归目标正负样本均衡化(筛选)
batch_size_per_image:每张图片用于计算损失的anchor数目,eg 256positive_fraction:正样本所占比例, eg 0.5 正样本取num_pos=min(0.5*256, fg),即若生成的anchor中正样本数目超过128,则取128;若少于128,则保留所有正样本。负样本为num_neg =batch_size_per_image - num_pos计算损失 前后景预测的损失和前景回归损失
右图中的池化目标3x3 首先在每个cell内采样,此处采样系数为2,因此在池化范围内采样2*2=4个点。将cell划分成4部分,每一部分的中心点作为采样点(图中蓝色点) 每一个蓝色点的值通过双线性插值计算 取四个蓝色点中最大的值作为该cell的池化结果
box feature extractor
先对2000个proposal做筛选(这里2000是为了保证训练和测试一致,因为测试时并不知道gt)。计算proposals与gt的IoU,大于0.7的设置为前景,小于0.3的设置为背景。总共取512个proposals,正样本最多为0.25×512=128个,其余为负样本。使用ROI Align取出proposal对应的特征。ROI尺寸设置为7,features的channel=256,则取出来的特征维度为512 * 256 * 7 * 7,reshape成512×12544送入两个全连接层(12544,1024)、(1024,1024),得到特征512*1024box predictor
分支一,全连接层 (1024, num_calsses)预测类别分支二,全连接(1024, 8) 预测坐标变换系数计算512个proposals的交叉熵分类损失计算正样本回归损失mask feature extractor 如果和box feature 不公用特征的话
取出512个proposals中的前景proposals,假设有20个使用ROI Align取出proposal对应的特征。ROI尺寸设置为14,features的channel=256,则取出来的特征维度为20 * 256 * 14 * 14mask predictor
输入20×256×14×14的tensor经过一个转置卷积,输出20×256×28×28再经过一个1×1的卷积,输出20×num_class×28×28mask loss
根据前景proposals和gt的IoU,得到每个proposals对应的实例及其mask用proposals裁剪mask,并将maskresize到28×28,作为实际值用于计算loss取出mask predictor输出中对应gt类别的Channel,和上一步得到的mask_target计算交叉熵损失。在82层卷积处输出第一个检测结果。假设图片的输入大小为416×416,此时特征图的大小为13×13。每一个cell设置3个anchor,每一个anchor预测(4+1+C)个值,假设类别为60类,那么共计输出3×(4+1+60)=255个值,即输出维度为13×13×255。
第79层的卷积的输出结果继续进行卷积操作,上采样,和浅层特征融合,卷积,得到第二种尺寸的检测输出。输出维度为26×26×255 后面进行与第二步类似的操作,输出维度为52×52×255
在YOLOv3中,预设的anchor个数共有 ( 13 ∗ 13 + 26 ∗ 26 ∗ 52 ∗ 52 ) ∗ 3 = 10647 (1313+26265252)3=10647 (13∗13+26∗26∗52∗52)∗3=10647;YOLOv2中共有 13 ∗ 13 ∗ 5 = 845 1313*5=845 13∗13∗5=845。
每一种scale中预设的anchor是从数据集中聚类得到的9种中的三种。
使用不同尺度的特征图来预测,改善了YOLO对小物体的检测效果。
-predictor 主干网后紧跟两个prediction modules,其中一个检测top-left corners ,另一个检测bottom-right corners,最后对两组corner进行筛选,组合,修正得到object的一对corners,从而定位object的box。Embeddings
Heatmaps Heatmaps预测哪些点最有可能是Corners点
损失函数为 其中 y c i j y_{cij} ycij由高斯公式算出,距离真正的角点越近,值就越大 原focal loss为 可以看出这里(1- y c i j y_{cij} ycij)用来降低正真交点附近预测点的惩罚Embeddings Embeddings用于表征属于相同对象的corner的相似度。训练的时候拉近同一对象的角点的距离,拉开不同对象角点的距离
Offsets 这里直接回归在heatmap上预测出一个corner后,映射回image时坐标精度的损失
由于采用全卷积网络直接得到4倍下采样的热力图,所以不需要提前设定anchors, 所以大大减少了网络参数量和计算量。热力图的通道数等于要检测的目标类别数,热力图的前100个峰值作为网络提取的目标中心点,然后设定一个阈值进行筛选得到最终的目标中心点。 Centernet 中所有的上采样前都有deformable卷积,这种卷积的作用就是使得网络的感受野变得更加精确,而不是限定为3*3的矩形卷积框内。同时4倍的下采样feature map 比一般网络的分辨率高很多,所有不需要进行多尺度预测和特征金字塔也可以同时较好的检测大小目标。 Centernet 不需要NMS,因为所有检测的中心点是由热力图的峰值得到的,这样就已经有一个非极大值抑制的过程,而且NMS是十分耗时的,所以Centernet才能又好又快。 Centernet 采用编码解码的全卷积骨干网络,上采样用到的是转置卷积,与一般上采样中的双线性差值有很大区别,转置卷积可以更好的还原图像的语义信息和位置信息
训练的时候直接利用gt的中心点在特征图(和heatmap不同分支)上对应的特征点来预测长宽和精度损失 并且和类别无关(不用每一个类别都算一遍,只有计算中心点heatmap时和类别有关),减少了计算量 那么怎么在训练时把中心点和长宽特征图关联起来呢? 可以在制作groundtruth的时候,保存每一个实例的中心点在长宽特征图中的索引,所以有gt_wh:[batch, max_instance_num,2]和gt_index:[batch, max_instance_num,index], gt_mask:[batch,max_instance_num]
计算关键点时,假设每个实例有k个关键点,模型先计算特征图 2表示特征点对于实例中心点的偏移量。模型另外还专门计算关键点的heatmap 推理过程: 对于模型输出的中心点heatmap,先用maxpool 代替nms:
pad = (pool_size - 1) // 2 fmap_max = F.max_pool2d(fmap, pool_size, stride=1, padding=pad) keep = (fmap_max == fmap).float()然后对每张图取score最大的100个中心点。 推理关键点时,先用偏移量算出每个中心点对应的所有关键点,然后用它们去查找heatmap中score>0.1 并且在包围框内的真正关键点。