Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 55 additions & 2 deletions benchmarking/nightly-benchmark.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -580,15 +580,15 @@ entries:
- metric: throughput_images_per_sec
min_value: 3.0

- name: audio_fleurs
- name: audio_fleurs_xenna
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=dev
--split=train
--wer-threshold=5.5
--gpus=1
ray:
Expand All @@ -600,6 +600,27 @@ entries:
ping_on_failure:
- U03C41SNADV # Aaftab V

- 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
Comment on lines +603 to +622

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.

Comment on lines +603 to +622

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.


- name: arxiv_e2e_pipeline_raydata
enabled: true
script: arxiv_e2e_pipeline_benchmark.py
Expand Down Expand Up @@ -888,3 +909,35 @@ entries:
min_value: 1
- metric: total_filtered_windows
min_value: 1

- name: alm_pipeline_ray_data
enabled: true
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.

--executor=ray_data
--target-window-duration=120.0
--tolerance=0.1
--min-sample-rate=16000
--min-bandwidth=8000
--min-speakers=2
--max-speakers=5
--overlap-percentage=50
--repeat-factor=2000
timeout_s: 600
sink_data:
- name: slack
ping_on_failure:
- U03C41SNADV # Aaftab V
ray:
num_cpus: 8
num_gpus: 0
enable_object_spilling: false
requirements:
- metric: is_success
exact_value: true
- metric: total_builder_windows
min_value: 1
- metric: total_filtered_windows
min_value: 1
8 changes: 7 additions & 1 deletion benchmarking/scripts/audio_fleurs_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
"""Audio Fleurs benchmarking script.

This script runs audio Fleurs benchmarks with comprehensive metrics collection
using XennaExecutor and logs results to configured sinks.
and logs results to configured sinks.
"""

import argparse
import traceback
from pathlib import Path
from typing import Any

Expand Down Expand Up @@ -59,6 +60,7 @@ def run_audio_fleurs_benchmark( # noqa: PLR0913
raise ValueError(msg)

logger.info("Starting audio fleurs benchmark")
logger.info(f"Executor: {executor}")
logger.info(f"Model: {model_name}")
logger.info(f"Language: {lang}")
logger.info(f"Split: {split}")
Expand Down Expand Up @@ -147,6 +149,10 @@ def main() -> int:
try:
result_dict.update(run_audio_fleurs_benchmark(**vars(args)))
success_code = 0 if result_dict["metrics"]["is_success"] else 1
except Exception as e:
error_traceback = traceback.format_exc()
logger.error(f"Benchmark failed: {e}")
logger.debug(f"Full traceback:\n{error_traceback}")
Comment on lines +152 to +155

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.

Exception swallowed, success_code stays 1 but function returns normally

Inside the except block (lines 167–170) the exception is logged but not re-raised. After the finally block the function returns success_code, which is still 1. The caller (SystemExit(main())) exits with a non-zero code, which is correct, but any exception raised inside run_audio_fleurs_benchmark (e.g. a RuntimeError from a stage) is silently discarded after logging. If any downstream code relies on propagating exceptions, this could hide failures.

Consider either re-raising the exception after logging, or documenting that exceptions are intentionally swallowed here:

Suggested change
except Exception as e:
error_traceback = traceback.format_exc()
logger.error(f"Benchmark failed: {e}")
logger.debug(f"Full traceback:\n{error_traceback}")
except Exception as e:
error_traceback = traceback.format_exc()
logger.error(f"Benchmark failed: {e}")
logger.debug(f"Full traceback:\n{error_traceback}")
raise

finally:
write_benchmark_results(result_dict, args.benchmark_results_path)
return success_code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

import os
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.

from nemo_curator.stages.audio.datasets.file_utils import download_file, extract_archive
from nemo_curator.stages.base import ProcessingStage
from nemo_curator.tasks import AudioBatch, _EmptyTask
Expand Down Expand Up @@ -138,6 +140,9 @@ def download_extract_files(self, dst_folder: str) -> None:

extract_archive(f"{dst_folder}/{self.split}.tar.gz", str(dst_folder), force_extract=True)

def ray_stage_spec(self) -> dict[str, Any]:
return {RayStageSpecKeys.IS_FANOUT_STAGE: True}
Comment thread
oyilmaz-nvidia marked this conversation as resolved.

def process(self, _: _EmptyTask) -> list[AudioBatch]:
self.download_extract_files(self.raw_data_dir)
return self.process_transcript(os.path.join(self.raw_data_dir, self.split + ".tsv"))
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ def _import_stage_module() -> tuple[Any, Any]:
return CreateInitialManifestFleursStage, get_fleurs_url_list


def test_ray_stage_spec(tmp_path: Path) -> None:
from nemo_curator.backends.experimental.utils import RayStageSpecKeys

stage_cls, _ = _import_stage_module()
stage = stage_cls(lang="hy_am", split="dev", raw_data_dir=str(tmp_path / "fleurs"))
spec = stage.ray_stage_spec()
assert spec[RayStageSpecKeys.IS_FANOUT_STAGE] is True


def test_get_fleurs_url_list_builds_urls() -> None:
_, get_fleurs_url_list = _import_stage_module()
urls = get_fleurs_url_list("hy_am", "dev")
Expand Down
Loading