Files
maths-cs-ai-compendium-zh/chapter 15: production software engineering/05. deployment and devops.md
T
flykhan 2536c937e3 feat: 完整中文翻译 maths-cs-ai-compendium(数学·计算机科学·AI 知识大全)
翻译自英文原版 maths-cs-ai-compendium,共 20 章全部完成。

第01章 向量 | 第02章 矩阵 | 第03章 微积分
第04章 统计学 | 第05章 概率论 | 第06章 机器学习
第07章 计算语言学 | 第08章 计算机视觉 | 第09章 音频与语音
第10章 多模态学习 | 第11章 自主系统 | 第12章 图神经网络
第13章 计算与操作系统 | 第14章 数据结构与算法
第15章 生产级软件工程 | 第16章 SIMD与GPU编程
第17章 AI推理 | 第18章 ML系统设计
第19章 应用人工智能 | 第20章 前沿人工智能

翻译说明:
- 所有数学公式 $...$ / $$...$$、代码块、图片引用完整保留
- mkdocs.yml 配置中文导航 + language: zh
- README.md 已翻译为中文(兼 docs/index.md)
- docs/ 目录包含指向各章文件的 symlink
- 约 29,000 行中文内容,排除 .cache/ 构建缓存
2026-05-03 10:23:20 +08:00

