核心要点

  • 可复现要同时锁定三件事:代码版本、数据版本、环境配置——少一个就复现不出

  • 非确定性来源很多:未 pin 的依赖、系统库(glibc/CUDA driver)、随机种子、GPU 浮点累加顺序

  • 用容器固化镜像 + lockfile(uv/poetry/conda-lock)锁依赖,比「在我机器上能跑」可靠

  • 训练与 serving 环境必须对齐,否则特征计算库版本差异会造成 train/serve skew

简要回答

可复现性定义:固定代码版本 + 数据版本 + 环境配置 → 训练得到可接受的相同指标与模型行为;

主要挑战

  1. 依赖地狱:pip 未锁版本、系统库差异(glibc、CUDA driver)
  2. 隐式状态:未记录的 notebook 单元格顺序、全局随机种子
  3. 硬件差异:不同 GPU 架构、混合精度非确定性(atomicAdd 顺序)
  4. 数据漂移:「同版本」数据实际已变(上游表更新)
  5. 训练-推理 skew:Python 3.9 训练、3.11 推理

标准回答

可复现性定义:固定代码版本 + 数据版本 + 环境配置 → 训练得到可接受的相同指标与模型行为。

主要挑战

  1. 依赖地狱:pip 未锁版本、系统库差异(glibc、CUDA driver)
  2. 隐式状态:未记录的 notebook 单元格顺序、全局随机种子
  3. 硬件差异:不同 GPU 架构、混合精度非确定性(atomicAdd 顺序)
  4. 数据漂移:「同版本」数据实际已变(上游表更新)
  5. 训练-推理 skew:Python 3.9 训练、3.11 推理;特征计算库版本不同

最佳实践

  • 容器化:Docker 镜像 pin 基础镜像 + requirements.lock
  • 依赖锁定:poetry/uv/pip-tools conda-lock
  • 种子管理:Python/NumPy/Torch/CUDA deterministic flags
  • 数据版本DVC / LakeFS 绑定数据 hash
  • 实验记录:环境 snapshot 写入 MLflow metadata

详见 MLOps 入门环境管理

常见误区

⚠️ 常见踩坑

只锁 pip 不锁 CUDA/系统库;忽视特征工程代码版本;不说训练与 serving 环境对齐。

追问

追问 1GPU 训练如何尽量确定性?

固定所有随机种子(Python/NumPy/Torch/CUDA),开启 deterministic 模式(如 torch.use_deterministic_algorithms(True)、cudnn.deterministic=True、关闭 benchmark),并固定 CUBLAS_WORKSPACE_CONFIG。代价是部分算子变慢、个别无确定性实现的算子需替换;完全 bit 级一致往往做不到,目标是结果可接受地一致。

追问 2Notebook 为何破坏可复现?

Notebook 单元格可乱序执行,内核里残留的全局变量与隐式状态不体现在代码顺序中;他人重跑顺序不同结果就变。改进:关键逻辑下沉为可导入的 .py 模块,用脚本/流水线驱动,notebook 只做探索。

追问 3如何验证环境可复现?

在干净环境(全新容器/CI runner)从锁定的镜像与 lockfile 重新构建并重跑训练,对比关键指标是否落在容许误差内;同时校验数据哈希与依赖清单一致。把这步纳入 CI,任何不可复现立即暴露。

延伸学习

与本题相关的知识库文章、术语、工具与行业资讯。

🛠️ AI 工具

  • BentoML

    AI 模型服务化框架,8.6K+ stars。最简化的方式部署 AI 应用和模型,支持模型推理 API、任务队列、LLM 服务等,是模型从实验到生产的桥梁

  • MLflow

    开源 AI 工程平台,26K+ stars。面向 Agent、LLM 和 ML 模型的端到端生命周期管理平台,支持实验追踪、模型注册、部署和监控