Skip to content

RezenkovD/MLOps

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MLOps Лабораторна №1: Налаштування MLOps середовища

Автор: Дмитро Рєзєнков Варіант: 12 Дата: 2026-05-06

Опис проекту

Повноцінний відтворюваний ML-проект, що демонструє інтеграцію Git, DVC, MLflow та scikit-learn Pipeline для задачі багатокласової класифікації текстів.

  • Датасет: 20 Newsgroups (sklearn.datasets.fetch_20newsgroups), підмножина 4 категорій: alt.atheism, comp.graphics, sci.med, soc.religion.christian (3 669 документів) — стандартний sklearn-бенчмарк, дозволяє провести 7 експериментів за прийнятний час на CPU. Перехід на повні 20 класів робиться зміною списку CATEGORIES у src/data/create_dataset.py.
  • Основна модель: Multinomial Naive Bayes
  • Альтернативні моделі: Logistic Regression, Linear SVC

Структура проекту

MLOps/
├── data/
│   ├── raw/                       # Сирий датасет (під DVC)
│   ├── processed/                 # Оброблені дані
│   └── external/                  # Зовнішні джерела
├── models/                        # Серіалізовані моделі (під DVC)
│   └── pipeline.pkl               # Найкращий pipeline
├── notebooks/                     # Дослідницькі ноутбуки
├── scripts/
│   ├── run_experiments.py         # Запускає всі 7 експериментів
│   ├── train_best_pipeline.py     # Тренує final pipeline на повному датасеті
│   ├── experiments_summary.json   # Зведення метрик усіх runs
│   └── best_run.json              # Параметри найкращого run
├── src/
│   ├── data/create_dataset.py     # Завантаження 20 Newsgroups -> CSV
│   ├── models/
│   │   ├── pipeline.py            # Фабрика Pipeline (TF-IDF + класифікатор)
│   │   └── train.py               # Тренування одного run з повним логуванням MLflow
│   └── utils.py                   # load_model_from_file, load_model_from_mlflow, predict
├── tests/
├── .gitignore
├── requirements.txt
└── README.md

Розділення data/raw → processed → external:

  • raw/ — сирі, незмінні дані (single source of truth)
  • processed/ — результат feature engineering, відтворюваний з raw
  • external/ — дані з третіх джерел (довідники, лексикони)

Швидкий старт

Передумови

  • Python 3.10+
  • Git
  • ~500 МБ вільного місця

Встановлення

git clone <url>
cd MLOps
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Отримання даних (через DVC)

dvc pull

Якщо локальний remote (/tmp/dvc-storage) недоступний, перегенеруйте:

python -m src.data.create_dataset

Запуск експериментів

mlflow ui --port 5000 &           # UI на http://localhost:5000
python scripts/run_experiments.py # 7 runs у експерименті lab1-variant12

Тренування найкращої моделі та збереження

python scripts/train_best_pipeline.py
dvc add models/pipeline.pkl
git add models/pipeline.pkl.dvc && git commit -m "Update best pipeline"
dvc push

Використання моделі

from src.utils import load_model_from_file, predict

model = load_model_from_file('models/pipeline.pkl')
predict(model, ['A new vaccine reduces side effects in clinical trials'])
# array([2])  # 2 = sci.med

Експерименти

Конфігурація

Усі експерименти використовують train_test_split(test_size=0.2, random_state=42, stratify=y) та 5-fold cross-validation на train. Pipeline: TfidfVectorizer (stop_words='english', min_df=2, sublinear_tf=True) → classifier.

Результати (відсортовано за test F1-weighted)

