Основы окружений
~20 мин

Git + CI/CD

Git (branching, merge, rebase) + CI/CD (GitHub Actions) для ML: автотесты кода и данных, DVC для версионирования датасетов, автоматический деплой модели при merge в main.

Git + CI/CD — от «работает на моём ноутбуке» до автоматического деплоя

Ты обучил модель, получил отличные метрики — и что дальше? Скинуть коллеге model_final_v3_FINAL.pkl в Slack? ML-проект — это не только модель. Это код предобработки, конфиги, данные, эксперименты, Docker-образы. И всё это нужно версионировать, тестировать и деплоить. Без системы — хаос: «кто сломал прод?», «какая версия модели сейчас крутится?», «где код, который обучил ту самую модель?».

Git решает первую проблему — версионирование кода и совместная работа. CI/CD решает вторую — автоматическое тестирование и деплой. Вместе они дают гарантию: каждый push проверен, каждый merge — безопасен, каждый деплой — автоматический. Для ML-инженера это не «приятно иметь», а базовая гигиена.

CI/CD пайплайн для ML: от git push до автоматического деплоя модели
Git push запускает цепочку: тесты, обучение, оценка, деплой

Большая картина: путь кода от ноутбука до продакшна

Представь полный цикл работы ML-инженера за один день:

1. Код — пишешь новый feature engineering pipeline в ветке feature/add-time-features. 2. Commit — фиксируешь изменения: git commit -m "feat: add time-based features". Pre-commit хуки автоматически прогоняют линтер и форматтер. 3. Push — отправляешь ветку на GitHub: git push origin feature/add-time-features. 4. CI (Continuous Integration) — GitHub Actions автоматически запускает: lint → unit-тесты → тесты данных → обучение модели → проверку метрик. Если что-то упало — PR не пройдёт. 5. Code Review — коллега смотрит PR, оставляет комментарии, аппрувит. 6. Merge — код вливается в main. 7. CD (Continuous Delivery) — автоматически собирается Docker-образ, пушится в registry, деплоится на staging. Smoke-тесты проходят → production. Руками — ноль шагов после git push. Всё остальное делает автоматика.

Загрузка интерактивного виджета...

Git: ключевые концепции

Git — распределённая система контроля версий. Каждый клон репозитория — полная копия с историей. Даже без интернета ты можешь коммитить, создавать ветки, смотреть историю. Вот четыре операции, которые ты используешь каждый день:

Commit — снимок состояния проекта. Каждый коммит имеет уникальный хеш (SHA), автора, дату и сообщение. Хороший коммит — атомарный: одно логическое изменение. Не «fix everything» на 500 строк.

Branch — параллельная линия разработки. Создаёшь ветку из main, работаешь в изоляции, не мешаешь остальным. Ветка — это просто указатель на коммит, создаётся мгновенно.

Merge — объединение двух веток. git merge feature/x берёт все коммиты из ветки и вливает в текущую. Если обе ветки меняли один файл — возникает merge conflict, который нужно разрешить вручную.

Rebase — альтернатива merge. Вместо слияния «переносит» твои коммиты поверх другой ветки, создавая линейную историю. git rebase main = «сделай вид, что я начал работу от последнего коммита main». Чище история, но опаснее: переписывает коммиты. Золотое правило: никогда не делай rebase ветки, которую уже запушил и расшарил с коллегами.

# Типичный workflow
git checkout -b feature/add-catboost      # создали ветку
# ... пишем код ...
git add src/models/catboost_model.py
git commit -m "feat: add CatBoost model with time features"

# Подтягиваем свежий main
git fetch origin
git rebase origin/main                    # линейная история

git push origin feature/add-catboost      # пушим, создаём PR

Conventional Commits

Вместо git commit -m "fix" используй структурированные сообщения: feat: add feature importance plot, fix: resolve OOM in batch prediction, ci: add model quality gate, docs: update API schema. Через полгода откроешь git log и поймёшь, что происходило. Подробнее: conventionalcommits.org.

Branching-стратегии: как организовать работу команды

