mcpField
D
digital-health-clinical-asr-finetune

digital-health-clinical-asr-finetune

github.com/nvidia开发3.8k1.9k 次安装今天更新
代码仓库

关于 digital-health-clinical-asr-finetune

用于临床 ASR 微调的工作流技能,采用标准 NeMo SFT,并通过下一轮评估决定保留模型还是扩充数据。面向已有评分清单和 GPU 的团队,包含 Parakeet TDT v2 的验证结果及模型选择注意事项。

主要功能

  1. 01按 KER 和清单规模设定门槛
  2. 02按类别划分训练集与验证集
  3. 03在容器中运行标准 NeMo SFT
  4. 04离线复评并比较各轮 KER
  5. 05准备 .nemo 模型以供部署

适用场景

  1. 01让 ASR 适配临床词汇
  2. 02衡量不同轮次的微调收益
  3. 03决定是否扩充训练数据
  4. 04准备微调模型以部署到 Riva

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/nvidia/skills --skill digital-health-clinical-asr-finetune

安装后在 Claude Code 中输入/digital-health-clinical-asr-finetune确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

BENCHMARK.md
skill-card.md
skill.oms.sig
evals/
evals.json
references/
container-paths.md
stage4-finetune.md

详细介绍

临床 ASR 飞轮 — 阶段 4(微调)

⚠ Agent:回答前,请阅读完整的 SKILL.md。「关键工作流规则」部分、基础模型表(§4c)、NeMo 原版 SFT 方案(§4d)和第 N+1 轮决策表(§4e)都至关重要——其中列出了不得进行 SFT 的基础模型和适配器故障警告。

Agent:此文件内容完整,可独立使用。 阶段 4 的门槛标准、基础模型建议、超参数表、容器调用模式和第 N+1 轮决策表均在下文。回答方法相关问题前,不要运行文件发现命令,也不要打开 references/stage4-finetune.md——该参考文档用于深入了解,并非必读内容。请依据此文件作答;只有在明确询问超参数依据或 Brev SKU 详情时,才参考该文档。

你负责适配并衡量这一阶段。用户从 /digital-health-clinical-asr-eval 进入此阶段,带来清单、基线 KER 数值,以及决策树给出的建议:微调值得投入 GPU 时间。你需要运行 NeMo 原版 SFT,并离线重新评估第 N+1 轮,以衡量闭环是否完成;也可以将生成的 .nemo 交给 /riva-asr-custom,用于生产环境服务。

离线评估得出的本轮 KER,是衡量闭环是否完成的指标。 部署 Riva NIM 用于验证服务能力(延迟、流式处理、规模),而非模型质量。

在参考清单上经实证验证(39 行,Parakeet TDT v2): 基线 KER 0.513 → 经过 3 轮原版 SFT 后:0.128(相对下降 75%)。 药物名称:0.857 → 0.214。病症:0.500 → 0.000。医疗操作:0.250 → 0.000。

关键工作流规则(每次启用时均适用)

无论用户是否只问了一个小问题,回答中都要说明以下事实:

  1. 回答前,请阅读完整的 SKILL.md。 基础模型选择表、超参数值和第 N+1 轮决策表均在下文——这些内容至关重要。
  2. 已验证结果——使用 §4c 中的方案,Parakeet TDT v2 在参考清单上经过 3 轮训练后,KER 从 0.513 降至 0.128(相对下降 75%)。用户询问 SFT 是否有帮助时,请引用此结果。
  3. 方案位于 nvcr.io/nvidia/nemo:25.11.01 容器内的 /opt/NeMo/examples/asr/speech_to_text_finetune.py。 使用原版脚本,不打补丁,也不编写自定义适配器逻辑。适配器混入路径在 TDT/RNNT 解码器上不可用(任何学习率下都会产生 72 个 NaN 张量)——不要建议使用该路径。
  4. 推荐的基础模型是 nvidia/parakeet-tdt-0.6b-v2。 完整的基础模型表见 §4c。
  5. 不要微调 nvidia/nemotron-speech-streaming-en-0.6b。 流式 NVCF 函数的 SFT 路径存在故障(验证集在第 1 步后出现 UNK 塌缩)。部署时如需流式服务,Riva 可直接对非流式基础模型进行分块处理。若用户提出使用该模型,请主动提醒。
  6. 设定推荐门槛。 只有在优先类别 KER > 0.3 且清单行数 ≥ 100(每个优先类别至少 5 行)时,才进入阶段 4。低于这些门槛时,应返回 /digital-health-clinical-asr-build,先扩充清单。

