Skip to content

Add ray data for audio modality - #1592

Merged
oyilmaz-nvidia merged 8 commits into
NVIDIA-NeMo:mainfrom
oyilmaz-nvidia:onur/ray-data-for-audio
Mar 16, 2026
Merged

Add ray data for audio modality#1592
oyilmaz-nvidia merged 8 commits into
NVIDIA-NeMo:mainfrom
oyilmaz-nvidia:onur/ray-data-for-audio

Conversation

@oyilmaz-nvidia

@oyilmaz-nvidia oyilmaz-nvidia commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

Description

This PR adds a few changes to test and benchmark Ray Data for audio workflows.

Fanouts

FLEURS is the only audio dataset with an initial manifest creation stage in this PR. The fanout is needed because CreateInitialManifestFleursStage takes a single input task and produces many AudioBatch tasks (one per transcript line). The other audio stages added in this PR (GetAudioDurationStage, ALMManifestWriterStage, InferenceAsrNemoStage) are 1-to-1 transforms, so they don't need fanout.

ALMManifestReaderStage also has IS_FANOUT_STAGE: True (it reads a JSONL and fans out one task per entry), but that's a pre-existing stage that just got ray_stage_spec() added.

Should You Add More Fanouts?

Not right now — the fanout is tied to a specific behavioral pattern (one-input → many-outputs), not to the audio modality itself. You'd only add fanouts for new audio stages that:

Checklist

  • I am familiar with the Contributing Guide.
  • New or Existing tests cover these changes.
  • The documentation is up to date with these changes.

@copy-pr-bot

copy-pr-bot Bot commented Mar 10, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@oyilmaz-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test a90a3af

Comment thread benchmarking/scripts/audio_fleurs_benchmark.py Outdated
Comment thread benchmarking/scripts/audio_fleurs_benchmark.py Outdated
Comment thread benchmarking/scripts/audio_fleurs_benchmark.py Outdated
Comment thread benchmarking/scripts/audio_fleurs_benchmark.py Outdated
Comment thread benchmarking/nightly-benchmark.yaml Outdated
Signed-off-by: Onur Yilmaz <oyilmaz@nvidia.com>
@oyilmaz-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test 235ef99

Comment thread tests/stages/audio/test_common.py Outdated

@praateekmahajan praateekmahajan 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.

Thanks @oyilmaz-nvidia

In the PR description can you explain the intent to change the stages to actors, and similarly which ones you converted to fanout and why, vs which ones you didn't and why?

script: alm_pipeline_benchmark.py
args: >-
--benchmark-results-path={session_entry_dir}
--input-manifest={curator_repo_dir}/tests/fixtures/audio/alm/sample_input.jsonl

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.

To run alm benchmark on large scale real world data, below are the following steps:

  1. Get data here. Size is 1.17 GB.
  2. Update --input-manifest= param with path of said download.
  3. set --repeat-factor=1 in this command.
  4. set timeout_s: 6000 or max permissible.

Same instructions for both xenna and ray.
Based on completed time for repeat-factor=1; consider increasing repeat factor to any number between 2-10.

Comment thread benchmarking/nightly-benchmark.yaml Outdated
--scratch-output-path={session_entry_dir}/scratch
--model-name=nvidia/stt_hy_fastconformer_hybrid_large_pc
--lang=hy_am
--split=dev

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.

For large scale benchmarks, here set --split=train. You should run on ~9x more data.

Comment thread tests/stages/audio/test_common.py Outdated
Comment thread nemo_curator/stages/audio/inference/asr_nemo.py Outdated
Comment thread nemo_curator/stages/audio/common.py Outdated
Comment thread nemo_curator/stages/audio/alm/alm_manifest_writer.py Outdated
Signed-off-by: Onur Yilmaz <oyilmaz@nvidia.com>
@oyilmaz-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test da6bf1e

…est.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Signed-off-by: Onur Yilmaz <35306097+oyilmaz-nvidia@users.noreply.github.com>
Comment on lines 19 to 23
def ray_stage_spec(self) -> dict[str, Any]:
from nemo_curator.backends.experimental.utils import RayStageSpecKeys

return {RayStageSpecKeys.IS_FANOUT_STAGE: True}
from nemo_curator.stages.audio.datasets.file_utils import download_file, extract_archive

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.

Syntax error: method definition floating between module-level imports

Lines 19–22 contain an indented def ray_stage_spec(self) body placed directly between top-level import statements. Python will raise an IndentationError the moment this module is collected, making the entire module unimportable. This is the complete implementation of the method (including the deferred RayStageSpecKeys import) that should have been placed inside the class body — it was apparently mis-applied here by mistake.

These four lines must be removed from the module scope entirely. The correct implementation already exists at line 146, but it is incomplete (see the companion comment below).

