أساسيات MLOps: الخطوات التسع الرئيسية للانتقال من الصفر إلى التشغيل
أساسيات MLOps: الأساسيات في مقال واحد — كود حقيقي، مخططات وخطوات ملموسة، مقتطفات من دورة تتكون من 72 درسًا.
يمكن للجميع تعلم MLOps Fundamentals — بشرط اتباع الخطوات بالترتيب الصحيح. لقد لخصنا دورة كاملة من 72 درسًا في مسار واضح، مع أكثر مقتطفات الكود فائدة.
- تثبيت بيئة MLOps
- اكتشاف MLOps
- إصدار البيانات والنماذج
- خطوط أنابيب ML باستخدام MLflow
- حاويات النماذج ML
دليل المشروع النهائي الكامل – خطوة بخطوة
Cours MLOps Fundamentals • كشف الاحتيال ببطاقة الائتمان • خط أنابيب MLOps شامل
يرافقك هذا الدليل التفصيلي خطوة بخطوة في تنفيذ المشروع النهائي. يتوافق كل قسم مع خطوة رئيسية في خط أنابيب MLOps. اتبع الخطوات بالترتيب. كل الكود مقدم ومشروح. المدة التقريبية: 8–12 ساعة إجمالاً.
① الخطوة 1 – تهيئة المشروع والبيئة
أنشئ هيكل المشروع وبيئة Conda:
mkdir fraud-detection-mlops
cd fraud-detection-mlops
git init
git config user.email "vous@email.com"
git config user.name "Votre Nom"
conda create -n fraud-mlops python=3.10 -y
conda activate fraud-mlops
pip install scikit-learn xgboost pandas numpy mlflow dvc \
fastapi uvicorn pydantic evidently \
pytest pytest-cov httpx joblib matplotlib \
seaborn imbalanced-learn flake8 black
conda env export > environment.ymlأنشئ الملف requirements.txt :
scikit-learn==1.4.0 xgboost==2.0.3 pandas==2.1.4 numpy==1.26.3 mlflow==2.10.0 dvc==3.38.1 fastapi==0.109.0 uvicorn==0.27.0 pydantic==2.5.3 evidently==0.4.16 pytest==7.4.4 pytest-cov==4.1.0 httpx==0.26.0 joblib==1.3.2 matplotlib==3.8.2 seaborn==0.13.1 imbalanced-learn==0.11.0
أنشئ هيكل المجلدات:
mkdir -p data/raw data/processed src api monitoring/reports tests models .github/workflows
__pycache__/ *.pyc *.pyo .env models/ mlruns/ *.pkl data/raw/ data/processed/ monitoring/reports/*.html monitoring/reports/*.json .coverage htmlcov/
dvc init git add . git commit -m "feat: init project structure and DVC"
② الخطوة 2 – توليد وإصدار البيانات
أنشئ src/generate_synthetic_data.py (إذا لم يكن لديك وصول إلى مجموعة بيانات Kaggle) :
"""يُنشئ مجموعة بيانات اصطناعية لاحتيال بطاقة الائتمان."""
import pandas as pd
import numpy as np
def generate_fraud_dataset(n_samples=50000, fraud_ratio=0.002, random_state=42):
np.random.seed(random_state)
n_fraud = int(n_samples * fraud_ratio)
n_legit = n_samples - n_fraud
legit = pd.DataFrame({
f'V{i}': np.random.normal(0, 1, n_legit) for i in range(1, 29)
})
legit['Amount'] = np.abs(np.random.exponential(scale=88, size=n_legit))
legit['Time'] = np.sort(np.random.uniform(0, 172800, n_legit))
legit['Class'] = 0
fraud = pd.DataFrame({
f'V{i}': np.random.normal(np.random.uniform(-3, 3), 2, n_fraud) for i in range(1, 29)
})
fraud['Amount'] = np.abs(np.random.exponential(scale=122, size=n_fraud))
fraud['Time'] = np.random.uniform(0, 172800, n_fraud)
fraud['Class'] = 1
df = pd.concat([legit, fraud], ignore_index=True)
df = df.sample(frac=1, random_state=random_state).reset_index(drop=True)
return df
if __name__ == "__main__":
df = generate_fraud_dataset()
df.to_csv("data/raw/creditcard.csv", index=False)
print(f"Dataset généré : {len(df)} lignes")
print(f"Fraudes : {df['Class'].sum()} ({df['Class'].mean()*100:.3f}%)")Dockerfile لنموذج ML : البناء والتشغيل
Cours MLOps Fundamentals — الفصل 04 — حاويات نماذج ML
- فهم كل تعليمة في Dockerfile لنموذج ML
- كتابة Dockerfile كامل لواجهة API scikit-learn مع FastAPI
- بناء صورة Docker باستخدام
docker build - تشغيل واختبار حاوية ML باستخدام
docker run - تصحيح مشكلات حاويات ML الشائعة
1. هيكل مشروع ML المراد تحويله إلى حاوية
قبل كتابة Dockerfile، دعنا نرى هيكل المشروع الذي سنحوله إلى حاوية. إنه واجهة API لتصنيف النبيذ مبنية على نموذج Random Forest مدرب باستخدام scikit-learn، ويُقدم عبر FastAPI.
wine-classifier/
â└â─â─ Dockerfile # Notre fichier de configuration Docker
â└â─â─ .dockerignore # Fichiers à exclure de l'image
â└â─â─ requirements.txt # Dépendances Python
â└â─â─ src/
â├â─â─ app.py # Application FastAPI (point d'entrée)
â├â─â─ predict.py # Logique de prédiction
â├â─â─ preprocessing.py # Pré-traitement des features
â└â─â─ models/
â└â─â─ rf_classifier.pkl # Modèle Random Forest sérialisé
â└â─â─ scaler.pkl # StandardScaler sauvegardéملف requirements.txt
يسرد requirements.txt جميع التبعيات Python مع إصداراتها المثبتة. هذا أمر حاسم لإعادة الإنتاج: بدون تثبيت الإصدار، قد يقوم pip install بتنزيل إصدار أحدث وغير متوافق.
# requirements.txt # Framework web fastapi==0.110.0 uvicorn[standard]==0.27.1 # Machine Learning scikit-learn==1.4.1 numpy==1.26.4 pandas==2.2.1 # Sérialisation du modèle joblib==1.3.2 # Validation des données pydantic==2.6.3
تجنب
scikit-learn>=1.0 أو scikit-learn بدون إصدار. إذا أصدر scikit-learn الإصدار 2.0 مع تغييرات في API، ستتعطل الحاوية عند إعادة البناء التالية. استخدم دائمًا scikit-learn==1.4.1.تطبيق FastAPI (src/app.py)
# src/app.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import joblib
import numpy as np
import os
app = FastAPI(
title="Wine Quality Classifier API",
description="API de classification de la qualité du vin basée sur Random Forest",
version="1.0.0"
)
# Chargement du modèle au démarrage (pas à chaque requête)
MODEL_PATH = os.getenv("MODEL_PATH", "/app/models/rf_classifier.pkl")
SCALER_PATH = os.getenv("SCALER_PATH", "/app/models/scaler.pkl")
model = joblib.load(MODEL_PATH)
scaler = joblib.load(SCALER_PATH)
class WineFeatures(BaseModel):
fixed_acidity: float
volatile_acidity: float
citric_acid: float
residual_sugar: float
chlorides: float
free_sulfur_dioxide: float
total_sulfur_dioxide: float
density: float
pH: float
sulphates: float
alcohol: float
@app.get("/health")
def health_check():
return {"status": "ok", "model": "rf_classifier", "version": "1.0.0"}
@app.post("/predict")
def predict(features: WineFeatures):
try:
X = np.array([[
features.fixed_acidity, features.volatile_acidity,
features.citric_acid, features.residual_sugar,
features.chlorides, features.free_sulfur_dioxide,
features.total_sulfur_dioxide, features.density,
features.pH, features.sulphates, features.alcohol
]])
X_scaled = scaler.transform(X)
prediction = model.predict(X_scaled)[0]
probability = model.predict_proba(X_scaled)[0].max()
return {
"quality": int(prediction),
"confidence": round(float(probability), 4),
"label": "bon vin" if prediction >= 6 else "vin moyen"
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))2. Dockerfile الكامل والمشروح
إليك Dockerfile الكامل. سنحلل كل تعليمة بالتفصيل فورًا بعد ذلك.
# ============================================================
# Dockerfile pour un modèle scikit-learn servi avec FastAPI
# ============================================================
# Étape 1 : Image de base
FROM python:3.11-slim
# Étape 2 : Métadonnées de l'image
LABEL maintainer="mlops-team@exemple.com"
LABEL version="1.0.0"
LABEL description="Wine Quality Classifier - Random Forest API"
# Étape 3 : Variables d'environnement système
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
# Étape 4 : Répertoire de travail dans le conteneur
WORKDIR /app
# Étape 5 : Dépendances système (si nécessaire)
RUN apt-get update && apt-get install -y --no-install-recommends \
libgomp1 \
&& rm -rf /var/lib/apt/lists/*
# Étape 6 : Copier ET installer les dépendances Python (couche cachée)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Étape 7 : Copier le code source
COPY src/ ./src/
# Étape 8 : Copier le modèle ML
COPY models/ ./models/
# Étape 9 : Exposer le port de l'API
EXPOSE 8000
# Étape 10 : Utilisateur non-root pour la sécurité
RUN useradd --create-home --shell /bin/bash appuser
USER appuser
# Étape 11 : Commande de démarrage
CMD ["uvicorn", "src.app:app", "--host", "0.0.0.0", "--port", "8000"]3. تحليل مفصل لكل تعليمة
3.1 FROM python:3.11-slim
يحدد FROM الصورة الأساسية. python:3.11-slim هي النسخة الخفيفة من صورة Python الرسمية:
بالنسبة لـ scikit-learn، يُعد slim الحل الوسط الجيد: صغير بما يكفي، لكنه متوافق مع امتدادات C الخاصة بـ numpy/scipy.
:latestقد ينتقل
FROM python:latest من Python 3.11 إلى 3.12 بين عشية وضحاها ويكسر الكود. حدد الإصدار دائمًا: python:3.11-slim أو حتى python:3.11.8-slim.إذا كان نموذجك يستخدم GPU (TensorFlow، PyTorch)، استخدم:
FROM nvidia/cuda:12.1-cudnn8-runtime-ubuntu22.043.2 متغيرات البيئة ENV
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1| المتغير | التأثير | لماذا تفعّله؟ |
|---|---|---|
PYTHONDONTWRITEBYTECODE=1 |
لا ملفات .pyc |
يقلل حجم الصورة، يتجنب الملفات غير الضرورية |
PYTHONUNBUFFERED=1 |
سجلات فورية | ضروري لرؤية السجلات في docker logs فورًا |
PIP_NO_CACHE_DIR=1 |
لا ذاكرة تخزين مؤقت لـ pip في الصورة | يقلل الحجم النهائي للصورة (قد يوفر 100-200 ميجابايت) |
PIP_DISABLE_PIP_VERSION_CHECK=1 |
لا فحص لتحديثات pip | يسرّع البناء، يتجنب التحذيرات غير الضرورية |
3.3 WORKDIR /app
يحدد WORKDIR دليل العمل داخل الحاوية. تنفذ جميع التعليمات التالية (COPY، RUN، CMD) من هذا الدليل. إذا لم يكن الدليل موجودًا، ينشئه Docker تلقائيًا.
/app كدليل عمل لتطبيقات Python. تجنب العمل مباشرة في / أو /root.تحسين صور Docker ML
Cours MLOps Fundamentals — الفصل 04 — حاويات نماذج ML
- فهم لماذا يُعد حجم صور Docker ML أمرًا حاسمًا في الإنتاج
- إتقان البناء متعدد المراحل لفصل البناء عن التنفيذ
- تهيئة
.dockerignoreفعال لمشاريع ML - استغلال ذاكرة التخزين المؤقت للطبقات في Docker إلى أقصى حد
- تطبيق أفضل الممارسات لصور ML الإنتاجية
1. لماذا حجم صور ML حرج
على عكس تطبيق ويب تقليدي (بضع عشرات الميجابايت)، قد تصل صورة Docker ML بسهولة إلى 2 إلى 8 جيجابايت. لهذا الحجم عواقب مباشرة على سير عمل MLOps:
🚬 نشر بطيء
تنزيل صورة بحجم 5 جيجابايت على عنقود Kubernetes يستغرق 10 إلى 20 دقيقة. في حالة التوسع التلقائي تحت الحمل، هذا غير مقبول.
💸 تكلفة التخزين
تخزين 50 نسخة من صورة بحجم 4 جيجابايت في AWS ECR = 200 جيجابايت × 0.10$/جيجابايت/شهر = 20$/شهر فقط للتخزين.
🔐 سطح الهجوم
كل أداة إضافية (مترجمات، أدوات نظام) هي ثغرة أمنية محتملة. الصورة الدنيا أكثر أمانًا.
2. مقارنة: صور كبيرة مقابل صور خفيفة
| النهج | الصورة الأساسية | الحجم النموذجي | وقت السحب (100 ميجابت/ث) | الثغرات |
|---|---|---|---|---|
| 🔴 صورة كبيرة (ساذجة) | python:3.11 + جميع الأدوات |
~2.1 جيجابايت | ~170 ث | كثيرة جدًا |
| 🟡 صورة خفيفة (ممارسة جيدة) | python:3.11-slim |
~700 ميجابايت | ~56 ث | متوسطة |
| 🟢 متعددة المراحل خفيفة | البناء: python:3.11-slimالتشغيل: python:3.11-slim |
~350 ميجابايت | ~28 ث | قليلة |
| 🆕 Distroless | gcr.io/distroless/python3 |
~180 ميجابايت | ~14 ث | قليلة جدًا |
| 🟢 Alpine (بحذر) | python:3.11-alpine |
~100 ميجابايت | ~8 ث | دنيا |
يستخدم Alpine
musl libc بدلاً من glibc. Numpy وscikit-learn وpandas وPyTorch مبنية لـ glibc. استخدام Alpine يجبر على الترجمة من المصدر، مما يستغرق 30 إلى 60 دقيقة وقد يفشل. احتفظ بـ Alpine للخدمات المصغرة بدون تبعيات C. لـ ML، فضّل python:3.11-slim.3. .dockerignore: خط دفاعك الأول
حتى قبل البناء متعدد المراحل، يُعد .dockerignore أبسط وأسرع تحسين. يمنع Docker من إرسال ملفات غير ضرورية (أو خطيرة) إلى daemon البناء.
عند تنفيذ
docker build .، يرسل Docker كامل الدليل الحالي إلى Docker daemon (يُسمى «سياق البناء»). بدون .dockerignore، يشمل ذلك مجموعة بياناتك بحجم 10 جيجابايت، ودفاتر Jupyter، وبيئات Python الافتراضية، وملفات الإعدادات السرية...# .dockerignore pour un projet ML # Contrôle de version .git/ .gitignore .github/ # Environnements Python virtuels (critique ! peut faire des centaines de Mo) .venv/ venv/ env/ ENV/ __pycache__/ *.py[cod] *.pyo .pytest_cache/ .mypy_cache/ # Données ML (ne jamais embarquer dans l'image !) data/ datasets/ *.csv *.parquet *.arrow *.feather # Notebooks Jupyter (pas nécessaires en production) *.ipynb .ipynb_checkpoints/ # Fichiers de configuration locale .env .env.local .env.development *.env # Documentation et tests (inutiles en production) docs/ tests/ README.md CHANGELOG.md # Artefacts de build dist/ build/ *.egg-info/ htmlcov/ .coverage # IDE et éditeurs .vscode/ .idea/ *.swp *.swo .DS_Store Thumbs.db # Logs et fichiers temporaires logs/ *.log tmp/ temp/ # Fichiers MLflow et expériences mlruns/ mlflow.db # Modèles de test (garder seulement le modèle de production) models/experiments/ models/checkpoints/
قياس تأثير .dockerignore
# Vérifier la taille du contexte de build AVANT .dockerignore docker build -t test-before . 2>&1 | head -5 # Sending build context to Docker daemon 4.521GB <-- sans .dockerignore ! # Vérifier la taille du contexte de build APRES .dockerignore docker build -t test-after . 2>&1 | head -5 # Sending build context to Docker daemon 12.34MB <-- avec .dockerignore
4. البناء متعدد المراحل لـ ML
يستخدم البناء متعدد المراحل عدة تعليمات FROM في Dockerfile واحد. تنتج كل مرحلة طبقة وسيطة، ولا يُحتفظ إلا بالمرحلة الأخيرة في الصورة النهائية. يسمح ذلك بـ:
4.1 بناء متعدد المراحل لنموذج scikit-learn
# ============================================================
# Multi-stage Dockerfile pour Wine Classifier (production)
# ============================================================
# ---- ÉTAPE 1 : Builder ----
# Cette étape installe tout, y compris les outils de compilation
FROM python:3.11-slim AS builder
# Variables d'environnement pour le build
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
WORKDIR /build
# Installer les outils de build système (ne seront PAS dans l'image finale)
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
g++ \
build-essential \
libgomp1 \
&& rm -rf /var/lib/apt/lists/*
# Copier et installer dans un répertoire local isolé (--prefix)
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
# ---- ÉTAPE 2 : Image de production (finale) ----
# Image finale ultra-légère : ne contient PAS gcc, build-essential, etc.
FROM python:3.11-slim AS production
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
WORKDIR /app
# Copier uniquement les bibliothèques installées depuis le builder
COPY --from=builder /install /usr/local
# Dépendances système runtime (minimales)
RUN apt-get update && apt-get install -y --no-install-recommends \
libgomp1 \
&& rm -rf /var/lib/apt/lists/*
# Copier le code source et le modèle
COPY src/ ./src/
COPY models/ ./models/
# Sécurité : utilisateur non-root
RUN useradd --create-home --shell /bin/bash appuser && \
chown -R appuser:appuser /app
USER appuser
EXPOSE 8000
CMD ["uvicorn", "src.app:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "2"]بإزالة
gcc، g++، build-essential والملفات الوسيطة من الصورة النهائية، توفر عادة بين 200 و600 ميجابايت حسب تبعيات C/C++ المستخدمة.4.2 بناء متعدد المراحل مع مرحلة اختبار
# ============================================================ # Multi-stage Dockerfile avec étape de test intégrée # ============================================================ FROM python:3.11-slim AS base ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 PIP_NO_CACHE_DIR=1 WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # ---- Étape de test ---- FROM base AS test COPY requirements-dev.txt . RUN pip install --no-cache-dir -r requirements-dev.txt COPY src/ ./src/ COPY models/ ./models/ COPY tests/ ./tests/ RUN pytest tests/ -v --tb=short # ---- Étape de production ---- FROM base AS production COPY src/ ./src/ COPY models/ ./models/ RUN useradd --create-home appuser && chown -R appuser /app USER appuser EXPOSE 8000 CMD ["uvicorn", "src.app:app", "--host", "0.0.0.0", "--port", "8000"]
يغطي هذا المقال المقتطفات الأكثر فائدة — الدورة الكاملة MLOps Fundamentals (13 فصلاً، 72 درسًا، تمارين مصححة ومشروع نهائي) تأخذك إلى النهاية.
./acceder-au-cours-complet cours gratuit : Maîtriser Claude Codeالأسئلة الشائعة
كم من الوقت لتعلم MLOps Fundamentals؟
هل هناك متطلبات مسبقة؟
من أين نبدأ عمليًا؟
📬 هل تريد تلقي هذا النوع من الأدلة أسبوعيًا؟ اشترك مجانًا — كود حقيقي، بدون كلام زائد.