跳转至

EnCodec 24 kHz · 可审计模型档案

当前结论:D0–D3 passed;下一步是 D4 · 执行论文原生复现与边界审计。 每个 Gate 只建立该 Gate 明示的证据;特别是 D3 passed 只表示协议已在结果前冻结,不等于 D4 论文结果已复现。

Gate 状态

Gate 状态
D0 passed
D1 passed
D2 passed
D3 passed
D4 not_started
D5 not_started
D6 not_started
D7 not_started

知识、执行、评测、文档四条状态仍然分账:

知识 执行 评测 文档
代码已深读 可运行 协议已冻结 草稿

D0 到底封住了什么

flowchart LR P["arXiv:2210.13438v1"] --> S["official v0.1.1 / f1479a65"] S --> W["24 kHz checkpoint / d7cc33bc"] W --> A["EvoSpeech official-package adapter"] H["Transformers conversion"] -. excluded from selected identity .-> A

选择范围是官方 24 kHz、单声道、因果推理模型,以及它的 encoder、RVQ 和 decoder。 48 kHz stereo、可选 entropy LM、训练判别器和 Transformers 转换都没有混入本次身份。

论文、源码、包与权重

固定身份 Primary source
论文 High Fidelity Neural Audio Compression; arXiv:2210.13438v1; arXiv preprint arXiv
作者 Alexandre Défossez, Jade Copet, Gabriel Synnaeve, Yossi Adi PDF
官方代码 tag v0.1.1 → commit f1479a65a75c0e49e7e5d85bb1418fd57e6a9d62 fixed commit
PyPI encodec==0.1.1; sdist SHA-256 36dde98ccfe6c51a15576476cadfcb3b35a63507b8b8555abd69889a6fba6772 release
Checkpoint encodec_24khz-d7cc33bc.th; 93,171,529 bytes; SHA-256 d7cc33bcf1aad7f2dad9836f36431530744abeace3ca033005e3290ed4fa47bf official artifact
Alternate Transformers revision c1dbe2ae3f1de713481a3b3e7c47f357092ee040,未纳入本次身份 model card

许可证已纠错

固定的 v0.1.1 源码与 PyPI 0.1.1 都是 CC-BY-NC-4.0, 不是旧清单所写的 MIT。checkpoint 没有找到独立许可文件,因此这里保守沿用固定 release 的 CC-BY-NC-4.0 通知;这不构成商业使用授权或法律意见。

三个关键已安装源码文件的 SHA-256 与固定 commit 原文逐字节一致;但环境没有保存 direct_url.json,因此只声明关键执行路径等价,不虚构整个安装分发包的来源证明。

推理与表示合同

字段 固定值
变体 encodec_24khz
输入 24,000 Hz / 1 channel
因果 true;由固定 factory 的 causal=True 建立
Normalization / segment false / None
Hop / frame rate 320 samples / 75 frames/s
RVQ 最多 32 级;每码本 1024 项 = 10 bit/code
官方离散带宽 1.5, 3.0, 6.0, 12.0, 24.0 kbps
Scale side information 所选 24 kHz 非归一化模型在全部已观测官方带宽下均为 None

带宽到 RVQ 深度:本机确定性探针

测量时间:2026-07-20T03:44:35.651739+00:00;运行时:Python 3.12.2 / EnCodec 0.1.1 / Torch 2.13.0 / CPU。 探针是一秒全零输入,只验证 shape 和 raw-code 码率,不是质量样本。

官方带宽 Active RVQ Codes [B,K,T] raw codes-only bits / 1 s
1.5 kbps 2 1×2×75 1,500
3 kbps 4 1×4×75 3,000
6 kbps 8 1×8×75 6,000
12 kbps 16 1×16×75 12,000
24 kbps 32 1×32×75 24,000

参数量为什么有两个正确答案

模块 nn.Parameter elements 完整 state elements state storage
encoder 7,425,792 7,425,792 28.33 MiB
quantizer 0 8,421,408 32.13 MiB
decoder 7,426,018 7,426,018 28.33 MiB
total 14,851,810 23,273,218 88.78 MiB

常见的“约 14.85M 参数”只计算 nn.Parameter,对应 56.66 MiB 的 float32 parameter storage。完整 inference state 是 88.78 MiB:RVQ 的 8,421,408 个 codebook/EMA 元素 被实现为 registered buffers,普通 parameter counter 会漏掉它们。这不是测量冲突,而是分母不同。 可选 entropy LM 和训练判别器均未包含在这两个数字中。

三种“bitstream”必须分开

  1. 官方 model.encode:由 (codes, scale) 组成的 frame 列表;codes shape 为 [batch, active RVQ stages, time]。
  2. 官方 CLI:.ecdc;可选用独立 language model 做 entropy coding。
  3. 本项目 payload:EVSENC01 / evospeech_encodec_10bit_v1 (.evc):确定性打包的 10-bit raw index 加项目 header;它不是官方 .ecdc,也未使用可选 entropy model。

因此 D0 只精确验证 raw-code 映射。D4–D6 必须把项目 payload 的实际字节数、论文 nominal codes-only bandwidth 和官方 entropy-coded 文件大小分开报告。

D0 允许与禁止的结论

