从工具选择到团队沟通,看ML工程师一步步打造生产级机器学习

  • 2020 年 2 月 24 日
  • 筆記

选自toucanai.com

机器之心编译

参与:Panda、杜伟

为了让机器学习为用户带来真正的价值,我们需要将其部署到生产系统中。人工智能销售软件开发公司 Toucan AI 的 ML 工程师 Marifel 介绍了他们在打造生成级机器学习时所考虑的一些问题,希望这些经验能为你的工作带来帮助。

这些年,随着数据和计算技术的发展,「机器学习」和「深度学习」已经变成了热门研究领域。对公司来说,虽然使用机器学习很时髦,但首先还是需要评估一下自己的业务能否从中受益。如果你的公司已经认定机器学习对公司的下一步发展来说是必需的,那么作为机器学习工程师的你就该思考如何为生产环境构建机器学习过程了。希望本文能帮你明晰你需要考虑的一些东西。

注:本文所提到的「创业公司」都是指有软件「产品」的公司;对于提供软件「服务」的公司,则会专门指明。软件产品公司的业务重心是开发自己的软件产品,而软件服务公司(如代理商或咨询公司)则是为客户开发软件。尽管这篇文章是根据作者在早期阶段的软件产品创业公司担任机器学习工程师的经历写的,但其中某些思考也适用于其它阶段的公司或其它公司类型。

本文作者、Toucan AI 公司 ML 工程师 Marifel。

寻找对你有用的工具

机器学习软件的选择有很多,有开源的工具,比如 PyTorch、TensorFlow 和 scikit-learn;也有企业提供的机器学习服务,比如 Google AI Platform、Amazon SageMaker 和 Azure Machine Learning。光是 PyTorch 和 TensorFlow,就有很多开源的软件库可用,这些直接可用的模型可用作开发产品的起点。

此外,每年还有大量不同领域的机器学习研究论文发表,有的研究者还会以开源形式提供代码。https://paperswithcode.com/ 这个网站可用来寻找带有代码的论文资源。

选择合适工具所要考虑的关键因素包括:

  • 文档的质量;
  • 工具的开发情况(有的工具仍有人维护,有的则已经中止开发或已被启用,或者有严重的问题等等);
  • 围绕该工具的其它工具所构成的生态系统;
  • 参与该工具开发的开发者社区;
  • 团队成员对该工具的熟悉程度;
  • 将会使用该工具的团队的规模;
  • 该工具所涉及的资金成本。

在作者个人看来,如果你在一家处于早期阶段的创业公司,则不必搞清楚所有这些因素。你可以先选择一种强大的工具,然后就此出发。另外,在开始的时候使用企业提供的机器学习服务也是完全可以的,只要你觉得这样做所带来的收益能超过你的投入。

何时做机器学习以及围绕机器学习的发展过程

开发伊始,使用简单的基准模型是很好的做法。从更简单的模型开始操作能帮助你找出工作流程中的问题,还能帮你了解是否值得采用更耗时间的解决方案。那么,你该如何选用简单的基准模型呢?

首先,「简单」是相对的。在某些案例中,简单的意思是模型简单,比如硬编码一些直观理解的结果。而在另一些案例中,模型本身可能很复杂,但是很容易应用。某些被广泛应用的数据集有一些开源的当前最佳模型,你能在研究论文或排行榜等地方找到它们;比如斯坦福问答数据集(SQuAD)就有这样一个排行榜。你可以寻找一些当前最佳的解决方案,然后寻找与该研究论文相关的代码。这能为你提供很好的起点。

在早期阶段的创业公司,你可能没有时间马上动手开发机器学习过程。通常而言,你的工作重心是早点做出一些有效的东西展示给你的投资者或客户。他们通常不是很关心过程的优化。所以不要在意你的初始部署完美与否;它们只需能得到有效的结果就行,即真实可见的最终产品。你可以在做好基础产品之后再去考虑机器学习过程的相关事项,这时候你会有更多的空闲时间,可以为你的机器学习过程应用小型的增量改进。