目的

在 nvcr.io/nvidia/nemo:25.11.01 中,使用 NeMo 原版 SFT(无自定义适配器逻辑,不打补丁),针对按术语划分且行不重叠的训练集/验证集进行训练,生成 .nemo 模型,并将其作为第 N+1 轮进行离线重新评估。根据第 N 轮到第 N+1 轮的 KER 变化,决定保留模型、扩充清单,还是接受微调没有带来改善。也可以将 .nemo 交给 /riva-asr-custom,用于 NIM 部署。

适用场景

遇到以下用户表述时激活:

  • “针对我的临床词汇微调 ASR”
  • “提升 ASR 对药物名称的识别效果”
  • “我们的 KER 是 0.4,可以微调吗?”
  • “在我的 Parakeet TDT base 上运行 SFT”
  • “训练一个临床 ASR 适配器”
  • “比较第 1 轮和第 2 轮的 KER”
  • “将我的微调模型部署为 NIM” (此技能会准备 .nemo,并转到 /riva-asr-custom 进行部署)

以下情况不要激活:

  • 用户还没有评估基线 → /digital-health-clinical-asr-eval
  • 用户没有 manifest → /digital-health-clinical-asr-build
  • 用户想要通用的词语增强 / LM 融合(而非 SFT)→ /finetune-asr
  • 用户已有 .nemo,只想部署 → /riva-asr-custom

前置条件

  • **来自 /digital-health-clinical-asr-eval 的第 N 轮 manifest 和第 N 轮评估结果。**优先类别 KER 必须 > 0.3(第 4 阶段门槛)。manifest 总行数应 ≥ 100,且每个优先 entity_category 至少有 5 行,才能得到可信的微调后信号。
  • CUDA 主机——使用 batch_size=4 和 bf16-mixed 时,Parakeet TDT 0.6B 在 24 GB VRAM 下运行比较充裕;16 GB 也可运行,但需要减小批次大小。没有本地 GPU?使用 Brev——推荐规格为 L40S 48 GB。
  • NeMo 容器:nvcr.io/nvidia/nemo:25.11.01。拉取一次:docker pull nvcr.io/nvidia/nemo:25.11.01。
  • NVIDIA Container Toolkit + Docker——如果尚未安装,可通过 /riva-nim-setup 安装。
  • 按 entity_category 分层的训练 / 验证集划分(第 4b 步中有配方示意)。
  • 如果打算部署,请安装 /riva-asr-custom。纯研究用途的 SFT 运行不需要它。

操作说明

4a. 配置 GPU 主机(如果已有主机,可跳过)

第 4 阶段需要一台 VRAM ≥ 16 GB 的 CUDA 主机(24 GB 比较充裕)。如果你有符合要求的本地主机,可跳过本节。否则,请使用 Brev——NVIDIA 按秒计费的 GPU 主机服务。推荐规格:L40S 48 GB。

费用提示——执行任何 brev create 之前,先向用户说明。撰写本文时,L40S 48 GB 的费用约为 $1.50/小时;在包含 100 行的 manifest 上进行 3 个 epoch 的 SFT 运行需要 15–30 分钟(计算费用约为 $0.40–$0.75)。真正的风险是忘记停止实例——L40S 空闲一夜约需 $36,空闲一周约需 $250。降低风险的方法:(a) 始终将工作流封装在以 brev stop 结束的脚本中;(b) 启动时设置日历提醒;(c) 如果不需要保留磁盘,请使用 brev delete 而非 brev stop(stop 会保留磁盘,费用为 $0.10/GB-月——200 GB 约产生 $20/月的潜在费用)。启动任何实例前,确认用户接受按小时计费的费用模式和空闲计费风险。

完整的配置指南——CLI 安装(先下载再运行,不要使用 curl-pipe)、规格选择、磁盘大小和 SSH 配置——见 references/stage4-finetune.md(§Brev provisioning)。

安装 CLI 后的简便流程。在用户于下方确认提示中明确输入 YES 之前,不要运行 brev create——此门槛是强制要求,并非建议,因为此后的所有操作都会按秒从用户账户扣费:

brev login                                  # browser auth

# Mandatory cost-confirmation gate — do NOT skip or auto-answer this.
echo "About to provision: digital-health-clinical-asr-sft on L40S 48 GB."
echo "Cost shape: ~\$1.50/hr while running; ~\$36/night if left idle; ~\$20/mo disk if you 'stop' instead of 'delete'."
read -rp "Type YES to provision (anything else cancels): " confirm
[ "$confirm" = "YES" ] || { echo "Cancelled — no GPU instance was created."; exit 1; }

