在过去的十年中,在我从事的每个项目中,我的内心深处都带着一个深刻的问题:“我应该如何(到底)如何构建和开发我的人工智能和机器学习项目?”
我想知道 – 是否有一种优雅的方式以迭代方式构建可用于生产的代码?一个可扩展、优化、可维护和可复制的代码库?
如果是这样的话——这个秘密在哪里?谁拥有这种黑暗艺术的知识?
多年来,我不断地寻找答案——阅读文章、观看教程并尝试不同的方法和框架。但我找不到满意的答案。每当我以为自己已经接近解决方案时,却仍然缺少一些东西。
经过大约十年的尝试和错误,加上过去两年的集中努力,我想我终于为我长期以来的追求找到了令人满意的答案。这篇文章是我分享我的发现的旅程的开始。
我的研究使我确定了 5 个关键支柱,这些支柱构成了我所说的超优化人工智能工作流程的基础。在这篇文章中,我将简要介绍它们中的每一个,让您对即将发生的事情有一个概述。
我想强调的是,我将提出的每个支柱都基于实用的方法和工具,我将在以后的帖子中详细阐述。如果您已经好奇地想看看他们的实际行动,请随时观看汉密尔顿聚会上的这段视频,我在其中现场展示了他们:
注意:在这篇文章和系列中,我将交替使用人工智能 (AI)、机器学习 (ML) 和数据科学 (DS) 等术语。我们将讨论的概念同样适用于所有这些领域。
现在,让我们探讨每个支柱。
在每个人工智能项目中,我们都有一个想要实现的特定目标,理想情况下是我们想要优化的一组指标。
这些指标可以包括:
- 预测质量指标:准确度、F1 分数、召回率、精确度等……
- 成本指标:实际金额、FLOPS、大小(以 MB 为单位)等…
- 性能指标:训练速度、推理速度等……
我们可以选择一个指标作为“北极星”或创建一个聚合指标。例如:
- 0.7 × F1-Score + 0.3 ×(1 / 推理时间(毫秒))
- 0.6 × AUC-ROC + 0.2 ×(1 / 训练时间(小时))+ 0.2 ×(1 / 云计算成本(美元))
吴恩达(Andrew Ng)制作了一段精彩的短视频。这里解释了有关单一数字评估指标的主题。
一旦我们有了商定的要优化的指标和要满足的一组约束,我们的目标就是构建一个工作流程,在满足我们的约束的同时最大化该指标。
在数据科学和人工智能开发领域,交互性是关键。
作为人工智能工程师(或者我们现在数据科学家的任何头衔),我们需要构建在不同场景下无错误运行的代码。
与传统的软件工程不同,我们的角色不仅仅是编写“只是”有效的代码。我们工作的一个重要方面涉及检查数据并检查模型的输出以及各个处理步骤的结果。
这种交互式探索最常见的环境是 Jupyter Notebooks。
在笔记本中工作使我们能够测试不同的实现、试验新的 API 并检查工作流程的中间结果并根据我们的观察做出决策。这是第二支柱的核心。
然而,尽管我们在日常工作中享受这些好处,但笔记本有时可能包含臭名昭著的糟糕代码,这些代码只能以不平凡的顺序执行。
此外,笔记本电脑的一些探索性部分可能与生产设置无关,因此不清楚如何将这些部分有效地交付生产。
“生产就绪”在不同的环境中可能意味着不同的事情。对于一个组织来说,这可能意味着在指定的时间范围内提供结果。另一方面,它可以指服务的正常运行时间(SLA)。另一方面,这可能意味着代码、模型或工作流程已经过充分的测试以确保可靠性。
这些都是运输可靠产品的重要方面,具体要求可能因地而异。由于我的探索重点是构建人工智能工作流程的“元”方面,因此我想讨论这些定义的一个共同点:将我们的工作流程包装为可服务的 API,并将其部署到可以由外部应用程序或用户查询的环境中。
这意味着我们需要一种方法将代码库的复杂性抽象为可在各种用例中使用的明确定义的接口。让我们考虑一个例子:
想象一下我们开发的 PDF 文件上的复杂 RAG(检索增强生成)系统。它可能包含 10 个不同的部分,每个部分由数百行代码组成。
然而,我们仍然可以将它们包装成一个简单的 API,只有两个主要函数:
- upload_document(文件: PDF) -> document_id: str
- query_document(document_id:str,查询:str,output_format:str)->响应:str
这种抽象允许用户:
- 上传 PDF 文档并接收唯一标识符。
- 使用自然语言询问有关文档的问题。
- 指定响应所需的格式(例如,markdown、JSON、Pandas Dataframe)。
通过提供这个干净的界面,我们有效地隐藏了工作流程的复杂性和实现细节。
拥有一种系统方法将任意复杂的工作流程转换为可部署的 API 是我们的第三个支柱。
此外,我们理想地希望建立一种方法来确保我们的迭代日常工作与我们的生产代码保持同步。
这意味着如果我们对工作流程进行更改(修复错误、添加新的实现,甚至调整配置),我们应该只需单击一个按钮即可将这些更改部署到我们的生产环境中。
我们方法的另一个重要方面是维护模块化和可扩展的代码库。
这意味着我们可以添加新的实现,并针对占用相同逻辑步骤的现有实现进行测试,而无需修改现有代码或覆盖其他配置。
这种方法符合开放封闭原则,即我们的代码对扩展开放,但对修改封闭。它使我们能够:
- 在现有实施的同时引入新的实施
- 轻松比较不同方法的性能
- 保持我们当前工作解决方案的完整性
- 扩展我们工作流程的功能,而不会危及整个系统的稳定性
让我们看一个玩具示例:
在这个例子中,我们可以看到一个模块化且可配置的(伪)代码。通过这种方式,我们可以轻松添加新配置并测试其性能:
一旦我们的代码由多个相互竞争的实现和配置组成,我们就进入了一种我喜欢称之为“工作流程叠加”的状态。在这种状态下,我们可以使用一组特定的配置来实例化并执行工作流程。
我喜欢分层思考并直观地看待事物……
如果我们将模块化和可扩展性更进一步呢?如果我们将这种方法应用于工作流程的整个部分会怎样?
因此,现在,我们可以配置整个预处理、训练或评估步骤,而不是配置这个 LLM 或那个检索器。
让我们看一个例子:
在这里我们看到了整个机器学习工作流程。现在,让我们添加一个新的数据准备实现并放大它:
当我们以这种分层和可视化的方式工作时,我们可以选择工作流程的一部分来改进并添加具有与现有接口相同的输入/输出接口的新实现。
然后,我们可以“放大”到该特定部分,只关注它,而不用担心项目的其余部分。一旦我们对我们的实施感到满意,我们就可以开始测试它以及工作流程中的其他各种配置。
这种方法有几个好处:
- 减少精神负担:一次专注于一个部分,提供清晰度并降低决策的复杂性。
- 更轻松的协作:模块化结构简化了向队友或人工智能助手的任务委派,每个组件都有清晰的界面。
- 可重用性:这些封装的实现可以在不同的项目中使用,可能无需修改其源代码。
- 自我文档化:可视化整个工作流程及其组件可以更轻松地理解项目的结构和逻辑,而无需深入研究不必要的细节。
我发现以下 5 个支柱是“超优化人工智能工作流程”的基础:
- 基于指标的优化:定义和优化明确的、特定于项目的指标,以指导决策和工作流程改进。
- 交互式开发人员体验:利用 Jupyter Notebooks 等工具进行迭代编码和数据检查。
- 生产就绪代码:将完整的工作流程包装到可部署的 API 中并同步开发和生产代码。
- 模块化和可扩展代码:构建代码以轻松添加、交换和测试不同的实现。
- 分层和可视化结构:将项目组织成可视化的分层组件,这些组件可以在不同的抽象级别上独立开发并易于理解。
版权声明
本文为本站原创内容,转载需注明文章来源(https://www.eiefun.com),另:文中部分素材可能会引用自其他平台,如有侵权或其它,请联系 admin@eiefun.com,我们会第一时间配合删除