已建立:

  • 论文、release tag、固定 commit、package、checkpoint 与所选变体的身份
  • 固定 revision 的许可证证据
  • checkpoint 精确大小与 SHA-256
  • 本机关键执行源码与固定 commit 的逐字节等价
  • parameter 与完整 checkpoint state 的分账
  • 一秒探针上的官方带宽到 RVQ 深度映射
  • 官方表示、官方文件与项目 payload 的边界

仍未建立:

  • 论文机制理解
  • 论文 headline result 复现
  • 音质、可懂度、身份或表达能力
  • 本机实时性能
  • Hugging Face Transformers 转换的等价性
  • 对 EvoSpeech 的适用性或相对其他 codec 的优越性

所以,历史 smoke 和 D0 仍不能被写成“EnCodec 已评测完成”。 D1 已在下文逐章解释论文并建立 claim-to-source ledger;论文结果复现仍要等待 D3/D4。

可复核命令

.venv/bin/python scripts/measure_encodec_identity.py --check
python3 scripts/validate_research_registry.py
python3 scripts/generate_research_docs.py --check
.docs-venv/bin/python -m mkdocs build --strict

机器记录:research/models/encodec/measurements/local_identity.json;measurement scope 是 identity_only_not_quality_evaluation。当前 checkpoint 的完整 state 与文件分别是 88.78 MiB 与 88.86 MiB; 容器/序列化开销不被误称为模型参数。

D1 · 论文深读:EnCodec 真正做了什么

D1 结论:passed。 这里的“读懂”表示论文的机制、实验协议、主要数字和边界均已定位到 arXiv:2210.13438v1 的页、节、图、公式或表;不表示论文结果已经在本地复现。 结构化 claim ledger 是 research/models/encodec/paper_claims.json,其中明确区分 paper_claimpaper_methodreader_inference

一句话心智模型

EnCodec 不是“把音频变成一个神奇 token”的黑盒。它先用因果卷积与 LSTM 把波形降采样成 75 帧/秒的连续 latent,再用多级 residual vector quantization(RVQ)逐层编码剩余误差,最后 由镜像 decoder 还原波形。带宽不是连续旋钮,而是保留多少级 RVQ;可选 Transformer 只负责 预测离散码的概率并做算术编码,不改变 decoder 所需的离散符号。[ENC-P-003–ENC-P-013]

flowchart LR X["24 kHz mono waveform"] --> E["causal SEANet-like encoder<br/>stride 2×4×5×8"] E --> Z["continuous latent<br/>75 frames/s"] Z --> Q["RVQ<br/>2/4/8/16/32 stages"] Q --> C["1024-way indices<br/>10 bits/index"] C --> D["mirror decoder"] D --> Y["reconstructed waveform"] C -. "optional probability model" .-> LM["causal Transformer + arithmetic coding"]

这张图也揭示了三个必须分开的对象:论文 nominal RVQ bits、可选 LM 压缩后的 entropy-coded bits、以及包含 header/长度/scale/packet 等信息的完整传输 payload。它们不能共用一个“码率”。 [ENC-I-004]

它继承了什么,又真正改了什么

最接近的前身是 SoundStream:端到端 encoder/decoder、RVQ、 对抗与重建联合训练,以及通过结构化 quantizer dropout 让一个模型覆盖多个码率,都不是 EnCodec 首次提出。EnCodec 论文自己的贡献更接近一组互相咬合的系统改进:[ENC-I-001]

  1. 把 SEANet 风格的卷积 encoder/decoder 做成清晰的 streaming 与 non-streaming 两套边界;
  2. 用一个 multi-scale STFT discriminator 取代更复杂的判别器组合;
  3. 用 loss balancer 让损失系数近似表示“各自应占多少梯度”,缓解不同损失量纲的调参问题;
  4. 在离散码之后增加小型因果 Transformer,以 entropy coding 再节省约 25%–40% 的表示带宽;
  5. 把 24 kHz mono general audio 扩到 48 kHz stereo music,并报告跨 speech/noisy speech/music 的主观评测。

因此,最值得学习的不是“RVQ 等于 EnCodec”,而是它怎样把表示、流式边界、训练稳定性、 主观音质和真实编码放进同一个系统。反过来,也不能把这些组合实验升级成宇宙定律:论文的 消融来自特定数据与训练运行,相关 checkpoint 并未全部公开。[ENC-I-006]

Encoder、decoder 与流式边界

24 kHz encoder 的主干是:kernel-7 Conv1D → 四个 residual/downsampling block → 两层 LSTM → 最终 Conv1D。四个 stride 为 2、4、5、8,总 hop 为 320 samples,所以 24,000 / 320 = 75 latent frames/s;decoder 镜像执行。基础通道数为 32,每次降采样后翻倍,非线性为 ELU。 [ENC-P-004, ENC-P-005]

Streaming 版本使用 left padding 的 causal convolution,并缓存转置卷积尚未输出的未来片段。 论文将架构初始延迟写为 320 samples,即 24 kHz 下约 13 ms。Non-streaming 版本则用 symmetric padding、1 秒 chunk、10 ms overlap 和 per-chunk normalization,并把 normalization scale 当 side information 传输。[ENC-P-006, ENC-P-007]

这一区别很重要:本项目 D0 选中的官方 24 kHz checkpoint 是 causal、normalize=Falsesegment=None 的推理对象,不能把论文 non-streaming 的 scale side information 偷渡进来, 也不能用“模型 13 ms”替代端到端文件、缓冲、声卡与网络延迟。D2 会逐调用确认 padding、句尾与 实际 tensor shape;D4 只会把同平台测量与论文 MacBook Pro 2019 单线程数字作条件化比较。

RVQ:为什么一个 checkpoint 能有五档带宽

RVQ 的第一级量化完整 latent,后续每一级只量化“上一轮仍未解释的残差”。若使用更多级, decoder 得到更多修正信息,nominal rate 也线性增加。每个 codebook 有 1024 个 entry,故每个 index 是 log2(1024) = 10 bit;24 kHz 模型每秒 75 帧,所以每级贡献 750 bit/s:[ENC-P-008–ENC-P-010]

R_nominal = frame_rate × active_codebooks × bits_per_index
          = 75 × Nq × log₂(1024)
          = 75 × Nq × 10 bit/s

因此 Nq = 2/4/8/16/32 对应 1.5/3/6/12/24 kbps。这不是从论文数字倒推的猜测:D0 已用 本机 checkpoint 的一秒 probe 精确观测到相同映射。但 D0 只验证表示身份;“更多 RVQ 一定在 任何维度都更好”并没有因此成立。

训练时,论文不是只训练 32 级后随便截断,而是每个 batch 随机选择一档 RVQ depth,使共享的 encoder/decoder 学会多带宽工作。codebook 由 EMA(decay 0.99)更新,dead code 会被替换, encoder 通过 straight-through estimator 与 commitment loss 得到梯度。[ENC-P-008, ENC-P-009, ENC-P-018]

Optional LM:压表示,不是“提升声学重建”

论文的 entropy model 是 5 层、8 heads、width 200、FFN 800 的 causal Transformer,感受野约 3.5 秒。它在每个时刻并行预测所有 codebook 的条件概率,再用 arithmetic coding 缩短文件。 论文特别固定了概率 rounding 与 24-bit arithmetic range,原因是 encoder 和 decoder 只要浮点 概率有微小分歧,整个码流就可能从该点开始不可解。[ENC-P-011, ENC-P-013]

Table 1 报告 nominal 3 kbps 可压到平均 1.9 kbps,全文总结为约 25%–40% 节省;但这是额外 checkpoint、额外计算和额外初始缓存换来的。它没有增加传给声学 decoder 的信息,因此不能把 entropy saving 写成音质提升。[ENC-P-012]

训练目标:五种压力如何同时作用

EnCodec 的 generator 不是只优化 sample MSE。论文把以下损失合起来:[ENC-P-014–ENC-P-019]

  • waveform L1:约束时域样本;
  • multi-scale mel L1/L2:在 7 个时间频率尺度约束听觉谱结构;
  • adversarial hinge loss:让重建在判别器看来像真实音频;
  • feature matching:对齐真实与重建经过判别器时的中间激活;
  • RVQ commitment:阻止 encoder latent 无限制逃离当前 codebook 表示。

判别器直接看 complex STFT 的 real/imaginary channels,使用 FFT 2048、1024、512、256、128 五个 尺度。多带宽训练每个 batch 只抽一档 bandwidth,并为每档使用独立 discriminator。

Loss balancer 是论文最有方法学价值的部分之一。普通加权和里,λ=1 对两个量纲完全不同的 loss 并不代表同等影响;balancer 先测每个 loss 对 generator 输出的 gradient norm,再用慢速 EMA 归一化,使 λ 更接近目标 gradient fraction。附录 Table A.4 显示,极端 adversarial 权重下, 不平衡版本出现负 SI-SNR,而 balancer 多数仍在稳定区间。[ENC-P-019, ENC-P-034]

这仍只是作者训练矩阵里的支持证据。D2 要确认公开源码到底如何 stop-gradient、EMA 与 rescale; 没有对应训练 run 与 checkpoint 时,D4 不能声称复现了这项因果消融。

数据与训练:规模大,但并非完整可重建配方

24 kHz mono 训练覆盖 Common Voice 7.0、DNS Challenge 4、AudioSet、FSD50K 与 Jamendo,域包括 clean/noisy speech、music 与 general audio。附录报告约 9,096 h Common Voice、1,998 h DNS、 4,989 h AudioSet、108 h FSD50K、919 h Jamendo;不同数据集/样本的许可证并不统一。 [ENC-P-020]

训练会随机单独取 music、单独取其他 source、混两源或混三源,概率分别为 0.32、0.32、0.24、 0.12;另有 -10 到 +6 dB gain 与可选 reverb。主模型训练为 300 epochs × 2,000 updates,batch 64 个一秒样本,Adam lr=3e-4, β1=0.5, β2=0.9,作者使用 8 张 A100。[ENC-P-021, ENC-P-022]

“列出数据集名称”不等于配方可完全重建:AudioSet/FSD50K 的采样选择、Common Voice 实际语言 组成、exact test clips、原始素材可用性与 proprietary music 都形成缺口。论文也没有报告中文或 逐语言结果,所以 Common Voice 出现在训练表里不能被翻译成“多语言能力已验证”。[ENC-I-002, ENC-I-005]

论文怎样评测

论文主观评测按四类 5 秒片段进行:clean speech、speech + noise、Jamendo music、proprietary music。每类 50 个样本,每个样本至少 10 个 MUSHRA 评分,并用 reference/low-anchor attention checks 排除不可靠标注者。对照包括 Opus、EVS、MP3、Lyra v2,以及作者自行重实现的 SoundStream; 客观指标为 ViSQOL 与 SI-SNR。[ENC-P-023–ENC-P-025]

