LSnet:Location-Sensitive Visual Recognition with Cross-IOU Loss 主要源码解读 1


写在前面
照例。每次写博文的时候来个介绍。LSnet是目标检测中基于anchor-free的检测方法。单单读论文并不能领悟其中一些特定的代码设计之巧妙。遂写下这篇博文以记之~
论文链接: Location-Sensitive Visual Recognition with Cross-IOU Loss
代码链接: Github

一、框架搭建

主体代码采用mmdection开源目标检测模型实现。
这里不去细讲,建议掌握一些开源模型的使用方法以备后用。(例如,dectron2这种)。
同样,CSDN上面也有很多博主关于mmdection的解读,建议了解一下,在很大程度上会减少阅读障碍。

其中最需要注意的地方,全框架通篇采用了Registry注册器,也就是一种装饰器,效果类似于全局变量,全局调用,这个Registry源于registry类,不只是在mmdection中,其他类似的框架中也用到了这种全局调用的方法,主要作用就是方便各种模块的搭建。
模块主体示意图:

Image
Backbone
neck
Head
Output

其中,Backbone可以是Resnet、Res2net、ResnetXt等结构,neck典型例如FPN、RPN等。
Backboneneck结构相对固定,没有太多选择(大神当我没说,重新设计个Backbone一样顶呱呱)。最主要就是Head的设计了,对于目标检测来说,输出目标矩形框坐标语义分割和实力分割:输出多个目标点的坐标;类似的还有姿态估计,道理同样如此。

二、网络主体解读

1、extrace_features

本篇论文LSnet最佳实验则是采用了Res2Net101+FPN的结构。这样就把前期的extrace_features定了下来。主要代码在lscpvnet.py(目标检测用)和lsnet.py(目标检测+语义分割+姿态估计共用)
这两个文件中。
在这里插入图片描述

2、lsnet.py解读

主要包含的类及内部函数:
在这里插入图片描述
构造函数:

@DETECTORS.register_module()
# 将LSCPVDetector类对象作为Registry类的实例化对象DETECTORS
# 中register_module方法的参数传入
class LSCPVDetector(SingleStageDetector):

    def __init__(self,
                 backbone,
                 neck,
                 bbox_head,
                 train_cfg=None,
                 test_cfg=None,
                 pretrained=None):
        super(LSCPVDetector, self).__init__(backbone, neck, bbox_head, train_cfg,
                                                test_cfg, pretrained)
        # 调用LSCPVDetector的父类构造函数

其中,最重要的是训练过程中的 foward_train,测试时用到的 simple_test 以及可视化时的 show_result 这三个函数。

2.1 forward_train 函数

def forward_train(self,
                  img,
                  img_metas,
                  gt_bboxes,
                  gt_labels,
                  gt_masks = None,
                  gt_extremes = None,
                  gt_keypoints = None,
                  gt_bboxes_ignore=None):
    x = self.extract_feat(img) # 这个和之前一样的套路  img -> |backbone+neck| -> base_feature
    # 将特征和标签传入,求损失值
    losses = self.bbox_head.forward_train(x, img_metas, gt_bboxes, gt_extremes, gt_keypoints,
                                          gt_masks, gt_labels, gt_bboxes_ignore)
    return losses

2.2 simple_test 函数

def simple_test(self, img, img_metas, rescale=False, show=False, out_dir=False):
    x = self.extract_feat(img)  # 这个和之前一样的套路  img -> |backbone+neck| -> base_feature
    outs = self.bbox_head(x)    # 传入 lsnet_head的 forward部分 得到第二阶段的输出
    bbox_list = self.bbox_head.get_bboxes(  # 根据输出 产生 bbox 的条件
        *outs, img_metas, rescale=rescale)  
   if self.bbox_head.task == 'bbox':
            bbox_results = [
                bbox_extreme2result(det_bboxes, det_extremes, det_labels, self.bbox_head.num_classes)
                for det_bboxes, det_extremes, det_labels in bbox_list
            ]
    elif self.bbox_head.task == 'segm':
        bbox_results = [    # 得出矩形框
            bbox_poly2result(det_bboxes, det_polygons, det_labels, 
                             self.bbox_head.num_classes,
                             self.bbox_head.num_vectors)
            for det_bboxes, det_polygons, det_labels in bbox_list
        ]
    elif self.bbox_head.task == 'pose_bbox' or self.bbox_head.task == 'pose_kbox':
        if show or out_dir:
            bbox_results = [
               bbox_poly2result(det_bboxes, det_kps, det_labels, 
                                self.bbox_head.num_classes,
                                self.bbox_head.num_vectors)
               for det_bboxes, det_kps, det_labels in bbox_list            
            ]
        else:
            for det_bboxes, det_kps, det_labels in bbox_list:
                bbox_w, bbox_h = det_bboxes[:, 2] - det_bboxes[:, 0], det_bboxes[:, 3] - det_bboxes[:, 1]
                areas = bbox_w*bbox_h
                pos_inds = areas > 1024

                det_bboxes = det_bboxes[pos_inds]
                det_kps    = det_kps[pos_inds]
                det_labels = det_labels[pos_inds]

            bbox_results = [
                bbox_poly2result(det_bboxes, det_kps, det_labels,
                                 self.bbox_head.num_classes,
                                 self.bbox_head.num_vectors)
            ]

   return bbox_results[0]

2.3 show_result 函数

def show_result(self,
                img,
                result,
                score_thr=0.3,
                show=False,
                out_file=None):

    img = mmcv.imread(img)  # 读入数据集或本地图片
    img = img.copy()        # 复制

    bbox_result, vector_result = result[0], result[1]

    bboxes = np.vstack(bbox_result)      # 按垂直方向(行顺序)堆叠数组构成一个新的数组
    vectors = np.vstack(vector_result)   # 按垂直方向(行顺序)堆叠数组构成一个新的数组
    labels = [
        np.full(bbox.shape[0], i, dtype=np.int32)
        for i, bbox in enumerate(bbox_result)
    ]   # 初步标签赋值
    labels = np.concatenate(labels)

    # if out_file specified, do not show image in window
    if show:  # 这句话不管用,
        warnings.warn('show is not supported, please use show-dir')
        return img
    if self.bbox_head.task == 'bbox':
        mmcv.imshow_extremes(img, bboxes, vectors, labels, class_names=self.CLASSES,
                             score_thr=score_thr, out_file=out_file)
    elif self.bbox_head.task == 'segm':  # 绘制多边形
        mmcv.imshow_polygons(img, bboxes, vectors, labels, class_names=self.CLASSES,
                             score_thr=score_thr, out_file=out_file)
    elif 'pose' in self.bbox_head.task:
        mmcv.imshow_pose(img, bboxes, vectors, labels, class_names=self.CLASSES,

3、lscpvnet.py解读

还是和上面那个lsnet.py类似,不过这里只有两个函数,并无可视化相关的函数。

def forward_train(self,
                  img,
                  img_metas,
                  gt_bboxes,
                  gt_labels,
                  gt_bboxes_ignore=None,
                  gt_sem_map=None,
                  gt_sem_weights=None,
                  gt_extremes=None):    # 重写父类的 forward_train的方法
    
    x = self.extract_feat(img)   # img -> |backbone+neck| -> base_feature
    outs = self.bbox_head(x)
    loss_inputs = outs + (gt_bboxes, gt_extremes, gt_sem_map, gt_sem_weights, gt_labels, img_metas)
    losses = self.bbox_head.loss(
        *loss_inputs, gt_bboxes_ignore=gt_bboxes_ignore)
    return losses

def simple_test(self, img, img_metas, rescale=False, show=False, out_dir=False):
    """Test function without test time augmentation

    Args:
        imgs (list[torch.Tensor]): List of multiple images
        img_metas (list[dict]): List of image information.
        rescale (bool, optional): Whether to rescale the results.
            Defaults to False.

    Returns:
        np.ndarray: proposals
    """
    x = self.extract_feat(img)
    outs = self.bbox_head(x)
    bbox_list = self.bbox_head.get_bboxes(
        *outs, img_metas, rescale=rescale)

    # 根据极值点 取出对应的bbox
    bbox_results = [
            bbox2result(det_bboxes, det_labels, self.bbox_head.num_classes)
            for det_bboxes, det_labels in bbox_list
    ]
    return bbox_results[0]

未完待续

下一篇:lsnet_head.py文件,敬请期待~

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乄洛尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值