相反,如果你是一家代理商,因为你已经将成品提供给了不同的客户,并已经事先修复了所有漏洞,因此出错的空间更小。在向客户发货了产品之后,你会转向下一个客户合同,因此通常不会有资源来进行进一步的改进。尽管如此,作为一家代理商,你仍然必须快速行动。为了做到更快,拥有一个更细化的机器学习工作过程会大有裨益。因此对于代理商的模型而言,如果事先花更多时间来进行细化和自动化,也许能为更长远业务节省时间。

实验管理中所要考虑的事项

在机器学习工作中,实验管理并不轻松。当你正尽可能多地运行实验时,很容易就会把你的项目工作区搞得一团糟。但是,在早期阶段的创业公司,你没有办法投入几个月的时间来运行数百场实验。你只得必须关注更好的东西,然后尽可能快地进行更新。无论如何,在实验管理方面,有肯定比没有好。下面是在管理机器学习实验时需要考虑的一些地方。

模型版本控制

我们 Toucan AI 使用 GitHub 来存储不同版本的代码。GitHub 很不错,但不适合对大型数据文件进行版本控制。尽管一个代码库可以高达 100GB,但 GitHub 建议将代码库的规模保持在 1GB 以下;此外,单个文件的大小也不能超过 100MB。

你可以使用其它云存储服务,比如 Google Cloud Storage 或 Amazon S3。使用云提供商的命令行工具或网络用户接口,只需创建一个存储空间(文件夹),就能实现对目标(文件或文件夹)的版本控制。但是,如果你希望同步你的云存储和你的 GitHub 项目代码库,还需要进行一些额外的人工操作。

