# 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 访问权限。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-zh/mlops-yu-bu-shu/mlflow.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