Run Модель Гіперпараметри CV mean ± std Test Acc Test F1
svc_C0.5_bi LinearSVC C=0.5, max_features=20000, ngram=(1,2) 0.8848 ± 0.0082 0.8856 0.8842
logreg_C10_bi LogReg C=10.0, max_features=20000, ngram=(1,2) 0.8814 ± 0.0107 0.8801 0.8788
nb_alpha0.1_uni NB α=0.1, max_features=10000, ngram=(1,1) 0.8804 ± 0.0096 0.8787 0.8777
svc_C1_uni LinearSVC C=1.0, max_features=10000, ngram=(1,1) 0.8811 ± 0.0095 0.8787 0.8776
nb_alpha0.5_bi NB α=0.5, max_features=10000, ngram=(1,2) 0.8637 ± 0.0091 0.8692 0.8666
logreg_C1_uni LogReg C=1.0, max_features=10000, ngram=(1,1) 0.8790 ± 0.0096 0.8665 0.8646
nb_alpha1.0_uni NB α=1.0, max_features=5000, ngram=(1,1) 0.8504 ± 0.0047 0.8610 0.8578

Найкраща модель

  • Pipeline: TfidfVectorizer(max_features=20000, ngram_range=(1,2)) → LinearSVC(C=0.5, max_iter=2000, random_state=42)
  • test_f1_weighted: 0.8842
  • test_accuracy: 0.8856
  • cv_mean_accuracy: 0.8848 ± 0.0082
  • MLflow run_id: 27d7522fab36444e825d27a242981cf4 (експеримент lab1-variant12)
  • Final retrained run_id: 7c209cefb4d34791a7143e909165384c (експеримент lab1-variant12-final)

Аналіз впливу гіперпараметрів

  • α у NB: зменшення з 1.0 → 0.1 дало +2.0 п.п. F1 (менше згладжування — більше уваги до рідкісних термінів, що важливо для коротких документів).
  • n-grams: додавання біграмів покращило LogReg (+1.4 п.п.) та LinearSVC (+0.7 п.п.) ціною x4 збільшення max_features. Для NB ефект слабший — біграми вводять колінеарні ознаки, які NB обробляє гірше через припущення незалежності.
  • C у LogReg/SVC: збільшення дозволяє моделі підлаштуватись під складніші межі; для LogReg C=10 з біграмами дав +1.4 п.п. F1.
  • max_features: збільшення з 5k до 20k стабільно покращувало результати, але virtual diminishing returns після ~10k для уніграмів.

Інструкції для відтворення

Відтворення на новій машині:

# 1. Клонування проекту
git clone <repo-url>
cd MLOps

# 2. Залежності
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

# 3. Дані з DVC remote
dvc pull

# 4. Запуск експериментів
python scripts/run_experiments.py

# 5. Перегляд результатів
mlflow ui --port 5000

Повернення до старішої версії датасету або моделі:

git log --oneline -- data/raw/dataset.csv.dvc   # знайти потрібний commit
git checkout <commit-hash> data/raw/dataset.csv.dvc
dvc checkout data/raw/dataset.csv.dvc

Контрольні питання

1. Що таке MLOps і які проблеми він вирішує? Назвіть п'ять основних компонентів MLOps інфраструктури.

MLOps — набір практик, що поєднує розробку ML-моделей з операційними процесами DevOps для автоматизації побудови, тестування, деплою та супроводу ML-систем.

Проблеми, які вирішує:

  • Відтворюваність: фіксація даних, коду, гіперпараметрів і середовища.
  • Версіонування великих артефактів: датасетів і моделей, для яких Git непридатний.
  • Простежуваність експериментів: хто/коли/з якими параметрами тренував яку модель.
  • Continuous training & deployment: автоматизація retraining та rollout у продакшн.
  • Моніторинг моделей: виявлення data drift, concept drift, деградації якості в проді.

П'ять основних компонентів:

  1. Version Control: код (Git), дані та моделі (DVC, LakeFS, MLflow Registry).
  2. Experiment Tracking: MLflow, W&B, Neptune.
  3. Pipeline Orchestration: Airflow, Kubeflow, Prefect, Dagster.
  4. Model Serving / Deployment: MLflow Models, TorchServe, BentoML, KServe.
  5. Monitoring & Observability: Evidently, Prometheus, Grafana, дашборди для метрик якості та системних метрик.

2. Чому Git не підходить для версіонування великих датасетів? Які компоненти ML-проекту потребують версіонування?

Git зберігає повний blob кожної версії файлу в .git/objects через delta-compression, оптимізовану для текстових (рядкових) змін. Для бінарних або дуже великих файлів це призводить до:

  • Експоненційного зростання .git/: датасет 1 ГБ із 10 версіями = ~10 ГБ репо.
  • Повільних clone/fetch/checkout (кожен користувач завантажує всю історію).
  • Неефективного diff: бінарні зміни не дельтуються — кожна версія зберігається повністю.
  • GitHub обмежує файли > 100 МБ; LFS — 1 ГБ безкоштовно і платний понад.

Версіонувати в ML-проекті потрібно:

  • Код: *.py, конфіги (YAML, JSON), Dockerfile, скрипти.
  • Дані: raw, processed, external — через DVC.
  • Моделі: serialized артефакти (.pkl, .onnx, .h5) — через DVC або MLflow Registry.
  • Гіперпараметри і параметри тренування — у MLflow (params).
  • Метрики експериментів — у MLflow (metrics).
  • Залежності: requirements.txt, pyproject.toml, Pipfile.lock.
  • Pipelines: послідовність етапів (DVC pipelines, MLflow Projects).

3. Що зберігається в .dvc файлах і навіщо? Поясніть різницю між dvc add і git add.

.dvc-файл — текстовий YAML-метафайл, що містить:

  • md5 (контрольну суму вмісту реального файлу),
  • size (розмір),
  • path (відносний шлях),
  • (опціонально) залежності, outs, deps для DVC pipelines.

Приклад з цього проекту:

outs:
- md5: dea055c4e3f378e7d24cfebfb6e2e6c4
  size: 5205498
  hash: md5
  path: dataset.csv

.dvc-файл маленький (< 1 КБ) — його можна спокійно зберігати в Git. Сам датасет лежить у DVC remote (S3, GDrive, локальна папка) і витягується через dvc pull.

Різниця:

Команда Куди потрапляє файл
git add file.csv Повний вміст потрапляє в .git/objects — погано для великих файлів.
dvc add file.csv Створює file.csv.dvc (метадані) + переносить файл у .dvc/cache, додає до .gitignore. У Git іде лише метафайл.

Workflow: dvc addgit add file.csv.dvc .gitignoregit commitdvc push (фактичні дані → remote).

4. Назвіть чотири компоненти MLflow. Що таке run, experiment, parameter, metric, artifact?

Чотири компоненти:

  1. MLflow Tracking — API + UI для логування параметрів, метрик, артефактів і коду під час тренування.
  2. MLflow Projects — стандартизований формат пакування ML-коду (MLproject + conda.yaml) для відтворюваного запуску.
  3. MLflow Models — універсальний формат серіалізації моделі з метаданими (signature, environment, flavor) для деплою на різні платформи.
  4. MLflow Model Registry — централізоване сховище версій моделей з life-cycle stages (None / Staging / Production / Archived).

Поняття:

  • Experiment — логічна група пов'язаних runs, що відповідає одній задачі/гіпотезі (у нас: lab1-variant12).
  • Run — одне виконання тренувального коду з конкретним набором параметрів. Ідентифікується унікальним run_id.
  • Parameter — вхідне значення run (гіперпараметр моделі, random_state, test_size). Логуються через mlflow.log_param/log_params.
  • Metric — числовий вихід run (accuracy, f1, loss). Логуються через mlflow.log_metric/log_metrics. Можуть мати timestamp/step для часових серій.
  • Artifact — будь-який файл, прив'язаний до run (модель, графік, classification_report, confusion_matrix). Логується через mlflow.log_artifact або типізовані mlflow.<flavor>.log_model.

5. Що таке scikit-learn Pipeline? Чому Pipeline запобігає data leakage?

Pipeline інкапсулює послідовність кроків ((name, transformer) для preprocessing і фінальний estimator) як єдиний об'єкт, що реалізує fit/transform/predict. У нашому проекті:

Pipeline([('tfidf', TfidfVectorizer(...)), ('clf', LinearSVC(...))])

Запобігання data leakage:

Без Pipeline типова помилка — застосувати fit_transform на ВСЬОМУ датасеті ДО train_test_split:

X_scaled = scaler.fit_transform(X)               # бачить test!
X_train, X_test = train_test_split(X_scaled)

Тоді статистики (mean, std, IDF, словник) обчислюються з урахуванням тестових даних, що штучно завищує метрики.

Pipeline розв'язує це автоматично: при pipeline.fit(X_train, y_train) кожен transformer виконує fit ТІЛЬКИ на train; при pipeline.predict(X_test) ті ж самі transformers роблять лише transform (з параметрами, навченими на train). У cross-validation це особливо важливо — fit для кожного fold відбувається лише на train fold.

Додаткові переваги: один сериалізований об'єкт містить весь pipeline (preprocessing + model), що спрощує deployment і запобігає розсинхронізації preprocessing між тренуванням і інференсом.

6. Обґрунтуйте структуру директорій вашого проекту. Чому важливо розділяти raw/processed/external дані?

Структура слідує канонічному cookiecutter-data-science layout, доповненому MLOps-специфічними каталогами (models/, scripts/).

Розділення data/:

  • raw/ — сирі, незмінні дані (single source of truth). Будь-яке відтворення має починатися звідси. У нас — оригінальний CSV від fetch_20newsgroups.
  • processed/ — результат препроцесингу (feature engineering, очищення, encode). Має бути повністю відтворюваним з raw скриптами в src/data/. Не зберігається довго — переробляється за потреби.
  • external/ — дані з третіх джерел (словники, embeddings, lookup-таблиці), які ми не контролюємо, але від яких залежать процеси.

Чому це важливо:

  • Відтворюваність: raw зафіксований у DVC, processed виводиться з raw + коду — отже, експеримент завжди можна відновити.
  • Розділення відповідальності: raw не зачіпає логіка препроцесингу, що знижує ризик випадкового пошкодження.
  • Економія сховища: processed можна не пушити у DVC remote, бо він відтворюється.
  • Аудит: видно, які саме external джерела використано і коли вони змінилися.

Каталоги src/data, src/features, src/models дзеркалюють етапи pipeline, а scripts/ містить orchestration-точки (entry points, які не імпортують одне одного).

7. Напишіть команди для клонування проекту та отримання всіх даних.

git clone <repo-url> mlops-lab1
cd mlops-lab1

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

dvc pull                          # тягне data/raw/dataset.csv та models/pipeline.pkl з remote
ls data/raw/ models/              # перевірка

python -c "from src.utils import load_model_from_file; print('OK', load_model_from_file('models/pipeline.pkl').named_steps.keys())"

Якщо remote недоступний (наприклад, локальний /tmp/dvc-storage був видалений):

python -m src.data.create_dataset                  # перегенерувати датасет
python scripts/train_best_pipeline.py              # перетренувати модель

8. Колега хоче відтворити ваш експеримент. Які інструкції дати? Потрібно повернутись до моделі тижневої давності. Як?

Інструкції відтворення:

  1. git clone <url> && cd MLOps
  2. python3 -m venv .venv && source .venv/bin/activate
  3. pip install -r requirements.txt — фіксовані версії гарантують ідентичні залежності.
  4. dvc pull — отримати датасет і модель з remote.
  5. python scripts/run_experiments.py — запустити всі 7 runs (random_state=42 гарантує однакові train/test splits і CV-folds).
  6. mlflow ui --port 5000 — порівняти отримані метрики з scripts/experiments_summary.json — мають збігатися bit-to-bit.

Повернення до моделі тижневої давності:

# 1. Знайти commit тижневої давності, що змінював модель
git log --since='1 week ago' --until='6 days ago' -- models/pipeline.pkl.dvc

