跳转至

EvoSpeech · 可迁移运行环境与云端训练规范

冻结日期:2026-07-20

机器合同:configs/runtime_profiles_v1.json

本规范回答两个问题:

  1. 现在有了 Docker,哪些研究应该容器化,哪些不应该假装能容器化?
  2. 本地是 Apple Silicon,未来怎样把原创模型从小实验安全地迁到云端 NVIDIA GPU?

一、裁决

Docker 是默认的 Linux 执行封装,不是整个科研项目的唯一运行环境。

项目以后采用“一个实验合同、多个运行 profile”:研究问题、数据/模型身份、命令、随机种子、 输出与验收规则只定义一次;Apple 原生、Linux CPU 和 Linux/CUDA 分别实现它。正式结果绑定 镜像 digest 或有证据的 native exception,不能只写“在我的环境能跑”。

这意味着:

  • Linux 兼容的评测、官方 metric、训练和 fresh replay 默认进 Docker;
  • macOS 保留为研究控制台、听测端、Apple 部署验证端和小型 CPU/MPS 实验端;
  • 云端 NVIDIA 是正式神经网络训练和 CUDA-only SOTA 的执行端;
  • CoreML/Metal、麦克风/真机、商业 codec SDK、某些本机构建走显式 native exception;
  • 数据、checkpoint、私有音频和 secret 不烤进镜像。

二、为什么不能只做一个万能镜像

不同模型已经证明会要求互相冲突的 PyTorch、Transformers、系统库和编译器。一个不断加包的 evospeech:latest 会产生三个问题:旧模型被新依赖悄悄破坏、镜像越来越不可审计、任何结果 都无法指出到底用了哪套运行时。

正确层次是:

OS / system base
└── project CPU 或 CUDA runtime
    └── model-family overlay
        └── exact metric-tool overlay(仅依赖冲突时独立)

每个正式镜像只解决一类可说明的问题。EnCodec 可以有 inference/evaluation overlay;ViSQOL 这种旧 Bazel 工具可以有独立 metric image;未来原创模型有 train image。它们通过文件合同交换 WAV、payload、checkpoint 和结构化结果,不要求安装在同一个进程里。

三、五个 runtime profile

Profile 用途 可以证明 不能证明
macos_arm64_native_control 编排、论文/代码审计、听测、小型 CPU/MPS smoke、Apple 部署 本机原生行为与 Apple 条件结果 Linux/CUDA 等价、大规模训练吞吐
linux_arm64_cpu_eval 当前 Mac Docker 的默认 portable eval、metric、fresh replay Linux/arm64 CPU 可复现 amd64/CUDA 等价
linux_amd64_cpu_eval 论文常见 Linux/x86 CPU、云前置验证 Linux/amd64 CPU 可复现 Apple 或 GPU 等价
linux_amd64_cuda_train CUDA-only 模型、单/多 GPU 训练与搜索 固定 NVIDIA 条件下的训练结果 端侧实时性、独立评测通过
documented_native_exception Metal/CoreML、商业 SDK、真机、特殊 toolchain 明示主机条件下的事实 未实际重放的平台

Apple Silicon 不是“不能训练”

PyTorch 的 MPS backend 明确支持在 macOS GPU 上训练和推理;它非常适合:

  • 检查 forward/backward 能否闭环;
  • 一小批 overfit;
  • 小模型、短消融和 loss/shape 调试;
  • 在租 GPU 之前发现数据、梯度、checkpoint 和恢复 bug。

但它不是本项目的 canonical 大训练环境:CUDA/FlashAttention/Triton/NCCL 生态、显存模型、 多 GPU 通信、论文官方 kernel 和云端硬件都不同。某些 op 可能不支持 MPS;正式实验禁止用未记录 的 CPU fallback 掩盖这种差异。PyTorch 官方 MPS 文档 说明 MPS 可用于 GPU 训练。

Docker 不是虚拟化 CUDA

Docker Desktop 在 Mac 上运行的是 Linux VM;它不会把 Apple GPU 变成 NVIDIA CUDA GPU。 Docker 当前官方 Desktop GPU 文档把 GPU passthrough 限定在 Windows WSL2,因此本机 Linux container 按 CPU 环境使用。需要 MPS 的实验在 macOS 原生 profile 运行;需要 CUDA 的实验迁往 Linux/NVIDIA 主机。Docker Desktop GPU 边界 必须作为正式结果的解释前提。

四、项目执行拓扑

flowchart LR A["Git: source / config / protocol"] --> C["Experiment capsule"] B["Object storage: data / checkpoints"] --> C C --> M["macOS arm64<br/>control + MPS smoke"] C --> E["Linux CPU containers<br/>formal evaluation"] C --> G["Linux NVIDIA container<br/>training"] G --> O["checkpoint + samples + logs"] O --> E E --> R["signed result manifest<br/>JSON / JSONL / report"] R --> W["Research docs / Cloudflare Pages"]

最重要的单向边界是:训练主机不兼任最终裁判。训练主机可以输出训练 loss 和诊断指标, 但模型晋级必须把 checkpoint/样本交回冻结 evaluation profile,使用同一套未被训练代码修改的 评估器重新裁决。

