09. 项目经验与 Production ML
1. 离线训练好的模型在线上不工作,可能是什么原因?
30 秒回答
我会先确认“不工作”的定义和退化发生在哪一层,再按以下顺序排查:
- 指标、流量和实验设置是否正确。
- 训练与线上特征流水线是否一致。
- 数据分布、标签定义或用户行为是否变化。
- 离线指标是否与业务目标错位。
- 阈值、校准、延迟和系统约束是否破坏模型效果。
不能一开始就假设“模型泛化差”,因为生产问题经常来自数据管道、实验分流或业务集成。
数据与标签问题
- Train/validation 存在 leakage,离线成绩虚高。
- 训练数据不代表线上用户、时间段、语言或设备。
- 标签延迟、标签噪声或线上标签定义不同。
- 线上出现新类别、冷启动用户或长尾输入。
- Sampling strategy 改变了类别先验。
- 训练数据经过人工清洗,线上原始数据更脏。
Training-Serving Skew
- 特征计算代码、窗口、时区、单位或归一化不同。
- 类别 ID、词表、缺失值编码或 schema 不一致。
- 线上特征过期,event-time 与 processing-time 混淆。
- Join key 错误、重复记录或默认值比例异常。
- 模型、preprocessor、feature store 版本不匹配。
应对关键特征做离线/在线 parity test:给定相同原始事件,两条流水线必须产生相同特征。
目标和评估错位
- 优化 AUC,但业务关心固定容量下的 Precision@K。
- 平均指标提高,但重要用户切片退化。
- 离线数据没有模拟曝光偏差、反馈回路或竞争环境。
- 模型概率未校准,线上阈值沿用旧模型。
- Proxy label 与真实长期目标不一致。
追问:离线指标高,但业务没提升,先怀疑什么?
优先怀疑 metric mismatch 和数据问题:
- 离线指标和业务目标不一致,例如 AUC 提升但 Precision@K 没提升。
- validation/test 分布不代表线上流量。
- 概率没校准,阈值沿用旧模型。
- 平均指标提升,但关键用户切片退化。
- 线上延迟、fallback、日志归因影响真实结果。
系统问题
- 延迟超时导致模型结果被 fallback 覆盖。
- 特征服务、缓存或下游规则修改模型输出。
- 量化、模型转换或不同推理库造成数值偏差。
- A/B 分流、日志或指标归因错误。
- 吞吐压力下发生丢请求、批处理 padding 或状态串扰。
推荐排查流程
- 用少量 request ID 端到端重放,核对原始输入、特征、logit、概率、阈值和最终动作。
- 比较 offline replay、shadow traffic 与正式线上结果。
- 检查 schema、missing rate、特征分布和预测分布。
- 按用户、时间、设备、地区和标签切片。
- 人工审查典型 false positive / false negative。
- 定位后再决定修数据、调阈值、重新校准还是重新训练。
2. Loss 变成 Inf 或 NaN 的原因
优化与梯度
- 学习率过大,参数或激活迅速爆炸。
- 梯度爆炸,特别是深层网络、RNN 或长序列。
- 没有 gradient clipping,或 clipping 在错误时机执行。
- 初始化、残差尺度或 optimizer hyperparameter 不合理。
- 恢复 checkpoint 时 optimizer state、scheduler 或 loss scaler 不一致。
数值不稳定
- 直接计算
exp(large_value)。 - 计算 \(\log(0)\)、除以 0、\(\sqrt{x<0}\)。
- Softmax/Log Loss 没使用 log-sum-exp 或 logits fused implementation。
- Normalization 的方差太小且 \(\epsilon\) 不足。
- FP16 overflow/underflow;BF16 动态范围通常更大,但也不能避免所有问题。
- 自定义 loss 中先求极小概率,再取 log。
数据问题
- 输入、label 或 sample weight 已包含 NaN/Inf。
- 异常大值、错误单位或未归一化特征。
- 非法标签,例如分类 label 越界。
- 空 batch、全 mask、长度为 0 或分母计数为 0。
- 数据增强产生无效值。
分布式与实现问题
- 某个 rank 先出现 NaN,经 all-reduce 污染全部 rank。
- Mask 符号或广播错误,把全部 logits 设为 \(-\infty\)。
- In-place operation 破坏 autograd 所需张量。
- 混合精度下错误的 loss scaling 或 cast。
- 自定义 kernel 越界、竞态或未初始化内存。
排查顺序
- 定位第一个出现非有限值的 step 和 batch,而不是只看最终 loss。
- 检查原始输入、label 和每个 loss component 是否 finite。
- 记录逐层 activation、logit、parameter、gradient norm。
- 暂时切到 FP32、降低学习率、关闭复杂优化和数据增强,缩小问题。
- 开启
torch.autograd.detect_anomaly()做小规模定位。 - 若只在分布式出现,比较各 rank 的第一个异常 tensor。
- 修复根因后从异常前的健康 checkpoint 恢复。
只加一个很大的 \(\epsilon\) 或跳过所有 NaN batch 可能掩盖问题,不应作为最终修复。
3. 如何检测 Data Shift?
三类 Shift
- Covariate shift:\(P(X)\) 改变,但 \(P(Y\mid X)\) 基本不变。
- Label shift:\(P(Y)\) 改变,但类条件分布 \(P(X\mid Y)\) 基本不变。
- Concept drift:\(P(Y\mid X)\) 改变,相同输入与目标的关系发生变化。
仅检测输入分布不能证明 concept drift;后者通常需要延迟到达的真实标签或可靠 proxy。
数据质量与 Schema
首先监控:
- 类型、取值范围、类别集合和 schema 版本。
- Missing rate、默认值率、唯一值数量。
- 数据量、延迟、重复率和 join success rate。
- 特征新鲜度和时间窗口。
这一步能快速发现管道故障,不应直接用复杂 drift detector 替代。
追问:Model drift 和 data bug 怎么区分?
- data bug 通常是突变:某个字段 missing rate 突然 90%,类别全变 unknown,join success rate 掉了。
- drift 通常是分布逐渐或周期性变化,例如季节、用户行为、产品策略改变。
先排 data quality,再谈模型漂移。
单变量检测
- 连续变量:KS test、Wasserstein distance、PSI、分位数变化。
- 类别变量:Chi-square、Jensen-Shannon divergence、类别频率变化。
- 预测:score distribution、entropy、positive rate。
大样本下很小差异也可能统计显著,因此必须同时设置 effect-size 和业务阈值。
多变量检测
- 训练一个 domain classifier 区分 reference 和 current data;AUC 明显高于 0.5 表示联合分布可区分。
- 对 embedding 或高维特征使用 MMD、energy distance 或聚类覆盖。
- 按重要业务切片监控,而不是只看全局平均。
有标签后的性能监控
- Accuracy、AUC、PR-AUC、calibration、业务收益。
- 各切片的错误率和置信区间。
- 标签延迟分层,避免只评估最快到达的一部分标签。
- Champion/challenger 和 shadow evaluation。
Drift 告警设计
不要让每个特征的轻微变化都触发告警。应组合:
- 数据质量硬规则。
- Drift score 持续多个时间窗口超阈值。
- 重要特征加权。
- 预测或业务指标同步异常。
- 人工可解释的 top shifted features。
4. Data Shift 如何补救?
先判断根因
- 数据 bug:修复 pipeline 并回填数据。
- 季节性或短期事件:调阈值、扩大窗口或临时 fallback。
- 类别先验变化:在假设成立时做 prior correction / label-shift adjustment。
- Covariate shift:importance weighting、补采样新分布数据。
- Concept drift:收集新标签并重新训练或持续学习。
常见方案
- 重新校准概率或重新选择 decision threshold。
- 使用近期数据 fine-tune/retrain,并保留历史 replay 防遗忘。
- 增加新类别、unknown bucket 和 OOD detection。
- Domain adaptation 或 invariant representation。
- Online learning,但必须防反馈污染和灾难性遗忘。
- 回退到更简单、鲁棒或规则化的 baseline。
生产机制
- 数据和模型版本化。
- 定期 retraining 与 event-triggered retraining 结合。
- Canary、shadow、A/B test 后再全量发布。
- 保留 rollback 和人工审批。
- 将每次 drift incident 变成 regression test。
5. 标注数据有限时如何训练?
优先级
- 使用预训练模型或 foundation model 做 transfer learning。
- 设计高质量、覆盖真实分布的 validation/test set。
- 用 active learning 把人工标注花在最有信息量的样本上。
- 再考虑 weak supervision、semi-supervised learning 和合成数据。
测试集不能全部被主动学习或伪标签过程污染,否则无法知道是否真正提升。
Transfer Learning
- 冻结大部分 backbone,只训练 linear head。
- 逐步 unfreeze。
- 使用 PEFT,例如 LoRA、adapter、prompt tuning。
- 从相近领域 checkpoint 开始。
Self-Supervised / Semi-Supervised
- 在无标注领域数据上继续预训练。
- Pseudo-labeling:用教师模型标注高置信样本。
- Consistency regularization:扰动前后预测保持一致。
- Teacher-student / self-training。
伪标签错误会被放大,应使用置信度、类别平衡、人工抽检和迭代更新。
Active Learning
选择:
- 不确定性高的样本。
- 彼此多样且覆盖新区域的样本。
- 模型之间分歧大的样本。
- 业务风险高的样本。
仅采最不确定样本可能集中在噪声和异常点,通常要把 uncertainty 与 diversity、业务价值结合。
Weak Supervision 与数据增强
- 规则、词典、远程监督和多个 noisy labeling functions。
- 图像增强、文本改写、回译、mixup 等。
- 强模型生成样本,再由规则、执行器或人工验证。
合成数据不能替代真实数据分布。要检查重复、模式单一、标签泄漏和 teacher bias。
Few-Shot 场景的评估
- 多个随机 seed 和数据切分。
- 报告均值、方差和置信区间。
- 与简单 baseline 比较。
- 做 learning curve,判断收益来自方法还是增加标注量。
6. 上线前发现重要特征缺失,但暂时不能重训怎么办?
第一步:确认缺失性质
- 是单次请求缺失,还是该特征永久无法在线获取?
- 训练时该特征是否出现过 missing value?
- 缺失是随机的,还是与用户/标签相关?
- 是否能从 feature store、缓存或上游系统可靠回填?
可选方案
按可靠程度排序:
- 恢复或回填特征:修复在线计算、使用最后有效值,但要限制 TTL。
- 延迟或拒绝预测:高风险业务中等待特征,比错误自动决策更安全。
- 使用预先验证的 fallback model:该模型不依赖缺失特征。
- 使用训练时定义的 missing/default 表示:前提是模型见过这种值并经过评估。
- 规则或人工 fallback:降低覆盖率,保住安全和业务底线。
- 临时调整阈值/校准:必须基于模拟缺失特征的离线 replay 验证。
不能直接做什么?
- 不能随意填 0。0 可能是有业务含义的合法值。
- 不能只用总体均值填充后直接上线,除非训练和评估时使用相同策略。
- 不能假装重要特征永久缺失也无需重训。若缺失是长期状态,临时方案只能争取时间,最终应重新训练并验证。
例子:过去 7 天消费金额 = 0 和 特征没拿到 含义完全不同。随便填 0 会让模型误以为用户真的没消费。
上线前验证
在离线测试流量中强制 mask 该特征,重放完整 serving pipeline,比较:
- 主指标和重要切片。
- 预测分布、校准和阈值通过率。
- Safety / business guardrail。
- Missing rate 增长时的 degradation curve。
未来可在训练时加入 feature dropout、missingness indicator,并长期维护不依赖高风险特征的 fallback model。
7. 上线后的模型监控
上线后不能只看服务是否 200,还要监控三层:
数据层
- Schema、类型、取值范围。
- Missing rate、默认值率、唯一值数量。
- 特征分布、类别分布、数据延迟。
- 训练/线上 feature parity。
模型层
- 预测分布、平均分、正例率、entropy。
- Calibration、AUC、PR-AUC、F1 等延迟标签指标。
- 重要切片表现,例如地区、设备、用户类型。
系统/业务层
- 延迟、吞吐、错误率、fallback 率。
- CTR、转化、留存、投诉、人工审核量等业务指标。
- Guardrail 指标,例如安全、合规、公平性、成本。
面试一句话:
生产监控要同时看 data quality、model behavior、business impact;没有标签时先看输入和预测分布,有标签后再看真实性能。
追问:没有线上 label 时,怎么判断模型是不是坏了?
先看 proxy 和无标签信号:
- 输入分布、missing rate、schema 是否异常。
- 预测分布、平均分、positive rate 是否漂移。
- 用户行为 proxy,例如点击、停留、跳出、投诉。
- fallback 率、延迟、错误率是否异常。
- 重要切片是否变化。
等延迟标签回来后,再确认真实 AUC、PR-AUC、校准和业务指标。
8. A/B Testing in ML
A/B test 用真实线上流量比较两个策略,而不是只看离线测试集。
基本流程:
- 定义主指标和 guardrail 指标。
- 随机分流,确保用户不会在 A/B 间频繁切换。
- 预估样本量和实验时长。
- 监控数据质量、延迟、错误率和业务指标。
- 达到统计和业务显著后再扩大流量。
常见坑:
- 提前偷看结果并反复停止实验。
- 分流单位错了,例如同一用户同时进 A/B。
- 新模型改变曝光后,标签分布也随之改变。
- 只看平均值,不看关键切片和负反馈。
追问:A/B test 指标涨了,但投诉也涨了怎么办?
不能只看主指标。要看 guardrail:
- 投诉率、隐藏/拉黑/取消关注。
- 延迟和错误率。
- 长期留存。
- 内容多样性、公平性、安全指标。
如果主指标提升来自短期刺激但损害长期体验,应降流量或回滚。
9. Cold Start
Cold start 指新用户、新物品或新场景缺少历史数据。
新用户
- 用注册信息、地理位置、入口来源等上下文特征。
- 先推荐热门、多样化或探索型内容。
- 通过少量 onboarding 问题获取偏好。
新物品
- 使用内容特征,例如文本、图片、类目、价格。
- 让新物品获得一定探索流量。
- 用相似物品的 embedding 或规则冷启动。
新场景
- 使用迁移学习、相近市场数据、人工规则 baseline。
- 从小流量 shadow/canary 开始收集反馈。
核心权衡:探索能收集数据,但可能牺牲短期体验;利用历史热门更安全,但会压制新内容。
追问:Cold Start 怎么评估?
不要只看整体 CTR。要单独看新用户/新物品切片:
- 新用户首日/首周留存。
- 首次正反馈时间。
- 新物品曝光覆盖率。
- 探索流量带来的长期收益。
- 负反馈率。
整体指标可能被老用户老物品掩盖。
10. Feature Store
Feature store 是统一管理特征定义、计算、存储和服务的系统。
它解决的问题:
- 训练和线上特征不一致。
- 多个团队重复写同一特征。
- 特征版本、血缘、TTL、权限难管理。
- 离线 batch 特征和在线 real-time 特征难对齐。
关键能力:
- Offline store:训练、回放、批量特征。
- Online store:低延迟 serving。
- Point-in-time correctness:训练样本只能拿当时可见的历史特征。
- Feature versioning 和 schema validation。
面试一句话:
Feature store 的核心价值不是“存特征”,而是保证训练和线上用的是同一套、同一时间语义的特征。
追问:Feature Store 和普通数据库有什么区别?
普通数据库只管存取数据。Feature store 还要管:
- 特征定义和版本。
- 离线训练与在线 serving 一致。
- point-in-time correctness。
- TTL、freshness、血缘、权限。
核心不是“存一张表”,而是避免 training-serving skew。
追问:Point-in-time correctness 举个例子
预测用户今天是否会流失时,不能使用“未来 7 天是否活跃”这种未来信息。训练样本在某个时间点 \(t\),所有特征都必须只来自 \(t\) 之前。
常见错误:用全量历史聚合特征,导致训练时偷偷看到未来。
11. 为什么时间序列不能用普通 K-Fold?
普通 K-fold 会随机打乱数据,容易让未来信息泄漏到训练中。时间序列应使用按时间前滚的验证方式:
Train: [过去] Val: [未来一段]
Train: [更长过去] Val: [再未来一段]
注意:
- 所有 rolling/window 特征只能用预测时间之前的数据。
- 标准化、填补、特征选择也要按训练窗口 fit。
- 如果同一用户/设备有强相关性,还要结合 group split。
追问:Time-series validation 最常见的坑是什么?
把未来信息带进训练:
- 随机 K-fold。
- 标准化用全量数据 fit。
- rolling 特征用了未来窗口。
- target encoding 用了未来 label。
时间序列要按时间切,所有 preprocessing 也只能看训练窗口。
12. Bias / Fairness 如何检测和缓解?
先定义敏感或重要分组,例如性别、年龄、地区、语言、设备、收入段。然后按组检查:
- 数据覆盖率和标签质量。
- Accuracy、FPR、FNR、Precision、Recall。
- Calibration。
- 通过率、拒绝率、排序曝光率。
常见公平性指标:
- Demographic parity:不同组的正向决策率接近。
- Equal opportunity:不同组的 TPR 接近。
- Equalized odds:不同组的 TPR 和 FPR 都接近。
缓解方法:
- 补充低覆盖组数据,改善标注质量。
- 调整采样、重加权或阈值。
- 删除或约束明显不合规特征,但要注意 proxy feature。
- 上线后持续按组监控。
公平性没有唯一答案,必须结合业务、法律和错误代价说明取舍。
追问:Fairness 指标冲突怎么办?
不同公平性定义可能无法同时满足。例如 demographic parity 要求不同组通过率接近,equalized odds 要求错误率接近。实际要根据业务和法律风险选择主约束,并报告 trade-off。