Modul 4: Kontinuerlig integrering och driftsättning för ML

I denna modul utforskar vi tillämpningen av kontinuerlig integrering och driftsättning (CI/CD) specifikt för maskininlärningssystem. Vi kommer att lära oss hur man anpassar traditionella CI/CD-praktiker för att hantera de unika utmaningarna med ML, inklusive dataversionshantering, modellvalidering och A/B-testning. Modulen fokuserar på att bygga automatiserade arbetsflöden som säkerställer att ML-modeller kan utvecklas, testas och driftsättas på ett säkert och effektivt sätt.

Efter denna modul kommer du att:

  • Förstå skillnaden mellan traditionell CI/CD och ML-specifik CI/CD
  • Kunna implementera CI/CD-pipelines för ML-projekt
  • Behärska modellvalidering och godkännandeprocesser
  • Skapa automatiserade driftsättningsstrategier för ML-modeller
  • Implementera A/B-testning för modeller i produktion
  • Hantera rollback och återställning av ML-system
Aspekt Traditionell CI/CD ML CI/CD
Artefakter Kodbaserade binärer/containers Modeller + kod + konfiguration
Validering Enhetstester, integrationstester Datakvalitetstester, modellvalideringstester
Miljövariabler Konfiguration, endpoints Feature stores, modellparametrar
Byggsteg Kompilering, paketisering Träning, validering, paketisering
Tidsåtgång Minuter Timmar till dagar (för träning)
Driftsättning Vanligtvis atomär Kan kräva gradvis utrullning
Rollback Relativt enkel (tidigare version) Komplex (återställ data + modell)

ML-system introducerar ett nytt koncept: Continuous Training (CT), som innebär automatisk omträning av modeller när:

  • Nya data blir tillgängliga
  • Modellprestanda sjunker under ett tröskelvärde
  • Koden för modellarkitekturen uppdateras
  • Feature engineering ändras
  • Nivå 0: Manuell process - ingen CI/CD
  • Nivå 1: ML-pipeline-automatisering - CI för kod, manuell CD
  • Nivå 2: CI/CD-pipeline-automatisering - automatiserad driftsättning
  • Nivå 3: Fullständig CI/CD/CT - automatiserad omträning och driftsättning
  • Kodkvalitetskontroll: Linting, formatering, statisk kodanalys
  • Enhetstestning: Testa individuella komponenter
  • Integrationstestning: Testa samverkan mellan komponenter
  • Datakvalitetstestning: Validera att data uppfyller förväntningar
  • Lightweight modellträning: Träna på mindre dataset för verifiering
  • Modellutvärdering: Validera modellprestanda mot baselines
# .github/workflows/mlops-ci.yml
name: MLOps CI Pipeline

