可能还有其他的特征……这些我弄了好一阵子。做一个“螺柱检测器”看上去微不足道,但其实事情也没那么简单。你需要记着螺柱可能位于任何方向,还有一些可能被识别成螺柱但其实并非螺柱的细小部件,积木可能会是颠倒放置,还可能是背对摄像头的。类似的问题几乎在每种特征上都要出现一遍,最后你要花费大量的精力去调整,才能让系统达到一个令你满意的状态。不过一旦你把上面这些都搞定,你就会收获一个能够检测很多不同种类积木、也能保证不错准确率的分类器了。 即便如此,这套系统离尽善尽美也还差得很远:它太慢了。每一次你往里添加进全新类别的积木,你就要为搞明白一块积木到底属于哪个类别而做更多的工作。电脑在集合元素上花费了大量的时间形成了一个不断膨胀的积木形状库,最佳匹配结果就从库里得出。系统的准确率令人印象深刻,但最后因为速度太慢(跟不上传送机器的速度),我还是放弃了这种方案。 剔除法 剔除系统使用了和上一种方法相同的分类条件。按有效性递减规则进行分类可以快速地将不合规则的对象剔除出去,剩余部分就可以被高效处理。这是第一次,atv,软件能跟上全速运行的机器。 不过这种方案同样存在几个问题:一旦某件积木被剔除掉了,它就再也回不来了——但这个剔除可能是错误的。事实是这种“二进制”的方式确实限制了系统的准确率,你需要一个非常庞大的数据集才能让这个系统跑起来,而这将在很大程度上降低整体效能。 这个系统经常到最后把所有东西都剔除掉了——这样它就毫无用处了。因此,为修正准确率而付出的成本很可能就把它在速度上的优势抵消了。 树形分类 这是个因吹斯汀的想法。我照着一个叫“猜动物”游戏里的台词简单做了棵小树,每次往里面加入新的东西时这棵树就会找出特征中不同的部分并在上面分出一个叉来装入新的积木。与剔除法相比,这种方法有两种非常重要的优势:一是一块积木能用树上的多个点表示,这回帮助提升准确率;二是与之前的方法相比,这个系统的速度简直就和闪电一样快。 但这种方法同样存在明显的弊端:起初的时候你需要手动去创造所有这些特征,而就算你能找到足够清晰的特征,只靠基本的OpenCV写一个特征检测器,这个过程也实在是太过冗长乏味了……很快,这个事还会变得更不好办,特别是Python属于那种相当慢的语言,如果你的问题不能用NumPy或OpenCV库调用来表示,在速度上就要吃大亏了。 机器学习 终于写到这了!被上面那些乱七八糟的方法折磨了差不多六个月后,我受够了。我意识到,要写一个能将所有乐高积木种类都完整包括在内的、能真正干起活来的分类器根本就是不可能的。当然,这让我沮丧了好一阵子。 我决定咬咬牙拼了。我把目光投向了机器学习,并且以一种更为严肃认真的方式来对待它:接下来的数周里我都在啃论文,学习各种与神经网络相关的有趣事情。 上世纪80年代,我曾经与神经网络有过短暂接触,而现在我发现,这一领域与当时相比,已经发生了很大变化。 经过不少研究,我最终决定选择谷歌大脑团队开发的TensorFlow。但要真正学会用这个也需要一个过程,一开始我就在上面卡住了好一阵子,不知道如何处理最好。 大概两个月前,一为叫greenpizza13的Hacker News用户给我推荐了Keras,让我能够直接使用TensorFlow而不至于再去兜个大圈子(Anaconda能帮上很大的忙),而这也直接把我领向了Jeremy Howard和Rachel Thomas棒极了的机器学习入门课(课程链接:)。 结果,在几个小时内(是的你没看错),我得到的结果就实现了对过去几个月里实践过的所有方案的超越;而在几天之内我就让分类系统实现了真正的实时工作,而不是智能简单地分个几类。再多吹一点:不管是在训练还是推理中,大概2000行特征检测代码以及另外2000行测试和胶水(glue)代码可以被少于200行的Keras代码代替了。 与其他手动对特征进行编码的方式相比,机器学习在速度与编码简易度上的优势真是简直了。虽然它不如树状机制那么快,准确率却比它不知道要高到哪里去了;与此同时,你还不用为那些千奇百怪的积木门类手写代码了,系统能自动搞定。 接下来的麻烦事在于,我要搞出一个足够大的训练数据集,来保证系统能进行1000种以上的分类。起初这看上去就是个不可能完成的任务,我不知道怎么样才能搞到足够的图像并且在可接受的时间内手动对它进行标注,即便按最乐观的情况计算,要搞出一个足够大的数据集,从而让这套系统按理想状态跑起来也要花上我6个月的时间。 (责任编辑:本港台直播) |