Dezember 21, 2025
14 Min. Lesezeit

Junior Machine Learning Engineer: Interviewfragen

interview
career-advice
job-search
entry-level
Junior Machine Learning Engineer: Interviewfragen
Milad Bonakdar

Milad Bonakdar

Autor

Bereiten Sie sich auf Interviews als Junior ML Engineer vor: Python, Modellevaluierung, Data Leakage, Deployment, Monitoring und MLOps mit klaren Antwortansätzen.


Junior Machine Learning Engineer: Interviewfragen

In einem Interview als Junior Machine Learning Engineer sollten Sie erklären können, wie Sie zuverlässigen Python-Code schreiben, Modelle trainieren und evaluieren, Data Leakage vermeiden, Modelle für das Deployment vorbereiten und Vorhersagen nach dem Release überwachen. Gute Antworten zeigen nicht nur den Algorithmus, sondern auch Datenannahmen, Metrikwahl und Produktions-Trade-offs.

Dieser Leitfaden hilft Ihnen, typische Fragen für Einstiegsrollen im ML Engineering zu üben: Python, klassische ML-Algorithmen, Validierung, unausgewogene Daten, Model Serving, Docker, Monitoring und CI/CD-Grundlagen.

Python & Programmierung (5 Fragen)

1. Wie handhaben Sie große Datensätze, die nicht in den Speicher passen?

Antwort: Es gibt verschiedene Techniken, um Daten zu verarbeiten, die größer sind als der verfügbare RAM:

  • Batch-Verarbeitung: Daten in Blöcken verarbeiten
  • Generatoren: Daten bei Bedarf liefern
  • Dask/Ray: Frameworks für verteiltes Rechnen
  • Datenbankabfragen: Nur benötigte Daten laden
  • Memory-Mapped Files: Zugriff auf die Festplatte, als ob sie sich im Speicher befindet
  • Data Streaming: Daten verarbeiten, sobald sie eintreffen
import pandas as pd
import numpy as np

# Schlecht: Gesamten Datensatz in den Speicher laden
# df = pd.read_csv('large_file.csv')  # Kann abstürzen

# Gut: In Blöcken einlesen
chunk_size = 10000
for chunk in pd.read_csv('large_file.csv', chunksize=chunk_size):
    # Jeden Block verarbeiten
    processed = chunk[chunk['value'] > 0]
    # Ergebnisse speichern oder aggregieren
    processed.to_csv('output.csv', mode='a', header=False)

# Verwenden von Generatoren
def data_generator(filename, batch_size=32):
    while True:
        batch = []
        with open(filename, 'r') as f:
            for line in f:
                batch.append(process_line(line))
                if len(batch) == batch_size:
                    yield np.array(batch)
                    batch = []

# Dask für verteiltes Rechnen
import dask.dataframe as dd
ddf = dd.read_csv('large_file.csv')
result = ddf.groupby('category').mean().compute()

Seltenheit: Sehr häufig Schwierigkeit: Mittel


2. Erklären Sie Dekoratoren in Python und nennen Sie einen ML-Anwendungsfall.

Antwort: Dekoratoren modifizieren oder erweitern Funktionen, ohne ihren Code zu verändern.

  • Anwendungsfälle in ML:
    • Zeitmessung der Funktionsausführung
    • Protokollierung von Vorhersagen
    • Zwischenspeichern von Ergebnissen
    • Eingabevalidierung
import time
import functools

# Timing-Dekorator
def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} hat {end - start:.2f} Sekunden gedauert")
        return result
    return wrapper