最关键的作者结果(不是本地结果)

证据 作者报告 D1 解释
Table 1 3 kbps EnCodec:clean/noisy/music1/music2 MUSHRA = 67.0/62.5/89.6/87.8 在作者协议内胜 Lyra 6 kbps 与 Opus 12 kbps;未独立复现 [ENC-P-026]
Table 1 6 kbps EnCodec:83.1/69.4/92.9/91.3 music 接近 hidden reference;noisy speech 差距仍明显 [ENC-P-027]
Table 2 单 MS-STFT:SI-SNR 6.67、ViSQOL 4.35、MUSHRA 77.5 接近 MS-STFT+MPD 的 79.0,支持“更简单即可”,但没有发布每个消融 checkpoint [ENC-P-028]
Table 3 streaming 6 kbps:6.67/4.35;non-streaming:7.46/4.39 客观退化小;不是端到端网络延迟结论 [ENC-P-029]
Table 4 48 kHz stereo 6/12/24 kbps MUSHRA = 82.9/88.0/87.5 均值不单调且 CI 重叠;不能宣称 24 必胜 12 [ENC-P-030]
Table 5 24 kHz raw encode/decode inverse RTF = 9.8/10.4;带 LM = 1.6/1.6 都快于实时,但 LM 显著吃掉余量;平台依赖 [ENC-P-031]
Table A.2 EnCodec RVQ 3 kbps 76.8;DiffQ 72.3;重实现 SoundStream 71.8 是作者重实现体系内比较,不是官方 SoundStream checkpoint 复现 [ENC-P-032]

注意论文把 RTF 定义成“音频时长 / 处理时长”,所以数值越大越快;这与很多代码仓库使用的 “处理时长 / 音频时长”正好相反。后续所有资源表必须显式写公式,不能只写 RTF 三个字母。

论文证明了什么、没证明什么

在论文自己的数据、系统与评测协议内,它给出较强证据说明:多级 RVQ codec 可以用一个 checkpoint 覆盖多档带宽;MS-STFT adversary 能以较简单的组合取得强主观结果;loss balancer 能提高多损失训练稳定性;optional LM 能明显降低离散表示的平均 entropy;streaming 版本能在 可控质量损失下快于实时。

没有建立以下结论:[ENC-I-002–ENC-I-006]

  • 中文、德语、法语、西班牙语、日语、韩语或任何逐语言鲁棒性;
  • 关键实体、数字顺序、否定作用域等语义保真;
  • speaker identity、expression/emotion 的独立保持;
  • packet loss、jitter、bit error、长音频状态漂移或真实移动端网络表现;
  • nominal rate 等于完整 .ecdc、项目 .evc 或网络 payload rate;
  • Table 1 的主观排名能跨听者、语料、实现和 2026 年模型保持;
  • 任何一个消融因素在所有数据与模型上都具有普适因果优势。

尤其要避免把总体 MUSHRA 当成内容合同:一个样本可以“听起来很自然”却把人名、金额或否定词 改错。MUSHRA、ViSQOL、SI-SNR 与内容/身份/表达是相关但不同的观测维度。[ENC-I-003]

D1 形成的 D3/D4 入口

下面只是复现分类的先验,不是尚未冻结的 D3 protocol:

主张族 当前公开性判断 D3 必须查清
checkpoint 结构、hop、RVQ depth、nominal rate 可精确复核 固定入口、shape、文件与容差
optional LM entropy saving 很可能可用官方 artifact 近似或部分复核 LM checkpoint、官方 .ecdc、样本集合与平均方式
公开语料上的 ViSQOL / SI-SNR 近似可复现候选 exact clips/split、metric version、resampling、聚合单位
Table 1 MUSHRA 严格复现受阻 exact stimuli、anchor、界面、原始 votes、听者总体、排除后样本
proprietary music / 48 kHz stereo主表 阻塞候选 数据与刺激是否公开;不能用 Jamendo 偷换
discriminator、LSTM、channels、balancer 消融 阻塞候选 是否存在对应 checkpoint/训练 config;不能用当前单一 checkpoint 冒充
MacBook Pro 2019 RTF 只能平台条件化比较 inverse RTF 公式、线程、warm-up、LM 与 I/O 边界

D1 到这里的价值,是提前告诉 D3 哪些结果能严谨冻结、哪些必须诚实写 blockedapproximate。它没有为了让 D4 好看而发明缺失资产,也没有用项目共同 benchmark 冒充论文 原生复现。

Primary sources

PDF evidence identity: 19 pages, 1,217,926 bytes, SHA-256 f307ade111fdaad081ac8092f4ab7543b9c925192159de5a1816dcf26a5129f7。全部页面已渲染并视觉核验; 文本抽取仅用于检索,不替代版面、表格和公式的人工核对。

D2 · 核心代码深读:从 factory 到真实字节

D2 结论:passed。 本节固定到官方 tag v0.1.1 / commit f1479a65a75c0e49e7e5d85bb1418fd57e6a9d62。11 个关键 upstream source 的本机 SHA-256 均与该 commit 一致;paper-to-code map 位于 research/models/encodec/code_map.json,可重放 shape/bytes trace 位于 research/models/encodec/measurements/code_trace.json。 这仍是机制验证,不是音质 evaluation。

先看真正的调用链

24 kHz 官方入口不是一个泛化模型名,而是很具体的一条路径:

EncodecModel.encodec_model_24khz()
  └─ _get_model(causal=True, weight_norm, normalize=False, segment=None)
       ├─ SEANetEncoder(ratios declared [8,5,4,2], executed [2,4,5,8])
       ├─ ResidualVectorQuantizer(dimension=128, n_q=32, bins=1024)
       └─ SEANetDecoder(ratios [8,5,4,2])

model.set_target_bandwidth(6.0)
model.encode([B,C,T])
  └─ _encode_frame → encoder → quantizer.encode → transpose KBT→BKT
model.decode([(codes_BKT, scale=None)])
  └─ transpose BKT→KBT → quantizer.decode → decoder

关键源码分别是 model.py:L222-L282model.py:L122-L187seanet.py:L91-L238

一个容易误读的细节是 shape 顺序:底层 RVQ 返回 [K,B,T]EncodecModel._encode_frame 转成公开 API 的 [B,K,T];decode 入口再转回去。把任何一个中间 tensor 直接称为“官方 token shape”而不标 API 层级,都会留下轴顺序 bug。

一秒 trace:波形怎样缩成离散码

Trace 使用一个固定的三分量合成波形,不含语音、数据集或质量样本。环境是 macOS arm64、 Python 3.12.2、EnCodec 0.1.1、Torch 2.13.0、CPU 单线程。输入 SHA-256 固定为 4d984992…3013

阶段 实际 shape 时间轴变化
input [1,1,24000] 24,000 samples
initial Conv1D [1,32,24000] 不降采样
stride 2 [1,64,12000] ÷2
stride 4 [1,128,3000] ÷4
stride 5 [1,256,600] ÷5
stride 8 [1,512,75] ÷8
2-layer residual LSTM [1,512,75] 时间长度不变
final Conv1D latent [1,128,75] 128-D × 75 fps
RVQ at 6 kbps internal [8,1,75]; public [1,8,75] 600 indices/s
summed code vectors [1,128,75] 回到连续 latent
decoder [1,1,24000] 8×5×4×2 上采样

Encoder 每档 downsample 之前都有一个 residual block;decoder 每档 upsample 之后有一个。公开 checkpoint 默认 true_skip=False,所以 residual shortcut 是 1×1 convolution,不是纯 identity。 LSTM 也不是普通串联:SLSTM[B,C,T] 转为 [T,B,C],跑两层 LSTM 后再加回输入 residual。

“因果”在源码里到底是什么意思

SConv1d 在 causal 模式把固定 receptive-field padding 放在左侧,只在右侧补齐最后一个 stride window; SConvTranspose1d 则把固定转置卷积 padding 从右边裁掉。

我们做了两个 future counterfactual,而不是只相信构造参数:

  • 把输入 16,000 samples 之后的未来波形改变,前 30 个 encoder frames 的 max abs diff = 0.0
  • 把第 50 帧之后的未来 codes 全部改变,decoder 前 10,000 samples 的 max abs diff = 0.0

这验证的是给定安全前缀内的未来不泄漏,不是完整 streaming 产品 API。上游 model.encode 仍然接收整段 tensor,卷积与 LSTM 没有公开增量 state;compress.py 只对 optional LM 明说 “emulate a streaming scenario”。所以准确表述是:acoustic network 是 causal/streamable architecture,但 v0.1.1 没有提供 chunk-by-chunk acoustic streaming API。

句尾不是无关紧要的实现细节

SConv1d 会为最后一个不完整 hop 增加 right padding。实测 24,001 samples:

input                 24,001 samples
codes                 [1,8,76]
model.decode output   24,320 samples
overshoot                 319 samples
model.forward output  24,001 samples

原因是 decode() 的合同明确允许输出略长,只有 forward() 才用 [:, :, :input_length] 裁回去。 官方 .ecdc header 和项目 .evc header 也保存原长,由 transport decoder 最后裁剪。以后若只用 model.decode() 评测而不裁原长,duration、码率、ASR 对齐和 SI-SNR 都会被句尾 padding 污染。

RVQ 不是“查一次表”,而是八次修残差

6 kbps 的八级路径可写成:

residual₀ = encoder(x)
for q in codebooks[0:8]:
    index_q    = nearest_code(residual_q)
    vector_q   = q[index_q]
    residual₍q+1₎ = residual_q - vector_q
quantized = Σ vector_q

源码证据在 core_vq.py:L315-L363。 合成 probe 的 latent residual RMS 从 5.3788 依次降到 1.0713 → 0.7916 → 0.6757 → 0.5965 → 0.5412 → 0.5018 → 0.4686 → 0.4379;逐级向量求和与 quantizer.decode 的 max abs diff 为 0.0。这说明该样本上每级确实在编码前级残差,但 residual RMS 数字不是音质分数,也不能推出每一级对听觉同等重要。

带宽映射由 vq.py:L86-L107 直接计算:每级 log₂(1024) × 75 / 1000 = 0.75 kbps,再对目标带宽除法取 floor。官方合法点 因此是 2/4/8/16/32 级。set_target_bandwidth 会拒绝非官方点;它不是一个可任意连续扫的 knob。

训练相关的单个 RVQ component 是开放的:codebook 有 k-means init、EMA、dead-code replacement, VectorQuantization.forward 在 training mode 做 straight-through 与 commitment MSE。但正式推理走 quantizer.encode,不会计算 commitment penalty,也不会更新 codebook。

