# MLflow

**MLflow** 是一个用于管理完整的开源平台 **机器学习生命周期** —— 从实验跟踪和模型版本管理到部署和监控。被全球数千家组织使用，MLflow 为机器学习工作流带来结构性和可重复性。在 Clore.ai 的 GPU 云上运行它，可在训练作业旁获得集中式跟踪服务器。

***

## 什么是 MLflow？

MLflow 提供四个核心组件：

| 组件        | 描述                     |
| --------- | ---------------------- |
| **跟踪**    | 记录来自 ML 运行的参数、指标、工件和代码 |
| **项目**    | 打包代码以实现可重现运行           |
| **模型**    | 用于跨框架部署的标准模型格式         |
| **模型注册表** | 具有版本控制和生命周期的集中式模型存储    |

**支持的框架（内置自动记录）：**

* PyTorch、TensorFlow/Keras
* Scikit-learn、XGBoost、LightGBM
* HuggingFace Transformers
* Spark MLlib、statsmodels、Prophet

***

## 先决条件

| 要求      | 数值                      |
| ------- | ----------------------- |
| GPU 显存  | 任何（MLflow 服务器本身受限于 CPU） |
| 存储      | 20 GB+（用于工件）            |
| 内存（RAM） | 服务器最少 4 GB              |
| 端口      | 22（SSH）、5000（MLflow UI） |

{% hint style="info" %}
MLflow 跟踪服务器很轻量。您可以在小型 CPU 实例上运行它，并将 GPU 训练作业指向该服务器。或者，将其与训练 GPU 实例共置。
{% endhint %}

***

## 步骤 1 — 在 Clore.ai 上租用服务器

