ML 系统设计


文档摘要

ML 系统设计 ML 系统设计把第 01-03 节的基础设施模式应用到机器学习的特定挑战上。本文件覆盖 ML 生命周期、数据管理、训练基础设施、模型评估、服务策略、特征工程、ML 流水线和监控 一道系统设计面试题,比如"为 YouTube 设计一个推荐系统",并不是让你描述推荐算法。它问的是:设计整个系统——数据流水线、特征工程、模型训练、评估、服务、监控、迭代。本文件给你这个框架。 ML 系统生命周期 ML 系统生命周期:从问题定义到部署和监控,并持续迭代 每个 ML 系统都遵循同样的生命周期,无论它是一个垃圾邮件分类器还是一个基础模型: 问题定义 在碰数据或模型之前,先定义清楚: 预测什么?(点击概率、下一个 token、目标边界框) 用户是谁?

ML 系统设计

ML 系统设计把第 01-03 节的基础设施模式应用到机器学习的特定挑战上。本文件覆盖 ML 生命周期、数据管理、训练基础设施、模型评估、服务策略、特征工程、ML 流水线和监控

  • 一道系统设计面试题,比如"为 YouTube 设计一个推荐系统",并不是让你描述推荐算法。它问的是:设计整个系统——数据流水线、特征工程、模型训练、评估、服务、监控、迭代。本文件给你这个框架。

ML 系统生命周期

ML 系统生命周期:从问题定义到部署和监控,并持续迭代

  • 每个 ML 系统都遵循同样的生命周期,无论它是一个垃圾邮件分类器还是一个基础模型:
问题定义 → 数据 → 特征 → 训练 → 评估 → 部署 → 监控 → 迭代 ↑ │ └────────────────────────────────────────────────────────────────────────────────────┘

问题定义

  • 在碰数据或模型之前,先定义清楚:

    • 预测什么?(点击概率、下一个 token、目标边界框)
    • 用户是谁?(终端用户、内部分析师、其他 ML 模型)
    • 约束是什么?(延迟 < 100ms、离线 batch 也行、必须在端上跑)
    • 业务指标是什么?(营收、参与度、准确率)以及 ML 指标和它怎么挂钩?
    • 基线是什么?(启发式规则、基于规则的系统、已有的模型)——你必须超过它,才值得做这个 ML 系统。
  • 常见错误:还没搞清楚问题,就跳到模型架构。"我们应该用 transformer"不是一个系统设计答案。"我们需要在 200ms 内对 1000 万个候选项预测点击概率,所以我们需要一个两阶段系统:先快速召回,再用一个小模型精排"才是。

数据管理

数据收集与标注

  • 显式标签(explicit labels):人工标注数据(点击/不点击、目标边界框、对话质量评分)。贵(每个标签约 $0.02-$10,视复杂度而定)、慢,且主观。

  • 隐式标签(implicit labels):从用户行为派生标签。点击、停留时长、购买、跳过。便宜且海量,但有噪声(一次点击不等于满意;一次跳过也不等于不喜欢)。

  • 程序化标注(programmatic labelling,Snorkel):写标注函数(启发式、正则、已有模型),让它们对每个样本投票。再用统计方法聚合投票,产出概率标签。能扩展到上百万样本,准确率中等。

  • 主动学习(active learning):模型挑出自己最没把握的样本,请人工标注。这最大化了标注效率:1000 个主动挑选的标签,效果可能抵得上 10000 个随机标签。

数据质量

  • 数据校验(data validation):检查每个进来的数据批次有没有 schema 违规(字段缺失、类型错)、分布漂移(均值显著变化)、体量异常(预期 100 万行,只来了 50 万)。

  • Great ExpectationsTFX Data Validation 是定义数据期望、并在期望被违反时告警的工具。

  • 数据版本管理(data versioning):每次训练都应该可复现。DVC(第 15 章)把数据文件和代码一起跟踪。每个数据集版本都有一个 hash;训练配置引用这个 hash。

特征存储