五、Experiment Capsule:真正可迁移的单位

镜像只是软件;一次实验还需要完整输入与输出身份。每个正式训练/评测生成一个 capsule,至少记录:

  • experiment_id、研究问题、git commit,以及工作树是否干净或对应 patch;
  • runtime profile 与 image digest;native exception 则记录主机/toolchain;
  • 完整 entrypoint 和参数,不能只有一段 shell history;
  • 模型源码 commit,checkpoint URL/revision/bytes/SHA-256;
  • 数据 manifest revision/SHA-256、协议 ID/SHA-256、随机种子;
  • GPU/CPU/内存/拓扑和 Python/PyTorch/CUDA/cuDNN/NCCL inventory;
  • 输入 mount、预期输出、结果 manifest/hash、成本、wall time 和 verdict。

可迁移性测试不是“容器能启动”,而是另一台机器拿 capsule 后可以:

  1. 拿到同一输入;
  2. 用同一镜像 digest 启动;
  3. 完成同一命令或从 checkpoint 恢复;
  4. 验证所有输出 hash 与 schema;
  5. 知道哪些数值允许因硬件不同而漂移。

六、固定目录与 mount 合同

所有容器以后使用同一逻辑路径:

容器路径 读写 语义
/workspace 正式运行只读 固定 commit 的源码与配置
/datasets 只读 manifest 选择且逐文件/分片校验的数据
/checkpoints 按 job 声明 导入 checkpoint 只读;训练输出写临时目录后原子发布
/artifacts 日志、metric、样本、profile 和结果 manifest
/cache 写、可丢弃 pip/HF/编译 cache,不能是唯一证据
/secrets 只读、可选 运行时 secret;不得进入镜像、日志或结果

大数据不进入 Git,也不复制进 Docker layer。Git 保存 manifest 和摘要;内容寻址对象存储保存 dataset shard、checkpoint 与大结果;云主机的本地 NVMe 只是 cache。

七、镜像与架构策略

1. CPU evaluation image

CPU 基础镜像优先发布 linux/arm64linux/amd64 两个 variant。Docker 的 multi-platform manifest 可以让同一个 tag 在不同机器选择正确架构;正式 capsule 仍记录最终选中的 digest。 Docker multi-platform 官方文档同时提醒: QEMU 对编译、压缩等重任务会很慢,所以 Mac 可做 amd64 smoke,正式重计算用 native amd64 runner。

2. CUDA training image

CUDA image 初期只承诺 linux/amd64

  • 固定 CUDA/PyTorch base digest;
  • 安装训练 lock 与固定源码;
  • 不下载训练数据或权重到 image layer;
  • build 阶段不要求 GPU,run 阶段要求 NVIDIA Container Toolkit;
  • 入口先执行 hardware/software preflight,再允许训练。

远端最小验证形式是:

docker run --rm --gpus all <cuda-image@sha256:...> nvidia-smi
docker run --rm --gpus all <cuda-image@sha256:...> \
  python -m scripts.runtime_probe --expect cuda

NVIDIA 官方容器工具使用 --gpus all 暴露 GPU;正式 job 还要记录 GPU UUID,而不是只写“A100”。 参考 NVIDIA Container Toolkit user guide

3. model overlay

每个模型不必复制整个基础镜像逻辑,只增加自己的:

  • 固定依赖 lock;
  • 固定 upstream commit/checkpoint 下载校验;
  • adapter/entrypoint;
  • smoke 与 healthcheck;
  • 许可证/再分发边界。

官方依赖冲突严重的 metric 或模型保留独立 image,通过文件交换。不能为了“一个容器”而修改 官方代码路径,进而破坏 paper-native reproduction。

八、云端训练六道 Gate

C0 · Capsule lint(本地,无 GPU)

配置 schema、数据/模型 hash、输出路径、随机种子、成本上限、checkpoint 间隔与恢复命令全部 可解析。先失败在本地,不花 GPU 钱发现 YAML 拼错。

C1 · Container GPU probe(远端,数分钟)

nvidia-smi 与容器看到相同 GPU;torch.cuda.is_available() 为真;记录 driver/CUDA/cuDNN; 固定 tensor smoke 成功。任何 CUDA extension 在此构建/加载,失败不得进入训练。

C2 · One-batch overfit(远端,短)

一个极小 batch 能让 loss 明显下降;保存 model、optimizer、scheduler、scaler、RNG 和 sampler 状态;停止后恢复,下一步结果在声明容差内一致。这一步比“跑通一个 epoch”更早发现训练图和 resume 假象。

C3 · Short single-GPU run(有硬预算)

验证吞吐、显存、数据加载、metric、样本导出、checkpoint 原子上传、抢占/中断恢复和成本模型。 先测每 step 秒数,再决定完整预算。

C4 · Multi-GPU or long run

只有 C0–C3 通过才启动。记录 DDP/NCCL、GPU 拓扑、global/effective batch、gradient accumulation、精度、扩展效率和通信占比。多 GPU 不是把单卡命令机械乘 N。

C5 · Independent evaluation