Когда в команде 3+ человека, нужны правила: кто куда коммитит, откуда деплоим, как ревьюим. Три основные стратегии:

GitHub Flow — самая простая. Одна ветка main (всегда рабочая). Для каждой задачи — short-lived ветка (живёт 1-5 дней). Создал PR → прошёл CI → code review → merge → автодеплой. Подходит большинству ML-команд.

Trunk-Based Development — ещё проще. Все коммитят в main (или ветки живут максимум 1 день). Требует сильную CI-дисциплину и feature flags (прятать незаконченный код за флагами). Используют команды с непрерывным деплоем: Google, Meta.

Git Flow — сложная. Ветки: main (production), develop (интеграция), feature/*, release/*, hotfix/*. Каждый релиз — отдельная ветка с тестированием. Подходит для продуктов с чётким релизным циклом (раз в 2 недели, раз в месяц). Для ML-команд обычно избыточна.

Что выбрать?

Для ML-команды из 2-10 человек — GitHub Flow. Просто, понятно, работает. Trunk-based — если у вас зрелая CI/CD и быстрые тесты. Git Flow — если продукт с формальными релизами и QA-циклом. В 90% случаев GitHub Flow — правильный ответ.

CI для ML: что тестировать помимо кода

В обычном софте CI запускает unit-тесты и линтер. В ML этого недостаточно — у тебя три источника ошибок: код, данные и модель. Каждый нужно тестировать отдельно.

Уровень 1: Код. Стандартные проверки — работают быстро, запускаются на каждый коммит: • Linting (ruff) — стиль кода, неиспользуемые импорты, потенциальные баги • Type checking (mypy) — ловит ошибки типов до запуска • Unit-тесты (pytest) — функции предобработки, feature engineering, утилиты • Pre-commit hooks — ruff + mypy + проверка на большие файлы локально, до push

Уровень 2: Данные. Проверяешь данные перед обучением — ловишь проблемы на входе: • Нет пропусков в критичных колонках • Типы данных соответствуют схеме (age — число, не строка) • Распределение не сдвинулось относительно baseline (PSI < 0.25) • Нет дупликатов, нет утечки из будущего (target leakage) Инструменты: Great Expectations, Pandera, dbt tests.

Уровень 3: Модель. После обучения — проверяешь, что модель не деградировала: • Метрики не хуже baseline (AUC ≥ 0.90) • Нет деградации по сегментам (новые пользователи, premium) • Inference-время ≤ 100ms • Модель не предсказывает один класс для всех • Размер модели ≤ лимита (актуально для мобильных/edge)

# Пример: тесты данных + модели в CI
import pytest
from sklearn.metrics import roc_auc_score

def test_no_nulls_in_critical_columns(df):
    """Критичные фичи не должны содержать пропуски"""
    critical = ["user_id", "amount", "timestamp"]
    for col in critical:
        assert df[col].notna().all(), f"Пропуски в {col}"

def test_feature_distribution_stable(train_df, fresh_df):
    """PSI < 0.25 — распределение не сдвинулось критично"""
    for col in train_df.select_dtypes("number").columns:
        psi = calc_psi(train_df[col], fresh_df[col])
        assert psi < 0.25, f"{col}: PSI={psi:.3f} — data drift!"

def test_model_quality(model, test_data):
    """AUC не упал ниже порога"""
    preds = model.predict_proba(test_data.X)[:, 1]
    auc = roc_auc_score(test_data.y, preds)
    assert auc >= 0.90, f"AUC {auc:.3f} < 0.90"

CD для ML: от registry до production

Continuous Delivery в ML — это не просто «собрать Docker и задеплоить». У тебя два артефакта: код (API-сервис, предобработка) и модель (обученные веса). Они могут меняться независимо. CD должен уметь обновлять оба.

Типичный pipeline деплоя ML-модели: 1. Model Registry — обученная модель регистрируется с версией и метриками (MLflow, W&B). Подробнее — в ноде MLOps Basics. 2. Staging — модель деплоится в staging-окружение. Прогоняются интеграционные тесты: API отвечает, латентность в норме, предсказания адекватны. 3. Shadow mode — новая модель работает параллельно с production, но её предсказания не показываются пользователям. Сравниваешь метрики. 4. Canary deploy — 5-10% трафика переключается на новую модель. Если метрики не падают за 1-2 дня — продолжаешь. 5. Full rollout — 100% трафика на новую модель. Старая версия остаётся в registry для быстрого отката.

Rollback за 30 секунд

Главное преимущество CD + Model Registry: если новая модель сломала метрики на проде, ты откатываешь на предыдущую версию одной командой. Без registry — «где та модель, которая работала в прошлый вторник?».

GitHub Actions: CI/CD для ML-проекта

GitHub Actions — бесплатный CI/CD для публичных репозиториев (2000 минут/месяц для приватных). Описываешь pipeline в YAML, GitHub запускает его на каждый push или PR. Вот полный пример для ML-проекта:

# .github/workflows/ml-ci.yml
name: ML Pipeline CI
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install dependencies
        run: pip install uv && uv sync

      # Уровень 1: код
      - name: Lint
        run: uv run ruff check .
      - name: Type check
        run: uv run mypy src/
      - name: Unit tests
        run: uv run pytest tests/unit/ -v

      # Уровень 2: данные (на PR — только smoke)
      - name: Data validation
        run: uv run pytest tests/data/ -v

      # Уровень 3: модель (только для main)
      - name: Model quality gate
        if: github.ref == 'refs/heads/main'
        run: |
          uv run python scripts/train.py --config configs/ci.yaml
          uv run pytest tests/model/ -v
# .github/workflows/deploy.yml — CD при merge в main
name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    needs: lint-and-test
    steps:
      - uses: actions/checkout@v4

      - name: Build Docker image
        run: docker build -t ml-service:{{ github.sha }} .

      - name: Push to registry
        run: |
          echo {{ secrets.REGISTRY_TOKEN }} | 
            docker login ghcr.io -u {{ github.actor }} --password-stdin
          docker push ghcr.io/{{ github.repository }}/ml-service:{{ github.sha }}

      - name: Deploy to staging
        run: |
          kubectl set image deployment/ml-service 
            app=ghcr.io/{{ github.repository }}/ml-service:{{ github.sha }}

Тяжёлые задачи (полная тренировка, GPU) — не на каждый PR. Выноси в отдельный workflow: on: schedule (раз в неделю) или workflow_dispatch (ручной запуск). GitHub предоставляет GPU-runners, но платно. Альтернатива — self-hosted runner на своём сервере с GPU.

DVC: версионирование данных и моделей

Git отлично версионирует код, но не подходит для больших файлов: датасет на 5 GB или модель на 2 GB в Git — это боль (медленный clone, раздутый .git). DVC (Data Version Control) решает эту проблему: данные и модели хранятся в S3/GCS/локально, а в Git лежат только маленькие .dvc-файлы — указатели на конкретные версии.

Как это работает: 1. dvc init — инициализируешь DVC в Git-репозитории 2. dvc add data/train.csv — DVC сохраняет файл в кеш, а в Git добавляет data/train.csv.dvc (хеш + метаданные) 3. dvc push — загружает данные в remote storage (S3, GCS, SSH) 4. git commit + git push — в Git уходит только .dvc-файл 5. Коллега делает git pull + dvc pull — получает те же данные

# Настройка DVC
dvc init
dvc remote add -d storage s3://my-bucket/dvc-store

# Версионируем датасет
dvc add data/train.csv          # → data/train.csv.dvc
git add data/train.csv.dvc .gitignore
git commit -m "data: add training dataset v1"

# Обновили данные → новая версия
dvc add data/train.csv          # хеш изменился
git add data/train.csv.dvc
git commit -m "data: update training dataset v2"
dvc push                        # → S3

# Коллега получает данные
git pull && dvc pull            # скачает именно версию v2

# Откат к предыдущей версии данных
git checkout HEAD~1 -- data/train.csv.dvc
dvc checkout                    # → данные v1 вернулись

DVC pipelines — следующий уровень. Описываешь ML-пайплайн в dvc.yaml: какие стадии (preprocess → train → evaluate), какие входы/выходы. dvc repro запускает только те стадии, входы которых изменились. Это как Makefile для ML.

# dvc.yaml — воспроизводимый ML pipeline
stages:
  preprocess:
    cmd: python src/preprocess.py
    deps:
      - data/raw/
      - src/preprocess.py
    outs:
      - data/processed/train.parquet

  train:
    cmd: python src/train.py
    deps:
      - data/processed/train.parquet
      - src/train.py
      - configs/model.yaml
    outs:
      - models/model.pkl
    metrics:
      - metrics/scores.json:
          cache: false

  evaluate:
    cmd: python src/evaluate.py
    deps:
      - models/model.pkl
      - data/processed/test.parquet
    plots:
      - plots/roc.json

dvc repro — запускает pipeline. Если изменился только configs/model.yaml, пересоберёт train и evaluate, но пропустит preprocess. dvc metrics show покажет метрики, dvc plots show — графики. Вся история экспериментов — в Git.

🎯 На собеседовании

Junior

Зачем Git в ML-проекте? Версионирование кода, совместная работа, возможность откатиться. Без Git — хаос из файлов model_v2_final_FINAL.py. • Что такое CI/CD? CI — автоматические тесты при каждом push (lint, unit tests). CD — автоматический деплой при merge в main (Docker build → registry → staging → production). • Merge vs rebase? Merge — сливает ветки, сохраняет историю. Rebase — переносит коммиты, линейная история. Rebase чище, но не делай на расшаренных ветках. • Что такое DVC? Git для данных и моделей. В Git — маленький .dvc-файл (указатель), сами данные — в S3/GCS.

Middle

Какую branching-стратегию выбрать? GitHub Flow для большинства ML-команд: main + short-lived feature branches + PR + CI. Git Flow — для формальных релизных циклов. Trunk-based — для зрелых команд с сильной CI. • Что тестировать в ML CI? Три уровня: код (ruff, mypy, pytest), данные (schema, пропуски, PSI), модель (AUC ≥ baseline, latency, нет деградации по сегментам). • Как деплоить ML-модель? Model Registry (версия) → staging (интеграционные тесты) → shadow mode (параллельно с prod) → canary (5-10% трафика) → full rollout. Rollback из registry за 30 секунд. • DVC pipelines — зачем? Воспроизводимость: dvc repro пересобирает только изменившиеся стадии. Метрики и данные версионируются вместе с кодом.

Senior

Спроектируй CI/CD для ML-команды из 10 человек. GitHub Flow + pre-commit (ruff, mypy) + GitHub Actions (lint → data tests → train → model quality gate → Docker build → push registry → deploy staging → smoke tests → canary 10% → full rollout). DVC для данных. Model Registry для версий моделей. Мониторинг после деплоя. • Как тестировать модель в CI без GPU и полного датасета? Маленький тестовый датасет (1000 строк). CPU-only smoke train (1 эпоха). Проверяем: pipeline не падает, метрики считаются, модель сериализуется. Полное обучение — weekly job на GPU-runner. • Training-serving skew в контексте CI/CD? Код предобработки в train и serve — один и тот же модуль. Feature store. Integration тест: отправить тестовый запрос в API, сравнить предсказание с offline-пайплайном. DVC гарантирует версию данных.

Собираем всё вместе

Git + CI/CD для ML — это цепочка: код в ветке → pre-commit hooks → push → CI (lint, тесты кода, данных, модели) → code review → merge → CD (Docker → registry → staging → canary → production). DVC добавляет версионирование данных и воспроизводимые пайплайны. Model Registry — версионирование моделей и мгновенный rollback.

Если запомнить одну вещь: ML-проект — это не только модель, а полный pipeline от данных до продакшна. Git + CI/CD + DVC — минимальный набор, чтобы этот pipeline был воспроизводимым, тестируемым и автоматическим.

Дальше на роадмапе: Docker — как упаковать модель в контейнер, MLOps Basics — полный цикл ML-системы от experiment tracking до мониторинга.