# 2. Відновити .dvc-файл з того commit
git checkout <commit-hash> -- models/pipeline.pkl.dvc

# 3. Витягти відповідну версію моделі з DVC cache/remote
dvc checkout models/pipeline.pkl.dvc

# 4. (Опційно) повернути увесь стан репо на той момент
git checkout <commit-hash>
dvc checkout

Для звітів MLflow аналогічно — кожен run має run_id, через mlflow.sklearn.load_model(f"runs:/{run_id}/pipeline") модель відновлюється точно з того стану.

9. Порівняйте ваші результати з та без Pipeline. Який вплив має кожен гіперпараметр на метрики?

Pipeline vs. без Pipeline:

Ми не запускали окремий експеримент «без Pipeline», але data leakage чітко продемонстрований у літературі: при TfidfVectorizer.fit_transform на повних даних до split-у IDF обчислюється з урахуванням тесту, тестовий accuracy зазвичай завищений на 0.5–2 п.п. Cross-validation у такому варіанті ще оптимістичніший — fold-leak через спільний словник.

З Pipeline: TfidfVectorizer.fit викликається лише на train fold; для невідомих у train слів TF-IDF присвоює 0 — що чесно відображає реальну ситуацію продакшну.

Вплив гіперпараметрів на метрики (з нашої таблиці):

Гіперпараметр Зміна Δ test_f1
MultinomialNB.alpha 1.0 → 0.1 (з max_features 5k → 10k) +0.0199
MultinomialNB.alpha 0.1 → 0.5 + bigrams (10k features) -0.0111 (bigrams шкодять NB через незалежність ознак)
LogReg.C + n-grams C=1, uni → C=10, bi (10k → 20k) +0.0142
LinearSVC.C + n-grams C=1, uni → C=0.5, bi (10k → 20k) +0.0066
ngram_range (1,1) → (1,2) +0.0066 для SVC, +0.0142 для LogReg, -0.0111 для NB
max_features 5k → 10k → 20k стабільне зростання, але плато після ~10k для уніграмів

Ключові висновки:

  • Linear-моделі (LogReg, SVC) виграють від bigrams + більший словник, бо вони здатні навчитися ваг на корельованих ознаках.
  • NB чутливий до згладжування (alpha); великий alpha «розмиває» ймовірності рідкісних інформативних слів.
  • NB не виграє від bigrams, бо порушується припущення умовної незалежності.
  • CV (5-fold) дає std ≈ 0.008–0.010 — отже, різниці < 0.005 між моделями статистично малозначущі.

Troubleshooting

Проблема Рішення
ModuleNotFoundError: No module named 'pip' Системний Python без pip. Створіть venv: python3 -m venv .venv && source .venv/bin/activate, потім python -m ensurepip --upgrade.
ModuleNotFoundError: pkg_resources (MLflow) pip install 'setuptools<81'.
dvc init падає з cannot import _DIR_MARK from pathspec Несумісна версія pathspec: pip install 'pathspec<0.12'.
dvc addbad DVC file name ... is git-ignored Додайте у .gitignore рядок !*.dvc після /data/raw/*.
dvc pullfailed to pull data from the cloud Локальний remote /tmp/dvc-storage зник після ребуту. Виконайте python -m src.data.create_dataset && dvc add data/raw/dataset.csv ще раз.
mlflow ui → порт 5000 зайнятий mlflow ui --port 5001 або вбити процес: lsof -ti:5000 | xargs kill.
LinearSVC warning dual will change Це майбутній breaking-change у sklearn 1.5; не впливає на результати в 1.4.x. Або явно вкажіть dual='auto'.
Великий час тренування Зменшіть max_features, перейдіть на 2 категорії, або скористайтесь n_jobs=-1 у cross_val_score (вже включено).

Літературa

  1. DVC. https://dvc.org/doc
  2. MLflow. https://mlflow.org/docs/latest/index.html
  3. scikit-learn Pipeline. https://scikit-learn.org/stable/modules/compose.html
  4. Git. https://git-scm.com/doc

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages