Generated banner for Nemotron Asr Finetune
Generated logo for Nemotron Asr Finetune

Nemotron Asr Finetune

NVIDIAOfficialCreated by Nemotron Speech TeamDistributed by NVIDIA

  • Skill
  • Workflow
  • Data and AI
  • Apache-2.0
  • Medium risk
  • Has scripts

From the author

Orchestration skill for NVIDIA Nemotron Speech (Riva) / NeMo ASR domain and language adaptation. Given a goal like "improve/fine-tune ASR for my domain or language", it scopes the task, picks the cheapest sufficient path (word boosting → n-gram LM → fine-tuning), delegates each stage to the right sub-skill (data generation, training, evaluation, deployment), and answers cost/time/data questions along the way.
— the description by Nemotron Speech Team

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill acts as an intelligent orchestrator for adapting NVIDIA Nemotron Speech (Riva) ASR models to specific domains or languages. Rather than jumping straight to training, it guides users through a cost-effective ladder of customization techniques, starting with word boosting and n-gram language models before escalating to full acoustic fine-tuning. It manages the end-to-end lifecycle by scoping requirements, delegating tasks to specialized sub-skills for data generation, training, evaluation, and deployment, and providing data-driven estimates for time, cost, and hardware requirements.

What it does

  • Scopes ASR customization goals based on domain, language, and performance targets.
  • Identifies the cheapest sufficient path for improvement, from word boosting to full fine-tuning.
  • Delegates execution to specialized sub-skills for data, training, evaluation, and deployment.
  • Performs pre-flight checks for dataset quality and environment compatibility.
  • Provides estimates for data volume, GPU requirements, and expected costs.
  • Maintains a structured workflow to ensure efficient, measurable model adaptation.

When to use it

  • When you need to improve ASR accuracy for a specific industry domain or jargon.
  • When you need to adapt an ASR model to a new language.
  • When you want to reduce Word Error Rate (WER) in noisy environments like call centers.
  • When you need to plan a cost-effective ASR customization strategy.
  • When you are unsure whether to use word boosting, language models, or full fine-tuning.

Advantages

  • Prevents unnecessary, expensive training by prioritizing cheaper, effective methods first.
  • Ensures a structured, repeatable approach to model adaptation.
  • Provides clear guidance on hardware selection and data requirements.
  • Reduces risk of catastrophic forgetting by enforcing data volume and mixing best practices.
  • Centralizes planning while leveraging specialized sub-skills for execution.

Usage examples

“I need to improve ASR accuracy for my medical domain, it gets jargon wrong.”
The agent will scope the jargon issues, suggest a word-boosting pilot to test offline, and outline the data requirements for potential fine-tuning if boosting is insufficient.
“How much data do I need to fine-tune an ASR model for a new language?”
The agent will explain the requirements for cross-language transfer versus training from scratch, emphasizing the need for real audio and providing a data-volume estimate.
“What is the cheapest way to improve my ASR model's performance?”
The agent will initiate a diagnostic process to measure the baseline WER and recommend the lowest-cost rung on the customization ladder, such as word boosting or n-gram LM.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/nvidia/nemotron-asr-finetune/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip nemotron-asr-finetune.zip -d .agents/skills

Documentation by Nemotron Speech Team

Nemotron Speech ASR Customization — Orchestration Skill

Note: "Nemotron Speech" is the public-facing name for what NVIDIA documents today as Riva / Riva NIM; the acoustic models are trained and fine-tuned with NVIDIA NeMo. Commands, config paths, imports, and doc URLs still use "Riva" / "NeMo" — the rename is brand-only. Do not rename them.

What This Skill Is

This is a high-level orchestration skill, not a step-by-step training manual. Its job, given a goal such as "I want to fine-tune ASR for my domain/language", is to:

  1. Scope the problem (how much real audio, target eval set, latency/hardware budget, language/domain).

  2. Choose the cheapest sufficient path — word boosting, n-gram LM fusion, or fine-tuning — and escalate only when quality falls short.

  3. Delegate each stage to the right sub-skill (data generation, training, evaluation, deployment/optimization).

  4. Answer cost/time/data questions along the way (how many hours to hit X% WER, synthetic vs real, L40S vs H100, expected cost).