# Logging-Dekorator
def log_predictions(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        predictions = func(*args, **kwargs)
        print(f"Habe {len(predictions)} Vorhersagen getroffen")
        print(f"Vorhersageverteilung: {np.bincount(predictions)}")
        return predictions
    return wrapper

# Verwendung
@timer
@log_predictions
def predict_batch(model, X):
    return model.predict(X)

# Caching-Dekorator (Memoisation)
def cache_results(func):
    cache = {}
    @functools.wraps(func)
    def wrapper(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrapper

@cache_results
def expensive_feature_engineering(data_id):
    # Aufwendige Berechnung
    return processed_features

Seltenheit: Häufig Schwierigkeit: Mittel


3. Was ist der Unterschied zwischen @staticmethod und @classmethod?

Antwort: Beide definieren Methoden, die keine Instanz benötigen.

  • @staticmethod: Kein Zugriff auf Klasse oder Instanz
  • @classmethod: Empfängt die Klasse als erstes Argument
class MLModel:
    model_type = "classifier"
    
    def __init__(self, name):
        self.name = name
    
    # Reguläre Methode - benötigt eine Instanz
    def predict(self, X):
        return self.model.predict(X)
    
    # Statische Methode - Hilfsfunktion
    @staticmethod
    def preprocess_data(X):
        # Kein Zugriff auf self oder cls
        return (X - X.mean()) / X.std()
    
    # Klassenmethode - Factory Pattern
    @classmethod
    def create_default(cls):
        # Hat Zugriff auf cls
        return cls(name=f"default_{cls.model_type}")
    
    @classmethod
    def from_config(cls, config):
        return cls(name=config['name'])

# Verwendung
# Statische Methode - keine Instanz benötigt
processed = MLModel.preprocess_data(X_train)

# Klassenmethode - erstellt eine Instanz
model = MLModel.create_default()
model2 = MLModel.from_config({'name': 'my_model'})

Seltenheit: Mittel Schwierigkeit: Mittel


4. Wie handhaben Sie Ausnahmen in ML-Pipelines?

Antwort: Eine ordnungsgemäße Fehlerbehandlung verhindert Pipeline-Fehler und hilft beim Debuggen.

import logging
from typing import Optional

# Logging einrichten
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class ModelTrainingError(Exception):
    """Benutzerdefinierte Ausnahme für Modelltrainingsfehler"""
    pass

def train_model(X, y, model_type='random_forest'):
    try:
        logger.info(f"Starte Training mit {model_type}")
        
        # Eingaben validieren
        if X.shape[0] != y.shape[0]:
            raise ValueError("X und y müssen die gleiche Anzahl an Samples haben")
        
        if X.shape[0] < 100:
            raise ModelTrainingError("Unzureichende Trainingsdaten")
        
        # Modell trainieren
        if model_type == 'random_forest':
            from sklearn.ensemble import RandomForestClassifier
            model = RandomForestClassifier()
        else:
            raise ValueError(f"Unbekannter Modelltyp: {model_type}")
        
        model.fit(X, y)
        logger.info("Training erfolgreich abgeschlossen")
        return model
        
    except ValueError as e:
        logger.error(f"Validierungsfehler: {e}")
        raise
    except ModelTrainingError as e:
        logger.error(f"Trainingsfehler: {e}")
        # Könnte auf einfacheres Modell zurückgreifen
        return train_fallback_model(X, y)
    except Exception as e:
        logger.error(f"Unerwarteter Fehler: {e}")
        raise
    finally:
        logger.info("Trainingsversuch beendet")

# Context Manager für Ressourcenverwaltung
class ModelLoader:
    def __init__(self, model_path):
        self.model_path = model_path
        self.model = None
    
    def __enter__(self):
        logger.info(f"Lade Modell von {self.model_path}")
        self.model = load_model(self.model_path)
        return self.model
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        logger.info("Bereinige Ressourcen")
        if self.model:
            del self.model
        return False  # Ausnahmen nicht unterdrücken

# Verwendung
with ModelLoader('model.pkl') as model:
    predictions = model.predict(X_test)

Seltenheit: Häufig Schwierigkeit: Mittel


5. Was sind Python-Generatoren und warum sind sie in ML nützlich?

Antwort: Generatoren liefern Werte einzeln und sparen so Speicher.

  • Vorteile:
    • Speicher effizient
    • Lazy Evaluation
    • Unendliche Sequenzen
  • ML-Anwendungsfälle:
    • Daten laden
    • Batch-Verarbeitung
    • Datenerweiterung
import numpy as np

# Generator für Batch-Verarbeitung
def batch_generator(X, y, batch_size=32):
    n_samples = len(X)
    indices = np.arange(n_samples)
    np.random.shuffle(indices)
    
    for start_idx in range(0, n_samples, batch_size):
        end_idx = min(start_idx + batch_size, n_samples)
        batch_indices = indices[start_idx:end_idx]
        yield X[batch_indices], y[batch_indices]

# Verwendung im Training
for epoch in range(10):
    for X_batch, y_batch in batch_generator(X_train, y_train):
        model.train_on_batch(X_batch, y_batch)

# Datenerweiterungsgenerator
def augment_images(images, labels):
    for img, label in zip(images, labels):
        # Original
        yield img, label
        # Geflippt
        yield np.fliplr(img), label
        # Gedreht
        yield np.rot90(img), label

# Unendlicher Generator für das Training
def infinite_batch_generator(X, y, batch_size=32):
    while True:
        indices = np.random.choice(len(X), batch_size)
        yield X[indices], y[indices]

# Verwendung mit steps_per_epoch
gen = infinite_batch_generator(X_train, y_train)
# model.fit(gen, steps_per_epoch=100, epochs=10)

Seltenheit: Häufig Schwierigkeit: Mittel


ML-Algorithmen & Theorie (5 Fragen)

6. Erklären Sie den Unterschied zwischen Bagging und Boosting.

Antwort: Beide sind Ensemble-Methoden, funktionieren aber unterschiedlich:

  • Bagging (Bootstrap Aggregating):
    • Paralleles Training auf zufälligen Teilmengen
    • Reduziert die Varianz
    • Beispiel: Random Forest
  • Boosting:
    • Sequentielles Training, jedes Modell korrigiert vorherige Fehler
    • Reduziert die Verzerrung (Bias)
    • Beispiele: AdaBoost, Gradient Boosting, XGBoost
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score

# Daten generieren
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)

# Bagging - Random Forest
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf_scores = cross_val_score(rf, X, y, cv=5)
print(f"Random Forest CV: {rf_scores.mean():.3f} (+/- {rf_scores.std():.3f})")

# Boosting - Gradient Boosting
gb = GradientBoostingClassifier(n_estimators=100, random_state=42)
gb_scores = cross_val_score(gb, X, y, cv=5)
print(f"Gradient Boosting CV: {gb_scores.mean():.3f} (+/- {gb_scores.std():.3f})")

# XGBoost (Advanced Boosting)
import xgboost as xgb
xgb_model = xgb.XGBClassifier(n_estimators=100, random_state=42)
xgb_scores = cross_val_score(xgb_model, X, y, cv=5)
print(f"XGBoost CV: {xgb_scores.mean():.3f} (+/- {xgb_scores.std():.3f})")

Seltenheit: Sehr häufig Schwierigkeit: Mittel


7. Wie handhaben Sie unausgeglichene Datensätze?

Antwort: Unausgeglichene Daten können Modelle in Richtung der Mehrheitsklasse verzerren.

  • Techniken:
    • Resampling: SMOTE, Undersampling
    • Klassengewichte: Bestrafen Sie Fehlklassifizierung
    • Ensemble-Methoden: Balanced Random Forest
    • Evaluierung: Verwenden Sie F1, Precision, Recall (nicht Accuracy)
    • Schwellwertanpassung: Optimieren Sie den Entscheidungsschwellwert
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler
from collections import Counter

# Unaausgeglichenen Datensatz erstellen
X, y = make_classification(
    n_samples=1000, n_features=20,
    weights=[0.95, 0.05],  # 95% Klasse 0, 5% Klasse 1
    random_state=42
)

print(f"Originalverteilung: {Counter(y)}")

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

# 1. Klassengewichte
model_weighted = RandomForestClassifier(class_weight='balanced', random_state=42)
model_weighted.fit(X_train, y_train)
print("\nMit Klassengewichten:")
print(classification_report(y_test, model_weighted.predict(X_test)))

# 2. SMOTE (Oversampling der Minderheitsklasse)
smote = SMOTE(random_state=42)
X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train)
print(f"Nach SMOTE: {Counter(y_train_smote)}")

