用于机器学习的 Podman 简介:简化 MLOps 工作流程
用于机器学习的 Podman 简介:简化 MLOps 工作流程
一种轻量级、无守护程序的 Docker Desktop 替代方案,可简化容器管理,从而实现机器学习模型的快速训练、评估和部署
IT 领域的每个开发人员和运营工程师都熟悉 Docker 来构建和部署应用程序,无论是在本地还是在云中。但是,作为开发人员或机器学习运营工程师,您可能希望优化资源、增强安全性并改进系统集成。Podman 提供了一个引人注目的替代方案。它是一个免费的开源工具,可替代 Docker 和 Docker Desktop。
在本教程中,我们将探讨什么是 Podman、Podman 和 Docker 之间的区别,以及如何安装和使用 Podman。此外,我们还将介绍如何使用 Dockerfile 和 Podman 命令在本地训练、评估和部署机器学习模型。
Podman介绍
Podman 是一种开源容器管理工具,旨在为开发人员和机器学习工程师提供无缝且安全的体验。与 Docker 不同,Podman 无守护进程运行,允许用户将容器作为无根进程运行,从而提高了安全性和灵活性。此关键功能使 Podman 无需 root 权限即可运行容器,从而最大限度地减少潜在漏洞。
Podman 与 OCI(开放容器计划)标准完全兼容,确保使用 Podman 创建的容器和映像可以轻松与其他符合 OCI 标准的工具和平台集成,例如 runc、Buildah 和 Skopeo。此外,Podman 还支持创建和管理 Pod,Pod 是共享同一网络命名空间的容器组,类似于 Kubernetes Pod。
使用 Podman 最好的方面之一是它提供了类似于 Docker 的体验。命令行界面可与 Docker 的界面相媲美,您也可以从 Docker Hub 提取映像。这种相似性使熟悉 Docker 的用户能够轻松过渡,同时提供满足容器化应用程序开发和部署不断变化的需求的高级功能
Docker 与 Podman 比较
Docker 和 Podman 是著名的容器管理工具,每个工具都提供独特的特性和功能。此比较将检查它们的差异并帮助您决定哪一个最适合您的需求。
码头工人 | 豆荚 | |
---|---|---|
建筑 | Docker 使用客户端-服务器架构和名为 dockerd 的守护进程。 | Podman 是无守护程序的,使用 fork-exec 模型,这增强了安全性和简单性。 |
安全 | 默认情况下,Docker 以 root 身份运行容器,这可能会带来安全风险。 | Podman 默认支持无根容器,降低安全风险。 |
映像管理 | Docker 可以使用自己的工具构建和管理容器镜像。 | Podman 依靠 Buildah 构建镜像,并且可以从 Docker 注册表运行镜像。 |
兼容性 | Docker 被广泛使用并与许多 CI/CD 工具集成。 | Podman 提供与 Docker 兼容的 CLI,使用户无需更改工作流即可更轻松地进行切换。 |
容器编排 | Docker 支持 Docker Swarm 和 Kubernetes 进行编排。 | Podman 不支持 Docker Swarm,但可以使用 Pod 与 Kubernetes 一起工作。 |
平台支持 | Docker 在 Linux、macOS 和 Windows(使用 WSL)上本机运行。 | Podman 还支持 Linux、macOS 和 Windows(使用 WSL)。 |
性能 | Docker 以其高效的资源管理和快速部署而闻名。 | Podman 的性能通常相当,并且启动时间更快。 |
使用案例 | Docker 非常适合需要成熟工具和集成的项目。 | Podman 适用于优先考虑安全性和轻量级作的环境。非常适合大规模部署。 |
Docker 和 Podman 之间的选择在很大程度上取决于特定的项目要求,特别是关于安全性、兼容性和编排需求。
Docker 仍然是已建立的 CI/CD 管道和全面容器管理的绝佳选择,而 Podman 则为优先考虑安全性和无根作的环境提供了一种安全、轻量级的替代方案。它还提供更快的启动时间,非常适合大规模部署。
安装 Podman
首先,您需要通过访问官方网站下载并安装 Podman Desktop 软件包
安装简单快捷。几分钟后,您将进入 Getting started (入门) 屏幕,系统会要求您安装可选扩展。如果您在 Windows 中没有 WSL,它将自动安装 WSL。
接下来,设置 Podman 计算机
与 Docker 相比,您无需设置机器。但是,在 Podman 中,您可以管理多台同时处理不同容器的机器,从而实现更好的资源管理。我们的机器已启动并运行,可以创建映像并运行容器。
为了验证 Podman 是否正常运行,我们将从 quay.io 中提取示例镜像并执行容器。
$ podman run quay.io/podman/hello
Podman 计算机已成功提取映像并运行容器,并显示日志。
Trying to pull quay.io/podman/hello:latest...
Getting image source signatures
Copying blob sha256:81df7ff16254ed9756e27c8de9ceb02a9568228fccadbf080f41cc5eb5118a44
Copying config sha256:5dd467fce50b56951185da365b5feee75409968cbab5767b9b59e325fb2ecbc0
Writing manifest to image destination
!... Hello Podman World ...!.--"--./ - - \/ (O) (O) \~~~| -=(,Y,)=- |.---. /` \ |~~~/ o o \~~~~.----. ~~| =(X)= |~ / (O (O) \~~~~~~~ ~| =(Y_)=- |~~~~ ~~~| U |~~Project: https://github.com/containers/podman
Website: https://podman.io
Desktop: https://podman-desktop.io
Documents: https://docs.podman.io
YouTube: https://youtube.com/@Podman
X/Twitter: @Podman_io
Mastodon: @Podman_io@fosstodon.org
使用 Podman 构建 MLOps 项目
在这个 MLOps 项目中,我们将自动化模型训练和评估,并使用 Dockerfile 和 Podman 为模型提供服务。这与 Docker 类似,但我们将使用 Podman CLI 构建镜像,然后运行容器。
如果您不熟悉这些概念,可以通过完成 MLOps 概念课程来学习 MLOP 的基础知识
设置机器学习项目
要设置机器学习项目,我们需要创建一个训练和服务脚本,以及用于安装 Python 包的 requirements.txt 文件。
训练 Python 脚本将加载信用评分分类数据集,对其进行处理、编码并训练模型。我们还将进行模型评估。最后,我们将使用 pickle 格式保存预处理和训练管道以及模型
# src/train.pyimport os
import pickleimport matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import SimpleImputer
from sklearn.metrics import (accuracy_score,classification_report,confusion_matrix,roc_auc_score,
)
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoderdef load_data():data_path = "data/train.csv"df = pd.read_csv(data_path,low_memory=False)print("Data loaded successfully!")return dfdef preprocess_data(df):# Drop unnecessary columnsdf = df.drop(columns=["ID", "Customer_ID", "SSN", "Name", "Month"])# Drop rows with missing valuesdf = df.dropna()# Convert data types# Convert the 'Age' column to numeric, setting errors='coerce' to handle non-numeric valuesdf["Age"] = pd.to_numeric(df["Age"], errors="coerce")# Filter the DataFrame to include only rows where 'Age' is between 1 and 60df = df[(df["Age"] >= 1) & (df["Age"] <= 60)]df["Annual_Income"] = pd.to_numeric(df["Annual_Income"], errors="coerce")df["Monthly_Inhand_Salary"] = pd.to_numeric(df["Monthly_Inhand_Salary"], errors="coerce")# Separate features and targetX = df.drop("Credit_Score", axis=1)y = df["Credit_Score"]print("Data preprocessed successfully!")return X, ydef encode_data(X):# Identify categorical and numerical featurescategorical_features = ["Occupation","Credit_Mix","Payment_of_Min_Amount","Payment_Behaviour","Type_of_Loan",]numerical_features = X.select_dtypes(include=["int64", "float64"]).columns.tolist()# Define preprocessing stepsnumerical_transformer = SimpleImputer(strategy="median")categorical_transformer = Pipeline(steps=[("imputer", SimpleImputer(strategy="most_frequent")),("onehot", OneHotEncoder(handle_unknown="ignore")),])preprocessor = ColumnTransformer(transformers=[("num", numerical_transformer, numerical_features),("cat", categorical_transformer, categorical_features),])return preprocessordef split_data(X, y):X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)return X_train, X_test, y_train, y_testdef train_model(X_train, y_train, preprocessor):# Create a pipeline with preprocessing and modelclf = Pipeline(steps=[("preprocessor", preprocessor),("classifier", RandomForestClassifier(n_estimators=100)),])# Train the modelclf.fit(X_train, y_train)# Return the trained modelreturn clfdef evaluate_model(clf, X_test, y_test):# Predict and evaluatey_pred = clf.predict(X_test)acc = accuracy_score(y_test, y_pred)report = classification_report(y_test, y_pred, labels=["Poor", "Standard", "Good"])cm = confusion_matrix(y_test, y_pred, labels=["Poor", "Standard", "Good"])# Calculate AUC scorey_test_encoded = y_test.replace({"Poor": 0, "Standard": 1, "Good": 2})y_pred_proba = clf.predict_proba(X_test)auc_score = roc_auc_score(y_test_encoded, y_pred_proba, multi_class="ovr")# Print metricsprint("Model Evaluation Metrics:")print(f"Accuracy: {acc}")print(f"AUC Score: {auc_score}")print("Classification Report:")print(report)# Plot confusion matrixplt.figure(figsize=(8, 6))plt.imshow(cm, interpolation="nearest", cmap=plt.cm.Blues)plt.title("Confusion Matrix")plt.colorbar()tick_marks = np.arange(3)plt.xticks(tick_marks, ["Poor", "Standard", "Good"], rotation=45)plt.yticks(tick_marks, ["Poor", "Standard", "Good"])plt.ylabel("True label")plt.xlabel("Predicted label")plt.tight_layout()cm_path = os.path.join("model", "confusion_matrix.png")plt.savefig(cm_path)print(f"Confusion matrix saved to {cm_path}")def save_model(clf):model_dir = "model"os.makedirs(model_dir, exist_ok=True)model_path = os.path.join(model_dir, "model.pkl")# Save the trained modelwith open(model_path, "wb") as f:pickle.dump(clf, f)print(f"Model saved to {model_path}")def main():# Execute stepsdf = load_data()X, y = preprocess_data(df)preprocessor = encode_data(X)X_train, X_test, y_train, y_test = split_data(X, y)clf = train_model(X_train, y_train, preprocessor)evaluate_model(clf, X_test, y_test)save_model(clf)if __name__ == "__main__":main()
模型服务脚本将使用模型文件加载保存的模型管道,创建一个 POST 请求函数,该函数从用户那里获取字典列表,将其转换为 DataFrame,将其提供给模型以生成预测,然后返回预测标签。我们使用 FastAPI 作为我们的 API 框架,这使我们能够只用几行代码来为模型提供服务
# src/app.pyimport pickle
from fastapi import FastAPI
from pydantic import BaseModel
import pandas as pd
import os# Load the trained model
model_path = os.path.join("model", "model.pkl")
with open(model_path, "rb") as f:model = pickle.load(f)app = FastAPI()class InputData(BaseModel):data: list # List of dictionaries representing feature values@app.post("/predict")
def predict(input_data: InputData):# Convert input data to DataFrameX_new = pd.DataFrame(input_data.data)# Ensure the columns match the training dataprediction = model.predict(X_new)# Return predictionsreturn {"prediction": prediction.tolist()}
我们需要创建一个
requirements.txt
文件,其中包含运行上述脚本所需的所有 Python 包。这个文件将用于在 Docker 容器中设置运行环境,确保我们可以顺利执行 Python 脚本
fastapi
uvicorn[standard]
numpy
pandas
scikit-learn
pydantic
matplotlib
创建 Dockerfile
创建一个 “Dockerfile” 并添加以下代码。
以下是此 Dockerfile 执行的步骤:
- 使用 Python 3.9 slim image 作为基础
- 将 /app 设置为工作目录
- 从 requirements.txt 安装 Python 依赖项
- 将源代码和数据文件复制到容器中
- 创建模型目录并运行训练脚本
- 为 API 公开端口 8000
- 使用 uvicorn 服务器在端口 8000 上启动 FastAPI 应用程序
# DockerfileFROM python:3.9-slimWORKDIR /app# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt# Copy the application code
COPY ./src/ ./src/
COPY ./data/ ./data/# Ensure the model directory exists and is copied
RUN mkdir -p model# Run the training script during the build
RUN python src/train.py# Expose the port for the API
EXPOSE 8000# Run the FastAPI app
CMD ["uvicorn", "src.app:app", "--host", "0.0.0.0", "--port", "8000"]
您的本地工作区应按如下方式组织:
- 包含所有 CSV 文件的文件夹
data
- 文件夹
models
- 保存 Python 脚本的文件夹
src
- 在主目录中,包含一个文件和一个
requirements.txt``Dockerfile
其余文件是用于自动化和 Git作的附加组件。
使用 Podman 构建 Docker 镜像
构建 Docker 镜像很简单:只需在命令中提供您的 Docker 镜像名称和 Dockerfile 所在的当前目录即可。
build
$ podman build -t mlops_app .
构建工具将按顺序执行 Dockerfile 中的所有命令,从设置环境到为机器学习应用程序提供服务。
我们还可以看到 log 中包含了模型评估结果。该模型的准确率为 75%,ROC AUC 得分为 0.89,被认为是平均水平
STEP 1/11: FROM python:3.9-slim
STEP 2/11: WORKDIR /app
--> Using cache 72ac9e49ae29da1ff19e118653efca17e7a489ae9e7ead917c83d942a3ea4e13
--> 72ac9e49ae29
STEP 3/11: COPY requirements.txt .
--> Using cache 3a05ca95caaf98c448c53a796714328bf9f7cff7896cce348f84a26b8d0dae61
--> 3a05ca95caaf
STEP 4/11: RUN pip install --no-cache-dir -r requirements.txt
--> Using cache 28109d1183449396a5df0006ab603dd5cf2aa2c06a810bdc6bcf0f843f855ee0
--> 28109d118344
STEP 5/11: COPY ./src/ ./src/
--> f814f699c58a
STEP 6/11: COPY ./data/ ./data/
--> 922550900cd0
STEP 7/11: RUN mkdir -p model
--> 36fc01f2d169
STEP 8/11: RUN python src/train.py
Data loaded successfully!
Data preprocessed successfully!
Data encoded successfully!
Data split successfully!
Model trained successfully!
Model Evaluation Metrics:
Accuracy: 0.7546181417149159
ROC AUC Score: 0.8897184704689612
Classification Report:precision recall f1-score supportGood 0.71 0.67 0.69 1769Poor 0.75 0.76 0.75 3403Standard 0.77 0.78 0.78 5709accuracy 0.75 10881macro avg 0.74 0.74 0.74 10881
weighted avg 0.75 0.75 0.75 10881Model saved to model/model.pkl
--> 5d4777c08580
STEP 9/11: EXPOSE 8000
--> 7bb09a613e7f
STEP 10/11: WORKDIR /app/src
--> 06b6394c2e2d
STEP 11/11: CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
COMMIT mlops-app
--> 9a7a42b03664
Successfully tagged localhost/mlops-app:latest
9a7a42b03664f1e4631330cd682cb2de26e513c5d776fa2ce2042b3bb9455e14
如果您打开 Podman Desktop 应用程序并单击“映像”选项卡,您将看到映像已成功创建。mlops_app
查看 Docker for Data Science 备忘单,了解所有相关的 Docker 命令。只需将第一个命令 , 替换为 .dockerpodman
使用 Podman 运行 Docker 容器
我们将使用该命令从映像启动名为 “mlops_container” 的容器。这将在分离模式 (-d) 下完成,将容器的 port 映射到主机上的 port。此设置将允许从容器外部访问 FastAPI 应用程序。runmlops-app80008000
$ podman run -d --name mlops_container -p 8000:8000 mlops-app
要查看 “mlops_container” 的所有日志,请使用命令
$ podman logs -f mlops_container
输出:
INFO: Started server process [1]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO: 10.88.0.1:36886 - "POST /predict HTTP/1.1" 200 OK
您还可以打开 Podman Desktop 应用程序,然后单击“容器”选项卡以查看正在运行的容器
要查看 Podman Desktop 应用程序中的日志,请单击“mlops_container”,然后选择“终端”选项卡。
测试 ML 推理服务器
现在,我们将通过访问以下网址的交互式 Swagger UI 来测试已部署的应用程序:http://localhost:8000/docs。Swagger UI 提供了一个用户友好的界面,允许您浏览所有可用的 API 端点。
我们还可以使用终端中的 CURL 命令来测试 API。
$ curl -X POST "http://localhost:8000/predict" \-H "Content-Type: application/json" \-d '{"data": [{"Age": 35,"Occupation": "Engineer","Annual_Income": 85000,"Monthly_Inhand_Salary": 7000,"Num_Bank_Accounts": 2,"Num_Credit_Card": 3,"Interest_Rate": 5,"Num_of_Loan": 1,"Type_of_Loan": "Personal Loan","Delay_from_due_date": 2,"Num_of_Delayed_Payment": 1,"Changed_Credit_Limit": 15000,"Num_Credit_Inquiries": 2,"Credit_Mix": "Good","Outstanding_Debt": 10000,"Credit_Utilization_Ratio": 30,"Credit_History_Age": 15,"Payment_of_Min_Amount": "Yes","Total_EMI_per_month": 500,"Amount_invested_monthly": 1000,"Payment_Behaviour": "Regular","Monthly_Balance": 5000}]}'
FastAPI 服务器运行正常,成功处理用户输入并返回准确的预测。
{"prediction":["Good"]}
停止和移除容器
在试验了 API 之后,我们将使用该命令停止容器。
$ podman stop mlops_container
此外,我们可以使用该命令删除容器,从而释放系统资源。必须先停止容器,然后才能将其删除。
$ podman rm mlops_container
删除图像
要删除名为 “mlops-app” 的本地存储的容器镜像,我们将使用以下命令
$ podman rmi mlops-app
如果您在运行上述代码或创建自己的 Docker 文件时遇到问题,请查看 GitHub 存储库 kingabzpro/mlops-with-podman。它包括使用指南和在系统上执行代码所需的所有文件。
学习之旅的下一步是尝试构建 10 个 Docker 项目创意,从初级到高级,但使用 Podman。这将帮助您更好地了解 Podman 生态系统
结论
Podman 为某些用例提供了引人注目的 Docker 替代方案,但许多开发人员仍然偏爱 Docker Desktop 和 CLI。这种偏好主要是由于 Docker 的广泛集成和用户友好的工具。
但是,对于简单的 MLOps 项目,工程师可能会选择 Podman,与 Docker Desktop 相比,它提供了轻量级且易于设置。
在本教程中,我们将探索 Podman,这是一种流行的容器管理工具,将其与 Docker 进行比较,并演示如何安装 Podman Desktop。我们还将指导您使用 Podman 完成 MLOps 项目,包括创建 Dockerfile、构建映像和运行容器。Podman 的入门非常简单,如果您已经熟悉 Docker,那么您会喜欢无缝过渡。