Skip to content

[WIP]Add CS-FLEURS code-switched ASR benchmark with Mixed Error Rate scoring#1494

Open
Slyne wants to merge 12 commits into
NVIDIA-NeMo:mainfrom
Slyne:cs-fleurs-eval
Open

[WIP]Add CS-FLEURS code-switched ASR benchmark with Mixed Error Rate scoring#1494
Slyne wants to merge 12 commits into
NVIDIA-NeMo:mainfrom
Slyne:cs-fleurs-eval

Conversation

@Slyne

@Slyne Slyne commented Jun 22, 2026

Copy link
Copy Markdown

What

Adds CS-FLEURS (paper), a massively multilingual code-switched extension of FLEURS (52 languages, 113 code-switched pairs), as an ASR benchmark group, plus a Mixed Error Rate (MER) scoring path in the audio evaluator.

Subtasks (ASR only): cs-fleurs.read (human-read, the paper's intended benchmark), cs-fleurs.mms (concatenative MMS-TTS), cs-fleurs.xtts-test1, cs-fleurs.xtts-test2 (generative XTTS-v2).

Why MER

Each utterance mixes two languages — and often two scripts — in one sentence. A single per-utterance CER-or-WER choice mis-scores it (e.g. whole-utterance CER over a cmn-eng sentence scores embedded English at the character level). MER counts scriptio-continua scripts (Han/kana/Hangul/Thai/Lao/Myanmar/Khmer) by character and space-delimited scripts by word within the same utterance, then scores with the standard word-level edit distance — the convention used for Mandarin-English code-switching (e.g. SEAME).

Changes

  • nemo_skills/dataset/cs-fleurs/ — new benchmark group: prepare.py (HF download + manifest build, with a download-skip guard for completed subsets), languages.py (language metadata, CER/grapheme policy), audio_score.py (per-test-set + overall aggregation), per-subtask configs.
  • nemo_skills/evaluation/evaluator/audio.py — adds mixed_segment() (multi-script tokenizer, with optional grapheme-cluster mode for combining-mark scripts), _grapheme_clusters(), and evaluate_mer(). Wired into the Multilingual-ASR branch.
  • Docsdocs/evaluation/speech-audio.md CS-FLEURS section + MER explanation + a known-limitation note.
  • Teststests/test_cs_fleurs.py, tests/test_mer_segmentation.py; registers cs-fleurs in test_datasets.py and excludes it from GPU auto-prepare (heavy HF download).

No impact on other datasets

MER is gated behind extra_fields["use_mer"], which only CS-FLEURS sets. The evaluator change is a prepended if use_mer: branch — the existing use_cer/WER logic is byte-identical. fleurs and covost2 (the other Multilingual-ASR consumers) never set the flag, so their scoring is unchanged. cs-fleurs/audio_score.py is private to this benchmark.

How to run

ns prepare_data cs-fleurs --data_dir /path/to/data --cluster <cluster>
# then evaluate with your audio model as usual; results report MER in the wer* column

Known limitation (reviewer input welcome)

The shared multilingual normalization removes Unicode combining marks (Mn) as "diacritics" — correct for Latin accents, but it strips meaning-bearing vowel/tone marks in Thai/Myanmar (e.g. ที่), so CER/MER for those languages is computed over consonant skeletons. This is pre-existing (affects the plain use_cer path and fleurs too), not introduced here, and affects only ~695 of ~49k records. A proper fix needs script-aware normalization in the shared evaluator (would change fleurs numbers), so it's deferred pending maintainer guidance. Details in the docs.

Testing

  • Unit tests for the MER tokenizer (all 5 scripts, codepoint + grapheme modes) and evaluate_mer scoring — passing.
  • Scoring helpers and aggregation unit-tested.
  • Not yet done: full on-cluster eval with the real multilingual model (off-the-shelf English models can't transcribe these languages meaningfully); the scoring logic is verified directly with controlled reference/hypothesis pairs.

Summary by CodeRabbit

Release Notes

  • New Features
    • Added CS-FLEURS benchmark support with dataset metadata, audio score aggregation across subtasks, and per-subtask audio evaluation profiles.
    • Introduced Mixed Error Rate (MER) scoring for code-switched ASR, including script-aware tokenization and optional grapheme-cluster handling.
    • Added a CS-FLEURS preparation CLI to generate test manifests for selected subtasks.
  • Documentation
    • Documented CS-FLEURS setup, MER/CER scoring, and a known Thai/Myanmar normalization limitation; included baseline MER references.
  • Tests
    • Added unit tests for CS-FLEURS helpers and MER segmentation/evaluation, plus updated dataset and GPU test coverage/exclusions.

Slyne and others added 5 commits June 22, 2026 15:25
New benchmark group nemo_skills/dataset/cs-fleurs/ (paper arXiv 2509.14161,
HF byan/cs-fleurs) covering the read / mms / xtts-test1 / xtts-test2 test
sets as ASR-only sub-benchmarks. Reuses the existing audio evaluator's
Multilingual-ASR path (same as fleurs): per-language CER for scriptio-continua
matrix languages (cmn/jpn/kor/tha/...), WER otherwise; subset_for_metrics is
the code-switched pair. prepare.py downloads from HF and roots audio at
NEMO_SKILLS_AUDIO_ROOT (default /data) like librispeech-pc/musan. Includes a
group score aggregator and a docs section. No existing files modified beyond
an appended docs section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: slyned <slyned@nvidia.com>
_download_subset re-fetched from HuggingFace on every prepare run, which could stall/hang when the (large) audio corpus was already present. Check for a complete local copy (metadata + matching .wav count, or metadata only under --no-audio) and return early, re-downloading only when incomplete.

Signed-off-by: slyned <slyned@nvidia.com>
- Exclude cs-fleurs from gpu-tests/test_eval.py auto-prepare (HF download,
  mirrors the existing fleurs group exclusion).
- Add network-free unit tests for the custom scoring helpers: pair parsing,
  CER-vs-WER language decision, and entry-weighted group aggregation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: slyned <slyned@nvidia.com>
Add cs-fleurs (own dataset; distinct from fleurs) to the DATASETS list,
matching how contextual-earnings22 is listed. Reword the GPU exclusion comment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: slyned <slyned@nvidia.com>
Code-switched utterances mix scriptio-continua scripts (counted by character)
with space-delimited scripts (counted by word) in one sentence, so a single
per-utterance CER/WER switch mis-scores them. Add a true MER path:

- audio.py: mixed_segment() tokenizes mixed text (Han/kana/Hangul/Thai/Lao/
  Myanmar/Khmer split into units, Latin runs kept as words), with optional
  grapheme-cluster mode for combining-mark scripts (Thai/Myanmar). evaluate_mer()
  normalizes -> segments -> word-level edit distance, reported under wer* keys.
  Wired into the Multilingual-ASR branch behind extra_fields["use_mer"], which
  defaults False so fleurs and all other datasets are unchanged.
- cs-fleurs/prepare.py: set use_mer=True; mer_grapheme=True only when a side is
  a combining-mark script (Thai/Lao/Myanmar/Khmer).
- cs-fleurs/languages.py: GRAPHEME_CLUSTER_LANGS + uses_grapheme().
- audio_score.py: emit zero-valued summed metrics instead of dropping them.
- tests: mixed_segment coverage + grapheme tests (test_mer_segmentation.py),
  uses_grapheme + helper-fallback + zero-sum tests (test_cs_fleurs.py).

Not yet runtime-validated: evaluate_mer needs jiwer (runs on CI/cluster), and
the Thai/Myanmar diacritic-normalization interaction needs GPU eval check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: slyned <slyned@nvidia.com>
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds the CS-FLEURS code-switched ASR benchmark as a new dataset group with four subsets (read, mms, xtts-test1, xtts-test2). Implements Mixed Error Rate (MER) tokenization and evaluation in the audio evaluator, a HuggingFace-based data preparation CLI, language metadata helpers, group-level score aggregation, unit tests, and documentation.

Changes

CS-FLEURS Benchmark Integration

Layer / File(s) Summary
Language metadata and scoring predicates
nemo_skills/dataset/cs-fleurs/languages.py
Defines CS_FLEURS_LANGUAGES mapping with ISO 639-3 codes to display names and ISO 639-1 codes, CER_LANGS and GRAPHEME_CLUSTER_LANGS sets, and helpers split_pair, get_lang_name, get_iso1, uses_cer, uses_grapheme for language-aware scoring decisions.
Language metadata unit tests
tests/test_cs_fleurs.py (TestSplitPair, TestGetIso1, TestGetLangName, TestUsesCer, TestUsesGrapheme)
Tests language pair parsing including hyphen/underscore normalization, ISO 639-1 code lookups with None handling for codes lacking an ISO-1 form, language name resolution, CER vs WER selection based on matrix language, and grapheme-cluster usage predicates.
MER tokenization and evaluate_mer in audio evaluator
nemo_skills/evaluation/evaluator/audio.py (mixed_segment, VALID_NORMALIZATION_MODES, lower_nopunct mode, evaluate_mer)
Adds mixed_segment tokenizer with scriptio-continua Unicode detection, optional grapheme-cluster grouping for Thai/Myanmar combining marks, lower_nopunct normalization mode, and evaluate_mer function that segments normalized reference/hypothesis and computes MER via word-level edit distance.
MER tokenization and evaluation unit tests
tests/test_mer_segmentation.py
Tests mixed_segment tokenization across scripts (Latin word-based, CJK character-based, Thai/Myanmar codepoint-based) and grapheme-cluster handling, plus end-to-end evaluate_mer assertions for perfect matches, token substitutions, and empty reference handling, and lower_nopunct normalization preserving combining marks.
MER routing and CER adjustment in evaluate_sample
nemo_skills/evaluation/evaluator/audio.py (Multilingual-ASR branch)
Routes use_mer=true samples in evaluate_sample to evaluate_mer before the existing use_cer fallback, passing mer_grapheme through to the grapheme parameter; adjusts parallel CER computation to use lower_nopunct normalization mode when MER is enabled.
CS-FLEURS dataset package and subset configs
nemo_skills/dataset/cs-fleurs/__init__.py, nemo_skills/dataset/cs-fleurs/read/__init__.py, nemo_skills/dataset/cs-fleurs/mms/__init__.py, nemo_skills/dataset/cs-fleurs/xtts-test1/__init__.py, nemo_skills/dataset/cs-fleurs/xtts-test2/__init__.py
Creates the cs-fleurs group package with REQUIRES_DATA_DIR, IS_BENCHMARK_GROUP, SCORE_MODULE, and BENCHMARKS registry; each of the four subset packages defines identical METRICS_TYPE, EVAL_ARGS, and GENERATION_ARGS constants.
Dataset preparation CLI and record building
nemo_skills/dataset/cs-fleurs/prepare.py
Implements HuggingFace snapshot-download with local completeness checking, metadata.jsonl parsing, audio path resolution via NEMO_SKILLS_AUDIO_ROOT, manifest record construction populating use_cer/use_mer/mer_grapheme/language code extra_fields, prepare_cs_fleurs iterator, and main() CLI with --data_dir, --subsets, --no-audio flags.
Group-level score aggregation
nemo_skills/dataset/cs-fleurs/audio_score.py, tests/test_cs_fleurs.py (TestComputeScore)
Adds compute_score with SUBSET_NAMES filtering to known subsets, entry-weighted aggregation of wer/wer_macro, preservation of summed count metrics, computation of an "overall" aggregate across all non-zero-entry subsets, and unit tests validating aggregation semantics and zero-value preservation.
Test infrastructure and documentation
tests/test_datasets.py, tests/gpu-tests/test_eval.py, docs/evaluation/speech-audio.md
Registers cs-fleurs with test split in the dataset test list; excludes cs-fleurs from GPU auto-prep tests due to HuggingFace download requirement; adds CS-FLEURS section to speech-audio.md documenting MER scoring semantics (use_mer=true, character vs word segmentation), Unicode combining-mark limitations affecting Thai/Myanmar, dataset location references, data preparation CLI usage, and Whisper large-v3 baseline MER results.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as prepare.py main()
    participant HF as HuggingFace Hub
    participant PrepFunc as prepare_cs_fleurs()
    participant Langs as languages.py
    participant Record as _build_record()
    participant Evaluator as evaluate_sample()
    participant MER as evaluate_mer()

    CLI->>PrepFunc: call with data_dir, subsets
    PrepFunc->>HF: snapshot_download(metadata.jsonl + audio)
    HF-->>PrepFunc: local files
    PrepFunc->>Record: iterate metadata rows
    Record->>Langs: split_pair(), uses_cer(), uses_grapheme()
    Langs-->>Record: matrix/embedded codes, scoring flags
    Record-->>PrepFunc: manifest record with use_mer, mer_grapheme
    PrepFunc-->>CLI: write test.jsonl per subset

    Note over Evaluator,MER: At evaluation time
    Evaluator->>Evaluator: read use_mer from extra_fields
    Evaluator->>MER: evaluate_mer(ref, hyp, grapheme=mer_grapheme)
    MER->>MER: mixed_segment(text) → tokens
    MER->>MER: _wer_with_counts(tokens)
    MER-->>Evaluator: wer* metrics dict
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • NVIDIA-NeMo/Skills#1476: Modifies nemo_skills/evaluation/evaluator/audio.py in the same evaluate_sample Multilingual-ASR branching section, adding CER alongside WER outputs — directly adjacent to where use_mer routing is inserted in this PR.

Suggested labels

run GPU tests

Suggested reviewers

  • naymaraq
  • Jorjeous
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title '[WIP]Add CS-FLEURS code-switched ASR benchmark with Mixed Error Rate scoring' directly describes the main changes: adding a new CS-FLEURS benchmark and implementing MER scoring for code-switched ASR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/evaluation/speech-audio.md`:
- Around line 811-831: The CS-FLEURS documentation section is missing expected
results examples for tested models, which is required per the coding guidelines
for new benchmarks. Add a new section after the output structure showing example
evaluation commands (similar to how the prepare_data command is shown) and
include expected results output from at least one model you have tested with on
this benchmark. The expected results should demonstrate what the evaluation
output looks like, including any metrics or scores produced by the evaluation
run.
- Around line 824-831: The fenced code block displaying the data directory
structure is missing a language specification tag, which violates the
markdownlint MD040 rule. Add the `text` language identifier to the opening fence
of the code block that contains the directory structure output (the block
showing `<data_dir>/cs-fleurs/` and its subdirectories), changing the opening
from just triple backticks to ```text triple backticks.

In `@nemo_skills/dataset/cs-fleurs/audio_score.py`:
- Around line 63-70: The aggregation code is using .get() with default values
for required metric fields (num_entries, gen_seconds, success_rate, avg_tokens,
no_answer), which silently defaults to 0 when keys are missing and can hide
upstream contract breaks. Replace all the .get() calls with direct dictionary
access using square brackets (for example, metrics["num_entries"] instead of
metrics.get("num_entries", 0), metrics["gen_seconds"] instead of
metrics.get("gen_seconds", 0), metrics["success_rate"] instead of
metrics.get("success_rate", 0.0), metrics["avg_tokens"] instead of
metrics.get("avg_tokens", 0.0), and metrics["no_answer"] instead of
metrics.get("no_answer", 0.0)) to fail fast when required keys are missing.

In `@nemo_skills/dataset/cs-fleurs/languages.py`:
- Around line 106-127: The code currently fails silently when encountering
malformed or unknown language codes. In the split_pair function, add validation
to ensure the language parameter has the correct format after splitting, raising
an error for malformed input. In the get_lang_name and get_iso1 functions,
replace the .get() dictionary lookups with direct bracket notation access to
CS_FLEURS_LANGUAGES so that KeyError is raised immediately for unknown language
codes instead of silently returning fallback values, ensuring bad language codes
are caught early in the evaluation pipeline.

In `@nemo_skills/dataset/cs-fleurs/prepare.py`:
- Around line 45-47: The file nemo_skills/dataset/cs-fleurs/prepare.py has
formatting issues that are causing ruff-format to fail in the CI pipeline. Run
the ruff-format tool on this file to automatically reformat it according to the
project's formatting standards, then commit the formatted changes to resolve the
pre-commit check failure.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c9fa19ce-210c-4f8d-a6af-6223eec72341

📥 Commits

Reviewing files that changed from the base of the PR and between da85a88 and 9159169.

📒 Files selected for processing (14)
  • docs/evaluation/speech-audio.md
  • nemo_skills/dataset/cs-fleurs/__init__.py
  • nemo_skills/dataset/cs-fleurs/audio_score.py
  • nemo_skills/dataset/cs-fleurs/languages.py
  • nemo_skills/dataset/cs-fleurs/mms/__init__.py
  • nemo_skills/dataset/cs-fleurs/prepare.py
  • nemo_skills/dataset/cs-fleurs/read/__init__.py
  • nemo_skills/dataset/cs-fleurs/xtts-test1/__init__.py
  • nemo_skills/dataset/cs-fleurs/xtts-test2/__init__.py
  • nemo_skills/evaluation/evaluator/audio.py
  • tests/gpu-tests/test_eval.py
  • tests/test_cs_fleurs.py
  • tests/test_datasets.py
  • tests/test_mer_segmentation.py

Comment thread docs/evaluation/speech-audio.md
Comment thread docs/evaluation/speech-audio.md Outdated
Comment thread nemo_skills/dataset/cs-fleurs/audio_score.py Outdated
Comment thread nemo_skills/dataset/cs-fleurs/languages.py Outdated
Comment thread nemo_skills/dataset/cs-fleurs/prepare.py
Slyne and others added 3 commits June 22, 2026 16:44
- languages.py: add aze/swh (the two dataset codes missing from the table);
  make get_lang_name/get_iso1 fail fast (KeyError) on unknown codes instead of
  silently degrading, now that the table covers every CS-FLEURS language.
  Intentional None (languages with no ISO 639-1, e.g. ceb/yue) is preserved.
- audio_score.py: bracket-access the required num_entries (fail loudly if
  absent); presence-gate the optional generation metrics (success_rate /
  no_answer / gen_seconds) instead of fabricating 0.0 for pure-ASR runs.
- prepare.py: ruff-format (collapse _lang_spec to one line).
- docs: add 'text' language tag to the directory-structure code block (MD040).
- tests: update get_iso1/get_lang_name tests to assert fail-fast on unknown.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: slyned <slyned@nvidia.com>
Adds reference MER numbers (full read subset, 5818 utterances, greedy) from an
external multilingual model, scored via the benchmark's own MER path, satisfying
the CONTRIBUTING requirement for example evaluation results. Overall MER 25.75%.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: slyned <slyned@nvidia.com>
Reformat the Whisper large-v3 baseline from a markdown table into a ```text
'Example output' block, matching the ContextASR-Bench / Contextual Earnings-22
sections in the same doc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: slyned <slyned@nvidia.com>
@Slyne

Slyne commented Jun 23, 2026

Copy link
Copy Markdown
Author

Comment thread docs/evaluation/speech-audio.md Outdated
**Scoring — Mixed Error Rate (MER).** Because each utterance mixes two scripts, a single per-utterance CER-or-WER choice mis-scores it (e.g. whole-utterance CER over a `cmn-eng` sentence scores the embedded English at the character level). Instead, records set `use_mer=true` and the audio evaluator computes a Mixed Error Rate: scriptio-continua scripts (Han / kana / Hangul / Thai / Lao / Myanmar / Khmer) are counted by character and space-delimited scripts (e.g. Latin) by word, within the same utterance, then scored with the standard word-level edit distance. This matches the standard MER used for Mandarin-English code-switching (e.g. SEAME). The mixed figure is reported in the headline `wer*` column (a parallel pure-CER column is still emitted). `subset_for_metrics` is the code-switched pair (e.g. `ara-eng`), giving a per-pair breakdown; the group score module adds a per-test-set and overall entry-weighted figure. Scoring uses the same multilingual normalization as `fleurs` (case-insensitive, punctuation/diacritics removed). MER only affects CS-FLEURS — it is gated behind `use_mer`, which monolingual benchmarks (including `fleurs`) never set, so their CER/WER behavior is unchanged.

!!! warning "Known limitation: Thai/Myanmar diacritic stripping (reviewers' input welcome)"
The shared multilingual normalization removes Unicode combining marks (category `Mn`, and turns `Mc` into spaces) as "diacritics". This is correct for Latin accents but **destroys meaning-bearing vowel and tone marks in Thai/Myanmar** (e.g. `ที่` → `ท`), so CER/MER for those languages is computed over consonant skeletons and under-counts real errors. This is **pre-existing** — it affects the plain `use_cer` path and `fleurs` too, not just MER. For combining-mark scripts the prepare step sets `mer_grapheme=true` so grapheme-cluster segmentation *would* keep marks together, but it is currently a no-op because normalization strips the marks first. Properly fixing this needs script-aware normalization (preserve `Mn`/`Mc` for Thai/Lao/Myanmar/Khmer/Indic) in the shared evaluator, which would change `fleurs` numbers too — deferred pending maintainer guidance. Affects only ~695 of ~49k CS-FLEURS records (Thai + Myanmar).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @KunalDhawan could you help with this issue? Need some input here. whether we want to change our normalization pipeline.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re the unit test issue: #1494 (comment)
The unit-tests job is dying at the Login to GHCR step (~13s in, before pytest runs), because fork PRs don't get the registry secrets to pull the test image. Could you raise the PR from a branch instead of a fork please?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re the scoring issue: thanks for flagging! I'd keep the current approach for this PR: the gated preserve_marks (for MER) + lower_nopunct (for the paper-comparable CER), both behind use_mer, is the right scope, it's correct for CS-FLEURS and leaves fleurs/covost2 untouched. So no change needed here.
On the broader question: yes, the shared multilingual normalizer stripping Mn/Mc is genuinely wrong for abugida scripts (Thai/Lao/Myanmar/Khmer/Indic) and under-reports errors in fleurs too, not just MER. But making it script-aware globally would change our existing fleurs baselines, so I don't want to fold that into a benchmark-addition PR. Let's do it as a separate change with explicit re-baselining + a note in the docs.

The CS-FLEURS paper reports 'case insensitive and unpunctuated character error
rate'. Add a mark-preserving normalization mode (lower_nopunct: lowercase +
drop punctuation, keep Mn/Mc combining marks) and route the parallel CER column
through it for cs-fleurs (gated on use_mer) so its cer* numbers are comparable
to the paper. Monolingual benchmarks (fleurs/covost2) keep the existing
multilingual normalization unchanged. MER (wer*) is unaffected.

Tests: lower_nopunct preserves Thai/Myanmar marks, lowercases, de-punctuates,
and differs from no_tn_itn (which strips marks). Docs updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: slyned <slyned@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_mer_segmentation.py`:
- Around line 134-136: In the test_preserves_myanmar_marks method, the assertion
string contains a Thai combining mark (U+0E48) instead of a Myanmar combining
mark, which defeats the purpose of testing Myanmar mark preservation. Replace
the Thai mark with a Myanmar combining mark such as U+1037 to ensure the test
actually validates that Myanmar combining marks are properly preserved during
normalization with lower_nopunct mode.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e75f0292-a58b-4065-910b-4ad0817797c6

📥 Commits

Reviewing files that changed from the base of the PR and between 87cd1b8 and c51df8c.

📒 Files selected for processing (3)
  • docs/evaluation/speech-audio.md
  • nemo_skills/evaluation/evaluator/audio.py
  • tests/test_mer_segmentation.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • nemo_skills/evaluation/evaluator/audio.py
  • docs/evaluation/speech-audio.md

Comment on lines +134 to +136
def test_preserves_myanmar_marks(self):
assert self._norm()("ကျော่.", mode="lower_nopunct") == "ကျော่"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

test_preserves_myanmar_marks is currently validating a Thai mark, not a Myanmar mark.

Line 135 uses (Thai U+0E48), so this test does not actually assert Myanmar combining-mark preservation. Replace it with a Myanmar combining mark (for example \u1037) to match the test intent.

Proposed fix
     def test_preserves_myanmar_marks(self):
-        assert self._norm()("ကျော่.", mode="lower_nopunct") == "ကျော่"
+        assert self._norm()("ကျော\u1037.", mode="lower_nopunct") == "ကျော\u1037"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_mer_segmentation.py` around lines 134 - 136, In the
test_preserves_myanmar_marks method, the assertion string contains a Thai
combining mark (U+0E48) instead of a Myanmar combining mark, which defeats the
purpose of testing Myanmar mark preservation. Replace the Thai mark with a
Myanmar combining mark such as U+1037 to ensure the test actually validates that
Myanmar combining marks are properly preserved during normalization with
lower_nopunct mode.

Slyne and others added 3 commits June 23, 2026 14:51
Add a preserve_marks option to MultilingualTextNormalizer (keeps category-M
combining marks while still removing symbols/punctuation, via NFC). Enable it
for cs-fleurs MER (gated on use_mer) so MER counts Thai/Myanmar vowel and tone
marks and grapheme-cluster segmentation is effective, while num2words and other
multilingual steps still apply. Monolingual benchmarks (fleurs/covost2) keep
the existing mark-stripping behavior. Both MER (preserve_marks) and the CER
column (lower_nopunct) now preserve marks for cs-fleurs.

Tests + docs updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: slyned <slyned@nvidia.com>
Refresh the Whisper large-v3 Example output with the current evaluator's numbers
(mark-preserving MER + paper-comparable CER per pair; overall MER 24.51, CER
16.47 / ~18.0 macro vs paper ~19.8). De-duplicate the CER-normalization detail
that overlapped the marks note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: slyned <slyned@nvidia.com>
Add a strip_whitespace option to evaluate_cer (removes all whitespace before
scoring, so CER counts only non-space characters) and enable it for cs-fleurs
(gated on use_mer). This matches the CS-FLEURS paper's character error rate,
where spaces are not counted; default False keeps existing behavior, so
fleurs/covost2 are unchanged.

Resolves the apparent CER mismatch: with whitespace excluded, the macro-averaged
read CER is 19.54% vs the paper's ~19.8% (the prior gap was spaces-counted +
micro-vs-macro averaging). Updated baseline numbers and tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: slyned <slyned@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants