# MOSS 长音频 16384-token 截断与后端诊断

日期：2026-07-21  
范围：只读审计；未启动模型、未安装运行包、未重跑音频。历史 run 与 snapshot 未修改。

## Owner 结论

1. 张翼 47:41 节目的重试已经解决了媒体容器问题：MOSS 实际输入是确定性解码的
   16 kHz mono WAV。当前失败不是 `m4a` 不支持，而是生成结果在音频 1284.75 秒处结构性截断。
2. `max_new_tokens=65536` 确实从冻结请求进入了复制后的 `GenerationConfig`，并作为
   `generation_config` 传给 Transformers `model.generate()`。实际却恰好返回 16384 个新 token。
3. 现有证据不能证明是“隐藏的 16384 上限”还是模型在第 16384 个 token 生成了 EOS。旧 runner
   没有保存生成 token IDs、末 token、EOS 命中、最终有效 GenerationConfig、streamer 进度或停止条件；
   因此不能靠现有 raw 补推内部 stop reason，也不应盲目再跑一次整期。
4. 这不是 128K 上下文或显存容量不足的证据。按本次真实 token 密度外推，完整节目约需 36,492
   个输出 token，总序列约 74,416 token；`65536` 输出预算和 131,072 上下文均有充分余量。
5. x1-dev 是 12 核 Ryzen AI 9 HX 470 + Radeon 890M（PCI `1002:150e`，gfx1150）集显，
   不是数据中心 GPU。当前 Transformers/ROCm 路径只有约 2.94 output token/s，RTF 1.949。
   这说明当前后端不合适，不足以推出“CPU 一定更慢”。CPU 值得做短配对微基准，但不值得直接跑整期。
6. SGLang Omni 的当前 MOSS 优化路径依赖 CUDA 13、CUDA Graph、flash-attn-4 和 CUDA relay 包，
   不能视为当前 AMD 主机上的可用替代后端。vLLM 的一般 ROCm 路径明确识别 gfx1150，且官方固定提交
   包含 MOSS 原生注册，因此技术上可行；但官方 MOSS 安装命令只给 CUDA wheel，固定提交的现成 ROCm
   wheel 与当前 7.2.1 runtime 也不一致，必须走独立兼容性验收，不能直接进入正式跑分。

## 一、已经证实的事实

### 1. 冻结执行路径确实收到了 65536

证据来自 immutable retry snapshot，而不是当前 mutable runner：

- `execution-snapshot/request.source.json` 中 `decoding.max_new_tokens=65536`、
  `decoding.max_length=131072`。
- snapshot runner 在调用前验证 CLI 的 `args.max_new_tokens` 与冻结请求相等。
- 官方 `generate_transcription()` 对 `model.generation_config` 做 `deepcopy`，随后执行
  `generation_config.max_new_tokens = max_new_tokens`，最后以
  `model.generate(..., generation_config=generation_config)` 调用 Transformers。
- MOSS 模型没有自定义 `generate()` 覆盖；使用 Transformers `GenerationMixin.generate()`。
- 运行环境记录的 `decoding.max_new_tokens` 也是 65536。

关键 frozen artifact：

| artifact | SHA-256 |
| --- | --- |
| snapshot runner | `2af50a573a2e14167ec82293c61619434d18617f27715b7f879b1d7e10f6ecdd` |
| source request | `a6398a2796c8bd87ee1d39d43aa9cb12a55f61ca9b7d742245b4af5bb04221b2` |
| result | `ddd3d1f70322a896a25abe4149bcefb8977e41430f9772f69c56abac8bc75f07` |
| raw transcript | `f9fcd4be2cfa178620e4bc260d54adafb1fe26d4e04ee3a1df8b4e15aa00c51a` |
| read-only stop analysis | `8b6443499566be87c2729112a8c67df5ae52d0f0522dc21741bd6ab55660eeda` |

Transformers 5.14.1 的标准逻辑是：有 `max_new_tokens` 时，将内部 `max_length` 设为
`input_ids_length + max_new_tokens`。本 run 的 prompt 是 37,924 token，所以长度停止点应是
103,460，而不是 54,308（37,924 + 16,384）。标准 stopping criteria 只有按总长度停止和 EOS；
runner 没有传入自定义 stopping criteria、max time 或 streamer。

### 2. 输出是结构性截断，不是 parser 少解析了一段

保留结果为：

- `generated_tokens=16384`
- `segment_count=632`
- 最后完整时间戳：1284.75 秒
- 音频总时长：2861.511125 秒
- 时间轴覆盖：44.8976%
- 尾部未覆盖：1576.761125 秒
- raw 尾部：`可以讲一下这背后你们的这个[12`

raw 自身停在半个时间戳标签中，因此即使完全绕过 parser，也没有后半段音频的输出。raw 重新编码为
16,380 个普通文本 token，且 decode round-trip 一致；生成张量比它多 4 token，但由于原生成 IDs
没有保留，不能据此认定那 4 个一定包含 EOS。

### 3. 128K 上下文与内存不是当前截断点

由保留数据直接计算：

| 项目 | 数值 |
| --- | ---: |
| 实际 prompt 密度 | 13.253 token / 音频秒 |
| 已覆盖部分的输出密度 | 12.753 token / 音频秒 |
| 按实际密度外推完整输出 | 36,492 token |
| 按保守 20 token/秒预算完整输出 | 57,231 token |
| 按实际密度外推总序列 | 74,416 token |
| 128K 上下文余量 | 56,656 token |
| prompt 后理论最大生成空间 | 93,148 token |

Qwen3 decoder 为 28 层、8 KV heads、head dim 128、BF16。忽略 allocator 和 workspace 开销，
KV cache 理论占用约 114,688 bytes/token：

- 实际返回序列（54,308 token）：约 5.80 GiB；
- 完整输出外推（74,416 token）：约 7.95 GiB；
- 把 65,536 输出预算全部用满（103,460 token）：约 11.05 GiB。

实测 peak allocated 8.36 GB、peak reserved 13.53 GB，且运行没有 OOM。完整结果会更慢并增加 cache，
但现有容量证据不支持“因为 GPU 内存不足而在 16384 正常返回”。

### 4. 当前运行栈

- model revision：`e6d68cdfcddbdad1a7e8454f0cb859cad76e2502`
- OpenMOSS code revision：`40cf8549c6b5634ba36b7e817cf523b5ad400c2e`
- Transformers：5.14.1
- PyTorch：2.9.1 + ROCm 7.2.1
- HIP runtime：7.2
- GPU：AMD Radeon 890M / gfx1150，共享内存环境中 PyTorch 报 32.46 GB
- CPU：AMD Ryzen AI 9 HX 470，12 cores / 24 threads
- inference：5576.416 秒，2.938 generated token/s，RTF 1.9488
- loader：custom flat BF16，完整 bitwise round-trip 与参数覆盖验证通过

## 二、尚不能证实的解释

### 假设 A：某个隐藏的 16384-token 上限生效

支持它的现象：返回 token 数恰好是 2 的幂，raw 又停在半标签；OpenMOSS 官方 Hugging Face Space 的
客户端默认 `max_new_tokens` 也恰好是 16384。

反对把它当结论的证据：本地 runner 没有调用该 Space 或其远端 API；冻结请求和本地
`GenerationConfig` 路径明确是 65536；Transformers 5.14.1 源码中也没有找到通用 16384 clamp。
因此 Space 默认值只能说明生态里常用过这个预算，不能解释本地进程为何停止。

### 假设 B：模型在第 16384 个 token 生成了 EOS

标准 Transformers greedy generation 会在 EOS 后正常返回；这与 `status=succeeded` 相符。
模型在结构标签中间错误地产生 EOS 也并非不可能。可是旧 runner 解码时使用
`skip_special_tokens=True`，又没有保存末 ID，所以 raw 中看不到 EOS，也不能证实此假设。

### 假设 C：ROCm、cache 或外层运行器静默截断

没有 OOM、异常、进程信号或外层 timeout 证据；普通 PyTorch cache 容量问题通常应报错，而不是返回
一个合法张量。当前源码审计也没有找到 runner 的 token callback、server cap 或自定义 stop criteria。
所以该假设目前证据最弱，但在保留末 token/stop reason 前仍不能完全排除 backend-specific 行为。

## 三、后端可行性

### SGLang Omni：当前 x1-dev 不可直接使用

MOSS 官方把 SGLang Omni 作为长音频推荐后端；其 cookbook 说明长音频的主要成本在 AR decode，
20 分钟、并发 1 时 AR decode 占 94.5%，CUDA Graph 是最重要的 decode 优化。

但是当前实现边界非常明确：

- 安装文档要求 CUDA 容器、`--gpus all`、UCX with CUDA、flash-attn-4；
- `pyproject.toml` 固定 CUDA 13 relay 包；
- MOSS pipeline 默认设备硬编码为 `cuda:0`；
- encoder 优化直接调用 `torch.cuda.CUDAGraph`、CUDA stream 与 CUDA graph pool；
- OpenMOSS README 自身也写明 SGLang Omni 当前面向 CUDA 13。

SGLang 主项目存在 ROCm 支持，不等于 SGLang **Omni 的 MOSS pipeline** 已支持或验证 ROCm。当前没有
官方 AMD 安装路径或 MOSS-on-ROCm parity 证据，因此状态应记为
`not_feasible_on_current_host_without_upstream_port`，不能为了尝试而安装整套重包。

### vLLM：硬件与模型注册均可行，但当前没有 drop-in 组合

有利事实：

- OpenMOSS 指定的 vLLM commit `68b4a1d582818e67adc903bf1b8fc5a5447da2fa` 包含
  `MossTranscribeDiarizeForConditionalGeneration` 原生实现和 transcription 注册；不是仅靠不透明
  `trust_remote_code` 回落。
- 同一 commit 的 ROCm platform 把 PCI `0x150e` 显式识别为 Radeon 890M / gfx1150。
- 同一 commit 的 ROCm requirements 列出 Ryzen AI 300 / gfx1150，要求 ROCm >= 7.0.2；
  x1-dev 的 Python 3.12、glibc 2.39、ROCm 7.2.1 满足一般要求。
- 该 commit 的 ROCm unsupported/partially-supported model 表为空，MOSS 实现本身未出现硬编码 CUDA
  op；其底层仍依赖 vLLM Whisper/Qwen3/attention kernel 的实际组合。

未解决事实：

- OpenMOSS 给这个固定 commit 的安装命令只列 `cu129` / `cu130` wheel。
- vLLM wheel 索引显示该 exact commit 的现成 ROCm 产物是 `rocm723`，而当前运行环境是 7.2.1；
  它不是当前容器的无安装替换件。
- vLLM model registry 把 MOSS 样本标为 `is_available_online=False`，代码树中只有 registry 级引用，
  没找到 MOSS 的端到端模型测试，更没有 gfx1150 专项结果。
- 集显共享内存、长 prompt 的 chunked prefill、74K 序列 KV cache 和 transcription endpoint 在此机上的
  正确性/稳定性仍未知。

因此状态应为 `feasible_with_isolated_qualification`。候选路径按风险排序：

1. 找到仍含 MOSS 注册、且有 `rocm721` wheel 的更新 vLLM nightly，在全新隔离环境做 10 秒 parity；
2. 在 ROCm 7.2.1 上从 exact commit 构建 wheel；
3. 单独升级到该 exact commit 已发布 wheel 的 ROCm 7.2.3 组合。

三条路径都会改变 backend identity；必须记录 vLLM commit、wheel SHA、ROCm/PyTorch、attention backend、
`max_model_len`、KV cache dtype、chunked-prefill 参数，并先与 Transformers 10 秒 raw 做可解释 parity。
在此之前不能把 vLLM 当作正式运行环境，也不能把它与当前 raw 共用 cache identity。

### CPU：只做短配对 microbenchmark

不能仅凭“GPU”二字推定更快：890M 是集显，当前任务 batch=1、小 decoder、逐 token eager decode，
kernel launch 与 Python/框架开销可能很大。12 核 Zen 5 CPU 可能在这个特定实现上接近甚至超过当前
2.94 token/s，只有实测才能判断。

但直接跑 47 分钟没有价值：

- 官方 helper 在 CPU 上会切 FP32，行为和 BF16 ROCm 不同；
- 整期可能再次耗时数小时；
- 即使 CPU 跑完，也不能解释 GPU 的 16384 stop，因为两边 backend 与数值路径不同；
- CPU 短输出不能验证 50K-token cache 增长、长上下文稳定性或整期 speaker consistency。

最低成本实验应是同一冻结 10 秒和 60 秒 WAV、相同 prompt、greedy、相同 token 上限，分别记录：
模型加载、prefill、decode token/s、峰值 RSS、完整 token IDs、EOS/stop reason 和结构化输出。先跑 10 秒
验证 instrumentation，再用 60 秒比较 steady-state；只有 CPU 明显更快且输出结构可用，才考虑一个
10 分钟工程窗口。CPU 结果单列 `cpu_diagnostic`，不与正式 ROCm/vLLM 性能混排。

## 四、下次运行前必须补齐的 instrumentation

不要修改任何旧 run/snapshot。创建新 runner version、新 execution snapshot 和新 cache identity，至少保存：

1. `generation-config.before-generate.json`
   - `model.generation_config.to_dict()` 原值；
   - 覆盖后的传入值；
   - prompt length、`prompt + max_new_tokens`、model/tokenizer context limit；
   - EOS/PAD/BOS token IDs、cache implementation、dtype、device。
