HardТеория14 min

ML платформа

MLOps, model registry, experiment tracking, CI/CD for ML и инфраструктура ML-платформы

Что такое ML Platform

ML Platform — инфраструктура и инструменты для полного жизненного цикла ML: от экспериментов до production. Платформа решает проблему: «Модель работает в notebook, но как доставить её в production?»

Компоненты ML Platform

Компонент Назначение Примеры инструментов
Experiment Tracking Логирование экспериментов MLflow, W&B, Neptune
Feature Store Хранение и serving features Feast, Tecton, Hopsworks
Model Registry Версионирование моделей MLflow, Vertex AI
Training Infrastructure GPU/TPU для обучения Kubernetes, Ray
Model Serving Production inference KServe, Triton, TorchServe
Monitoring Drift, quality, latency Evidently, NannyML, Prometheus
Data Pipeline ETL для ML Airflow, Prefect, Dagster
CI/CD for ML Автоматизация pipeline GitHub Actions, Jenkins

MLOps

MLOps — применение DevOps-практик к ML-проектам. Автоматизация процесса от данных до production.

Уровни зрелости MLOps

Уровень Описание Характеристика
0 Manual Notebook → ручной деплой
1 ML Pipeline Автоматизированный training
2 CI/CD Pipeline Автоматический ретрейнинг + деплой
3 Full Automation Continuous training + monitoring + auto-retrain

CI/CD for ML

В отличие от обычного CI/CD, ML CI/CD включает проверку данных и модели.

Code Change:     Code → Lint → Test → Build → Deploy
ML Pipeline:     Data → Validate → Train → Evaluate → Register → Deploy → Monitor
                   ↓       ↓         ↓         ↓
              Data tests  Schema   Model    Quality
              Quality     check    tests    gates

Model Registry

Model Registry — версионированное хранилище обученных моделей с метаданными.

Клиент для Model Registry

<?php

declare(strict_types=1);

namespace App\ML;

/**
 * Client for interacting with a Model Registry (e.g., MLflow).
 */
final readonly class ModelRegistryClient
{
    public function __construct(
        private string $registryUrl,
    ) {}

    /**
     * Get the latest production model version.
     *
     * @return ModelVersion
     */
    public function getProductionModel(string $modelName): ModelVersion
    {
        $response = $this->request(
            "/api/2.0/mlflow/registered-models/get-latest-versions",
            ['name' => $modelName, 'stages' => ['Production']],
        );

        $versions = $response['model_versions'] ?? [];

        if (empty($versions)) {
            throw new \RuntimeException("No production model found for '{$modelName}'");
        }

        $latest = $versions[0];

        return new ModelVersion(
            name: $latest['name'],
            version: (int) $latest['version'],
            stage: $latest['current_stage'],
            runId: $latest['run_id'],
            artifactUri: $latest['source'],
            createdAt: new \DateTimeImmutable('@' . ($latest['creation_timestamp'] / 1000)),
        );
    }

    /**
     * Transition model version to a new stage.
     */
    public function transitionStage(
        string $modelName,
        int $version,
        string $stage, // 'Staging', 'Production', 'Archived'
    ): void {
        $this->request(
            "/api/2.0/mlflow/model-versions/transition-stage",
            [
                'name' => $modelName,
                'version' => (string) $version,
                'stage' => $stage,
                'archive_existing_versions' => true,
            ],
        );
    }

    /**
     * List all model versions.
     *
     * @return array<ModelVersion>
     */
    public function listVersions(string $modelName): array
    {
        $response = $this->request(
            "/api/2.0/mlflow/model-versions/search",
            ['filter' => "name='{$modelName}'"],
        );

        return array_map(
            static fn(array $v) => new ModelVersion(
                name: $v['name'],
                version: (int) $v['version'],
                stage: $v['current_stage'],
                runId: $v['run_id'],
                artifactUri: $v['source'],
                createdAt: new \DateTimeImmutable('@' . ($v['creation_timestamp'] / 1000)),
            ),
            $response['model_versions'] ?? [],
        );
    }

    private function request(string $endpoint, array $data): array
    {
        $ch = curl_init($this->registryUrl . $endpoint);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode($data),
            CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
        ]);

        $response = curl_exec($ch);
        curl_close($ch);

        return json_decode($response, true, 512, JSON_THROW_ON_ERROR);
    }
}

final readonly class ModelVersion
{
    public function __construct(
        public string $name,
        public int $version,
        public string $stage,
        public string $runId,
        public string $artifactUri,
        public \DateTimeImmutable $createdAt,
    ) {}
}
## Experiment Tracking

Experiment tracking — систематическое логирование параметров, метрик и артефактов каждого эксперимента.

Что логировать

Категория Примеры
Parameters learning_rate, batch_size, epochs
Metrics accuracy, loss, F1, AUC
Artifacts Модель, графики, confusion matrix
Environment Python version, GPU, dependencies
Data Dataset version, split ratio, size
Tags experiment_type, author, ticket

Data Versioning

Инструмент Описание
DVC Git for data — версионирование датасетов
Delta Lake ACID-транзакции для data lakes
LakeFS Git-like operations для object storage

Model Deployment Patterns

Паттерн Описание Когда
Shadow deployment Новая модель работает параллельно, результаты не используются Перед A/B
Canary Малый % трафика на новую модель После shadow
Blue-Green Мгновенное переключение Когда canary успешен
Multi-armed bandit Автоматическое распределение трафика A/B + оптимизация

Monitoring в Production

Что мониторить

Категория Метрики
Model quality Accuracy, precision, recall (с задержкой)
Data quality Missing values, outliers, schema
Data drift Distribution changes в features
Concept drift Изменение связи input → output
System Latency, throughput, errors, memory
Business CTR, conversion, revenue

Мониторинг предсказаний

<?php

declare(strict_types=1);

namespace App\ML;

/**
 * Log predictions for monitoring and analysis.
 */
final readonly class PredictionLogger
{
    public function __construct(
        private \Redis $redis,
        private string $prefix = 'ml_predictions:',
    ) {}

    /**
     * Log a prediction for monitoring.
     */
    public function logPrediction(
        string $modelName,
        string $modelVersion,
        array $features,
        mixed $prediction,
        float $confidence,
        float $latencyMs,
    ): void {
        $entry = json_encode([
            'timestamp' => (new \DateTimeImmutable())->format(\DATE_ATOM),
            'model' => $modelName,
            'version' => $modelVersion,
            'prediction' => $prediction,
            'confidence' => $confidence,
            'latency_ms' => $latencyMs,
            'features_hash' => md5(json_encode($features)),
        ]);

        $key = $this->prefix . $modelName . ':' . date('Y-m-d');

        $this->redis->rPush($key, $entry);
        $this->redis->expire($key, 604800); // Keep for 7 days
    }

    /**
     * Get prediction statistics for monitoring dashboard.
     *
     * @return array{count: int, avg_confidence: float, avg_latency_ms: float, p99_latency_ms: float}
     */
    public function getStats(string $modelName, string $date): array
    {
        $key = $this->prefix . $modelName . ':' . $date;
        $entries = $this->redis->lRange($key, 0, -1);

        if (empty($entries)) {
            return ['count' => 0, 'avg_confidence' => 0, 'avg_latency_ms' => 0, 'p99_latency_ms' => 0];
        }

        $confidences = [];
        $latencies = [];

        foreach ($entries as $entry) {
            $data = json_decode($entry, true);
            $confidences[] = $data['confidence'];
            $latencies[] = $data['latency_ms'];
        }

        sort($latencies);
        $p99Index = (int) (count($latencies) * 0.99);

        return [
            'count' => count($entries),
            'avg_confidence' => round(array_sum($confidences) / count($confidences), 4),
            'avg_latency_ms' => round(array_sum($latencies) / count($latencies), 2),
            'p99_latency_ms' => round($latencies[$p99Index] ?? end($latencies), 2),
        ];
    }
}
## Итоги
Концепция Суть
ML Platform Инфраструктура для полного ML lifecycle
MLOps DevOps для ML: CI/CD, monitoring, automation
Model Registry Версионирование и стадии моделей
Experiment Tracking Логирование параметров и метрик
Data Versioning Git-подобное версионирование данных
Production Monitoring Drift detection + quality + latency

Для инженера: ML Platform — это software engineering задача. ML-инженеры строят модели, а platform engineers строят инфраструктуру для их надёжной работы в production.