【mmdetection】使用心得

目录

1.关于使用环境

2.训练非jpg的数据

3.关于cuda out of memory

4.多尺度训练理解


1.关于使用环境

截止到2019年底,一共三台机器在跑:
1、第一台台式机:anaconda + 1080ti + python 3.7 + cuda9.0 + pytorch 1.2 跑起来ok
2、第二台台式机: anaconda + 2080ti + python 3.6 + cuda10.0 + pytorch 1.3 跑起来ok
3、第三台老式笔记本: 无anaconda + 1050ti + python 3.5 + cuda9.0 + pytorch 1.3 因为内存限制 只能infer 

建议用anaconda创建一个环境安装mmdetection比较顺利,建议python 3.6+ ,python 3.5在编译的过程中配套的一些包需要手动降级安装,如matplotlib,scipy-image等等,比较麻烦,笔记本就是这么安装的。

pytorch的安装直接可以通过官网,百度pytorch+ github即可

2.训练非jpg的数据

mmdetection默认是训练jpg的数据,要训练其他格式的数据更改pipelines/loading代码:

class LoadImageFromFile(object):

    def __init__(self, to_float32=False):
        self.to_float32 = to_float32

    def __call__(self, results):
        
        if results['img_prefix'] is not None:
            filename = osp.join(results['img_prefix'],
                                results['img_info']['filename'])
            filename = filename.replace('jpg', 'png') #替换为自己的格式
            #print(filename)   
        else:
            filename = results['img_info']['filename']
        print(filename)
        img = mmcv.imread(filename)
        if self.to_float32:
            img = img.astype(np.float32)
        results['filename'] = filename
        results['img'] = img
        results['img_shape'] = img.shape
        results['ori_shape'] = img.shape
        return results

3.关于cuda out of memory

这一点在截止到2019年12月已经得到部分修正,官方修正主要在max_iou_assigner.py文件中,增添了self.gpu_assign_thr。

因为mmdetecton默认将gt求交求并的运算全部放在gpu进行,因此一旦gt数量太多,gpu的内存就爆了,例如DOTA数据集。因此可以设置self.gpu_assign_thr,当gt的数量大于self.gpu_assign_thr时,将gt的运算放在cpu。

 if bboxes.shape[0] == 0 or gt_bboxes.shape[0] == 0:
        raise ValueError('No gt or bboxes')
        assign_on_cpu = True if (self.gpu_assign_thr > 0) and (
            gt_bboxes.shape[0] > self.gpu_assign_thr) else False
        # compute overlap and assign gt on CPU when number of GT is large
        if assign_on_cpu:
            device = bboxes.device
            bboxes = bboxes.cpu()
            gt_bboxes = gt_bboxes.cpu()
            if gt_bboxes_ignore is not None:
                gt_bboxes_ignore = gt_bboxes_ignore.cpu()
            if gt_labels is not None:
                gt_labels = gt_labels.cpu()

本人一直在训练dota数据集所以将self.gpu_assign_thr设置在300-400之间。但是一旦使用到多尺度的训练或者anchor free的算法时,还是会爆掉,将self.gpu_assign_thr设置到100也不能幸免,主要爆炸的地方在geometry.py中bbox_overlaps函数(其实有点费解,按道理前面的设置self.gpu_assign_thr,就不会在产生求交内存爆炸的的问题了,不知道为何还会产生,希望高人解答)

为了解决这个问题,我在geometry.py中bbox_overlaps函数增添了代码,也是模拟上面添加了gpu_assign_thr。

但是有一个问题是,如果在这里设置了gpu_assign_thr,那么上面的self.gpu_assign_thr必须设置为-1,否则会报错。毕竟这个是非官方实现,与官方是有冲突的。