2. `raw/generated-token-ids.json`
   - output tensor shape；
   - 完整 generated token IDs（65K 规模的 JSON 仍很小；也可用 `.npy` + SHA）；
   - 最后至少 64 个 IDs，以及 `skip_special_tokens=false/true` 两种 decode；
   - EOS 出现位置、末 token 是否 EOS。
3. `generation-progress.ndjson`
   - 每 256 token 或 30 秒写一个 append-only checkpoint；
   - monotonic time、generated count、tokens/s、GPU allocated/reserved、末 8 token IDs；
   - 首 token 时间、prefill 完成时间、最后 callback 时间。
4. `generation-stop.json`
   - `eos_token`：末 token 命中有效 EOS；
   - `max_new_tokens`：生成数达到传入预算且未命中 EOS；
   - `max_length`：总序列达到内部有效总长度；
   - `exception_or_external_termination`；
   - 其余一律 `unknown`，不得根据“恰好是 2 的幂”猜测。
5. `token-budget.json`
   - 音频秒数、prompt token 密度；
   - 根据已完成时间戳覆盖估算的 output token/音频秒；
   - observed、保守 20 token/秒和 context-constrained 三种预算；
   - 预计总序列与理论 BF16 KV bytes；
   - `budget_fits_context` 与 `budget_fits_memory_estimate` 分开记录。

instrumented runner 先用可控的短样本分别触发 EOS 与小 `max_new_tokens`，验证 stop 分类；之后才允许
10 秒 MOSS smoke。现有 `moss-0.9b-meeting-first-pass-v2` snapshot 没有这些终止证据，若要执行应由
owner 显式接受缺口；更稳妥的是准备带新 runner identity 的 v3，而不是原地改 v2 snapshot。

## 五、评测协议建议

- 小于官方约 90 分钟单次范围的 47/52 分钟节目，保留 `native_longform` 整期轨是正确的；小时级
  成功率、尾部覆盖、说话人稳定性和时间轴漂移正是 10 分钟窗口不能替代的指标。
- 10 分钟窗口仍然必要，用于 human gold 的 CER/cpCER/DER/JER/时间戳精度与跨模型公平比较。
- 如为工程交付增加显式切分，放入独立 `chunked_engineering` 轨，冻结切点、overlap、stitching 和
  cache identity；不得用切片成功掩盖 native 整期失败，也不得把两种 RTF/完整性混排。
- 2:47:59 的节目超出 MOSS 官方单次范围，应切片或只跑 gold windows；不是 native failure。
- 张翼节目下一次不应仅把 `max_new_tokens` 再调大：65536 已足够。先补 stop evidence，再决定是修
  Transformers runner、换 vLLM，还是把 native 截断作为模型/后端结果保留。

## 参考

- [OpenMOSS 官方仓库（冻结提交）](https://github.com/OpenMOSS/MOSS-Transcribe-Diarize/tree/40cf8549c6b5634ba36b7e817cf523b5ad400c2e)
- [OpenMOSS 模型 revision](https://huggingface.co/OpenMOSS-Team/MOSS-Transcribe-Diarize/tree/e6d68cdfcddbdad1a7e8454f0cb859cad76e2502)
- [Transformers 5.14.1 generation 实现](https://github.com/huggingface/transformers/blob/v5.14.1/src/transformers/generation/utils.py)
- [OpenMOSS 官方 Space 客户端（16384 默认值只作旁证）](https://huggingface.co/spaces/OpenMOSS-Team/MOSS-transcribe-diarize/blob/main/app.py)
- [SGLang Omni MOSS cookbook](https://github.com/sgl-project/sglang-omni/blob/main/docs/cookbook/moss_transcribe_diarize.md)
- [SGLang Omni 安装要求](https://github.com/sgl-project/sglang-omni/blob/main/docs/get_started/installation.md)
- [SGLang Omni MOSS CUDA graph 实现](https://github.com/sgl-project/sglang-omni/blob/main/sglang_omni/models/moss_transcribe_diarize/encoder_cuda_graph.py)
- [vLLM 固定提交的 MOSS 注册](https://github.com/vllm-project/vllm/blob/68b4a1d582818e67adc903bf1b8fc5a5447da2fa/vllm/model_executor/models/moss_transcribe_diarize.py)
- [vLLM 固定提交的 ROCm requirements](https://github.com/vllm-project/vllm/blob/68b4a1d582818e67adc903bf1b8fc5a5447da2fa/docs/getting_started/installation/gpu.rocm.inc.md)

