RCNN、Faster-RCNN寻找出错图片——小项目

写在前面的话

这是一次小项目的记录博客,项目具体内容是利用RCNN和Faster-RCNN在VOC数据集找出那些预测错误的图片。其实也称不上是一个项目,只是我花了很多时间并且像模像样的学着大佬写项目那样构造代码。

项目介绍

Introduction

这篇博客主要是讲解我的每个文件或者函数的作用,具体代码在我的Github中。其中faster-rcnn的代码是借用陈云老师的simple-faster-rcnn,我自己加上了一个检测函数和修改一个画图函数;rcnn代码就是自己手撸的🙄,主要是只能找到matlab的RCNN代码,这个我也不会修改,所以自己手撸,自己Train,自己记录权重。话说这就是第一份Pytorch RCNN代码,优秀(不是 顺手提一句,这篇博客开始写的时候,我只是测试完代码跑通和速度是否可行(别问我为什么提速度,问就是因为RCNN内存开销太大,有时候服务器直接将其kill了😭),正在训练。
第一次正经仓库 欢迎大家star 欢迎大家star 欢迎大家star (懂我意思趴
(最终训练代码能跑通,但是测试总是存在一点问题😭)

Faster-RCNN

Code

ppp函数
def ppp(**kwargs):
    opt._parse(kwargs)
    device = opt.device
    
    dataset = Dataset(opt,split = 'test')
    dataloader = data_.DataLoader(dataset,
                                       batch_size=1,
                                       num_workers=opt.test_num_workers,
                                       shuffle=False, \
                                       pin_memory=True
                                       )
    faster_rcnn = FasterRCNNVGG16()
    faster_rcnn.to(device)
    print('model construct completed')
    
    trainer = FasterRCNNTrainer(faster_rcnn)
    if opt.load_path:
        trainer.load(opt.load_path)
        print('load pretrained model from %s' % opt.load_path)
    trainer.vis.text(dataset.db.label_names, win='labels')
    all_count = 0
    count = 0
    zhen_duo = 0
    # ipdb.set_trace()
    pred_bboxes, pred_labels, pred_scores = list(), list(), list()
    gt_bboxes, gt_labels, gt_difficults = list(), list(), list()
    for ii, (img, bbox_, label_, scale,difficult) in tqdm(enumerate(dataloader)):
        all_count += 1
        img, bbox, label = img.float().to(device), bbox_.to(device), label_.to(device)
        ori_img_ = inverse_normalize(at.tonumpy(img[0]))
        _bboxes, _labels, _scores = trainer.faster_rcnn.predict([ori_img_], visualize=True)
        
        
        thresh = 0.2
        gp_ = bbox_iou(_bboxes[0],bbox.numpy()[0])
        if _labels[0].size == 0 :
            continue
        gp = gp_.max(axis = 1)
        gp_ind = gp_.argmax(axis = 1)
        
        gt_bboxes += list(bbox_.numpy())
        gt_labels += list(label_.numpy())
        gt_difficults += list(difficult.numpy())
        pred_bboxes += _bboxes
        pred_labels += _labels
        pred_scores += _scores
        
        do = False
        # 如果预测框的最大IoU存在小于阈值的,检测错误
        # 如果预测框对应的那个真实框分类错误
        if sum(gp < thresh) > 0 or sum(at.tonumpy(_labels[0]).reshape(-1) != at.tonumpy(label_[0])[gp_ind]) > 0 : 
            do = True
        if do :
            if at.tonumpy(_labels[0]).reshape(-1).shape[0] < at.tonumpy(label_[0]).shape[0]:
                zhen_duo += 1
        
            gt_img = visdom_bbox(ori_img_,
                                at.tonumpy(bbox_[0]),
                                at.tonumpy(label_[0]),
                                None,None,'green')
            trainer.vis.img('img_{}_gt'.format(ii+1), gt_img)
    
            # plot predicti bboxes
            pred_img = visdom_bbox(ori_img_,
                                at.tonumpy(_bboxes[0]),
                                at.tonumpy(_labels[0]).reshape(-1),
                                at.tonumpy(_scores[0]))
            trainer.vis.img('img_{}_pred'.format(ii+1), pred_img)
            count += 1
    result = eval_detection_voc(
        pred_bboxes, pred_labels, pred_scores,
        gt_bboxes, gt_labels, gt_difficults,
        use_07_metric=True)
    print(result)
    print('count:{}\t all:{}\t per:{:.2f}'.format(count,all_count,count/all_count))
    print('zhenduo:{}\t count:{}\t per:{:.2f}'.format(zhen_duo,count,zhen_duo/count))
Visualizer.img
class Visualizer(object):
    def img(self, name, img_, **kwargs):

        self.vis.images(t.Tensor(img_).cpu().numpy(),
                        win=name,
                        opts=dict(title=name),
                        **kwargs
                        )
        im = Image.fromarray(np.uint8(t.Tensor(img_).cpu().numpy().transpose((1,2,0))*255))
        im.save('./pic/{}.png'.format(name))

Explanation

其他的一些小的修改,可以在运行代码的时候看出(主要是我也不记得修改了哪里了
预测错误的评判:这里指的是什么叫做目标检测的预测错误(我一开始在这里纠结了很久),后面通过查阅资料和询问学长,认为指定一个阈值,若对于每一个预测框都至少存在一个与之IoU大于该阈值的ground truth,并且与这个最大IoU的ground truth的分类相同就认为是正确的;反之为错误的。注意这里是针对每一个预测框,若是算法没有预测出一个预测框那么也是错的,但是若是每个预测框都预测正确但是ground truth要多一些(也就是有些地方没有检测出来),那算作整张图片预测正确。

Result(Take a Example)

Ground truth
Pred Bbox

RCNN

Code Structure

(代码文件在上述项目介绍中的链接中)
下面用一张表格来表示RCNN项目的代码结构(介绍中没有包含__init__.py文件)

Layer 1 Layer 2 Explanation
dataset 构建Pytorch dataset的代码文件夹
👉 BaseDataset.py 包含了BaseDataset.class,主要是基本的读取相应的图片和真实框的函数,这一部分主要修改自simple-faster-rcnn-pytorch的数据集代码
👉 VOCDataset.py 包含了继承自BaseDataset的TrainCNNDataset.class、NormalDataset.class、TrainSVMAndLRDataset.class,其中NormalDataset.class是用于测试的
model 构建程序处理的模型模块代码文件夹
👉 checkpoints 保存模型权重的文件夹
👉 SelectiveSearch.py 包含了selective_search函数,用于RCNN一开始的图像分割
👉 AlexNet.py 包含了AlexNet.class,是RCNN网络的提取特征网络。AlexNet的权重来自于参考资料第二条
👉 SVM.py 包含了SVMs.class,主要是将20种SVM分类器写成一个类方便存储和管理
👉 LinearRegressor.py 包含了LRs.class,主要是将20种SVM分类器写成一个类方便存储和管理,同时注意在论文使用的是线性回归分类器并且有四个输出,所以在这里使用的sklearn.neural_network.MLPRegressor和不是激活函数
pic 用来保存生成的图像的文件夹
utils 在实现RCNN种一些需要用到的工具函数代码文件夹
👉 bbox_tools.py 包含了bbox_iou、bbox2loc和loc2bbox函数,来自于simple-faster-rcnn-pytorch
👉 eval_tool.py 包含了eval_detection_voc、calc_detection_voc_prec_rec和calc_detection_voc_ap函数,来自于simple-faster-rcnn-pytorch
👉 Config.py 包含了Config.class,定义了一些可以修改的常量
👉 supplement.py 包含了warp_img、wrong_2_draw、draw_、cut_img和maki_all补充辅助工具函数
VOCdevkit VOC数据集
main.py 包含了train_CNN、train_SVMs_and_LRs、train和test函数,是整个项目最终main函数

Structure Pic

Project Tips

说到底这也是我第一次完整的写,整完还是学到了不少东西的。稍微闲聊一点收个尾:

  • RCNN的训练是真的难(写这篇博客的时候,我现在感觉都训练不出来了,真的慢++)
  • 在写深度学习的任务时,自我感觉很重要一部分在于将数据集dataset这一部分的代码编写好,我大部分时间都花在了这儿。感觉就像是数据挖掘大部分时间花在了数据预处理上一样
  • 借用了实验室的服务器以后,接触到了docker和screen操作。特别是docker感觉是一个功能非常强大的工具,理论上应该是可以免去自己装开发环境的麻烦,直接pull一个就好了,直接利用虚拟环境进行开发学习
  • 虽然内容都是自己手撸的,但是整个代码框架其实还是依照他人的模板写出来的,并且在Pytorch的利用上也不是很充分,真的是面向百度编程啊🐶,还有很长的路要走哦😜

参考博客和资料

大佬👍👍👍,同一大佬我只贴上了一份链接

人生此处、绝对乐观

posted @ 2020-10-19 21:51  CodeDancing  阅读(255)  评论(0编辑  收藏  举报