1. 登录到 [clore.ai](https://clore.ai).
2. 点击 **市场**.
3. 对于专用跟踪服务器：按 RAM ≥ 8 GB 过滤（GPU 可选）。
4. 对于共置：使用您现有的训练实例。
5. 设置 Docker 镜像： **`ghcr.io/mlflow/mlflow:latest`**
6. 设置开放端口： `22` （SSH）和 `5000` （MLflow UI）。
7. 点击 **租用**.

***

## 步骤 2 — 启动 MLflow 跟踪服务器

官方 `ghcr.io/mlflow/mlflow` 镜像需要覆盖启动命令。

### 在 Clore.ai Docker 配置中

设置 **命令** （或入口点覆盖）为：

```bash
bash -c "apt-get update -q && apt-get install -y -q openssh-server && \
    mkdir /var/run/sshd && \
    echo 'root:clore123' | chpasswd && \
    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && \
    service ssh start && \
    mlflow server \
        --host 0.0.0.0 \
        --port 5000 \
        --default-artifact-root /mlflow/artifacts \
        --backend-store-uri sqlite:////mlflow/mlflow.db"
```

### 可选：自定义 Dockerfile

```dockerfile
FROM ghcr.io/mlflow/mlflow:latest

RUN apt-get update && apt-get install -y \
    openssh-server \
    && rm -rf /var/lib/apt/lists/*

# 配置 SSH
RUN mkdir /var/run/sshd && \
    echo 'root:clore123' | chpasswd && \
    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# 额外的 Python 包
RUN pip install boto3 psycopg2-binary

RUN mkdir -p /mlflow/artifacts

EXPOSE 22 5000

CMD service ssh start && \
    mlflow server \
        --host 0.0.0.0 \
        --port 5000 \
        --default-artifact-root /mlflow/artifacts \
        --backend-store-uri sqlite:////mlflow/mlflow.db
```

***

## 步骤 3 — 访问 MLflow UI

打开您的浏览器：

```
http://<clore-host>:<public-port-5000>
```

您应该能看到 MLflow 实验仪表板。

{% hint style="info" %}
默认的 SQLite 后端（`mlflow.db`）将所有运行元数据存储在本地。对于生产或团队使用，请切换到 PostgreSQL — 见下方高级配置。
{% endhint %}

***

## 步骤 4 — 记录您的第一个实验

### 从远程训练作业连接

在您的训练机器（或另一个 Clore.ai 实例）上，设置跟踪 URI：

```bash
export MLFLOW_TRACKING_URI=http://<clore-host>:<public-port-5000>
```

### 基本 PyTorch 实验记录

```python
import mlflow
import mlflow.pytorch
import torch
import torch.nn as nn
import torch.optim as optim

# 连接到 MLflow 服务器
mlflow.set_tracking_uri("http://<clore-host>:<public-port-5000>")
mlflow.set_experiment("my-first-experiment")

# 定义一个简单模型
class SimpleNet(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super().__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size, output_size)
    
    def forward(self, x):
        return self.fc2(self.relu(self.fc1(x)))

# 在 MLflow 跟踪下训练
with mlflow.start_run(run_name="training-run-001"):
    # 记录超参数
    params = {
        "learning_rate": 0.001,
        "batch_size": 64,
        "epochs": 100,
        "hidden_size": 256,
        "optimizer": "adam"
    }
    mlflow.log_params(params)
    
    # 初始化模型
    model = SimpleNet(784, 256, 10).cuda()
    optimizer = optim.Adam(model.parameters(), lr=params["learning_rate"])
    criterion = nn.CrossEntropyLoss()
    
    # 训练循环
    for epoch in range(params["epochs"]):
        loss = torch.tensor(0.5 / (epoch + 1))  # 模拟
        accuracy = 0.7 + epoch * 0.003
        
        # 在每个 epoch 记录指标
        mlflow.log_metrics({
            "train_loss": loss.item(),
            "train_accuracy": accuracy,
        }, step=epoch)
    
    # 记录最终模型
    mlflow.pytorch.log_model(model, "model")
    
    # 记录最终指标
    mlflow.log_metric("final_accuracy", accuracy)
    
    print(f"Run logged to MLflow. ID: {mlflow.active_run().info.run_id}")
```

### HuggingFace Transformers 自动记录

```python
import mlflow
from transformers import TrainingArguments, Trainer

mlflow.set_tracking_uri("http://<clore-host>:<public-port-5000>")
mlflow.set_experiment("llm-finetuning")

# 启用自动记录 — 自动记录参数、指标和模型
mlflow.transformers.autolog()

training_args = TrainingArguments(
    output_dir="./results",
    num_train_epochs=3,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=64,
    learning_rate=2e-5,
    warmup_steps=500,
    weight_decay=0.01,
    logging_dir="./logs",
    logging_steps=10,
    evaluation_strategy="epoch",
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
)

with mlflow.start_run():
    trainer.train()
```

***

## 步骤 5 — 使用自动记录的 Scikit-learn

```python
import mlflow
import mlflow.sklearn
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_digits

mlflow.set_tracking_uri("http://<clore-host>:<public-port-5000>")
mlflow.set_experiment("sklearn-experiments")

# 自动记录所有内容
mlflow.sklearn.autolog()

X, y = load_digits(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

with mlflow.start_run(run_name="random-forest-v1"):
    rf = RandomForestClassifier(n_estimators=100, max_depth=10, random_state=42)
    rf.fit(X_train, y_train)
    
    score = rf.score(X_test, y_test)
    print(f"Test Accuracy: {score:.4f}")
    # 所有参数、指标和模型都会自动记录！
```

***

## 步骤 6 — 模型注册表

通过 UI 或 API 注册并管理模型版本：

```python
import mlflow

client = mlflow.MlflowClient("http://<clore-host>:<public-port-5000>")

# 从某次运行注册模型
run_id = "your-run-id-here"
model_uri = f"runs:/{run_id}/model"

registered = mlflow.register_model(
    model_uri=model_uri,
    name="production-classifier"
)

print(f"Version: {registered.version}")

# 转换模型阶段
client.transition_model_version_stage(
    name="production-classifier",
    version=registered.version,
    stage="Production"
)

# 在任何地方加载生产模型
model = mlflow.pyfunc.load_model(
    model_uri="models:/production-classifier/Production"
)
```

***

## 步骤 7 — 提供模型服务

MLflow 可以将任何已记录的模型作为 REST API 提供：

```bash
# 在 MLflow 服务器实例上
export MLFLOW_TRACKING_URI=http://localhost:5000

mlflow models serve \
    --model-uri "models:/production-classifier/Production" \
    --host 0.0.0.0 \
    --port 5001 \
    --no-conda
```

测试已提供的模型：

```bash
curl -X POST http://<clore-host>:5001/invocations \
    -H "Content-Type: application/json" \
    -d '{"inputs": [[1.0, 2.0, 3.0, ...]]}'
```

***

## 高级配置

### PostgreSQL 后端（生产）

```bash
# 使用 PostgreSQL 启动
mlflow server \
    --host 0.0.0.0 \
    --port 5000 \
    --backend-store-uri postgresql://user:password@db-host/mlflow \
    --default-artifact-root s3://my-bucket/mlflow-artifacts
```

### S3 工件存储

```bash
pip install boto3

export AWS_ACCESS_KEY_ID=your_key
export AWS_SECRET_ACCESS_KEY=your_secret

mlflow server \
    --host 0.0.0.0 \
    --port 5000 \
    --default-artifact-root s3://my-mlflow-bucket/artifacts \
    --backend-store-uri sqlite:////mlflow/mlflow.db
```

### 身份验证（企业）

```bash
pip install mlflow[auth]

mlflow server \
    --host 0.0.0.0 \
    --port 5000 \
    --app-name basic-auth \
    --backend-store-uri sqlite:////mlflow/mlflow.db \
    --default-artifact-root /mlflow/artifacts
```

***

## 在 UI 中比较运行

1. 在以下地址打开 MLflow UI `http://<clore-host>:<port>`
2. 从左侧面板选择一个实验
3. 勾选多个运行旁的复选框
4. 点击 **比较** 以并排查看指标和参数
5. 使用 **图表** 选项卡进行可视化比较

***

## 故障排除

### 无法连接到跟踪服务器

```
mlflow.exceptions.MlflowException: API 请求失败，状态码 503
```

**将批量大小减小到 1**

* 检查端口 5000 在 Clore.ai 中是否已打开并转发
* 验证服务器是否正在运行： `ps aux | grep mlflow`
* 测试连接性： `curl http://<clore-host>:<port>/health`

### 工件上传失败

**解决方案：** 确保工件目录可写：

```bash
chmod 777 /mlflow/artifacts
```

### SQLite 锁定错误（并发写入）

**解决方案：** 对于多用户设置切换到 PostgreSQL：

```bash
pip install psycopg2-binary
```

### 模型注册表未显示

**解决方案：** 验证您正在使用一个 `--backend-store-uri` 支持注册表的后端（SQLite 或 PostgreSQL——而不仅仅是本地路径）。

***

## 成本估算

| 实例       | 在 Clore.ai 上的预估费用 | 预计价格       | 说明          |
| -------- | ----------------- | ---------- | ----------- |
| CPU 四核   | 仅跟踪服务器            | ≈$0.05/小时  | 非常轻量        |
| RTX 3080 | 共置训练              | 约 $0.10/小时 | 训练 + MLflow |
| RTX 4090 | 重度训练 + 跟踪         | 约 $0.35/小时 | 最常见的设置      |

{% hint style="info" %}
在廉价的 CPU 实例上运行 MLflow，并将所有 GPU 训练作业指向它。这样跟踪服务器可以持续运行，而不会消耗昂贵的 GPU 资源。
{% endhint %}

***

## 有用的资源

* [MLflow 官方文档](https://mlflow.org/docs/latest/index.html)
* [MLflow GitHub](https://github.com/mlflow/mlflow)
* [MLflow Docker Hub](https://github.com/mlflow/mlflow/pkgs/container/mlflow)
* [MLflow 模型注册表指南](https://mlflow.org/docs/latest/model-registry.html)
* [MLflow 跟踪 API 参考](https://mlflow.org/docs/latest/python_api/mlflow.html)

***

## Clore.ai 的 GPU 建议

| 在 Clore.ai 上的预估费用 | 开发/测试             | RTX 3090（24GB） |
| ----------------- | ----------------- | -------------- |
| \~$0.12/每 GPU/每小时 | 生产                | RTX 4090（24GB） |
| 生产训练              | 大规模               | A100 80GB      |
| 大规模实验             | 💡 本指南中的所有示例均可部署在 | Clore.ai       |

> GPU 服务器上。浏览可用 GPU 并按小时租用 — 无需承诺，提供完整的 root 访问权限。 [Clore.ai](https://clore.ai/marketplace) GPU 服务器。浏览可用 GPU 并按小时租用 — 无需承诺，提供完整的 root 访问权限。