建议如果存在内存爆炸问题,先按照官方的设置self.gpu_assign_thr,如果不行再试试我这个三脚猫的方法吧。

        if bboxes1.shape[0] == 0 or bboxes2.shape[0] == 0:
            raise ValueError('No gt or bboxes')
        gpu_assign_thr = 400
        assign_on_cpu = True if (gpu_assign_thr > 0) and (
            bboxes1.shape[0] > gpu_assign_thr) else False
        # compute overlap and assign gt on CPU when number of GT is large
        if assign_on_cpu:
            bboxes1 = bboxes1.cpu().detach().numpy()
            bboxes2 = bboxes2.cpu().detach().numpy()
            tl = np.maximum(bboxes1[:, None, :2], bboxes2[:, :2])
            br = np.minimum(bboxes1[:, None, 2:], bboxes2[:, 2:])
            
            iw = (br - tl + 1)[:, :, 0]
            ih = (br - tl + 1)[:, :, 1]
            iw[iw < 0] = 0
            ih[ih < 0] = 0
            overlaps = iw * ih
        
            area1 = (bboxes1[:, 2] - bboxes1[:, 0] + 1) * (
                bboxes1[:, 3] - bboxes1[:, 1] + 1)
        
            if mode == 'iou':
                area2 = (bboxes2[:, 2] - bboxes2[:, 0] + 1) * (
                    bboxes2[:, 3] - bboxes2[:, 1] + 1)
                ious = overlaps / (area1[:, None] + area2 - overlaps)
            else:
                ious = overlaps / (area1[:, None])
            ious = torch.from_numpy(ious).cuda()         
        else:
            lt = torch.max(bboxes1[:, None, :2], bboxes2[:, :2])  # [rows, cols, 2]
            rb = torch.min(bboxes1[:, None, 2:], bboxes2[:, 2:])  # [rows, cols, 2]
    
            wh = (rb - lt + 1).clamp(min=0)  # [rows, cols, 2]
            overlap = wh[:, :, 0] * wh[:, :, 1]
            area1 = (bboxes1[:, 2] - bboxes1[:, 0] + 1) * (
                bboxes1[:, 3] - bboxes1[:, 1] + 1)
    
            if mode == 'iou':
                area2 = (bboxes2[:, 2] - bboxes2[:, 0] + 1) * (
                    bboxes2[:, 3] - bboxes2[:, 1] + 1)
                ious = overlap / (area1[:, None] + area2 - overlap)
            else:
                ious = overlap / (area1[:, None])

4.多尺度训练理解

mmdetection的多尺度训练与其他开源框架的多尺度训练不同。以典型的detectron为例,在训练中人为指定几个尺度如
(512,768,1024),再设置最长边为1024,其缩放的步骤是:

(1)首先以样本的短边为基准缩放到(512,768,1024)中的一个尺度,这时候会有一个缩放比例。

(2)以这个比例缩放样本的长边,计算缩放后的样本长边。

(3)如果这个长边大于1024,那么就以样本的长边为基准缩放到1024,此时还会有一个缩放比例,以这个比例缩放短边。

总之缩放的尺度是有限的

mmdetection的缩放代码在piplines/transforms.py,如下,在config文件中设置的时候只能设置两个尺度如(800,1200),(900,1300)

    def random_sample(img_scales):
        assert mmcv.is_list_of(img_scales, tuple) and len(img_scales) == 2
        img_scale_long = [max(s) for s in img_scales]
        img_scale_short = [min(s) for s in img_scales]
        long_edge = np.random.randint(
            min(img_scale_long),
            max(img_scale_long) + 1)
        short_edge = np.random.randint(
            min(img_scale_short),
            max(img_scale_short) + 1)
        img_scale = (long_edge, short_edge)
        return img_scale, None

步骤如下:

(1)算法会在(800,1200)和(900,1300)这两个尺度中找到每个尺度的最大值,作为长边的缩放范围,即此时是(1200,1300);

(2)同样地,会在这两个尺度中找到每个尺度的最小值,作为短边的缩放范围,即(800,900);

(3)从长边的范围中随机选一个作为长边的最大尺度,同样地在短的范围中随机选一个作为短边的尺度

(4)之后就与前面detectron的缩放步骤一致了

可见由于随机性,mmdetection可以缩放到指定范围的任意一个尺度

 

你可能感兴趣的:(pytorch,mmdetection)