model_smote = RandomForestClassifier(random_state=42)
model_smote.fit(X_train_smote, y_train_smote)
print("\nMit SMOTE:")
print(classification_report(y_test, model_smote.predict(X_test)))

# 3. Schwellwertanpassung
y_proba = model_weighted.predict_proba(X_test)[:, 1]
threshold = 0.3  # Niedrigerer Schwellwert bevorzugt die Minderheitsklasse
y_pred_adjusted = (y_proba >= threshold).astype(int)
print("\nMit angepasstem Schwellwert:")
print(classification_report(y_test, y_pred_adjusted))

Seltenheit: Sehr häufig Schwierigkeit: Mittel


8. Was ist Kreuzvalidierung und warum ist sie wichtig?

Antwort: Die Kreuzvalidierung bewertet die Modellleistung zuverlässiger als eine einzelne Train-Test-Aufteilung.

  • Typen:
    • K-Fold: Aufteilung in k Folds
    • Stratified K-Fold: Bewahrt die Klassenverteilung
    • Time Series Split: Berücksichtigt die zeitliche Reihenfolge
  • Vorteile:
    • Robusterer Leistungsschätzer
    • Verwendet alle Daten für Training und Validierung
    • Erkennt Overfitting
from sklearn.model_selection import (
    cross_val_score, KFold, StratifiedKFold,
    TimeSeriesSplit, cross_validate
)
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris

# Daten laden
data = load_iris()
X, y = data.data, data.target

model = RandomForestClassifier(random_state=42)

# Standard K-Fold
kfold = KFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=kfold)
print(f"K-Fold Scores: {scores}")
print(f"Mittelwert: {scores.mean():.3f} (+/- {scores.std():.3f})")

# Stratified K-Fold (bewahrt die Klassenverteilung)
stratified_kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
stratified_scores = cross_val_score(model, X, y, cv=stratified_kfold)
print(f"\nStratified K-Fold: {stratified_scores.mean():.3f}")

# Time Series Split (für zeitabhängige Daten)
tscv = TimeSeriesSplit(n_splits=5)
ts_scores = cross_val_score(model, X, y, cv=tscv)
print(f"Time Series CV: {ts_scores.mean():.3f}")

# Mehrere Metriken
cv_results = cross_validate(
    model, X, y, cv=5,
    scoring=['accuracy', 'precision_macro', 'recall_macro', 'f1_macro'],
    return_train_score=True
)

print(f"\nAccuracy: {cv_results['test_accuracy'].mean():.3f}")
print(f"Precision: {cv_results['test_precision_macro'].mean():.3f}")
print(f"Recall: {cv_results['test_recall_macro'].mean():.3f}")
print(f"F1: {cv_results['test_f1_macro'].mean():.3f}")

Seltenheit: Sehr häufig Schwierigkeit: Leicht


9. Erklären Sie Precision, Recall und F1-Score.

Antwort: Klassifikationsmetriken zur Bewertung der Modellleistung:

  • Precision (Genauigkeit): Von den vorhergesagten Positiven, wie viele sind korrekt?
    • Formel: TP / (TP + FP)
    • Verwenden, wenn: Falsch Positive kostspielig sind
  • Recall (Trefferquote): Von den tatsächlichen Positiven, wie viele wurden gefunden?
    • Formel: TP / (TP + FN)
    • Verwenden, wenn: Falsch Negative kostspielig sind
  • F1-Score: Harmonisches Mittel aus Precision und Recall
    • Formel: 2 × (Precision × Recall) / (Precision + Recall)
    • Verwenden, wenn: Ein Gleichgewicht zwischen Precision und Recall erforderlich ist
from sklearn.metrics import (
    precision_score, recall_score, f1_score,
    classification_report, confusion_matrix
)
import numpy as np

# Beispielvorhersagen
y_true = np.array([0, 1, 1, 0, 1, 1, 0, 1, 0, 0])
y_pred = np.array([0, 1, 0, 0, 1, 1, 0, 1, 1, 0])

# Metriken berechnen
precision = precision_score(y_true, y_pred)
recall = recall_score(y_true, y_pred)
f1 = f1_score(y_true, y_pred)

print(f"Precision: {precision:.3f}")  # 0.800
print(f"Recall: {recall:.3f}")        # 0.800
print(f"F1-Score: {f1:.3f}")          # 0.800

