EvoSpeech · 可迁移运行环境与云端训练规范¶
冻结日期:2026-07-20
机器合同:configs/runtime_profiles_v1.json
本规范回答两个问题:
- 现在有了 Docker,哪些研究应该容器化,哪些不应该假装能容器化?
- 本地是 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 边界 必须作为正式结果的解释前提。
四、项目执行拓扑¶
最重要的单向边界是:训练主机不兼任最终裁判。训练主机可以输出训练 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 后可以:
- 拿到同一输入;
- 用同一镜像 digest 启动;
- 完成同一命令或从 checkpoint 恢复;
- 验证所有输出 hash 与 schema;
- 知道哪些数值允许因硬件不同而漂移。
六、固定目录与 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/arm64 与 linux/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 的一部分¶
- 建立固定 ViSQOL v3.3.3 metric image;
- 建立最小
linux_arm64_cpu_evalimage/命令合同; - 让 D4 result 记录 image ID/digest 与宿主 Docker inventory;
- 保留当前 macOS native smoke,只把它标为诊断,不与 container formal result 混合。
EnCodec D7 前¶
- 提交
docker/层次、构建脚本和 runtime probe; - 在 arm64 clean container 重放关键评测;
- 至少对一个 CPU 点做 native vs container 数值差异审计;
- 把 exception schema 接入 registry 校验。
第一个原创模型训练前¶
- 建立固定
linux_amd64_cuda_trainimage; - 选一个临时 NVIDIA 主机完成
C0–C3; - 验证对象存储 checkpoint 上传、下载和 resume;
- checkpoint 回到 evaluation image 完成
C5; - 只有这条小闭环通过,才扩大训练时间或 GPU 数。
十四、最终原则¶
本地负责思考、编排、快速证伪和独立验收;Docker 负责封装 Linux 执行身份;云端 GPU 负责规模化训练;Experiment Capsule 负责让三者仍是同一个实验。