因此,我们选择了最自然的集成方案,其中组合了 Git 平台的最佳特性以及其它云存储选择的优势:数据版本控制(DVC,https://dvc.org/。该项目的宣传语是「用于机器学习项目的开源版本控制系统」。

DVC 是一款命令行工具,其带有的子命令与 Git 子命令非常类似。设置好 Git 平台与云存储之后,你可以运行 DVC 的 add 和 push 命令,在云存储中以文件或文件夹的形式保存不同的版本。同时,你还可以通过 DVC 文件的引用功能在你的 Git 项目代码库中跟踪较大的数据文件。DVC 的一大优势是仅需要少量类 Git 的命令,让你不至于与已有的 Git 工作流程脱节。

为实验编写文档

如果你在调节超参数,可能很容易就会忘记你在特定时间运行过的某个模型的某种设置。为了为这个模型准备或预处理数据集,你可能还必须回顾一下你之前的工作。你的 Jupyter Notebook 可能具有大致了描述了其中内容的文件名,但你仍然需要些时间才知道当时做了什么——先做了 A 还 B?

针对这个问题,一种解决方案是在你的笔记文件名中加入排序号(我喜欢使用 step 01_),而且你之后也可以重新调整顺序。为笔记文件使用清晰明了的命名规则和排序方式能为你的团队(以及未来的你)提供很大的帮助,让他们能快速了解你究竟是如何做实验的。除了在实践中为笔记文件排序,我们也可使用开源平台 MLflow(https://mlflow.org (https://mlflow.org/)),其提供了可用于查看实验超参数和度量结果的网络接口。

此外,在为实验编写文档时,你还应关注逻辑结构和简洁性。对于一个又一个模型的笔记和训练脚本,你需要充分利用文件夹结构的命令规则来进行组织管理。假设有读者在阅读你的笔记本,他们通常会从上到下阅读,所以你要移除那些临时仓促添加的部分。根据过往经验,你应该为一个模型和一个数据集写一个笔记,如果当前的笔记过长,也要创建一个新笔记。你的最终版笔记不应该包含训练和推理过程的代码;这些应被放在另外的脚本中,然后你可以在笔记中调用它们。最后,当你在使用 MLflow 等软件来生成实验记录时,可以试试将运行实验的笔记自动引用到所生成的实验输出文件中。

测试框架

在某个指标上得到更好的分数并不意味着你的模型能在真实世界样例上取得更好推理结果。此外,在生产级机器学习系统中,机器学习模型通常并不单独工作。举个例子,你的工作流程中可能包含探索方法、预处理和缓存的结果。因此,当你尝试改进你已有的机器学习模型时,你要意识到打造出适用于真实世界的推理样例需要大量时间。

你需要深入理解更大规模的生产代码,了解你想要改进的模型在实际情况中被调用的时机。你不能只是检查一下输入和输出,仅了解模型本身的情况,而要检查整个机器学习系统工作过程。你改进的模型将如何影响整个系统?效果更好还是更差?

为了真正实现模型提升,而不只是想出一些新的推理样例或改变生产流程中的某些东西,我们需要配置一个自动化系统或端到端的测试框架。

我们 Toucan AI 的主要产品是一款 AI 销售智能体,因此测试覆盖主要逻辑分支的示例对话就足够了,并且我们还提供了一种形式的回归测试。我们目前正在开发一款命令行工具(command-line interface,CLI),该工具可以基于一系列示例对话运行 pytest 审定: https://docs.pytest.org/en/latest/。只需一行命令就可以测试所有对话,如果有任何测试不过关,我们就会以人工方式更新该测试或评估我们的「更好」模型是否真的能更好地应对生产环境。

简而言之,为了了解你当前的实验模型在生产机器学习系统中的表现,配备一个测试框架是非常重要的。有了好用的测试框架,你的模型改进工作流程能更高效地运行,让你可以比之前运行更多实验。

使用还在快速演进的工具

在我们的生产系统中,我们往往使用的是更老版本代码库的修改版;如果这个代码库正在快速演进,我们可能很难将新的改进整合到生产系统中。因此,对于正在快速演进的代码库,你该如何对其进行修改以满足自己的需求以及尽可能高效地应用其最新的更新呢?

我认为这个问题不存在唯一的正确答案,而是有很多不同的路径可走。其中一条路是将他们的一部分代码与你的一部分代码组合起来,做成可用的系统;另一条路是取用他们的代码;并且完全升级你的旧版本,但这种做法需要更长的时间。

简而言之,你要仔细考虑重新开发需要多少时间,以及什么是优先事项。把重心放在优先事项上,之后再考虑要不要完全重构;你可以在你自己的代码库和这个快速演进的工具更加稳定之后再做这件事。

实验清理

当你关注的重点是获得结果时,你很容易就会忽视整洁性。你会思考要运行的下一组实验及其超参数设置。出现了一个错误?没有问题,修改输出文件夹上的时间戳,然后再次运行实验。但是,你最后得到的不过是另一些由不完整实验生成的文件或文件夹。之后,查看实验记录的人会深感头痛,他们被迫在 MLflow 中查看长长的列表,搜寻那些完整运行了的实验。

解决方案很简单,自动删除那些你不想保存的试验性运行。举个例子,最好删除那些在第一轮训练迭代之前就已经失败的实验。为了团队的未来,我们应当尽己所能地保持实验记录的整洁干净。

隔离问题

为了改善你的模型,你会研究和尝试各种不同的机器学习项目,你会遇到一些互相冲突的 Python 软件包需求。一开始,你可能会使用在两个开发者之间共享的云服务器,但很快你就会发现这样很不方便,因为你的安装可能会覆盖己方团队的安装。

使用 Docker 吧!这是一种轻量级的容器化软件平台,可用于管理你的项目环境和依赖。你应该为你的每个机器学习模型和应用服务使用不同的 Docker 容器,这样可以主动地减少「这只在我的机器上有效」的问题,防止项目之间出现依赖冲突。你和你的团队无需设置更多开发服务器,而是可以每个人都在同一个共享服务器上设置自己的 Docker 容器,这样做一般也更具成本效益。

此外,你可能会疑惑为什么选 Docker 而不是 Conda,毕竟 Conda 让你能用不同的软件版本创建不同的环境?我们选择 Docker 的原因是其提供的工具更适合生产以及在云上操作。如果你要在一台远程机器上使用 Conda,就必须首先连接到该机器,然后处理文件传输问题。而在使用 Docker 时,只需要几行命令,就能将本地文件修改同步到远程机器的 Docker 容器中。

此外,运行项目所需的一切都会在 Dockerfile 或 Docker Compose 文件中说明。而在使用 Conda 时,如果不参考一下 README,我们不知道是否还需要额外的步骤。

最后,在 Docker Compose 的帮助下,如果一个机器学习项目需要其它服务才能运行,那么就可以将这些额外服务运行在其它 Docker 容器中,然后让这些容器根据 Docker Compose 文件设置进行通信。就我所知,使用 Conda 不能实现跨环境通信。

做好在有需要时扩展规模的准备

当创业公司还处于早期阶段时,还不需要扩展规模,但还是有必要思考一下用于实现扩展的技术。其中之一是 Celery:http://www.celeryproject.org/。这是一个异步任务队列系统,可以将任务分发给多个工作器处理。我们目前是为每种类型的服务(服务器、客户端、嵌入式模型)使用一个工作器,但如无必要,不应该花太多精力来为同一服务设置更多工作器。

此处有一个疑问,通过嵌入进行缓存是你的扩展瓶颈吗?没有问题,我们可以再做另一个嵌入式 Celery 工作器或增加当前工作器的并发数量,这能让你并行运行多个子进程。我们 Toucan AI 的配置是在一个 Docker 容器中运行单个 Celery 工作器,这同时也考虑到了隔离问题。

Celery 不仅能扩展你的生产系统,还非常适合用于执行那些需要长时间运行的任务,比如机器学习模型推理任务。除了允许服务器响应挂起,服务器响应(智能体的回复)可以立即返回给与 Toucan AI 智能体对话的终端用户,同时还可以在后台安静地运行异步任务(比如缓存机制)。

此外,我们还使用 Celery beat 来运行我们日常安排的分析工作器任务。Celery beat 有助于使用 cron 来安排工作器任务。

与团队和未来的自己合作

机器学习研究论文正在大量发表,作为一位机器学习工程师,你需要知道你的团队正在开发以及尝试过哪些模型和技术。那么你该怎么做呢?你没有任何捷径可以获得他们的知识、经验和见解,但你可以与他们沟通,并且要多多沟通。

无论什么时候,都要保持沟通,尤其是通过书面沟通。很多时候,你做着自己的项目,而你当前所做的事情可能与你的团队所做的事情完全无关。尽管如此,也许未来某个时间他们需要审查或扩展你已经实现的东西。可能在你完成那项任务的几个月后,你需要对你自己的项目进行一些修改,而这时你可能已经忘记了你做过了什么。所以记得做文档,做文档,做文档!重复三篇,现在你知道做文档的重要性了吧?

另外要注意,有时候光有笔记是不够的。你需要让你的团队也了解你做的事情。如果你有些不确定的地方,当你需要他们的诚实意见时,或你感觉口语是更有效率的沟通媒介时,你都可以与他们谈谈你的项目的发展方向。注意从一开始就要保持沟通清楚,这是非常重要的,可以防止误解、徒劳、担忧和悔恨。

机器学习工程师的内心挣扎

作为一位机器学习工程师,你必须学会调整自己的思想,不要老想着查漏补缺,把事情做得比实际所需的更好。你必须学会接受不完美,把重要的时间放在完成最紧迫的任务上。举个例子,我喜欢花时间改进第三方的训练/评估代码,但这个时候我也许只需要尽快知道推理结果是否有所改善。

我有做网站开发的背景,那时候我基本必须完全自己写代码,但在机器学习工程开发中,我必须学会如何应用其他人的代码。当你总是使用别人的代码时(这些代码往往是学生和研究者花费几个月乃至几年的时间研究出来的),有时候难免觉得失落,觉得自己的工作不完整,尤其是当你过于在意地想要理解那些代码的方方面面时。但是,这是不必要的,你要做的只是将他们的模型成功地部署到你的生产系统中。

不管怎么说,我们本质上都是好奇的生物,很自然会想要理解超过实际所需的东西。如果你想要做些探索,最好让你的团队也知道这一点。如果你能足够及时地完成你的目标工作,互相理解的工作环境能为你提供学习更多的机会。只要你知道什么是优先事项,那就不要太担忧,开心去探索吧。

总结

为生产系统打造机器学习过程并非易事。尽管文中列出了这么多所要考虑的东西,但有时候,你要做的仅仅是一个决定。如果这条路不同,那就走另一条。虽说如此,但还是希望这篇文章能帮你了解这些需要考虑的东西。

原文链接:https://www.toucanai.com/blog/post/building-production-ml/