Suggested change
def ray_stage_spec(self) -> dict[str, Any]:
from nemo_curator.backends.experimental.utils import RayStageSpecKeys
return {RayStageSpecKeys.IS_FANOUT_STAGE: True}
from nemo_curator.stages.audio.datasets.file_utils import download_file, extract_archive
from nemo_curator.stages.audio.datasets.file_utils import download_file, extract_archive

Signed-off-by: Onur Yilmaz <oyilmaz@nvidia.com>
@oyilmaz-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test 3b4cb6c

Comment on lines +603 to +622
- name: audio_fleurs_raydata
enabled: true
script: audio_fleurs_benchmark.py
args: >-
--benchmark-results-path={session_entry_dir}
--scratch-output-path={session_entry_dir}/scratch
--model-name=nvidia/stt_hy_fastconformer_hybrid_large_pc
--lang=hy_am
--split=train
--wer-threshold=5.5
--gpus=1
--executor=ray_data
ray:
num_cpus: 64
num_gpus: 4
enable_object_spilling: false
sink_data:
- name: slack
ping_on_failure:
- U03C41SNADV # Aaftab V

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.

No timeout_s for train-split benchmarks

Both audio_fleurs_raydata (new) and audio_fleurs_xenna (changed from devtrain) now process the full Armenian FLEURS training split, which is considerably larger than dev. Without a timeout_s, a slow download, a hung Ray worker, or unexpectedly slow ASR inference could cause these entries to block the entire nightly run indefinitely.

The alm_pipeline_ray_data entry added in this same PR does include timeout_s: 600 for reference. Consider adding a generous but bounded timeout to both audio-fleurs entries, e.g.:

  - name: audio_fleurs_raydata
    enabled: true
    timeout_s: 7200   # 2 h ceiling for train-split download + inference
    script: audio_fleurs_benchmark.py
    ...

and similarly for audio_fleurs_xenna.

@mohammadaaftabv

Copy link
Copy Markdown
Contributor

Looks Good to me.

@praateekmahajan praateekmahajan 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.

PR LGTM. I do think we should run with a larger dataset than this since a 2-3 minute tests won't tell us much about the autoscaling behaviors of the frameworks or help us catch regressions

@sarahyurick

Copy link
Copy Markdown
Contributor

/ok to test bd25cbc

from dataclasses import dataclass
from typing import Any

from nemo_curator.backends.experimental.utils import RayStageSpecKeys

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.

Module-level Ray import still present

RayStageSpecKeys is imported at module level (line 19), and nemo_curator/backends/experimental/utils.py has import ray at its top level (line 19 of that file). This means every import of CreateInitialManifestFleursStage now transitively requires Ray to be installed — even in Xenna-only environments.

Concretely, test_get_fleurs_url_list_builds_urls and test_process_transcript_parses_tsv both call _import_stage_module(), which now pulls in ray and will raise an ImportError in environments without Ray installed. Since ray_stage_spec() is only ever called by the Ray Data backend, the import should be deferred to inside that method:

def ray_stage_spec(self) -> dict[str, Any]:
    from nemo_curator.backends.experimental.utils import RayStageSpecKeys
    return {RayStageSpecKeys.IS_FANOUT_STAGE: True}

Then remove the module-level from nemo_curator.backends.experimental.utils import RayStageSpecKeys on line 19.

Comment on lines +603 to +622
- name: audio_fleurs_raydata
enabled: true
script: audio_fleurs_benchmark.py
args: >-
--benchmark-results-path={session_entry_dir}
--scratch-output-path={session_entry_dir}/scratch
--model-name=nvidia/stt_hy_fastconformer_hybrid_large_pc
--lang=hy_am
--split=train
--wer-threshold=5.5
--gpus=1
--executor=ray_data
ray:
num_cpus: 64
num_gpus: 4
enable_object_spilling: false
sink_data:
- name: slack
ping_on_failure:
- U03C41SNADV # Aaftab V

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.

Missing requirements for audio_fleurs_raydata and audio_fleurs_xenna

Neither audio_fleurs_raydata nor audio_fleurs_xenna (both processing the full train split now) define a requirements block, while the other new entry in this PR — alm_pipeline_ray_data — does:

requirements:
  - metric: is_success
    exact_value: true
  - metric: total_builder_windows
    min_value: 1
  - metric: total_filtered_windows
    min_value: 1

Without requirements, the nightly framework cannot distinguish between a run that crashes (and writes is_success: false) and a run that silently produces zero output records (all audio filtered by WER threshold). The benchmarking framework will mark these entries as "passed" as long as the script exits without an unhandled exception.

Consider adding at minimum an is_success requirement for both entries, and ideally a min_value guard on a count metric (e.g., number of audio samples that passed the WER filter) to catch regressions in result quality.

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.

4 participants