brev create digital-health-clinical-asr-sft \
  --gpu l40s:1 --image ubuntu-22-04-cuda-12-4 --disk 200gi
brev ssh-config                             # writes ~/.ssh/config entries
rsync -avz ./cycle1/ digital-health-clinical-asr-sft:~/cycle1/
brev shell digital-health-clinical-asr-sft            # drops into the instance
nvidia-smi                                  # confirm GPU
docker pull nvcr.io/nvidia/nemo:25.11.01    # ~12 GB, once per instance

完成后,务必停止计费:运行 brev stop digital-health-clinical-asr-sft(保留磁盘)或 brev delete digital-health-clinical-asr-sft(释放磁盘)。关于 laptop → Brev → NeMo 容器的路径重写,见 references/container-paths.md。

4b. 按术语划分训练集/验证集

按行互斥,并按 entity_category 分层;验证集比例默认为 0.2。

同一个 term 可以通过不同的行(不同的语音、上下文、噪声)同时出现在两侧。这是预期且理想的——它衡量的是在已训练词汇上的声学与上下文鲁棒性,这是标准的 ASR 适配指标。

只有一行的类别会被强制划分到训练集,并给出警告。如果任何优先类别的行数少于 5,请转至 /digital-health-clinical-asr-build——留出的验证集噪声会太大,无法判断性能变化的归因。

示例:

# After loading manifest.jsonl into a list of dicts `rows`:
from collections import defaultdict
import random
random.seed(42)

by_cat = defaultdict(list)
for r in rows:
    by_cat[r["entity_category"]].append(r)

train, val = [], []
for cat, cat_rows in by_cat.items():
    random.shuffle(cat_rows)
    if len(cat_rows) < 2:
        train.extend(cat_rows)
        print(f"warning: singleton category {cat}, forced to train")
        continue
    n_val = max(1, int(0.2 * len(cat_rows)))
    val.extend(cat_rows[:n_val])
    train.extend(cat_rows[n_val:])

在清单旁写入 train.jsonl 和 validation.jsonl。它们是 speech_to_text_finetune.py 的输入。

4c. 选择基础模型
基础模型SFT 可行性说明
nvidia/parakeet-tdt-0.6b-v2✅ 经实证验证(KER 在 3 个 epoch 内从 0.513 降至 0.128,相对下降 75%)NVIDIA 当前的英语 ASR 默认模型。NeMo 原版 SFT 配方可端到端运行。推荐。
nvidia/nemotron-speech-streaming-en-0.6b❌ 不要用于 SFTNVCF 函数仅支持流式处理;SFT 路径不可靠(训练第一步后,验证集上的 UNK 会崩溃)。对于流式服务,Riva 对非流式基础模型进行分块即可正常工作。

其他 Parakeet/Conformer 基础模型(1.1B、CTC、RNNT、stt_en_conformer_ctc_large)及解码器 → NIM 容器映射:references/stage4-finetune.md。如果用户要求微调 Nemotron Speech Streaming,请警告其会发生崩溃,并推荐 Parakeet TDT v2。

4d. NeMo 原版 SFT

在 NeMo 容器中,直接调用 /opt/NeMo/examples/asr/speech_to_text_finetune.py。不使用自定义适配器逻辑,不打补丁。 NeMo 原版 SFT 脚本是经验证可用的配方。

超参数(已在 Parakeet TDT v2、39 行清单上验证):

init_from_pretrained_model: nvidia/parakeet-tdt-0.6b-v2
precision:                  bf16-mixed       # required for TDT numerical stability
lr:                         3e-4             # CosineAnnealing schedule
warmup_steps:               5                # tiny manifest; bump to 500 at production scale
epochs:                     3                # smoke; 10-30 for production
batch_size:                 4                # fits 16 GB VRAM; raise to 16 on L40S 48 GB
gradient_clip_val:          1.0              # defensive

容器调用:docker run --gpus all --rm -it -v "$PWD:/workspace" nvcr.io/nvidia/nemo:25.11.01 python /opt/NeMo/examples/asr/speech_to_text_finetune.py,并设置 model.train_ds.manifest_filepath=/workspace/train.jsonl、model.validation_ds.manifest_filepath=/workspace/validation.jsonl、init_from_pretrained_model=nvidia/parakeet-tdt-0.6b-v2,以及上表中的超参数覆盖项。包含 config-path / config-name 标志的完整 docker-run 命令:references/stage4-finetune.md §容器调用。