训练产物回到冻结 CPU/evaluation image;检查 checkpoint hash、生成样本、真实 payload、共同 benchmark 和 stress。只有这个裁判结果能进入模型 D5/D6 与 Pareto 表。

九、从本地到云端的标准流水线

本地 CPU/MPS lint + one-batch smoke
→ build linux/amd64 CUDA image
→ push immutable digest to registry
→ cloud bootstrap installs Docker + NVIDIA Container Toolkit only
→ pull digest + fetch hashed dataset/checkpoint
→ C1/C2/C3
→ approved full run / C4
→ atomic checkpoint and artifact sync
→ destroy instance
→ frozen evaluation container / C5

初期不引入 Kubernetes。单人项目先用“一台临时 GPU 主机 + Docker + 对象存储 + 一个 provider adapter”最透明。只有出现并行多节点排队、共享配额和大量自动搜索后,再考虑 Slurm、Kubernetes 或托管训练服务。

云厂商不可写进训练逻辑

训练命令只依赖标准 mount、环境变量和 capsule。云适配层只负责:

  • 创建/销毁机器;
  • 安装或验证 Docker/NVIDIA runtime;
  • 注入 secret;
  • 挂盘/同步对象;
  • 启动容器、采集退出码和成本。

这样可以在任意提供合适 NVIDIA GPU 的平台之间切换,而不改模型代码。选择平台时按所需显存、 GPU 架构、互联、可用区、抢占风险、存储吞吐和总成本裁决,不按“每小时单价”单一排序。

十、checkpoint、抢占与成本纪律

  • 第一次昂贵 run 前必须做真实 resume drill;“代码里有 save()”不算验证;
  • checkpoint 先写临时名,完成后原子 rename/上传,再更新 latest 指针;
  • 至少保存 model、optimizer、scheduler、AMP scaler、step/epoch、RNG、sampler 与 config hash;
  • 云盘/NVMe 不能是唯一副本;关键 checkpoint 同步到持久对象存储;
  • job 有 wall-time、GPU-hour 和货币 hard cap,达到上限安全 checkpoint 后退出;
  • 每次 run 记录有效训练秒数、数据等待、checkpoint 开销和失败成本;
  • 训练完成后自动销毁实例是云 adapter 的验收项,不依赖人记得关机。

十一、什么必须容器化,什么可以例外

默认必须容器化

  • Linux 可运行的 D4 paper-native metrics;
  • D5/D6 共同 benchmark 的评估器与 ASR/speaker evaluator;
  • CUDA-only SOTA reproduction;
  • 原创模型训练与搜索;
  • 能改变结论的格式转换、metric 和结果生成工具。

允许 native exception

  • Apple MPS/CoreML/Metal 专属实验;
  • Opus/Codec 2 等系统安装,但要固定二进制/动态库版本与 hash;
  • 麦克风、扬声器、真机网络和人工听测;
  • 许可证不允许封装/再分发的 SDK;
  • upstream toolchain 在容器里会改变所研究机制的情况。

例外不是降级。它必须记录为何容器不忠实、主机身份、命令、日志、可重放程度和禁止外推的结论。

十二、与 D0–D7 的关系

  • D0 固定官方环境、项目 runtime profile、架构和许可证边界;
  • D2 记录 adapter 是否依赖 host/CUDA/MPS,以及容器是否改了官方调用链;
  • D3 在见结果前固定 image/exception、mount、硬件条件和环境漂移容差;
  • D4 保存 image digest、逐样本结果与完整 inventory;
  • D5/D6 的统一 benchmark 必须由冻结 evaluation image 或明示例外产生;
  • D7 至少从 clean container/fresh process 重放关键点;高价值结论再跨第二台主机重放。

Docker 解决依赖封装,不自动解决随机性、驱动差异、数据身份、秘密泄漏或科学协议。它是证据链 的一层,不是“用了 Docker,所以可复现”的免责章。

十三、实施顺序

现在,作为 EnCodec D4 的一部分

  1. 建立固定 ViSQOL v3.3.3 metric image;
  2. 建立最小 linux_arm64_cpu_eval image/命令合同;
  3. 让 D4 result 记录 image ID/digest 与宿主 Docker inventory;
  4. 保留当前 macOS native smoke,只把它标为诊断,不与 container formal result 混合。

EnCodec D7 前

  1. 提交 docker/ 层次、构建脚本和 runtime probe;
  2. 在 arm64 clean container 重放关键评测;
  3. 至少对一个 CPU 点做 native vs container 数值差异审计;
  4. 把 exception schema 接入 registry 校验。

第一个原创模型训练前

  1. 建立固定 linux_amd64_cuda_train image;
  2. 选一个临时 NVIDIA 主机完成 C0–C3
  3. 验证对象存储 checkpoint 上传、下载和 resume;
  4. checkpoint 回到 evaluation image 完成 C5
  5. 只有这条小闭环通过,才扩大训练时间或 GPU 数。

十四、最终原则

本地负责思考、编排、快速证伪和独立验收;Docker 负责封装 Linux 执行身份;云端 GPU 负责规模化训练;Experiment Capsule 负责让三者仍是同一个实验。