使用 Metaflow、AWS 和 Weights Biases 优化物体检测
原文towardsdatascience.com/streamlining-object-detection-with-metaflow-aws-and-weights-biases-b44a14cb2e11?sourcecollection_archive---------1-----------------------#2024-07-19如何为物体检测创建生产级管道https://medium.com/ed.izaguirre?sourcepost_page---byline--b44a14cb2e11--------------------------------https://towardsdatascience.com/?sourcepost_page---byline--b44a14cb2e11-------------------------------- Ed Izaguirre·发表于Towards Data Science ·14 分钟阅读·2024 年 7 月 19 日–https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/c157f2b7af842d1ff59de906324c2968.png项目流程概述。图片来自作者。目录介绍或标题中的内容没有 Ops 的 MLOps 现实有效管理依赖关系如何调试生产流程找到合适的步长要点总结参考文献相关链接GitHub 仓库链接到讨论该项目开发版本的早期文章介绍或标题中的内容在数据科学职位名称的世界中导航可能令人不知所措。以下是我最近在 LinkedIn 上看到的一些例子数据科学家机器学习工程师MLOps 工程师数据科学家/机器学习工程师机器学习性能工程师…话题还可以继续深入。让我们关注两个关键角色数据科学家和机器学习工程师。根据 Chip Huyen 在她的书《Introduction to Machine Learning Interviews》中的描述[1]数据科学的目标是生成商业洞察而机器学习工程的目标是将数据转化为产品。这意味着数据科学家往往更擅长统计学而机器学习工程师则通常是更优秀的工程师。机器学习工程师肯定需要了解机器学习算法而许多数据科学家则可以在不涉及机器学习的情况下完成他们的工作。明白了。所以数据科学家必须懂得统计学而机器学习工程师则必须了解机器学习算法。但如果数据科学的目标是产生商业洞察并且到 2024 年最强大的算法特别是深度学习往往能够产生最佳洞察那么两者之间的界限就变得模糊了。或许这也能解释我们之前看到的数据科学家/机器学习工程师这一职位的结合Huyen 接着说随着公司对机器学习的采用逐步成熟可能希望拥有一个专门的机器学习工程团队。然而随着越来越多的预构建和预训练模型可以即插即用开发机器学习模型可能不再需要那么多的机器学习知识机器学习工程与数据科学将更加统一。这是 2020 年写的。到 2024 年机器学习工程和数据科学之间的界限确实变得模糊了。那么如果实现机器学习模型的能力不是分界线那么究竟是什么呢这一界限因实践者而异。如今典型的数据科学家和机器学习工程师的区别如下数据科学家使用 Jupyter notebook从未听说过 AirflowKaggle 专家管道由手动按正确顺序执行代码单元组成擅长超参数调优Docker夏天穿的好鞋专注于开发。机器学习工程师编写 Python 脚本听说过 Airflow但不喜欢它支持 PrefectKaggle 中级选手自动化管道模型调优交给数据科学家Docker 爱好者。专注于生产环境。在大公司中数据科学家开发机器学习模型来解决业务问题然后交给机器学习工程师。工程师将这些模型投入生产并进行部署确保其可扩展性和鲁棒性。简而言之今天数据科学家和机器学习工程师之间的根本区别不在于谁在使用机器学习而在于你是否专注于开发还是生产环境。但如果你没有一家大公司而是处于初创公司或小型公司的情况下预算只能雇佣一位或几位数据科学团队成员呢他们可能希望招聘能够兼做数据科学家/机器学习工程师的人员为了成为这个神话般的“全栈数据科学家”我决定将我之前的一个项目使用 RetinaNet 和 KerasCV 进行物体检测进行生产化请参阅上述链接获取相关文章和代码。原始项目是使用 Jupyter notebook 完成的但存在一些不足之处以前没有模型版本控制、数据版本控制甚至代码版本控制。如果我的 Jupyter notebook 在某次运行时有效而在随后的运行中无效那时没有任何系统化的方法可以回到有效的脚本/模型Ctrl ZKaggle 中的保存 notebook 选项模型评估相当简单使用了 Matplotlib 和一些 KerasCV 图表。没有存储评估结果。我们的计算资源受限于 Kaggle 免费的 20 小时 GPU。无法使用更大的计算实例也不能并行训练多个模型。该模型从未部署到任何端点因此无法在 Jupyter notebook 以外的地方进行预测没有业务价值。为了完成这个任务我决定尝试使用 Metaflow。Metaflow 是一个开源的机器学习平台旨在帮助数据科学家训练和部署机器学习模型。Metaflow 主要有两个功能一个工作流编排工具。Metaflow 将一个工作流分解为多个步骤。将一个 Python 函数转化为 Metaflow 步骤非常简单只需在函数上方添加step装饰器即可。Metaflow 并不一定具备像 Airflow 这样的工作流工具所提供的所有功能但它简单、符合 Python 风格并且可以设置使用 AWS Step Functions 作为外部编排器。此外使用像 Airflow 或 Prefect 与 Metaflow 配合使用也是完全没问题的。一个基础设施抽象工具。这正是 Metaflow 的真正优势所在。通常数据科学家需要手动设置基础设施将模型训练任务从他们的笔记本电脑发送到 AWS。这可能需要了解基础设施方面的知识如 API 网关、虚拟私有云VPC、Docker/Kubernetes、子网掩码等。听起来这更像是机器学习工程师的工作然而通过使用 Cloud Formation 模板基础设施即代码文件和batchMetaflow 装饰器数据科学家能够以简单可靠的方式将计算任务发送到云端。本文详细介绍了我使用 Metaflow、AWS 和 Weights Biases 生产化物体检测模型的历程。我们将在这个过程中探讨四个关键的学习经验“没有 Ops 的 MLOps”现实有效的依赖管理生产环境工作流的调试策略优化工作流结构通过分享这些见解我希望能指导你们这些数据从业者从开发转向生产相关的工作突出在这一过程中遇到的挑战和解决方案。在深入具体内容之前让我们先来看一下我们 Metaflow 管道的高层结构。这将为你提供一个鸟瞰视图帮助你了解本文中讨论的工作流frommetaflowimportFlowSpec,Parameter,step,current,batch,S3,environmentclassmain_flow(FlowSpec):stepdefstart(self): Start-up: check everything works or fail fast! self.next(self.augment_data_train_model)batch(gpu1,memory8192,imagedocker.io/tensorflow/tensorflow:latest-gpu,queuejob-queue-gpu-metaflow)stepdefaugment_data_train_model(self): Code to pull data from S3, augment it, and train our model. self.next(self.evaluate_model)stepdefevaluate_model(self): Code to evaluate our detection model, using Weights Biases. self.next(self.deploy)stepdefdeploy(self): Code to deploy our detection model to a Sagemaker endpoint self.next(self.end)stepdefend(self): The final step! print(All done. \n\n Congratulations! Plants around the world will thank you. \n)returnif__name____main__:main_flow()这个结构构成了我们生产级目标检测流水线的骨架。Metaflow 是 Python 风格的使用装饰器将函数标记为流水线中的步骤处理依赖关系管理并将计算任务移到云端。步骤通过self.next()命令按顺序执行。更多关于 Metaflow 的内容请参见 文档。没有运维的 MLOps 现实Metaflow 的一个承诺是数据科学家应该能够专注于他们关心的事情通常是模型开发和特征工程想想 Kaggle同时将他们不关心的事情计算任务在哪儿运行数据存储在哪儿等等抽象化。对此有一句话“没有运维的 MLOps”。我以为这意味着我能够抽象化 MLOps 工程师的工作而无需自己学习或做太多运维工作。我以为我可以不用了解 Docker、CloudFormation 模板、EC2 实例类型、AWS 服务配额、Sagemaker 端点以及 AWS 批量配置。不幸的是这是天真了。我意识到许多 Metaflow 教程中链接的 CloudFormation 模板并没有提供从 AWS 配置 GPU 的方法。这是在云端做数据科学的一个基本部分因此缺乏文档令我感到惊讶。我不是第一个对缺乏文档感到疑惑的人以下是一个代码片段演示了在 Metaflow 中将作业发送到云端的样子pip(libraries{tensorflow:2.15,keras-cv:0.9.0,pycocotools:2.0.7,wandb:0.17.3})batch(gpu1,memory8192,imagedocker.io/tensorflow/tensorflow:latest-gpu,queuejob-queue-gpu-metaflow)environment(vars{S3_BUCKET_ADDRESS:os.getenv(S3_BUCKET_ADDRESS),WANDB_API_KEY:os.getenv(WANDB_API_KEY),WANDB_PROJECT:os.getenv(WANDB_PROJECT),WANDB_ENTITY:os.getenv(WANDB_ENTITY)})stepdefaugment_data_train_model(self): Code to pull data from S3, augment it, and train our model. 注意指定所需库和必要环境变量的重要性。因为计算任务是在云端运行的它将无法访问你本地计算机上的虚拟环境或.env文件中的环境变量。使用 Metaflow 装饰器来解决这个问题既优雅又简单。确实你不必成为 AWS 专家才能在云端运行计算任务但不要指望仅仅安装 Metaflow使用默认的 CloudFormation 模板就能成功。没有运维的 MLOps实在太美好难以置信也许这个短语应该是没有运维的 MLOps在学习了一些运维之后。有效管理依赖关系将一个开发项目转变为生产项目时最重要的考虑因素之一是如何管理依赖关系。依赖关系指的是 Python 包例如 TensorFlow、PyTorch、Keras、Matplotlib 等。依赖管理类似于管理食谱中的食材以确保一致性。一个食谱可能会说“加入一汤匙盐”。这在某种程度上是可重复的但有经验的读者可能会问“Diamond Crystal 还是 Morton”指定使用的盐的确切品牌可以最大程度地提高食谱的可重复性。类似地在机器学习中依赖管理有不同的层次使用requirements.txt文件。这种简单的方式列出了所有带有固定版本的 Python 包。它工作得相当不错但也有局限性虽然你可以固定这些高层依赖但无法固定任何传递依赖依赖的依赖。这使得创建可重复的环境变得非常困难并且因为包被下载和安装运行时也会变慢。例如pinecone4.0.0langchain0.2.7python-dotenv1.0.1pandas2.2.2streamlit1.36.0iso-6390.4.5prefect2.19.7langchain-community0.2.7langchain-openai0.1.14langchain-pinecone0.1.1这工作得相当不错但也有局限性虽然你可以固定这些高层依赖但无法固定任何传递依赖依赖的依赖。这使得创建可重复的环境变得非常困难并且因为包被下载和安装运行时也会变慢。使用 Docker 容器。这是黄金标准。它封装了整个环境包括操作系统、库、依赖项和配置文件使其非常一致且可重复。不幸的是使用 Docker 容器可能会比较复杂尤其是当数据科学家没有平台使用经验时。Metaflow[pypi/conda](https://docs.metaflow.org/scaling/dependencies/libraries)装饰器在这两种选项之间找到了一个折中方案既轻量且简单便于数据科学家使用同时比requirements.txt文件更具鲁棒性和可重复性。这些装饰器基本上执行以下操作为流程中的每一步创建独立的虚拟环境。锁定 Python 解释器版本而简单的requirements.txt文件做不到这一点。为每一步解析完整的依赖图并将其锁定以确保稳定性和可重复性。这个锁定的图被存储为元数据便于审计和一致的环境重建。将本地解析的环境传输到远程执行即使远程环境的操作系统和 CPU 架构与客户端不同。这比仅仅使用requirements.txt文件要好得多而且不需要数据科学家额外学习任何内容。让我们回顾一下训练步骤看看一个示例pypi(libraries{tensorflow:2.15,keras-cv:0.9.0,pycocotools:2.0.7,wandb:0.17.3})batch(gpu1,memory8192,imagedocker.io/tensorflow/tensorflow:latest-gpu,queuejob-queue-gpu-metaflow)environment(vars{S3_BUCKET_ADDRESS:os.getenv(S3_BUCKET_ADDRESS),WANDB_API_KEY:os.getenv(WANDB_API_KEY),WANDB_PROJECT:os.getenv(WANDB_PROJECT),WANDB_ENTITY:os.getenv(WANDB_ENTITY)})stepdefaugment_data_train_model(self): Code to pull data from S3, augment it, and train our model. 我们所要做的就是指定库和版本Metaflow 会处理剩下的部分。不幸的是事情并非完全顺利。我的个人笔记本电脑是 Mac但 AWS Batch 中的计算实例采用的是 Linux 架构。这意味着我们必须为 Linux 机器创建隔离的虚拟环境而不是 Mac。这就需要所谓的交叉编译。我们只有在处理.whl二进制包时才能进行交叉编译。我们不能在尝试交叉编译时使用.tar.gz或其他源代码发行版。这是pip的一个特点而不是 Metaflow 的问题。使用conda装饰器是有效的conda似乎能够解决pip不能解决的问题但如果我想利用 GPU 进行计算则必须使用 conda 中的tensorflow-gpu包这也带来了自己的问题。虽然有一些解决方法但它们为我希望保持简洁的教程增加了太多复杂性。因此我实际上不得不选择了pip install -r requirements.txt使用了自定义 Pythonpip装饰器来实现。虽然不太理想但它确实有效。如何调试生产环境中的流程最初使用 Metaflow 感觉有些慢。每次步骤失败时我都需要添加打印语句并重新运行整个流程——这是一个耗时且代价高昂的过程尤其是在计算密集型步骤中。一旦我发现可以将流程变量作为工件存储并且之后可以在 Jupyter notebook 中访问这些工件的值我的迭代速度大大提升。例如在处理model.predict调用的输出时我将变量作为工件存储以便于调试。以下是我如何做到的imageexample[images]self.imagetf.expand_dims(image,axis0)# Shape: (1, 416, 416, 3)y_predmodel.predict(self.image)confidencey_pred[confidence][0]self.confidence[confforconfinconfidenceifconf!-1]self.y_predbounding_box.to_ragged(y_pred)在这里model是我经过充分训练的目标检测模型image是一张示例图像。当我在处理这个脚本时我遇到了处理model.predict调用输出的问题。输出是什么类型的输出的结构是什么样的拉取示例图像的代码是否有问题为了检查这些变量我使用self._语法将它们作为工件存储。任何可以被pickle序列化的对象都可以作为 Metaflow 工件存储。如果你跟随我的教程这些工件将被存储在 Amazon S3 存储桶中供以后引用。为了检查示例图像是否正确加载我可以在我的本地计算机的同一代码库中打开 Jupyter notebook并通过以下代码访问该图像importmatplotlib.pyplotasplt latest_runFlow(main_flow).latest_run steplatest_run[evaluate_model]sample_imagestep.task.data.image sample_imagesample_image[0,:,:,:]one_image_normalizedsample_image/255# Display the image using matplotlibplt.imshow(one_image_normalized)plt.axis(off)# Hide the axesplt.show()在这里我们获取流程的最新运行并通过在 Flow 调用中指定main_flow来确保获取到流程的信息。我存储的工件来自evaluate_model步骤因此我指定了这一步骤。我通过调用.data.image获取图像数据。最后我们可以绘制图像来检查并查看我们的测试图像是否有效或者是否在管道的某个环节被破坏了https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/190557d883fea877399a116a9732e6e1.png在我的 Jupyter notebook 中输出的图像。图像来源作者。很棒这和从 PlantDoc 数据集中下载的原始图像一致尽管颜色看起来有些奇怪。为了查看我们物体检测模型的预测结果我们可以使用以下代码latest_runFlow(main_flow).latest_run steplatest_run[evaluate_model]y_predstep.task.data.y_predprint(y_pred)https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8d79e9da2d852fa191d977303249ae23.png来自物体检测模型的预测。图片由作者提供。输出结果似乎表明这个图像没有预测的边界框。这一点很有意思可能有助于解释某个步骤为何表现异常或出现错误。所有这些都可以通过一个简单的 Jupyter 笔记本完成这是所有数据科学家都很熟悉的。那么何时应将变量作为工件存储在 Metaflow 中呢Ville Tuulos 给出了一个启发式的方法[2]一条经验法则使用实例变量例如 self来存储任何可能在步骤外部有用的数据和对象。仅将本地变量用于中间的临时数据。如果不确定使用实例变量因为它们使调试更加容易。如果你在使用 Metaflow请从我的经验中吸取教训充分利用工件和 Jupyter 笔记本使调试在生产级项目中变得轻松。关于调试的另一个注意事项如果一个流程在某个特定步骤失败且你希望从该失败步骤重新运行流程可以在 Metaflow 中使用resume命令。这样可以加载之前步骤的所有相关输出而无需重新执行它们从而节省时间。直到我尝试了Prefect才意识到那里并没有一个简单的方法来做到这一点。寻找合适的步骤大小Goldilocks步骤的大小应该是多少理论上你可以把整个脚本塞进一个巨大的pull_and_augment_data_and_train_model_and_evaluate_model_and_deploy步骤中但这样并不可取。如果流程中的某个部分失败你就不能轻松使用resume功能跳过重新运行整个流程。相反将脚本拆分为一百个微小步骤也是可能的但这同样不推荐。存储工件和管理步骤会带来一定的开销拥有一百个步骤会占据大部分执行时间。为了找到一个合适的步骤大小Tuulos 告诉我们一条经验法则将工作流结构化为逻辑清晰、容易解释和理解的步骤。如果不确定倾向于选择较小的步骤。小步骤往往比大步骤更容易理解和调试。最初我将我的流程结构设计为这些步骤增强数据训练模型评估模型部署模型在增强数据后我需要将数据上传到一个 S3 存储桶然后在train步骤中下载增强后的数据用于模型训练原因有两个augment步骤将在我的本地笔记本上进行而train步骤则会发送到云端的 GPU 实例。Metaflow 的工件通常用于在步骤之间传递数据但它无法处理 TensorFlow 数据集对象因为它们不能被 pickle。于是我将它们转换为tfrecords格式并上传到 S3。这个上传/下载过程花费了很长时间。因此我将数据增强和训练步骤合并为一个步骤。这样减少了流程的运行时间和复杂性。如果你感兴趣可以查看我 GitHub 仓库中的separate_augement_train分支该版本包含了分开的步骤。主要收获在本文中我讨论了在将我的目标检测项目投入生产时所经历的一些高峰和低谷。简要总结如下你必须学习一些操作才能在没有操作的情况下实现 MLOps。但在学习了一些基础的设置后你将能够仅使用 Python 装饰器将计算任务发送到 AWS。本文附带的代码库介绍了如何在 AWS 中配置 GPU因此如果这是你的目标之一请仔细研究。依赖管理是生产中的一个关键步骤。requirements.txt文件是最基本的要求Docker 是黄金标准而 Metaflow 提供了一条中间路径适用于许多项目。只不过这个项目不适用不幸的是。在 Metaflow 中使用工件和 Jupyter 笔记本可以方便地进行调试。使用resume功能可以避免重新运行时间或计算密集型的步骤。在将脚本拆分为适合 Metaflow 流程的步骤时尽量将步骤拆分成合理大小的小步骤倾向于使用较小的步骤。但如果开销过大也不要害怕合并步骤。这个项目仍然有一些我希望改进的方面。一个方面是添加更多的数据这样我们就能在更多种类的植物上检测疾病。另一个方面是为项目添加前端允许用户上传图片并按需获取物体检测。像 Streamlit 这样的库非常适合这个功能。最后我希望最终模型的性能能达到最先进的水平。Metaflow 具备并行训练多个模型的能力这将有助于实现这一目标。不幸的是这需要大量的计算资源和资金但这是任何最先进模型所必需的。参考文献[1] C. Huyen, 《机器学习面试简介》(2021), 自出版[2] V. Tuulos, 《高效的数据科学基础设施》 (2022), Manning 出版社