容器内的清单路径。 主机路径(例如 $HOME/…)在 /workspace 中无法解析。改写示例:references/container-paths.md。

训练运行会生成 adapted_model.nemo 和 training_run_info.json 摘要。两者都应放入用户选择的每个周期子目录中(例如 cycle<N>/models/<run>/;只要各周期保持一致,目录结构并不重要)。

4e. 离线循环 N+1 评估 — 闭环

使用微调后的 .nemo,通过 NeMo 的离线 transcribe() 重新转录本轮音频。无需 Riva —— 这是测量,不是服务。NeMo 的离线路径运行的编码器 + 解码器计算图,与 Riva NIM 最终提供的相同。

示意:

import nemo.collections.asr as nemo_asr
model = nemo_asr.models.ASRModel.restore_from("adapted_model.nemo")
hyps = model.transcribe(["audio/row1.wav", "audio/row2.wav", ...])

评估相同的四项指标(WER/CER/KER/SER),以及评估技能生成的相同五部分排行榜。将结果写入 leaderboard_cycle<N+1>.md。与 leaderboard_cycle<N>.md 对比。

决策表 —— 第 N+1 轮与第 N 轮对比:

结果操作
目标类别的 KER 明显下降(例如药物 KER 相对下降 20% 或更多)✅ 保留 .nemo。更新排行榜。如果要部署,请进入步骤 4f。
KER 略有改善,但你希望效果更好返回 /digital-health-clinical-asr-build,扩充清单。小型清单很少能从超参数调整中受益 —— 信号密度胜过 LR 扫描。
KER 变差在小型清单上过拟合。返回 /digital-health-clinical-asr-build 并扩充数据,然后再训练。不要在相同数据上加大调参力度。
没有可测量的变化部分类别可能已包含在基础模型的词汇表中。在断定训练“没有帮助”之前,先检查各类别的数值是否合理。
4f. (可选)部署为 Riva NIM

将 .nemo 交给 /riva-asr-custom。明确指定源架构 —— /riva-asr-custom 无法仅凭 .nemo 可靠识别 CTC、RNNT 或 TDT,错误的 NIM 容器会生成有问题的 RMIR,且不会给出明确错误:

源解码器riva-build 标志NIM 容器系列
Conformer-CTCdecoder=greedy_ctcparakeet-*-ctc-*
Conformer-RNNTdecoder=nemoparakeet-rnnt-*
Conformer-TDT(默认)decoder=nemoparakeet-tdt-*
Cache-Aware RNNT(Nemotron 流式)decoder=nemonemotron-streaming-* ⚠ 此基础模型上的 SFT 已损坏,详见“限制”

部署后:针对新端点(ASR_ENDPOINT=localhost:50051)重新运行 /digital-health-clinical-asr-eval,验证生产服务的数值是否与离线数值一致。任何差异都来自 Riva 预处理或 riva-build 标志,而非模型。转交给 /riva-asr-custom。

示例

场景 A —— 达到门槛。 用户:“药物 KER 为 0.42,共 130 行。要做 SFT 吗?” → 是(已达到门槛)。parakeet-tdt-0.6b-v2(已验证从 0.513 降至 0.128)。没有本地 GPU?步骤 4a(Brev)→ 4b(拆分)→ 4d(标准 SFT)→ 4e(离线重新评估)。如果第 2 轮药物 KER 相对下降 ≥ 20%,则保留 .nemo;否则返回 /digital-health-clinical-asr-build。

场景 B —— Nemotron Streaming。 用户:“对 nvidia/nemotron-speech-streaming-en-0.6b 做 SFT?” → 否(UNK 崩溃)。改用 parakeet-tdt-0.6b-v2。Riva 会将非流式基础模型分块,以支持流式服务 —— 基础模型无需原生支持流式处理。

场景 C —— 第 2 轮 KER 未变化。 用户:“KER 几乎没变。” → 返回 /digital-health-clinical-asr-build。信号密度胜过 LR 扫描。如果 magpie_g2p 行效果差,而 merriam-webster 行效果好,差距来自发音覆盖率 —— 请参阅 /digital-health-clinical-asr-build 步骤 2d。