# Konfusionsmatrix
cm = confusion_matrix(y_true, y_pred)
print(f"\nKonfusionsmatrix:\n{cm}")
# [[4 1]
#  [1 4]]

# Klassifikationsbericht (alle Metriken)
print("\nKlassifikationsbericht:")
print(classification_report(y_true, y_pred))

# Trade-off Beispiel
from sklearn.metrics import precision_recall_curve
import matplotlib.pyplot as plt

# Wahrscheinlichkeitsvorhersagen abrufen
y_proba = model.predict_proba(X_test)[:, 1]

# Precision-Recall bei verschiedenen Schwellenwerten berechnen
precisions, recalls, thresholds = precision_recall_curve(y_test, y_proba)

# Optimalen Schwellwert finden (F1 maximieren)
f1_scores = 2 * (precisions * recalls) / (precisions + recalls + 1e-10)
optimal_idx = np.argmax(f1_scores)
optimal_threshold = thresholds[optimal_idx]
print(f"Optimaler Schwellwert: {optimal_threshold:.3f}")

Seltenheit: Sehr häufig Schwierigkeit: Leicht


10. Was ist Regularisierung und wann würden Sie sie verwenden?

Antwort: Die Regularisierung verhindert Overfitting, indem sie die Modellkomplexität bestraft.

  • Typen:
    • L1 (Lasso): Addiert den Absolutwert der Koeffizienten
    • L2 (Ridge): Addiert die quadrierten Koeffizienten
    • Elastic Net: Kombiniert L1 und L2
  • Wann verwenden:
    • Hohe Varianz (Overfitting)
    • Viele Features
    • Multikollinearität
from sklearn.linear_model import Ridge, Lasso, ElasticNet, LinearRegression
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np

# Daten mit vielen Features generieren
X, y = make_regression(
    n_samples=100, n_features=50,
    n_informative=10, noise=10, random_state=42
)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

# Keine Regularisierung
lr = LinearRegression()
lr.fit(X_train, y_train)
lr_score = r2_score(y_test, lr.predict(X_test))
print(f"Lineare Regression R²: {lr_score:.3f}")

# L2 Regularisierung (Ridge)
ridge = Ridge(alpha=1.0)
ridge.fit(X_train, y_train)
ridge_score = r2_score(y_test, ridge.predict(X_test))
print(f"Ridge R²: {ridge_score:.3f}")

# L1 Regularisierung (Lasso)
lasso = Lasso(alpha=0.1)
lasso.fit(X_train, y_train)
lasso_score = r2_score(y_test, lasso.predict(X_test))
print(f"Lasso R²: {lasso_score:.3f}")
print(f"Lasso Nicht-Null-Koeffizienten: {np.sum(lasso.coef_ != 0)}")

# Elastic Net (L1 + L2)
elastic = ElasticNet(alpha=0.1, l1_ratio=0.5)
elastic.fit(X_train, y_train)
elastic_score = r2_score(y_test, elastic.predict(X_test))
print(f"Elastic Net R²: {elastic_score:.3f}")

# Hyperparameter-Tuning für Alpha
from sklearn.model_selection import GridSearchCV

param_grid = {'alpha': [0.001, 0.01, 0.1, 1.0, 10.0]}
grid = GridSearchCV(Ridge(), param_grid, cv=5)
grid.fit(X_train, y_train)
print(f"\nBestes Alpha: {grid.best_params_['alpha']}")
print(f"Bester CV-Score: {grid.best_score_:.3f}")

Seltenheit: Sehr häufig Schwierigkeit: Mittel


Modelltraining & Bereitstellung (5 Fragen)

11. Wie speichern und laden Sie Modelle in der Produktion?

Antwort: Die Modellserialisierung ermöglicht die Bereitstellung und Wiederverwendung.

import joblib
import pickle
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris

# Modell trainieren
X, y = load_iris(return_X_y=True)
model = RandomForestClassifier()
model.fit(X, y)

# Methode 1: Joblib (empfohlen für scikit-learn)
joblib.dump(model, 'model.joblib')
loaded_model = joblib.load('model.joblib')

# Methode 2: Pickle
with open('model.pkl', 'wb') as f:
    pickle.dump(model, f)

with open('model.pkl', 'rb') as f:
    loaded_model = pickle.load(f)

# Für TensorFlow/Keras
import tensorflow as tf

# Gesamtes Modell speichern
# keras_model.save('model.h5')
# loaded_model = tf.keras.models.load_model('model.h5')

# Nur Gewichte speichern
# keras_model.save_weights('model_weights.h5')
# new_model.load_weights('model_weights.h5')

# Für PyTorch
import torch

# Modellzustands-Dictionary speichern
# torch.save(model.state_dict(), 'model.pth')
# model.load_state_dict(torch.load('model.pth'))

# Gesamtes Modell speichern
# torch.save(model, 'model_complete.pth')
# model = torch.load('model_complete.pth')

# Versionskontrolle für Modelle
import datetime

model_version = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
model_path = f'models/model_{model_version}.joblib'
joblib.dump(model, model_path)
print(f"Modell gespeichert unter {model_path}")

Seltenheit: Sehr häufig Schwierigkeit: Leicht


12. Wie erstellen Sie eine REST-API für die Modellbereitstellung?

Antwort: REST-APIs machen Modelle für Anwendungen zugänglich.

from flask import Flask, request, jsonify
import joblib
import numpy as np

app = Flask(__name__)

# Modell beim Start laden
model = joblib.load('model.joblib')

@app.route('/predict', methods=['POST'])
def predict():
    try:
        # Daten aus der Anfrage abrufen
        data = request.get_json()
        features = np.array(data['features']).reshape(1, -1)
        
        # Vorhersage treffen
        prediction = model.predict(features)
        probability = model.predict_proba(features)
        
        # Antwort zurückgeben
        return jsonify({
            'prediction': int(prediction[0]),
            'probability': probability[0].tolist(),
            'status': 'success'
        })
    
    except Exception as e:
        return jsonify({
            'error': str(e),
            'status': 'error'
        }), 400

@app.route('/health', methods=['GET'])
def health():
    return jsonify({'status': 'healthy'})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

# FastAPI-Alternative (modern, schneller)
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

class PredictionRequest(BaseModel):
    features: list

class PredictionResponse(BaseModel):
    prediction: int
    probability: list
    status: str

@app.post("/predict", response_model=PredictionResponse)
async def predict(request: PredictionRequest):
    try:
        features = np.array(request.features).reshape(1, -1)
        prediction = model.predict(features)
        probability = model.predict_proba(features)
        
        return PredictionResponse(
            prediction=int(prediction[0]),
            probability=probability[0].tolist(),
            status="success"
        )
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

# Verwendung:
# curl -X POST "http://localhost:5000/predict" \
#      -H "Content-Type: application/json" \
#      -d '{"features": [5.1, 3.5, 1.4, 0.2]}'

Seltenheit: Sehr häufig Schwierigkeit: Mittel


13. Was ist Docker und warum ist es nützlich für die ML-Bereitstellung?

Antwort: Docker-Container packen Anwendungen mit allen Abhängigkeiten.

  • Vorteile:
    • Reproduzierbarkeit
    • Konsistenz über verschiedene Umgebungen hinweg
    • Einfache Bereitstellung
    • Isolation
# Dockerfile für ML-Modell
FROM python:3.9-slim

WORKDIR /app

# Anforderungen kopieren
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Modell und Code kopieren
COPY model.joblib .
COPY app.py .

# Port freigeben
EXPOSE 5000

# Anwendung ausführen
CMD ["python", "app.py"]
# Docker Image erstellen
docker build -t ml-model:v1 .

# Container ausführen
docker run -p 5000:5000 ml-model:v1

# Docker Compose für Multi-Container-Setup
# docker-compose.yml
version: '3.8'
services:
  model:
    build: .
    ports:
      - "5000:5000"
    environment:
      - MODEL_PATH=/app/model.joblib
    volumes:
      - ./models:/app/models

Seltenheit: Häufig Schwierigkeit: Mittel


14. Wie überwachen Sie die Modellleistung in der Produktion?