官方 .ecdc 与项目 .evc:相同 indices,不同字节协议

上游确实提供真实文件格式,不应再把 model.encode() 的 tensor 误叫成官方 bitstream。 .ecdcECDC magic + version + JSON header + code body;未启用 LM 时使用官方 10-bit BitPacker,启用时改用 arithmetic coder。1 秒合成 probe 的真实 bytes 为:

nominal rate K representation bits official raw .ecdc header/body project raw .evc header/body
1.5 kbps 2 1,500 254 B 66 / 188 B 511 B 323 / 188 B
3 kbps 4 3,000 441 B 66 / 375 B 698 B 323 / 375 B
6 kbps 8 6,000 816 B 66 / 750 B 1,073 B 323 / 750 B
12 kbps 16 12,000 1,567 B 67 / 1,500 B 1,825 B 325 / 1,500 B
24 kbps 32 24,000 3,067 B 67 / 3,000 B 3,325 B 325 / 3,000 B

两者 body 长度相同却 SHA 不同。不是 corruption:

  • official compress_to_file 的循环是 timestep → codebook,即 time-major;
  • 项目 write_payload[K,T]reshape(-1),即 codebook-major;
  • 两边各自 unpack 都精确恢复同一个 [K,T] indices;因此是协议顺序不同、语义相同、字节不兼容

项目 .evc 多出的约 257–258 B 是更严格的 model/checkpoint/rate/shape/original-length header, 不是声学表示;D5 必须同时报 representation bits 与 total payload bytes。

官方 6 kbps raw .ecdc 用 fresh model 重放后 shape 与原长一致。浮点输出不是逐 bit 相等:与同一 进程 direct decode 的 max/mean abs diff 为 2.09e-7 / 2.98e-8,但在 rtol=0, atol=1e-6 下 allclose。结论应写“codes 无损重放、波形数值等价到预声明容差”,不能写“fresh float bytes 相同”。

Optional LM 的代码路径

LMModel 为每个 codebook 建独立 embedding,先把同一 timestep 的 embeddings 求和,再进 5-layer causal Transformer,最后用各 codebook 独立 linear head 并行预测概率。get_lm_model 固定 width 200 与 3.5 秒 past context,并加载第二个 checkpoint。.ecdc encoder 每个 timestep 用上一时刻的 codes 作为下一次 LM input,然后按 codebook 做 arithmetic coding。

它与声学 codec 的边界非常干净:无 LM 和有 LM 解出的 indices 应相同,区别只是字节长度与计算。 D2 没下载/运行 LM checkpoint;其 paper-native entropy saving 进入 D3/D4,而不是在代码阅读阶段 提前宣布复现。

代码审计发现的五个 release gap

  1. 完整训练 runner 不在 v0.1.1。 quantizer.forward 接收显式 bandwidth,但论文的随机 depth sampler、每档 discriminator 选择和 batch policy 没有入口。
  2. 大多数 loss 与 balancer 不在 release。 waveform/mel reconstruction、hinge loss、relative feature matching、gradient loss balancer、optimizer、dataset loader 均缺失。
  3. MS-STFT 默认值不是论文配方。 开放的 class 默认 FFT [1024,2048,512] 三尺度;论文写 [2048,1024,512,256,128] 五尺度。class 可配置,但 exact training instantiation 不在仓库。
  4. entropy precision 有 paper/code 差异。 论文写先以 1e-6 precision round probability; 固定源码 build_stable_quantized_cdf 默认 roundoff=1e-8compress.py 没有 override。
  5. causal 不等于已交付增量 API。 未来不泄漏成立,但 acoustic encoder/decoder stateful chunk interface 缺失。

最重要的裁决是:官方 inference code 很完整,论文 training code 不完整。 msstftd.py 文件 顶部甚至明确写“provided here for reference”。因此 D3 不能把“官方 repo 可安装”误判为“论文 从训练到主表可完全复现”。

本地两个 adapter 各自做了什么

codecs_/encodec_codec.py 是早期 convenience baseline:它调用官方 encode/decode,但只把 frames × K × 10 换算成理想 payload bytes,没有真实写 bitstream。它的历史结果只能保留为 codes-only 工程证据。

codecs_/encodec_payload.py 是当前 Transport Qualified 路径:

  • encoder 负责 ffmpeg → mono 24 kHz、官方 checkpoint encode、写 .evc
  • decoder 只接收 .evc 与共享 checkpoint,不接触原音路径;
  • header 固定 checkpoint SHA、rate、shape、sample rate 与原长;
  • raw indices 精确 10-bit pack,无 entropy LM;
  • decode 后裁到原长,再转为 16 kHz benchmark WAV。

它没有改变 encoder、RVQ code selection 或 decoder 权重;它改变的是 file header、index ordering、 I/O sample rate 边界和输出裁剪。因此项目 .evc 可以用于公平 evaluator,却不能冒充官方 .ecdc

D2 允许与禁止的结论

D2 已建立:固定 inference commit 的端到端调用链;每层 tensor shape;RVQ residual 机制;合法 bandwidth 到 active stages;padding、因果前缀与句尾裁剪;official/project raw transport 的真实 bytes 与协议差异;paper/code/release gaps。

D2 仍未建立:optional LM 的本地输出;任何论文 MUSHRA/ViSQOL/SI-SNR;任何语言、内容、身份、 表达或音质优劣;paper training run 的复现;相对其他 codec 的 Pareto 排名。这些必须等待 D3–D6。