生成的产物

  • train.jsonl、validation.jsonl —— 感知术语的拆分(步骤 4b)
  • adapted_model.nemo —— 微调后的模型(步骤 4d)
  • training_run_info.json —— 超参数、数据集统计信息、训练结束时的指标
  • offline_hyps.jsonl —— 第 N+1 轮转录假设(步骤 4e)
  • leaderboard_cycle<N+1>.md —— 第 N+1 轮五部分排行榜
  • (可选,步骤 4f 之后) 已部署的 NIM 端点(交由 /riva-asr-custom 处理)

故障排查

  • Stage 4 训练在第一步后崩溃为全 UNK → 你使用的是缓存感知型流式 RNNT 基础模型(nemotron-speech-streaming-en-0.6b)。请改用 nvidia/parakeet-tdt-0.6b-v2(推荐的默认选择)或 nvidia/stt_en_conformer_ctc_large(旧版备用选择)。流式 RNNT SFT 路径已损坏;不要尝试使用不同的超参数重试。
  • NeMo 容器内的清单路径无法解析 → 主机路径(例如 $HOME/…)需要重写为 /workspace/…。重写代码片段请参见 references/container-paths.md。
  • Cycle N+1 的 KER 与 Cycle N 相比没有变化 → 如果你使用的是 parakeet-tdt-0.6b-v2 和上述配方,这几乎总是意味着清单信号密度过低。先扩充清单;不要扫描 LR。(如果你用的是旧式适配器配方,而不是标准 SFT,适配器权重可能仍停留在零初始化状态——请改用标准 SFT。)
  • Cycle N+1 的 KER 变差 → 在过小的清单上过拟合。请转到 /digital-health-clinical-asr-build 并扩充清单。
  • Riva 提供服务时的指标与离线指标不一致 → 差异出在 Riva 预处理或 riva-build 标志,而不是模型。请转到 /riva-asr-custom。
  • bf16-mixed 精度错误 → 某些 GPU(较旧的 Turing,以及所有 Volta)不支持 BF16。请改用 fp32 并减小 batch_size。只有在 fp32 太慢时才使用 fp16-mixed——TDT 解码器使用 fp16 可能产生 NaN 损失,因此请尽早检查损失曲线。
  • 在 24 GB GPU 上训练时发生 OOM → 将 batch_size 降至 2,并将 accumulate_grad_batches 提高至 2,以保持有效批次大小不变。

限制

  • 在 TDT/RNNT 解码器上使用适配器式 SFT 已损坏。 经实测确认:较早的 LinearAdapter-mixin 配方在 TDT 和 RNNT 解码器上无论 LR 为何,都会产生 72 个 NaN 张量。改用 NeMo 的标准全模型 SFT(speech_to_text_finetune.py)后问题解决——本技能推荐的正是这种方式。不要在 TDT/RNNT 基础模型上尝试适配器 SFT。
  • 不要对 nemotron-speech-streaming-en-0.6b 做 SFT。 仅用于流式处理的 NVCF 函数,其 SFT 路径不可靠(会崩溃为 UNK)。部署时若要提供流式服务,Riva 会对非流式基础模型进行分块处理。
  • 小型清单很容易过拟合。 总行数少于约 100 行,或每个优先类别少于约 5 行时,Cycle N+1 的指标会有较大波动。信任较小的 KER 降幅前,请先扩充清单。
  • 默认仅支持英语。 基础模型表仅针对 en-US。其他地区语言需要使用不同的基础模型,并重新验证 SFT 配方。
  • 没有开箱即用的驱动程序。 用户需要自行编写训练驱动程序的布局,包括输出路径、运行命名和排行榜重新渲染。方法和配方可以迁移;Cycle 1 的具体指标取决于用户的清单。

后续步骤

  • 将 .nemo 部署为 NIM: /riva-asr-custom(请明确传入源架构)。
  • 扩充清单以用于 Cycle N+2: /digital-health-clinical-asr-build。
  • 重新评估该 Cycle: /digital-health-clinical-asr-eval(针对新端点或直接针对新的 .nemo)。
  • 横向拓展到词语增强 / LM 融合 / 非临床 SFT 配方:/finetune-asr。

参考资料

  • references/stage4-finetune.md — 基础模型选择表、超参数依据、解码器到 NIM 容器的映射,以及比较 Cycle N+1 与 Cycle N 的决策树
  • references/container-paths.md — 为实现跨主机清单可移植性而将主机路径重写为 /workspace/ 路径(笔记本电脑 ↔ Brev ↔ NeMo 容器)

评论

支持 Markdown