以精度提升为目的
让每一类的特征更加明显,例如都是车,但可以细分为:越野车,城市越野车,跑车,卡车,拖挂车等;
该方法是为了扩大数据的多样性。常规包括以下几种方式:
Fixing the train-test resolution discrepancy,,具体的训练方式请参考https://blog.csdn.net/u013066730/article/details/112369794(比赛时专用)
在做一些分类问题或者检索问题上可能会有提升,具体参考论文[13]
针对的问题是当图片中两个相同类别的物体离得比较近的时候,一般的NMS可能会出现错误抑制的情况,这是因为NMS直接将与最大score的box的IoU有大于某个阈值的其他同类别的box的score直接置为0导致的,这就有点hard了。所以soft NMS就是说不直接将这些满足条件的box直接设置为0而是降低score值,这样循环操作。
有两种形式,线性加权和高斯加权
对于大量正样本负样本比较少的时候,如何挑选对model来说更具有信息性的负样本显得尤为重要。对于batch=M的训练数据,我们从中挑选出loss比较大的样本反向传播。在Faster RCNN中计算RoIs的时候,我们对每个RoI的loss从大到小排序,选择前N个RoIs样本反向传播。
(这里会有一个问题,即位置相近的ROI在map中可能对应的是同一个位置,loss值是相近的,所以如果直接按照loss对roi进行排序的话,选出来的很可能是靠的很近的一些rois,所以针对这个问题,提出的解决方法是:对hard做nms,然后再选择B/N个ROI反向传播,这里nms选择的IoU=0.7。)
OHEM流程图[4]
[4]中指出是有两种方法,一种是将选出的部分样本再输入红色网络(进行forward和backward)学习并进行梯度传播。而另一种方法是在反向传播时,只对选出的样本的梯度/残差回传,而其他的props的梯度/残差设为0。但这样做容易导致显存显著增加,迭代时间增加。
传统的卷积操作无法适应复杂的几何形变,因为卷积操作的的几何结构是固定的,是一种规则格点的采样方式,而可形变卷积就是在普通卷积上加一个偏移量。类似的还有Deformable ROI Pooling等。
可形变卷积的流程如下:
(1)在原始图像(b,h,w,c)上经过一个普通卷积得到(b,h,w,2c)的输出,这里的2c代表的是x,y两个方向上的偏移量。
(2)将原始图像上的像素索引值与偏移量相加,得到偏移之后的像素索引(限定在图像内部),此时的position是一个float型的坐标值。
(3)使用双线性插值将float坐标值映射得到像素值,在新得到的图像上应用一个普通的卷积。
(b,h,w,c) - > (b,h,w,2c) - > position(b*c,h,w, 2)+ origin image(b*c,h,w)
-> (b*c,h,w) -> (b,h,w,c)
训练时,预先定义几个固定的尺度,每个epoch随机选择一个尺度进行训练。测试时,生成几个不同尺度的feature map,对每个Region Proposal,在不同的feature map上也有不同的尺度,我们选择最接近某一固定尺寸(即检测头部的输入尺寸)的Region Proposal作为后续的输入。选择单一尺度的方式被Maxout(element-wise max,逐元素取最大【cascade rcnn中就是】)取代:随机选两个相邻尺度,经过Pooling后使用Maxout进行合并。[5]
这一技巧在ResNet的工作中提出,做法是把整张图片作为一个RoI,对其进行RoI Pooling并将得到的feature vector拼接于每个RoI的feature vector上,作为一种辅助信息传入之后的R-CNN子网络。目前,也有把相邻尺度上的RoI【cascede rcnn 中的fpn】互相作为context共同传入的做法。
不同的训练策略,不同的 epoch 预测的结果,使用 NMS 来融合,或者softnms
需要调整的参数: box voting 的阈值。不同的输入中这个框至少出现了几次来允许它输出,得分的阈值,一个目标框的得分低于这个阈值的时候,就删掉这个目标框。
Box Voting[9]想法是根据NMS被抑制掉重合度较高的box进一步refine NMS之后的边框。主要做法步骤是:
目标检测中的实现可以参考gluoncv[7]中的实现。
mix_image 就是两张图片直接相加。
img1, label1 = self._dataset[idx]
lambd = 1
# draw a random lambda ratio from distribution
if self._mixup is not None:
lambd = max(0, min(1, self._mixup(*self._mixup_args)))
if lambd >= 1:
weights1 = np.ones((label1.shape[0], 1))
label1 = np.hstack((label1, weights1))
return img1, label1
# second image
idx2 = np.random.choice(np.delete(np.arange(len(self)), idx))
img2, label2 = self._dataset[idx2]
# mixup two images
height = max(img1.shape[0], img2.shape[0])
width = max(img1.shape[1], img2.shape[1])
mix_img = mx.nd.zeros(shape=(height, width, 3), dtype='float32')
mix_img[:img1.shape[0], :img1.shape[1], :] = img1.astype('float32') * lambd
mix_img[:img2.shape[0], :img2.shape[1], :] += img2.astype('float32') * (1. - lambd)
mix_img = mix_img.astype('uint8')
y1 = np.hstack((label1, np.full((label1.shape[0], 1), lambd)))
y2 = np.hstack((label2, np.full((label2.shape[0], 1), 1. - lambd)))
mix_label = np.vstack((y1, y2))
return mix_img, mix_label
cascade-rcnn主要针对的问题是:训练阶段和测试阶段,bounding box回归器的输入分布是不一样的。training阶段的输入proposals质量更高(被采样过,IoU>threshold),inference阶段的输入proposals质量相对较差(没有被采样过,因为不知道gt),这就是论文中提到mismatch问题,这个问题是固有存在的,通常threshold取0.5时,mismatch问题还不会很严重。
而为了提高bounding box回归器输入的proposals的质量而一味的提高IoU的阈值会导致过拟合问题和更严重的mismatch问题。因此作者提出了cascade-rcnn结构。
如上图所示,和Iterative BBox比较,Iterative BBox的H位置都是共享的,而且3个分支的IoU阈值都取0.5。而Integral Loss共用pooling,只有一个stage,但有3个不共享的H,每个H处都对应不同的IoU阈值。
Cascade R-CNN使用cascade回归作为一种重采样的机制,逐stage提高proposal的IoU值,从而使得前一个stage重新采样过的proposals能够适应下一个有更高阈值的stage。
可以从三个点来看GN比BN“好用”的原因[11]:
而GN在速度上,通常比BN要慢,这是因为GN相对于BN来说,有额外的transpose与reshape操作,当层数加深的时候,训练速度也按比例下降。
福音是pytorch days ago已经可以通过简单的接口实现GN了
def get_gn(num_channels):
return nn.GroupNorm(32, num_channels) # Separate num_channels into 32 groups
model = models.ResNet(models.Bottleneck, [3, 4, 6, 3], norm_layer=get_gn)
主要是针对待检测物体尺度的问题做的改进,如图[12]所示,每个level的feature P2,P3,P4,P5,P6只对应一种scale,比例还是3个比例。分别在这些level的feature上进行roi的计算。
针对X光图像像素值普遍偏高,大都在200以上,所以除了减均值归一化之外,看到有的同学会做像素值的映射变换操作,目的是为了降低像素值,从而让像素值可以基本上均匀的散布在[0, 255]之间,用的映射函数类似于一个二次函数。
协方差池化的迭代矩阵平方根标准化[14]、[15]
文中提出了用一个二阶甚至高阶的统计方法来替换一阶的全局平均池化,即将一阶的均值替换为二阶的协方差,幂值取经验值0.5,其优点在于能够利用深度网络学习后的各通道之间的相关信息。之前求协方差平方根的方法是将协方差进行本征分解得到本征值,然后求本征值的平方根。但是基于 GPU 的平台对本征分解的支持都非常差,所以本文在求协方差的平方根时,不再使用本征分解,而是使用迭代法,称为 iSQRT-COV。而这种迭代法非常适合大规模的 GPU 实现,提高了计算效率。
中间的meta-layer包含三个层,分别进行预正则化,牛顿-舒尔茨迭代和后补偿处理。第一层(pre-normalization)将协方差矩阵除以它的迹以保证下一个阶段的牛顿-舒尔茨迭代的可收敛性;第二层则是一个循环结构,进行一定次数的耦合矩阵方程迭代以计算合适的矩阵平方根;第三层乘以协方差矩阵迹的平方根来抵消第一层改变数据的量级的影响。meta-layer的输出是一个对称矩阵,然后将这个矩阵的上三角区concate成一个d(d+1)/2 维的向量,再接到后面的ConvNet中进行处理。
文章地址https://arxiv.org/abs/1910.13302, 对应的github代码https://github.com/ZFTurbo/Weighted-Boxes-Fusion
https://zhuanlan.zhihu.com/p/141254917
https://zhuanlan.zhihu.com/p/50621694