234 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 部署与 DevOps
*部署是你的模型从研究产物变成产品的地方。本文涵盖用于机器学习的 Docker、模型推理、实验追踪、可重现性、生产环境监控、特征存储和管道编排——这些基础设施将一个训练好的模型从 notebook 带到数百万用户面前。*
- 一个只在你笔记本电脑上运行的模型是原型。一个能够可靠地大规模运行、在毫秒内提供预测结果、能够从故障中恢复并在不中断服务的情况下更新的模型才是产品。两者之间的差距就是**部署与 DevOps**。
- 大多数机器学习工程师在部署、监控和调试生产问题上花费的时间比训练模型还多。理解这些基础设施对于任何构建真实 ML 系统的人来说都不是可选项。
## 用于机器学习的 Docker
- 我们在第 13 章(操作系统)中概念性地介绍了容器。这里我们关注实践方面:为机器学习工作负载编写 Dockerfile。
- **Dockerfile** 是构建容器镜像的配方:
```dockerfile
# 从官方的 CUDA 基础镜像开始
FROM nvidia/cuda:12.1.0-cudnn8-runtime-ubuntu22.04
# 系统依赖
RUN apt-get update && apt-get install -y \
python3.11 python3-pip git \
&& rm -rf /var/lib/apt/lists/*
# Python 依赖(单独安装以利用缓存)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 复制源代码(频繁更改,因此此层放在最后)
COPY src/ /app/src/
COPY configs/ /app/configs/
WORKDIR /app
# 入口点
CMD ["python3", "src/scripts/serve.py", "--config", "configs/serve.yaml"]
```
- **层缓存**:Docker 会缓存每一层。如果 `requirements.txt` 没有变化,`pip install` 在重新构建时会被跳过。将不常更改的层(系统包、pip 安装)放在频繁更改的层(源代码)之前。这将 10 分钟的构建变成 10 秒的重新构建。
- **GPU 访问**:使用 `nvidia/cuda` 基础镜像,并使用 `docker run --gpus all` 运行。`nvidia-container-toolkit` 提供从宿主机到容器的 GPU 透传。
- **多阶段构建**通过将构建环境与运行环境分离来减小镜像大小:
```dockerfile
# 构建阶段:安装构建工具、编译依赖
FROM python:3.11 AS builder
COPY requirements.txt .
RUN pip install --user -r requirements.txt
# 运行阶段:仅运行环境依赖
FROM nvidia/cuda:12.1.0-cudnn8-runtime-ubuntu22.04
COPY --from=builder /root/.local /root/.local
COPY src/ /app/src/
ENV PATH=/root/.local/bin:$PATH
```
- 最终镜像只包含运行时库,不包含编译器、头文件或构建工具。一个 5GB 的构建镜像变成了 2GB 的运行镜像。
- **Docker Compose** 运行多容器设置(模型服务器 + 负载均衡器 + 监控):
```yaml
# docker-compose.yml
services:
model:
build: .
ports:
- "8080:8080"
deploy:
resources:
reservations:
devices:
- capabilities: [gpu]
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
```
## 模型推理
- **模型推理**是将推理作为服务运行:接收请求、运行模型、返回预测结果。
- **FastAPI**(在文件 03 中介绍)适用于低到中等吞吐量的最简单方法。对于高吞吐量和 GPU 优化推理,使用专用工具:
- **Triton Inference Server**NVIDIA):以 TensorRT、ONNX、PyTorch 和 TensorFlow 格式提供模型。特性:
- **动态批处理**:收集单个请求并将它们分批处理以提高 GPU 效率。单个请求流被分组为 32 的批次,大幅提高吞吐量。
- **模型集成**:在单个请求中链式调用多个模型(预处理器 → 模型 → 后处理器)。
- **多模型推理**:在同一 GPU 上提供多个模型,共享资源。
- **并发模型执行**:在同一 GPU 上并行运行多个推理请求。
- **TorchServe**PyTorch):以 REST/gRPC API 提供 PyTorch 模型。支持模型版本控制、A/B 测试和自定义处理器。
- **vLLM**:专门用于 LLM 推理。实现了 PagedAttention(高效的 KV 缓存管理)、连续批处理和跨 GPU 的张量并行。对于大语言模型,吞吐量比朴素推理高出 10-20 倍。
- **Cactus**[github.com/cactus-compute/cactus](https://github.com/cactus-compute/cactus)):一个用于移动端和边缘端设备推理的低延迟 AI 引擎。Cactus 提供**兼容 OpenAI 的 API**(聊天补全、流式传输、工具调用、转录、嵌入、RAG、视觉),完全在设备上运行,当本地模型无法处理请求时自动进行**云回退**。这种混合架构意味着你的应用程序代码使用相同的 API,无论推理是在本地还是在云端运行——引擎根据模型置信度和设备能力来决定。提供 Python、Swift、Kotlin、Flutter、React Native 和 Rust 的 SDK,以及 HuggingFace 上预转换的模型权重。支持多模态推理(LLM、视觉、语音),配备自定义 ARM SIMD 内核以实现 ARM CPU 上的最快推理,以及零拷贝内存映射以实现 10 倍 RAM 使用降低(第 16 章、第 17 章)。
- **模型格式优化**
- **ONNX**:用于互操作性的开放格式。从 PyTorch/TensorFlow 导出,在任何地方运行。
- **TensorRT**NVIDIA 的优化器。融合层、选择最佳内核、量化权重。在 NVIDIA GPU 上通常比 PyTorch 快 2-5 倍。
- **GGUF/GGML**:适用于 CPU 高效推理的格式,在消费级硬件上运行 LLM 时很流行。
## 实验追踪
- 没有实验追踪,机器学习研究会退化为:"我觉得上周二那个我改了些配置的模型是最好的,但我不记得改了啥。"
- **Weights & BiasesW&B**:最流行的实验追踪工具。从你的训练脚本中记录任何内容:
```python
import wandb
wandb.init(project="my-project", config={
"model": "transformer",
"lr": 3e-4,
"batch_size": 64,
})
for epoch in range(num_epochs):
train_loss = train_one_epoch()
val_loss = validate()
wandb.log({
"train/loss": train_loss,
"val/loss": val_loss,
"epoch": epoch,
})
# 将模型记录为产物
if val_loss < best_loss:
wandb.save("best_model.pt")
wandb.finish()
```
- W&B 提供:用于比较运行的仪表板、超参数扫描工具、模型注册表、数据集版本控制和团队协作。
- **MLflow**:开源替代方案。在本地或服务器上运行:
```python
import mlflow
mlflow.set_experiment("my-experiment")
with mlflow.start_run():
mlflow.log_params({"lr": 3e-4, "batch_size": 64})
mlflow.log_metric("val_loss", 0.042, step=epoch)
mlflow.pytorch.log_model(model, "model")
```
- **模型注册表**:训练模型的中央存储,带版本控制、阶段(开发 → 预发布 → 生产)和元数据。W&B 和 MLflow 都提供注册表。注册表回答:"当前生产环境中的是哪个模型,谁训练的,其验证准确率是多少,以及由哪个代码/数据产生?"
## 可重现性
- 可重现性意味着:给定相同的代码、数据和配置,产生相同的模型。这在机器学习中出奇地困难,因为 GPU 操作的非确定性、数据打乱和浮点数累积。
- **可重现性检查清单**
| 什么 | 如何做 |
|------|------|
| 代码版本 | Git 提交哈希值 |
| 配置 / 超参数 | 配置文件(在 Git 中版本控制或记录到 W&B |
| 随机种子 | 设置并记录所有种子(Python、NumPy、PyTorch、CUDA |
| 数据版本 | DVC 哈希值、数据集版本标签或 S3 对象版本 |
| 依赖项 | `pip freeze`、Docker 镜像哈希值或锁定文件 |
| 硬件 | GPU 类型、GPU 数量、CUDA 版本 |
| 非确定性 | `torch.backends.cudnn.deterministic = True`(较慢但可重现) |
- **锁定所有内容**`pip install torch==2.2.1` 而不是 `torch>=2.0`。次版本号升级可能改变数值行为、优化器实现或默认超参数。
- **使用 Docker 实现可重现性**:Docker 镜像锁定了操作系统、系统库、Python 版本和 pip 包。镜像哈希值是完整的环境指纹。如果你能重现 Docker 镜像,就能重现训练。
## 生产环境监控
- 部署模型不是终点——而是一系列新问题的开始。随着现实世界的变化(**概念漂移**)以及输入数据分布的变化(**数据漂移**),模型会随时间推移而退化。
- **需要监控的内容**
- **延迟**:推理需要多长时间?追踪 p50(中位数)、p95 和 p99。p99 为 500ms 意味着每 100 个用户中有 1 个要等待半秒钟,这可能不可接受。
- **吞吐量**:每秒处理多少个请求?系统是否跟得上需求?
- **错误率**:有多少比例的请求失败(异常、超时、无效输入)?
- **模型指标**:在验证集上的准确率、精确率、召回率。如果生产环境中存在标注数据(例如用户纠正),追踪在线指标。
- **数据漂移**:输入数据的分布是否发生了变化?在白天照片上训练的模型可能在夜间照片上失败。统计检验(KS 检验、PSI)将训练分布与在线分布进行比较。
- **特征漂移**:单个特征的分布是否发生了变化?训练时呈正态分布但在生产时呈双峰分布的特征,表明数据管道存在问题。
- **工具**
- **Prometheus** + **Grafana**:基础设施监控的标准方案。Prometheus 收集指标,Grafana 将其可视化为带告警的仪表板。
- **Evidently AI**:开源机器学习监控。生成关于数据漂移、模型性能和数据质量的报告。
- **告警**:不要只放在仪表板上——设置自动告警。"如果 p99 延迟超过 200ms 持续 5 分钟,发送 Slack 通知。""如果数据漂移评分超过阈值,通知值班工程师。"
## 特征存储
- **特征存储**是预计算特征的集中式仓库,在训练和推理之间共享。它解决两个问题:
- **训练-推理偏差**:训练期间使用的特征必须与推理期间使用的特征完全相同。如果训练使用一种方式计算的 `user_age_at_signup`,而推理使用不同的方式计算,模型的预测结果会静默出错。
- **特征复用**:多个模型通常使用相同的特征(用户人口统计、物品嵌入、聚合统计)。计算一次并共享,避免了重复和不一致性。
- **Feast** 是最流行的开源特征存储。它管理在线特征(低延迟,从 Redis 或 DynamoDB 提供)和离线特征(批处理,存储在数据仓库中用于训练)。
- 特征存储对于推荐系统、欺诈检测以及任何特征从原始数据管道计算而来的应用都至关重要。
## 管道编排
- 生产级机器学习系统不仅仅是模型。它是一个**管道**:数据采集 → 预处理 → 特征计算 → 训练 → 评估 → 部署 → 监控。每个步骤依赖于前一步骤,可以独立失败,可能需要在不同的时间表上运行。
- **编排器**管理这些管道:
- **Apache Airflow**:数据管道编排的标准方案。DAG(有向无环图)定义任务依赖关系。每个任务独立运行,失败时可以重试,并通过 Web UI 进行监控。
```python
# airflow DAG 示例(简化)
from airflow import DAG
from airflow.operators.python import PythonOperator
dag = DAG("training_pipeline", schedule="@daily")
preprocess = PythonOperator(task_id="preprocess", python_callable=preprocess_data, dag=dag)
train = PythonOperator(task_id="train", python_callable=train_model, dag=dag)
evaluate = PythonOperator(task_id="evaluate", python_callable=evaluate_model, dag=dag)
deploy = PythonOperator(task_id="deploy", python_callable=deploy_model, dag=dag)
preprocess >> train >> evaluate >> deploy
```
- **Kubeflow Pipelines**:在 Kubernetes 上运行机器学习特定编排。每个步骤在容器中运行,GPU 资源按需分配,实验自动追踪。
- **Prefect** 和 **Dagster**:Airflow 的现代替代方案,拥有更好的开发者体验、原生 Python API 和内置数据血缘追踪。
- **何时需要编排**:当你的管道有超过 2-3 个步骤、按计划运行、涉及多个团队或服务、或需要自动故障恢复时。单一脚本的训练任务不需要编排器。每天重新训练的管道——从 5 个数据源采集数据、训练 3 个模型、评估它们并部署最佳模型——绝对需要。