It owns the plan and the routing; the sub-skills own the execution. When a needed sub-skill does not exist yet, this skill names it as a placeholder and gives interim guidance.

When to Use

Use for any request to make a Nemotron Speech / Riva ASR model work better on a specific domain or language — improving accuracy, reducing WER, adding a language, or planning a fine-tune. Start here even when the user names a specific technique: treat it as a candidate until the orchestration step confirms it is the cheapest sufficient path, then sequence the right sub-skills.

Orchestration Workflow

Run the loop below; each stage names the sub-skill it invokes. Full detail in references/workflow.md.

#StageWhat happensSub-skill
1State the goalCapture the target: domain/language, the errors, the metric.Orchestration (this skill)
2Clarify & scopeAsk the discovery questions: how much real audio? target eval set? latency/HW budget? deployment target?Orchestration
3Choose the pathPick the cheapest sufficient rung (boosting → n-gram LM → fine-tune). Escalate only if quality is short; experiment while proposing the full plan.Orchestration → Research/Training
4Get the data rightIf data is scarce/noisy: synthetic (TTS), TTS-friendly formatting, noise profiling/harvest, blend, score vendor samples; align customer data to training format; flag missing real data.SDG / Data
5TrainApply the recipe (configs, hyperparameters, replay/curriculum, GPU/OOM preflight) and run.Research / Training
6EvaluateNormalized WER on the domain set + A/B forgetting check on a general set; error-driven analysis to find the next lever.Evaluation
7Loop or shipIf short of target, loop to 4/5 with targeted data; else select/average checkpoints. Consult the user before more cycles.Orchestration
8DeployExport to NIM/HF, hot-swap the checkpoint, serve.Deployment / Optimization

Stages 4–8 are the fine-tune path (data → NeMo train → NeMo eval → Riva deploy). Cheaper rungs (boosting, custom vocab, n-gram LM) take a shorter branch owned by a single sub-skill — don't force them through the full loop. See the branch-by-rung table in references/workflow.md (§3b).

Before training (Stage 5), run the pre-flight dataset quality check (§4a): verify/convert audio to 16 kHz, and, on user request, audit transcript quality by running a reference pretrained model and checking WER against the provided ground truth. See references/workflow.md §4a.

Also before training (Stage 5), run the pre-flight environment/dependency check (§4b): if no NeMo is provided, pull the latest main (local execution) or the latest published container tag (container execution). If a NeMo checkout/install is already provided, check its version, but still recommend switching to latest main (staleness risk) and ask the user — if they insist on the provided one, proceed with it and only revisit once a concrete version issue (e.g. unsupported functionality) is actually hit. See references/workflow.md §4b.

Throughout, answer the "along the way" questions (data volume, synthetic vs real, hours to reach a WER target, cost, GPU choice) — see references/planning-answers.md.

Sub-Skills This Skill Calls

Detailed registry, invocation, and handoff contracts in references/sub-skills.md.

Role (per the architecture)PurposeSub-skill to invoke
Research / TrainingNeMo configs, recipes, fine-tuning, checkpoint averaging; also owns the NeMo-side word-boosting and n-gram LM pilotsnemo-speech-asr-finetune
SDG / Data DesignerSynthetic transcripts/text, noise profiling, vendor-data impact, blendsdata-designer (synthetic text; audio via TTS in nemotron-speech); placeholder: asr-data-profiling
EvaluationNormalized WER, A/B forgetting, error analysisOffline file WER → nemo-speech-asr-finetune; served-endpoint WER → nemotron-speech
Deployment / OptimizationNIM/Riva export, checkpoint swap, NIM-build optimization, servingnemotron-speech

If a sub-skill is unavailable, say so, give the interim guidance from the reference, and continue the plan.

Choosing The Path (cheapest first)

The scoping in Stage 3 selects the lowest-cost rung that can meet the target. Summary; full docs-grounded ladder in references/path-selection.md.

  • Word boosting — a bounded set of known words/names/jargon. Two realizations that are different artifacts: pilot (NeMo) to prove lift offline via GPU-PB context biasing (nemo-speech-asr-finetune), or deploy (Riva) to ship it via runtime boosted_lm_score (nemotron-speech) — different score systems, don't reuse one for the other. Runtime, no training either way. See references/path-selection.md.

  • Custom vocabulary / pronunciation — OOV or consistently mispronounced terms. Deploy-time. → Deployment sub-skill.

  • N-gram (KenLM) LM — domain phrasing/word-sequences when you have text but little audio. Two realizations, built the same way but deployed differently by architecture: pilot (NeMo, NGPU-LM) to prove lift offline (nemo-speech-asr-finetune), or deploy (Riva) to ship it (nemotron-speech). For CTC, rebuild the pilot corpus into a Riva word-level LM — don't ship the pilot artifact as-is. For RNN-T/TDT, the opposite: hand the pilot's .nemo artifact to Riva unchanged, no rebuild. See references/path-selection.md.

  • Fine-tune — real acoustic gaps (accents, noise, channel) with enough transcribed audio (NIM guide: 100+ h; ~10 h floor only if mixed to avoid catastrophic forgetting). Below ~10 h, do not recommend fine-tuning — recommend word boosting instead (severe catastrophic-forgetting/overfitting risk). → Research/Training.

  • Train from scratch / cross-language transfer — a new language with no suitable checkpoint (last resort). → Research/Training.

Ordering and per-model support follow the NVIDIA Speech NIM ASR customization guide: https://docs.nvidia.com/nim/speech/latest/asr/customization/customization.html.

Key Principles

  • Scope before you pick. Don't recommend fine-tuning before the discovery questions and a measured baseline.

  • Cheapest sufficient path. Escalate rungs only when the current one provably can't hit the target; you may experiment on a cheap rung while presenting the full fine-tuning plan.

  • Measure with a contract. Report normalized WER on the domain set plus an A/B forgetting check on a general set — never in-training logs alone.

  • Verify before you train. Run the pre-flight dataset quality check before Stage 5: verify/convert audio to 16 kHz, and, when the user asks, audit ground-truth transcripts by comparing them to a reference model's WER. Don't train on an unresampled or unaudited-on-request dataset. See references/workflow.md §4a.

  • Know your environment before you train. If no NeMo is provided, pull the latest main (or latest published container tag). If one is provided, check its version but still recommend latest main and ask the user first — a provided checkout always carries staleness risk. If they insist on keeping it, don't pull preemptively; only revisit once a concrete version issue (e.g. unsupported functionality) is actually hit. Record what was resolved in the ledger. See references/workflow.md §4b.

  • Delegate, don't reimplement. Route execution to the sub-skills; keep this skill focused on the plan, sequencing, and cost/time/data answers.

  • Real target-domain audio is the usual bottleneck. Prefer real data; use synthetic to fill measured gaps, kept separately weighted so it can be ablated.

  • Consult the user before extra tuning cycles, and when a needed sub-skill is a placeholder.

Source of Truth

TopicLocation
NIM Speech docs homehttps://docs.nvidia.com/nim/speech/latest/index.html
ASR customization guide (methods, per-model support)https://docs.nvidia.com/nim/speech/latest/asr/customization/customization.html
ASR support matrix (models & features)https://docs.nvidia.com/nim/speech/latest/reference/support-matrix/asr.html
NeMo fine-tuning (flags/config)docs/source/asr/fine_tuning.rst, and the nemo-speech-asr-finetune sub-skill
Riva ASR tutorials (boosting, LM, fine-tune)https://github.com/nvidia-riva/tutorials
Tokenizer extension to new language + acoustic fine-tunehttps://github.com/nvidia-riva/tutorials/blob/main/asr-extend-tokenizer-to-newlang-ft-acoustic-model.ipynb