Antwort: Die Überwachung erkennt den Modellabbau und gewährleistet die Zuverlässigkeit.

  • Was ist zu überwachen:
    • Vorhersagemetriken: Genauigkeit, Latenz
    • Data Drift: Änderungen der Eingabeverteilung
    • Model Drift: Leistungsverschlechterung
    • Systemmetriken: CPU, Speicher, Fehler
import logging
from datetime import datetime
import numpy as np

class ModelMonitor:
    def __init__(self, model):
        self.model = model
        self.predictions = []
        self.actuals = []
        self.latencies = []
        self.input_stats = []
        
        # Logging einrichten
        logging.basicConfig(
            filename='model_monitor.log',
            level=logging.INFO,
            format='%(asctime)s - %(message)s'
        )
    
    def predict(self, X):
        import time
        
        # Eingabestatistiken verfolgen
        self.input_stats.append({
            'mean': X.mean(),
            'std': X.std(),
            'min': X.min(),
            'max': X.max()
        })
        
        # Latenz messen
        start = time.time()
        prediction = self.model.predict(X)
        latency = time.time() - start
        
        self.predictions.append(prediction)
        self.latencies.append(latency)
        
        # Vorhersage protokollieren
        logging.info(f"Vorhersage: {prediction}, Latenz: {latency:.3f}s")
        
        # Warnen, wenn die Latenz zu hoch ist
        if latency > 1.0:
            logging.warning(f"Hohe Latenz festgestellt: {latency:.3f}s")
        
        return prediction
    
    def log_actual(self, y_true):
        self.actuals.append(y_true)
        
        # Genauigkeit berechnen, wenn wir genügend Daten haben
        if len(self.actuals) >= 100:
            accuracy = np.mean(
                np.array(self.predictions[-100:]) == np.array(self.actuals[-100:])
            )
            logging.info(f"Rolling Accuracy (letzte 100): {accuracy:.3f}")
            
            if accuracy < 0.8:
                logging.error(f"Modellleistung verschlechtert: {accuracy:.3f}")
    
    def check_data_drift(self, reference_stats):
        if not self.input_stats:
            return
        
        current_stats = self.input_stats[-1]
        
        # Einfache Drift-Erkennung (Mittelwerte vergleichen)
        mean_diff = abs(current_stats['mean'] - reference_stats['mean'])
        if mean_diff > 2 * reference_stats['std']:
            logging.warning(f"Data Drift festgestellt: mean diff = {mean_diff:.3f}")

# Verwendung
monitor = ModelMonitor(model)
prediction = monitor.predict(X_new)
# Später, wenn das tatsächliche Label verfügbar ist
monitor.log_actual(y_true)

Seltenheit: Häufig Schwierigkeit: Mittel


15. Was ist CI/CD für maschinelles Lernen?

Antwort: CI/CD automatisiert das Testen und die Bereitstellung von ML-Modellen.

  • Continuous Integration:
    • Automatisiertes Testen
    • Code-Qualitätsprüfungen
    • Modellvalidierung
  • Continuous Deployment:
    • Automatisierte Bereitstellung
    • Rollback-Funktionen
    • A/B-Tests
# .github/workflows/ml-pipeline.yml
name: ML Pipeline

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

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      
      - name: Set up Python
        uses:
Newsletter subscription

Wöchentliche Karrieretipps, die wirklich funktionieren

Erhalten Sie die neuesten Einblicke direkt in Ihr Postfach

Erstellen Sie einen Lebenslauf, der Sie 60% schneller einstellt

Erstellen Sie in wenigen Minuten einen maßgeschneiderten, ATS-freundlichen Lebenslauf, der nachweislich 6-mal mehr Vorstellungsgespräche vermittelt.

Einen besseren Lebenslauf erstellen

Diesen Beitrag teilen

Verdoppeln Sie Ihre Vorstellungsgespräch-Rückrufe

Kandidaten, die ihre Lebensläufe auf die Stellenbeschreibung zuschneiden, erhalten 2,5-mal mehr Vorstellungsgespräche. Nutzen Sie unsere KI, um Ihren Lebenslauf sofort für jede Bewerbung anzupassen.