on:
  push:
    branches: [ main, dev ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.9'
        
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install flake8 pytest pytest-cov
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
        
    - name: Lint with flake8
      run: |
        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
        
    - name: Test with pytest
      run: |
        pytest tests/ --cov=src
        
    - name: Run data quality checks
      run: |
        python scripts/validate_data.py --data-path data/sample.csv
        
    - name: Run lightweight model training
      run: |
        python scripts/train_model.py --small-dataset --epochs 1
        
    - name: Validate model performance
      run: |
        python scripts/evaluate_model.py --model-path models/latest.h5 --threshold 0.7
  • Dataintegritet: Kontrollera att data uppfyller scheman och begränsningar
  • Datafördelning: Validera att datafördelningen inte har förändrats avsevärt
  • Feature drift: Kontrollera att feature-fördelningen är konsekvent
  • Referensdata: Jämför med referensdataset för att upptäcka avvikelser
# .github/workflows/dvc-data-ci.yml
name: DVC Data Pipeline CI

on:
  push:
    branches: [ main ]
    paths:
      - 'data/**'
      - 'dvc.yaml'
      - 'params.yaml'

jobs:
  data_pipeline:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.9'
        
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install dvc dvc[s3]
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
        
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: eu-west-1
        
    - name: Pull DVC data
      run: |
        dvc pull
        
    - name: Run DVC pipeline
      run: |
        dvc repro
        
    - name: Run data validation
      run: |
        python scripts/validate_data_pipeline.py
        
    - name: Push DVC results
      run: |
        dvc push
  • Modellvalidering: Grundlig utvärdering av modellprestanda
  • Modelljämförelse: Jämförelse med nuvarande produktionsmodell
  • Modellåtgärdsplan: Automatisk godkännande eller manuell granskning
  • Modellpaketisering: Förpackning av modeller för driftsättning
  • Infrastrukturförberedelse: Skapande eller uppdatering av infrastruktur
  • Driftsättning: Publicering av modellen i produktionsmiljö
  • Post-driftsättningsvalidering: Kontrollera att driftsättningen lyckades
# .github/workflows/mlops-cd.yml
name: MLOps CD Pipeline

on:
  workflow_run:
    workflows: ["MLOps CI Pipeline"]
    branches: [main]
    types: [completed]

jobs:
  deploy:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.9'
        
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install awscli boto3
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
        
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: eu-west-1
        
    - name: Download model from S3
      run: |
        aws s3 cp s3://my-model-bucket/models/latest/ ./models/latest/ --recursive
        
    - name: Validate model
      run: |
        python scripts/validate_model_for_production.py --model-path models/latest/model.h5
        
    - name: Compare with current production model
      run: |
        python scripts/compare_models.py --new-model models/latest/model.h5 --threshold 0.05
        
    - name: Package model as Docker image
      run: |
        docker build -t my-model-service:${{ github.sha }} .
        
    - name: Push Docker image to ECR
      run: |
        aws ecr get-login-password | docker login --username AWS --password-stdin ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.eu-west-1.amazonaws.com
        docker tag my-model-service:${{ github.sha }} ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.eu-west-1.amazonaws.com/my-model-service:${{ github.sha }}
        docker push ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.eu-west-1.amazonaws.com/my-model-service:${{ github.sha }}
        
    - name: Update ECS service
      run: |
        aws ecs update-service --cluster ml-cluster --service my-model-service --force-new-deployment
        
    - name: Wait for deployment
      run: |
        aws ecs wait services-stable --cluster ml-cluster --services my-model-service
        
    - name: Validate deployment
      run: |
        python scripts/validate_deployment.py --endpoint https://api.example.com/model
  • Canary releases: Driftsättning till en liten användargrupp först
  • Blue/Green-driftsättning: Parallella miljöer för snabb växling
  • Feature flagging: Aktivera/inaktivera specifika modellversioner för olika användare
# kubernetes/model-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: model-service
spec:
  replicas: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  selector:
    matchLabels:
      app: model-service
  template:
    metadata:
      labels:
        app: model-service
    spec:
      containers:
      - name: model-service
        image: my-model-registry/model-service:latest
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10
        resources:
          limits:
            cpu: "1"
            memory: "2Gi"
          requests:
            cpu: "0.5"
            memory: "1Gi"
  • Definition: Jämför två modellversioner i produktion för att avgöra vilken som presterar bättre
  • Användningsfall: Validera modellförbättringar, experimentera med nya algoritmer, optimera affärsmätvärden
  • Key Performance Indicators (KPIs): Definiera tydliga framgångsmätvärden
  • Trafikuppdelning: Ruttning av användare till olika modellversioner
  • Statistisk utvärdering: Beräkning av statistisk signifikans
  • Automatisk promotion: Främjande av den vinnande modellen
import boto3
import json
 
# Skapa en SageMaker-klient
sagemaker_client = boto3.client('sagemaker')
 
# Konfigurera A/B-testning
response = sagemaker_client.create_endpoint_config(
    EndpointConfigName='my-ab-test-config',
    ProductionVariants=[
        {
            'VariantName': 'ModelA',
            'ModelName': 'model-a',
            'InitialInstanceCount': 1,
            'InstanceType': 'ml.c5.large',
            'InitialVariantWeight': 0.5
        },
        {
            'VariantName': 'ModelB',
            'ModelName': 'model-b',
            'InitialInstanceCount': 1,
            'InstanceType': 'ml.c5.large',
            'InitialVariantWeight': 0.5
        }
    ]
)
 
# Skapa eller uppdatera endpoint
response = sagemaker_client.create_endpoint(
    EndpointName='my-ab-test-endpoint',
    EndpointConfigName='my-ab-test-config'
)
 
# För att anropa en specifik modellvariant för testning
runtime_client = boto3.client('sagemaker-runtime')
response = runtime_client.invoke_endpoint(
    EndpointName='my-ab-test-endpoint',
    ContentType='application/json',
    TargetVariant='ModelA',  # Specifikt anropa ModelA
    Body=json.dumps({"features": [1, 2, 3, 4]})
)
  • Datainsamling: Lagring av prediktioner och utfall för varje variant
  • Mätning: Beräkning av KPIs för varje modellvariant
  • Visualisering: Dashboards för att visa testresultat över tid
  • Automatiskt beslut: Algoritmer för att avgöra när testet kan avslutas
  • Data-driven: Trigga vid nya data eller dataförändring
  • Prestanda-driven: Trigga när modellprestanda sjunker
  • Schema-driven: Regelbunden omträning och driftsättning
  • Händelse-driven: Trigga vid specifika händelser, t.ex. kodändringar
  • Hög frekvens: Kontinuerlig omträning för snabbt föränderliga data
  • Medelhög frekvens: Daglig eller veckovis omträning
  • Låg frekvens: Månatlig eller kvartalsvis omträning
  • Automatiskt godkännande: För mindre modellförändringar
  • Semi-automatiskt godkännande: Automatisk validering + manuell granskning
  • Manuellt godkännande: För större modellförändringar eller känsliga system
def evaluate_and_approve_model(model_path, production_model_path, metrics_threshold):
    """Utvärd och godkänn en modell baserat på tröskelvärden"""
    # Ladda modellerna
    new_model = load_model(model_path)
    prod_model = load_model(production_model_path)
 
    # Utvärdera på testdata
    new_metrics = evaluate_model(new_model, test_data)
    prod_metrics = evaluate_model(prod_model, test_data)
 
    # Beräkna prestandaförbättring
    improvement = {}
    for metric_name, threshold in metrics_threshold.items():
        improvement[metric_name] = new_metrics[metric_name] - prod_metrics[metric_name]
 
    # Kontrollera om alla tröskelvärden är uppfyllda
    approval_decision = True
    approval_reasons = []
 
    for metric_name, threshold in metrics_threshold.items():
        if improvement[metric_name] < threshold:
            approval_decision = False
            approval_reasons.append(f"{metric_name} förbättring {improvement[metric_name]:.4f} under tröskelvärde {threshold}")
 
    if approval_decision:
        approval_reasons.append("Alla prestandamätvärden möter förbättringströskelvärdena")
 
    return {
        "approved": approval_decision,
        "reasons": approval_reasons,
        "metrics": new_metrics,
        "improvement": improvement
    }
  • Komplex återställning: Modell + infrastruktur + data
  • Data dependencies: Modeller är beroende av historiska data
  • Dåliga prediktioner: Felaktiga prediktioner kan propagera i system
  • Modellversionering: Tydlig spårning av alla driftsatta modeller
  • Infrastruktur som kod: Versionerad infrastruktur för återställning
  • Observabilitet: Tidig upptäckt av problem
  • Automatisk återställning: Självläkande system vid upptäckt av problem
def monitor_and_rollback_if_needed(deployed_model_id, performance_threshold, window_size=1000):
    """Övervaka modellprestanda och återställ om den faller under tröskelvärdet"""
    # Hämta senaste prestandamätvärden
    recent_metrics = get_recent_metrics(deployed_model_id, window_size)
 
    # Beräkna genomsnittlig prestanda
    avg_performance = np.mean([m['accuracy'] for m in recent_metrics])
 
    if avg_performance < performance_threshold:
        print(f"Modellprestanda {avg_performance:.4f} under tröskelvärde {performance_threshold}")
 
        # Hämta tidigare (stabil) modellversion
        previous_stable_model = get_previous_stable_model()
 
        # Initiera rollback
        rollback_success = initiate_rollback(deployed_model_id, previous_stable_model.id)
 
        if rollback_success:
            print(f"Rollback till modell {previous_stable_model.id} lyckades")
 
            # Skicka notifiering till team
            send_alert(
                subject="Automatisk modellrollback utförd",
                message=f"Modell {deployed_model_id} återställd till {previous_stable_model.id} på grund av låg prestanda"
            )
        else:
            print("Rollback misslyckades, eskalera till manuell åtgärd")
            # Skicka larmnotifiering för manuell åtgärd
            send_alert(
                subject="AKUT: Modellrollback misslyckades",
                message=f"Manuell åtgärd krävs för modell {deployed_model_id}",
                priority="high"
            )
    else:
        print(f"Modellprestanda {avg_performance:.4f} över tröskelvärde {performance_threshold}, ingen åtgärd krävs")

1. CI Pipeline: Implementera en CI-pipeline för ett ML-projekt med GitHub Actions 2. CD Pipeline: Skapa en CD-pipeline för automatisk driftsättning av ML-modeller 3. A/B-testning: Implementera A/B-testning för två modellvarianter 4. Rollback-strategi: Designa och implementera en rollback-strategi för ML-modeller

  • GitHub Actions: Konfiguration för ML CI/CD
  • AWS SageMaker: Driftsättning och A/B-testning
  • Kubernetes: Gradvis utrullning av ML-modeller
  • FastAPI: REST API för modellbetjäning
  • ”Continuous Delivery for Machine Learning” - Continuous Delivery Foundation
  • ”Practical MLOps” - Noah Gift & Alfredo Deza
  • ”Implementing CI/CD for ML” - AWS Technical Guide
  • ”A/B Testing Machine Learning Models” - Microsoft Azure Documentation
  • CI/CD för ML kräver särskild hänsyn till data och modeller utöver kod
  • En robust modellvalideringsprocess är avgörande före driftsättning
  • Gradvis utrullning och A/B-testning minskar risken för problem i produktion
  • Automatiserade pipeline-triggers bör anpassas efter datans och modellens natur
  • Effektiva rollback-strategier är avgörande för ML-systemens tillförlitlighet

I nästa modul kommer vi att utforska containerisering och orkestrering av ML-applikationer, där vi kommer att lära oss hur man paketerar och driftsätter ML-modeller i containeriserade miljöer.