原文:
towardsdatascience.com/model-deployment-with-fastapi-azure-and-docker-10e5cfbc1f4f
欢迎来到我MLOps 系列文章的第三篇。在 第一篇文章 中,我们探讨了 Docker 以及它是如何简化应用程序打包的。在 第二篇文章 中,我们使用MLflow、Azure和Docker管理机器学习模型。现在,在这一部分的第三部分,我们将通过构建一个FastAPI应用程序来整合所有内容,该应用程序在 Azure 上为我们之前存储的模型提供服务。这使我们能够创建一个全球可访问的预测服务!
什么是 API?
API就像一座桥梁。每次你与 Python 中的库交互时,你都在使用它的 API。它是你可以与之交互的应用程序公开部分,而其背后的所有内容都是隐藏的。
API 通常用于与 Web 应用程序通信,并提供一组返回数据的 URL(你发送带有一些参数的请求并得到响应)。最常见的是,数据以 JSON 或 XML 等易于解析的格式返回。这与返回 HTML 的网站不同,HTML 包含用于渲染页面的信息。使用 API,你只得到原始数据。
一些 API 是公开的,而另一些则是私有的。在构建 API 时,你决定要共享哪些数据,如何共享,以及与谁共享。一切由你决定!大多数 API 使用 HTTP 协议进行通信。你可能听说过遵循共同标准的REST API。主要的 HTTP 方法包括:
GET:检索数据。
POST:提交新数据。
PUT:更新现有数据。
DELETE:删除数据。
这些方法形成了几乎每个 API 都遵循的CRUD(创建、读取、更新、删除)操作。
如何请求 API?
既然我们已经知道了什么是 API,让我们尝试调用一个。我们将使用猫事实 API,它以 JSON 格式返回随机的猫事实。
API 附带文档,解释了可用的端点和参数。端点是请求数据的地址(URL 中的路径)。阅读文档是必不可少的,因为它可以节省你以后的时间。
这里有一个使用 Python 的requests库调用 Cat Facts API 的/fact端点的快速示例:
importrequests response=requests.get("https://catfact.ninja/fact").json()print(response)这个有趣的 API 以 JSON 格式返回关于猫的随机事实:
{'fact':'Cats lap liquid from the underside of their tongue, not from the top.','length':69}使用requests可以帮助你使用 API,但如果你想要构建一个呢?这就是FastAPI发挥作用的地方。它是构建 API 的最佳框架之一。
FastAPI 基础
有许多 Python 框架可以用于构建 API,但在这个教程中,我选择了FastAPI。它是构建 API 中最好和最简单的框架之一,并且它带有许多实用功能,因此您不需要重新发明轮子:
Web 服务器:FastAPI 使用 Uvicorn 为您设置网络服务器。
数据验证:它使用 Pydantic 自动验证数据格式。
自动文档:FastAPI 可以自动生成 API 文档,这使得开发者工作变得非常简单。
您的 FastAPI Python 文件的基本结构
当你使用 FastAPI 构建 API 时,你的.py文件将具有特定的结构,看起来像这样:
importuvicornfromfastapiimportFastAPI#### Here you can define some configurations###app=FastAPI()#### Here you define enpoints###if__name__=="__main__":uvicorn.run(app,host="0.0.0.0",port=8000)app = FastAPI():这创建了一个 FastAPI 实例,它将包含您应用程序的所有功能。
if name==“main”:这确保了当直接执行此文件而不是将其作为模块导入时,代码块才会运行。
uvicorn.run(app, host=“0.0.0.0”, port=8000):这启动了 Uvicorn 网络服务器,指定了主机 IP 和端口。
创建端点
端点是一个 URL,API 用户可以在此处请求或发送数据。我们主要有两种类型:
GET:用于检索数据。
POST:用于发送新数据。
让我们从最简单的可能的GET端点/开始,它将显示一个问候消息:
importuvicornfromfastapiimportFastAPI app=FastAPI()@app.get("/")asyncdefindex():return{"message":"Welcome to the Iris classification API. Use `/predict` to classify a flower."}if__name__=="__main__":uvicorn.run(app,host="0.0.0.0",port=8000)@app.get(“/”):这个装饰器定义了当向
/端点发送 GET 请求时,将调用index()函数。async:FastAPI 允许异步操作。异步函数让您更有效地处理请求,尤其是在处理数据库查询等输入/输出任务时。
让我们添加一个POST端点来提交数据:
importuvicornfromfastapiimportFastAPIfrompydanticimportBaseModel app=FastAPI()className(BaseModel):name:str@app.post("/submit")asyncdefsubmit_name(data:Name):return{"message":f"Hello,{data.name}!"}if__name__=="__main__":uvicorn.run(app,host="0.0.0.0",port=8000)- 这个POST端点接受用户输入数据。并非所有 API 都接受用户数据,但当他们这样做时,数据需要具有特定的结构,这在
Name(BaseModel)类中定义。
使用 Docker 运行 API
为什么使用 Docker?使用 Docker,您不需要在本地机器上安装依赖项。所有内容都在容器中运行,这使得它易于便携和部署。如果您不熟悉 Docker,请查看我之前的文章初学者指南:Docker。
第 1 步:创建一个 Dockerfile
要部署 FastAPI 应用程序,我们首先创建一个 Dockerfile:
# python base image in the container from Docker HubFROM python:3.9-slim RUN apt-get update-y RUN apt-get install nano unzip RUN apt-get install-y python3.10RUN apt install curl-y RUN curl-fsSL https://get.deta.dev/cli.sh|sh# Set the working directoryWORKDIR/app# Copy the current directory contents into the container at /appCOPY./app# Install Python dependencies specified in requirements.txtRUN pip install--no-cache-dir-r requirements.txt# expose the port that uvicorn will run the app onENV PORT=8000EXPOSE8000# execute the command python main.py (in the WORKDIR) to start the app# CMD ["python", "api.py"]CMD["uvicorn","api:app","--host","0.0.0.0","--port","8000"]- 这个 Dockerfile 安装所有依赖项,设置工作目录,并使用 Gunicorn 和 Uvicorn 运行应用程序。
requirements.txt文件将包含必要的 Python 包,如 FastAPI、Uvicorn 等。
第 2 步:构建和运行 Docker 容器
构建 Docker 镜像:
docker build.-t fastapiserver# if your are on mac, use :# docker build - platform=linux/amd64 -t fastapiserver运行 Docker 容器:
docker run-it-v"$(pwd):/app"-p8000:8000-e PORT=8000fastapiserver一旦运行,打开您的浏览器并转到http://0.0.0.0:8000。您应该能看到您的 FastAPI 应用程序正在运行!
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/75d459a33eb8ece3813393b8cce866fe.png
作者
创建一个用于提供 ML 模型的端点
现在,让我们将MLflow与FastAPI结合起来,以提供机器学习模型。我们将加载存储在 Azure 中的模型,并创建一个用于进行预测的端点。
到目前为止,你有两个选择:
你已经遵循了我的上一篇文章,并且你的模型已经序列化并保存在 Azure 中。
你没有遵循我的上一篇文章。你需要知道的是:我们在 Iris 数据集上训练了一个模型,该模型根据四个特征预测花朵的类型。我们使用MLflow序列化此模型并将其存储在 Azure 中。如果你没有这样做,你可以从这个 GitHub 文件夹下载 model.pkl 文件并将其上传到 Azure Blob 存储。
完成上述步骤后,无论你是处于案例 1 还是案例 2,你都需要检索你的Azure 存储信息,并在以下脚本中替换相关值:
importuvicornimportpandasaspdfromfastapiimportFastAPIfrompydanticimportBaseModelfromazure.storage.blobimportBlobClientimportjoblibimportio# Initialize FastAPIapp=FastAPI()# Define the request body format for predictionsclassPredictionFeatures(BaseModel):sepal_length:floatsepal_width:floatpetal_length:floatpetal_width:float# Global variable to store the loaded modelmodel=None# Download the model from Azure Blob Storage directly into memorydefdownload_model():globalmodel# If you want to follow the tutorial but don't have an azure account, just load the model directly from the local file# model = joblib.load("path_to_your_local_model/model.pkl")blob=BlobClient(account_url="https://<your-storage-account>.blob.core.windows.net/",container_name="<your-container>",blob_name="model.pkl",credential="<your-storage-key>")# Download the model as a stream of bytesstream=io.BytesIO()blob.download_blob().download_to_stream(stream)# Load the model directly from the in-memory streamstream.seek(0)model=joblib.load(stream)print("Model loaded from Azure Blob Storage successfully!")# Download the model immediately when the script runsdownload_model()# API Root endpoint@app.get("/")asyncdefindex():return{"message":"Welcome to the Iris classification API. Use `/predict` to classify a flower."}# Prediction endpoint@app.post("/predict")asyncdefpredict(features:PredictionFeatures):# Create input DataFrame for predictioninput_data=pd.DataFrame([{"sepal length (cm)":features.sepal_length,"sepal width (cm)":features.sepal_width,"petal length (cm)":features.petal_length,"petal width (cm)":features.petal_width}])# Predict using the loaded modelprediction=model.predict(input_data)# Get the class number (0, 1, or 2)class_index=int(prediction[0])# Get the class name from the class indexclass_names=['setosa','versicolor','virginica']class_name=class_names[class_index]return{"prediction":class_index,"class_name":class_name}if__name__=="__main__":uvicorn.run(app,host="0.0.0.0",port=8000)download_model()函数从 Azure Blob 存储检索模型并将其加载到内存中。根端点
/提供了一个欢迎信息。/predict端点仍然存在,允许用户将花朵测量值作为 JSON 数据发送给模型以获取预测。在此脚本中,
class用于定义用户必须发送到/predict端点的数据结构。在 FastAPI 中这很重要,因为它有助于验证用于预测的传入数据。
本地测试 API
重新构建并运行你的 Docker 容器,然后访问http://0.0.0.0:8000。使用以下 Python 脚本测试预测端点:
importrequests# Define the API endpointurl="http://0.0.0.0:8000/predict"# Define the input datadata={"sepal_length":5.1,"sepal_width":3.5,"petal_length":1.4,"petal_width":0.2}# Make a POST request to the APIresponse=requests.post(url,json=data)# Check if the request was successfulifresponse.status_code==200:# Print the prediction resultprediction=response.json()print("Prediction:",prediction)else:print(f"Failed to get a prediction. Status code:{response.status_code}")print("Response:",response.text)这将根据输入数据返回预测的花朵分类。我们的花朵属于类别 0,即**-setosa**。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/53c964fe87ce680fef3ca406a386f45a.png
作者
这听起来不错,但这里有个问题:我们的 API 目前仅在本地上可用。如果有人在世界另一端想要用它来预测他们花朵的分类怎么办?你猜对了——我们需要将这个 API 部署到云端。让我们将其部署到 Azure,这样全世界的花迷都可以使用它!
将 FastAPI 部署到 Azure
在开始之前,确保你准备好了订阅 ID和其他相关细节。你可以从 Azure 门户中获取这些信息。接下来,从我的 GitHub克隆必要的文件,并更新deploy.sh脚本。
更新完信息后,只需运行deploy.sh脚本即可自动化整个设置过程。虽然 Azure 提供了图形界面来设置资源,但此脚本通过单个命令简化了所有操作。
下面是运行deploy.sh脚本时你正在做的事情的分解:
1. 登录并设置订阅:首先,登录到你的 Azure 账户,并设置资源部署的订阅。
az login az accountset--subscription $SUBSCRIPTION_ID2. 创建资源组:此组将组织您为 FastAPI 部署的所有资源。如果您已经有了资源组,您可以跳过此步骤或在脚本中将其注释掉。
az group create--name $RG_NAME--location<location>3. 将 Docker 镜像推送到 Azure 容器注册库(ACR):在推送 Docker 镜像之前,获取您的 ACR 凭证并登录。
export ACR_USERNAME=$(az acr credential show--name $ACR_NAME--query"username"--output tsv)export ACR_PASSWORD=$(az acr credential show--name $ACR_NAME--query"passwords[0].value"--output tsv)docker login $ACR_NAME.azurecr.io--username"$ACR_USERNAME"--password"$ACR_PASSWORD"# Push the imagesdocker tag $DOCKER_IMAGE_NAME $ACR_NAME.azurecr.io/$DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG docker push $ACR_NAME.azurecr.io/$DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG4. 创建应用服务计划:设置应用服务计划以在 Azure 上托管您的 FastAPI 服务器。
az appservice plan create--name $ASP_NAME--resource-group $RG_NAME--sku B1--is-linux--location $RG_LOCATION5. 使用 FastAPI 容器部署 Web 应用:将 ACR 中的 Docker 镜像部署到您的 Web 应用。
az webapp create--resource-group $RG_NAME--plan $ASP_NAME--name $WEB_APP_NAME--deployment-container-image-name $ACR_NAME.azurecr.io/$DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG6. 配置 Web 应用以使用容器注册库:设置应用以拉取 Docker 镜像,并配置环境变量。
az webapp config containerset--name $WEB_APP_NAME--resource-group $RG_NAME--docker-custom-image-name $ACR_NAME.azurecr.io/$DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG--docker-registry-server-url https://$ACR_NAME.azurecr.io--docker-registry-server-user $ACR_USERNAME--docker-registry-server-password $ACR_PASSWORD--enable-app-service-storage true az webapp config appsettingsset--resource-group $RG_NAME--name $WEB_APP_NAME--settings WEBSITES_PORT=$MLFLOW_PORT部署脚本完成后,检查 Azure 门户以确认您的 API 已上线并可访问。导航到应用服务以获取您已部署的 FastAPI Web 应用的 URL。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8c966f99f35170c776009b733e99bb71.png
作者提供
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4c8a178092a258b06a0bcdef87396656.png
作者提供
恭喜!您的 API 现在已上线,世界上任何地方的人都可以使用它来根据特征对花卉进行分类。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/76bd57ed40adc12bc7aa156f4ebee49f.png
作者提供
最终测试:访问已部署的 API
让我们使用与之前相同的 Python 请求脚本来测试已部署的 API,但这次将本地 URL 替换为 Azure 的实际 URL。您应该能看到返回的预测结果!
结论
这篇文章到此结束。您已成功将 FastAPI 应用部署到 Azure,并且它准备好为任何拥有花卉数据的人提供服务。在本系列的下一部分,我们将通过添加文档、单元测试,以及使用CI/CD和GitHub Actions自动化部署来改进 API。敬请期待!
感谢您的阅读!
***注意:*某些部分的文章最初是用法语撰写的,并在 ChatGPT 的帮助下翻译成英语。
如果您觉得这篇文章信息丰富且有帮助,请毫不犹豫地👏并关注我在Medium | LinkedIn上的账号。