Dezember 21, 2025
14 Min. Lesezeit

Vorstellungsgesprächsfragen für angehende Machine-Learning-Ingenieure: Der komplette Leitfaden

interview
career-advice
job-search
entry-level
Vorstellungsgesprächsfragen für angehende Machine-Learning-Ingenieure: Der komplette Leitfaden
MB

Milad Bonakdar

Autor

Meistern Sie die Grundlagen des ML-Engineerings mit wichtigen Fragen für Vorstellungsgespräche, die Python, ML-Algorithmen, Modelltraining, Grundlagen der Bereitstellung und MLOps für angehende Machine-Learning-Ingenieure abdecken.


Einführung

Machine-Learning-Ingenieure entwickeln, implementieren und warten ML-Systeme in der Produktion. Von Junior ML-Ingenieuren wird erwartet, dass sie über fundierte Programmierkenntnisse, ein Verständnis von ML-Algorithmen, Erfahrung mit ML-Frameworks und Kenntnisse über Bereitstellungspraktiken verfügen.

Dieser Leitfaden behandelt wichtige Interviewfragen für Junior Machine Learning Engineers. Wir untersuchen Python-Programmierung, ML-Algorithmen, Modelltraining und -evaluierung, Bereitstellungsgrundlagen und MLOps-Grundlagen, um Ihnen bei der Vorbereitung auf Ihre erste ML-Engineering-Rolle zu helfen.


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

Decorative doodle

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.

Vorstellungsgesprächsfragen für angehende Machine-Learning-Ingenieure: Der komplette Leitfaden | Minova - ATS Resume Builder