“Faster-RCNN + Attention”提高相似小物体识别准确率
前言
1、最近在做一个物体识别的项目,使用的是基础的Faster-RCNN网络架构,但是该架构在识别相似物体的时候性能有所欠佳,网络的定位还是比较准确的,关键是分类出错,一方面可能是需要识别的物体较小,经过多层网络特征提取之后特征表示欠佳,另一方面物体特征有重合;
2、正好看了Attention注意力机制的一些知识,包括递归注意力机制,原文里面用了两次递归,试验了一下我们的项目效果不是很好,关键是我们的项目里面物体识别背景太复杂,分类具有一定的逻辑性;当然还有一些多注意力机制等等;
3、这里主要介绍将Attention注意力机制与Faster-rcnn相结合的一种思想,综合两者的优点,实现物体的精确定位和准确分类;
一、Faster-RCNN + Attention注意力机制?
1、Faster-RCNN网络有很多介绍,主要的工作步骤分成:图片特征提取、RPN物体候选款生成(相当于物体特征筛选)、物体特征匹配以及候选框回归几步;
2、Attention注意力机制:首先获取用于分类的物体特征,然后找到该分类特征在原始图片上的映射,将用于分类的物体特征放大,进行递归;原始论文中使用了交叉熵损失+Rank loss,大家感兴趣的可以参考链接:递归注意力网络:https://openaccess.thecvf.com/content_cvpr_2017/papers/Fu_Look_Closer_to_CVPR_2017_paper.pdf 以及多注意力网络:Multi-Attention Multi-Class Constraint for Fine-grained Image Recognition
3、Faster-RCNN + Attention注意力机制:前者由于是监督学习,所以在物体定位方面有很好的的表现,且候选框网络收敛速度很快,在这里将RPN候选框得到的候选框以及最后的候选框回归值计算出正确的候选框位置,从而得到原始图片中的分类物体,使用插值的方法放大该物体,在进行特征提取、特征匹配、物体分类;
二、网络修改步骤
1. RPN输出+候选框回归==>>物体预测框
参考原始网络中的bbox_transform_inv()函数和clip_boxes()函数
boxes = rois[:, 1:5] ##### shape[batch,4] batch为RIO候选框的个数
box_deltas = self.prediction["bbox_pred"] ###### shape:[batch,4*num_cls]
pred_boxes = bbox_transform_inv(boxes, box_deltas)
pred_boxes = clip_boxes(pred_boxes, im.shape)
def bbox_transform_inv(boxes, deltas): if boxes.shape[0] == 0: return np.zeros((0, deltas.shape[1]), dtype=deltas.dtype) boxes = boxes.astype(deltas.dtype, copy=False) widths = boxes[:, 2] - boxes[:, 0] + 1.0 heights = boxes[:, 3] - boxes[:, 1] + 1.0 ctr_x = boxes[:, 0] + 0.5 * widths ctr_y = boxes[:, 1] + 0.5 * heights dx = deltas[:, 0::4] dy = deltas[:, 1::4] dw = deltas[:, 2::4] dh = deltas[:, 3::4] pred_ctr_x = dx * widths[:, np.newaxis] + ctr_x[:, np.newaxis] pred_ctr_y = dy * heights[:, np.newaxis] + ctr_y[:, np.newaxis] pred_w = np.exp(dw) * widths[:, np.newaxis] pred_h = np.exp(dh) * heights[:, np.newaxis] pred_boxes = np.zeros(deltas.shape, dtype=deltas.dtype) # x1 pred_boxes[:, 0::4] = pred_ctr_x - 0.5 * pred_w # y1 pred_boxes[:, 1::4] = pred_ctr_y - 0.5 * pred_h # x2 pred_boxes[:, 2::4] = pred_ctr_x + 0.5 * pred_w # y2 pred_boxes[:, 3::4] = pred_ctr_y + 0.5 * pred_h return pred_boxes
def clip_boxes(boxes, im_shape): """ Clip boxes to image boundaries. """ # x1 >= 0 boxes[:, 0::4] = np.maximum(np.minimum(boxes[:, 0::4], im_shape[1] - 1), 0) # y1 >= 0 boxes[:, 1::4] = np.maximum(np.minimum(boxes[:, 1::4], im_shape[0] - 1), 0) # x2 < im_shape[1] boxes[:, 2::4] = np.maximum(np.minimum(boxes[:, 2::4], im_shape[1] - 1), 0) # y2 < im_shape[0] boxes[:, 3::4] = np.maximum(np.minimum(boxes[:, 3::4], im_shape[0] - 1), 0) return boxes
2. 输出候选框ID如何与最终输出候选框的ID统一
原始faster-rcnn中测试模式roi候选框个数为300个,但是pred_bbox个数为300*num_cls,相当于每个候选框对应的num_cls个候选款回归,最后在测试的时候针对每一类物体采用nms筛选出可靠的候选框;
网络修改:这里面针对这种情况,每个RPN输出候选框只针对物体概率最大的物体进行回归,即pred_bbox只输出300个
cls_prob = self.predtion["cls_prob"]
box_deltas = self.prediction["bbox_pred"]
bbox_out = np.zeros((boxes.shape[0],6))
for i in range(boxes.shape[0]):
cls = np.argmax(cls_prob[i,1::]) + 1 ###### 排除背景
bbox_out[i,0:4] = box_deltas[i,4*cls:4*(cls+1)]
bbox_out[i,4] = cls ######### 物体类别
bbox_out[i,5] = cls_prob[i,cls] #########得分
这样在测试的时候输出的就是300个已经回归之后的候选框,然后在做后处理。
3. 利用回归之后的候选框得到裁剪图片
这里主要借助了tf.image.crop_and_resize函数
def crop_and_resize( |
这里面需要主要的是:用于训练或测试的图片是经过resize之后的,在blob["im_info"]中有一个im_scale的参数是图片resize的大小,使用crop_and_resize函数的时候,需要将图片的输入尺寸归一化到[0,1],即输入bixex是:[y0,x0,y1,x1],这里面需要将h=h / im_scale,w = w / im_scale
4、输出结果
这里面就不贴我的检测结果了,引用一下Attention里面的经典附图吧:图片引用自 递归网络原文https://openaccess.thecvf.com/content_cvpr_2017/papers/Fu_Look_Closer_to_CVPR_2017_paper.pdf
总结
总的来说这个方法算法对网络修改的初步尝试吧,也走了很多弯路,希望对大家有所帮助,另外为了快速收敛,后面新建的物体分类网络中的特征提取采用了原始网络中的共享参数,在使用tensorflow.contrib.slim进行网络参数共享的时候会出现一些问题,需要将源码中的参数共享方式修改为tf.Auto_reuse,以上就是本次分享的所有内容啦,欢迎大家留言,共同探讨!