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)
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的利用上也不是很充分,真的是面向百度编程啊🐶,还有很长的路要走哦😜
参考博客和资料
大佬👍👍👍,同一大佬我只贴上了一份链接
- simple-faster-rcnn-pytorch -- Github -- chenyuntc
- pytorch-playground -- Github -- aaron-xichen
- Selective Search for Object Detection (C++ / Python) -- learnopencv -- Vaibhaw Singh Chandel
- R-CNN论文详解(论文翻译)-- CSDN -- vi_vivian
- R-CNN网络结构讲解 -- CSDN -- ukuu
- 论文笔记:RCNN -- zhihu -- JermmyXu