骨灰级乐高粉讲述:我是怎么用算法给两吨积木自动分类的

简介:
本文来自AI新媒体量子位(QbitAI)


本文的作者Jacques Mattheij自小就是一名乐高粉。在接触乐高的过程中,他发现了这么一种现象:不同种类的乐高售价是不同的。比如精装乐高的售价大概是每公斤40欧元,散装的乐高只需要10欧元;而一些限量、稀有版本以及乐高机械组的售价能达到每公斤100欧元。

为此甚至有人专门去买那些散装和精装新品的乐高,然后把它们进行重新分类以获取更高的价值。

然而,手动给那些千奇百怪的乐高分类看上去并不是个好主意。于是Mattheij某日突发奇想,决定尝试用机器干这件事。他在各个拍卖网站上拍下了能装满一整车库的乐高(运回来途中还丢了辆卡车)来做这个实验。

这是Mattheij在个人网站上发布的第二篇帖子,讲的是他为给这堆乐高分类而在软件上尝试过的方法;在第一篇帖子里,他介绍了硬件方面的准备和面临的困难。

我们先跳过买几车乐高、安装摄像头、传送带等等过程,来看看他是怎么写这个分类程序的。如果你对硬件部分更有兴趣,请到这里围观:https://jacquesmattheij.com/sorting-two-metric-tons-of-lego

以下内容编译自Mattheij的第二篇帖子:


概述

全部的软件都是用Python写出来的。我本人并不是Python专家,不过好在我也不至于花一辈子才能把它弄会。Anaconda是一种非常好用的Python分发工具。原本,要解决各种关联性和版本问题,给Python设置一个虚拟环境这种事简直就是个噩梦。而对我来讲,Anaconda能帮上很大的忙。

关于乐高分类软件,有个主要部分。比如说,一个通过摄像头实现的图像采集系统:

扫描仪/“图像缝纫机”

采集器完成工作后,会将图像发送到“图像缝纫机”(把两张图接在一起)上,后者的主要任务是两件事:一是判定自从上一张图像之后带着某块乐高的传送带移动了多少( 看视频里的波浪线),二是更新一张新扫描进来的内存图像。在两块乐高中间隔开的部分“缝纫机”会剪一下,然后把下一张扫进来的乐高图像接上。

上述这些都是用OpenCV写出来的。

扫描器和“图像缝纫机”完成了自己的工作后,成果看起来是这样的:

分类

这是这件事真正有趣的部分。这块我弄过好多次,现在已经烦得不行了。

OpenCV基元

我第一次选择的方法是用OpenCV基元,特别是其中的轮廓匹配和圆检测。只要处理乐高的种类没那么多,用这种方式就还能保证一个相对不错的识别准确率。结合一部分简单的元数据(比一块乐高的长、宽、高),它就能分辨出所有基本型乐高积木块之间的区别,不过也不能再多了。

贝叶斯

换种方式,我们试试贝叶斯。贝叶斯分类器相当好理解:你先设计一大堆特征,然后依据这些特征构建检测器,之后再创建一个测试集以保证你的检测器运行得就像他们告诉你的那样好,都完成之后,你就尽己所能提高系统对那些特征的识别能力。你要把一个尽可能大的测试图像集扔到这个系统里去跑,以确定你所设定特征的优先级,进而确定每个特征所占的权重——如果某一特征出现就会被检测为“正确”,特征没有出现就会被检测为“错误”。

我用这种方法建立了一个基于如下特征的分类器:

  • 交叉(两条线在中间某处相交)
  • 圆(积木里包含比螺柱更大的圆形)
  • 侧螺柱(侧面可见的螺柱)
  • “饱满”(the part occupies a large fraction of its outer perimeter)(PS:这个表述量子位也不懂┑( ̄Д  ̄)┍)
  • 高度
  • 洞(积木上某处有个洞)
  • 洞穿(这块积木被打通了)
  • 长度
  • 盘子(积木大概跟个盘子那么高)
  • 矩形(积木大致是长方形)
  • 斜坡(积木上有斜坡)
  • “皮包骨”(the part occupies a small fraction of its outer perimeter)(PS:没怎么玩过乐高的量子位依旧是不懂┑( ̄Д  ̄)┍)
  • 正方形(积木大概是正方形)
  • 螺柱(积木上有可见的螺柱)
  • “透”(积木是透明的)
  • 体积(以立方毫米表示)
  • 楔形(积木是楔形的)
  • 宽度

可能还有其他的特征……这些我弄了好一阵子。做一个“螺柱检测器”看上去微不足道,但其实事情也没那么简单。你需要记着螺柱可能位于任何方向,还有一些可能被识别成螺柱但其实并非螺柱的细小部件,积木可能会是颠倒放置,还可能是背对摄像头的。类似的问题几乎在每种特征上都要出现一遍,最后你要花费大量的精力去调整,才能让系统达到一个令你满意的状态。不过一旦你把上面这些都搞定,你就会收获一个能够检测很多不同种类积木、也能保证不错准确率的分类器了。

