骨灰级乐高粉述说:我是怎样用算法给两吨积木手动分类的
优采云 发布时间: 2020-08-26 08:22骨灰级乐高粉述说:我是怎样用算法给两吨积木手动分类的
唐旭 编译自Jacques Mattheij博客
量子位 出品 | 公众号 QbitAI
本文的作者Jacques Mattheij自小就是一名乐高粉。在接触乐高的过程中,他发觉了如此一种现象:不同种类的乐高售价是不同的。比如精装乐高的售价大约是每公斤40欧元,散装的乐高只须要10欧元;而一些限量、稀有版本以及乐高机械组的售价能达到每公斤100欧元。
为此甚至有人专门去买这些散装和精装新款的乐高,然后把它们进行重新分类以获取更高的价值。
然而,手动给这些千奇百怪的乐高分类看上去并不是个好主意。于是Mattheij某日突发奇想,决定尝试用机器干这件事。他在各个拍卖网站上拍下了能装满一整车库的乐高(运回去途中还丢了辆货车)来做这个实验。
这是Mattheij在个人网站上发布的第二篇贴子,讲的是他为给这堆乐高分类而在软件上尝试过的方式;在第一篇贴子里,他介绍了硬件方面的打算和面临的困难。
我们先跳过买几车乐高、安装*敏*感*词*、传送带等等过程,来瞧瞧他是如何写这个分类程序的。如果你对硬件部份更有兴趣,请到这儿围观:
以下内容编译自Mattheij的第二篇贴子:
概述
全部的软件都是用Python写下来的。我本人并不是Python专家,不过好在我也不至于花一辈子能够把它弄会。Anaconda是一种非常好用的Python分发工具。原本,要解决各类关联性和版本问题,给Python设置一个虚拟环境这种事简直就是个恶梦。而对我来讲,Anaconda能帮上很大的忙。
关于乐高分类软件,有个主要部份。比如说,一个通过*敏*感*词*实现的图象采集系统:
扫描仪/“图像缝纫机”
采集器完成工作后,会将图象发送到“图像缝纫机”(把两张图接在一起)上,后者的主要任务是两件事:一是判断自从上一张图象然后带着某块乐高的传送带联通了多少( 看视频里的波浪线),二是更新一张新扫描进来的显存图象。在两块乐高中间隔开的部份“缝纫机”会剪一下,然后把下一张扫进来的乐高图象接上。
上述这种都是用OpenCV写下来的。
扫描器和“图像缝纫机”完成了自己的工作后,成果看起来是这样的:
分类
这是这件事真正有趣的部份。这块我弄过好多次,现在早已烦得不行了。
OpenCV基元
我第一次选择的方式是用OpenCV基元,特别是其中的轮廓匹配和圆监测。只要处理乐高的种类没那么多,用这些方法就能够保证一个相对不错的辨识准确率。结合一部分简单的元数据(比一块乐高的长、宽、高),它能够区分出所有基本型乐高积木块之间的区别,不过也不能再多了。
贝叶斯
换种方法,我们试试贝叶斯。贝叶斯分类器相当好理解:你先设计一大堆特点,然后根据这种特点建立检测器,之后再创建一个测试集以保证你的检测器运行得如同她们告诉你的那样好,都完成以后,你就尽己所能增强系统对这些特点的辨识能力。你要把一个尽可能大的测试图象集扔到这个系统里去跑,以确定你所设定特点的优先级,进而确定每位特点所占的权重——如果某一特点出现才会被测量为“正确”,特征没有出现才会被测量为“错误”。
我用这些技巧构建了一个基于如下特点的分类器:
可能还有其他的特点……这些我弄了好一阵子。做一个“螺柱检测器”看上去微不足道,但毕竟事情也没那么简单。你须要记着螺柱可能坐落任何方向,还有一些可能被辨识成螺柱但显然并非螺柱的细小部件,积木可能会是颠倒放置,还可能是背对*敏*感*词*的。类似的问题几乎在每种特点上都要出现一遍,最后你要耗费大量的精力去调整,才能使系统达到一个令你满意的状态。不过一旦你把里面那些都搞定,你还会收获一个就能测量好多不同种类积木、也能保证不错准确率的分类器了。
即便这般,这套系统距尽善尽美也还差得很远:它很慢了。每一次你往里添加进全新类别的积木,你就要为搞明白一块积木究竟属于那个类别而做更多的工作。电脑在集合元素上耗费了大量的时间产生了一个不断膨胀的积木形状库,最佳匹配结果就从库里得出。系统的准确率令人印象深刻,但最后由于速率很慢(跟不上传送机器的速率),我还是舍弃了这些方案。
剔除法
剔除系统使用了和上一种方式相同的分类条件。按有效性递减规则进行分类可以快速地将不合规则的对象剔除出去,剩余部份就可以被高效处理。这是第一次,软件能跟上全速运行的机器。
不过这些方案同样存在几个问题:一旦某件积木被剔除掉了,它就再也回不来了——但这个剔除可能是错误的。事实是这些“二进制”的方法确实限制了系统的准确率,你须要一个十分庞大的数据集能够使这个系统跑起来,而这将在很大程度上减少整体效能。
这个系统常常到最后把所有东西都剔除掉了——这样它就毫无益处了。因此,为修正准确率而付出的成本太可能就把它在速率上的优势抵消了。
树形分类
这是个因吹斯汀的看法。我照着一个叫“猜植物”游戏里的台词简单做了棵大树,每次往里边加入新的东西时这棵树才会找出特点中不同的部份并在里面分出一个叉来放入新的积木。与剔除法相比,这种方式有两种特别重要的优势:一是一块积木能用树上的多个点表示,这回帮助提高准确率;二是与之前的方式相比,这个系统的速率简直就和闪电一样快。
但这些方式同样存在显著的弊病:起初的时侯你须要自动去创造所有这种特点,而即使你能找到足够清晰的特点,只靠基本的OpenCV写一个特征检测器,这个过程也实在是很过繁琐厌倦了……很快,这个事都会显得更不好办,特别是Python属于那个相当慢的语言,如果你的问题不能用NumPy或OpenCV库调拿来表示,在速率上就要要不得了。
机器学习
终于讲到这了!被前面这些乱七八糟的方式摧残了差不多六个月后,我受够了。我意识到,要写一个能将所有乐高积木种类都完整包括在内的、能真正干起活来的分类器根本就是不可能的。当然,这使我失望了好一阵子。
我决定咬咬牙拼了。我把眼神投向了机器学习,并且以一种更为严肃认真的方法来对待它:接下来的数周里我都在啃论文,学习各类与神经网路相关的有趣事情。
上世纪80年代,我以前与神经网路有过短暂接触,而如今我发觉,这一领域与当时相比,已经发生了很大变化。
经过不少研究,我最终决定选择微软脑部团队开发的TensorFlow。但要真正学会用这个也须要一个过程,一开始我就在里面卡住了好一阵子,不知道怎样处理最好。
大概两个月前,一为叫greenpizza13的Hacker News用户给我推荐了Keras,让我就能直接使用TensorFlow而不至于再去兜个大圈子(Anaconda能帮上很大的忙),而这也直接把我领向了Jeremy Howard和Rachel Thomas棒极了的机器学习入门课(课程链接:)。
结果,在几个小时内(是的你没看错),我得到的结果就实现了对过去几个月里实践过的所有方案的赶超;而在几天之内我就让分类系统实现了真正的实时工作,而不是智能简单地分个几类。再多吹一点:不管是在训练还是推理中,大概2000行特点检查代码以及另外2000行测试和胶带(glue)代码可以被多于200行的Keras代码替代了。
与其他自动对特点进行编码的方法相比,机器学习在速率与编码简易度上的优势真是简直了。虽然它不如树形机制这么快,准确率却比它不知道要高到那里去了;与此同时,你还不用为这些千奇百怪的积木门类手写代码了,系统能手动搞定。
接下来的麻烦事在于,我要搞出一个足够大的训练数据集,来保证系统能进行1000种以上的分类。起初这看上去就是个不可能完成的任务,我不知道怎么样就能搞到足够的图象而且在可接受的时间内自动对它进行标明,即便按最豁达的情况估算,要搞出一个足够大的数据集,从而使这套系统按理想状态跑起来也要花上我6个月的时间。
最后我想通了:这事不重要。大部分时间里都可以使机器自己对自己的图象进行标明,而我所要做的就是修正它的错误。随着系统的运行,错误也显得越来越少。这种方法十分迅速地扩展了训练图像集。第一天,我自动标明了500块积木;第二天,机器把这个数字提升到了2000,当然,其中有大约一半都标错了——这2500件积木就成了接下来一天这轮训练的基础数据,而最后机器标明了超过4000块乐高,其中90%都是正确的!我只须要修正400块错误的就行了。在这两周的最后,我早已有了一个全部正确标明的20000张图象的数据集。
这还远远不够,其中的一些类别十分不具有代表性,因此我需要增强这种类别中的图象数目,我恐怕应当把这部份拉下来单独在机器上处理一遍——不需要再进行任何修正,它们将被同样地标明。
自上周发布第一篇贴子后我收获了好多帮助,这里我想非常谢谢两个人。一是Jeremy Howard,他帮我补上了知识的空缺,没有他的帮助,我都开不了头;第二位是Francois Chollet,Keras的作者,他将自己自定义版本的Xception模型提供给了我,大大加速了训练的进程。
现在训练在速率上深陷了困局,即使我的Nvidia GPU早已够快的了,我还是嫌它跑得慢。要生成一个新的网路须要耗费几天时间,在一台有4个GPU的机器上,这速率真是不行……我是个没哪些耐心的人,不过生使这个事给练下来了。
在某一时刻这种软件和数据就会被开源,但在此之前,我还有太长一段路要走。
什么时候软件真正具备给这一大堆散装乐高分类的能力了,翻身的日子就该到了。等我把这堆山一样的乐高拾掇完,我就把它们廉价处理出去。
最后,这是一张呈现我先前设想的概念图,全是用乐高拼下来的:
招聘
量子位正在招募编辑记者、运营、产品等岗位,工作地点在上海中关村。相关细节,请在公众号对话界面,回复:“招聘”。
One More Thing…
今天AI界还有什么事值得关注?在量子位(QbitAI)公众号对话界面回复“今天”,看我们全网搜罗的AI行业和研究动态。笔芯~