1.问题


继上次训练挂起的bug后,又遇到了现在评估时AP非常低的bug。具体有多低呢?Pelee论文中提到,用128的batchsize大小在coco数据集上训练70K次迭代后,AP@0.5:0.95为22.4,而我用32的batchsize反复微调之后,最后AP也只从2.9上升到了3.7...下图为训练的过程:

2.解决


其实看loss和accuracy还是可以的,但是ap就是上不去,粗略想到了4个地方可能存在的问题:

  • 训练有误

    因为尝试了各种学习率,而且在各个学习率下都是训练到ap和loss都不变之后才改变学习率,因此我想不出训练还有什么其他花样了...排除
  • 数据有误

    因为coco的数据是自己转换的,说实话对这块还是有点不放心的。况且之前训练的bug已经检查过数据了,看样子是没什么问题。现在再检查工作量也比较大,存疑,先放着
  • 模型有误

    模型在voc数据集上能成功复现,排除
  • 计算有误

    因为coco评估的脚本是在voc上改的,生成json文件之后再使用官方的cocoapi计算。所以有很大可能是生成json文件的脚本哪里写错了

综上,先排查评估是否有计算错误。

但是没看出来...于是,我寻思着在原来的voc_eval.py文件上做一些修改,以适配coco,再用voc的方式评估。虽然计算方式有差别,但不会差太远。如果ap变化不大,那说明计算方式没有问题,需要检查数据(最怕的就是这种情况,因为工作量很大,而且数据也容易出错,还好gt标错的坑已经提前踩了,想想就可怕);反之就是评估计算有问题。

# voc_eval.py 程序结构
def do_python_eval(dataset_path, pred_path, use_07=True):
aps = []
#对每个类别:执行
rec, prec, ap = voc_eval(filename, # 每个类别的预测文件result_x.txt
os.path.join(dataset_path, anno_files), # 每张图片的标注文件
os.path.join(dataset_path, all_images_file), # 所有图片的文件名文件
cls_name, # 类别名
cache_path, # 用于暂存所有图片的标注
ovthresh=0.5,
use_07_metric=use_07_metric)
aps += [ap]
#将rec, prec和ap 存到对应类别的 xx_pr.pkl文件
#打印AP和mAP def voc_eval(detpath,
annopath,
imagesetfile,
classname,
cachedir,
ovthresh=0.5,
use_07_metric=True):
#1.从imagesetfile中读取所有图片文件名
#2.如果cachedir中的annots.pkl文件不存在,则将标注按文件名打包之后写入annots.pkl;否则加载文件到recs字典中(key为文件名)
#3.提取该类别的标注,按文件名打包存到class_recs字典中
#4.从txt文件读取该类别的标注
#5.计算rec, prec, 用voc_ap计算ap
#6.返回rec, prec, ap #如果要更改以适配COCO,需要:
#获取所有image_id
#从minival.json中按image_id提取标注

分析了一波之后改好了代码,也能正常运行(非常慢)。要命的是好不容易把文件都读完了,结果报错了。显示keyerror:

{213035: [{'name': 'scissors', 'bbox': [314.25, 168.05, 79.57, 53.75]}, {'name': 'scissors', 'bbox': [238.06, 170.62, 89.75, 64.11]}, {'name': 'person', 'bbox': [0.0, 110.12, 311.59, 235.62]}, {'name': 'person', 'bbox': [195.75, 2.88, 260.04, 109.39]}, {'name': 'bowl', 'bbox': [177.04, 0.0, 66.69, 135.89]}, {'name': 'person', 'bbox': [305.0, 53.24, 330.51, 373.76]}]}
r = [obj for obj in dic[213035] if obj['name'] == 'person']
# 大致是说obj没有name属性

输出改obj的iamge_id之后到minival.json去找,发现这个标注的类别是82还是83...coco不是80个类吗?给我整懵逼了...

但是,突然灵光一闪,我似乎已经找到问题所在了。coco数据集虽然有80个类,但是却不是顺序排下来的,中间有跳过的序号,所以真实的序号是从1到90,这个项目之前做过一个转换:

labelmap = {
"none_of_the_above": 0,
"1": 1,
"2": 2,
"3": 3,
"4": 4,
"5": 5,
"6": 6,
"7": 7,
"8": 8,
"9": 9,
"10": 10,
"11": 11,
"13": 12,
"14": 13,
"15": 14,
"16": 15,
"17": 16,
"18": 17,
"19": 18,
"20": 19,
"21": 20,
"22": 21,
"23": 22,
"24": 23,
"25": 24,
"27": 25,
"28": 26,
"31": 27,
"32": 28,
"33": 29,
"34": 30,
"35": 31,
"36": 32,
"37": 33,
"38": 34,
"39": 35,
"40": 36,
"41": 37,
"42": 38,
"43": 39,
"44": 40,
"46": 41,
"47": 42,
"48": 43,
"49": 44,
"50": 45,
"51": 46,
"52": 47,
"53": 48,
"54": 49,
"55": 50,
"56": 51,
"57": 52,
"58": 53,
"59": 54,
"60": 55,
"61": 56,
"62": 57,
"63": 58,
"64": 59,
"65": 60,
"67": 61,
"70": 62,
"72": 63,
"73": 64,
"74": 65,
"75": 66,
"76": 67,
"77": 68,
"78": 69,
"79": 70,
"80": 71,
"81": 72,
"82": 73,
"84": 74,
"85": 75,
"86": 76,
"87": 77,
"88": 78,
"89": 79,
"90": 80
}
COCO_LABELS = {
"bench": (14, 'outdoor'),
"skateboard": (37, 'sports'),
"toothbrush": (80, 'indoor'),
"person": (1, 'person'),
"donut": (55, 'food'),
"none": (0, 'background'),
"refrigerator": (73, 'appliance'),
"horse": (18, 'animal'),
"elephant": (21, 'animal'),
"book": (74, 'indoor'),
"car": (3, 'vehicle'),
"keyboard": (67, 'electronic'),
"cow": (20, 'animal'),
"microwave": (69, 'appliance'),
"traffic light": (10, 'outdoor'),
"tie": (28, 'accessory'),
"dining table": (61, 'furniture'),
"toaster": (71, 'appliance'),
"baseball glove": (36, 'sports'),
"giraffe": (24, 'animal'),
"cake": (56, 'food'),
"handbag": (27, 'accessory'),
"scissors": (77, 'indoor'),
"bowl": (46, 'kitchen'),
"couch": (58, 'furniture'),
"chair": (57, 'furniture'),
"boat": (9, 'vehicle'),
"hair drier": (79, 'indoor'),
"airplane": (5, 'vehicle'),
"pizza": (54, 'food'),
"backpack": (25, 'accessory'),
"kite": (34, 'sports'),
"sheep": (19, 'animal'),
"umbrella": (26, 'accessory'),
"stop sign": (12, 'outdoor'),
"truck": (8, 'vehicle'),
"skis": (31, 'sports'),
"sandwich": (49, 'food'),
"broccoli": (51, 'food'),
"wine glass": (41, 'kitchen'),
"surfboard": (38, 'sports'),
"sports ball": (33, 'sports'),
"cell phone": (68, 'electronic'),
"dog": (17, 'animal'),
"bed": (60, 'furniture'),
"toilet": (62, 'furniture'),
"fire hydrant": (11, 'outdoor'),
"oven": (70, 'appliance'),
"zebra": (23, 'animal'),
"tv": (63, 'electronic'),
"potted plant": (59, 'furniture'),
"parking meter": (13, 'outdoor'),
"spoon": (45, 'kitchen'),
"bus": (6, 'vehicle'),
"laptop": (64, 'electronic'),
"cup": (42, 'kitchen'),
"bird": (15, 'animal'),
"sink": (72, 'appliance'),
"remote": (66, 'electronic'),
"bicycle": (2, 'vehicle'),
"tennis racket": (39, 'sports'),
"baseball bat": (35, 'sports'),
"cat": (16, 'animal'),
"fork": (43, 'kitchen'),
"suitcase": (29, 'accessory'),
"snowboard": (32, 'sports'),
"clock": (75, 'indoor'),
"apple": (48, 'food'),
"mouse": (65, 'electronic'),
"bottle": (40, 'kitchen'),
"frisbee": (30, 'sports'),
"carrot": (52, 'food'),
"bear": (22, 'animal'),
"hot dog": (53, 'food'),
"teddy bear": (78, 'indoor'),
"knife": (44, 'kitchen'),
"train": (7, 'vehicle'),
"vase": (76, 'indoor'),
"banana": (47, 'food'),
"motorcycle": (4, 'vehicle'),
"orange": (50, 'food')
}

妈的生成json文件的时候我忘了换回来了(其实想一下好像不这样来回转也行)...所以只有序号从1到11的类别能够对上。简单修改后,得到真正的预测结果:

 Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.199
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.343
Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.201
Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.030
Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.200
Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.365
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.201
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.295
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.314
Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.054
Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.342
Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.548

与论文中的22.4和38.3相比还有差距,但是至少没有开始吓人了,再根据正确的AP微调一下应该还能提高点。

算是误打误撞解决了?

虽然这次的bug也调了一星期,但是明显没有上次那么慌了。

[PocketFlow]解决在coco上mAP非常低的bug的更多相关文章

  1. [PocketFlow]解决TensorFLow在COCO数据集上训练挂起无输出的bug

    1. 引言 因项目要求,需要在PocketFlow中添加一套PeleeNet-SSD和COCO的API,具体为在datasets文件夹下添加coco_dataset.py, 在nets下添加pelee ...

  2. IIS上部署MVC网站,打开后ExtensionlessUrlHandler-Integrated-4.0解决方法IIS上部署MVC网站,打开后500错误

    IIS上部署MVC网站,打开后ExtensionlessUrlHandler-Integrated-4.0解决方法 IIS上部署MVC网站,打开后500错误:处理程序“ExtensionlessUrl ...

  3. Gulp解决发布线上文件(CSS和JS)缓存问题

    Gulp解决发布线上文件(CSS和JS)缓存问题 本文的缘由:目前经常线上发布文件后要不断的刷新页面及过很长时间,页面上的CSS和JS文件才能生效,特别对于目前做微信商城的时候,微信内置的浏览器缓存非 ...

  4. 微信JSSDK多图片上传并且解决IOS系统上传一直加载的问题

    微信多图片上传必须挨个上传,也就是不能并行,得串行: 那么我们可以定义一个如下所示的上传函数: var serverIds = []; function uploadImages(localImage ...

  5. 解决TableView / ScrollView上的Menu问题(1滑出View区域还可点击2导致点击menu后View不能滑动)

    解决TableView / ScrollView上的Menu问题 1划出区域还可点击 重写CCMenu的触摸事件函数 TouchBegin/TouchMove/TouchCancle/TouchEnd ...

  6. 解决iphone safari上的圆角问题

    -webkit-appearance : none ; /*解决iphone safari上的圆角问题*/

  7. 解决WordPress无法上传媒体文件以及无法下载和安装主题与插件的问题

    前言: 我的个人博客网站荒原之梦在安装成功WordPress之后本来是可以上传媒体文件,安装主题和插件的,但是后来不知道怎么回事就出了问题:不能上传媒体文件也不能安装主题和插件了.出现这个问题后我尝试 ...

  8. [转]通过设置nginx的client_max_body_size解决nginx+php上传大文件的问题

    转:http://blog.csdn.net/zhengwish/article/details/51602059 通过设置nginx的client_max_body_size解决nginx+php上 ...

  9. android 解决小米手机上选择照片路径为null情况

    昨天测试帅哥说他手机选择图库崩溃了,这是一个上传头像的功能,相信很多应用都有这个功能,于是我就把手机拿过来打log看了下返回的路径 为null,在网上搜索了下解决方案,现在把解决方案记录下: 这是在o ...

随机推荐

  1. webstorm开发nodejs的技巧--代码提示DefinitelyTyped

    先发视频“WebStorm - MEAN Stack Walkthrough and Tips”,地址:http://www.tudou.com/programs/view/txhBUA7fcNA/? ...

  2. 安装 centos7

    一.安装 省略前面安装操作,直接进入设置界面: 日期.键盘等设置按默认即可,主要是系统安装位置需要设置,点击 系统安装位置,进入设置 最终完成分区: 点击左上角完成按钮 接受更改 开始安装 设置roo ...

  3. JVM由浅入深

    运行时数据区域 Java比起C++一个很大的进步就在于Java不用再手动控制指针的delete与free,统一交由JVM管理,但也正因为如此,一旦出现内存溢出异常,不了解JVM,那么排查问题将会变成一 ...

  4. oracle net manager 数据传输安全

    oracle net manager来加密客户端与数据库之间或中间件与 数据库之间的网络传输数据 第一步:开始-->所有程序 -->oracle --> 配置和移植工具 --> ...

  5. Vue--- VueX组件间通信链接(共有方法放入了扩展目录store里面) 1.2

    Vuex结构图再仔细看 Vuex原理: 就是  把共有属性放入到一个公共的地方,进行使用 多组件共享状态, 之前操作方式,由父组件传递到各个子组件. 当路由等加入后,会变得复杂. 引入viewx 解决 ...

  6. 选择客栈(noip2011 day1 t2)

    题目描述 丽江河边有 n 家很有特色的客栈,客栈按照其位置顺序从 1 到 nn n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k−1 表示),且每家客栈都设有一家咖啡店,每 ...

  7. FirstBird--项目流程

    创建项目(英文路径)—–img图片文件 创建窗体–设置大小(Basic—size–>320*480)—最大化功能禁用(Expert–>setResizable(false)) 添加面板–设 ...

  8. Java分享笔记:RandomAccessFile流 & 在文件指定位置插入内容

    RandomAccessFile流:随机存取文件流,该类定义了一个记录指针,通过移动指针可以访问文件的任意位置,且对文件既可以读也可以写.使用该类的write方法对文件写入时,实际上是一种覆盖效果,即 ...

  9. kubeadm常见报错和解决方法

    k8s随着社区不断壮大国内使用率现在也是比较高的,常用的部署方式主要还是以二进制和kubeadm为主,当然1.13之前大部分人还是以二进制,但是随着版本更新kubeadm已经逐步适用于生成环境,由于k ...

  10. 邮件发送失败问题:Sending the email to the following server failed : smtp.qiye.163.com:25

    [邮件发送错误] : Sending the email to the following server failed : smtp.qiye.163.com:25, {}org.apache.com ...