即便如此,这套系统离尽善尽美也还差得很远:它太慢了。每一次你往里添加进全新类别的积木,你就要为搞明白一块积木到底属于哪个类别而做更多的工作。电脑在集合元素上花费了大量的时间形成了一个不断膨胀的积木形状库,最佳匹配结果就从库里得出。系统的准确率令人印象深刻,但最后因为速度太慢(跟不上传送机器的速度),我还是放弃了这种方案。

剔除法

剔除系统使用了和上一种方法相同的分类条件。按有效性递减规则进行分类可以快速地将不合规则的对象剔除出去,剩余部分就可以被高效处理。这是第一次,软件能跟上全速运行的机器。

不过这种方案同样存在几个问题:一旦某件积木被剔除掉了,它就再也回不来了——但这个剔除可能是错误的。事实是这种“二进制”的方式确实限制了系统的准确率,你需要一个非常庞大的数据集才能让这个系统跑起来,而这将在很大程度上降低整体效能。

这个系统经常到最后把所有东西都剔除掉了——这样它就毫无用处了。因此,为修正准确率而付出的成本很可能就把它在速度上的优势抵消了。

树形分类

这是个因吹斯汀的想法。我照着一个叫“猜动物”游戏里的台词简单做了棵小树,每次往里面加入新的东西时这棵树就会找出特征中不同的部分并在上面分出一个叉来装入新的积木。与剔除法相比,这种方法有两种非常重要的优势:一是一块积木能用树上的多个点表示,这回帮助提升准确率;二是与之前的方法相比,这个系统的速度简直就和闪电一样快。

但这种方法同样存在明显的弊端:起初的时候你需要手动去创造所有这些特征,而就算你能找到足够清晰的特征,只靠基本的OpenCV写一个特征检测器,这个过程也实在是太过冗长乏味了……很快,这个事还会变得更不好办,特别是Python属于那种相当慢的语言,如果你的问题不能用NumPy或OpenCV库调用来表示,在速度上就要吃大亏了。

机器学习

终于写到这了!被上面那些乱七八糟的方法折磨了差不多六个月后,我受够了。我意识到,要写一个能将所有乐高积木种类都完整包括在内的、能真正干起活来的分类器根本就是不可能的。当然,这让我沮丧了好一阵子。

我决定咬咬牙拼了。我把目光投向了机器学习,并且以一种更为严肃认真的方式来对待它:接下来的数周里我都在啃论文,学习各种与神经网络相关的有趣事情。

上世纪80年代,我曾经与神经网络有过短暂接触,而现在我发现,这一领域与当时相比,已经发生了很大变化。

经过不少研究,我最终决定选择谷歌大脑团队开发的TensorFlow。但要真正学会用这个也需要一个过程,一开始我就在上面卡住了好一阵子,不知道如何处理最好。