可复核命令

.venv/bin/python scripts/trace_encodec_code.py --check
python3 scripts/validate_research_registry.py
python3 scripts/generate_research_docs.py --check
.venv/bin/python -m pytest tests/test_research_registry.py tests/test_encodec_payload.py -q
.docs-venv/bin/python -m mkdocs build --strict

D2 · 已验证完整结构图

flowchart LR subgraph ENCODER["Official 24 kHz causal encoder"] X["waveform<br/>B×1×T"] --> C0["Conv k7<br/>B×32×T"] C0 --> D2["ResBlock + stride 2<br/>B×64×T/2"] D2 --> D4["ResBlock + stride 4<br/>B×128×T/8"] D4 --> D5["ResBlock + stride 5<br/>B×256×T/40"] D5 --> D8["ResBlock + stride 8<br/>B×512×ceil(T/320)"] D8 --> L1["2-layer residual LSTM"] L1 --> Z["Conv k7 latent<br/>B×128×frames"] end subgraph RVQ["Residual vector quantizer"] Z --> Q1["stage 1: nearest code"] Q1 --> R1["residual -= vector 1"] R1 --> QN["stages 2…K repeat"] QN --> IDX["indices<br/>public B×K×frames"] QN --> SUM["sum decoded stage vectors<br/>B×128×frames"] end subgraph DECODER["Official 24 kHz causal decoder"] SUM --> DL["2-layer residual LSTM"] DL --> U8["stride 8 upsample"] U8 --> U5["stride 5 upsample"] U5 --> U4["stride 4 upsample"] U4 --> U2["stride 2 upsample"] U2 --> Y["Conv k7 waveform<br/>B×1×padded T"] Y --> TRIM["transport/forward trims original length"] end IDX --> OFF["official .ecdc<br/>time-major raw 10-bit or entropy-coded"] IDX --> EVS["EvoSpeech .evc<br/>codebook-major raw 10-bit + strict identity header"] IDX -. "optional previous-token context" .-> LM["5-layer causal Transformer LM"] LM -. "probability CDF" .-> OFF

D3 · 论文原生复现协议:先把“什么算复现”锁死

本节是 protocol freeze,不是结果页。冻结时尚未计算 D4 的本地最终指标。所有 operating point、样本、预处理、metric、统计单位、容差和合法 verdict 都来自结构化文件 evaluations/paper_native_protocol.json;D4 不能在看见数字后悄悄改规则。

这次最重要的发现:论文可读,不等于主表可重跑

论文给出了相当多实验信息:四类测试内容、MUSHRA 每类 50 个 5 秒片段、每题至少 10 票、 听者排除规则、ViSQOL 与 SI-SNR,以及公开数据集的随机划分比例。但是,严格复现需要的下列 对象没有随论文或固定官方仓库发布:

  • 随机 test item ID、split seed、混音 source/gain/RIR 决策;
  • proprietary music test set;
  • MUSHRA 的 200 个原片、low anchor、逐听者逐题投票与 assignment graph;
  • ViSQOL 的 commit、audio/speech mode、resampler,以及 SI-SNR 的确切实现;
  • discriminator、streaming、SoundStream、LSTM/channels、balancer 等消融 checkpoint;
  • 能从训练数据构造论文表格的完整 training/evaluation runner。

这是由三份一手证据共同支持的“不可得”判断,而不是因为本地还没找够:19 页固定 PDF 没有 这些标识;固定 commit 的完整 tree 只有 40 个文件,没有 dataset/evaluation/training script;官方 README 只给推理、压缩、demo 和 package test。因而,Table 1 MUSHRA、Tables 2/3 的严格 objective reproduction、Table 5 跨机器 runtime 等价和附录消融,不能被诚实标成 passed

公开资产到底允许我们验证什么

作者 sample page 仍然很有价值。它公开了 24 kHz 的四种内容:一个 Common Voice clean、两个 Common Voice + FSD50K noisy、一个 proprietary music demo;每种都有 ground truth 与 EnCodec 1.5/3/6/12 kbps 输出。D3 已下载并核对 20 个 WAV:全部 24 kHz、单声道、PCM16、恰好 6 秒, 逐文件 SHA-256 已冻结,但音频因逐样本许可不明而只留在 git-ignored cache,不重新分发。

它们支持三类不同强度的 D4 检查:

  1. 严格 primary-artifact 检查:用固定 checkpoint 从四个 ground truth 重生成 16 个输出,按 预注册的 16-bit serialization 容差对齐作者输出。这能验证“我们拿到的 release artifact 与作者 demo 是否为同一推理行为”,但不能证明 MUSHRA 优势。
  2. 近似 paper-native diagnostic:用官方 LM 测四类 demo 的 entropy body/full-file bitrate, 用冻结 SI-SNR 和 ViSQOL v3.3.3 audio-mode 配方测 6 kbps。它们可帮助判断量级与实现漂移, 但 N=4 与论文未发布 test mix 不同,数字再接近也只能叫 approximate
  3. 平台条件化 runtime:固定官方 repo 的 20 秒 test_24k.wav,取前 10 秒、单 CPU thread、 3 次 warmup + 20 次正式重复,报告中位数和 bootstrap CI。当前 Apple Silicon 结果只能与 “MacBook Pro 2019”作者值作条件化对照,不能声称跨硬件等价。

为什么没有用“现代标准数据集”补论文缺口