Limitations

  • Orchestration only — execution happens in the sub-skills. Where a sub-skill is a placeholder, guidance is interim until it exists.

  • GPU required for the training rungs; deployment/serving is owned by the nemotron-speech sub-skill.

  • Model names, config paths, flags, and per-model feature support drift across NeMo/Riva releases — verify against the support matrix and the current checkout.

  • Public branding is "Nemotron Speech"; commands, imports, config paths, and doc URLs still use "Riva" / "NeMo" — do not rename.

Files

scripts/main.py

#!/usr/bin/env python3

# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Route ASR customization/orchestration prompts to the right bundled reference file.

This helper is intentionally small and deterministic. It does not run training,
evaluation, or invoke sub-skills; the orchestration skill drives those. The default
route is the orchestration workflow, since the skill's job is to scope the task and
sequence sub-skills before anything else.
"""

from __future__ import annotations

import argparse
import json
import re
import sys
from dataclasses import dataclass
from typing import Iterable


SKILL_NAME = "nemotron-asr-finetune"


@dataclass(frozen=True)
class Route:
    name: str
    reference: str
    reason: str
    patterns: tuple[str, ...]
    next_steps: tuple[str, ...]


DOMAIN_CUES = (
    r"\bfine[- ]?tun",
    r"\bfinetun",
    r"\bcustomiz",
    r"\badapt\b.*\b(asr|language|domain|model)\b",
    r"\bdomain adaptation\b",
    r"\bnew language\b",
    r"\bimprove\b.*\b(asr|accuracy|recognition|transcri)",
    r"\basr\b",
    r"\bspeech[- ]to[- ]text\b",
    r"\btranscri(?:be|bing|ption)\b",
    r"\brecogniz",
    r"\bmishear",
    r"\bword boost",
    r"\bn-?gram\b",
    r"\bkenlm\b",
    r"\blanguage model\b",
    r"\breduce (?:the )?wer\b",
    r"\bwer\b",
    r"\bnemo\b",
    r"\bparakeet\b",
    r"\bcanary\b",
    r"\bnemotron\b.*\b(asr|speech|streaming)\b",
)


ROUTES: tuple[Route, ...] = (
    Route(
        name="sub-skills",
        reference="references/sub-skills.md",
        reason="Which sub-skill to invoke and its handoff contract.",
        patterns=(
            r"\bsub-?skill",
            r"\bdelegate\b",
            r"\binvoke\b",
            r"\bwhich skill\b",
            r"\bdata[- ]?designer\b",
            r"\bsynthetic data\b",
            r"\bnemo-speech-asr-finetune\b",
            r"\bnemotron-speech\b",
            r"\bevaluator\b",
            r"\bdeploy",
            r"\bexport\b",
            r"\bserve\b|\bserving\b",
            r"\bnoise profil",
            r"\bvendor data\b",
        ),
        next_steps=(
            "Read references/sub-skills.md.",
            "Invoke the sub-skill by name; if it is a placeholder, use the interim guidance and tell the user.",
            "Pass the handoff inputs listed for that sub-skill and integrate what it returns.",
        ),
    ),
    Route(
        name="planning-answers",
        reference="references/planning-answers.md",
        reason="Cost/time/data planning questions (hours, synthetic vs real, GPU choice, cost).",
        patterns=(
            r"\bhow much data\b",
            r"\bhow many hours\b",
            r"\bhours\b",
            r"\bcost\b",
            r"\bexpensive\b|\bcheap",
            r"\bbudget\b",
            r"\bl40s\b",
            r"\bh100\b",
            r"\bgpu\b.*\b(choice|which|pick)\b",
            r"\bsynthetic vs real\b",
            r"\bhow long\b",
            r"\bhit\b.*\bwer\b",
            r"\bto (?:reach|hit) \d",
        ),
        next_steps=(
            "Read references/planning-answers.md.",
            "Give ranges with assumptions; prefer a measured pilot over a guessed hours-to-WER number.",
            "Lead with the cheapest sufficient path's cost, then the full fine-tuning plan's cost.",
        ),
    ),
    Route(
        name="path-selection",
        reference="references/path-selection.md",
        reason="Choosing the cheapest sufficient rung (boosting / vocab / n-gram LM / fine-tune).",
        patterns=(
            r"\bwhich\b.*\b(option|approach|way|method|path|rung)\b",
            r"\bcheapest\b",
            r"\bword boost",
            r"\bboost",
            r"\bn-?gram\b",
            r"\bkenlm\b",
            r"\blanguage model\b",
            r"\bcustom vocab",
            r"\bpronunciation\b",
            r"\bfull fine[- ]?tune\b",
            r"\bfrom scratch\b",
            r"\bnot recogniz|\bmis-?recogniz",
            r"\bjargon\b|\bvocabulary\b|\bnames?\b",
            r"\bcatastrophic forgetting\b",
            r"\boverfit",
            r"\blimited data\b",
            r"\bsmall(?:er)? dataset\b",
            r"\bnot enough (?:data|audio|hours)\b",
            r"\bonly have\b.*\bhours?\b",
            r"\bboosting.tree\b",
            r"\bgpu-?pb\b",
            r"\bcontext.biasing\b",
            r"\bboosted_lm_score\b",
        ),
        next_steps=(
            "Read references/path-selection.md.",
            "Diagnose the failure mode and measure a baseline, then pick the lowest matching rung.",
            "Escalate the tuning method only if the target is missed; you may run a cheap-rung experiment now.",
        ),
    ),
    Route(
        name="workflow",
        reference="references/workflow.md",
        reason="The end-to-end orchestration loop: scope, choose path, data, train, evaluate, loop/ship, deploy.",
        patterns=(
            r"\bfine[- ]?tun",
            r"\bcustomiz",
            r"\bworkflow\b",
            r"\borchestrat",
            r"\bpipeline\b",
            r"\bscope\b|\bclarify\b",
            r"\bwhere do i start\b|\bhow do i start\b",
            r"\bnew language\b",
            r"\bdomain\b",
            r"\bimprove\b",
            r"\btrain\b",
            r"\bevaluat",
            r"\bloop\b|\bship\b",
            r"\bpre-?flight\b",
            r"\bsample rate\b",
            r"\b(?:8|16)\s?khz\b",
            r"\bresample",
            r"\bdata(?:set)? quality\b",
            r"\btranscript quality\b",
            r"\bground truth\b",
            r"\blabel (?:noise|quality)\b",
            r"\bnemo version\b",
            r"\bwhich nemo\b",
            r"\bpull\b.*\bmain\b",
            r"\bnemo checkout\b",
            r"\bpackage version\b",
            r"\bdependenc(?:y|ies)\b",
            r"\benvironment check\b",
            r"\bsymlink\b|\bsymbolic link\b",
            r"\bnpx skills add\b",
            r"\bproject-local\b",
        ),
        next_steps=(
            "Read references/workflow.md.",
            "Announce each step (Step N/8) and run the discovery questions before recommending a path.",
            "Delegate each stage to its sub-skill (see references/sub-skills.md) and answer planning questions along the way.",
        ),
    ),
)


def any_match(patterns: Iterable[str], text: str) -> bool:
    return any(re.search(pattern, text, flags=re.IGNORECASE) for pattern in patterns)


def score_route(route: Route, text: str) -> int:
    return sum(1 for pattern in route.patterns if re.search(pattern, text, flags=re.IGNORECASE))


def classify(question: str) -> dict[str, object]:
    text = " ".join(question.strip().split())
    if not text:
        return {
            "expected_skill": None, "route": None, "reference": None, "confidence": "low",
            "reason": "Empty prompt.",
            "next_steps": ["Do not activate nemotron-asr-finetune without a concrete ASR customization task."],
        }

    if not any_match(DOMAIN_CUES, text):
        return {
            "expected_skill": None, "route": None, "reference": None, "confidence": "low",
            "reason": "No NeMo/Riva ASR customization or fine-tuning cue was found.",
            "next_steps": ["Keep the nemotron-asr-finetune skill silent and use a more relevant workflow."],
        }

    # Stay silent when another provider/framework is named without an in-domain cue.
    strong_domain = (r"\briva\b", r"\bnemo\b", r"\bparakeet\b", r"\bcanary\b", r"\bnemotron\b",
                     r"\bspeech_to_text")
    other_provider = (r"\bopenai\b", r"\bwhisper\b", r"\bgpt\b", r"\bllama\b", r"\bmistral\b",
                      r"\bgemini\b", r"\bcohere\b")
    text_llm = (r"\btext (?:llm|model)\b", r"\bchat log", r"\bllm\b")
    if any_match(other_provider, text) and not any_match(strong_domain, text):
        return {
            "expected_skill": None, "route": None, "reference": None, "confidence": "low",
            "reason": "Another provider/framework was requested; not a NeMo/Riva ASR customization task.",
            "next_steps": ["Keep the nemotron-asr-finetune skill silent and use the appropriate workflow."],
        }
    if any_match(text_llm, text) and not any_match((r"\basr\b", r"\bspeech", r"\btranscri", r"\bwer\b"), text):
        return {
            "expected_skill": None, "route": None, "reference": None, "confidence": "low",
            "reason": "Text-LLM task, not ASR customization.",
            "next_steps": ["Keep the nemotron-asr-finetune skill silent and use the LLM fine-tuning workflow."],
        }

    # Defer pure export/deployment execution to the nemotron-speech skill. These are concrete
    # commands that skill owns; the orchestrator only sequences the deploy stage, never runs them.
    defer_cues = (r"\bnemo2riva\b", r"\briva-build\b", r"\briva-deploy\b", r"\brmir\b", r"\.riva\b")
    if any_match(defer_cues, text):
        return {
            "expected_skill": None, "route": None, "reference": None, "confidence": "low",
            "reason": "Export/deployment execution is owned by the nemotron-speech skill.",
            "next_steps": ["Defer to the nemotron-speech skill for nemo2riva / riva-build / riva-deploy and serving."],
        }

    # ROUTES are declared so the orchestration workflow is last (highest index).
    # Break ties (and the all-zero case) toward it: scoping and sequencing come first.
    scored = [(score_route(route, text), index, route) for index, route in enumerate(ROUTES)]
    scored.sort(key=lambda item: (-item[0], -item[1]))
    score, _, route = scored[0]

    confidence = "high" if score >= 2 else "medium"
    return {
        "expected_skill": SKILL_NAME,
        "route": route.name,
        "reference": route.reference,
        "confidence": confidence,
        "reason": route.reason,
        "next_steps": list(route.next_steps),
    }


def parse_args(argv: list[str]) -> argparse.Namespace:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("question", nargs="*", help="User prompt to classify.")
    parser.add_argument("--pretty", action="store_true", help="Pretty-print JSON.")
    return parser.parse_args(argv)


def main(argv: list[str] | None = None) -> int:
    args = parse_args(sys.argv[1:] if argv is None else argv)
    question = " ".join(args.question) if args.question else sys.stdin.read()
    result = classify(question)
    print(json.dumps(result, indent=2 if args.pretty else None, sort_keys=True))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs Python

Security

What our scanner noticed· Medium risk

  • Large base64-encoded blobs
  • Scripts that your agent may run

This skill includes scripts that your agent may run. Read them before you use it.

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
Nemotron Speech Team
Publisher
NVIDIA (Official)
Distributed by
NVIDIA
Source
NVIDIA/skills · skills/nemotron-asr-finetune · commit fce3cca
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE-APACHE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Nemotron Speech Team or NVIDIA.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download nemotron-asr-finetune.zip