大概两个月前,一为叫greenpizza13的Hacker News用户给我推荐了Keras,让我能够直接使用TensorFlow而不至于再去兜个大圈子(Anaconda能帮上很大的忙),而这也直接把我领向了Jeremy Howard和Rachel Thomas棒极了的机器学习入门课(课程链接:http://course.fast.ai/)。

结果,在几个小时内(是的你没看错),我得到的结果就实现了对过去几个月里实践过的所有方案的超越;而在几天之内我就让分类系统实现了真正的实时工作,而不是智能简单地分个几类。再多吹一点:不管是在训练还是推理中,大概2000行特征检测代码以及另外2000行测试和胶水(glue)代码可以被少于200行的Keras代码代替了。

与其他手动对特征进行编码的方式相比,机器学习在速度与编码简易度上的优势真是简直了。虽然它不如树状机制那么快,准确率却比它不知道要高到哪里去了;与此同时,你还不用为那些千奇百怪的积木门类手写代码了,系统能自动搞定。

接下来的麻烦事在于,我要搞出一个足够大的训练数据集,来保证系统能进行1000种以上的分类。起初这看上去就是个不可能完成的任务,我不知道怎么样才能搞到足够的图像并且在可接受的时间内手动对它进行标注,即便按最乐观的情况计算,要搞出一个足够大的数据集,从而让这套系统按理想状态跑起来也要花上我6个月的时间。

最后我想通了:这事不重要。大部分时间里都可以让机器自己对自己的图像进行标注,而我所要做的就是修正它的错误。随着系统的运行,错误也变得越来越少。这种方式非常迅速地扩充了训练图像集。第一天,我手动标注了500块积木;第二天,机器把这个数字提高到了2000,当然,其中有大概一半都标错了——这2500件积木就成了接下来三天这轮训练的基础数据,而最后机器标注了超过4000块乐高,其中90%都是正确的!我只需要修正400块错误的就行了。在这两周的最后,我已经有了一个全部正确标注的20000张图像的数据集。

这还远远不够,其中的一些类别非常不具有代表性,因此我需要提高这些类别中的图像数量,我或许应该把这部分拉出来单独在机器上处理一遍——不需要再进行任何修正,它们将被同样地标注。

自上周发布第一篇帖子后我收获了很多帮助,这里我想特别感谢两个人。一是Jeremy Howard,他帮我补上了知识的空缺,没有他的帮助,我都开不了头;第二位是Francois Chollet,Keras的作者,他将自己自定义版本的Xception模型提供给了我,大大加速了训练的进程。

现在训练在速度上陷入了瓶颈,即使我的Nvidia GPU已经够快的了,我还是嫌它跑得慢。要生成一个新的网络需要花费几天时间,在一台有4个GPU的机器上,这速度真是不行……我是个没什么耐心的人,不过生让这个事给练出来了。

在某一时刻这些软件和数据都会被开源,但在此之前,我还有很长一段路要走。

什么时候软件真正具备给这一大堆散装乐高分类的能力了,翻身的日子就该到了。等我把这堆山一样的乐高收拾完,我就把它们廉价处理出去。

最后,这是一张呈现我起初构想的概念图,全是用乐高拼出来的:

本文作者:唐旭
原文发布时间: 2017-05-09
相关文章
|
3月前
|
机器学习/深度学习 人工智能 算法
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
文本分类识别系统。本系统使用Python作为主要开发语言,首先收集了10种中文文本数据集("体育类", "财经类", "房产类", "家居类", "教育类", "科技类", "时尚类", "时政类", "游戏类", "娱乐类"),然后基于TensorFlow搭建CNN卷积神经网络算法模型。通过对数据集进行多轮迭代训练,最后得到一个识别精度较高的模型,并保存为本地的h5格式。然后使用Django开发Web网页端操作界面,实现用户上传一段文本识别其所属的类别。
112 1
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
|
2月前
|
存储 缓存 分布式计算
数据结构与算法学习一:学习前的准备,数据结构的分类,数据结构与算法的关系,实际编程中遇到的问题,几个经典算法问题
这篇文章是关于数据结构与算法的学习指南,涵盖了数据结构的分类、数据结构与算法的关系、实际编程中遇到的问题以及几个经典的算法面试题。
40 0
数据结构与算法学习一:学习前的准备,数据结构的分类,数据结构与算法的关系,实际编程中遇到的问题,几个经典算法问题
|
2月前
|
移动开发 算法 前端开发
前端常用算法全解:特征梳理、复杂度比较、分类解读与示例展示
前端常用算法全解:特征梳理、复杂度比较、分类解读与示例展示
30 0
|
3月前
|
机器学习/深度学习 算法 数据挖掘
决策树算法大揭秘:Python让你秒懂分支逻辑,精准分类不再难
【9月更文挑战第12天】决策树算法作为机器学习领域的一颗明珠,凭借其直观易懂和强大的解释能力,在分类与回归任务中表现出色。相比传统统计方法,决策树通过简单的分支逻辑实现了数据的精准分类。本文将借助Python和scikit-learn库,以鸢尾花数据集为例,展示如何使用决策树进行分类,并探讨其优势与局限。通过构建一系列条件判断,决策树不仅模拟了人类决策过程,还确保了结果的可追溯性和可解释性。无论您是新手还是专家,都能轻松上手,享受机器学习的乐趣。
55 9
|
4月前
|
数据采集 机器学习/深度学习 算法
【python】python客户信息审计风险决策树算法分类预测(源码+数据集+论文)【独一无二】
【python】python客户信息审计风险决策树算法分类预测(源码+数据集+论文)【独一无二】
|
4月前
|
算法 5G Windows
OFDM系统中的信号检测算法分类和详解
参考文献 [1]周健, 张冬. MIMO-OFDM系统中的信号检测算法(I)[J]. 南京工程学院学报(自然科学版), 2010. [2]王华龙.MIMO-OFDM系统传统信号检测算法[J].科技创新与应用,2016(23):63.
84 4
|
4月前
|
机器学习/深度学习 算法 数据挖掘
决策树算法大揭秘:Python让你秒懂分支逻辑,精准分类不再难
【8月更文挑战第2天】决策树算法以其直观性和解释性在机器学习领域中独具魅力,尤其擅长处理非线性关系。相较于复杂模型,决策树通过简单的分支逻辑实现数据分类,易于理解和应用。本示例通过Python的scikit-learn库演示了使用决策树对鸢尾花数据集进行分类的过程,并计算了预测准确性。虽然决策树优势明显,但也存在过拟合等问题。即便如此,无论是初学者还是专家都能借助决策树的力量提升数据分析能力。
50 4
|
4月前
|
存储 算法 安全
密码算法的分类
【8月更文挑战第23天】
139 0
|
6月前
|
机器学习/深度学习 算法
基于鲸鱼优化的knn分类特征选择算法matlab仿真
**基于WOA的KNN特征选择算法摘要** 该研究提出了一种融合鲸鱼优化算法(WOA)与K近邻(KNN)分类器的特征选择方法,旨在提升KNN的分类精度。在MATLAB2022a中实现,WOA负责优化特征子集,通过模拟鲸鱼捕食行为的螺旋式和包围策略搜索最佳特征。KNN则用于评估特征子集的性能。算法流程包括WOA参数初始化、特征二进制编码、适应度函数定义(以分类准确率为基准)、WOA迭代搜索及最优解输出。该方法有效地结合了启发式搜索与机器学习,优化特征选择,提高分类性能。
|
6月前
|
算法
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素