因为那会把 D4 和 D5 混在一起。LibriSpeech、FLEURS、DNS、Jamendo 或我们的六语集合当然 适合重新做一个更好的共同 benchmark,但它们不能恢复作者当年的随机测试 item、proprietary music 和听者。D3 明确规定:

  • 论文主表缺资产时,D4 写 blocked,不能换一套数据后写“官方复现”;
  • 四个 author demo 只形成 approximate diagnostic,不做等价检验;
  • 新的权威、多语言、内容/身份/表达横评全部留给 D5/D6,并在页面另表展示。

metric 与统计规则已经预先确定

  • Author artifact:16 对样本率、声道和长度必须精确一致;max_abs <= 2/32768mean_abs <= 0.25/32768、最小 pairwise SI-SNR 至少 80 dB。PCM hash 仅作更强诊断。
  • SI-SNR:reference/estimate 各自去均值,以 reference 投影为 target,eps=1e-8
  • ViSQOL:固定 Google v3.3.3 / commit c3aa2e…、audio mode;24 kHz 输入用固定 scipy.signal.resample_poly(2,1,kaiser=5.0) 联合升到 48 kHz。这是我们为近似诊断选定的 可复现配方,不冒充论文未披露配方。
  • Entropy:nominal raw-code rate、arithmetic-coded body rate、完整 .ecdc file rate 三本账; 必须先验证 entropy decode 返回完全相同 codes。
  • Quality:四个 item 是 bootstrap unit,seed 20260720、10,000 次、95% CI;N=4 的区间只 表示这个 demo 集合的不确定性,不允许推断论文总体。
  • Runtime:每次 repetition 是 bootstrap unit,RTF 定义为 audio duration / wall time。

D3 允许与禁止的结论

允许: 协议已在正式 D4 前冻结;官方公开资产足以做 nominal-rate、transport 与 author-demo 重生成强校验,也足以做小样本 entropy/objective/runtime 诊断;严格 headline quality reproduction 因缺失资产而先验不可行。

禁止: 现在宣称 Table 1/2/3/5 已复现;把四个 demo 当成论文 200 个 MUSHRA item;把 ViSQOL 接近 4.35 视为等价;用 D5 新 benchmark 替代 D4;因结果不理想而事后放宽容差。

D3 结论:passed。 下一关是按冻结顺序执行 D4,并让每个 claim 落到 passed / failed / approximate / blocked / out_of_scope 中唯一一个状态。

D3 · 冻结 claim matrix(机器记录生成)

ID Paper claim 预注册分类 Operating point D4 判定边界
PN-DET-RATE-24K ENC-P-002 strict_reproducible 1.5, 3, 6, 12, 24 kbps Every point has exactly K=[2,4,8,16,32], 75 frames/s, 1024 entries, and K7510 equals the advertised bits/s; fresh decode preserves the exact code indices.
PN-AUTHOR-DEMO-REGEN ENC-P-001, ENC-P-002 strict_primary_artifact_check_not_headline_metric 1.5, 3, 6, 12 kbps For all 16 pairs: sample rate/channels/frame count exact, max_abs<=2/32768, mean_abs<=0.25/32768, and SI-SNR(local,author)>=80 dB.
PN-ENTROPY-T1 ENC-P-012 approximate_only 1.5, 3, 6, 12 kbps Run all 16 sample/rate points, verify entropy decode returns identical codes, and report body/full-file kbps and paper-minus-local descriptively. It must remain approximate regardless of numerical closeness.
PN-OBJECTIVE-T23 ENC-P-025, ENC-P-028, ENC-P-029 approximate_only 6 kbps Retain four per-item values and macro mean/95% bootstrap CI; compare descriptively to 6.67 SI-SNR and 4.35 ViSQOL, with no strict-equivalence verdict.
PN-MUSHRA-24K ENC-P-024, ENC-P-026, ENC-P-027 blocked_before_execution 1.5, 3, 6, 12 kbps D4 records blocked using primary-source evidence. No new listening test or four-demo average may be substituted.
PN-BASELINE-SOTA ENC-P-001, ENC-P-023, ENC-P-026 blocked_before_execution D4 records blocked. D5 may compare currently available anchors on a new common benchmark but may not relabel it as paper reproduction.
PN-RUNTIME-T5 ENC-P-031 approximate_platform_conditioned 6 kbps One CPU thread, 3 warmups, 20 repetitions, median and bootstrap CI; compare to Table 5 only as a platform-conditioned ratio, never as equivalence.
PN-ABLATIONS ENC-P-028, ENC-P-029, ENC-P-032, ENC-P-033, ENC-P-034 blocked_before_execution D4 records blocked. Evaluating the sole released final checkpoint is not an ablation.
PN-STEREO-48K ENC-P-002, ENC-P-030 different_model_identity Record out_of_scope and open a separate 48 kHz model record if this claim becomes a project priority.

D3 · 冻结公开资产

作者 sample page HTML 为 13,162 bytes / SHA-256 252a8b65d932c40821a323f9b09587338a87631ee194e538aec8ebf93c090045; 本协议选择并冻结 20 个 WAV。所有音频只保存在 git-ignored cache, 公开页面只发布 URL、hash、metadata 与研究结论。

.venv/bin/python scripts/audit_encodec_paper_assets.py --check
python3 scripts/validate_research_registry.py
python3 scripts/generate_research_docs.py --check