我开始为工作开发 AI 功能,因为我看到了一个绕过笨重、老旧的专家工具的机会,当然,每个初创公司都需要成为AI初创公司。在为此功能制作原型时,我遇到了一些奇怪的熟悉问题。所以我翻看了我的日记,找到了 Maggie,这是我和朋友在疫情前开发的婴儿翻译器。已经过去了近七年,困扰 AI 测试和生产部署的相同问题仍然是一个无法缓解的灾难,尽管最先进的技术已经取得了重大进展。以下是我对 Maggie 的笔记、想法和代码的反思,以展示 AI 生产化过程中的常见问题。希望对您有所帮助。
Maggie 是辛普森一家中最小的孩子的名字,出自同名电视剧。Maggie 是一个还没有学会说话的婴儿。Maggie 的叔叔 Herb 在一次错误的商业决策后陷入了困境,于是搬去和辛普森一家住在一起。他从侄女那里获得了灵感,并了解到家人对她无法说话的沮丧,于是奇迹般地制作了一款可以正常工作的婴儿翻译器。同样,我的朋友 Chris 也从他与妹妹的关系中萌生了制作婴儿翻译器的想法,他的妹妹在学习说话方面有困难。因此,我们将我们的应用命名为 Maggie。
当时Chris在一家婴儿实验室工作,他发现特定年龄段的儿童发出的声音频谱存在生理限制。基于这一发现,他收集了训练数据并建立了一个婴儿哭声分类模型——这是一个了不起的成就,因为他是一名物理专业的学生,没有任何计算机科学经验。
我们一起上了一门课——工程师服务学习——全班同学都在为校园里的一栋建筑申请 LEED 认证。我记得他是个无忧无虑的家伙,骑着长板进教室。我们第一次见面是在教室外面,在一家杂货店的黑暗停车场,我看到他正准备骑越野车。他把车停在我的车旁边,我们聊了起来。然后我注意到他旁边有一张揉皱的纸,捡起来发现是钱,就告诉他钱掉了。他说不是他的,但我让他留着。我们不知道钱有多少钱;停车场太暗了。1 美元、10 美元还是 100 美元。我告诉他我希望是 100 美元。他说是 10 美元。但那次初次互动在我们之间建立了足够的信任,几周后,当我们都在加州大学默塞德分校的创业孵化器 Venture Lab 工作时,他请我开发一款应用来部署他的婴儿翻译器。如果没有创业实验室,我们永远不会想到合作。我当然不会到处跟同学说我开发 Android 应用,他也没有到处吹嘘他的婴儿翻译模型。面对面的第三空间有一种不可低估的魔力。
尽管构建了一个工作模型,Chris 还是不知道如何部署它。当时是 2017 年初,没有太多课程或指南来演示这一点。他在 TensorFlow 的导师建议在 Android 上部署,但学习移动开发太难了。我了解 Android,并在 Play Store 上部署了多个应用,但即使对我来说,这也是一件很难的事。所以,我选择了简单的做法。
我将模型放到服务器上,然后对其调用 API。在 Flask 服务器中执行模型非常简单:导入 TensorFlow,从本地磁盘加载模型(我甚至没有想过以一种易于版本控制的方式部署模型,直到后来),然后将请求指向它。但也有一些问题:
尽管存在这些问题,但它还是奏效了。共享模型输入解析器和转换器代码解决了第一个问题。将模型视为黑盒并对其进行模拟使得围绕它构建集成测试变得更容易。这些测试将确保服务器和模型之间没有意外的错位——只要模拟准确即可。现在,有模型接口可以确保开发过程中模拟的正确性。如今,模型的部署和版本控制对于大多数用例来说都不是需要新解决方案的问题。
另一方面,延迟和可用性问题最终迫使我们将模型部署在边缘应用上。这样做的好处是消除了网络延迟,使用手机更快的 CPU,并让应用在后台运行,这解决了我们的启动延迟问题并降低了我们的托管成本。但当然,也有新的问题。
我们花了很多时间讨论将模型放在哪里。我们想要手机的速度和确定性,但渴望服务器的安全性和部署的便利性。最初,将模型放在服务器上很有吸引力:
最后,我们决定将模型放在应用程序中,因为前两点——如果你必须等待它翻译,或者它偶尔会宕机,那么应用程序就不具吸引力。当你怀里抱着一个哭闹的新生儿时,几秒钟的延迟似乎就像永恒一样。但将模型放在手机上也有问题,我将在下一节中描述。
我从中学到的教训是,你应该优化以获得最佳用户体验——即使解决方案不可扩展、不会给你带来未来的增长,或者危及你的知识产权。用户体验决定公司的生死,尤其是对于需要赢得信任和打造品牌的新公司来说。
将模型放到手机上遇到了很多技术难题。有些难题现在已经不存在了,但大多数难题仍然存在。我们处于最前沿。TensorFlow for Android 刚刚推出——公开发布是在 2017 年 2 月,而我在 3 月开发应用程序。但凭借毅力和 TensorFlow 的Pete Warden的大力帮助,我们设法让模型在应用程序中运行。
第一个问题是获取 APK 包中的模型。当时,Android 的 APK 限制为 50 MB,并且有一个扩展功能,允许应用程序在安装后下载组件,从而使其变得更大。但是,我认为扩展功能不安全,因为它意味着将模型暴露在服务器上。因此,我们决定量化应用程序 — — 这是一种涉及降低每一层所有输入和输出的准确度的技术。
在我们的案例中,我们将所有浮点数转换为整数,这显著减少了模型的大小并使其更快,但也降低了准确性。Chris 使用不同的量化方案对模型进行了几次迭代,最终尽管准确性有所降低,但还是选择了整数量化。只要模型的表现比新父母更好,它就很有用。额外好处:它解决了更新问题——每次模型更新下载数百 MB 的数据对于计量互联网连接来说要求很高,但几 MB 的数据是可以管理的(现在我觉得这很愚蠢,因为现在人们经常在手机上下载 GB 的视频内容)。
随后出现了一系列小问题。最大的问题是,Android 附带的不同 Java 版本支持的 FFT 库无法生成用于训练模型的相同频谱图。我们使用 C++ FFT 库训练模型,它生成了具有不同颜色和维度的频谱图。作为秘密工具,C++ 和 Java 版本都是不透明的,很难修改。另一个快速决定:我们决定使用 Java FFT 频谱图重新训练模型。这意味着将所有音频文件转换为频谱图,然后运行训练过程,这在我朋友的旧 Macbook 上花了几天时间。但问题解决了,我可以在此期间专注于其他事情。
但应用程序一直冻结和崩溃。事实证明,将录音加载到内存然后在内存中创建频谱图并不是一个好主意。该应用程序占用了手机的大量资源。解决方案是保存到磁盘并进行流式传输。保存到磁盘很容易;流式传输部分很难,因为一旦音频离开内存,磁盘上的任何事情都可能发生。另一个程序可以读取和修改它;它可以被删除,可能无法保存,等等……这些边缘情况通常不会存在于网络上——你与用户之间有一个隔离的通道,但在设备上却不存在。确保首先有足够的空间来执行此操作并在应用程序结束后进行清理是一项意想不到的挑战。后来我发现,如果手机有足够的内存来安装你的应用程序,那么它就有足够的内存来运行它,那么这是一个错误的假设。
最后,设备本身也是一个对手——Android 手机配有各种各样的 CPU、内存量,以及最重要的麦克风。CPU 和内存问题可以通过将所需的 Android 版本设置为最新版本并希望获得最佳效果来解决;最坏的情况是应用程序运行缓慢——Android 中无法直接设置资源要求。真正的问题是考虑麦克风的各种品质——Android 确实允许您在安装应用程序的设备上要求麦克风,但不允许要求麦克风的类型。
我没有尝试解决这个问题。当时我有很多测试手机,并注意到廉价手机的预测结果要差得多。我认为现在没有时间寻找解决方案——我们正试图尽快推出产品。有时,解决问题的最佳方法是记下它并继续前进。现在我意识到这个问题为我们指明了最终产品的方向——Homer,一款智能音箱。
在克服(或避免)了技术难题之后,我们开始着手解决更棘手的预测质量问题。由于模型存在于应用程序上,我们无法了解其性能。如果性能不佳,我们唯一能判断的方式是通过应用程序页面上的评论或卸载;到那时,已经太晚了。因此,围绕模型构建日志、监控、数据收集和反馈的包装器至关重要。
该模型利用声谱图和其他一些信息对婴儿发出的声音进行分类——饥饿、不舒服、疼痛、困倦和胀气,这些都是翻译。它返回所有可能类别的列表,每个类别都有一个百分比,代表模型对该特定翻译的信心程度。所有百分比加起来是 100——如果最准确的翻译是饥饿,准确率为 90%,那么其他五个类别的准确率加起来就是 10%。
我们早期面临的问题是,是否显示所有翻译(从最准确到最不准确排序)还是只显示一个。我选择只显示一个,因为我不想用更多的翻译让人们感到困惑,而且构建这个更简单(懒惰是敏捷的基石)。然而,我们在第一批用户身上遇到了问题。
当模型确定(高于 80%)时,这个建议就起作用了——我们没有收到家长的抱怨。但它并不总是那么自信。当翻译准确率低于 80% 时,就和家长猜测的一样好。这就违背了应用程序的初衷;它应该提供比新手父母惊慌失措地安抚孩子更准确的翻译。事实也确实如此,毫不奇怪,第二或第三个翻译就准确无误了。我们通过面对面访谈发现了这一点——面对面访谈不可扩展且耗时,但信息量极其密集;如果你可以每天做一次,那就去做吧。婴儿会哭,应用程序会以较低的置信度显示错误的翻译,但我们会尝试其他翻译(我们在日志中看到了它们),它们会起作用。
这对我来说是违反直觉的,因为我认为该应用是一个翻译器;翻译应该只有一种方法,对吗?错了。该应用是一个探索工具,供新父母和看护者确定他们应该首先尝试什么。我应该试着拍嗝吗?他饿了吗?他上次午睡是什么时候?每个父母在宝宝开始哭的时候都会检查这份清单。我们的应用加速了这一探索;这就是父母使用它的方式,也是我们在推出多种翻译功能后得到的反馈。这不是杀手级功能,但它确实将应用从一个噱头变成了一个日常使用的工具,一个在配偶不在或祖父母睡着时值得信赖的伙伴。
有了这些数据的支持,我们很快决定显示更多翻译。关键在于确定要显示多少。显示所有翻译(所有五个类别)会让应用看起来每次都重复相同的翻译。如果每次你搜索食物时,Google 都向你显示相同的四家餐厅,你会怎么想?我们决定显示前三名翻译——这部分是艺术,部分是数据。
出于某种原因,人们倾向于数字 3。数据显示,在第三次翻译之后,模型对其他翻译的信心显著下降。如果第一次翻译的信心为 70%,那么第二次翻译的信心为 20%,第三次翻译的信心为 9%,其余翻译的信心低于 1%。因此,我们删除了这些翻译。这些被删除的翻译准确的可能性很小,但将它们包括在内可能会让应用程序看起来重复。选择是,100 个用户中会有 1 个收到完全错误的翻译,或者所有用户都会看到无用的翻译并认为应用程序是在猜测。这是一个简单的选择。
当然,事后看来,我应该使用多臂老虎机进行测试——发布五个不同版本的应用程序,每个选择一个,例如,显示一个翻译,显示两个,显示三个等,然后慢慢将人们迁移到效果最好的应用程序版本。主要的成功指标是点击绿色复选标记(对翻译感到满意)的人数。但在如此早期的阶段,我相信我们做出了正确的决定,更重要的是,我们以正确的方式做出了决定。我们思想开放,我们不认为任何决定是具体的(这里没有自负),我们不断与用户沟通,倾听他们的意见,即使感觉不对。
每次互动都是一次改进和留下深刻印象的机会。从开始这项冒险开始,我就担心这个模型只是运气好而已,会有一个单身爸爸或妈妈被告知他们的宝宝哭是因为他们胀气,然后他们就把宝宝打嗝打得死去活来。虽然不太可能,但我们觉得自己对每个用户宝宝的健康都有责任。所以我们通过为应用添加反馈功能推迟了发布。
每次翻译后,应用程序都会询问你翻译的帮助程度——这是一个不可跳过的页面。然后,应用程序上传了用户反馈、模型输出、设备类型和频谱图。起初,我上传了音频文件,但很快意识到麦克风捕捉到了很多背景噪音。为了保护用户的隐私,我们选择只上传频谱图。当时我不知道的是,你可以反转频谱图并重建音频,尽管质量较差且有些困难。这就是我们的飞轮。
但是,我跳过了导致最终版本的辩论和多个草稿。决定收集哪些数据、如何衡量成功以及如何定义成功很难,但这是一个可以逐步改进的迭代过程。我得到的最好建议是定义成功是什么样子,或者,如果这太难,定义失败是什么样子(对我来说,定义失败比定义成功容易得多——我从来不知道我想要什么,但我确定我想避免什么),并且要具体。从这个答案中,得出可以用来判断你的努力的指标——如果失败是在用户的孩子长大到无法使用该应用之前失去用户,那么就测量该应用在用户手机上的平均生命周期。但请记住,这些定义和指标并不是静态的——它们会发生变化。你只需要决定并坚持它们,直到它们停止工作。当你停止从中学习,或者至少当从中学习变得更加困难时,它们就会停止工作。这就是目标,学习和改进,其余的都是细节。
在 AI/ML 时代,公司最有价值的数字资产是其所委托的数据,而不是模型。增长这些数据(最好以透明和合乎道德的方式)对于持续成功至关重要。因此,无论转化率如何,每次用户交互都应被视为价值创造时刻。因此,每次交互都应让用户印象深刻并希望再次使用。我们打造了一些令人惊叹和鼓舞人心的产品;我们有一位出色的设计师Teresa Ibarra ,她将我的草稿打磨成一款使用起来令人舒缓和愉悦的应用程序。每一次翻译都使下一次翻译变得更好。
我们最后开发的产品是 Homer。在对应用用户进行了数十次面对面采访并给更多人打电话后,我们意识到,在抱着哭闹的孩子时寻找手机、解锁屏幕、找到我们的应用、打开它并点击翻译非常困难且不方便。为什么我们花了这么长时间才意识到这一点?我们是两个二十多岁的单身无子女男性——我不记得我上次抱孩子是什么时候了,更不用说安抚它的哭声了。因此,我们决定使用智能扬声器构建婴儿监视器。我从 Raspberry Pi 订购了一套套件,并构建了一个定制的 Google Home 扬声器,顶部有一个蓝色的大按钮。
Chris 有一个伟大的愿景,那就是将这种模式卖给婴儿监视器公司,但我们并没有获得这些公司的青睐,那么为什么不使用智能扬声器构建我们自己的婴儿监视器呢?构建 Google Home 后,我创建了一个 bash 脚本,在启动时运行翻译器。翻译器使用 Google Home 的 SDK 来翻译触发短语“好的,Google,翻译”。翻译器是一个 Python 脚本,它从麦克风读取音频,将其转换为频谱图,然后将其发送到服务器进行翻译。我保持敏捷,它成功了!我们终于有了杀手级应用,但它并没有拯救公司。
我们用完了资金——从比赛中赢得的奖金。生活很快就对我们两人造成了巨大打击。我们大学毕业,都回家了——我接受了一份湾区的工作,克里斯则离开去德克萨斯照顾生病的母亲。创业失败了。
创业既艰难又令人心碎。你不能兼职创业。所有有股份的人都必须全职工作,或者必须离开,为其他人腾出空间。或者你必须缩小你的野心,甚至完全放弃它们。现在,有些问题可以通过兼职的方式解决,而且很赚钱——但这些事情值得吗?它们让你兴奋吗?
如果说我学到了什么,除了在 Android 上部署 ML 模型有多痛苦之外,那就是你真的需要关心你正在解决的问题。你需要鼓起勇气,全身心投入其中,尽管有财务风险和巨大的机会成本。我绝不会放弃我的技术工作来从事这项工作。我喜欢帮助新父母和绝望的父亲;学习和开发技术令人兴奋,但我该如何向我爸爸解释为什么我毕业后要搬回我们狭窄的第 8 区公寓?在靠福利生活了这么久之后,我怎么能拒绝六位数的薪水呢?
那风险投资呢?你为什么不试着筹集资金?现实情况是,风险投资家只有在了解你、你上的学校或你工作的公司时才会接电话。他们不在乎你创造了什么——除非它盈利,否则你的创新只是一个小细节——风险投资家首先投资创始人和团队,最后投资产品。但他们中的大多数人不知道如何挑选优秀的创始人或团队,所以他们让精英学校或 FAANG 的招生官来做这件事。