特征存储:同一份特征计算同时喂给离线存储(训练用)和在线存储(服务用),避免训练-服务偏差

  • 特征存储(feature stores)(第 15 章)为训练和服务提供一致的特征。关键概念:

    • 离线特征(offline features):由批处理流水线(Spark)计算,存在数据仓库里。训练和批量推理时用。例如:用户过去 30 天的平均会话时长、物品的总购买数。

    • 在线特征(online features):实时计算,或预先算好放到低延迟存储(Redis、DynamoDB)里供服务时用。实时推理时用。例如:用户最近 5 次操作、当前购物车内容。

    • 训练-服务偏差(training-serving skew):如果特征计算在训练和服务时不一致,模型推理时看到的特征值就和训练时不一样。特征存储通过让两者用同一份计算,消除了这种偏差。

训练基础设施

  • 对本书读者而言,分布式训练已经在第 6 章深入讲过(数据并行、模型并行、混合精度、扩展律)。这里聚焦系统层面:

  • 实验跟踪(experiment tracking)(W&B、MLflow——第 15 章):每次训练都记录超参数、指标、git commit、数据版本和硬件。这是模型领域的"版本控制"。

  • 超参数调优(hyperparameter tuning):在超参数空间上自动搜索。方法有:网格搜索(穷举,贵)、随机搜索(出奇地有效)、贝叶斯优化(建模目标函数,在可能有提升的地方采样)、以及 ASHA(异步连续减半,Asynchronous Successive Halving:同时跑很多试验,早早干掉表现差的)。

  • 训练流水线编排(training pipeline orchestration)(Airflow、Kubeflow——第 15 章):把"数据准备 → 训练 → 评估 → 注册"这一串自动化。安排每日重训。失败时告警。

模型评估

离线评估

  • 留出测试集(held-out test set):在训练时模型从没见过的数据上评估。标准做法,但如果测试集不能代表线上数据,可能会有误导。

  • 分切片评估(slice-based evaluation):在子群上评估(按用户人口统计、内容类型、语言、时间段)。一个整体准确率 95% 的模型,对某个特定少数群体的准确率可能只有 70%——这不可接受。

  • 回测(backtesting):对时间序列或序列预测,按时间顺序在历史数据上评估。在到时刻 t 为止的数据上训练,在 tt + \Delta t 的数据上评估。避免用未来数据训练导致的泄漏。

在线评估

A/B 测试:把用户随机分成对照组(旧模型)和实验组(新模型),用统计显著性对比指标

  • A/B 测试(A/B testing):把线上流量随机分成对照组(旧模型)和实验组(新模型)。用统计显著性比较业务指标(营收、参与度、留存)。评估 ML 变更的金标准。

    • 样本量:要有足够数据才能检出预期的效应大小。点击率提升 0.1%,需要几百万次曝光才能以显著性检出。

    • 时长:至少跑完一个完整周期(多数产品为 1-2 周),以捕捉星期几效应。

    • 护栏指标(guardrail metrics):在关注目标指标的同时,监控那些不应该变化的指标(页面加载时间、错误率、崩溃率)。一个提高了营收但也提高了崩溃率的模型,净效果是负的。

  • 影子部署(shadow deployment):在生产环境里把新模型和老模型并行跑。两者收到相同请求,但只有老模型的预测真正服务给用户。对比两者的输出。这能在不影响用户的风险下抓住 bug 和质量问题。

  • 交替(interleaving):对于排序问题,把老模型和新模型的结果在同一个列表里交替排列。用户和这个交替列表交互,你测量哪个模型的结果获得了更多参与。比 A/B 测试需要更少用户就能达到显著性。

模型服务

批量 vs 实时

  • 批量推理(batch inference):对所有可能的输入预先算好预测,存在数据库/缓存里,服务时直接从缓存取。适用场景:输入空间有限(每晚为所有用户算推荐)、新鲜度不关键(每天算一次就行)、延迟容忍度高。

  • 实时推理(real-time inference):对每个请求按需算预测。适用场景:输入空间无限(任意用户查询)、新鲜度重要(就为这个具体查询马上预测)、延迟必须低。

  • 很多系统两者并用:批量预计算一批候选项(便宜,覆盖 80% 流量),实时处理剩下的(贵,覆盖长尾查询和新用户)。

