所以,你已经完成了你的研究。您开发了一个机器学习 (ML) 模型,对其进行了测试和验证,现在您已准备好开始开发,然后将该模型投入生产。艰苦的工作——研究——终于在你身后了。或者是吗?

了解机器学习模型交付中的挑战

你突然想到,“我怎样才能确保模型在生产中按预期工作?”

您辛辛苦苦开发的模型在部署到生产环境中时可能会失败,原因有多种。以下是一些:

数据不同

开发和研究没有使用相同的数据库,数据也不完全相同。在生产中,推理是对内存中的数据实时执行的。通过研究,通常使用数据湖和多个处理批量数据的查询引擎。 

不同的环境

生产系统使用 Java 和 C,而研究系统使用 Python。解决此问题的一种方法是将模型部署为 Web 端点,但有时此解决方案的性能要求过于严格。

功能不兼容

有一些很棒的工具可以简化模型从研究到开发的交付过程。例如,研究人员可以使用特征存储,其中实时提取特征并将其保存到数据库中。研究人员使用相同的数据,稍后将由生产系统使用并提供执行预测的端点。当研究团队或多或少知道他们计划使用哪些功能时,此解决方案特别有用。当数据和上下文随着每个项目的变化而变化时,使用特征存储就会变得更加困难,因为您每次都需要创建新特征。它非常适合交付,但它不灵活,并且显着增加了更改或添加新功能的开销。  

由于这些原因,在某些项目中,首选的交付方式是以伪代码或概念验证(POC)代码作为参考的规范文档。研究团队将文档交付给开发团队,他们以适合其系统的方式重新实现解决方案,因为他们无法按原样使用研究团队的代码。

大多数情况下,熟练的开发人员不会发现基于伪代码和规范实现某些代码很困难,但最终产品不会完全相同。

开发和研究必须经过多轮并解决错误才能得到想要的结果。

研究和开发模型之间存在一些差异的主要原因之一是开发人员无法真正测试他们的代码。他们可以确保它符合规范和伪代码,比较最终结果,但他们无法正确测试他们的代码,因为他们无法知道它是否有效 确切地 正如研究中心所希望的那样。此外,如果规范文档中存在错误,可能需要一段时间才会有人注意到(如果有的话)。

机器学习模型交付挑战的解决方案

解决这个问题的一种方法是提供测试。我们讨论的是研究部门在开发模型时使用的相同测试。测试是研究团队改进机器学习模型结果的一种方法。这确保了更好、更有效的结果,并且它也可以用于最终产品。如何进行测试?通过使用测试 API 端点。当研究人员想要测试某个功能时,他们将实现一个运行该功能的 API 端点,然后为该 API 端点编写测试。这使得测试语言不可知,因为它们针对 API 端点而不是代码运行。

然后,可以使用测试来验证开发团队创建的模型,以确保生产中的模型能够发挥应有的作用。我们从这个方法中得到更多。研究部现在向开发部提供模型和测试,并且由研究部负责保持模型和测试最新,这增加了研究部的所有权。

另一方面,开发人员现在可以更快地进行工作,因为他们可以使用测试驱动开发 (TDD) 方法来工作,这使得在编写代码时可以轻松地测试代码,并在通过测试后获得代码已准备就绪的信心。这会带来更快的开发速度,因为开发人员不需要不断回溯和重新检查他们的代码。

为什么要测试解决方案?让我们参考前面提到的问题,并解释测试如何解决这些常见问题:

数据不同

尽管初始数据不同,但通过测试,开发人员可以调整其代码以确保生成的中间数据相同。

不同的环境

开发使用与研究不同的环境和代码语言,这使得将代码从一个组交付到另一个组变得困难。因为测试是使用 API 交付的,所以整个难题就得以避免。测试充当中间语言。

机器学习模型交付测试

我们使用 Pytest 来开发和运行测试,并使用 Flask 使测试在本地测试端点上运行。在本地端点上运行测试可以让我们稍后替换该端点并在 DEV 端点上运行测试。

研究必须创建一个连接器。它获取 REST API 调用并执行推理和处理操作。这两个操作都会获取包含输入记录的 DataFrame 并返回 JSON 记录:

我们使用 Flask 应用程序来创建本地连接器实现。研究使用的本地端点从测试中调用连接器函数:

辅助函数有助于隐藏 JSON 序列化,从而使测试变得干净,就好像端点不存在一样。例如,我们将使用一个模型来获取查询字符串并决定它是否包含 SQL 注入负载。下面是模型辅助函数和测试。在此测试中,将发送 SQL 注入有效负载,并验证其是否被识别为:

下面是测试特征提取代码的另一个示例。 _process 辅助函数与上一个示例中的 _inference 函数类似。 null_values 是一个计算空词数量的功能:

测试文件是模型开发 git 项目的一部分。它们是作为其中的一部分编写和维护的。

交付到开发

开发人员负责运行测试作为构建过程的一部分。他们必须将模型和处理代码包装在 API 中,并将 API 端点发送到测试。

我们使用 Docker 来隐藏内部测试实现。测试打包为 Docker 镜像。该映像包含最小的 Python 运行时以及测试的依赖项。测试获取端点作为参数,并返回测试结果(例如通过、失败)和日志。

“ENDPOINT”环境变量用于在给定端点而不是本地测试应用程序上运行测试。以下是在端点上运行测试的示例,其中图像名称为 sqli-ml-test:

The “ENDPOINT” environment variable is used for running the tests

以下是测试结果示例:

开发人员可以从 Git(master 或特定分支)中选择要使用的测试版本并运行测试。端点可以在本地端口上运行。构建过程可以启动端点,然后运行测试。使用 Docker 桌面,可以在 PC 上运行测试,而无需安装 Python 和依赖项。

Bug 生命周期流程

测试与源代码一起维护和版本化。它们可以按需交付给开发人员。以下是错误生命周期流程的示例。发现错误后,可以通过研究或开发来编写测试。该测试将在研究和开发端点上运行,并将相应地对代码进行更新。

概括

为了保证机器学习模型对研究团队的实用性,进行测试至关重要。通过利用 Pytest、Flask、git 和 Docker 等流行工具,我们成功实现了测试流程,促进了从研究到生产的过渡。这使我们能够在两个环境中重复使用测试。这些测试仍然组织良好,研究人员并没有受到它们在本地端点上执行这一事实的影响,因为这方面对他们来说仍然是透明的。

该方法会影响研究人员,他们在交付后继续维护其代码、测试和所有权。开发接受测试,从而加速并提高其进度的质量。