使用Poetry和Docker为AWS Lambda打包模型

2024年02月05日 由 alex 发表 357 0

在本文中我将讨论一个技术性更强的话题,下面我将介绍将本地训练的模型成功部署到 Lambda 的步骤.


设置模型架构


如果你还没有一个首选的 Python 软件包管理器/环境管理器工具,请允许我为 Poetry 做个介绍。有些人喜欢 venv 或其他的工具,这没有问题,但 Poetry 有一些不错的额外功能,我认为值得一用。


我想强调的是,Poetry 可以非常容易地打包你的项目,这样你创建的内部模块就可以被调用,而无需大费周章。这意味着你不必与 "Python 说那个模块不存在 "的争论作斗争,我相信我们中的许多人都很熟悉这种情况。


这里嵌入的示例只是像这样一个项目的 pyproject.toml 文件的头部--注意以 packages 开头的一行,它告诉 env 在其导入中包含我创建的包。这样我就可以调用 new_package.tools 导入项目中的任何内容,即使这些内容不在直接的父目录或其他目录中。


[tool.poetry]
name = "new_package"
version = "0.1.0"
description = "What this package is gonna do"
authors = [
    "Stephanie Kirmer <stephanie@stephaniekirmer.com>",
]
packages = [{ include = "new_package"}]
include = [{ path = "tests", format = "sdist" }]
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
# Requirements
[tool.poetry.dependencies]
python = ">=3.9, <4.0"


你需要构建一个 "处理程序"。这到底是什么?它只是一个函数,接受传递给 Lambda 的 JSON 对象,并以 JSON 有效负载的形式返回模型的结果。因此,推理管道要做的所有事情都需要在这个函数中调用。


在我的项目中,我有一整套特征工程函数的代码库:涉及语义嵌入、聚合、regexes 等大量内容。我将它们整合到了一个 FeatureEngineering 类中,该类有很多私有方法,但只有一个公有方法 feature_eng。因此,从传递给模型的 JSON 开始,该方法可以运行将数据从 "原始 "转换为 "特征 "所需的所有步骤。我喜欢这种设置方式,因为它从处理函数本身抽象出了许多复杂性。我可以直接调用


fe = FeatureEngineering(input=json_object)
processed_features = fe.feature_eng()


后半部分是推理工作,在我的案例中,这是一个独立的类。我采用了一种非常类似的方法,它只接收一些参数。


ps = PredictionStage(features=processed_features)
predictions = ps.predict(
    feature_file="feature_set.json",
    model_file="classifier",
)


类的初始化接受特征工程类方法的结果,因此握手的定义非常清晰。然后,预测方法会接收两个项目:特征集(列出所有特征名称的 JSON 文件)和模型对象,在我的例子中,模型对象是我已经训练并保存的 CatBoost 分类器。我使用的是原生的 CatBoost 保存方法,但无论你使用什么方法和什么模型算法都没有问题。重点是,这个方法抽象掉了一堆底层的东西,并巧妙地返回了预测对象,这就是我的 Lambda 运行时要给你的东西。


因此,概括地说,我的 "处理程序 "函数本质上就是这样:


def lambda_handler(json_object, _context):
  fe = FeatureEngineering(input=json_object)
  processed_features = fe.feature_eng()
  ps = PredictionStage(features=processed_features)
  predictions = ps.predict(
      feature_file="feature_set.json",
      model_file="classifier",
  )
  return predictions.to_dict("records")


构建 Docker 映像


下面,我将向你展示这种情况下的 dockerfile 骨架。首先,我们从 AWS 获取 Lambda 的正确基础镜像。接下来,我们需要设置将在 Docker 映像中使用的文件结构。


dockerfile 的开头


FROM public.ecr.aws/lambda/python:3.9
ARG YOUR_ENV
ENV NLTK_DATA=/tmp
ENV HF_HOME=/tmp


在这个项目中,你拷贝过来的任何东西都会存放在 /tmp 文件夹中,所以如果你的项目中有软件包试图在任何时候保存数据,你就需要将它们引导到正确的地方。


你还需要确保将 Poetry 正确安装到 Docker 镜像中,这样才能让你精心策划的依赖项正常工作。在这里,我设置了版本,并告诉 pip 在继续之前安装 Poetry。


ENV YOUR_ENV=${YOUR_ENV} \
  POETRY_VERSION=1.7.1
ENV SKIP_HACK=true
RUN pip install "poetry==$POETRY_VERSION"


下一个问题是确保你的项目在本地使用的所有文件和文件夹都能正确地添加到这个新镜像中--Docker 复制有时会令人恼火地将目录扁平化,所以如果你构建了这个镜像,却开始出现 "找不到模块"(module not found)的问题,请检查以确保这不会发生在你身上。提示:复制完成后,在 dockerfile 中添加 RUN ls -R,看看目录是什么样子的。你可以在 Docker 中查看这些日志,也许会发现一些问题。


此外,确保复制了所有需要的内容!这包括 Lambda 文件、Poetry 文件、功能列表文件和模型。除非你把这些文件存储在其他地方(比如 S3),并让 Lambda 在运行时下载,否则所有这些都是需要的。


WORKDIR ${LAMBDA_TASK_ROOT}
COPY /poetry.lock ${LAMBDA_TASK_ROOT}
COPY /pyproject.toml ${LAMBDA_TASK_ROOT}
COPY /new_package/lambda_dir/lambda_function.py ${LAMBDA_TASK_ROOT}
COPY /new_package/preprocessing ${LAMBDA_TASK_ROOT}/new_package/preprocessing
COPY /new_package/tools ${LAMBDA_TASK_ROOT}/new_package/tools
COPY /new_package/modeling/feature_set.json ${LAMBDA_TASK_ROOT}/new_package
COPY /data/models/classifier ${LAMBDA_TASK_ROOT}/new_package


最后要做的是安装 Poetry 环境,然后设置处理程序的运行。这里有几个重要的标志,包括--no-dev,它告诉 Poetry 不要在你的环境中添加任何开发工具,比如 pytest 或 black。


dockerfile 的结尾


RUN poetry config virtualenvs.create falseconfig virtualenvs.create false
RUN poetry install --no-dev
CMD [ "lambda_function.lambda_handler" ]


就是这样,你已经有了你的 dockerfile!现在是构建它的时候了。


  1. 确保 Docker 已安装并运行在你的电脑上。这可能需要一点时间,但并不难。
  2. 进入 dockerfile 所在的目录,也就是项目的顶层,然后运行 docker build 。让 Docker 做它该做的事,当它完成构建后,就会停止返回信息。你可以在 Docker 应用程序控制台看到它是否已成功构建。
  3. 回到终端,运行 docker image ls,你就会看到刚刚构建的新镜像,它还附有一个 ID 号。
  4. 再次从终端运行 docker run -p 9000:8080 IMAGE ID NUMBER,并填入步骤 3 中的 ID 号。现在,你的 Docker 镜像将开始运行!
  5. 打开一个新的终端(Docker 会连接到你的旧窗口,就放在那里吧),你可以向现在通过 Docker 运行的 Lambda 传递一些信息。我个人喜欢将输入内容放入一个 JSON 文件,如 lambda_cases.json,然后像这样运行:


curl -d @lambda_cases.json http://localhost:9000/2015-03-31/functions/function/invocations@lambda_cases.json http://localhost:9000/2015-03-31/functions/function/invocations


如果终端的结果与模型预测的一致,那么你就可以开始工作了。如果不是,请检查错误,看看可能出了什么问题。在一切顺利运行之前,你可能需要调试一下,解决一些问题,但这都是过程的一部分。


部署到 AWS 并进行测试


下一阶段将在很大程度上取决于你的组织设置,我不是DevOps专家,所以只能含糊其辞。我们的系统使用 AWS Elastic Container Registry(ECR)来存储构建的 Docker 镜像,Lambda 从那里访问它。


当你对上一步的 Docker 镜像完全满意时,你需要使用下面的格式再构建一次。第一个标志表示 Lambda 使用的平台。(在 -t 标志后面的项目是 AWS ECR 映像的路径,请填写正确的账号、地区和项目名称。


docker build . --platform=linux/arm64 -t accountnumber.dkr.ecr.us-east-1.amazonaws.com/your_lambda_project:latest


之后,你应该在终端中对亚马逊 ECR 注册表进行身份验证,可能使用 aws ecr get-login-password 命令,并使用适当的标志。


最后,你就可以将新的 Docker 镜像推送到 ECR 了:


docker push accountnumber.dkr.ecr.us-east-1.amazonaws.com/your_lambda_project:latest


如果你的身份验证正确,这应该只需要片刻时间。


在准备就绪之前还有一个步骤,那就是在 AWS UI 中设置 Lambda。登录你的 AWS 账户,找到 "Lambda "产品。


12


弹出左侧菜单,找到“功能”。


13


你可以在这里找到你的特定项目。如果你尚未设置 Lambda,请点击“创建函数”并按照说明根据容器映像创建新函数。


14


如果你已经创建了一个函数,请找到该函数。从那里,你所需要做的就是点击“部署新映像”。无论它是一个全新的功能还是只是一个新镜像,请确保你选择的平台与你在 Docker 构建中所做的相匹配! (还记得那个别针吗?)


15


最后一个任务,也是我在此阶段继续解释的原因,是在实际的 Lambda 环境中测试你的图像。这可能会出现你在本地测试中没有遇到的错误!翻转到“测试”选项卡,然后通过输入反映模型将在生产中看到的内容的 JSON 正文来创建新测试。运行测试,并确保你的模型符合预期。


16


如果它有效,那么你就做到了!你已经部署了模型。

文章来源:https://medium.com/towards-data-science/using-poetry-and-docker-to-package-your-model-for-aws-lambda-cd6d448eb88f
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消