神经网络算法再牛, 也不会比你标的数据更准
标注数据, 对于算法本身和应用都意义重大, 而其中很有学问;有幸 Pascal VOC 的标注规则是公开的, 自己读后有一些学习体会,与君共享。
如果图片内物体过多导致无法标注, 放弃
检测画框个人认为其中 (2) 并不十分合理, 或者说扩展性差; 因为在不同情况下我们很容易改变对物体的定义,如果按一种固定标准去给出一个布尔值 (True/False),则会让我们的标注与当前 Project 绑定, 甚至和算法绑定, 这显然并不划算。
一个直接的想法是让标注人员估计物体可见的百分比, 而这会带来极高的标注代价, 加之 Human is not good at estimating absolute number scale,这也会成为误差的来源。
照片中物体相对 camera 的角度理论上有用, 但实际上物体也会自己形变转动,感觉意义有限
(检测) 框需要包含物体全部像素, 除非物体有过于细长伸出的臂 (伸出部分占像素 < 5%)
(分割) 描边精度有 5 个像素的自由度, 保证外部的肯定是背景
这两个互为对立;
Truncation
如果物体超过 15-20% 的区域都不在标注框内, 则备注为 Truncated。
与开头的 Visibility 同理, 个人觉得布尔值不方便扩展, 下面的 Occlusion 也是。
(检测) 如果框内物体超过 5% 的区域被遮挡, 则标注为 Occluded
(分割) 对混合的像素 (由于运动, 透明性等) 如果能确认属于物体,依旧要标注。
对于图片质量差,比如过多运动模糊,过强光照
除了滤除坏样本,还可以考虑识别出场景,比如夜晚,或者强阳光情况 (应该可以通过程序自动分出)
如果是物体被衣服,泥或雪这种可穿着的物体部分遮盖, 则不算 Occluded
物体是不是在玻璃后面, 如果是,算 Occluded
物体是否是出现在镜子中
如果物体只是在 T-shift, 画中, 而不是真实物体,则不算物体
有些地方可能需要标为物体,或许可以设置布尔字段
Difficult Label
(分割) 物体过于难标注, 比如一堆自行车
类别要求
例如:
椅子: 除去长椅,轮椅,车内座椅,长凳,这些都不标为椅子
TV/显示器: 笔记本电脑不算,电子广告牌不算
而另外一个角度, 把他们标为 "可坐的", ”有数字显示的“ , 似乎比 “椅子” 或 ”显示器“ 更接近物体性质和不同类间的关系。(参考程序语言中的 DuckType) 但这不免费,甚至是昂贵的,而且并没有解决重用问题。
短暂总结
在读过 Pascal 的上述标准后, 我们了解了数据标注的一些基本常识, 甚至可以动手标注了; 但同时发现了新的问题:
由于现实世界和人类自身的模糊性 (Fuzzyness),以及任务的多样化, 经常对于同类物体有不同的标注要求,而我们希望实现数据标注的重用
像素级分割 vs 检测: 看起来前者包含了后者, 而我们应该如何选择
能否实现半自动标注
下面, 就这些问题, 我记录了一些思考和总结。
规则一致性
我认为规则的一致性, 是数据重用的必要条件。 换句话说, 标注规则可以复杂, 但只能有一个!
规则可以演进, 而只要保证统一性, 向前向后兼容就容易保障; 一个直接的成功例子就是 NoSQL, 不需要预先定义数据格式,数据格式可以随着不同数据的存储动态更新 (比如 Mongodb, CouchDB, 当然前提是不要乱存)
当出现多规则, 规则间必定是不互通的,显然无法重用
为了保证规则一致性, 我们需要强类型语言的协助,而 Google 的 Protocol Buffer 正是为此而生 (下面我随手写了个例子 box.proto);
message Box { required int32 xmin = 1; required int32 ymin = 2; required int32 xmax = 3; required int32 ymax = 4; required string class_name = 5; enum OcclusionLevelType { V33 = 0; V66 = 1; V100 = 2; } optional OcclusionLevelType occlusion_level = 6;}
有了类型系统的保障,规则不一样就编译不过,读取不了, 甚至规则还可以继承组合的方式迭代,版本控制。
中间层"计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决,除了中间层过多的问题。"
--- Beautiful Code
规则统一性只是数据复用的必要条件, 为了面对多变的任务需求, 我认为需要一个 ”Query - Rules“ 模型, 来进行复杂度的分离
图中的 Query 可对应需求: ”在数据集 A,B 中,选出无遮挡,或小部分遮挡的数据, 并且其中人的标注必须包含头部"
底层的规则 (Rules) 尽量是原子的, 易组合的,来满足上层的 ”查询“ 需求。
规则扩展性也是要适当考虑的, 比如布尔字段的扩展性比枚举要差
用 Query 承载多样化的需求
代价是标注的工作量会变大 (考虑到复用性的提高, 工作量不一定真的变大)
而规则显然是可以独立于 Query 演进的, 他们其实像极了 CSS 这种网页语言 (用于 Web 端 UI 格式声明), 通过定义规则描述网页的基础 Look and Feel
body { background-color: lightblue;}h1 { color: white; text-align: center;}p { font-family: verdana; font-size: 20px;}
而 CSS 著名的缺点就是缺乏模块化, 任何规则都是全局有效的,导致了 CSS 代码的复用难度极高,需要遵守严格的开发规范 (因为两个人的 CSS 规则放在一起会互相影响)。
而对标注规则相信也是如此, 尽量是底层的,原子的,可组合的,做好复杂度的分离。
--- [5]
像素分割在任务设定上更合理,从算法上看也是如此, 前者是一个分类任务, 简单明了; 而检测涉及到了回归,还包含了 NMS, 坐标变换,Anchor 等等 Trick 和不能求导的模块。
但我认为分割 (Segmentation) 暂时无法替代检测 (Detection)。
因为检测任务中,网络学会了忽视图中的部分区域, 高效快速地完成了多类物体的 localization。
而如果要一个网络完全用像素分割达到同样的目的, 则需要解决大范围的 Invaraince vs. Equivaraince 问题 (Panoptic Segmentation), 极大地提高了网络训练的难度, 即使问题本身我们只需要找到物体的位置。
Instance Segmentation 是两者很好的折中。
另外在 ImageNet, COCO 的 Tech Report 中, 他们都提到
将标注任务划分为流水线, 让每个标注人员只负责一件事, 提高效率, 也让标注流程得到更精细的控制比如 Instance Spotting 不需要很精确, 只需要给接下来的标注人员一个 Clue, 很适合机器来做 (来自 COCO)
机器完全代替人类可能性感觉比较低, 而如果能将流水线的一部分用机器代替, 也有提高标注效率的可能。
自己见少识短,现学现卖, 望大家见笑。
很多标注需求比上述要更复杂, 甚至还有无法标注的任务, 比如 Optical Flow; 希望有一天大家能找到彻底解决人工智能标注数据的问题, 让 AI 更进一步。