模型版本管理与注册表

  • 模型注册表(model registry)(MLflow、W&B、SageMaker)把训练好的模型连同元数据一起存起来:

    • 版本号和训练日期。
    • 训练配置和数据版本。
    • 评估指标(准确率、延迟、内存占用)。
    • 阶段:开发(development) → 预发布(staging) → 生产(production) → 归档(archived)。
  • 回滚(rollback):如果新模型在线上让指标退化,立刻切回上一个版本。注册表让这变成一键操作。

特征工程

  • 特征工程(feature engineering) 把原始数据转换成模型需要的输入。它往往是 ML 中杠杆最高的活动:更好的特征能让所有模型受益,而更好的模型则受限于喂给它的特征。

在线 vs 离线特征

  • 离线特征 预先算好、变化缓慢(用户人口统计、30 天聚合值)。由批处理流水线(Spark)计算,存在特征存储里。

  • 在线特征 反映当前状态、变化很快(购物车里的商品、最近一次操作、当前位置)。从事件流实时算,或从快速存储里查。

  • 特征新鲜度(feature freshness):有些特征需要秒级新鲜(欺诈检测:给定最近 5 笔交易,这笔交易异常吗?)。有些可以容忍几小时不新鲜(推荐:基于历史,这个用户偏好哪些类型?)。越新鲜的特征,计算和服务的成本越高。

常见特征模式

  • 计数特征(counting features):一个时间窗口内的事件数(过去 7 天的购买数、过去 24 小时的登录数)。
  • 嵌入特征(embedding features):类别变量的学习嵌入(用户嵌入、物品嵌入、查询嵌入)。这是双塔模型及类似架构的输入。
  • 交叉特征(cross features):两个或多个特征的组合(user_age × item_category)。捕捉单个特征捕捉不到的交互。
  • 时间特征(temporal features):距上次操作的时间、星期几、几点钟。捕捉时间模式。
  • 聚合特征(aggregation features):某数值特征在某分组上的均值、中位数、最小值、最大值、标准差(某卖家物品的平均评分)。

ML 流水线

  • 一条 ML 流水线编排从数据到部署模型的整个工作流:
数据摄入 → 校验 → 特征工程 → 训练 → 评估 → 注册 → 部署 → 监控
  • 每一步都是编排器(Airflow、Kubeflow、Metaflow——第 15 章)里的一个任务。这条流水线:

    • 按调度(每日重训)或触发(新数据可用)运行。
    • 是幂等的(重跑结果相同)。
    • 有重试逻辑(特征计算失败就带退避重试 3 次)。
    • 产出带版本管理的产物(训练好的模型、评估报告、特征统计)。
  • Metaflow(Netflix/Outerbounds)特别适合 ML:它把代码、数据和模型一起做版本管理,支持用同一份代码在本地开发和云上执行,并和 K8s、AWS 集成。

监控

  • 我们在第 15 章介绍过监控基础(Prometheus、Grafana、告警)。这里聚焦ML 专属的监控

数据漂移

  • 数据漂移(data drift) 指的是输入数据的分布相对训练数据发生了变化。用夏季数据训练的模型,在冬季数据上可能表现很差(用户行为不同、商品可得性不同)。

  • 检测:用统计检验把输入特征的分布和训练分布对比:

    • KS 检验(Kolmogorov-Smirnov):比较两个经验分布,检验它们是否来自同一个底层分布。
    • PSI(群体稳定性指标,Population Stability Index):衡量一个分布漂移了多少。PSI < 0.1 稳定,0.1-0.25 中度漂移,> 0.25 显著漂移。
    • 嵌入漂移(embedding drift):用质心距离或 MMD(最大均值差异,Maximum Mean Discrepancy)把输入查询的嵌入分布和训练集对比。

概念漂移

  • 概念漂移(concept drift) 指的是输入和输出之间的关系发生了变化。特征看起来一样,但正确的预测变了。例子:在某次文化事件、疫情或产品变更后,用户偏好发生转变。

  • 概念漂移比数据漂移更难检测,因为它需要标签。监控代理指标:点击率、转化率、用户满意度评分。持续下降暗示概念漂移。

模型退化

  • 模型随时间退化有多种原因:数据漂移、概念漂移、特征流水线 bug(某个特征开始返回 null)、上游数据变更(某个第三方 API 改了响应格式)。

  • 应对:检测到退化时,行动取决于严重程度:

    • 轻度:在近期数据上重训(定时重训即可处理)。
    • 中度:调查根因(哪个特征变了?哪个用户群体受影响?)。
    • 重度:立刻回滚到上一个模型版本,然后再调查。

反馈回路

  • ML 系统会创造反馈回路(feedback loops):模型的预测影响用户行为,而这些行为又成了下一个版本模型的训练数据。这些回路可以是良性的,也可以是恶性的。

  • 正反馈回路(positive feedback loop,危险):推荐模型主要展示热门物品 → 用户点击热门物品(因为他们只看得到这些)→ 模型学到热门物品更热门 → 多样性崩溃。模型创造出了证实自身偏见的那些数据。

  • 负反馈回路(negative feedback loop,同样危险):欺诈检测模型抓住了所有 A 类欺诈 → 没有A类欺诈进入训练数据 → 下一版模型学不到如何检测 A 类 → A 类欺诈卷土重来。

  • 缓解措施

    • 探索(exploration):展示一些模型不太确定的物品(epsilon-greedy、Thompson sampling)。这能产生多样化的训练数据。
    • 反事实日志(counterfactual logging):记录模型本来会预测什么,而不只是用户看到的。用反事实数据训练以去偏。
    • 留出集(holdout sets):随机把一部分流量不经模型过滤地服务出去。这些未过滤的数据提供了评估模型质量的真实参照。
    • 延迟标签(delayed labels):等真实结果出来后再用数据训练。今天被点击的推荐,明天可能就后悔了。一笔欺诈预测必须等到退单窗口(30-90 天)结束。

嵌入表管理

  • 大规模 ML 系统往往有上亿条目的嵌入表(每个用户、物品、广告或实体一个嵌入)。在规模上管理它们是一个系统挑战:

  • 存储:1 亿实体 × 256 维 × float16 = 50 GB。塞不进 GPU 显存。解决方案:存在 CPU 内存里配合 GPU 端缓存、跨多台机器分片,或用哈希嵌入(hash embeddings)(把实体哈希到一个固定大小的表,接受冲突)。

  • 更新:嵌入随模型重训而变化。把新嵌入表部署到服务端需要:在不打扰线上流量的情况下把 50 GB 加载进内存、校验正确性、指标退化时回滚。对嵌入表用蓝绿部署。

  • 陈旧度:一个新创建的用户没有嵌入(冷启动问题)。解决方案:用一个默认嵌入、通过一个"特征到嵌入"模型从用户特征派生嵌入,或退回到一个非个性化模型。

公平性与偏见

  • ML 系统可能系统性地对不同群体区别对待,这往往反映训练数据中的偏见。公平性监控(fairness monitoring) 是一种责任,不是可有可无的功能。

  • 要监控的指标

    • 人口统计均等(demographic parity):不同群体(性别、种族、年龄)的正预测率是否不同?
    • 机会均等(equal opportunity):不同群体的真正例率是否不同?(一个招聘模型应该在所有群体中都同样擅长识别合格候选人。)
    • 校准(calibration):如果模型说 P(合格) = 0.7(A 群体),那 A 群体中实际真有 70% 合格吗?B 群体呢?
  • 实践步骤

    • 在切片(子群)上评估模型表现,而不只看整体指标。
    • 把公平性指标纳入模型评估流水线(一个提高了整体准确率但对某特定群体退化的模型,不应未经评审就部署)。
    • 文档化已知的局限和失败模式。
    • 为部署在敏感领域(招聘、信贷、刑事司法、医疗)的模型建立评审流程。

发布者: 作者: HenryNdubuaku 转发
评论区 (0)
U