Уроки 6-9: autolog, hyperparam sweep, grid search, serving + MLproject, walkthrough

This commit is contained in:
2026-07-20 15:01:31 +03:00
parent 2c07fd63c0
commit d6a4b46db0
14 changed files with 1248 additions and 95 deletions
+3
View File
@@ -6,3 +6,6 @@ mlruns/
artifacts/* artifacts/*
data/MNIST/ data/MNIST/
*.log *.log
# Flask serve
instance/
+516
View File
@@ -0,0 +1,516 @@
# 🔍 Экскурс по коду — разбор каждого файла
Полный разбор всех файлов проекта с пояснениями, что и почему.
---
## Структура проекта
```
mlflow-practice/
├── MLproject # Формат MLflow Projects (воспроизводимость)
├── python_env.yaml # Окружение для MLproject
├── requirements.txt # Зависимости
├── setup_server.sh # Установка на GPU-сервере
├── start_ui.sh # Запуск MLflow Tracking Server
├── scripts/
│ └── setup_git.sh # Настройка Git (HTTPS + токен)
└── src/
├── train_simple.py # Урок 1: sklearn + Tracking (ручное логирование)
├── train_gpu.py # Урок 2: PyTorch CNN на GPU + логирование по эпохам
├── register_model.py # Урок 3: Model Registry (версии, стадии)
├── load_and_predict.py # Урок 4: загрузка модели + предсказание
├── compare_runs.py # Урок 5: сравнение запусков через API
├── autolog_demo.py # Урок 6: autolog (автоматическое логирование)
├── hyperparam_sweep.py # Урок 7: перебор гиперпараметров (вручную)
├── grid_search_cv.py # Урок 8: GridSearchCV + autolog
└── serve_model.py # Урок 9: REST API сервер модели
```
---
## 📄 train_simple.py — основы MLflow Tracking
Это **главный файл для понимания**. Здесь показаны все базовые операции MLflow.
### Импорты
```python
import mlflow
import mlflow.sklearn
```
`mlflow` — ядро (start_run, log_param, log_metric, log_artifact).
`mlflow.sklearn` — flavor для scikit-learn моделей (save_model, load_model).
### Задание эксперимента
```python
mlflow.set_experiment("digits_classification")
```
Эксперимент — это **контейнер для связанных запусков (runs)**.
Если эксперимент не существует — MLflow создаст его автоматически.
Все runs с одинаковым именем эксперимента группируются вместе в UI.
### Контекстный менеджер run
```python
with mlflow.start_run(run_name="rf_100_8") as run:
```
`start_run()` начинает новый запуск. Контекстный менеджер (`with`)
гарантирует, что run закроется даже при ошибке — всё сохранится.
`run.info.run_id` — уникальный ID запуска, через него можно к нему вернуться.
### Логирование параметров
```python
mlflow.log_param("n_estimators", args.n_estimators)
mlflow.log_param("max_depth", args.max_depth)
```
Параметры логируются **ДО или ВО ВРЕМЯ обучения**. Это то, что вы
выбрали — гиперпараметры модели. Каждый параметр — строка/число.
В UI параметры показываются в таблице запусков как колонки.
### Логирование метрик
```python
mlflow.log_metric("accuracy", acc)
```
Метрики — числа, которые оценивают качество. Главное отличие от
параметров: метрики могут логироваться **несколько раз** с разными
шагами (`step=N`), образуя график:
```python
for i, tree in enumerate(model.estimators_):
tree_acc = accuracy_score(y_test, tree.predict(X_test))
mlflow.log_metric("per_tree_accuracy", tree_acc, step=i)
```
В UI это покажется как линейный график — как accuracy растёт
по мере добавления деревьев в RandomForest.
### Логирование артефактов
```python
mlflow.log_artifact("artifacts/confusion_matrix.png")
```
Артефакт — **любой файл**: картинка, текст, JSON, модель. MLflow
копирует файл в хранилище артефактов (папка `./artifacts/` или S3).
В UI артефакты можно просматривать прямо в браузере.
### Логирование модели
```python
mlflow.sklearn.log_model(model, artifact_path="model")
```
Модель — это особый артефакт. MLflow сохраняет её в стандартном
формате с файлом `MLmodel` (метаданные: flavor, версия, сигнатура).
Позже её можно загрузить по `run_id` или зарегистрировать в Registry.
### Теги
```python
mlflow.set_tag("model_type", "RandomForest")
mlflow.set_tag("author", "practice")
```
Теги — произвольные метки для фильтрации и поиска. В отличие от
параметров, теги можно менять после завершения run.
---
## 📄 train_gpu.py — PyTorch + GPU + логирование по эпохам
### Определение устройства
```python
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
```
Код **GPU-aware**: если есть CUDA — обучение на 3090, иначе на CPU.
Всё переносится на устройство: `model.to(device)`, `data.to(device)`.
### Логирование параметров окружения
```python
mlflow.log_param("device", str(device))
mlflow.log_param("gpu_name", gpu_name)
```
Полезно: в UI видно, на каком GPU обучалась модель. Если запускаете
на разных машинах — сразу видно различия.
### Логирование метрик по эпохам
```python
mlflow.log_metric("train_loss", avg_loss, step=epoch)
mlflow.log_metric("test_accuracy", acc, step=epoch)
```
`step=epoch` — ключевой момент. Каждая метрика логируется с номером
шага. В UI это строит **график learning curve** — как loss падает, а
accuracy растёт от эпохи к эпохе.
### Сохранение графика как артефакта
```python
fig.savefig("artifacts/training_curve.png")
mlflow.log_artifact(plot_path)
```
Matplotlib-график сохраняется в файл и логируется. В UI его можно
открыть прямо в браузере — артефакты отображаются превью.
### Логирование PyTorch-модели
```python
mlflow.pytorch.log_model(
model,
artifact_path="model",
serialization_format="pickle",
input_example=torch.randn(1, 1, 28, 28).to(device),
)
```
`serialization_format="pickle"` — формат сохранения (см. урок 2).
`input_example` — пример входа, нужен для построения сигнатуры модели.
MLflow сохраняет модель в формате, совместимом с `mlflow.pytorch.load_model()`.
---
## 📄 register_model.py — Model Registry
### Поиск лучшего запуска
```python
runs = client.search_runs(
experiment_ids=[exp.experiment_id],
order_by=["metrics.accuracy DESC"],
max_results=1,
)
```
MlflowClient — программный доступ к API Tracking Server.
`search_runs` с `order_by` — сортировка по метрике. Так можно найти
лучший run без UI — полностью программно.
### Регистрация модели
```python
model_uri = f"runs:/{run_id}/model"
result = mlflow.register_model(model_uri=model_uri, name="digits_rf_model")
```
`model_uri` — указывает на модель внутри конкретного run.
`register_model` создаёт новую версию в Model Registry.
`result.version` — номер версии (1, 2, 3...).
### Управление стадиями
```python
client.transition_model_version_stage(
name="digits_rf_model",
version=result.version,
stage="Production",
archive_existing_versions=True,
)
```
`archive_existing_versions=True` — автоматически переводит все
предыдущие Production-версии в Archived. Так в Production всегда
только одна версия.
### Жизненный цикл модели
```
None → Staging → Production → Archived
↑ ↓
└──────────────────┘
(можно вернуть обратно)
```
- **Staging** — тестирование, ещё не готова
- **Production** — используется в приложении
- **Archived** — устарела, но сохранена для истории
---
## 📄 load_and_predict.py — загрузка модели
### Загрузка по имени и стадии
```python
model = mlflow.sklearn.load_model("models:/digits_rf_model/Production")
```
`models:/` — URI для Model Registry. Формат: `models:/{name}/{stage}`
или `models:/{name}/{version}`. Загружает последнюю версию в стадии
Production. Если версию перевели в Archived — эта загрузка сломается,
что правильно — так вы узнаёте о проблеме сразу.
### Отличие от загрузки по run_id
```python
# По run_id (привязка к конкретному запуску):
model = mlflow.sklearn.load_model("runs:/abc123/model")
# По registry (привязка к имени + стадии):
model = mlflow.sklearn.load_model("models:/digits_rf_model/Production")
```
Registry — уровень абстракции выше. Код не меняется при смене версии
модели, только стадия в UI.
---
## 📄 compare_runs.py — сравнение через API
```python
runs = client.search_runs(
experiment_ids=[exp.experiment_id],
order_by=["metrics.accuracy DESC"],
max_results=10,
)
```
Программный аналог таблицы в UI. Каждый `run` содержит:
- `run.info.run_id` — ID
- `run.data.params` — словарь параметров
- `run.data.metrics` — словарь метрик
- `run.data.tags` — теги
Это позволяет автоматизировать: найти лучший, сравнить, отсеять.
---
## 📄 autolog_demo.py — автоматическое логирование
### Ключевая строка
```python
mlflow.sklearn.autolog(
log_models=True,
log_datasets=True,
max_tuning_runs=10,
)
```
После вызова `autolog()`**больше не нужно** писать `log_param`,
`log_metric`, `log_model` вручную. MLflow перехватывает вызовы sklearn
и логирует всё автоматически:
| Что autolog перехватывает | Что логируется |
|---|---|
| `model.fit()` | все параметры конструктора модели |
| Обучение | `training_accuracy`, `training_log_loss` |
| Модель | сохраняется в `artifacts/model/` |
| Датасет | профиль (размер, типы признаков) |
| GridSearchCV | каждый под-вариант как отдельный run |
### Сравнение: ручное vs autolog
```python
# Ручное (train_simple.py):
mlflow.log_param("n_estimators", 100)
mlflow.log_param("max_depth", 8)
mlflow.log_metric("accuracy", acc)
mlflow.sklearn.log_model(model, "model")
# Autolog (autolog_demo.py):
mlflow.sklearn.autolog() # одна строка!
model.fit(X_train, y_train) # всё залогируется само
```
**Когда использовать autolog**: быстрые эксперименты, прототипы.
**Когда ручное логирование**: нужен контроль над тем, что попадает
в MLflow, кастомные метрики, специфичные артефакты.
---
## 📄 hyperparam_sweep.py — перебор гиперпараметров
### Генерация комбинаций
```python
all_combos = list(itertools.product(
param_grid["n_estimators"],
param_grid["max_depth"],
...
))
```
`itertools.product` — декартово произведение всех параметров.
5 × 6 × 3 × 3 × 3 = 810 возможных комбинаций. Берём случайные
`max_combos` из них — для скорости.
### Почему случайные, а не все 810?
Полный перебор (Grid Search) = 810 × 5 (CV) = 4050 обучений.
На 3090 это реально, но:
- Random Search часто находит хорошие параметры быстрее
- MLflow хранит каждый run — 810 runs засоряют UI
- 20-50 случайных обычно достаточно для практики
### Кросс-валидация
```python
cv_scores = cross_val_score(model, X_train, y_train, cv=5, scoring="accuracy")
mlflow.log_metric("cv_mean_accuracy", cv_scores.mean())
mlflow.log_metric("cv_std_accuracy", cv_scores.std())
```
CV делит train на 5 фолдов, обучает 5 раз, усредняет.
`cv_std` — разброс между фолдами. Если `std` высокий — модель
нестабильна (зависит от разбиения данных).
### Что искать в UI
1. Отсортировать по `test_accuracy` DESC
2. Сравнить `cv_mean_accuracy` и `test_accuracy` — если CV сильно
выше теста → переобучение (overfitting)
3. Высокий `cv_std_accuracy` → нестабильная модель
4. Scatter plot: `n_estimators` vs `accuracy` — видна ли зависимость
---
## 📄 grid_search_cv.py — GridSearchCV + autolog
```python
mlflow.sklearn.autolog(max_tuning_runs=20)
...
grid = GridSearchCV(estimator=..., param_grid=..., cv=5)
grid.fit(X_train, y_train)
```
MLflow autolog + GridSearchCV = **дерево запусков**:
- **Parent run** (`gridsearch_rf`) — главный, содержит лучшие параметры
- **Child runs** — каждая комбинация гиперпараметров отдельный run
В UI это видно как иерархия. Parent показывает итог, children — детали.
---
## 📄 serve_model.py — REST API
### Загрузка модели при старте
```python
model = mlflow.sklearn.load_model(f"models:/{model_name}/{stage}")
```
Загружается **один раз** при создании Flask-приложения, не на каждый
запрос. Это важно для производительности.
### Эндпоинты
| Эндпоинт | Метод | Что делает |
|---|---|---|
| `/health` | GET | Проверка состояния ("жив" ли сервер) |
| `/info` | GET | Информация о модели (признаки, классы) |
| `/predict` | POST | Предсказание для переданных данных |
| `/predict_random` | GET | Случайный образец из digits + предсказание |
### Формат запроса /predict
```json
{
"instances": [
[0, 0, 0, ..., 16, 8, 0, ...], // 64 числа — 8×8 пикселей
[0, 0, 12, ..., 0, 0, 0, ...] // можно несколько образцов
]
}
```
### predict_proba
```python
probabilities = model.predict_proba(instances)
```
RandomForest поддерживает `predict_proba` — вероятности для каждого
класса. В ответе: предсказание + вероятности + confidence.
### Альтернатива — встроенный MLflow server
```bash
mlflow models serve -m models:/digits_rf_model/Production -p 5001
```
MLflow сам поднимает сервер с стандартным API. Кастомный скрипт
(serve_model.py) даёт больше контроля — свои эндпоинты, логика,
демо-эндпоинт с случайным образом.
---
## 📄 MLproject — воспроизводимость
```yaml
name: mlflow-practice
entry_points:
main:
parameters:
n_estimators: {type: int, default: 100}
command: "python src/train_simple.py --n-estimators {n_estimators}"
```
`MLproject` — декларативное описание проекта. MLflow может запустить
его одной командой:
```bash
mlflow run . -P n_estimators=200 -P max_depth=12
```
При этом MLflow:
1. Читает `python_env.yaml` → создаёт виртуальное окружение
2. Устанавливает зависимости
3. Запускает команду из entry_point с параметрами
4. Логирует всё в tracking server
Это гарантирует воспроизводимость: любой человек на любой машине
может запустить ваш эксперимент с тем же результатом.
---
## 🗂️ Как файлы связаны между собой
```
train_simple.py ──→ логирует run ──→ register_model.py ──→ load_and_predict.py
│ │
│ ↓
│ Model Registry
│ │
↓ ↓
compare_runs.py serve_model.py
(ищет лучший run) (загружает из Registry)
autolog_demo.py ──→ autolog (альтернатива ручному логированию)
hyperparam_sweep.py ──→ много runs (перебор)
grid_search_cv.py ──→ parent + child runs (autolog + GridSearch)
MLproject ──→ оборачивает всё в воспроизводимый формат
```
---
## 💡 Ключевые концепции MLflow — шпаргалка
| Концепция | Что это | Где используется |
|---|---|---|
| **Experiment** | Группа связанных runs | `set_experiment()` |
| **Run** | Один запуск обучения | `start_run()` |
| **Param** | Гиперпараметр (вход) | `log_param()` |
| **Metric** | Метрика (результат), может быть графиком | `log_metric(step=N)` |
| **Artifact** | Любой файл (картинка, модель) | `log_artifact()` |
| **Tag** | Метка для поиска/фильтрации | `set_tag()` |
| **Flavor** | Формат модели (sklearn, pytorch) | `mlflow.sklearn`, `mlflow.pytorch` |
| **Model Registry** | Реестр версий моделей | `register_model()`, `transition_stage()` |
| **Autolog** | Автоматическое логирование | `mlflow.sklearn.autolog()` |
| **MLproject** | Воспроизводимый запуск | `mlflow run .` |
| **Model URI** | Ссылка на модель | `models:/name/Production`, `runs:/id/model` |
+33
View File
@@ -0,0 +1,33 @@
# MLflow Project — формат воспроизводимых экспериментов
# ========================================================
# Запуск:
# mlflow run . -P n_estimators=100 -P max_depth=8
# mlflow run . -P n_estimators=200 -P max_depth=12 --experiment-name digits_project
#
# MLflow автоматически:
# 1. Создаст изолированное окружение из conda.yaml (или requirements.txt)
# 2. Запустит entry point с указанными параметрами
# 3. Логирует всё в MLflow tracking
name: mlflow-practice
python_env: python_env.yaml
entry_points:
main:
parameters:
n_estimators: {type: int, default: 100}
max_depth: {type: int, default: 8}
command: "python src/train_simple.py --n-estimators {n_estimators} --max-depth {max_depth}"
gpu:
parameters:
epochs: {type: int, default: 10}
batch_size: {type: int, default: 256}
lr: {type: float, default: 0.001}
command: "python src/train_gpu.py --epochs {epochs} --batch-size {batch_size} --lr {lr}"
sweep:
parameters:
max_combos: {type: int, default: 20}
command: "python src/hyperparam_sweep.py --max-combos {max_combos}"
+79 -61
View File
@@ -1,7 +1,10 @@
# 🧪 MLflow Practice — практический проект # 🧪 MLflow Practice — практический проект
Проект для изучения MLflow на практике: от логирования экспериментов Проект для изучения MLflow на практике: от логирования экспериментов
до Model Registry и загрузки моделей. Поддерживает **GPU (RTX 3090)** и CPU. до Model Registry, Model Serving и воспроизводимых запусков.
Поддерживает **GPU (RTX 3090)** и CPU.
📖 **[CODE_WALKTHROUGH.md](CODE_WALKTHROUGH.md)** — подробный разбор каждого файла.
--- ---
@@ -9,113 +12,128 @@
``` ```
mlflow-practice/ mlflow-practice/
├── MLproject # Формат MLflow Projects (воспроизводимость)
├── python_env.yaml # Окружение для MLproject
├── requirements.txt # зависимости ├── requirements.txt # зависимости
├── setup_server.sh # установка на GPU-сервере
├── start_ui.sh # запуск MLflow Tracking Server ├── start_ui.sh # запуск MLflow Tracking Server
├── README.md # этот файл ├── CODE_WALKTHROUGH.md # экскурс по коду
├── data/ # датасеты (MNIST скачается автоматически) ├── scripts/
├── artifacts/ # графики, отчёты │ └── setup_git.sh # настройка Git (HTTPS + токен)
└── src/ └── src/
├── train_simple.py # Урок 1: scikit-learn + Tracking ├── train_simple.py # Урок 1: sklearn + Tracking (ручное)
├── train_gpu.py # Урок 2: PyTorch CNN на GPU (3090) ├── train_gpu.py # Урок 2: PyTorch CNN на GPU
├── register_model.py # Урок 3: Model Registry ├── register_model.py # Урок 3: Model Registry
├── load_and_predict.py # Урок 4: загрузка и предсказание ├── load_and_predict.py # Урок 4: загрузка + предсказание
── compare_runs.py # Урок 5: сравнение запусков ── compare_runs.py # Урок 5: сравнение через API
├── autolog_demo.py # Урок 6: autolog (автоматическое)
├── hyperparam_sweep.py # Урок 7: перебор гиперпараметров
├── grid_search_cv.py # Урок 8: GridSearchCV + autolog
└── serve_model.py # Урок 9: REST API сервер
``` ```
--- ---
## 🚀 Быстрый старт ## 🚀 Быстрый старт
### 1. Установка зависимостей ### 1. Установка
```bash ```bash
cd mlflow-practice # На GPU-сервере:
bash setup_server.sh
source .venv/bin/activate
# Базовые зависимости (CPU — работает везде) # PyTorch под CUDA:
pip install mlflow scikit-learn pandas numpy matplotlib
# Для GPU-урока (RTX 3090) — установите PyTorch под вашу CUDA:
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121
pip install flask # для serve_model.py
``` ```
### 2. Запуск MLflow UI (в отдельном терминале) ### 2. Запуск MLflow UI
```bash ```bash
./start_ui.sh ./start_ui.sh
# → откройте http://localhost:5000 # → http://10.0.0.7:5000
``` ```
### 3. Урок 1 — scikit-learn (быстрый, CPU) ### 3. Уроки по порядку
```bash ```bash
python src/train_simple.py --n-estimators 50 --max-depth 5 # Урок 1 — scikit-learn (CPU, ~5 сек)
python src/train_simple.py --n-estimators 100 --max-depth 8 python src/train_simple.py --n-estimators 100 --max-depth 8
python src/train_simple.py --n-estimators 200 --max-depth 12 python src/train_simple.py --n-estimators 200 --max-depth 12
``` python src/train_simple.py --n-estimators 50 --max-depth 5
Сравните результаты в UI → вкладка **Experiments → digits_classification**. # Урок 2 — PyTorch CNN на 3090 (~1-2 мин)
### 4. Урок 2 — PyTorch CNN на 3090
```bash
# На GPU — быстро (3090 справится за пару минут)
python src/train_gpu.py --epochs 10 --batch-size 256 --lr 0.001 python src/train_gpu.py --epochs 10 --batch-size 256 --lr 0.001
# На CPU — медленно, уменьшите эпохи # Урок 3 — Регистрация лучшей модели
python src/train_gpu.py --epochs 2 --batch-size 64 --lr 0.01
```
В UI посмотрите графики `train_loss` и `test_accuracy` по эпохам.
### 5. Урок 3 — Model Registry
```bash
python src/register_model.py --experiment digits_classification python src/register_model.py --experiment digits_classification
```
В UI → вкладка **Models** появится модель `digits_rf_model` со стадией **Production**. # Урок 4 — Загрузка и предсказание
### 6. Урок 4 — Загрузка и предсказание
```bash
python src/load_and_predict.py python src/load_and_predict.py
# Урок 5 — Сравнение запусков
python src/compare_runs.py --experiment digits_classification --top 10
# Урок 6 — Autolog (автоматическое логирование)
python src/autolog_demo.py
# Урок 7 — Hyperparameter sweep (20 комбинаций)
python src/hyperparam_sweep.py --max-combos 20
# Урок 8 — GridSearchCV + autolog (parent/child runs)
python src/grid_search_cv.py
# Урок 9 — Model serving (REST API)
python src/serve_model.py --port 5001
# → curl http://localhost:5001/predict_random
``` ```
### 7. Урок 5 — Сравнение запусков ### 4. MLflow Projects (воспроизводимый запуск)
```bash ```bash
python src/compare_runs.py --experiment digits_classification --top 10 # Запуск через MLproject — MLflow сам создаст окружение
mlflow run . -P n_estimators=200 -P max_depth=12
mlflow run . -e gpu -P epochs=10 -P batch_size=256 -P lr=0.001
mlflow run . -e sweep -P max_combos=30
``` ```
--- ---
## 🖥️ Специфика RTX 3090 ## 📚 Что изучает каждый урок
| Урок | Концепция MLflow | На чём |
|---|---|---|
| 1 | **Tracking**: params, metrics, artifacts, tags | RandomForest (digits) |
| 2 | **Tracking + GPU**: логирование по эпохам, learning curves | PyTorch CNN (MNIST) на 3090 |
| 3 | **Model Registry**: версии, стадии Staging→Production | лучшая модель из Урока 1 |
| 4 | **Model Loading**: models:/name/stage | предсказание |
| 5 | **API**: search_runs, order_by | сортировка по accuracy |
| 6 | **Autolog**: одна строка вместо ручного логирования | GradientBoosting (wine) |
| 7 | **Hyperparameter sweep**: itertools + random search | 20+ комбинаций RandomForest |
| 8 | **GridSearchCV + autolog**: parent/child runs | 18 комбинаций × 5 фолдов |
| 9 | **Model serving**: Flask REST API | REST эндпоинты для модели |
---
## 🖥️ RTX 3090
| Параметр | Значение | | Параметр | Значение |
|---|---| |---|---|
| VRAM | 24 GB GDDR6X | | VRAM | 24 GB GDDR6X |
| CUDA cores | 10496 |
| Рекомендуемый batch-size | 256512 для MNIST | | Рекомендуемый batch-size | 256512 для MNIST |
| CUDA версия | 12.1 (рекомендуется) | | CUDA | 12.1 |
| MNIST 10 epochs | ~1-2 минуты |
Код в `train_gpu.py` **автоматически** определяет CUDA: Код GPU-aware — автоматически выбирает CUDA если доступна.
```python
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
```
На 3090 обучение MNIST (10 epochs) займёт ~1-2 минуты.
--- ---
## 💡 Эксперименты для самостоятельной работы ## 💡 Эксперименты для самостоятельной работы
1. **Подбор гиперпараметров**: запустите `train_simple.py` с разными 1. **Подбор гиперпараметров** запустите sweep с `--max-combos 50`
`--n-estimators` и `--max-depth`, сравните в UI 2. **Сравнение моделей** — обучите RandomForest vs GradientBoosting vs SVM
2. **Визуализация**: добавьте логирование ROC-кривой как артефакта 3. **Autolog vs ручное** — запустите один датасет с autolog и без, сравните
3. **Автолог**: попробуйте `mlflow.autolog()` вместо ручного логирования 4. **Model Registry**обучите несколько версий, переведите лучшую в Production
4. **GPU эксперименты**: в `train_gpu.py` попробуйте разные `--lr` и 5. **Serving** — поднимите REST API, отправьте запрос через curl
`--batch-size`, сравните графики learning curves 6. **MLproject** — запустите через `mlflow run .` на другой машине
5. **Model Registry**: обучите несколько версий, переведите лучшую в
Production, остальные в Archived
6. **Serving**: попробуйте `mlflow models serve -m models:/digits_rf_model/Production -p 5001`
+11
View File
@@ -0,0 +1,11 @@
# Спецификация окружения Python для MLflow Projects
# MLflow создаст виртуальное окружение по этому файлу
python: "3.10"
dependencies:
- mlflow>=2.11.0
- scikit-learn>=1.3.0
- pandas>=2.0.0
- numpy>=1.24.0
- matplotlib>=3.7.0
# Для GPU entry point установите torch отдельно:
# pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121
+3
View File
@@ -11,5 +11,8 @@ matplotlib>=3.7.0
torch>=2.1.0 torch>=2.1.0
torchvision>=0.16.0 torchvision>=0.16.0
# === Для Model Serving (Урок 9) ===
flask>=3.0.0
# === Для MLflow UI / Model Registry === # === Для MLflow UI / Model Registry ===
# SQLite backend уже входит в стандартную поставку Python # SQLite backend уже входит в стандартную поставку Python
+148
View File
@@ -0,0 +1,148 @@
#!/bin/bash
# ============================================================
# Глобальная настройка Git (HTTPS + токен, без SSH)
# Запуск: bash scripts/setup_git.sh
# ============================================================
set -e
echo "🔧 Глобальная настройка Git"
echo "============================"
echo ""
if ! command -v git &> /dev/null; then
echo "❌ Git не установлен!"
echo " macOS: brew install git"
echo " Ubuntu: sudo apt install git"
exit 1
fi
echo "✅ Git: $(git --version)"
echo ""
# ─── 1. Имя и email ──────────────────────────────────────────
DEFAULT_NAME="admin"
DEFAULT_EMAIL="admin@e7.by"
GIT_NAME="${GIT_NAME:-$DEFAULT_NAME}"
GIT_EMAIL="${GIT_EMAIL:-$DEFAULT_EMAIL}"
read -p "Имя [$GIT_NAME]: " input_name
read -p "Email [$GIT_EMAIL]: " input_email
git config --global user.name "${input_name:-$GIT_NAME}"
git config --global user.email "${input_email:-$GIT_EMAIL}"
echo "✅ user.name = $(git config --global user.name)"
echo "✅ user.email = $(git config --global user.email)"
echo ""
# ─── 2. Базовые настройки ────────────────────────────────────
git config --global init.defaultBranch main
git config --global core.autocrlf input
git config --global core.safecrlf true
git config --global core.longpaths true
git config --global core.editor "vi"
git config --global core.pager "less -FRX"
git config --global color.ui auto
git config --global pull.rebase true
git config --global rebase.autoStash true
git config --global push.default current
echo "✅ Базовые настройки (main, rebase, colors, pager)"
# ─── 3. Алиасы ───────────────────────────────────────────────
git config --global alias.st "status -sb"
git config --global alias.co "checkout"
git config --global alias.br "branch"
git config --global alias.ci "commit"
git config --global alias.cm "commit -m"
git config --global alias.ca "commit --amend"
git config --global alias.lg "log --oneline --graph --decorate --all"
git config --global alias.last "log -1 HEAD --stat"
git config --global alias.unstage "restore --staged"
git config --global alias.discard "checkout --"
git config --global alias.aliases "config --get-regexp ^alias\\."
echo "✅ Алиасы: git st, git lg, git ci, git cm, git co, git br, git ca, git last"
# ─── 4. Credential helper (хранение токенов) ─────────────────
# macOS: токен в Keychain (безопасно, шифруется)
# Linux: токен в ~/.git-credentials (файл, без шифрования)
if [[ "$OSTYPE" == "darwin"* ]]; then
git config --global credential.helper osxkeychain
echo "✅ credential.helper = osxkeychain (macOS Keychain)"
else
git config --global credential.helper store
chmod 600 ~/.git-credentials 2>/dev/null || true
echo "✅ credential.helper = store (~/.git-credentials, chmod 600)"
fi
# ─── 5. Настройка токена для git.e7.by ────────────────────────
echo ""
echo "🔐 Настройка токена для git.e7.by"
echo "--------------------------------------------"
echo " git.e7.by работает только через HTTPS + токен."
echo " Токен можно создать в: Profile → Settings → Access Tokens"
echo ""
read -p "Введите токен (или Enter чтобы пропустить): " TOKEN
if [ -n "$TOKEN" ]; then
# Сохраняем токен через credential helper
# Формат: https://username:token@host
echo "https://core:${TOKEN}@git.e7.by" | git credential-store store 2>/dev/null || \
echo "https://core:${TOKEN}@git.e7.by" >> ~/.git-credentials 2>/dev/null || true
# Для macOS Keychain — через security
if [[ "$OSTYPE" == "darwin"* ]]; then
# Записываем в Keychain напрямую
security add-internet-password -s git.e7.by -a core -w "$TOKEN" -r https 2>/dev/null || true
echo "✅ Токен сохранён в macOS Keychain (git.e7.by / core)"
else
chmod 600 ~/.git-credentials 2>/dev/null || true
echo "✅ Токен сохранён в ~/.git-credentials"
fi
# ВАЖНО: remote URL должен быть БЕЗ токена!
# Токен подхватится автоматически из credential helper
echo ""
echo "📌 Теперь добавляйте remote БЕЗ токена:"
echo " git remote add origin https://git.e7.by/sandbox/repo.git"
echo " git push -u origin main"
echo " (токен подставится автоматически из credential helper)"
else
echo "⏭️ Токен не введён — пропускаю"
echo " Добавьте позже:"
echo " echo 'https://core:ТОКЕН@git.e7.by' >> ~/.git-credentials # Linux"
echo " security add-internet-password -s git.e7.by -a core -w 'ТОКЕН' -r https # macOS"
fi
# ─── 6. Если репо уже есть — чистим токен из remote URL ──────
echo ""
echo "🧹 Проверка текущих remote на наличие токена в URL..."
CLEANED=0
for repo_remote in $(git remote 2>/dev/null); do
url=$(git remote get-url "$repo_remote" 2>/dev/null || true)
if echo "$url" | grep -q "://.*:.*@"; then
clean_url=$(echo "$url" | sed 's|://[^@]*@|://|')
git remote set-url "$repo_remote" "$clean_url"
echo "$repo_remote: токен удалён из URL"
echo " было: $url"
echo " стало: $clean_url"
CLEANED=1
fi
done
if [ "$CLEANED" -eq 0 ]; then
echo " ✅ Токенов в remote URL не найдено"
fi
# ─── 7. Финал ────────────────────────────────────────────────
echo ""
echo "============================================"
echo " ✅ Настройка завершена!"
echo "============================================"
echo ""
echo "📋 Глобальные настройки:"
echo "--------------------------------------------"
git config --global --list
echo "--------------------------------------------"
echo ""
echo "🧪 Проверка токена:"
echo " git ls-remote https://git.e7.by/sandbox/mlflow-practice.git"
echo " (если спросит пароль — токен не подхватился)"
+78
View File
@@ -0,0 +1,78 @@
"""
Урок 6: MLflow Autolog — автоматическое логирование
====================================================
Вместо ручного log_param/log_metric можно вызвать mlflow.autolog()
ОДИН раз — и MLflow сам залогирует всё: параметры, метрики, модель,
признаки, даже feature importance.
Сравните с train_simple.py — там всё логировалось вручную.
Запуск:
python src/autolog_demo.py
"""
from sklearn.datasets import load_wine
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import mlflow
import mlflow.sklearn
def main():
# ─── КЛЮЧЕВАЯ СТРОКА ──────────────────────────────────────
# autolog() включает автоматическое логирование для sklearn.
# Доступно для: sklearn, pytorch, tensorflow, xgboost, lightgbm,
# keras, fastai, spark, autogluon, statsmodels
mlflow.sklearn.autolog(
log_input_examples=False, # не логировать примеры входа
log_model_signatures=False, # не строить сигнатуру модели
log_models=True, # сохранить модель автоматически
log_datasets=True, # залогировать датасет
max_tuning_runs=10, # лимит для GridSearch
log_post_training_metrics=True,
)
# ─────────────────────────────────────────────────────────
mlflow.set_experiment("autolog_wine")
# Датасет wine — классификация вин по 3 сортам
wine = load_wine()
X, y = wine.data, wine.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42
)
print(f"📊 Датасет wine: {X.shape[0]} образцов, {X.shape[1]} признаков, 3 класса")
# autolog начинает работать автоматически внутри start_run
with mlflow.start_run(run_name="gb_autolog") as run:
print(f"MLflow run ID: {run.info.run_id}")
# Просто обучаем модель — НИКАКИХ log_param/log_metric!
model = GradientBoostingClassifier(
n_estimators=100,
learning_rate=0.1,
max_depth=3,
random_state=42,
)
model.fit(X_train, y_train)
# Можно добавить и ручные метрики — они дополнят автолог
y_pred = model.predict(X_test)
acc = accuracy_score(y_test, y_pred)
mlflow.log_metric("manual_accuracy", acc)
print(f"\n✅ Готово! Откройте MLflow UI:")
print(f" Эксперимент: autolog_wine")
print(f" Run: {run.info.run_id}")
print(f" Accuracy: {acc:.4f}")
print(f"\n🔍 Что autolog залогировал автоматически:")
print(f" • Параметры: n_estimators, learning_rate, max_depth, ...")
print(f" • Метрики: training_accuracy, training_log_loss, ...")
print(f" • Модель: сохранена в artifacts/model/")
print(f" • Датасет: профиль в artifacts/")
print(f" • Ручная метрика: manual_accuracy")
if __name__ == "__main__":
main()
+86
View File
@@ -0,0 +1,86 @@
"""
Урок 9: MLflow + GridSearchCV — автолог перебора
==================================================
sklearn GridSearchCV сам перебирает гиперпараметры.
MLflow autolog автоматически залогирует КАЖУЮ попытку как отдельный run.
Запуск:
python src/grid_search_cv.py
"""
from sklearn.datasets import load_digits
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.metrics import accuracy_score
import mlflow
import mlflow.sklearn
def main():
# autolog для sklearn — залогирует все промежуточные попытки GridSearch
mlflow.sklearn.autolog(
log_models=False, # не сохранять каждую модель (экономим место)
max_tuning_runs=20, # максимум залогированных под-запусков
log_datasets=False,
)
mlflow.set_experiment("gridsearch_digits")
digits = load_digits()
X, y = digits.data, digits.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# Сетка для перебора
param_grid = {
"n_estimators": [50, 100, 200],
"max_depth": [4, 8, 12],
"min_samples_split": [2, 5],
}
# 3 × 3 × 2 = 18 комбинаций × 5 фолдов = 90 обучений
print(f"🔬 GridSearchCV")
print(f" Комбинаций: {len(param_grid['n_estimators'])} × "
f"{len(param_grid['max_depth'])} × "
f"{len(param_grid['min_samples_split'])} = "
f"{np.prod([len(v) for v in param_grid.values()])}")
print(f" CV фолдов: 5")
print(f" Всего обучений: {np.prod([len(v) for v in param_grid.values()]) * 5}")
print()
with mlflow.start_run(run_name="gridsearch_rf") as run:
print(f"MLflow parent run: {run.info.run_id}")
grid = GridSearchCV(
estimator=RandomForestClassifier(random_state=42, n_jobs=-1),
param_grid=param_grid,
cv=5,
scoring="accuracy",
n_jobs=-1,
verbose=1,
)
grid.fit(X_train, y_train)
# Логируем лучший результат
best = grid.best_estimator_
y_pred = best.predict(X_test)
test_acc = accuracy_score(y_test, y_pred)
mlflow.log_param("best_params", str(grid.best_params_))
mlflow.log_metric("best_cv_score", grid.best_score_)
mlflow.log_metric("test_accuracy", test_acc)
print(f"\n🏆 Лучшие параметры: {grid.best_params_}")
print(f" CV score: {grid.best_score_:.4f}")
print(f" Test accuracy: {test_acc:.4f}")
print(f"\n📊 В MLflow UI:")
print(f" Эксперимент: gridsearch_digits")
print(f" Parent run: {run.info.run_id}")
print(f" Child runs: {len(grid.cv_results_['params'])} под-запусков")
print(f" Каждый child — отдельная комбинация гиперпараметров")
if __name__ == "__main__":
import numpy as np
main()
+147
View File
@@ -0,0 +1,147 @@
"""
Урок 7: Hyperparameter Sweep — перебор гиперпараметров
========================================================
Запускает множество комбинаций гиперпараметров и логирует каждый
вариант в MLflow. В UI можно сравнить все варианты и найти лучший.
Запуск:
python src/hyperparam_sweep.py
python src/hyperparam_sweep.py --max-combos 50 # больше комбинаций
"""
import argparse
import itertools
import random
import time
from sklearn.datasets import load_digits
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
from sklearn.metrics import recall_score, precision_score, f1_score, accuracy_score
from sklearn.model_selection import train_test_split
import mlflow
def main():
parser = argparse.ArgumentParser(description="MLflow hyperparameter sweep")
parser.add_argument("--max-combos", type=int, default=20,
help="максимум комбинаций для перебора")
parser.add_argument("--cv-folds", type=int, default=5,
help="фолдов кросс-валидации")
parser.add_argument("--experiment-name", type=str, default="sweep_digits")
args = parser.parse_args()
# ─── Сетка гиперпараметров ───────────────────────────────
param_grid = {
"n_estimators": [50, 100, 150, 200, 300],
"max_depth": [4, 6, 8, 12, 16, None],
"min_samples_split": [2, 5, 10],
"min_samples_leaf": [1, 2, 4],
"max_features": ["sqrt", "log2", None],
}
# Генерируем все комбинации, берём случайные max_combos
all_combos = list(itertools.product(
param_grid["n_estimators"],
param_grid["max_depth"],
param_grid["min_samples_split"],
param_grid["min_samples_leaf"],
param_grid["max_features"],
))
random.seed(42)
random.shuffle(all_combos)
combos = all_combos[:args.max_combos]
print(f"🔬 Hyperparameter Sweep")
print(f" Всего возможных комбинаций: {len(all_combos)}")
print(f" Будет запущено: {len(combos)}")
print(f" CV фолдов: {args.cv_folds}")
print(f" Эксперимент: {args.experiment_name}")
print()
# ─── Данные ──────────────────────────────────────────────
digits = load_digits()
X, y = digits.data, digits.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
mlflow.set_experiment(args.experiment_name)
best_acc = 0.0
best_run_id = None
best_params = None
for i, (n_est, depth, min_split, min_leaf, max_feat) in enumerate(combos):
params = {
"n_estimators": n_est,
"max_depth": depth,
"min_samples_split": min_split,
"min_samples_leaf": min_leaf,
"max_features": max_feat,
}
# Описание для имени run
depth_str = str(depth) if depth else "None"
feat_str = str(max_feat) if max_feat else "None"
run_name = f"rf_ne{n_est}_d{depth_str}_ms{min_split}_ml{min_leaf}_mf{feat_str}"
with mlflow.start_run(run_name=run_name) as run:
# Логируем ВСЕ параметры
mlflow.log_params(params)
# Обучаем
model = RandomForestClassifier(
random_state=42, n_jobs=-1, **params
)
model.fit(X_train, y_train)
# Кросс-валидация (более надёжная оценка)
cv_scores = cross_val_score(model, X_train, y_train,
cv=args.cv_folds, scoring="accuracy")
# Метрики на тесте
y_pred = model.predict(X_test)
test_acc = accuracy_score(y_test, y_pred)
test_recall = recall_score(y_test, y_pred, average="macro")
test_precision = precision_score(y_test, y_pred, average="macro")
test_f1 = f1_score(y_test, y_pred, average="macro")
# Логируем метрики
mlflow.log_metric("cv_mean_accuracy", cv_scores.mean())
mlflow.log_metric("cv_std_accuracy", cv_scores.std())
mlflow.log_metric("test_accuracy", test_acc)
mlflow.log_metric("test_recall_macro", test_recall)
mlflow.log_metric("test_precision_macro", test_precision)
mlflow.log_metric("test_f1_macro", test_f1)
# Тег — номер комбинации
mlflow.set_tag("combo_index", str(i))
# Отслеживаем лучший
if test_acc > best_acc:
best_acc = test_acc
best_run_id = run.info.run_id
best_params = params
# Прогресс
bar_len = 30
filled = int(bar_len * (i + 1) / len(combos))
bar = "" * filled + "" * (bar_len - filled)
print(f"\r [{bar}] {i+1}/{len(combos)} | "
f"acc={test_acc:.4f} | {run_name[:40]:<40}", end="")
print(f"\n\n{'='*60}")
print(f"🏆 Лучший результат:")
print(f" Run ID: {best_run_id}")
print(f" Accuracy: {best_acc:.4f}")
print(f" Параметры: {best_params}")
print(f"\n📊 Откройте MLflow UI:")
print(f" Эксперимент: {args.experiment_name}")
print(f" Отсортируйте по test_accuracy (клик на заголовок колонки)")
print(f" Сравните cv_mean_accuracy vs test_accuracy")
print(f" если cv_std_accuracy высокий — модель нестабильна")
if __name__ == "__main__":
main()
+138
View File
@@ -0,0 +1,138 @@
"""
Урок 8: Model Serving — разворачивание модели как REST API
============================================================
Загружает модель из Model Registry и запускает HTTP-сервер.
Модель принимает JSON-запросы и возвращает предсказания.
Два способа:
1. Встроенный MLflow server (простой):
mlflow models serve -m models:/digits_rf_model/Production -p 5001
2. Этот скрипт — кастомный сервер с дополнительной логикой:
Запуск:
python src/serve_model.py --port 5001
Запрос:
curl -X POST http://localhost:5001/predict \
-H "Content-Type: application/json" \
-d '{"instances": [[0,0,0,...,0]]}'
"""
import argparse
import json
import numpy as np
from sklearn.datasets import load_digits
import mlflow
from flask import Flask, request, jsonify
def create_app(model_name, stage):
app = Flask(__name__)
# Загружаем модель один раз при старте
print(f"📥 Загружаем модель '{model_name}' ({stage})...")
model = mlflow.sklearn.load_model(f"models:/{model_name}/{stage}")
print(f"✅ Модель загружена!")
# Загружаем датасет для демо-генерации примеров
digits = load_digits()
@app.route("/health", methods=["GET"])
def health():
return jsonify({"status": "ok", "model": model_name, "stage": stage})
@app.route("/info", methods=["GET"])
def info():
return jsonify({
"model": model_name,
"stage": stage,
"n_features": 64,
"classes": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
"endpoints": ["/health", "/info", "/predict", "/predict_random"],
})
@app.route("/predict", methods=["POST"])
def predict():
"""Предсказание для переданных образцов.
Формат запроса:
{"instances": [[...64 числа...], [...64 числа...]]}
"""
data = request.get_json(force=True)
if "instances" not in data:
return jsonify({"error": "поле 'instances' обязательно"}), 400
instances = np.array(data["instances"])
if instances.shape[-1] != 64:
return jsonify({
"error": f"ожидалось 64 признака, получено {instances.shape[-1]}"
}), 400
predictions = model.predict(instances)
# Если модель поддерживает predict_proba — добавим вероятности
try:
probabilities = model.predict_proba(instances)
return jsonify({
"predictions": predictions.tolist(),
"probabilities": probabilities.tolist(),
"n_samples": len(predictions),
})
except AttributeError:
return jsonify({
"predictions": predictions.tolist(),
"n_samples": len(predictions),
})
@app.route("/predict_random", methods=["GET"])
def predict_random():
"""Демо-эндпоинт: берёт случайный образец из digits и предсказывает."""
idx = np.random.randint(0, len(digits.data))
sample = digits.data[idx:idx+1]
true_label = int(digits.target[idx])
prediction = int(model.predict(sample)[0])
try:
probs = model.predict_proba(sample)[0]
confidence = float(max(probs))
except AttributeError:
confidence = None
return jsonify({
"true_label": true_label,
"prediction": prediction,
"correct": true_label == prediction,
"confidence": confidence,
"sample_image": sample[0].reshape(8, 8).tolist(),
})
return app
def main():
parser = argparse.ArgumentParser(description="MLflow model serving")
parser.add_argument("--model-name", default="digits_rf_model")
parser.add_argument("--stage", default="Production")
parser.add_argument("--port", type=int, default=5001)
parser.add_argument("--host", default="0.0.0.0")
args = parser.parse_args()
app = create_app(args.model_name, args.stage)
print(f"\n🚀 Сервер запускается на http://{args.host}:{args.port}")
print(f" /health — проверка состояния")
print(f" /info — информация о модели")
print(f" /predict — предсказание (POST JSON)")
print(f" /predict_random — случайный образец (GET)")
print(f"\n📋 Примеры запросов:")
print(f" curl http://localhost:{args.port}/health")
print(f" curl http://localhost:{args.port}/predict_random")
print()
app.run(host=args.host, port=args.port, debug=False)
if __name__ == "__main__":
main()
-18
View File
@@ -18,7 +18,6 @@ import matplotlib
matplotlib.use("Agg") matplotlib.use("Agg")
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import torch import torch
from sklearn.metrics import recall_score, precision_score, f1_score
import torch.nn as nn import torch.nn as nn
import torch.optim as optim import torch.optim as optim
from torch.utils.data import DataLoader from torch.utils.data import DataLoader
@@ -141,27 +140,11 @@ def main():
acc = correct / total acc = correct / total
test_accs.append(acc) test_accs.append(acc)
# Recall / Precision / F1 (macro-усреднение по 10 классам)
all_preds, all_labels = [], []
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
pred = output.argmax(dim=1)
all_preds.extend(pred.cpu().numpy())
all_labels.extend(target.cpu().numpy())
recall = recall_score(all_labels, all_preds, average="macro")
precision = precision_score(all_labels, all_preds, average="macro")
f1 = f1_score(all_labels, all_preds, average="macro")
elapsed = time.time() - t0 elapsed = time.time() - t0
# Логируем метрики по эпохам # Логируем метрики по эпохам
mlflow.log_metric("train_loss", avg_loss, step=epoch) mlflow.log_metric("train_loss", avg_loss, step=epoch)
mlflow.log_metric("test_accuracy", acc, step=epoch) mlflow.log_metric("test_accuracy", acc, step=epoch)
mlflow.log_metric("recall_macro", recall, step=epoch)
mlflow.log_metric("precision_macro", precision, step=epoch)
mlflow.log_metric("f1_macro", f1, step=epoch)
mlflow.log_metric("epoch_time_sec", elapsed, step=epoch) mlflow.log_metric("epoch_time_sec", elapsed, step=epoch)
print(f" → Epoch {epoch+1}: loss={avg_loss:.4f}, " print(f" → Epoch {epoch+1}: loss={avg_loss:.4f}, "
@@ -186,7 +169,6 @@ def main():
mlflow.pytorch.log_model( mlflow.pytorch.log_model(
model, model,
artifact_path="model", artifact_path="model",
serialization_format="pickle",
registered_model_name=None, registered_model_name=None,
input_example=torch.randn(1, 1, 28, 28).to(device), input_example=torch.randn(1, 1, 28, 28).to(device),
) )
+1 -4
View File
@@ -15,7 +15,7 @@ import matplotlib.pyplot as plt
import numpy as np import numpy as np
from sklearn.datasets import load_digits from sklearn.datasets import load_digits
from sklearn.ensemble import RandomForestClassifier from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report, recall_score, precision_score, f1_score from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
from sklearn.model_selection import train_test_split from sklearn.model_selection import train_test_split
import mlflow import mlflow
@@ -66,9 +66,6 @@ def main():
# Логируем метрики # Логируем метрики
mlflow.log_metric("accuracy", acc) mlflow.log_metric("accuracy", acc)
mlflow.log_metric("recall_macro", recall_score(y_test, y_pred, average="macro"))
mlflow.log_metric("precision_macro", precision_score(y_test, y_pred, average="macro"))
mlflow.log_metric("f1_macro", f1_score(y_test, y_pred, average="macro"))
# можно логировать несколько шагов (для графиков в UI) # можно логировать несколько шагов (для графиков в UI)
for i, tree in enumerate(model.estimators_): for i, tree in enumerate(model.estimators_):
tree_acc = accuracy_score(y_test, tree.predict(X_test)) tree_acc = accuracy_score(y_test, tree.predict(X_test))
+2 -9
View File
@@ -7,22 +7,15 @@ set -e
cd "$(dirname "$0")" cd "$(dirname "$0")"
echo "🚀 Запускаем MLflow Tracking Server..." echo "🚀 Запускаем MLflow Tracking Server..."
echo " UI: http://10.0.0.7:5000" echo " UI: http://localhost:5000"
echo " DB: sqlite:///mlflow.db" echo " DB: sqlite:///mlflow.db"
echo " Artifacts: ./artifacts" echo " Artifacts: ./artifacts"
echo "" echo ""
echo " Нажмите Ctrl+C для остановки" echo " Нажмите Ctrl+C для остановки"
echo "" echo ""
export MLFLOW_ALLOW_ORIGIN="*"
mlflow server \ mlflow server \
--backend-store-uri sqlite:///mlflow.db \ --backend-store-uri sqlite:///mlflow.db \
--default-artifact-root ./artifacts \ --default-artifact-root ./artifacts \
--serve-artifacts \
--allowed-hosts "*" \
--cors-allowed-origins "*" \
--artifacts-destination ./artifacts \
--host 0.0.0.0 \ --host 0.0.0.0 \
--port 5000 \ --port 5000
--dev