diff --git a/.github/workflows/config/.secrets.baseline b/.github/workflows/config/.secrets.baseline index fe6859af49..63aeab357f 100644 --- a/.github/workflows/config/.secrets.baseline +++ b/.github/workflows/config/.secrets.baseline @@ -464,16 +464,16 @@ { "type": "Hex High Entropy String", "filename": "tutorials/audio/fleurs/fleurs_tutorial.ipynb", - "hashed_secret": "7616c5879286847f5720a0ada8806fb784d53266", + "hashed_secret": "b158f69d26847139deedc024c3270d8b8fc79d81", "is_verified": false, - "line_number": 331 + "line_number": 232 }, { "type": "Base64 High Entropy String", "filename": "tutorials/audio/fleurs/fleurs_tutorial.ipynb", - "hashed_secret": "15f8f5a83e733b440678e56ef2a83603149b9b58", + "hashed_secret": "45b1cbaefaa19a0f8d57a797a742ff8e5681b922", "is_verified": false, - "line_number": 517 + "line_number": 323 } ], "tutorials/audio/readspeech/readspeech_tutorial.ipynb": [ @@ -534,5 +534,5 @@ } ] }, - "generated_at": "2026-07-28T01:32:05Z" + "generated_at": "2026-08-07T18:14:16Z" } diff --git a/benchmarking/scripts/audio_fleurs_benchmark.py b/benchmarking/scripts/audio_fleurs_benchmark.py index 0e09d024bc..9329af34e4 100644 --- a/benchmarking/scripts/audio_fleurs_benchmark.py +++ b/benchmarking/scripts/audio_fleurs_benchmark.py @@ -31,7 +31,7 @@ from nemo_curator.pipeline import Pipeline from nemo_curator.stages.audio.common import GetAudioDurationStage, PreserveByValueStage from nemo_curator.stages.audio.datasets.fleurs.create_initial_manifest import CreateInitialManifestFleursStage -from nemo_curator.stages.audio.inference.asr.asr_nemo import InferenceAsrNemoStage +from nemo_curator.stages.audio.inference.asr.stage import ASRStage from nemo_curator.stages.audio.io.convert import AudioToDocumentStage from nemo_curator.stages.audio.metrics.wer import GetPairwiseWerStage from nemo_curator.stages.resources import Resources @@ -109,7 +109,16 @@ def run_audio_fleurs_benchmark( # noqa: PLR0913, PLR0915 auto_download=auto_download, ).with_(batch_size=4) ) - pipeline.add_stage(InferenceAsrNemoStage(model_name=model_name).with_(resources=Resources(gpus=gpus))) + pipeline.add_stage( + ASRStage( + adapter_target="nemo_curator.models.asr.nemo_asr.NeMoASRAdapter", + model_id=model_name, + audio_filepath_key="audio_filepath", + batch_size=16, + fail_on_audio_error=True, + adapter_kwargs={"use_cuda_graph_decoder": False}, + ).with_(resources=Resources(gpus=gpus)) + ) pipeline.add_stage( GetPairwiseWerStage( text_key="text", @@ -192,7 +201,7 @@ def main() -> int: parser.add_argument("--split", default="dev", help="Dataset split to use") parser.add_argument("--wer-threshold", type=float, default=5.5, help="WER threshold for filtering") parser.add_argument("--executor", default="xenna", choices=["xenna", "ray_data"], help="Executor to use") - parser.add_argument("--gpus", type=int, default=1, help="Number of GPUs to use") + parser.add_argument("--gpus", type=int, choices=[0, 1], default=1, help="GPUs per NeMo ASR worker") parser.add_argument( "--raw-data-dir", default=None, @@ -207,10 +216,7 @@ def main() -> int: "--no-auto-download", dest="auto_download", action="store_false", - help=( - "Disable runtime Hugging Face download; read pre-staged data from " - "// instead." - ), + help=("Disable runtime Hugging Face download; read pre-staged data from // instead."), ) parser.set_defaults(auto_download=True) parser.add_argument( diff --git a/nemo_curator/config/README.md b/nemo_curator/config/README.md index 606c1a3b79..77c78ef2dd 100644 --- a/nemo_curator/config/README.md +++ b/nemo_curator/config/README.md @@ -10,6 +10,8 @@ python run.py --config-path ./{target_dir} --config-name {target_file}.yaml para Where `{target_dir}` is the subdirectory containing the YAML file, `{target_file}` is the YAML file name, and `param_1=... param_2=...` are any parameters in the YAML file which are formatted with: +When the configuration file is named `pipeline.yaml`, `--config-name` may be omitted. Use `--config-name` for differently named configuration files. + ```bash param_1: ??? param_2: ??? diff --git a/nemo_curator/config/run.py b/nemo_curator/config/run.py index fe1d935a0e..1da6b9ecbc 100644 --- a/nemo_curator/config/run.py +++ b/nemo_curator/config/run.py @@ -121,7 +121,7 @@ def create_pipeline_from_yaml(cfg: DictConfig, *, log_config: bool = True) -> Pi raise RuntimeError(msg) -@hydra.main(version_base=None) +@hydra.main(version_base=None, config_name="pipeline") def main(cfg: DictConfig) -> None: ray_client = create_ray_client_from_yaml(cfg) ray_client.start() diff --git a/nemo_curator/models/asr/base.py b/nemo_curator/models/asr/base.py index 7f8855e1ce..eef44f292c 100644 --- a/nemo_curator/models/asr/base.py +++ b/nemo_curator/models/asr/base.py @@ -59,9 +59,9 @@ class ASRResult: class ASRAdapter(Protocol): """Structural protocol every ASR adapter must implement. - Constructor contract: the stage builds adapters as - ``cls(model_id=..., revision=..., **adapter_kwargs)``, so every adapter - must accept ``model_id`` and ``revision`` keyword args plus its own knobs. + ``ASRStage`` constructs adapters with ``model_id`` and the explicitly + configured ``adapter_kwargs``. Model-provider options therefore stay with + the adapter that implements them instead of becoming shared stage fields. Per-batch contract: ``transcribe_batch`` receives a list of per-task dicts (unpacked from ``task.data``) and returns one ``ASRResult`` per input, in @@ -81,12 +81,11 @@ class ASRAdapter(Protocol): model_id: str - @classmethod - def download_weights_on_node(cls, model_id: str, revision: str | None = None) -> None: + def download_weights_on_node(self) -> None: """Download weights to local cache without allocating a GPU. - Classmethod so the stage can call it (once per node) without - instantiating the adapter or importing heavy GPU libraries. + The stage calls this once per node on a lightweight adapter instance so + provider-specific download options remain encapsulated by that adapter. """ ... diff --git a/nemo_curator/models/asr/nemo_asr.py b/nemo_curator/models/asr/nemo_asr.py new file mode 100644 index 0000000000..56ff272a36 --- /dev/null +++ b/nemo_curator/models/asr/nemo_asr.py @@ -0,0 +1,226 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""NeMo Framework ASR behind the shared :class:`ASRAdapter` contract.""" + +from __future__ import annotations + +import gc +from copy import deepcopy +from dataclasses import dataclass, field +from numbers import Integral +from typing import Any, ClassVar + +import numpy as np +import torch +from omegaconf import open_dict + +from nemo_curator.models.asr.base import ASRResult + + +def _nemo_asr_module() -> Any: # noqa: ANN401 + try: + import nemo.collections.asr as nemo_asr + except ImportError as exc: + msg = "NeMoASRAdapter requires the audio_common extra: uv sync --extra audio_common" + raise ImportError(msg) from exc + return nemo_asr + + +def _extract_nemo_transcription_texts(outputs: object) -> list[str]: + """Extract text from the output shapes used by supported NeMo ASR models.""" + if isinstance(outputs, tuple): + outputs = outputs[0] + if outputs is None: + return [] + if not isinstance(outputs, list): + msg = f"Unsupported NeMo transcription output type: {type(outputs).__name__}" + raise TypeError(msg) + + texts: list[str] = [] + for output in outputs: + primary = (output[0] if output else "") if isinstance(output, list) else output + text = getattr(primary, "text", primary) + if not isinstance(text, str): + msg = f"Unsupported NeMo transcription item type: {type(primary).__name__}" + raise TypeError(msg) + texts.append(text) + return texts + + +@dataclass +class NeMoASRAdapter: + """Run a pretrained NeMo checkpoint using waveforms prepared by ``ASRStage``. + + Args: + model_id: Pretrained NeMo ASR checkpoint name. + num_workers: Data-loader workers used by NeMo's transcription call. + verbose: Forward NeMo transcription progress output. + enable_local_attention: Convert a compatible FastConformer checkpoint + from global to local attention after loading. + local_attention_context_size: Left and right local-attention context. + use_cuda_graph_decoder: Override NeMo's RNNT CUDA-graph decoder. Leave + as ``None`` to preserve the checkpoint default. Set to ``False`` + on GPU/driver combinations that do not support NeMo's label-loop + CUDA graph implementation. + refresh_cache: Forward NeMo's checkpoint cache refresh flag. + strict: Forward NeMo's strict checkpoint loading flag. + """ + + _DEFAULT_FASTCONFORMER_CTC_MODEL: ClassVar[str] = "nvidia/stt_en_fastconformer_ctc_large" + _DEFAULT_SAMPLE_RATE: ClassVar[int] = 16_000 + _ATTENTION_CONTEXT_DIRECTIONS: ClassVar[int] = 2 + + model_id: str = _DEFAULT_FASTCONFORMER_CTC_MODEL + num_workers: int = 0 + verbose: bool = False + enable_local_attention: bool = False + local_attention_context_size: tuple[int, int] = (128, 128) + use_cuda_graph_decoder: bool | None = None + refresh_cache: bool = False + strict: bool = True + _model: Any = field(default=None, init=False, repr=False) + + def __post_init__(self) -> None: + if self.num_workers < 0: + msg = "NeMoASRAdapter.num_workers must be non-negative" + raise ValueError(msg) + try: + context_size = tuple(self.local_attention_context_size) + except TypeError as exc: + msg = "NeMoASRAdapter.local_attention_context_size must contain two positive integers" + raise ValueError(msg) from exc + if len(context_size) != self._ATTENTION_CONTEXT_DIRECTIONS or any( + isinstance(value, bool) or not isinstance(value, Integral) or value <= 0 for value in context_size + ): + msg = "NeMoASRAdapter.local_attention_context_size must contain two positive integers" + raise ValueError(msg) + self.local_attention_context_size = (int(context_size[0]), int(context_size[1])) + + def download_weights_on_node(self) -> None: + """Download a pretrained checkpoint without allocating a GPU model.""" + _nemo_asr_module().models.ASRModel.from_pretrained(model_name=self.model_id, return_model_file=True) + + def _load_checkpoint(self, device: Any) -> Any: # noqa: ANN401 + return _nemo_asr_module().models.ASRModel.from_pretrained( + model_name=self.model_id, + map_location=device, + refresh_cache=self.refresh_cache, + strict=self.strict, + ) + + def load_model(self, *, num_gpus: int) -> None: + """Load one worker-local model on the device requested by ``ASRStage``.""" + if self._model is not None: + return + if isinstance(num_gpus, bool) or not isinstance(num_gpus, Integral) or num_gpus not in {0, 1}: + msg = f"NeMoASRAdapter requires num_gpus to be 0 or 1, got {num_gpus!r}" + raise ValueError(msg) + + device = torch.device("cuda" if num_gpus else "cpu") + model = self._load_checkpoint(device) + if self.enable_local_attention: + self._configure_local_attention(model) + if self.use_cuda_graph_decoder is not None: + self._configure_rnnt_cuda_graph_decoder(model) + self._model = model + + def _configure_local_attention(self, model: Any) -> None: # noqa: ANN401 + change_attention_model = getattr(model, "change_attention_model", None) + change_subsampling_chunking = getattr(model, "change_subsampling_conv_chunking_factor", None) + encoder = getattr(model, "encoder", None) + encoder_change_attention = getattr(encoder, "change_attention_model", None) + encoder_change_subsampling = getattr(encoder, "change_subsampling_conv_chunking_factor", None) + if ( + not callable(change_attention_model) + or not callable(change_subsampling_chunking) + or not callable(encoder_change_attention) + or not callable(encoder_change_subsampling) + ): + msg = f"NeMo checkpoint {self.model_id!r} does not support FastConformer local-attention conversion" + raise TypeError(msg) + change_attention_model( + self_attention_model="rel_pos_local_attn", + att_context_size=list(self.local_attention_context_size), + ) + change_subsampling_chunking(1) + + def _configure_rnnt_cuda_graph_decoder(self, model: Any) -> None: # noqa: ANN401 + """Override the CUDA-graph setting on a compatible NeMo RNNT decoder.""" + change_decoding_strategy = getattr(model, "change_decoding_strategy", None) + model_cfg = getattr(model, "cfg", None) + decoding_cfg = getattr(model_cfg, "decoding", None) + greedy_cfg = getattr(decoding_cfg, "greedy", None) + if not callable(change_decoding_strategy) or decoding_cfg is None or greedy_cfg is None: + msg = f"NeMo checkpoint {self.model_id!r} does not expose a configurable RNNT decoder" + raise TypeError(msg) + + decoding_cfg = deepcopy(decoding_cfg) + with open_dict(decoding_cfg.greedy): + decoding_cfg.greedy.use_cuda_graph_decoder = self.use_cuda_graph_decoder + change_decoding_strategy(decoding_cfg=decoding_cfg) + + def unload_model(self) -> None: + """Release worker-local model and CUDA cache state.""" + self._model = None + gc.collect() + if torch.cuda.is_available(): + torch.cuda.empty_cache() + + def transcribe_batch(self, items: list[dict[str, Any]]) -> list[ASRResult]: + """Transcribe one adapter call while preserving input order.""" + if not items: + return [] + if self._model is None: + msg = "NeMoASRAdapter is not initialized; call load_model() first" + raise RuntimeError(msg) + + valid_indices: list[int] = [] + waveforms: list[np.ndarray] = [] + for index, item in enumerate(items): + waveform = np.asarray(item.get("waveform"), dtype=np.float32) + if waveform.size == 0: + continue + if waveform.ndim != 1: + msg = f"ASRStage must provide a mono 1-D waveform, got shape {waveform.shape}" + raise ValueError(msg) + sample_rate = int(item.get("sample_rate") or 0) + if sample_rate != self._DEFAULT_SAMPLE_RATE: + msg = ( + f"ASRStage must provide {self._DEFAULT_SAMPLE_RATE} Hz audio for {self.model_id!r}; " + f"received {sample_rate} Hz" + ) + raise ValueError(msg) + waveforms.append(np.ascontiguousarray(waveform)) + valid_indices.append(index) + + results = [ASRResult(text="", skipped=True, skip_reason="empty_audio") for _ in items] + if not waveforms: + return results + + outputs = self._model.transcribe( + audio=waveforms, + batch_size=len(waveforms), + return_hypotheses=False, + num_workers=self.num_workers, + verbose=self.verbose, + ) + texts = _extract_nemo_transcription_texts(outputs) + if len(texts) != len(valid_indices): + msg = f"NeMo returned {len(texts)} transcriptions for {len(valid_indices)} valid inputs" + raise RuntimeError(msg) + + for index, text in zip(valid_indices, texts, strict=True): + results[index] = ASRResult(text=text) + return results diff --git a/nemo_curator/models/asr/qwen_asr.py b/nemo_curator/models/asr/qwen_asr.py index e2eb551c4c..528c7c0900 100644 --- a/nemo_curator/models/asr/qwen_asr.py +++ b/nemo_curator/models/asr/qwen_asr.py @@ -61,8 +61,8 @@ class QwenASRAdapter: ``max_inference_batch_size`` is the library's own internal cap and is passed through at construction. - ``revision`` is accepted to satisfy the shared adapter constructor and is - forwarded to both weight prefetch and the vLLM model loader. + ``revision`` is an adapter-owned Hugging Face option and is forwarded to + both weight prefetch and the vLLM model loader. ``vllm_kwargs`` exposes additional engine settings, following the existing Qwen-Omni adapter convention. Adapter-owned settings cannot be overridden @@ -104,7 +104,7 @@ def __post_init__(self) -> None: raise ValueError(msg) self.vllm_kwargs = deepcopy(dict(self.vllm_kwargs)) - def _model_owned_vllm_kwargs(self) -> dict[str, Any]: + def _adapter_owned_model_kwargs(self) -> dict[str, Any]: """Return the qwen-asr constructor arguments owned by this adapter.""" return { "model": self.model_id, @@ -118,10 +118,12 @@ def _model_owned_vllm_kwargs(self) -> dict[str, Any]: "prefix_caching_hash_algo": "xxhash", } - @classmethod - def download_weights_on_node(cls, model_id: str, revision: str | None = None) -> None: + def download_weights_on_node(self) -> None: """Populate the local Hugging Face cache without allocating a GPU.""" - snapshot_download(model_id, revision=revision) + kwargs: dict[str, Any] = {} + if self.revision is not None: + kwargs["revision"] = self.revision + snapshot_download(self.model_id, **kwargs) def load_model(self, *, num_gpus: int) -> None: """Load one worker-local Qwen3-ASR model through its vLLM backend.""" @@ -140,7 +142,7 @@ def load_model(self, *, num_gpus: int) -> None: ) model_kwargs = merge_vllm_kwargs( self.vllm_kwargs, - self._model_owned_vllm_kwargs(), + self._adapter_owned_model_kwargs(), owner_description="adapter-owned arguments", ) if model_kwargs["revision"] is None: diff --git a/nemo_curator/models/asr/qwen_omni.py b/nemo_curator/models/asr/qwen_omni.py index 0fb958d4e8..0dca380db0 100644 --- a/nemo_curator/models/asr/qwen_omni.py +++ b/nemo_curator/models/asr/qwen_omni.py @@ -101,9 +101,9 @@ def _default_sampling_kwargs() -> dict[str, Any]: class QwenOmniASRAdapter: """Qwen3-Omni in-process vLLM adapter (thinker-only path). - Stages construct adapters via - ``cls(model_id=..., revision=..., **adapter_kwargs)``, so the fields below - can be supplied from the YAML ``adapter_kwargs``. + ``ASRStage`` supplies ``model_id`` plus this adapter's explicitly configured + ``adapter_kwargs``. Hugging Face ``revision`` pinning therefore remains a + Qwen adapter capability rather than part of the shared ASR stage contract. Notable Args: prompt_text / *_file: User prompt; ``{language}`` is interpolated @@ -117,8 +117,9 @@ class QwenOmniASRAdapter: max_output_tokens: maximum transcription tokens. Kept separate so the adapter remains the only source of ``SamplingParams.max_tokens``. vllm_kwargs: engine settings forwarded to Curator's shared - ``create_vllm_llm`` helper. ``model``, ``revision``, and - ``tensor_parallel_size`` are stage-owned and cannot be overridden. + ``create_vllm_llm`` helper. ``model`` and ``revision`` have + dedicated adapter fields, while ``tensor_parallel_size`` comes + from the stage's GPU allocation; none can be overridden here. sampling_kwargs: settings forwarded to vLLM ``SamplingParams``. ``max_tokens`` is adapter-owned and cannot be overridden. """ @@ -161,8 +162,8 @@ def __post_init__(self) -> None: self._llm: Any = None self._sampling_params: Any = None - def _stage_owned_vllm_kwargs(self, *, num_gpus: int | None) -> dict[str, Any]: - """Return vLLM constructor arguments supplied by the stage contract.""" + def _adapter_owned_vllm_kwargs(self, *, num_gpus: int | None) -> dict[str, Any]: + """Return vLLM arguments controlled by adapter fields and the allocated GPU count.""" return { "model": self.model_id, "revision": self.revision, @@ -179,13 +180,12 @@ def _load_text(text: str | None, file_path: str | None) -> str | None: return path.read_text(encoding="utf-8").strip() return text - @classmethod - def download_weights_on_node(cls, model_id: str, revision: str | None = None) -> None: + def download_weights_on_node(self) -> None: """Cache the model snapshot on local disk without touching the GPU.""" kwargs: dict[str, Any] = {} - if revision is not None: - kwargs["revision"] = revision - snapshot_download(model_id, **kwargs) + if self.revision is not None: + kwargs["revision"] = self.revision + snapshot_download(self.model_id, **kwargs) def load_model(self, *, num_gpus: int) -> None: if self._llm is not None: @@ -211,8 +211,8 @@ def load_model(self, *, num_gpus: int) -> None: engine_kwargs = merge_vllm_kwargs( self.vllm_kwargs, - self._stage_owned_vllm_kwargs(num_gpus=num_gpus), - owner_description="stage-owned arguments", + self._adapter_owned_vllm_kwargs(num_gpus=num_gpus), + owner_description="adapter-owned arguments", ) del engine_kwargs["model"] if engine_kwargs["revision"] is None: diff --git a/nemo_curator/stages/audio/README.md b/nemo_curator/stages/audio/README.md index 9a73322991..3f986a5362 100644 --- a/nemo_curator/stages/audio/README.md +++ b/nemo_curator/stages/audio/README.md @@ -143,9 +143,9 @@ inference call. ```python @dataclass -class InferenceAsrNemoStage(ProcessingStage[AudioTask, AudioTask]): - batch_size: int = 16 # default for this stage - resources: Resources = field(default_factory=lambda: Resources(cpus=1.0)) +class ASRStage(ProcessingStage[AudioTask, AudioTask]): + batch_size: int = 32 + resources: Resources = field(default_factory=lambda: Resources(gpus=1.0)) ``` The default is a sensible starting point; pipeline authors can override it @@ -155,7 +155,11 @@ at pipeline construction time without modifying the stage class: ```python pipeline.add_stage( - InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2") + ASRStage( + adapter_target="nemo_curator.models.asr.nemo_asr.NeMoASRAdapter", + model_id="nvidia/parakeet-tdt-0.6b-v2", + audio_filepath_key="audio_filepath", + ) .with_(resources=Resources(gpus=1), batch_size=32) ) ``` @@ -168,8 +172,10 @@ from the default `16` to `32` and assigns 1 GPU. ```yaml pipeline: stages: - - _target_: nemo_curator.stages.audio.inference.asr_nemo.InferenceAsrNemoStage - model_name: nvidia/parakeet-tdt-0.6b-v2 + - _target_: nemo_curator.stages.audio.inference.asr.stage.ASRStage + adapter_target: nemo_curator.models.asr.nemo_asr.NeMoASRAdapter + model_id: nvidia/parakeet-tdt-0.6b-v2 + audio_filepath_key: audio_filepath batch_size: 32 ``` @@ -262,7 +268,7 @@ process_batch(list[AudioTask]) -> list[AudioTask] instead of `not tasks` because Ray Data's `map_batches` passes `tasks` as a numpy array, and `not ndarray` raises `ValueError` for arrays with more than one element. This applies to - `process_batch` in `InferenceAsrNemoStage` and + `process_batch` in `ASRStage` and `AudioToDocumentStage`. ## How backends parallelise your stage @@ -341,8 +347,9 @@ For a GPU stage with `resources=Resources(cpus=1.0, gpus=1.0)` and ``` Each `process_batch([16 tasks])` call goes directly to: -`InferenceAsrNemoStage.process_batch` → `validate_input` per task → -extract filepaths → **one** batched GPU call → mutate each task in-place. +`ASRStage.process_batch` → validate and load the current task waveforms → +`NeMoASRAdapter.transcribe_batch` → **one** batched NeMo call → mutate each +task in-place. ### Xenna specifics @@ -403,7 +410,7 @@ the value takes until it controls how many tasks land in your `process_batch` call: ``` -InferenceAsrNemoStage (your stage dataclass) +ASRStage (generic stage dataclass) batch_size: int = 16 ← defined as a dataclass field │ │ ProcessingStage (base class) @@ -492,7 +499,7 @@ pipeline.run(executor) │ └─ return results ``` -### GPU stage (e.g. `InferenceAsrNemoStage`, `batch_size=16`) +### GPU stage (e.g. `ASRStage` + `NeMoASRAdapter`, `batch_size=16`) **Xenna backend:** @@ -510,14 +517,15 @@ pipeline.run(executor) │ ├─ Per worker — one-time setup: │ backends/xenna/adapter.py XennaStageAdapter.setup_on_node() -│ → stages/audio/inference/asr_nemo.py InferenceAsrNemoStage.setup_on_node() -│ nemo_asr.models.ASRModel.from_pretrained(model_name, return_model_file=True) +│ → stages/audio/inference/asr/stage.py ASRStage.setup_on_node() +│ → models/asr/nemo_asr.py NeMoASRAdapter.download_weights_on_node() +│ ASRModel.from_pretrained(model_name=model_id, return_model_file=True) │ (downloads model to shared cache — one download per node) │ backends/xenna/adapter.py XennaStageAdapter.setup() │ → backends/base.py stage.setup(worker_metadata) -│ → stages/audio/inference/asr_nemo.py InferenceAsrNemoStage.setup() -│ map_location = self.check_cuda() → "cuda" -│ self.asr_model = ASRModel.from_pretrained(model_name, map_location=cuda) +│ → stages/audio/inference/asr/stage.py ASRStage.setup() +│ → models/asr/nemo_asr.py NeMoASRAdapter.load_model(num_gpus=1) +│ ASRModel.from_pretrained(model_name=model_id, map_location=cuda) │ ├─ Per batch (batch_size=16, so 16 AudioTask tasks per call): │ backends/xenna/adapter.py XennaStageAdapter.process_data(tasks) @@ -528,18 +536,17 @@ pipeline.run(executor) │ └─ return results │ │ │ │ ┌────────────────────────────────────────────────────────────────────────────────────────────┘ -│ │ InferenceAsrNemoStage.process_batch() (OVERRIDDEN — batched GPU) -│ │ stages/audio/inference/asr_nemo.py +│ │ ASRStage.process_batch() (generic batched GPU stage) +│ │ stages/audio/inference/asr/stage.py │ │ validate_input(task) per task schema check -│ │ files = [t.data[self.filepath_key] for t in tasks] -│ │ → list of 16 audio file paths -│ │ texts = self.transcribe(files) -│ │ → stages/audio/inference/asr_nemo.py -│ │ self.asr_model.transcribe(files) -│ │ → ONE batched GPU kernel call for all 16 files -│ │ return [output.text for output in outputs] -│ │ for task, text in zip(tasks, texts): -│ │ task.data[self.pred_text_key] = text (mutate in-place) +│ │ load and normalize the current 16 waveforms +│ │ adapter.transcribe_batch(items) +│ │ → models/asr/nemo_asr.py +│ │ self._model.transcribe(audio=waveforms, batch_size=16) +│ │ → ONE batched NeMo inference call +│ │ return list[ASRResult] +│ │ for task, result in zip(tasks, results): +│ │ task.data[self.pred_text_key] = result.text │ └─ return tasks → same 16 AudioTask objects ``` @@ -610,7 +617,7 @@ processing median ALM entries (~4 MB each), that is ~128 MB of task data in flight. The worker process itself uses minimal additional memory (soundfile, editdistance, etc. are lightweight). -**GPU stages** (e.g. `InferenceAsrNemoStage`): Peak memory is +**GPU stages** (e.g. `ASRStage` + `NeMoASRAdapter`): Peak memory is dominated by **model VRAM**, not task data. A NeMo ASR FastConformer-TDT model uses ~2–4 GB of VRAM. The task data (`batch_size × entry_size`) is negligible in comparison — 16 FLEURS @@ -620,9 +627,9 @@ entries is 16 × 741 B ≈ 12 KB, while even 16 large ALM entries is ## End-to-end `AudioTask` trace (FLEURS pipeline) Below is a single English FLEURS entry flowing through every stage in -`tutorials/audio/fleurs/pipeline.py`. All values are **real output** -from running `--lang en_us --model_name nvidia/parakeet-tdt-0.6b-v2 ---split dev --wer_threshold 75`. +`tutorials/audio/fleurs/main.py`. All values are **real output** from running +`lang=en_us stages.1.model_id=nvidia/parakeet-tdt-0.6b-v2 +data_split=dev wer_threshold=75`. Pipeline: download → ASR → WER → duration → filter → convert → write. @@ -647,11 +654,12 @@ AudioTask( *(Only 2 keys: `audio_filepath` and `text`.)* -### Stage 2: `InferenceAsrNemoStage` (GPU) +### Stage 2: `ASRStage` + `NeMoASRAdapter` (GPU) -Loads `nvidia/parakeet-tdt-0.6b-v2` onto the GPU. Receives a batch -of 16 `AudioTask`s, extracts file paths, runs one batched -`transcribe()` call, and writes predictions back **in-place**. +The generic stage loads and normalizes each current-batch waveform; the NeMo +adapter loads `nvidia/parakeet-tdt-0.6b-v2` onto the GPU and runs one batched +`transcribe()` call for 16 `AudioTask`s. The stage writes predictions back +**in-place**. **Output** — `data` gains `pred_text`: @@ -746,7 +754,7 @@ Writes each row of the DataFrame as one JSON line to | Stage | Keys in `data` | Type out | |---|---|---| | `CreateInitialManifestFleursStage` | `audio_filepath`, `text` | `AudioTask` | -| `InferenceAsrNemoStage` | + `pred_text` | `AudioTask` | +| `ASRStage` + `NeMoASRAdapter` | + `pred_text` | `AudioTask` | | `GetPairwiseWerStage` | + `wer` | `AudioTask` | | `GetAudioDurationStage` | + `duration` | `AudioTask` | | `PreserveByValueStage` | (unchanged or dropped) | `AudioTask` | diff --git a/nemo_curator/stages/audio/inference/asr/asr_nemo.py b/nemo_curator/stages/audio/inference/asr/asr_nemo.py deleted file mode 100644 index 3baaf29988..0000000000 --- a/nemo_curator/stages/audio/inference/asr/asr_nemo.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. -# -# 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. - -import time -from dataclasses import dataclass, field -from typing import Any - -import nemo.collections.asr as nemo_asr -import torch - -from nemo_curator.backends.base import NodeInfo, WorkerMetadata -from nemo_curator.stages.base import ProcessingStage -from nemo_curator.stages.resources import Resources -from nemo_curator.tasks import AudioTask - - -@dataclass -class InferenceAsrNemoStage(ProcessingStage[AudioTask, AudioTask]): - """Speech recognition inference using a NeMo ASR model. - - Overrides ``process_batch`` for batched GPU inference. - - Args: - model_name: Pretrained NeMo ASR model name. - See full list at https://docs.nvidia.com/nemo-framework/user-guide/latest/nemotoolkit/asr/all_chkpt.html - cache_dir: Optional directory for model download cache. - When set, NeMo stores/loads the pretrained checkpoint here - instead of the default cache location. - filepath_key: Key in the entry dict pointing to the audio file. - pred_text_key: Key where the predicted transcription is stored. - """ - - name: str = "ASR_inference" - model_name: str = "" - cache_dir: str | None = None - asr_model: Any | None = field(default=None, repr=False) - filepath_key: str = "audio_filepath" - pred_text_key: str = "pred_text" - resources: Resources = field(default_factory=lambda: Resources(cpus=1.0)) - batch_size: int = 16 - - def __post_init__(self) -> None: - if not self.model_name and not self.asr_model: - msg = "Either model_name or asr_model is required for InferenceAsrNemoStage" - raise ValueError(msg) - - def check_cuda(self) -> torch.device: - return torch.device("cuda") if self.resources.gpus > 0 else torch.device("cpu") - - def setup_on_node( - self, - _node_info: NodeInfo | None = None, - _worker_metadata: WorkerMetadata | None = None, - ) -> None: - if self.asr_model: - return - try: - kwargs: dict[str, Any] = {"model_name": self.model_name, "return_model_file": True} - if self.cache_dir is not None: - kwargs["cache_dir"] = self.cache_dir - nemo_asr.models.ASRModel.from_pretrained(**kwargs) - except Exception as e: - msg = f"Failed to download {self.model_name}" - raise RuntimeError(msg) from e - - def setup(self, _worker_metadata: WorkerMetadata | None = None) -> None: - if not self.asr_model: - try: - map_location = self.check_cuda() - kwargs: dict[str, Any] = {"model_name": self.model_name, "map_location": map_location} - if self.cache_dir is not None: - kwargs["cache_dir"] = self.cache_dir - self.asr_model = nemo_asr.models.ASRModel.from_pretrained(**kwargs) - except Exception as e: - msg = f"Failed to load {self.model_name}" - raise RuntimeError(msg) from e - - def inputs(self) -> tuple[list[str], list[str]]: - return [], [self.filepath_key] - - def outputs(self) -> tuple[list[str], list[str]]: - return [], [self.filepath_key, self.pred_text_key] - - def transcribe(self, files: list[str]) -> list[str]: - outputs = self.asr_model.transcribe(files) - - if isinstance(outputs, tuple): - outputs = outputs[0] - - if outputs and isinstance(outputs[0], list): - if outputs[0] and hasattr(outputs[0][0], "text"): - return [inner[0].text for inner in outputs] - return [inner[0] for inner in outputs] - - return [output.text for output in outputs] - - def process(self, task: AudioTask) -> AudioTask: - msg = "InferenceAsrNemoStage only supports process_batch" - raise NotImplementedError(msg) - - def process_batch(self, tasks: list[AudioTask]) -> list[AudioTask]: - if len(tasks) == 0: - return [] - t0 = time.perf_counter() - for task in tasks: - if not self.validate_input(task): - msg = f"Task {task.task_id} missing required columns for {type(self).__name__}: {self.inputs()}" - raise ValueError(msg) - files = [t.data[self.filepath_key] for t in tasks] - texts = self.transcribe(files) - for task, text in zip(tasks, texts, strict=True): - task.data[self.pred_text_key] = text - self._log_metrics( - { - "process_time": time.perf_counter() - t0, - "files_transcribed": len(files), - } - ) - return tasks diff --git a/nemo_curator/stages/audio/inference/asr/stage.py b/nemo_curator/stages/audio/inference/asr/stage.py index 1693800602..9c6ab17209 100644 --- a/nemo_curator/stages/audio/inference/asr/stage.py +++ b/nemo_curator/stages/audio/inference/asr/stage.py @@ -27,7 +27,6 @@ import hydra.utils import numpy as np -import soundfile import torch import torchaudio from loguru import logger @@ -122,7 +121,6 @@ class ASRStage(ProcessingStage[AudioTask, AudioTask]): adapter_target: str model_id: str name: str = "ASR_inference" - revision: str | None = None # Task I/O keys. audio_filepath_key: str = "resampled_audio_filepath" @@ -137,6 +135,7 @@ class ASRStage(ProcessingStage[AudioTask, AudioTask]): extras_key: str | None = None skip_if_output_exists: bool = False + fail_on_audio_error: bool = False prefetch_fail_on_error: bool = True @@ -184,6 +183,13 @@ def _adapter_class(self) -> type: """Resolve the configured adapter lazily to avoid importing optional model dependencies.""" return hydra.utils.get_class(self.adapter_target) + def _create_adapter(self) -> ASRAdapter: + """Construct one adapter with only its explicitly configured options.""" + return self._adapter_class()( + model_id=self.model_id, + **self.adapter_kwargs, + ) + def setup_on_node( self, _node_info: NodeInfo | None = None, @@ -191,7 +197,7 @@ def setup_on_node( ) -> None: """Cache model weights once per node (no GPU allocation).""" try: - self._adapter_class().download_weights_on_node(self.model_id, self.revision) + self._create_adapter().download_weights_on_node() logger.info( "ASR weights cached on node for {} ({})", self.model_id, @@ -205,12 +211,7 @@ def setup_on_node( def setup(self, _worker_metadata: WorkerMetadata | None = None) -> None: if self._adapter is None: - cls = self._adapter_class() - adapter = cls( - model_id=self.model_id, - revision=self.revision, - **self.adapter_kwargs, - ) + adapter = self._create_adapter() try: adapter.load_model(num_gpus=self._adapter_gpu_count()) except Exception: @@ -292,15 +293,13 @@ def _build_items(self, tasks: list[AudioTask]) -> list[dict[str, Any]]: def _load_audio(audio_filepath: str) -> tuple[np.ndarray, int]: """Open one resampled file inside the ASR worker. - ``soundfile`` avoids making PCM WAV decoding depend on TorchCodec's - optional CUDA/FFmpeg shared libraries. SoundFile returns multichannel - audio as sample-major, so transpose it to the channel-first shape used - by ``_prepare_waveform``. + ``torchaudio.load`` returns channel-first audio. Resampled pipeline + inputs are normally mono, so squeezing removes that singleton channel; + multichannel inputs remain channel-first for ``_prepare_waveform`` to + downmix. """ - waveform, sample_rate = soundfile.read(audio_filepath, dtype="float32") - if waveform.ndim == _CHANNEL_FIRST_DIMENSIONS: - waveform = waveform.T - return np.ascontiguousarray(waveform, dtype=np.float32), sample_rate + waveform, sample_rate = torchaudio.load(audio_filepath) + return waveform.squeeze(0).numpy(), sample_rate def _prepare_waveform(self, waveform: object, sample_rate: object) -> np.ndarray: """Return contiguous mono float32 samples at ``target_sample_rate``.""" @@ -390,7 +389,10 @@ def run_inference(self, items: list[dict[str, Any]]) -> list[ASRResult]: audio_source = str(item["audio_filepath"]) waveform, sample_rate = self._load_audio(audio_source) waveform = self._prepare_waveform(waveform, sample_rate) - except Exception as exc: # noqa: BLE001 + except Exception as exc: + if self.fail_on_audio_error: + msg = f"ASRStage ({self.adapter_target}): failed to prepare audio for task {item['task_id']} from {audio_source}" + raise RuntimeError(msg) from exc logger.warning( "ASRStage ({}): failed to prepare audio for task {} from {}: {}", self.adapter_target, diff --git a/pyproject.toml b/pyproject.toml index be844a2155..4f56d5a010 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -112,6 +112,7 @@ audio_common = [ "nemo_toolkit[asr]>=2.7.2; platform_machine == 'x86_64' and platform_system != 'Darwin'", "soundfile>=0.12.0", "torchaudio", + "torchcodec; platform_machine == 'x86_64' and platform_system != 'Darwin'", "onnx>=1.19.0", "silero-vad", "librosa", @@ -138,7 +139,6 @@ audio_cuda12 = [ # Do not use qwen-asr[vllm], whose vLLM 0.14.0 pin conflicts with Curator's shared vLLM version. "qwen-asr==0.0.6; platform_machine == 'x86_64' and platform_system != 'Darwin'", "qwen-omni-utils>=0.0.9", - "torchcodec; platform_machine == 'x86_64' and platform_system != 'Darwin'", ] image_cpu = [ @@ -365,7 +365,7 @@ override-dependencies = [ "torch==2.11.0; sys_platform == 'linux' and (platform_machine == 'x86_64' or platform_machine == 'aarch64')", # Match vLLM's CUDA requirements; Linux resolves to cu129 via tool.uv.sources "torchaudio==2.11.0; sys_platform == 'linux' and (platform_machine == 'x86_64' or platform_machine == 'aarch64')", # Match torch==2.11.0 "torchvision==0.26.0; sys_platform == 'linux' and (platform_machine == 'x86_64' or platform_machine == 'aarch64')", # Match torch==2.11.0 - "torchcodec~=0.11.0; platform_machine == 'x86_64' and platform_system != 'Darwin'", # pin to torchcodec 0.11.x for torch 2.11 ABI compatibility; torchcodec does not declare a torch dep, so the resolver cannot enforce the match; satisfies pyannote-audio's >=0.7.0 floor; x86_64-only since aarch64 lacks wheels + "torchcodec~=0.11.0; platform_machine == 'x86_64' and platform_system != 'Darwin'", # TorchCodec 0.11 matches torch 2.11; TorchCodec does not declare a torch dependency, so enforce the ABI-compatible series across direct and transitive requirements; satisfies pyannote-audio's >=0.7.0 floor; x86_64-only since aarch64 lacks wheels "nixl-cu12>=0.10.0; platform_system == 'Linux' and (platform_machine == 'x86_64' or platform_machine == 'aarch64')", # Use the CUDA 12 backend on both supported Linux architectures. "xgrammar>=0.1.32", # Override vllm's ==0.1.29 pin to address CVE GHSA-7rgv-gqhr-fxg3 (DoS via multi-layer nesting) "sqlfluff>=4.2.0", # Address CVE-2026-46373/46374 (parser DoS); overrides data-designer-engine==0.5.5 sqlfluff<4 cap @@ -401,8 +401,7 @@ torchvision = [ { index = "pypi", marker = "sys_platform == 'darwin' or (platform_machine != 'x86_64' and platform_machine != 'aarch64')" }, ] torchcodec = [ - { index = "pytorch", marker = "platform_machine == 'x86_64' and sys_platform != 'darwin'" }, - { index = "pypi", marker = "platform_machine != 'x86_64' or sys_platform == 'darwin'" }, + { index = "pypi", extra = "audio-common" }, ] vllm = [ { index = "vllm-cu129", marker = "sys_platform == 'linux' and (platform_machine == 'x86_64' or platform_machine == 'aarch64')" }, diff --git a/tests/config/test_run.py b/tests/config/test_run.py index 5a81d90d5f..89904af196 100644 --- a/tests/config/test_run.py +++ b/tests/config/test_run.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import subprocess +import sys from pathlib import Path from unittest.mock import MagicMock, patch @@ -421,6 +423,7 @@ def test_qwen_tutorial_yaml_matches_reference_runner_config(): overrides=[ "manifest_path=tests/fixtures/audio/tagging/sample_input.jsonl", "pred_text_key=custom_prediction", + "model_revision=abc123", ], ) @@ -464,6 +467,7 @@ def test_qwen_tutorial_yaml_matches_reference_runner_config(): assert stage.batch_size == 32 assert stage.resources.gpus == 2 assert dict(stage.adapter_kwargs) == { + "revision": "abc123", "prompt_text": "Transcribe the audio.", "prompt_file": None, "en_prompt_text": None, @@ -505,6 +509,7 @@ def test_qwen_asr_tutorial_yaml_uses_generic_adapter_contract(): overrides=[ "manifest_path=tests/fixtures/audio/tagging/sample_input.jsonl", "pred_text_key=custom_prediction", + "model_revision=abc123", ], ) @@ -563,10 +568,75 @@ def test_qwen_asr_tutorial_yaml_uses_generic_adapter_contract(): assert stage.batch_size == 128 assert stage.resources.gpus == 1 assert dict(stage.adapter_kwargs) == { + "revision": "abc123", "gpu_memory_utilization": 0.7, "max_new_tokens": 4096, "max_inference_batch_size": 128, "vllm_kwargs": {"max_model_len": 8192}, } + assert executor.__class__.__name__ == "RayDataExecutor" assert executor.config == {} + + +def test_nemo_fastconformer_tutorial_yaml_uses_shared_adapter_contract(): + config_dir = Path(__file__).parents[2] / "tutorials" / "audio" / "nemo_fastconformer" + with initialize_config_dir(config_dir=str(config_dir), version_base=None): + cfg = compose( + config_name="pipeline", + overrides=[ + "manifest_path=tests/fixtures/audio/tagging/sample_input.jsonl", + "pred_text_key=custom_prediction", + ], + ) + + pipeline = create_pipeline_from_yaml(cfg, log_config=False) + reader, resample_stage, stage, writer = pipeline.stages + executor = create_executor_from_yaml(cfg) + + assert reader.__class__.__name__ == "ManifestReader" + assert resample_stage.__class__.__name__ == "ResampleAudioStage" + assert resample_stage.target_sample_rate == 16000 + assert resample_stage.target_format == "wav" + assert resample_stage.target_nchannels == 1 + assert Path(resample_stage.resampled_audio_dir).parts[-2:] == ( + "nemo_fastconformer_workspace", + "audio_resampled", + ) + assert stage.__class__.__name__ == "ASRStage" + assert stage.adapter_target == "nemo_curator.models.asr.nemo_asr.NeMoASRAdapter" + assert stage.model_id == "nvidia/stt_en_fastconformer_ctc_large" + assert stage.audio_filepath_key == "resampled_audio_filepath" + assert stage.target_sample_rate == 16000 + assert stage.pred_text_key == "custom_prediction" + assert stage.batch_size == 16 + assert stage.resources.gpus == 1 + assert dict(stage.adapter_kwargs) == { + "num_workers": 0, + "verbose": False, + "enable_local_attention": False, + } + assert writer.__class__.__name__ == "ManifestWriterStage" + assert executor.__class__.__name__ == "RayDataExecutor" + assert executor.config == {} + + +def test_run_cli_defaults_to_pipeline_config_for_fastconformer() -> None: + repo_root = Path(__file__).parents[2] + result = subprocess.run( # noqa: S603 + [ + sys.executable, + str(repo_root / "nemo_curator/config/run.py"), + "--config-path", + "../../tutorials/audio/nemo_fastconformer", + "--cfg", + "job", + "manifest_path=tests/fixtures/audio/tagging/sample_input.jsonl", + ], + cwd=repo_root, + check=True, + capture_output=True, + text=True, + ) + + assert "adapter_target: nemo_curator.models.asr.nemo_asr.NeMoASRAdapter" in result.stdout diff --git a/tests/gpu_test_groups.json b/tests/gpu_test_groups.json index ffdd6ddb55..324b63402a 100644 --- a/tests/gpu_test_groups.json +++ b/tests/gpu_test_groups.json @@ -17,7 +17,7 @@ }, "audio": { "extras": ["audio_cuda12"], - "paths": ["tests/stages/audio"] + "paths": ["tests/stages/audio", "tests/models/asr/test_nemo_asr.py"] }, "audio_qwen_asr": { "extras": ["audio_cuda12", "vllm"], diff --git a/tests/models/asr/test_nemo_asr.py b/tests/models/asr/test_nemo_asr.py new file mode 100644 index 0000000000..ea6a98182d --- /dev/null +++ b/tests/models/asr/test_nemo_asr.py @@ -0,0 +1,209 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# 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. + +"""Tests for the NeMo implementation of the shared ASR adapter.""" + +from __future__ import annotations + +import wave +from pathlib import Path +from types import SimpleNamespace +from unittest.mock import MagicMock, patch + +import numpy as np +import pytest +import torch +from omegaconf import OmegaConf + +from nemo_curator.models.asr import nemo_asr +from nemo_curator.models.asr.base import ASRAdapter +from nemo_curator.models.asr.nemo_asr import NeMoASRAdapter + +_MODEL_ID = "nvidia/stt_en_fastconformer_ctc_large" +_SAMPLE_RATE = 16_000 +_FIXTURE_PATH = Path(__file__).parents[2] / "fixtures/audio/qwen_omni/audio_1_5s_16khz_mono.wav" + + +def _item(samples: int = _SAMPLE_RATE, *, sample_rate: int = _SAMPLE_RATE) -> dict[str, object]: + return { + "waveform": np.zeros(samples, dtype=np.float32), + "sample_rate": sample_rate, + "audio_seconds": float(samples) / float(sample_rate), + } + + +def _mock_model(outputs: object) -> MagicMock: + model = MagicMock() + model.preprocessor._sample_rate = _SAMPLE_RATE + model.transcribe.return_value = outputs + return model + + +def _load_fixture() -> np.ndarray: + with wave.open(str(_FIXTURE_PATH), "rb") as wav_file: + assert wav_file.getframerate() == _SAMPLE_RATE + assert wav_file.getnchannels() == 1 + assert wav_file.getsampwidth() == 2 + pcm = np.frombuffer(wav_file.readframes(wav_file.getnframes()), dtype=" None: + assert isinstance(NeMoASRAdapter(), ASRAdapter) + + +def test_download_weights_uses_adapter_model_id() -> None: + nemo_asr = MagicMock() + adapter = NeMoASRAdapter(model_id="nvidia/stt_en_fastconformer_ctc_large") + with patch("nemo_curator.models.asr.nemo_asr._nemo_asr_module", return_value=nemo_asr): + adapter.download_weights_on_node() + + nemo_asr.models.ASRModel.from_pretrained.assert_called_once_with( + model_name="nvidia/stt_en_fastconformer_ctc_large", + return_model_file=True, + ) + + +def test_load_model_uses_stage_owned_gpu_count_and_is_idempotent() -> None: + adapter = NeMoASRAdapter() + model = _mock_model([]) + + with patch.object(adapter, "_load_checkpoint", return_value=model) as load: + adapter.load_model(num_gpus=0) + adapter.load_model(num_gpus=0) + + assert adapter._model is model + assert load.call_count == 1 + assert load.call_args.args[0].type == "cpu" + + +@pytest.mark.parametrize("num_gpus", [-1, 1.5, 2, True]) +def test_load_model_rejects_invalid_worker_gpu_counts(num_gpus: object) -> None: + adapter = NeMoASRAdapter() + + with pytest.raises(ValueError, match="requires num_gpus to be 0 or 1"): + adapter.load_model(num_gpus=num_gpus) # type: ignore[arg-type] + + +def test_load_model_configures_local_attention_when_enabled() -> None: + adapter = NeMoASRAdapter(enable_local_attention=True, local_attention_context_size=(64, 96)) + model = _mock_model([]) + + with patch.object(adapter, "_load_checkpoint", return_value=model): + adapter.load_model(num_gpus=0) + + model.change_attention_model.assert_called_once_with( + self_attention_model="rel_pos_local_attn", + att_context_size=[64, 96], + ) + model.change_subsampling_conv_chunking_factor.assert_called_once_with(1) + + +@pytest.mark.parametrize("enabled", [False, True]) +def test_load_model_configures_rnnt_cuda_graph_decoder_when_requested(enabled: bool) -> None: + adapter = NeMoASRAdapter(use_cuda_graph_decoder=enabled) + model = _mock_model([]) + model.cfg = OmegaConf.create({"decoding": {"strategy": "greedy_batch", "greedy": {}}}) + + with patch.object(adapter, "_load_checkpoint", return_value=model): + adapter.load_model(num_gpus=0) + + decoding_cfg = model.change_decoding_strategy.call_args.kwargs["decoding_cfg"] + assert decoding_cfg.strategy == "greedy_batch" + assert decoding_cfg.greedy.use_cuda_graph_decoder is enabled + + +def test_transcribe_batch_uses_one_exact_nemo_batch() -> None: + model = _mock_model([SimpleNamespace(text="alpha"), SimpleNamespace(text="beta")]) + adapter = NeMoASRAdapter(num_workers=2) + adapter._model = model + + results = adapter.transcribe_batch([_item(), _item(samples=2 * _SAMPLE_RATE)]) + + assert [result.text for result in results] == ["alpha", "beta"] + assert all(not result.skipped for result in results) + kwargs = model.transcribe.call_args.kwargs + assert kwargs["batch_size"] == 2 + assert kwargs["num_workers"] == 2 + assert len(kwargs["audio"]) == 2 + + +def test_transcribe_batch_preserves_empty_positions() -> None: + model = _mock_model(["valid"]) + adapter = NeMoASRAdapter() + adapter._model = model + + results = adapter.transcribe_batch([_item(samples=0), _item()]) + + assert [result.text for result in results] == ["", "valid"] + assert [result.skipped for result in results] == [True, False] + assert results[0].skip_reason == "empty_audio" + + +def test_transcribe_batch_requires_upstream_resampling() -> None: + adapter = NeMoASRAdapter() + adapter._model = _mock_model([]) + + with pytest.raises(ValueError, match="ASRStage must provide 16000 Hz"): + adapter.transcribe_batch([_item(sample_rate=8_000)]) + + +def test_transcribe_batch_requires_upstream_mono_conversion() -> None: + adapter = NeMoASRAdapter() + adapter._model = _mock_model([]) + item = _item() + item["waveform"] = np.zeros((1, _SAMPLE_RATE), dtype=np.float32) + + with pytest.raises(ValueError, match="mono 1-D waveform"): + adapter.transcribe_batch([item]) + + +@pytest.mark.parametrize( + ("outputs", "expected"), + [ + (([SimpleNamespace(text="tuple")], None), ["tuple"]), + ([[SimpleNamespace(text="nested")]], ["nested"]), + (["plain"], ["plain"]), + ], +) +def test_extract_transcription_texts_matches_nemo_output_shapes(outputs: object, expected: list[str]) -> None: + assert nemo_asr._extract_nemo_transcription_texts(outputs) == expected + + +@pytest.mark.gpu +def test_nemo_fastconformer_real_one_gpu_smoke() -> None: + """Load the default model and transcribe one existing five-second WAV.""" + if torch.cuda.device_count() < 1: + pytest.fail("NeMo FastConformer smoke test requires one visible GPU") + + adapter = NeMoASRAdapter(model_id=_MODEL_ID) + adapter.load_model(num_gpus=1) + try: + results = adapter.transcribe_batch( + [ + { + "waveform": _load_fixture(), + "sample_rate": _SAMPLE_RATE, + "language": "English", + "language_code": "en", + "task_id": "nemo-fastconformer-gpu-smoke", + } + ] + ) + finally: + adapter.unload_model() + + assert len(results) == 1 + assert results[0].text.strip() + assert results[0].skipped is False diff --git a/tests/models/asr/test_package_lazy_import.py b/tests/models/asr/test_package_lazy_import.py index be708e7d47..730283d115 100644 --- a/tests/models/asr/test_package_lazy_import.py +++ b/tests/models/asr/test_package_lazy_import.py @@ -25,10 +25,11 @@ def test_importing_asr_subpackage_does_not_load_concrete_adapters(monkeypatch: pytest.MonkeyPatch) -> None: - """The package init must not pull in either concrete Qwen adapter.""" + """The package init must not pull in concrete ASR adapters.""" original_import = builtins.__import__ blocked: list[str] = [] concrete_modules = { + "nemo_curator.models.asr.nemo_asr", "nemo_curator.models.asr.qwen_asr", "nemo_curator.models.asr.qwen_omni", } @@ -51,6 +52,7 @@ def tracking_import( module_names = { "nemo_curator.models.asr", "nemo_curator.models.asr.base", + "nemo_curator.models.asr.nemo_asr", "nemo_curator.models.asr.qwen_asr", "nemo_curator.models.asr.qwen_omni", } @@ -62,6 +64,7 @@ def tracking_import( import nemo_curator.models.asr as asr_pkg assert blocked == [] + assert "NeMoASRAdapter" not in vars(asr_pkg) assert "QwenASRAdapter" not in vars(asr_pkg) assert "QwenOmniASRAdapter" not in vars(asr_pkg) finally: @@ -81,3 +84,11 @@ def test_hydra_resolves_both_qwen_adapters_from_module_paths() -> None: } for target, expected_name in targets.items(): assert hydra.utils.get_class(target).__name__ == expected_name + + +def test_hydra_resolves_nemo_adapter_from_module_path() -> None: + import hydra.utils + + adapter_cls = hydra.utils.get_class("nemo_curator.models.asr.nemo_asr.NeMoASRAdapter") + + assert adapter_cls.__name__ == "NeMoASRAdapter" diff --git a/tests/models/asr/test_qwen_asr.py b/tests/models/asr/test_qwen_asr.py index f235f38403..7805cfcdc1 100644 --- a/tests/models/asr/test_qwen_asr.py +++ b/tests/models/asr/test_qwen_asr.py @@ -107,7 +107,7 @@ def test_qwen_adapter_copies_nested_vllm_kwargs() -> None: @pytest.mark.parametrize( "reserved_key", - QwenASRAdapter()._model_owned_vllm_kwargs(), + QwenASRAdapter()._adapter_owned_model_kwargs(), ) def test_qwen_adapter_rejects_adapter_owned_vllm_kwargs(reserved_key: str) -> None: adapter = QwenASRAdapter(vllm_kwargs={reserved_key: object()}) @@ -117,8 +117,24 @@ def test_qwen_adapter_rejects_adapter_owned_vllm_kwargs(reserved_key: str) -> No def test_download_weights_on_node_downloads_snapshot_without_constructing_model() -> None: + adapter = QwenASRAdapter(model_id="Qwen/Qwen3-ASR-0.6B", revision="abc123") with patch("nemo_curator.models.asr.qwen_asr.snapshot_download") as snapshot_download: - QwenASRAdapter.download_weights_on_node("Qwen/Qwen3-ASR-0.6B", "abc123") + adapter.download_weights_on_node() + snapshot_download.assert_called_once_with("Qwen/Qwen3-ASR-0.6B", revision="abc123") + + +def test_asr_stage_prefetches_qwen_adapter_with_adapter_owned_revision() -> None: + stage = ASRStage( + adapter_target="nemo_curator.models.asr.qwen_asr.QwenASRAdapter", + model_id="Qwen/Qwen3-ASR-0.6B", + adapter_kwargs={"revision": "abc123"}, + ) + with ( + patch("hydra.utils.get_class", return_value=QwenASRAdapter), + patch("nemo_curator.models.asr.qwen_asr.snapshot_download") as snapshot_download, + ): + stage.setup_on_node() + snapshot_download.assert_called_once_with("Qwen/Qwen3-ASR-0.6B", revision="abc123") diff --git a/tests/models/asr/test_qwen_omni.py b/tests/models/asr/test_qwen_omni.py index 74a5007a1d..573680692c 100644 --- a/tests/models/asr/test_qwen_omni.py +++ b/tests/models/asr/test_qwen_omni.py @@ -104,6 +104,15 @@ def _mock_qwen_model_load( yield llm_ctor, processor_cls.from_pretrained, sampling_ctor +@patch("nemo_curator.models.asr.qwen_omni.snapshot_download") +def test_qwen_adapter_download_weights_forwards_its_revision(mock_download: MagicMock) -> None: + adapter = QwenOmniASRAdapter(model_id="mock/qwen-omni", revision="abc123") + + adapter.download_weights_on_node() + + mock_download.assert_called_once_with("mock/qwen-omni", revision="abc123") + + @pytest.mark.parametrize("num_gpus", [0, -1, 1.5, True]) def test_qwen_adapter_load_model_requires_positive_integer_stage_gpu_count(num_gpus: object) -> None: adapter = QwenOmniASRAdapter(model_id="mock/qwen-omni") @@ -118,10 +127,10 @@ def test_qwen_adapter_rejects_invalid_prompt_content_order() -> None: @pytest.mark.parametrize("reserved_key", ["model", "revision", "tensor_parallel_size"]) -def test_qwen_adapter_rejects_stage_owned_vllm_kwargs(reserved_key: str) -> None: +def test_qwen_adapter_rejects_adapter_owned_vllm_kwargs(reserved_key: str) -> None: adapter = QwenOmniASRAdapter(model_id="mock/qwen-omni", vllm_kwargs={reserved_key: object()}) - with _mock_qwen_model_load(), pytest.raises(ValueError, match="cannot override stage-owned arguments"): + with _mock_qwen_model_load(), pytest.raises(ValueError, match="cannot override adapter-owned arguments"): adapter.load_model(num_gpus=1) diff --git a/tests/stages/audio/inference/test_asr_nemo.py b/tests/stages/audio/inference/test_asr_nemo.py deleted file mode 100644 index 1137451dbe..0000000000 --- a/tests/stages/audio/inference/test_asr_nemo.py +++ /dev/null @@ -1,201 +0,0 @@ -# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. -# -# 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. - -from pathlib import Path -from unittest.mock import MagicMock, patch - -import pytest - -from nemo_curator.stages.audio.inference.asr.asr_nemo import InferenceAsrNemoStage -from nemo_curator.stages.resources import Resources -from nemo_curator.tasks import AudioTask - - -class TestAsrNeMoStage: - """Test suite for InferenceAsrNemoStage.""" - - def test_stage_properties(self) -> None: - stage = InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2") - assert stage.name == "ASR_inference" - assert stage.inputs() == ([], ["audio_filepath"]) - assert stage.outputs() == ([], ["audio_filepath", "pred_text"]) - - def test_validate_input_valid(self) -> None: - stage = InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2") - assert stage.validate_input(AudioTask(data={"audio_filepath": "/a.wav"})) is True - - def test_validate_input_missing_filepath(self) -> None: - stage = InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2") - assert stage.validate_input(AudioTask(data={"text": "hello"})) is False - - def test_process_raises_not_implemented(self) -> None: - stage = InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2") - with pytest.raises(NotImplementedError, match="only supports process_batch"): - stage.process(AudioTask(data={"audio_filepath": "/a.wav"})) - - def test_process_batch_raises_on_missing_filepath(self) -> None: - with patch.object(InferenceAsrNemoStage, "transcribe", return_value=["x"]): - stage = InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2") - stage.setup_on_node() - stage.setup() - with pytest.raises(ValueError, match="missing required columns"): - stage.process_batch([AudioTask(data={"text": "hello"})]) - - def test_process_batch_single_entry(self) -> None: - with patch.object(InferenceAsrNemoStage, "transcribe", return_value=["the cat"]): - stage = InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2") - stage.setup_on_node() - stage.setup() - - entry = AudioTask(data={"audio_filepath": "/test/audio1.wav"}) - results = stage.process_batch([entry]) - - assert len(results) == 1 - assert isinstance(results[0], AudioTask) - assert results[0].data["audio_filepath"] == "/test/audio1.wav" - assert results[0].data["pred_text"] == "the cat" - - def test_process_batch_success(self) -> None: - with patch.object(InferenceAsrNemoStage, "transcribe", return_value=["the cat", "sat on a mat"]): - stage = InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2") - stage.setup_on_node() - stage.setup() - - tasks = [ - AudioTask(data={"audio_filepath": "/test/audio1.wav"}), - AudioTask(data={"audio_filepath": "/test/audio2.mp3"}), - ] - results = stage.process_batch(tasks) - - assert len(results) == 2 - assert all(isinstance(r, AudioTask) for r in results) - assert results[0].data["pred_text"] == "the cat" - assert results[1].data["pred_text"] == "sat on a mat" - - @patch("nemo_curator.stages.audio.inference.asr.asr_nemo.nemo_asr") - def test_setup_on_node_downloads_only(self, mock_nemo_asr: MagicMock) -> None: - mock_nemo_asr.models.ASRModel.from_pretrained.return_value = "/cache/model.nemo" - stage = InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2") - stage.setup_on_node() - mock_nemo_asr.models.ASRModel.from_pretrained.assert_called_once_with( - model_name="nvidia/parakeet-tdt-0.6b-v2", return_model_file=True - ) - assert stage.asr_model is None - - @patch("nemo_curator.stages.audio.inference.asr.asr_nemo.nemo_asr") - def test_setup_on_node_failure(self, mock_nemo_asr: MagicMock) -> None: - mock_nemo_asr.models.ASRModel.from_pretrained.side_effect = Exception("network error") - stage = InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2") - with pytest.raises(RuntimeError, match="Failed to download"): - stage.setup_on_node() - - def test_setup_on_node_skipped_when_model_provided(self) -> None: - stage = InferenceAsrNemoStage(model_name="dummy", asr_model=MagicMock()) - stage.setup_on_node() - - @patch("nemo_curator.stages.audio.inference.asr.asr_nemo.nemo_asr") - def test_setup_on_node_with_cache_dir(self, mock_nemo_asr: MagicMock, tmp_path: Path) -> None: - cache = str(tmp_path / "models") - mock_nemo_asr.models.ASRModel.from_pretrained.return_value = "/cache/model.nemo" - stage = InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2", cache_dir=cache) - stage.setup_on_node() - mock_nemo_asr.models.ASRModel.from_pretrained.assert_called_once_with( - model_name="nvidia/parakeet-tdt-0.6b-v2", return_model_file=True, cache_dir=cache - ) - - @patch("nemo_curator.stages.audio.inference.asr.asr_nemo.nemo_asr") - def test_setup_loads_model(self, mock_nemo_asr: MagicMock) -> None: - mock_model = MagicMock() - mock_nemo_asr.models.ASRModel.from_pretrained.return_value = mock_model - stage = InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2") - stage.setup() - assert stage.asr_model is mock_model - - @patch("nemo_curator.stages.audio.inference.asr.asr_nemo.nemo_asr") - def test_setup_with_cache_dir(self, mock_nemo_asr: MagicMock, tmp_path: Path) -> None: - cache = str(tmp_path / "models") - mock_model = MagicMock() - mock_nemo_asr.models.ASRModel.from_pretrained.return_value = mock_model - stage = InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2", cache_dir=cache) - stage.setup() - mock_nemo_asr.models.ASRModel.from_pretrained.assert_called_once() - call_kwargs = mock_nemo_asr.models.ASRModel.from_pretrained.call_args[1] - assert call_kwargs["cache_dir"] == cache - - @patch("nemo_curator.stages.audio.inference.asr.asr_nemo.nemo_asr") - def test_setup_failure(self, mock_nemo_asr: MagicMock) -> None: - mock_nemo_asr.models.ASRModel.from_pretrained.side_effect = Exception("GPU OOM") - stage = InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2") - with pytest.raises(RuntimeError, match="Failed to load"): - stage.setup() - - def test_setup_skipped_when_model_provided(self) -> None: - model = MagicMock() - stage = InferenceAsrNemoStage(model_name="dummy", asr_model=model) - stage.setup() - assert stage.asr_model is model - - def test_check_cuda_gpu(self) -> None: - stage = InferenceAsrNemoStage(model_name="dummy", resources=Resources(gpus=1.0)) - device = stage.check_cuda() - assert device.type == "cuda" - - def test_check_cuda_cpu(self) -> None: - stage = InferenceAsrNemoStage(model_name="dummy", resources=Resources(gpus=0.0)) - device = stage.check_cuda() - assert device.type == "cpu" - - def test_post_init_requires_model_name_or_model(self) -> None: - with pytest.raises(ValueError, match="Either model_name or asr_model"): - InferenceAsrNemoStage() - - def test_process_batch_empty(self) -> None: - stage = InferenceAsrNemoStage(model_name="dummy", asr_model=MagicMock()) - assert stage.process_batch([]) == [] - - def test_transcribe_tuple_outputs_hypothesis(self) -> None: - class Hypo: - def __init__(self, text: str) -> None: - self.text = text - - class DummyModel: - def transcribe(self, _files: list[str]) -> tuple[list[list[Hypo]], None]: - hyps = [[Hypo("alpha")], [Hypo("beta")]] - return (hyps, None) - - stage = InferenceAsrNemoStage(model_name="dummy-model", asr_model=DummyModel()) - outputs = stage.transcribe(["/a.wav", "/b.wav"]) - assert outputs == ["alpha", "beta"] - - def test_transcribe_nested_list_of_strings(self) -> None: - class DummyModel: - def transcribe(self, _files: list[str]) -> list[list[str]]: - return [["foo"], ["bar"]] - - stage = InferenceAsrNemoStage(model_name="dummy-model", asr_model=DummyModel()) - outputs = stage.transcribe(["/a.wav", "/b.wav"]) - assert outputs == ["foo", "bar"] - - def test_transcribe_list_of_objects_with_text(self) -> None: - class Hypo: - def __init__(self, text: str) -> None: - self.text = text - - class DummyModel: - def transcribe(self, _files: list[str]) -> list[Hypo]: - return [Hypo("x"), Hypo("y")] - - stage = InferenceAsrNemoStage(model_name="dummy-model", asr_model=DummyModel()) - outputs = stage.transcribe(["/a.wav", "/b.wav"]) - assert outputs == ["x", "y"] diff --git a/tests/stages/audio/inference/test_asr_stage.py b/tests/stages/audio/inference/test_asr_stage.py index 923fb68b9b..1e955a81d7 100644 --- a/tests/stages/audio/inference/test_asr_stage.py +++ b/tests/stages/audio/inference/test_asr_stage.py @@ -14,10 +14,12 @@ """Tests for the generic ``ASRStage`` exercised against a mock ``ASRAdapter`` (no real model load).""" +from pathlib import Path from unittest.mock import MagicMock, patch import numpy as np import pytest +import soundfile as sf from nemo_curator.backends.base import BaseStageAdapter from nemo_curator.models.asr.base import ASRResult @@ -39,6 +41,7 @@ def _make_stage( # noqa: PLR0913 waveform_key: str | None = None, keep_waveform: bool = False, extras_key: str | None = None, + fail_on_audio_error: bool = False, ) -> ASRStage: """Build an ASRStage wired to a mock adapter (no real model load).""" stage = ASRStage( @@ -52,6 +55,7 @@ def _make_stage( # noqa: PLR0913 waveform_key=waveform_key, keep_waveform=keep_waveform, extras_key=extras_key, + fail_on_audio_error=fail_on_audio_error, ) mock_adapter = MagicMock() stage._adapter = mock_adapter @@ -165,6 +169,16 @@ def test_audio_load_failure_skips_only_failed_item_and_preserves_order() -> None assert [item["task_id"] for item in inferred_items] == [tasks[0].task_id, tasks[2].task_id] +def test_audio_load_failure_can_fail_strict_benchmarks() -> None: + stage = _make_stage(fail_on_audio_error=True) + stage._load_audio.side_effect = RuntimeError("corrupt audio") + + with pytest.raises(RuntimeError, match="failed to prepare audio"): + stage.process_batch([_make_task()]) + + stage._adapter.transcribe_batch.assert_not_called() + + def test_skip_if_output_exists_reuses_prediction_and_only_infers_missing_rows() -> None: stage = _make_stage(skip_if_output_exists=True) stage._adapter.transcribe_batch.return_value = [ASRResult(text="new prediction")] @@ -348,29 +362,24 @@ def test_in_memory_input_contract_requires_waveform_and_sample_rate() -> None: assert required_inputs == ["waveform", "sampling_rate"] -def test_stage_loads_resampled_audio_like_tagging_pipeline_and_preserves_sample_rate() -> None: +def test_stage_loads_resampled_audio_with_torchaudio_and_preserves_sample_rate(tmp_path: Path) -> None: decoded_sample_rate = 8000 - decoded = np.ones(_SR, dtype=np.float32) - with patch( - "nemo_curator.stages.audio.inference.asr.stage.soundfile.read", - return_value=(decoded, decoded_sample_rate), - ) as load: - waveform, sample_rate = ASRStage._load_audio(_RESAMPLED_AUDIO_PATH) - - load.assert_called_once_with(_RESAMPLED_AUDIO_PATH, dtype="float32") + audio_path = tmp_path / "resampled.wav" + sf.write(audio_path, np.ones(_SR, dtype=np.float32), decoded_sample_rate, subtype="FLOAT") + + waveform, sample_rate = ASRStage._load_audio(str(audio_path)) assert sample_rate == decoded_sample_rate assert waveform.shape == (_SR,) assert waveform.dtype == np.float32 np.testing.assert_array_equal(waveform, np.ones(_SR, dtype=np.float32)) -def test_stage_load_audio_transposes_soundfile_stereo_to_channel_first() -> None: +def test_stage_load_audio_preserves_stereo_channel_first(tmp_path: Path) -> None: decoded = np.ones((_SR, 2), dtype=np.float32) - with patch( - "nemo_curator.stages.audio.inference.asr.stage.soundfile.read", - return_value=(decoded, _SR), - ): - waveform, sample_rate = ASRStage._load_audio(_RESAMPLED_AUDIO_PATH) + audio_path = tmp_path / "stereo.wav" + sf.write(audio_path, decoded, _SR, subtype="FLOAT") + + waveform, sample_rate = ASRStage._load_audio(str(audio_path)) assert sample_rate == _SR assert waveform.shape == (2, _SR) @@ -480,9 +489,13 @@ def test_skipped_result_sets_typed_skip_reason(result: ASRResult, expected_reaso @patch("nemo_curator.models.asr.qwen_omni.snapshot_download") def test_setup_on_node_downloads_weights(mock_download: MagicMock) -> None: - stage = ASRStage(adapter_target=_QWEN_ADAPTER_TARGET, model_id="mock/model") + stage = ASRStage( + adapter_target=_QWEN_ADAPTER_TARGET, + model_id="mock/model", + adapter_kwargs={"revision": "abc123"}, + ) stage.setup_on_node() - mock_download.assert_called_once_with("mock/model") + mock_download.assert_called_once_with("mock/model", revision="abc123") @patch( @@ -520,18 +533,27 @@ def test_model_id_required() -> None: ASRStage(adapter_target=_QWEN_ADAPTER_TARGET) +def test_stage_rejects_model_specific_revision_field() -> None: + with pytest.raises(TypeError, match="unexpected keyword argument 'revision'"): + ASRStage( + adapter_target=_QWEN_ADAPTER_TARGET, + model_id="mock/model", + revision="abc123", # type: ignore[call-arg] + ) + + def test_setup_uses_adapter_target_and_kwargs() -> None: """``setup()`` resolves adapter_target via hydra.utils.get_class and - constructs the adapter with model_id+revision+**adapter_kwargs.""" + constructs the adapter with model_id plus its explicit adapter_kwargs.""" stage = ASRStage( adapter_target=_QWEN_ADAPTER_TARGET, model_id="mock/model", - revision="abc123", adapter_kwargs={ + "revision": "abc123", "vllm_kwargs": { "max_model_len": 8192, "enable_prefix_caching": False, - } + }, }, resources=Resources(gpus=2), ) diff --git a/tests/stages/audio/tagging/inference/test_base_asr_processor.py b/tests/stages/audio/tagging/inference/test_base_asr_processor.py index 40de7f1b39..379387617b 100644 --- a/tests/stages/audio/tagging/inference/test_base_asr_processor.py +++ b/tests/stages/audio/tagging/inference/test_base_asr_processor.py @@ -12,6 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from pathlib import Path + +import numpy as np +import soundfile as sf + from nemo_curator.backends.base import WorkerMetadata from nemo_curator.stages.audio.tagging.inference.nemo_asr_align import BaseASRProcessorStage from nemo_curator.tasks import AudioTask @@ -94,3 +99,25 @@ def test_empty_segments_returns_empty_list(self) -> None: assert result == [] result = stage._prepare_segment_batch_with_metadata([{}], cut_audio_segments=False) assert result == [] + + def test_cuts_segments_with_torchaudio(self, tmp_path: Path) -> None: + sample_rate = 8000 + audio = np.linspace(-0.25, 0.25, sample_rate, dtype=np.float32) + audio_path = tmp_path / "source.wav" + sf.write(audio_path, audio, sample_rate, subtype="FLOAT") + stage = ConcreteASRProcessor(min_len=0.1) + + result = stage._prepare_segment_batch_with_metadata( + [ + { + "resampled_audio_filepath": str(audio_path), + "segments": [{"start": 0.25, "end": 0.75}], + } + ], + cut_audio_segments=True, + ) + + assert len(result) == 1 + assert result[0]["metadata_idx"] == 0 + assert result[0]["segment_idx"] == 0 + np.testing.assert_array_equal(result[0]["audio_segment"], audio[2000:6000]) diff --git a/tests/stages/audio/tagging/test_split.py b/tests/stages/audio/tagging/test_split.py index 6a8f45e893..48f349719b 100644 --- a/tests/stages/audio/tagging/test_split.py +++ b/tests/stages/audio/tagging/test_split.py @@ -13,6 +13,10 @@ # limitations under the License. from collections.abc import Callable +from pathlib import Path + +import numpy as np +import soundfile as sf from nemo_curator.stages.audio.tagging.split import ( JoinSplitAudioMetadataStage, @@ -61,7 +65,7 @@ def test_empty_segments_returns_empty_splits(self) -> None: class TestSplitLongAudioStageProcessDatasetEntry: - """Tests for SplitLongAudioStage.process (no actual audio I/O).""" + """Tests for SplitLongAudioStage.process.""" def test_short_audio_passthrough(self, audio_task: Callable[..., AudioTask]) -> None: """When duration < suggested_max_len, entry returned with split_filepaths wrapping the filepath.""" @@ -75,6 +79,32 @@ def test_short_audio_passthrough(self, audio_task: Callable[..., AudioTask]) -> out = result.data assert out["split_filepaths"] == ["test_1_resampled.wav"] + def test_long_audio_round_trip_with_torchaudio( + self, + tmp_path: Path, + audio_task: Callable[..., AudioTask], + ) -> None: + sample_rate = 8000 + audio_path = tmp_path / "long.wav" + sf.write(audio_path, np.zeros(sample_rate * 3, dtype=np.float32), sample_rate) + stage = SplitLongAudioStage(suggested_max_len=1.5, min_len=0.5) + task = audio_task( + duration=3.0, + segments=[ + {"start": 0.0, "end": 1.0}, + {"start": 1.0, "end": 2.0}, + {"start": 2.0, "end": 3.0}, + ], + audio_item_id="long", + resampled_audio_filepath=str(audio_path), + ) + + result = stage.process(task) + + assert len(result.data["split_filepaths"]) == 3 + assert result.data["split_offsets"] == [0.0, 1.0, 2.0] + assert all(sf.info(path).frames == sample_rate for path in result.data["split_filepaths"]) + class TestJoinSplitAudioMetadataStage: """Tests for JoinSplitAudioMetadataStage.""" diff --git a/tutorials/audio/README.md b/tutorials/audio/README.md index 1743a656b1..57b6df7b4f 100644 --- a/tutorials/audio/README.md +++ b/tutorials/audio/README.md @@ -32,23 +32,21 @@ PIPELINE COMPLETE [alm_data_overlap] output_windows (after overlap): 25 ``` -**With a GPU?** Try the FLEURS pipeline — it auto-downloads data and runs ASR: +**With a GPU?** Run FastConformer on the bundled two-file manifest: ```bash uv sync --extra audio_cuda12 && source .venv/bin/activate -python tutorials/audio/fleurs/main.py \ - --config-path . --config-name pipeline \ - raw_data_dir=./example_audio/fleurs \ - lang=en_us \ - stages.1.model_name=nvidia/parakeet-tdt-0.6b-v2 \ - stages.1.resources.gpus=1 +python nemo_curator/config/run.py \ + --config-path ../../tutorials/audio/nemo_fastconformer \ + manifest_path=tests/fixtures/audio/tagging/sample_input.jsonl ``` ## Which tutorial should I use? | I want to... | Tutorial | GPU | Data | |---|---|---|---| +| Transcribe a manifest with NeMo FastConformer through the shared ASR adapter | [**nemo_fastconformer/**](nemo_fastconformer/) | Recommended (1 per ASR actor) | Bundled sample or your own manifest | | Curate multilingual ASR data (download, transcribe, filter by WER) | [**fleurs/**](fleurs/) | Yes (~4 GB VRAM) | Auto-downloads from HuggingFace | | Transcribe a manifest in-process with Qwen3-Omni and vLLM | [**qwen_omni_inprocess/**](qwen_omni_inprocess/) | Yes (2 per ASR actor) | Bundled sample or your own manifest | | Transcribe a manifest with Qwen3-ASR through the generic ASR adapter | [**qwen_asr/**](qwen_asr/) | Yes (1 per ASR actor) | Bundled sample or your own manifest | @@ -62,6 +60,7 @@ python tutorials/audio/fleurs/main.py \ | Tutorial | Auto-download | Size | Notes | |---|---|---|---| +| `nemo_fastconformer/` | Model only | Two bundled audio files | Downloads the configured NeMo ASR checkpoint on first use | | `fleurs/` | Yes | ~50 MB per language split | Downloads from HuggingFace `google/fleurs` | | `qwen_omni_inprocess/` | Model only | Two bundled audio files | Downloads Qwen3-Omni weights on first use | | `qwen_asr/` | Model only | Two bundled audio files | Downloads Qwen3-ASR weights on first use | @@ -83,6 +82,7 @@ sudo apt-get install -y ffmpeg | Tutorial | System packages | Pip extras | |---|---|---| +| `nemo_fastconformer/` | `ffmpeg` | `audio_cpu` or `audio_cuda12` | | `fleurs/` | `ffmpeg` | `audio_cpu` or `audio_cuda12` | | `qwen_omni_inprocess/` | `ffmpeg` | `audio_cuda12`, `vllm` | | `qwen_asr/` | `ffmpeg` | `audio_cuda12`, `vllm` | diff --git a/tutorials/audio/fleurs/README.md b/tutorials/audio/fleurs/README.md index ecd34c9b8f..9219c0d04a 100644 --- a/tutorials/audio/fleurs/README.md +++ b/tutorials/audio/fleurs/README.md @@ -10,7 +10,7 @@ FLEURS contains spoken utterances across 100+ languages. This pipeline downloads ```mermaid flowchart LR - A["CreateInitialManifestFleursStage
HF download + JSONL"] --> B["InferenceAsrNemoStage
GPU transcription"] + A["CreateInitialManifestFleursStage
HF download + JSONL"] --> B["ASRStage + NeMoASRAdapter
GPU transcription"] B --> C["GetPairwiseWerStage
WER computation"] C --> D["GetAudioDurationStage
duration calc"] D --> E["PreserveByValueStage
wer_pct ≤ threshold"] @@ -69,7 +69,7 @@ python tutorials/audio/fleurs/main.py \ raw_data_dir=./example_audio/fleurs \ data_split=dev \ lang=en_us \ - stages.1.model_name=nvidia/parakeet-tdt-0.6b-v2 \ + stages.1.model_id=nvidia/parakeet-tdt-0.6b-v2 \ wer_threshold=25.0 \ backend=ray_data ``` @@ -80,7 +80,8 @@ python tutorials/audio/fleurs/main.py \ | `lang` | FLEURS language code (e.g. `en_us`, `hy_am`) | | `data_split` | FLEURS split: `train`, `dev`, or `test` | | `wer_threshold` | Keep samples with `wer_pct ≤` this value (default: `5.5`) | -| `stages.1.model_name` | NeMo ASR model for inference | +| `stages.1.model_id` | NeMo ASR model for inference | +| `stages.1.adapter_kwargs.use_cuda_graph_decoder` | RNNT CUDA-graph decoder override. The FLEURS hybrid-RNNT default is `false` for broad driver compatibility. | | `stages.1.resources.gpus` | GPUs for ASR (`0` for CPU) | | `backend` | `xenna` (default) or `ray_data` | @@ -101,9 +102,11 @@ Both backends run on top of Ray. `main.py` uses `RayClient` to manage the Ray cl Downloads the FLEURS split from HuggingFace (if not cached under `//`) and emits one `AudioTask` per utterance with `audio_filepath` and `text`. -### 2. `InferenceAsrNemoStage` +### 2. `ASRStage` + `NeMoASRAdapter` -Runs a NeMo ASR model on each audio file (GPU-accelerated). Adds `pred_text` to the task data. +`ASRStage` owns Curator task I/O, batching, resampling, and output assembly. The configured +`NeMoASRAdapter` owns NeMo checkpoint download, model lifecycle, and transcription. Together +they run a NeMo ASR model on each audio file and add `pred_text` to the task data. ### 3. `GetPairwiseWerStage` @@ -201,14 +204,18 @@ from nemo_curator.backends.xenna import XennaExecutor from nemo_curator.core.client import RayClient from nemo_curator.pipeline import Pipeline from nemo_curator.stages.audio.datasets.fleurs.create_initial_manifest import CreateInitialManifestFleursStage -from nemo_curator.stages.audio.inference.asr.asr_nemo import InferenceAsrNemoStage +from nemo_curator.stages.audio.inference.asr.stage import ASRStage from nemo_curator.stages.audio.metrics.wer import GetPairwiseWerStage pipeline = Pipeline( name="fleurs-custom", stages=[ CreateInitialManifestFleursStage(lang="en_us", split="dev", raw_data_dir="./data"), - InferenceAsrNemoStage(model_name="nvidia/parakeet-tdt-0.6b-v2"), + ASRStage( + adapter_target="nemo_curator.models.asr.nemo_asr.NeMoASRAdapter", + model_id="nvidia/parakeet-tdt-0.6b-v2", + audio_filepath_key="audio_filepath", + ), GetPairwiseWerStage(text_key="text", pred_text_key="pred_text", wer_key="wer_pct"), ], ) @@ -226,7 +233,8 @@ finally: | Problem | Cause | Fix | |---|---|---| | Output directory already exists | Previous run left `${raw_data_dir}/result/${lang}/` | Remove the directory before re-running | -| OOM during ASR inference | GPU VRAM too small for model + batch | Reduce `stages.0.batch_size` in `pipeline.yaml` or use a smaller model | +| OOM during ASR inference | GPU VRAM too small for model + batch | Reduce `stages.1.batch_size` or use a smaller model | +| `CUDA error: invalid argument` in RNNT label-loop decoding | NeMo CUDA-graph decoder is unsupported by the local CUDA runtime/driver combination | Set `stages.1.adapter_kwargs.use_cuda_graph_decoder=false` (the supplied FLEURS config already does this) | | CPU inference very slow | CPU is 10–50x slower than GPU | Set `stages.1.resources.gpus=1`; CPU is only for testing | | Empty output JSONL | `wer_threshold` too strict for the model+language pair | Increase `wer_threshold` or use a better-matching ASR model | | HuggingFace download fails | Network/auth issue | Check connectivity; some splits may need `huggingface-cli login` | diff --git a/tutorials/audio/fleurs/fleurs_tutorial.ipynb b/tutorials/audio/fleurs/fleurs_tutorial.ipynb index 5591a451a6..20939158d6 100644 --- a/tutorials/audio/fleurs/fleurs_tutorial.ipynb +++ b/tutorials/audio/fleurs/fleurs_tutorial.ipynb @@ -5,10 +5,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2026-06-11T16:39:21.369688Z", - "iopub.status.busy": "2026-06-11T16:39:21.368919Z", - "iopub.status.idle": "2026-06-11T16:39:21.397704Z", - "shell.execute_reply": "2026-06-11T16:39:21.394949Z" + "iopub.execute_input": "2026-08-07T18:04:45.263478Z", + "iopub.status.busy": "2026-08-07T18:04:45.263301Z", + "iopub.status.idle": "2026-08-07T18:04:45.291081Z", + "shell.execute_reply": "2026-08-07T18:04:45.290346Z" } }, "outputs": [], @@ -20,16 +20,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Curating the FLEURS Dataset with NeMo Curator\n", - "\n", - "This notebook walks through the FLEURS audio curation pipeline step by step:\n", - "1. Download a small FLEURS split\n", - "2. Run ASR inference\n", - "3. Compute WER and duration\n", - "4. Filter by WER threshold\n", - "5. Inspect and visualize results\n", - "\n", - "**Requirements**: GPU recommended for ASR inference. Install with `uv sync --extra audio_cuda12`." + "# Curating the FLEURS Dataset with NeMo Curator\n\nThis notebook walks through the FLEURS audio curation pipeline step by step:\n1. Download a small FLEURS split\n2. Run ASR inference\n3. Compute WER and duration\n4. Filter by WER threshold\n5. Inspect and visualize results\n\n**Requirements**: GPU recommended for ASR inference. Install with `uv sync --extra audio_cuda12`." ] }, { @@ -37,10 +28,10 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2026-06-11T16:39:21.404933Z", - "iopub.status.busy": "2026-06-11T16:39:21.404167Z", - "iopub.status.idle": "2026-06-11T16:39:28.753570Z", - "shell.execute_reply": "2026-06-11T16:39:28.752868Z" + "iopub.execute_input": "2026-08-07T18:04:45.293289Z", + "iopub.status.busy": "2026-08-07T18:04:45.292992Z", + "iopub.status.idle": "2026-08-07T18:04:52.768027Z", + "shell.execute_reply": "2026-08-07T18:04:52.767349Z" } }, "outputs": [ @@ -48,42 +39,40 @@ "name": "stderr", "output_type": "stream", "text": [ - "[NeMo W 2026-06-11 22:09:27 megatron_init:62] Megatron num_microbatches_calculator not found, using Apex version.\n" + "[NeMo W 2026-08-07 23:34:51 megatron_init:62] Megatron num_microbatches_calculator not found, using Apex version.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-06-11 22:09:27,454 - WARNING - OneLogger: Setting error_handling_strategy to DISABLE_QUIETLY_AND_REPORT_METRIC_ERROR for rank (rank=0) with OneLogger disabled. To override: explicitly set error_handling_strategy parameter.\n" + "2026-08-07 23:34:51,462 - WARNING - OneLogger: Setting error_handling_strategy to DISABLE_QUIETLY_AND_REPORT_METRIC_ERROR for rank (rank=0) with OneLogger disabled. To override: explicitly set error_handling_strategy parameter.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-06-11 22:09:27,476 - INFO - Final configuration contains 0 exporter(s)\n" + "2026-08-07 23:34:51,482 - INFO - Final configuration contains 0 exporter(s)\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-06-11 22:09:27,477 - WARNING - No exporters were provided. This means that no telemetry data will be collected.\n" + "2026-08-07 23:34:51,483 - WARNING - No exporters were provided. This means that no telemetry data will be collected.\n" ] } ], "source": [ - "import json\nimport os\nimport shutil\n\nfrom nemo_curator.backends.xenna import XennaExecutor\nfrom nemo_curator.core.client import RayClient\nfrom nemo_curator.pipeline import Pipeline\nfrom nemo_curator.stages.audio.common import GetAudioDurationStage, PreserveByValueStage\nfrom nemo_curator.stages.audio.datasets.fleurs.create_initial_manifest import CreateInitialManifestFleursStage\nfrom nemo_curator.stages.audio.inference.asr.asr_nemo import InferenceAsrNemoStage\nfrom nemo_curator.stages.audio.io.convert import AudioToDocumentStage\nfrom nemo_curator.stages.audio.metrics.wer import GetPairwiseWerStage\nfrom nemo_curator.stages.resources import Resources\nfrom nemo_curator.stages.text.io.writer import JsonlWriter\n\nconfigure_loguru()\n_silence_third_party_loggers()" + "import json\nimport os\nimport shutil\n\nfrom nemo_curator.backends.xenna import XennaExecutor\nfrom nemo_curator.core.client import RayClient\nfrom nemo_curator.pipeline import Pipeline\nfrom nemo_curator.stages.audio.common import GetAudioDurationStage, PreserveByValueStage\nfrom nemo_curator.stages.audio.datasets.fleurs.create_initial_manifest import CreateInitialManifestFleursStage\nfrom nemo_curator.stages.audio.inference.asr.stage import ASRStage\nfrom nemo_curator.stages.audio.io.convert import AudioToDocumentStage\nfrom nemo_curator.stages.audio.metrics.wer import GetPairwiseWerStage\nfrom nemo_curator.stages.resources import Resources\nfrom nemo_curator.stages.text.io.writer import JsonlWriter\n\nconfigure_loguru()\n_silence_third_party_loggers()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Configuration\n", - "\n", - "Adjust these parameters for your setup:" + "## Configuration\n\nAdjust these parameters for your setup:" ] }, { @@ -91,34 +80,22 @@ "execution_count": 3, "metadata": { "execution": { - "iopub.execute_input": "2026-06-11T16:39:28.755249Z", - "iopub.status.busy": "2026-06-11T16:39:28.754949Z", - "iopub.status.idle": "2026-06-11T16:39:28.758086Z", - "shell.execute_reply": "2026-06-11T16:39:28.757462Z" + "iopub.execute_input": "2026-08-07T18:04:52.769654Z", + "iopub.status.busy": "2026-08-07T18:04:52.769347Z", + "iopub.status.idle": "2026-08-07T18:04:52.772283Z", + "shell.execute_reply": "2026-08-07T18:04:52.771808Z" } }, "outputs": [], "source": [ - "RAW_DATA_DIR = os.path.abspath(\"./example_audio/fleurs\")\n", - "LANG = \"hy_am\"\n", - "SPLIT = \"dev\" # matches audio_fleurs_benchmark.py default (nightly CI uses train)\n", - "MODEL_NAME = \"nvidia/stt_hy_fastconformer_hybrid_large_pc\"\n", - "WER_THRESHOLD = 5.5\n", - "GPUS = 1.0\n", - "\n", - "RESULT_DIR = os.path.join(RAW_DATA_DIR, \"result\", LANG)\n", - "if os.path.isdir(RESULT_DIR):\n", - " shutil.rmtree(RESULT_DIR)" + "RAW_DATA_DIR = os.path.abspath(\"./example_audio/fleurs\")\nLANG = \"hy_am\"\nSPLIT = \"dev\" # matches audio_fleurs_benchmark.py default (nightly CI uses train)\nMODEL_NAME = \"nvidia/stt_hy_fastconformer_hybrid_large_pc\"\n# Keep GPU inference enabled while avoiding NeMo's RNNT label-loop CUDA graph,\n# which is unsupported by some CUDA runtime/driver combinations.\nUSE_CUDA_GRAPH_DECODER = False\nWER_THRESHOLD = 5.5\nGPUS = 1.0\n\nRESULT_DIR = os.path.join(RAW_DATA_DIR, \"result\", LANG)\nif os.path.isdir(RESULT_DIR):\n shutil.rmtree(RESULT_DIR)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 1: Build the pipeline\n", - "\n", - "The pipeline has 7 stages: download \u2192 ASR \u2192 WER \u2192 duration \u2192 filter \u2192 convert \u2192 write.\n", - "We define a function so we can rebuild the pipeline for each backend run." + "## Step 1: Build the pipeline\n\nThe pipeline has 7 stages: download \u2192 ASR \u2192 WER \u2192 duration \u2192 filter \u2192 convert \u2192 write.\nWe define a function so we can rebuild the pipeline for each backend run." ] }, { @@ -126,10 +103,10 @@ "execution_count": 4, "metadata": { "execution": { - "iopub.execute_input": "2026-06-11T16:39:28.759383Z", - "iopub.status.busy": "2026-06-11T16:39:28.759236Z", - "iopub.status.idle": "2026-06-11T16:39:28.764513Z", - "shell.execute_reply": "2026-06-11T16:39:28.763848Z" + "iopub.execute_input": "2026-08-07T18:04:52.773576Z", + "iopub.status.busy": "2026-08-07T18:04:52.773429Z", + "iopub.status.idle": "2026-08-07T18:04:52.777865Z", + "shell.execute_reply": "2026-08-07T18:04:52.777400Z" } }, "outputs": [ @@ -137,70 +114,19 @@ "name": "stdout", "output_type": "stream", "text": [ - "Pipeline: fleurs_tutorial\n", - "Description: Download FLEURS, run ASR, filter by WER\n", - "Stages: 7\n", - "\n", - "Stage 1: CreateInitialManifestFleurs\n", - " Resources: 1.0 CPUs\n", - " Batch size: 4\n", - " Outputs:\n", - " Output columns: audio_filepath, text\n", - "Stage 2: ASR_inference\n", - " Resources: 1.0 CPUs\n", - " GPU Memory: 0.0 GB (1.0 GPUs)\n", - " Batch size: 16\n", - " Inputs:\n", - " Required columns: audio_filepath\n", - " Outputs:\n", - " Output columns: audio_filepath, pred_text\n", - "Stage 3: GetPairwiseWerStage\n", - " Resources: 1.0 CPUs\n", - " Batch size: 1\n", - " Inputs:\n", - " Required columns: text, pred_text\n", - " Outputs:\n", - " Output columns: text, pred_text, wer_pct\n", - "Stage 4: GetAudioDurationStage\n", - " Resources: 1.0 CPUs\n", - " Batch size: 1\n", - " Inputs:\n", - " Required columns: audio_filepath\n", - " Outputs:\n", - " Output columns: duration\n", - "Stage 5: PreserveByValueStage\n", - " Resources: 1.0 CPUs\n", - " Batch size: 1\n", - " Inputs:\n", - " Required columns: wer_pct\n", - " Outputs:\n", - " Output columns: wer_pct\n", - "Stage 6: AudioToDocumentStage\n", - " Resources: 1.0 CPUs\n", - " Batch size: 1\n", - "Stage 7: jsonl_writer\n", - " Resources: 1.0 CPUs\n", - " Batch size: 1\n", - " Inputs:\n", - " Required attributes: data\n", - " Outputs:\n", - " Output attributes: data\n", - "\n" + "Pipeline: fleurs_tutorial\nDescription: Download FLEURS, run ASR, filter by WER\nStages: 7\n\nStage 1: CreateInitialManifestFleurs\n Resources: 1.0 CPUs\n Batch size: 4\n Outputs:\n Output columns: audio_filepath, text\nStage 2: ASR_inference\n Resources: 1.0 CPUs\n GPU Memory: 0.0 GB (1.0 GPUs)\n Batch size: 16\n Inputs:\n Required columns: audio_filepath\n Outputs:\n Output columns: pred_text, _skipme, additional_notes\nStage 3: GetPairwiseWerStage\n Resources: 1.0 CPUs\n Batch size: 1\n Inputs:\n Required columns: text, pred_text\n Outputs:\n Output columns: text, pred_text, wer_pct\nStage 4: GetAudioDurationStage\n Resources: 1.0 CPUs\n Batch size: 1\n Inputs:\n Required columns: audio_filepath\n Outputs:\n Output columns: duration\nStage 5: PreserveByValueStage\n Resources: 1.0 CPUs\n Batch size: 1\n Inputs:\n Required columns: wer_pct\n Outputs:\n Output columns: wer_pct\nStage 6: AudioToDocumentStage\n Resources: 1.0 CPUs\n Batch size: 1\nStage 7: jsonl_writer\n Resources: 1.0 CPUs\n Batch size: 1\n Inputs:\n Required attributes: data\n Outputs:\n Output attributes: data\n\n" ] } ], "source": [ - "def build_pipeline(result_dir: str) -> Pipeline:\n \"\"\"Create a fresh pipeline writing to *result_dir*.\"\"\"\n if os.path.isdir(result_dir):\n shutil.rmtree(result_dir)\n p = Pipeline(name=\"fleurs_tutorial\", description=\"Download FLEURS, run ASR, filter by WER\")\n p.add_stage(\n CreateInitialManifestFleursStage(lang=LANG, split=SPLIT, raw_data_dir=RAW_DATA_DIR).with_(batch_size=4)\n )\n p.add_stage(InferenceAsrNemoStage(model_name=MODEL_NAME).with_(resources=Resources(gpus=GPUS)))\n p.add_stage(GetPairwiseWerStage(text_key=\"text\", pred_text_key=\"pred_text\", wer_key=\"wer_pct\"))\n p.add_stage(GetAudioDurationStage(audio_filepath_key=\"audio_filepath\", duration_key=\"duration\"))\n p.add_stage(PreserveByValueStage(input_value_key=\"wer_pct\", target_value=WER_THRESHOLD, operator=\"le\"))\n p.add_stage(AudioToDocumentStage().with_(batch_size=1))\n p.add_stage(JsonlWriter(path=result_dir, write_kwargs={\"force_ascii\": False}))\n return p\n\n\nprint(build_pipeline(RESULT_DIR).describe())\n" + "def build_pipeline(result_dir: str) -> Pipeline:\n \"\"\"Create a fresh pipeline writing to *result_dir*.\"\"\"\n if os.path.isdir(result_dir):\n shutil.rmtree(result_dir)\n p = Pipeline(name=\"fleurs_tutorial\", description=\"Download FLEURS, run ASR, filter by WER\")\n p.add_stage(\n CreateInitialManifestFleursStage(lang=LANG, split=SPLIT, raw_data_dir=RAW_DATA_DIR).with_(batch_size=4)\n )\n p.add_stage(\n ASRStage(\n adapter_target=\"nemo_curator.models.asr.nemo_asr.NeMoASRAdapter\",\n model_id=MODEL_NAME,\n audio_filepath_key=\"audio_filepath\",\n adapter_kwargs={\"use_cuda_graph_decoder\": USE_CUDA_GRAPH_DECODER},\n batch_size=16,\n ).with_(resources=Resources(gpus=GPUS))\n )\n p.add_stage(GetPairwiseWerStage(text_key=\"text\", pred_text_key=\"pred_text\", wer_key=\"wer_pct\"))\n p.add_stage(GetAudioDurationStage(audio_filepath_key=\"audio_filepath\", duration_key=\"duration\"))\n p.add_stage(PreserveByValueStage(input_value_key=\"wer_pct\", target_value=WER_THRESHOLD, operator=\"le\"))\n p.add_stage(AudioToDocumentStage().with_(batch_size=1))\n p.add_stage(JsonlWriter(path=result_dir, write_kwargs={\"force_ascii\": False}))\n return p\n\n\nprint(build_pipeline(RESULT_DIR).describe())\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 2: Execute the pipeline with both backends\n", - "\n", - "`RayClient` manages the Ray cluster lifecycle (start/stop, port allocation, dashboard).\n", - "We run the pipeline with **both** backends and compare results and timing." + "## Step 2: Execute the pipeline with both backends\n\n`RayClient` manages the Ray cluster lifecycle (start/stop, port allocation, dashboard).\nWe run the pipeline with **both** backends and compare results and timing." ] }, { @@ -208,188 +134,114 @@ "execution_count": 5, "metadata": { "execution": { - "iopub.execute_input": "2026-06-11T16:39:28.765872Z", - "iopub.status.busy": "2026-06-11T16:39:28.765673Z", - "iopub.status.idle": "2026-06-11T16:41:07.066403Z", - "shell.execute_reply": "2026-06-11T16:41:07.065640Z" + "iopub.execute_input": "2026-08-07T18:04:52.779190Z", + "iopub.status.busy": "2026-08-07T18:04:52.779011Z", + "iopub.status.idle": "2026-08-07T18:06:27.648571Z", + "shell.execute_reply": "2026-08-07T18:06:27.647938Z" } }, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "2026-06-11 22:09:30,410\tINFO usage_lib.py:448 -- Usage stats collection is disabled.\n", - "2026-06-11 22:09:30,410\tINFO scripts.py:940 -- \u001b[37mLocal node IP\u001b[39m: \u001b[1m127.0.1.1\u001b[22m\n", - "2026-06-11 22:09:37,249\tSUCC scripts.py:979 -- \u001b[32m--------------------\u001b[39m\n", - "2026-06-11 22:09:37,249\tSUCC scripts.py:980 -- \u001b[32mRay runtime started.\u001b[39m\n", - "2026-06-11 22:09:37,249\tSUCC scripts.py:981 -- \u001b[32m--------------------\u001b[39m\n", - "2026-06-11 22:09:37,249\tINFO scripts.py:983 -- \u001b[36mNext steps\u001b[39m\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:986 -- To add another node to this Ray cluster, run\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:989 -- \u001b[1m ray start --address='127.0.1.1:6379'\u001b[22m\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1000 -- To connect to this Ray cluster:\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1002 -- \u001b[35mimport\u001b[39m\u001b[26m ray\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1003 -- ray\u001b[35m.\u001b[39m\u001b[26minit(_node_ip_address\u001b[35m=\u001b[39m\u001b[26m\u001b[33m'127.0.1.1'\u001b[39m\u001b[26m)\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1017 -- To submit a Ray job using the Ray Jobs CLI:\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1018 -- \u001b[1m RAY_API_SERVER_ADDRESS='http://127.0.0.1:8265' ray job submit --working-dir . -- python my_script.py\u001b[22m\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1027 -- See https://docs.ray.io/en/latest/cluster/running-applications/job-submission/index.html \n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1031 -- for more information on submitting Ray jobs to the Ray cluster.\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1036 -- To terminate the Ray runtime, run\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1037 -- \u001b[1m ray stop\u001b[22m\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1040 -- To view the status of the cluster, use\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1041 -- \u001b[1mray status\u001b[22m\u001b[26m\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1045 -- To monitor and debug Ray, view the dashboard at \n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1046 -- \u001b[1m127.0.0.1:8265\u001b[22m\u001b[26m\n", - "2026-06-11 22:09:37,250\tINFO scripts.py:1053 -- \u001b[4mIf connection to the dashboard fails, check your firewall settings and network configuration.\u001b[24m\n", - "2026-06-11 22:09:37,251\tINFO scripts.py:1159 -- \u001b[36m\u001b[1m--block\u001b[22m\u001b[39m\n", - "2026-06-11 22:09:37,251\tINFO scripts.py:1160 -- This command will now block forever until terminated by a signal.\n", - "2026-06-11 22:09:37,251\tINFO scripts.py:1163 -- Running subprocesses are monitored and a message will be printed if any of them terminate unexpectedly. Subprocesses exit with SIGTERM will be treated as graceful, thus NOT reported.\n", - "2026-06-11 22:09:37,251\tINFO scripts.py:1168 -- Process exit logs will be saved to: \u001b[1m/tmp/ray/session_2026-06-11_22-09-30_410708_724715/logs/ray_process_exit.log\u001b[22m\u001b[26m\n" + "2026-08-07 23:34:54,582 - INFO - NumExpr defaulting to 16 threads.\n" ] }, { - "name": "stderr", + "name": "stdout", "output_type": "stream", "text": [ - "2026-06-11 22:09:38,676\tINFO worker.py:1672 -- Using address 127.0.1.1:6379 set in the environment variable RAY_ADDRESS\n" + "2026-08-07 23:34:54,984\tINFO usage_lib.py:448 -- Usage stats collection is disabled.\n2026-08-07 23:34:54,984\tINFO scripts.py:1042 -- \u001b[37mLocal node IP\u001b[39m: \u001b[1m127.0.1.1\u001b[22m\n2026-08-07 23:35:01,521\tSUCC scripts.py:1081 -- \u001b[32m--------------------\u001b[39m\n2026-08-07 23:35:01,521\tSUCC scripts.py:1082 -- \u001b[32mRay runtime started.\u001b[39m\n2026-08-07 23:35:01,521\tSUCC scripts.py:1083 -- \u001b[32m--------------------\u001b[39m\n2026-08-07 23:35:01,521\tINFO scripts.py:1085 -- \u001b[36mNext steps\u001b[39m\n2026-08-07 23:35:01,521\tINFO cli_output_helpers.py:16 -- \u001b[2mNote: The following commands are intended for use on\u001b[22m\n2026-08-07 23:35:01,522\tINFO cli_output_helpers.py:17 -- \u001b[2mthe head node or within the cluster network.\u001b[22m\n2026-08-07 23:35:01,522\tINFO scripts.py:1089 -- To add another node to this Ray cluster, run\n2026-08-07 23:35:01,522\tINFO scripts.py:1092 -- \u001b[1m ray start --address='127.0.1.1:6380'\u001b[22m\n2026-08-07 23:35:01,522\tINFO scripts.py:1103 -- To connect to this Ray cluster:\n2026-08-07 23:35:01,522\tINFO scripts.py:1105 -- \u001b[35mimport\u001b[39m\u001b[26m ray\n2026-08-07 23:35:01,522\tINFO scripts.py:1106 -- ray\u001b[35m.\u001b[39m\u001b[26minit(_node_ip_address\u001b[35m=\u001b[39m\u001b[26m\u001b[33m'127.0.1.1'\u001b[39m\u001b[26m)\n2026-08-07 23:35:01,522\tINFO scripts.py:1120 -- To submit a Ray job using the Ray Jobs CLI:\n2026-08-07 23:35:01,522\tINFO scripts.py:1121 -- \u001b[1m RAY_API_SERVER_ADDRESS='http://127.0.0.1:8266' ray job submit --working-dir . -- python my_script.py\u001b[22m\n2026-08-07 23:35:01,522\tINFO scripts.py:1130 -- See https://docs.ray.io/en/latest/cluster/running-applications/job-submission/index.html \n2026-08-07 23:35:01,522\tINFO scripts.py:1134 -- for more information on submitting Ray jobs to the Ray cluster.\n2026-08-07 23:35:01,522\tINFO scripts.py:1139 -- To terminate the Ray runtime, run\n2026-08-07 23:35:01,522\tINFO scripts.py:1140 -- \u001b[1m ray stop\u001b[22m\n2026-08-07 23:35:01,522\tINFO scripts.py:1143 -- To view the status of the cluster, use\n2026-08-07 23:35:01,522\tINFO scripts.py:1144 -- \u001b[1mray status\u001b[22m\u001b[26m\n2026-08-07 23:35:01,522\tINFO scripts.py:1148 -- To monitor and debug Ray, view the dashboard at \n2026-08-07 23:35:01,522\tINFO scripts.py:1149 -- \u001b[1m127.0.0.1:8266\u001b[22m\u001b[26m\n2026-08-07 23:35:01,522\tINFO scripts.py:1156 -- \u001b[4mIf connection to the dashboard fails, check your firewall settings and network configuration.\u001b[24m\n2026-08-07 23:35:01,522\tINFO scripts.py:1262 -- \u001b[36m\u001b[1m--block\u001b[22m\u001b[39m\n2026-08-07 23:35:01,522\tINFO scripts.py:1263 -- This command will now block forever until terminated by a signal.\n2026-08-07 23:35:01,522\tINFO scripts.py:1266 -- Running subprocesses are monitored and a message will be printed if any of them terminate unexpectedly. Subprocesses exit with SIGTERM will be treated as graceful, thus NOT reported.\n2026-08-07 23:35:01,522\tINFO scripts.py:1271 -- Process exit logs will be saved to: \u001b[1m/tmp/ray/session_2026-08-07_23-34-55_007962_3227098/logs/ray_process_exit.log\u001b[22m\u001b[26m\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-06-11 22:09:38,681\tINFO worker.py:1814 -- Connecting to existing Ray cluster at address: 127.0.1.1:6379...\n" + "2026-08-07 23:35:04,888\tINFO worker.py:1683 -- Using address 127.0.1.1:6380 set in the environment variable RAY_ADDRESS\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-06-11 22:09:38,710\tINFO worker.py:2003 -- Connected to Ray cluster. View the dashboard at \u001b[1m\u001b[32mhttp://127.0.0.1:8265 \u001b[39m\u001b[22m\n" + "2026-08-07 23:35:04,894\tINFO worker.py:1833 -- Connecting to existing Ray cluster at address: 127.0.1.1:6380...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "[2026-06-11 22:09:38,712 I 723237 723237] logging.cc:303: Set ray log level from environment variable RAY_BACKEND_LOG_LEVEL to 2\n" + "2026-08-07 23:35:04,929\tINFO worker.py:2015 -- Connected to Ray cluster. View the dashboard at \u001b[1m\u001b[32mhttp://127.0.0.1:8266 \u001b[39m\u001b[22m\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-06-11 22:09:41,404\tINFO worker.py:1672 -- Using address 127.0.1.1:6379 set in the environment variable RAY_ADDRESS\n" + "[2026-08-07 23:35:04,931 I 3227011 3227011] logging.cc:303: Set ray log level from environment variable RAY_BACKEND_LOG_LEVEL to 2\n2026-08-07 23:35:07,521\tINFO worker.py:1683 -- Using address 127.0.1.1:6380 set in the environment variable RAY_ADDRESS\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-06-11 22:09:41,406\tINFO worker.py:1814 -- Connecting to existing Ray cluster at address: 127.0.1.1:6379...\n" + "2026-08-07 23:35:07,522\tINFO worker.py:1833 -- Connecting to existing Ray cluster at address: 127.0.1.1:6380...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-06-11 22:09:41,406\tINFO worker.py:1828 -- Calling ray.init() again after it has already been called.\n" + "2026-08-07 23:35:07,522\tINFO worker.py:1847 -- Calling ray.init() again after it has already been called.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-06-11 22:10:27,803\tINFO worker.py:1672 -- Using address 127.0.1.1:6379 set in the environment variable RAY_ADDRESS\n" + "2026-08-07 23:35:49,109\tINFO worker.py:1683 -- Using address 127.0.1.1:6380 set in the environment variable RAY_ADDRESS\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-06-11 22:10:27,806\tINFO worker.py:1814 -- Connecting to existing Ray cluster at address: 127.0.1.1:6379...\n" + "2026-08-07 23:35:49,112\tINFO worker.py:1833 -- Connecting to existing Ray cluster at address: 127.0.1.1:6380...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-06-11 22:10:27,827\tINFO worker.py:2003 -- Connected to Ray cluster. View the dashboard at \u001b[1m\u001b[32mhttp://127.0.0.1:8265 \u001b[39m\u001b[22m\n" + "2026-08-07 23:35:49,142\tINFO worker.py:2015 -- Connected to Ray cluster. View the dashboard at \u001b[1m\u001b[32mhttp://127.0.0.1:8266 \u001b[39m\u001b[22m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "[xenna] 49.13s \u2014 50 samples, mean WER 2.6%\n" + "[xenna] 44.20s \u2014 50 samples, mean WER 2.6%\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "[2026-06-11 22:10:39,317 E 723237 723237] core_worker.cc:2194: Actor with class name: 'MapWorker(MapBatches(FleursAsrStageActor))' and ID: '137913df0e59ce3cb8cf2e5c02000000' has constructor arguments in the object store and max_restarts > 0. If the arguments in the object store go out of scope or are lost, the actor restart will fail. See https://github.com/ray-project/ray/issues/53727 for more details.\n" + "[2026-08-07 23:36:06,231 E 3227011 3227011] core_worker.cc:2149: Actor with class name: 'MapWorker(MapBatches(ASRStageActor))' and ID: 'ee32769e30c13dcaf25853c102000000' has constructor arguments in the object store and max_restarts > 0. If the arguments in the object store go out of scope or are lost, the actor restart will fail. See https://github.com/ray-project/ray/issues/53727 for more details.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "[ray_data] 39.26s \u2014 50 samples, mean WER 2.6%\n" + "[ray_data] 38.56s \u2014 50 samples, mean WER 2.6%\n" ] } ], "source": [ - "import time\n", - "\n", - "from nemo_curator.backends.ray_data import RayDataExecutor\n", - "\n", - "# Avoid attaching to a stale Ray cluster left over from a prior notebook run.\n", - "os.environ.pop(\"RAY_ADDRESS\", None)\n", - "\n", - "ray_client = RayClient(num_gpus=int(GPUS))\n", - "ray_client.start()\n", - "configure_quiet_ray()\n", - "\n", - "\n", - "def load_results(result_dir: str) -> list[dict]:\n", - " \"\"\"Read all JSONL files from a result directory.\"\"\"\n", - " data = []\n", - " for fname in os.listdir(result_dir):\n", - " if fname.endswith(\".jsonl\"):\n", - " with open(os.path.join(result_dir, fname)) as f:\n", - " data.extend(json.loads(line) for line in f if line.strip())\n", - " return data\n", - "\n", - "\n", - "backends = {\n", - " \"xenna\": XennaExecutor,\n", - " \"ray_data\": RayDataExecutor,\n", - "}\n", - "\n", - "run_results = {}\n", - "\n", - "for name, executor_cls in backends.items():\n", - " result_dir = os.path.join(RAW_DATA_DIR, f\"result_{name}\")\n", - " pipeline = build_pipeline(result_dir)\n", - " executor = executor_cls()\n", - "\n", - " t0 = time.time()\n", - " with quiet_pipeline_run():\n", - " pipeline.run(executor)\n", - " elapsed = time.time() - t0\n", - "\n", - " data = load_results(result_dir)\n", - " wers = [r.get(\"wer_pct\", 0) for r in data]\n", - "\n", - " run_results[name] = {\n", - " \"time\": elapsed,\n", - " \"samples\": len(data),\n", - " \"mean_wer\": sum(wers) / len(wers) if wers else 0,\n", - " \"total_dur\": sum(r.get(\"duration\", 0) for r in data),\n", - " \"data\": data,\n", - " }\n", - " print(f\"[{name}] {elapsed:.2f}s \u2014 {len(data)} samples, mean WER {run_results[name]['mean_wer']:.1f}%\")" + "import time\n\nfrom nemo_curator.backends.ray_data import RayDataExecutor\n\n# Avoid attaching to a stale Ray cluster left over from a prior notebook run.\nos.environ.pop(\"RAY_ADDRESS\", None)\n\nray_client = RayClient(num_gpus=int(GPUS))\nray_client.start()\nconfigure_quiet_ray()\n\n\ndef load_results(result_dir: str) -> list[dict]:\n \"\"\"Read all JSONL files from a result directory.\"\"\"\n data = []\n for fname in os.listdir(result_dir):\n if fname.endswith(\".jsonl\"):\n with open(os.path.join(result_dir, fname)) as f:\n data.extend(json.loads(line) for line in f if line.strip())\n return data\n\n\nbackends = {\n \"xenna\": XennaExecutor,\n \"ray_data\": RayDataExecutor,\n}\n\nrun_results = {}\n\nfor name, executor_cls in backends.items():\n result_dir = os.path.join(RAW_DATA_DIR, f\"result_{name}\")\n pipeline = build_pipeline(result_dir)\n executor = executor_cls()\n\n t0 = time.time()\n with quiet_pipeline_run():\n pipeline.run(executor)\n elapsed = time.time() - t0\n\n data = load_results(result_dir)\n wers = [r.get(\"wer_pct\", 0) for r in data]\n\n run_results[name] = {\n \"time\": elapsed,\n \"samples\": len(data),\n \"mean_wer\": sum(wers) / len(wers) if wers else 0,\n \"total_dur\": sum(r.get(\"duration\", 0) for r in data),\n \"data\": data,\n }\n print(f\"[{name}] {elapsed:.2f}s \u2014 {len(data)} samples, mean WER {run_results[name]['mean_wer']:.1f}%\")" ] }, { @@ -397,10 +249,10 @@ "execution_count": 6, "metadata": { "execution": { - "iopub.execute_input": "2026-06-11T16:41:07.067853Z", - "iopub.status.busy": "2026-06-11T16:41:07.067698Z", - "iopub.status.idle": "2026-06-11T16:41:07.073170Z", - "shell.execute_reply": "2026-06-11T16:41:07.072667Z" + "iopub.execute_input": "2026-08-07T18:06:27.650184Z", + "iopub.status.busy": "2026-08-07T18:06:27.649769Z", + "iopub.status.idle": "2026-08-07T18:06:27.655205Z", + "shell.execute_reply": "2026-08-07T18:06:27.654584Z" } }, "outputs": [ @@ -408,45 +260,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", - "============================================================\n", - "Backend Comparison\n", - "============================================================\n", - " Xenna Ray Data Match\n", - " Time (s) 49.13 39.26 \n", - " Samples 50 50 \u2713\n", - " Mean WER 2.6 2.6 \u2713\n", - " Audio (s) 554.0 554.0 \u2713\n", - "\n", - "\u2192 ray_data was 1.3x faster on this dataset\n" + "\n============================================================\nBackend Comparison\n============================================================\n Xenna Ray Data Match\n Time (s) 44.20 38.56 \n Samples 50 50 \u2713\n Mean WER 2.6 2.6 \u2713\n Audio (s) 554.0 554.0 \u2713\n\n\u2192 ray_data was 1.1x faster on this dataset\n" ] } ], "source": [ - "MATCH_TOL = 0.1\n", - "\n", - "print(\"\\n\" + \"=\" * 60)\n", - "print(\"Backend Comparison\")\n", - "print(\"=\" * 60)\n", - "print(f\"{'':>12s} {'Xenna':>10s} {'Ray Data':>10s} {'Match':>6s}\")\n", - "print(f\"{'Time (s)':>12s} {run_results['xenna']['time']:10.2f} {run_results['ray_data']['time']:10.2f} {'':>6s}\")\n", - "print(\n", - " f\"{'Samples':>12s} {run_results['xenna']['samples']:10d} {run_results['ray_data']['samples']:10d}\"\n", - " f\" {'\u2713' if run_results['xenna']['samples'] == run_results['ray_data']['samples'] else '\u2717':>6s}\"\n", - ")\n", - "print(\n", - " f\"{'Mean WER':>12s} {run_results['xenna']['mean_wer']:10.1f} {run_results['ray_data']['mean_wer']:10.1f}\"\n", - " f\" {'\u2713' if abs(run_results['xenna']['mean_wer'] - run_results['ray_data']['mean_wer']) < MATCH_TOL else '\u2717':>6s}\"\n", - ")\n", - "print(\n", - " f\"{'Audio (s)':>12s} {run_results['xenna']['total_dur']:10.1f} {run_results['ray_data']['total_dur']:10.1f}\"\n", - " f\" {'\u2713' if abs(run_results['xenna']['total_dur'] - run_results['ray_data']['total_dur']) < MATCH_TOL else '\u2717':>6s}\"\n", - ")\n", - "speedup = run_results[\"ray_data\"][\"time\"] / run_results[\"xenna\"][\"time\"]\n", - "faster = \"xenna\" if speedup > 1 else \"ray_data\"\n", - "print(f\"\\n\u2192 {faster} was {max(speedup, 1 / speedup):.1f}x faster on this dataset\")\n", - "\n", - "results = run_results[\"xenna\"][\"data\"]" + "MATCH_TOL = 0.1\n\nprint(\"\\n\" + \"=\" * 60)\nprint(\"Backend Comparison\")\nprint(\"=\" * 60)\nprint(f\"{'':>12s} {'Xenna':>10s} {'Ray Data':>10s} {'Match':>6s}\")\nprint(f\"{'Time (s)':>12s} {run_results['xenna']['time']:10.2f} {run_results['ray_data']['time']:10.2f} {'':>6s}\")\nprint(\n f\"{'Samples':>12s} {run_results['xenna']['samples']:10d} {run_results['ray_data']['samples']:10d}\"\n f\" {'\u2713' if run_results['xenna']['samples'] == run_results['ray_data']['samples'] else '\u2717':>6s}\"\n)\nprint(\n f\"{'Mean WER':>12s} {run_results['xenna']['mean_wer']:10.1f} {run_results['ray_data']['mean_wer']:10.1f}\"\n f\" {'\u2713' if abs(run_results['xenna']['mean_wer'] - run_results['ray_data']['mean_wer']) < MATCH_TOL else '\u2717':>6s}\"\n)\nprint(\n f\"{'Audio (s)':>12s} {run_results['xenna']['total_dur']:10.1f} {run_results['ray_data']['total_dur']:10.1f}\"\n f\" {'\u2713' if abs(run_results['xenna']['total_dur'] - run_results['ray_data']['total_dur']) < MATCH_TOL else '\u2717':>6s}\"\n)\nspeedup = run_results[\"ray_data\"][\"time\"] / run_results[\"xenna\"][\"time\"]\nfaster = \"xenna\" if speedup > 1 else \"ray_data\"\nprint(f\"\\n\u2192 {faster} was {max(speedup, 1 / speedup):.1f}x faster on this dataset\")\n\nresults = run_results[\"xenna\"][\"data\"]" ] }, { @@ -461,10 +280,10 @@ "execution_count": 7, "metadata": { "execution": { - "iopub.execute_input": "2026-06-11T16:41:07.074593Z", - "iopub.status.busy": "2026-06-11T16:41:07.074372Z", - "iopub.status.idle": "2026-06-11T16:41:07.077430Z", - "shell.execute_reply": "2026-06-11T16:41:07.076900Z" + "iopub.execute_input": "2026-08-07T18:06:27.656634Z", + "iopub.status.busy": "2026-08-07T18:06:27.656445Z", + "iopub.status.idle": "2026-08-07T18:06:27.659318Z", + "shell.execute_reply": "2026-08-07T18:06:27.658788Z" } }, "outputs": [ @@ -472,32 +291,19 @@ "name": "stdout", "output_type": "stream", "text": [ - "Total samples after filtering: 50\n", - "\n", - "Sample entry:\n", - "{\n", - " \"audio_filepath\": \"/home/aaftabv/grananary-v2/references/CuratorPRReviews/tutorials/audio/fleurs/example_audio/fleurs/hy_am/dev/12606436530546538989.wav\",\n", - " \"text\": \"\u0547\u0561\u057f \u0564\u0565\u057a\u0584\u0565\u0580\u0578\u0582\u0574, \u0561\u0580\u057f\u0561\u057d\u0561\u0570\u0574\u0561\u0576\u0578\u0582\u0574 \u0574\u0561\u057d\u0576\u0561\u056f\u0581\u0565\u056c\u0578\u057e \u057f\u0561\u0580\u056f\u0565\u057f\u0574\u0561\u0576 \u0564\u0561\u057d\u0568\u0576\u0569\u0561\u0581\u056b, \u056f\u0561\u0580\u0578\u0572 \u0565\u0584 \u056b\u0580\u0561\u056f\u0561\u0576\u0578\u0582\u0574 \u0562\u0561\u0580\u0565\u056c\u0561\u057e\u0565\u056c \u0570\u0561\u0575\u0580\u0565\u0576\u056b\u0584\u0578\u0582\u0574 \u0562\u0561\u0580\u0571\u0580\u0561\u0563\u0578\u0582\u0575\u0576 \u056f\u0580\u0569\u0561\u056f\u0561\u0576 \u0570\u0561\u057d\u057f\u0561\u057f\u0578\u0582\u0569\u0575\u0578\u0582\u0576 \u057f\u0565\u0572\u0561\u0583\u0578\u056d\u057e\u0565\u056c\u0578\u0582 \u0571\u0565\u0580 \u0570\u0576\u0561\u0580\u0561\u057e\u0578\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0576\u0565\u0580\u0568\u0589\",\n", - " \"pred_text\": \"\u0547\u0561\u057f \u0564\u0565\u057a\u0584\u0565\u0580\u0578\u0582\u0574, \u0561\u0580\u057f\u0561\u057d\u0561\u0570\u0574\u0561\u0576\u0578\u0582\u0574 \u0574\u0561\u057d\u0576\u0561\u056f\u0581\u0565\u056c\u0578\u057e \u057f\u0561\u0580\u056f\u0565\u057f\u0574\u0561\u0576 \u0564\u0561\u057d\u0568\u0576\u0569\u0561\u0581\u056b, \u056f\u0561\u0580\u0578\u0572 \u0565\u0584 \u056b\u0580\u0561\u056f\u0561\u0576\u0578\u0582\u0574 \u0562\u0561\u0580\u0565\u056c\u0561\u057e\u0565\u056c \u0570\u0561\u0575\u0580\u0565\u0576\u056b\u0584\u0578\u0582\u0574 \u0562\u0561\u0580\u0571\u0580\u0561\u0563\u0578\u0582\u0575\u0576 \u056f\u0580\u0569\u0561\u056f\u0561\u0576 \u0570\u0561\u057d\u057f\u0561\u057f\u0578\u0582\u0569\u0575\u0578\u0582\u0576 \u057f\u0565\u0572\u0561\u0583\u0578\u056d\u057e\u0565\u056c\u0578\u0582 \u0571\u0565\u0580 \u0570\u0576\u0561\u0580\u0561\u057e\u0578\u0580\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0576\u0565\u0580\u0568\u0589\",\n", - " \"wer_pct\": 0.0,\n", - " \"duration\": 12.3\n", - "}\n" + "Total samples after filtering: 50\n\nSample entry:\n{\n \"audio_filepath\": \"/home/aaftabv/prs-into-curator/CuratorPR2254FastConformer/tutorials/audio/fleurs/example_audio/fleurs/hy_am/dev/11348083370274933042.wav\",\n \"text\": \"\u053b\u057d\u0580\u0561\u0575\u0565\u056c\u0568 \u057a\u0561\u0570\u0561\u0576\u057b\u0578\u0582\u0574 \u0567 \u0577\u0561\u0580\u0578\u0582\u0576\u0561\u056f\u0561\u056f\u0561\u0576 \u057c\u0561\u0566\u0574\u0561\u056f\u0561\u0576 \u0576\u0565\u0580\u056f\u0561\u0575\u0578\u0582\u0569\u0575\u0578\u0582\u0576 \u0570\u0578\u057e\u057f\u0578\u0582\u0574 \u057f\u0561\u057d\u0568 \u057f\u0561\u0580\u057e\u0561 \u0568\u0576\u0569\u0561\u0581\u0584\u0578\u0582\u0574 \u057a\u0561\u0575\u0574\u0561\u0576\u0561\u0563\u056b\u0580\u0568 \u056f\u0576\u0584\u0565\u056c\u0578\u0582\u0581 \u0570\u0565\u057f\u0578, \u0574\u056b\u0576\u0579\u0564\u0565\u057c \u054a\u0561\u0572\u0565\u057d\u057f\u056b\u0576\u056b \u056b\u0580\u0561\u057e\u0561\u057d\u0578\u0582 \u0574\u0561\u0580\u0574\u056b\u0576\u0576\u0565\u0580\u0568 \u0570\u0561\u0574\u0561\u0571\u0561\u0575\u0576\u057e\u0578\u0582\u0574 \u0565\u0576 \u0569\u0578\u0572\u0576\u0565\u056c \u0561\u0575\u0564\u057a\u056b\u057d\u056b \u0576\u0565\u0580\u056f\u0561\u0575\u0578\u0582\u0569\u0575\u0561\u0576\u0568 \u0574\u056b\u0561\u0575\u0576 \u0570\u056b\u0576\u0563 \u057f\u0561\u0580\u0578\u057e:\",\n \"pred_text\": \"\u053b\u057d\u0580\u0561\u0575\u0565\u056c\u0568 \u057a\u0561\u0570\u0561\u0576\u057b\u0578\u0582\u0574 \u0567 \u0577\u0561\u0580\u0578\u0582\u0576\u0561\u056f\u0561\u056f\u0561\u0576 \u057c\u0561\u0566\u0574\u0561\u056f\u0561\u0576 \u0576\u0565\u0580\u056f\u0561\u0575\u0578\u0582\u0569\u0575\u0578\u0582\u0576 \u0570\u0578\u057e\u057f\u0578\u0582\u0574 \u057f\u0561\u057d\u0568 \u057f\u0561\u0580\u057e\u0561 \u0568\u0576\u0569\u0561\u0581\u0584\u0578\u0582\u0574 \u057a\u0561\u0575\u0574\u0561\u0576\u0561\u0563\u056b\u0580\u0568 \u056f\u0576\u0584\u0565\u056c\u0578\u0582\u0581 \u0570\u0565\u057f\u0578, \u0574\u056b\u0576\u0579\u0564\u0565\u057c \u054a\u0561\u0572\u0565\u057d\u057f\u056b\u0576\u056b \u056b\u0580\u0561\u057e\u0561\u057d\u0578\u0582 \u0574\u0561\u0580\u0574\u056b\u0576\u0576\u0565\u0580\u0568 \u0570\u0561\u0574\u0561\u0571\u0561\u0575\u0576\u057e\u0578\u0582\u0574 \u0565\u0576 \u0569\u0578\u0572\u0576\u0565\u056c \u0561\u0575\u0564\u057a\u056b\u057d\u056b \u0576\u0565\u0580\u056f\u0561\u0575\u0578\u0582\u0569\u0575\u0561\u0576\u0568 \u0574\u056b\u0561\u0575\u0576 \u0570\u056b\u0576\u0563 \u057f\u0561\u0580\u0578\u057e\u0589\",\n \"wer_pct\": 4.0,\n \"duration\": 19.2\n}\n" ] } ], "source": [ - "print(f\"Total samples after filtering: {len(results)}\")\n", - "print(\"\\nSample entry:\")\n", - "print(json.dumps(results[0], indent=2, ensure_ascii=False) if results else \"No results\")" + "print(f\"Total samples after filtering: {len(results)}\")\nprint(\"\\nSample entry:\")\nprint(json.dumps(results[0], indent=2, ensure_ascii=False) if results else \"No results\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 4: Visualize results\n", - "\n", - "### WER distribution" + "## Step 4: Visualize results\n\n### WER distribution" ] }, { @@ -505,16 +311,16 @@ "execution_count": 8, "metadata": { "execution": { - "iopub.execute_input": "2026-06-11T16:41:07.078903Z", - "iopub.status.busy": "2026-06-11T16:41:07.078746Z", - "iopub.status.idle": "2026-06-11T16:41:07.813179Z", - "shell.execute_reply": "2026-06-11T16:41:07.812498Z" + "iopub.execute_input": "2026-08-07T18:06:27.660795Z", + "iopub.status.busy": "2026-08-07T18:06:27.660644Z", + "iopub.status.idle": "2026-08-07T18:06:28.246610Z", + "shell.execute_reply": "2026-08-07T18:06:28.246014Z" } }, "outputs": [ { "data": { - "image/png": "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SktLc1lvz549uvfee1W+fHnZ7XaVLVtWbdq00ddff53rNn788UcdPXo0y7cOihUrpkaNGunHH39UYmKis33btm1KSEjQgAEDVKZMGZf3qfR/089ER0fneT/zIqfPuoLYv3+/pk2bpg4dOigkJESdO3fOMi1Bbi5evOhyXAoiLS1NDocjx+VJSUmSpJCQEEmSh4eHgoODlZCQ4Fxn1KhRqlSpkgYPHnzFbbVq1UrFihXTJ598clWZAQCAK4q2AAAUgsTERJ05c8blduHChQL3l5qamqW/M2fOFOqFfc6dO6ezZ886f6nPVKVKFUnS3LlzsxR48mvnzp2666671KhRI02dOlXt27fXnDlzNGLECOc6jz76qCTpvffey/L8+fPnKz09Pd/TMcybN09nz55Vnz59NH36dA0fPlx79+5V27Zt9d1332VZPyEhQbfddpuCg4M1efJkde/eXfPnz1f//v01ePBgff755xo8eLDGjx+vY8eOqXPnznl+vVNSUrR8+fI8nWW7detWtWvXTvv379dTTz2l0aNH66efflKfPn2yXf+hhx7SoEGDVLVqVb388ssaP3684uLidPvttzvn8AwODlaXLl309ddf6+zZsy7Pz8jI0MKFC1W3bt1sv2ZuhqCgIAUFBcnPz0+33367tm7dmmWdbdu2qXz58qpYsaJLe8WKFRUWFqZt27blup17771Xb775pu68805Nnz5dY8eOVePGjbOcHfrqq6+qZMmSGjJkiGbMmKH77rtPS5YsUbNmzbL9+fz555917733qnXr1poyZYqqVaump59+Wq+//rratm2rc+fOady4cXr88ce1YsWKHF/bPn36aMuWLc73wV9//aU77rgj23liL/f111+refPm2r9/v0aOHKk33nhDTZs21XPPPadevXo514uNjdVtt92mjRs3qn///po5c6ZGjBihUqVKZXvcL5f5R5Dspq9o06aNUlNTXf7AsX79egUEBKhhw4aKjo52OdaZZ+HWrVvXOTfupbL7fDxz5kyePqNy+qzLi6SkJC1fvlyDBw9WlSpVFBUVpeHDh+vvv//WkCFDtG7dOkVGRua5vylTpsjf31/FihVTxYoV9dxzzyk5OTlfmbZu3Sp/f38FBQUpODhYMTExWYr/DRo0kLe3t5599lkdPXpU8+fP1y+//OI8A33Dhg2aP3++3nnnHXl4XPlXRk9PTzVq1CjbP3oBAICrYAAAALdZt26dISnbW8+ePV3WlWR06tQp1z5z6k+SUaxYMZd1w8PDjfDw8Bz7iomJMSQZhw8fdraNHTvWkGSsXr3a+Oeff4wTJ04YmzZtMlq3bm1IMkaNGuXSx9mzZ42KFSsakozSpUsb99xzjzF58mTju+++M9LT03M/SJfsl81mM7Zs2eLSfueddxpeXl7GhQsXnG1NmzY1ypUrZ6SlpbmsW61aNaNmzZp53mam+Pj4LG0nT540QkNDjY4dO7q0R0dHG5KMl19+2aW9W7duhs1mMxo0aGCkpKQ425cuXWpIMmbNmpWnLMuXLzckGdu2bct13aZNmxre3t7Gvn37nG3JyclGo0aNDEnG2LFjne2ff/65IcmYPXu2Sx+pqalGgwYNjIiICCMjI8MwDMP46quvDEnGjBkzXNZdvXq1IcmYMmVKnvalMD311FPG8OHDjQ8++MBYsmSJMW7cOCM4ONjw9vY2Vq1a5bJuQECA0bhx42z7adSokVGuXLkrbuv8+fOGJOM///lPrrmyey9lHreXXnrJpT2793xycrJRtmxZw2azGYMHD3ZZf/jw4YYk4/fff3e2Zf68Nm7c2EhOTna2Hzt2zChWrJhRo0YNlz7Cw8ON6Oho5+OkpCSjTJkyRsuWLY3U1FSXdadOnWpIMtatW2cYxv+9lz/66KNcj0N2+vTpY0gy4uLisizLPEajR492trVv397o0KGDYRiG8dZbbxne3t7O4/vDDz8YkoyhQ4e69JP585nT7dKfq/x+1uUkKSnJeOONN4w77rjD8PX1dX4Wd+7c2Zg5c6bx559/5vdQGUePHjVuu+0244033jCWLl1qvPvuu0b79u0NSUa7du2yfPbl5M477zSef/5549NPPzU+/PBD47HHHjM8PT2N8uXLG3///bfLujNnzjTsdrvzWPXt29fIyMgwLl68aFSvXt3ltcnNI488Ykgyzpw5k6/9BgAAOaNoCwCAG2UWbQcMGGCsWrXK5bZr1y6XdfNTtG3SpEmW/latWuUsrmS6mqLt5Te73W489dRTWQo7hmEYp0+fNp566imjWrVqLs+JiIgwvv3221z3KXO/mjVrlqX91VdfNSS5HK+5c+cakoxly5Y52zZs2GBIMl599dU8bS8nFy5cMM6cOWP8888/xp133mmEhIS4LI+OjjY8PT2NpKQkl/bMAtc777zj0n727FlDkjFy5Mg8bX/AgAFGhQoVcl3v1KlThiSjR48eWZYtWrQoS9G2e/fuRvHixY1Tp04Z//zzj8tt3LhxhiRn8Tc1NdUoU6aM0aRJE5d++/TpY3h5eRknT57M075ca/v37zf8/f2NqlWrurR7eHgYLVu2zPY5LVu2NIKCgq7Yb3JysmG3241bbrnF5WflStLT043z5887j3FQUJDRvXt3l3Vyes936dLFkGQcOHDApT2z8P7ll1862zJ/Xj/88MMs/QwYMMCQZPz222/OtsuLtsuWLTMkGe+9916W98Xvv//uUkhdv369s5iXXeE1Nx07djS8vLyyXZaYmGj4+PgYTZs2NQzj3/dgsWLFjBdffNEwDMPYs2ePIcn5efLiiy8akowvvvjCpZ/o6GjD19c328/HVatWGQ6HI8uxy89nXXYOHz7sfK6Pj4/xxBNPFOj45MWjjz5qSDI++OCDAvexcOFCQ5LRv3//LMvOnj1rbN682aXQPGbMGKNq1apGUlKSERsbazz00ENG+fLljfr16xsff/xxttt48skns7z3AADA1eFCZAAAFIJq1apluSr61ShZsqRb+7PZbFnaZsyYoerVqysxMVHr1q3TG2+8oXPnzmV7NfBSpUpp8uTJmjx5smJjY7V582Z9/PHH+uCDD9StWzf98ssvqlq1aq45KleunKUt86vPl361vGfPnho2bJjmzJmjzp07S5LmzJkjHx+fHL8+fiWHDh3SmDFj9O233+r8+fMuy7I7NuXKlZOvr69LW4kSJSQpy1efM9vzMnVFRkaGli5dqnvvvTfXdf/44w9J/14Z/nK1atXK0rZ3715duHBBZcqUybHPU6dOqXr16vLy8lLv3r01depU7d+/X9WrV1dCQoI+//xztW/f/op9SFJ8fHyO8+rmhY+PT4G+ml6tWjXdd999mjdvnjO3JPn7++f4lfKLFy/K398/1zyZF9qLjIxUrVq1dNttt6lr165Z5nJeu3atJkyYoK1bt+rixYsuy86dO5el7+ze8wV5L9WsWTNLW+b74I8//sh2ufTv+0LSFeeBPnXqlCQpOjpaffr00bx587Rw4UI1atRI7dq1U8+ePbN9z10uu5+lTH5+frr11lv1ww8/KCEhQb/++qsSEhKc89XWqlVLpUqV0rp169S+fXutX79eHh4e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fJxZ8M1Uvnx5Pfjgg3nabo8ePVSyZElJ0mOPPab7779fH330kX788Uc1btw41+d7eXll2dbEiRM1efJkjR49Wo8++qg++ugj5zIfH5885SqojIwMpaSkyNfXV76+voW6rdzY7XZTtw8AAIq2w4cP64cfftDnn3+uxx57TAsXLtTYsWOvybYLYxxVvXr1LOPGyZMnq3Pnzho5cqRq1KihO++80y3bSkxMlL+//1X3Y7PZTB1TMtbOGWNtoGjhTywAirQWLVro559/VlJSkrPt+++/V+3atdWxY0dt2bLF5WtQ33//vWw2m5o3b+62DC1btpQkHTp06Kr6efrpp9W+fXt98skn2r9/v7M9u3m2pk+frtq1a8vf318lSpRQw4YNtWjRIkn/TuMwatQoSVJkZKTz62FHjhyR9O9AetCgQVq4cKFq164tu92uFStWOJdlNxfbmTNndN999ykwMFChoaEaOnSoLl686Fx+pbnLLu0zt2zZzbP1xx9/6N5771VISIj8/f1166236uuvv3ZZZ/369bLZbPr444/1wgsvqEKFCvL19VXbtm118ODBHI85AAC4vixcuFAlSpRQp06d1KNHDy1cuDDLOpnjhvXr17u05zSe+eKLL1SnTh35+vqqTp062U7NJWU/jvr555/VsWNHBQYGKiAgQG3bttWWLVuuZhcVGhqqxYsXy8vLSy+88IKzfd68eS7jqkzZ7W/r1q1Vp04dbd++Xa1atZK/v7/+97//SZKWLl2qTp06KSwsTHa7XVWqVNHzzz+v9PR0l+d//fXXOnr0qHM8lznHb07Hce3atWrZsqWKFSum4OBg3X333dq7d6/LOpnTkR08eNB5pmhQUJAefvhhJSYmXtVxY6zNWBsoajjTFkCR1qJFC73//vvaunWrc7D1/fffq1mzZmrWrJni4uK0e/du1a1b17msRo0aCg0NdeknNTU12wsAFCtWTH5+flfMkDkIKlGixFXvz0MPPaSVK1dq1apVql69erbrvPPOOxoyZIh69OjhHND9+uuv2rp1qx544AF1795d+/fv14cffqjXXnvNeVZwqVKlnH2sXbtWH3/8sQYNGqSSJUtmuZDG5e677z5FRERo0qRJ2rJli9544w2dO3dOCxYsyNf+5SXbpU6dOqVmzZopMTFRQ4YMUWhoqObPn68uXbro008/dZkWQ/r3zBMPDw898cQTiouL08svv6zevXtr69at+coJAACKpoULF6p79+7y8fFRr169NHPmTG3btk2NGjUqUH8rV67UPffco1q1amnSpEmKjY3Vww8/rAoVKuT63D179qhly5YKDAzUk08+KW9vb82ePVutW7fWhg0brmrO3UqVKik6Olrr1q2Tw+Fw+bp/XsXGxqpjx466//779eCDD6pMmTKS/i3+BgQEaMSIEQoICNDatWv13HPPyeFw6JVXXpEkjRkzRnFxcfrrr7/02muvSZICAgJy3Nbq1avVsWNHVa5cWePGjVNSUpKmT5+u5s2ba8eOHVnGovfdd58iIyM1adIk7dixQ++++65Kly6tl156Kd/7eSnG2q4YawPWRtEWQJF26by2rVu3VlpamrZu3aqYmBhVqVJFZcqU0aZNm1S3bl1duHBBu3btUr9+/bL0s3LlymwHM5MmTdLTTz/t0nb27FlJUkJCgtauXasZM2aoVKlSatWq1VXvT506dSRd+azdr7/+WrVr19Ynn3yS7fK6devqlltu0YcffqiuXbtmO0jct2+fdu3apVq1auUpV2RkpJYuXSpJGjhwoAIDA/XWW2/piSeecBbE8yIv2S41efJknTp1St99953ztX700UdVt25djRgxQnfffbfLvFwXL17Uzp07nV9zK1GihIYOHardu3c7jy0AALg+bd++Xb///rumT58u6d9xYoUKFbRw4cICF22feuop53gyKChIkhQdHa327dsrPDz8is995plnlJqaqk2bNqly5cqSpD59+igqKkpPPvmkNmzYUKBMmerUqaM1a9boyJEj+RqPZTp58qRmzZqlxx57zKV90aJFLictPP7443r88cf11ltvaeLEibLb7br99ttVvnx5nTt3Lk9TjI0aNUohISHavHmzQkJCJEldu3bVzTffrLFjx2r+/Pku6998882aM2eO83FsbKzmzJlz1UVbxtquGGsD1sb0CACKtJo1ayo0NNQ5V+0vv/yihIQENWvWTJLUrFkzff/995L+nes2PT09y3y2ktSkSROtWrUqy61Xr15Z1o2KilKpUqUUERGhfv36qWrVqvrmm2/cMgdY5hkKFy5cyHGd4OBg/fXXX9q2bVuBtxMdHZ3nQaT07+DxUoMHD5YkLV++vMAZ8mL58uVq3Lixy2sWEBCgAQMG6MiRI1munPzwww+7zEuW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FatcWbWeGe3S9tvESUr4449cnxt2d2eVv7tLgTPmxZgxYzRlyhSVKlVKjz/+uPr166fvv//eufzgwYP67LPP9PnnnzunELj33nvl5+enb775RkFBQZo9e7batm2r/fv3KyQkRL1799bNN9+smTNnytPTUzt37nQWMCUpMTFRr776qt5//315eHjowQcf1BNPPKGFCxdKkl5//XVNmTJFs2fP1s0336z33ntPXbp00Z49e1StWrUs+3Ds2DF1795dAwcO1IABA/TTTz9p5MiRue77d999pwceeCDbZfXr11dycrLq1KmjcePGqXnz5rn216VLF128eFHVq1fXk08+qS5d/n3tSpUqpXLlymnlypVq166dvvvuO8XExCg1NVX/+c9/9N577zmP7eUaNmyotLQ0bd26Va1bt841w+5nxirl/Hn5BAer0pO5HwMzHDhwQGFhYfL19VXTpk01adIkVapUKdt1k5OTlZyc7HzscDiuVUwAAABYFEXbQnIxJU1paRlu6cvLy0O+PrxUAIBrLz0xSSmxZ3Ndz57NWYRpDkeenpueWPhnV77wwguKjo6W9O/X9Dt16qSLFy86zz5NSUnRggULVKpUKUn/Tinw448/6vTp07Lb7ZKkV199VV988YU+/fRTDRgwQH/++adGjRrlnKv08kJramqqZs2apSpVqkiSBg0apAkTJjiXv/rqq3rqqad0//33S5JeeuklrVu3TtOmTdOMGTOy7MPMmTNVpUoVTZkyRZIUFRWlXbt26aWXXrrivh89elRhYWEubeXKldOsWbPUsGFDJScn691331Xr1q21detW3XLLLdn2ExAQoClTpqh58+by8PDQZ599pq5du+qLL75Qly5dZLPZ9PHHH2v48OEaOnSo7rzzTvXr10+TJ09WmzZt5Ovrq+bNm+vMmTMaPHiwc9oESfL391dQUFCW+W5zknT8uFJizyo9MTFP619rTZo00bx58xQVFaUTJ05o/PjxatmypXbv3q3ixYtnWX/SpEkaP368CUkBoOCS01KUmpHmtv68Pbxk93LP9ETuzObOXACQH1QCC0laWobmL/9NZ85f3S+iJYP9FHNnLYn/IwAAJvD095NPaEiu63ldMi/qpW15ea6nv1+BsuVH3bp1nffLlSsnSTp9+rTzzMfw8HBnwVb6d+qD+Ph453ytmZKSknTo0CFJ0ogR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/2nVqlX2vs+dOyc/Pz8StgAyYU5bAMhnbdq00cqVK7Vy5Uq1bt3aXn/zzTdr4cKF+u2335yazzZD37595eHhoWnTpmXbpkqVKgoMDNTu3buzbfPSSy+pU6dOuv7665Wenu6w4nBqaqrS09Pt27t27ZKnp6fq1KnjdPwAAAD4x/Lly7Vz50716dNH0j8fkv97vtl/L0p2JevWrdPdd9+t3r17q169egoLC8u0JoGXl5fDc15WatWqpXXr1mXqu3bt2jmKIzsNGzbM8vk0MjJSDzzwgBYsWKDHHntMH3zwgSTp+uuv1++//65KlSqpatWqDsXPz0/VqlWTr6+vli1blu11bN++XQkJCQ7X4ebmpho1auQo5po1ayotLU2bN2+21+3du1cXLlxwaOfr66vu3bvr7bff1sqVK/Xrr7/aR+tKl5+nGzZsmKNzAiheSNoCQD5r06aN1q5dq23bttlHrEpSq1at9P777yslJSXLpO3FixcVExPjUOLi4rI9j2EYGjlypF599dVspytwc3NT+/bttXbt2iz37969W//73/80YcIESZcfRt3c3PTRRx/pxx9/1B9//KEmTZrY269Zs0Y33XQTIwMAAACckJycrJiYGB07dkxbtmzRK6+8op49e6pbt2666667JF1O/t144432BcZWrVqlZ599Nkf9V6tWTQsWLNC2bdu0fft23X777ZlGjFaqVEmrV6/WsWPHdObMmSz7GTNmjGbNmqXp06dr3759evPNN7VgwQI9/vjjTl1/x44d9euvvzokjUePHq3Fixfr4MGD2rJli1asWKFatWpJurxI2blz5zRw4EBt3LhR+/fv1+LFizVkyBClp6fLx8dHTz75pJ544gl98skn2r9/v9avX6+PPvpIkjRo0CD5+Pho8ODB2rVrl1asWKGHH35Yd955p31qhKupUaOGOnXqpGHDhmnDhg3avHmz7rvvPofn4lmzZumjjz7Srl27dODAAX322Wfy9fVVxYoV7W3WrFmjDh06OPX6Abg2kbQFgHzWpk0bXbp0SVWrVnV4CGzVqpUuXryoGjVqKDw8PNNxzz//vMLDwx3KE088ccVzDR48WKmpqZo6dWq2be677z7Nmzcv04O6aZoaOnSo3nzzTftX6nx9fTVr1ixNmDBB9957r6ZOneowr+68efN0//335+h1AAAAQNYWLVqk8PBwVapUSZ06ddKKFSv09ttv69tvv3WYU/Xjjz9WWlqaGjVqpNGjR+ull17KUf9vvvmmSpYsqebNm6t79+7q2LGjrr/+eoc2EyZM0KFDh1SlSpVsp77q1auXpkyZotdff1116tTR+++/r5kzZzp8mywvOnfuLA8PDy1dutRel56eruHDh6tWrVrq1KmTqlevbv9GWUREhNatW6f09HR16NBB9erV0+jRoxUcHGyfRuK5557TY489pueff161atVS//797fPqlihRQosXL9a5c+fUpEkT9e3bV+3atbviM3RWZs6cqYiICLVq1Uq33nqrhg4dal/7QZKCg4P1wQcfqEWLFqpfv76WLl2q77//XqVLl5YkHTt2TL/88ouGDBni1OsH4NpkmP+eEAcAcM0zTVNNmzbVI488ooEDB+a5n4ULF+qxxx7Tjh07HBZTAAAAAHLr3Xff1XfffafFixe7OpQC8+STT+r8+fOaMWOGq0MBUAjxLhsAihnDMDRjxgyHubTyIiEhQTNnziRhCwAAAKcNGzZMFy5c0MWLFxUQEODqcApE2bJl9eijj7o6DACFFCNtAQAAAAAAAKAQYU5bAAAAAAAAAChESNoCAAAAAAAAQCFC0hYAAAAAAAAAChGStgAAAAAAAABQiJC0BQAAAAAAAIBChKQtAAAAAAAAABQiJG0BAAAAAAAAoBAhaQsAAAAAAAAAhQhJWwAAAAAAAAAoREjaAgAAAAAAAEAhQtIWAAAAAAAAAAoRkrYAAAAAAAAAUIiQtAUAAAAAAACAQoSkLQAAAAAAAAAUIiRtAaAQqVSpku6++25XhwEAAIBi6IUXXpBhGHk69u6771alSpWu2u7QoUMyDEOzZs26YrtZs2bJMAxt2rQpT/FYLeO1OXPmjKtDkZQ/8bRu3VqtW7e+aruVK1fKMAytXLnSsnMDyIykLVDEzZ8/X4Zh6Ouvv860r0GDBjIMQytWrMi0r0KFCmrevLl9u1KlSjIMI8vSqVMne7uMh4OM4unpqUqVKmnkyJG6cOFCvlxjbrVu3doen5ubmwIDA1WjRg3deeedWrJkiavD0y+//KIXXnih0LxeAAAA14qMRF9G8fHxUUREhDp27Ki3335bFy9ezHPfhe0Zbtq0aVdNfErSvHnzZBiG3n///Sz3P/jgg/L09NT27dstjrBwy0g85qQAgCt4uDoAAM5p2bKlJGnt2rXq3bu3vT4uLk67du2Sh4eH1q1bpzZt2tj3RUdHKzo6WgMGDHDo67rrrtNjjz2W6RwRERGZ6qZPny5/f38lJCRo2bJleuedd7RlyxatXbvWqktzSvny5TVx4kRJUkJCgv766y8tWLBAn332mfr166fPPvtMnp6eLontl19+0fjx43X33XcrODjYYd/evXvl5sbnaQAAAM6YMGGCoqKilJqaqpiYGK1cuVKjR4/Wm2++qe+++07169fPdZ9XeoZzhWnTpikkJOSq39IaMGCAZs+eraeeekq9evVSaGiofd9vv/2mGTNm6LHHHlODBg1Up04dPfXUU/kceeFQq1Ytffrppw51Y8eOlb+/v5555hkXRQUA/yBpCxRxERERioqKypQs/fXXX2Wapm677bZM+zK2MxK+GcqVK6c77rgjR+ft27evQkJCJEnDhg3TgAED9L///U+//fabbrjhhrxejmWCgoIyXcurr76qkSNHatq0aapUqZJee+01S86VkJAgPz8/S/ry9va2pB8AAIDirHPnzmrcuLF9e+zYsVq+fLm6deumHj16aM+ePfL19XVhhAVr+vTpqlOnjh555BHNnTtXkpSenq5hw4apQoUKeuGFFyRJHh4e8vAoHmmC0NDQLN8vhISE5Pg9UU7ZbDalpKTIx8fH0n4BXNsYzgVcA1q2bKmtW7fq0qVL9rp169apTp066ty5s9avXy+bzeawzzAMtWjRwrIYbrrpJknS/v37r9huxIgR8vf3V2JiYqZ9AwcOVFhYmNLT0yVJmzZtUseOHRUSEiJfX19FRUXpnnvuyXOM7u7uevvtt1W7dm1NnTpVsbGxkq48r5ZhGPaHWOmf6SF2796t22+/XSVLlrQnv3fs2KG7775blStXlo+Pj8LCwnTPPffo7NmzDsePGTNGkhQVFWX/ytWhQ4ckZT2n7YEDB3TbbbepVKlSKlGihG688Ub9+OOPDm0yvt41f/58vfzyyypfvrx8fHzUrl07/fXXX3l+zQAAAK4Vbdu21XPPPafDhw/rs88+s9db8Qw3c+ZMtW3bVmXLlpW3t7dq166t6dOnZ4ohJ8+3NptNkydPVp06deTj46PQ0FANGzZM58+ft7epVKmSfv/9d61atcoey5XmIq1UqZJeeOEFff755/bpwt5++21t27ZN06dPV4kSJezXmdV0AJ999pkaNWokX19flSpVSgMGDFB0dPRVXnHpwoULuvvuuxUUFKTg4GANHjw419NLJCYmatiwYSpdurQCAwN11113ObwWgwcPVkhIiFJTUzMd26FDB9WoUSNX57uajGsKDg5WUFCQhgwZkum9jWEYGjFihObMmaM6derI29tbixYtkiQdO3ZM99xzj0JDQ+Xt7a06dero448/znSed955R3Xq1FGJEiVUsmRJNW7c2J5wz208aWlpevHFF1WlShV5e3urUqVKevrpp5WcnHzV6z169Kh69eolPz8/lS1bVo888kiOjgPgvOLxERpwjWvZsqU+/fRTbdiwwf6wtm7dOjVv3lzNmzdXbGysdu3aZf8a2Lp161SzZk2VLl3aoZ/U1NQsJ7L38/O76kiEjAfWkiVLXrFd//799e677+rHH3/UbbfdZq9PTEzU999/r7vvvlvu7u46deqUOnTooDJlyuipp55ScHCwDh06pAULFlzt5bgid3d3DRw4UM8995zWrl2rrl275qmf2267TdWqVdMrr7wi0zQlSUuWLNGBAwc0ZMgQhYWF6ffff9eMGTP0+++/a/369TIMQ7feeqv+/PNPff7553rrrbfso5XLlCmT5XlOnjyp5s2bKzExUSNHjlTp0qU1e/Zs9ejRQ19++aXDlBjS5dEBbm5uevzxxxUbG6tJkyZp0KBB2rBhQ56uEwAA4Fpy55136umnn9bPP/+s+++/X5I1z3AZI1l79OghDw8Pff/993rooYdks9k0fPhwScrx8+2wYcM0a9YsDRkyRCNHjtTBgwc1depUbd26VevWrZOnp6cmT56shx9+2OGr/P+e9iArjzzyiObMmaMHH3xQixYt0vPPP68BAwY4rF+RlZdfflnPPfec+vXrp/vuu0+nT5/WO++8o5tvvllbt27NdqoI0zTVs2dPrV27Vg888IBq1aqlr7/+WoMHD77yTfqPESNGKDg4WC+88IL27t2r6dOn6/Dhw/ZBC3feeac++eQTLV68WN26dbMfFxMTo+XLl2vcuHG5Ot/V9OvXT1FRUZo4caK2bNmiDz/8UGXLls30Lb7ly5dr/vz5GjFihEJCQlSpUiWdPHlSN954oz2pW6ZMGS1cuFD33nuv4uLiNHr0aEnSBx98oJEjR6pv374aNWqUkpKStGPHDm3YsEG33357ruO57777NHv2bPXt21eP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v9q1a6eaNWvqzTffVGRkpLy8vPTTTz/prbfesveRk+dbm82msmXLas6cOVmeK7t1EPKLzWaTYRhauHBhls+ZzjyTW6l27dpq1KiRPvvsM91111367LPP5OXlpX79+ll+rpw+b//3/ULGz8Edd9yR7by+GWuQ1KpVS3v37tUPP/ygRYsW6auvvtK0adP0/PPPa/z48XmKJ7v3PAAKL5K2wDUiY+Ts2rVrtW7dOvsk9pLUqFEjeXt7a+XKldqwYYO6dOli6bn9/f01btw4DRkyRPPnz9eAAQOueky/fv00ZcoUxcXF6X//+58qVapk/xrav91444268cYb9fLLL2vu3LkaNGiQ5s2bp/vuuy9Psaanp2vu3LkqUaKE/TXL+DT6vyvZXulT5/86f/68li1bpvHjx+v555+31+/bty9T29w8MFWsWFF79+7NVP/HH3/Y9wMAACBnPv30U0lSx44dJVnzDPf9998rOTlZ3333ncOox+ymDrjS822VKlW0dOlStWjR4qrfYiuIJFyVKlVkmqaioqJUvXr1XB1bsWJFLVu2TPHx8Q7J3ayeba9k3759atOmjX07Pj5eJ06cyPSe5q677tKjjz6qEydOaO7cueratetVF0kuSGXKlFFAQIDS09PVvn37q7b38/NT//791b9/f6WkpOjWW2/Vyy+/rLFjx8rHxyfH561YsaJsNpv27dtn/7aedHnB4wsXLlzx/UTFihW1a9cumabp8POW23sIIG+YHgG4RjRu3Fg+Pj6aM2eOjh075jDS1tvbW9dff73effddJSQkZDk1grMGDRqk8uXLZ1o1NTv9+/dXcnKyZs+erUWLFmX6FPz8+fOZPh2+7rrrJCnPUySkp6dr5MiR2rNnj0aOHKnAwEBJUmBgoEJCQrR69WqH9tOmTctx3xmfcP835smTJ2dq6+fnJylzkjgrXbp00W+//aZff/3VXpeQkKAZM2aoUqVKDvNkAQAAIHvLly/Xiy++qKioKA0aNEiSNc9wWfURGxurmTNnOrTLyfNtv379lJ6erhdffDHT+dPS0hzO7efnl6PnSWfceuutcnd31/jx4zPFbpqmzp49m+2xXbp0UVpamqZPn26vS09P1zvvvJOrGGbMmOEwB/D06dOVlpamzp07O7QbOHCgDMPQqFGjdODAAd1xxx25Ok9+c3d3V58+ffTVV1/Zv/n3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3Dw9lXTqrM5u2iXDzVDpJvUKVVLTWWmJly7/PMZeVFDd6gqoUuHqBxUwhxjrVFNA1YquDqlYcPW/9xnn3/TwE/L39naqr/jkZDV+Z5Kio6MdrsXb21veOej7woULqlixot58803de++9TsUC13D1zzMAAADyT06f9UjaAgCAIs/V/95nnH/zSGuSto3enuTUtTRp0kTt27fPdnQuCjdX/zwDAAAg/+T0WY/pEQAAAK4h8fHx2r9/v8LDnZ9/HAAAAIBrkLQFAACwiJULkeXU448/rlWrVunQoUP65Zdf1Lt3b7m7u2vgwIH5c5EAirypU6eqcePG8vb2Vq9evRz2xcXF6fbbb1dgYKBCQ0P14osv5mr/mDFjVKpUKTVo0EC7d++21x84cEDXXXedkpKS8u26iiLuReHC/Sg8uBeFC/fDNTIvkw4AAIC8MaRcrH+YbR+5cfToUQ0cOFBnz55VmTJl1LJlS61fv15lypRxMhAA16qIiAg9++yzWrp0qY4ePeqw7+GHH9a5c+d05MgRnTp1Su3bt1fFihV11113XXX/xo0b9c033+jQoUOaNWuWnnzySX3//feSpIceekhvvvmmfHx8Cvx6CzPuReHC/Sg8uBeFC/fDNRhpCwAAUITNmzdPx48fV3Jyso4ePap58+apSpUqrg4LQCF26623qlevXgoJCXGoT0xM1Lx58/TSSy8pODhY1atX18MPP6yPPvooR/sPHDigxo0bKzAwUB06dND+/fslSXPnzlVYWJjatm1bsBdaBHAvChfuR+HBvShcuB+uQdIWAADAIoZhTQEAV9i7d69SUlJ03XXX2euuu+467dixI0f769atq02bNunChQtaunSp6tWrp/Pnz+uVV17RG2+8UZCXUuRxLwoX7kfhwb0oXLgf+YukLQAAgEXcDGsKALhCfHy8/Pz85OHxzyx6wcHBunjxYo7216lTR6NGjVLr1q21ePFivf766xozZoyefPJJ7d69W23btlW7du20du3agr2wIoh7UbhwPwoP7kXhwv3IX8xpCwAAAACQv7+/EhMTlZaWZn+DHRsbq4CAgBztl6QRI0ZoxIgRkqTVq1fryJEjGjRokCpWrKhVq1bJNE21bdtWhw4dksFXC7LFvShcuB+FB/eicOF+5C9G2gIAAFiE6REAFGU1atSQp6entm/fbq/btm2b6tWrl6P9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xo0b9c033+jQoUOaNWuWnnzySX3//feSpIceekhvvvkmi74BAIAij5G2ACDJKBEsIziiQBO2Duf3DZRRshwJW6Coc3OzpgDFyG+//abdu3fr7rvvdqjfvHmzFi1apCeffNKh/sCBA2rcuLECAwPVoUMH7d+/X5I0d+5chYWFqW3btgUVOgAAQL7hXQEAAAAAl/noo4/UuXNnRURE2OvS0tJ0//33691335WXl+MHmnXr1tWmTZt04cIFLV26VPXq1dP58+f1yiuv6I033ijo8AEAAPIFSVsAAACrGBYVoJhISEjQvHnzdN999znU/9///Z8aNmyom2++OdMxderU0ahRo9S6dWstXrxYr7/+usaMGaMnn3xSu3fvVtu2bdWuXTutXbu2oC4DAADAcsxpCwAAYBXDuFyc7QMoJr744guVKFFCXbt2tdf99ddfeu+997R169ZsjxsxYoRGjBghSVq9erWOHDmiQYMGqWLFilq1apVM01Tbtm116NAhGfydAgAARRBJWwAAAAAu8eGHH2rw4MHy8PjnbcnatWt18uRJVa9eXZKUmpqqixcvKiQkRD/++KOaNm1qb5uSkqLRo0dr/vz5On36tNLS0lS5cmX7vtOnT6ts2bIFe1EAAAAWIGkLAABgFcOQDCdnn2JUIIqJvXv36pdfftHMmTMd6vv166f27dvbt3/99Vfdd9992rZtW6YE7MSJE3XbbbepatWqSk9PV3JysrZv3y7DMJSSkqLSpUsXyLUAAABYjaQtAAAAgAL30Ucf6aabblK1atUc6kuUKKESJUrYt8uUKSPDMFS+fHmHdnv37tX333+vX3/9VZLk7u6u6dOnq3PnzjIMQ++//77c3d3z/0IAAADyAUlbAAAAq1ixkBgDbVFMTJo0KUftWrdurQsXLmSqr1GjhjZt2uRQ179/f/Xv39+K8AAAAFyKpC0AAIBV3IzLxdk+AAAAABRrJG0BAABQJO3Zs0fz5s3TmjVrdPjwYSUmJqpMmTJq2LChOnbsqD59+sjb29vVYQIAAAC55uRKGQAAALAz3KwpuKItW7aoffv2atiwodauXaumTZtq9OjRevHFF3XHHXfINE0988wzioiI0Guvvabk5GRXhwwAAADkCiNtARQ5Zkq85OYuw8PXdec33GR4lrh6YxRJZlqSlJ4qefnLMPiqOnKBOW0LRJ8+fTRmzBh9+eWXCg4Ozrbdr7/+qilTpuiNN97Q008/XXABFlE2myk3pufIM14/AABgJZK2AIoMMzlWOvqLzOTzkgwpoLxU7kYZbp4Fc/7UROnoOpmXTl+u8AuTyjWX4eFTIOdH/jNt6dKJ32TGHpJkSl6BUrlmMnxLuzo0AP/y559/ytPz6r/7mzVrpmbNmik1NbUAoir63NwMLZizRWdOxrs6lCInJNRftw663tVhAACAawhJWwBFgmmaMqPXSClxGTUyL0bLOOkrhTcumCCO/fJPwlaSmRAj48RGKfKmgjk/8t+Z32XGHvxnOyVOZvRqqVpPGXxlHTlhGJeLs33ginKSsHWmfXF25mS8Yo7FujoMAACAYo93oACKhuQL/0rY/sOMO1wgpzdTL8lMPJW5/uLRy6MzcU3I8ucp7ZKUxb0HspSRtHW2INdOnDihvn37qkyZMipVqpS6d++uAwcOuDosAAAAIE9I2gIoGrIb5VhQox+NbCaqZPTlNSXb0bTcZ6DQu+eee1S3bl2tWrVKy5cvV2hoqG6//XZXhwUAAADkCe9CARQJhneQDN+QzPXBVQrm/B4+MgLKZa4PipLh5l4gMaAAZPXz5BUo+ZYp+FhQNBmG5OZkYaRtjowaNUoJCQn27b/++ktPPvmkateureuuu06jRo3S3r17XRghAAAAkHfMaQug6Ii8ScaJTTIvHpXcPGSUrCqVqVtw54+4UUbMZplxRyQZMoIrSaGNCu78yH+lasiwpco896eUniLDL0wKbyKDJBpyijltC0z58uXVqFEjTZo0ST169FD//v3VtGlTdenSRampqVqwYIEGDRrk6jABAACAPCFpC6DIMDx8Ly/6ZdokGQWeSDPcvaRyzaSIpi45P/KfYRhSmXpSSF1JJouPAYXYmDFj1LdvXz300EOaNWuW3nnnHTVt2lQrV65Uenq6Jk2apL59+7o6TAAAACBPSNoCKHJcnUhz9fmR/4zs5jAGroaRtgUqKipKCxcu1Jw5c9SqVSuNGjVKr7/+Oh+qAQAAoMgj8wAAAGARwzAsKci5s2fPatCgQdq4caO2bt2qZs2aaceOHa4OCwAAAHAKSVsAAAAUOcuWLVNoaKjKlCmj8uXL648//tDHH3+siRMnauDAgXriiSd06dIlV4cJAAAA5AlJWwAAAKtkTI/gbMFVDR8+XE888YQSExM1depUjR49WpLUpk0bbdmyRZ6enrruuutcGiMAAACQVyRtAQAAUOScOHFCXbt2lY+Pjzp16qTTp0/b93l7e+vll1/WggULXBghAAAAkHcsRAYAAGAVFiIrMD169FDfvn3Vo0cPrV27Vl26dMnUpk6dOi6IDAAAAHAeI20BAACswvQIBeajjz7SsGHDFBsbqzvuuEOTJ092dUgAAACAZRhpCwAAgCLHy8tLDz/8sKvDAAAAAPIFI20BAACswkjbArF+/foct01MTNTvv/+ej9EAAAAA1iNpCwAAYBU3w5qCK7rzzjvVsWNHffHFF0pISMiyze7du/X000+rSpUq2rx5cwFHCAAAADiH6REAAABQpOzevVvTp0/Xs88+q9tvv13Vq1dXRESEfHx8dP78ef3xxx+Kj49X79699fPPP6tevXquDhkAAADIFZK2AAAAVrFiegOmR7gqT09PjRw5UiNHjtSmTZu0du1aHT58WJcuXVKDBg30yCOPqE2bNipVqpSrQwUAAADyhKQtAACAVUjaFrjGjRurcePGrg4DAAAAsBRz2gIAAAAAAABAIcJIWwAAAKsw0hYAAACABUjaAgAAWIWkLQAAAAALMD0CAAAAAAAAABQijLQFAACwipskNydHyvKROgAAAFDskbQFAACwCtMjFLi33347y3rDMOTj46OqVavq5ptvlru7ewFHBgAAAOQdSVsAAAAUWW+99ZZOnz6txMRElSxZUpJ0/vx5lShRQv7+/jp16pQqV66sFStWKDIy0sXRAgAAADnDF/AAAACskjHS1tmCHHvllVfUpEkT7du3T2fPntXZs2f1559/qmnTppoyZYqOHDmisLAwPfLII64OFQAAAMgxRtoCAABYxoqkK0nb3Hj22Wf11VdfqUqVKva6qlWr6vXXX1efPn104MABTZo0SX369HFhlAAAAEDuMNIWAAAARdaJEyeUlpaWqT4tLU0xMTGSpIiICF28eLGgQwMAAADyjKQtAACAZQyLCnKqTZs2GjZsmLZu3Wqv27p1qx588EG1bdtWkrRz505FRUW5KkQAAAAg10jaAgAAoMj66KOPVKpUKTVq1Eje3t7y9vZW48aNVapUKX300UeSJH9/f73xxhsujhQAAADIOea0BQAAsIrhdrk42wdyLCwsTEuWLNEff/yhP//8U5JUo0YN1ahRw96mTZs2rgoPAAAAyBOStgAAAFYxLFiIzOmFzIqnmjVrqmbNmq4OAwAAALAESVsAAAAUWenp6Zo1a5aWLVumU6dOyWazOexfvny5iyIDAAAA8o7v3wEAAFglY6StsyUXpk+frvr16yswMFCBgYFq1qyZFi5cmE8XWPiMGjVKo0aNUnp6uurWrasGDRo4FAAAAKAoYqQtAACAZYy/i7N95Fz58uX16quvqlq1ajJNU7Nnz1bPnj21detW1alTx8lYCr958+Zp/vz56tKli6tDAQAAACxTqEfaFveRIwAAAFfTvXt3denSRdWqVVP16tX18ssvy9/fX+vXr3d1aAXCy8tLVatWdXUYAAAAgKXybaTtkSNHdPjwYSUmJqpMmTKqU6eOvL29c9VHcR85AgAAihgLFyKLi4tzqPb29r7qs1R6erq++OILJSQkqFmzZs7FUUQ89thjmjJliqZOnSqDRdwAAABwjbA0aXvo0CFNnz5d8+bN09GjR2Wapn2fl5eXbrrpJg0dOlR9+vSRm9vVB/l2797dYfvll1/W9OnTtX79epK2AACg8DHcLhdn+5AUGRnpUD1u3Di98MILWR6yc+dONWvWTElJSfL399fXX3+t2rVrOxdHEbF27VqtWLFCCxcuVJ06deTp6emwf8GCBS6KDAAAAMg7y5K2I0eO1OzZs9WxY0e99NJLuuGGGxQRESFfX1+dO3dOu3bt0po1a/T8889r/Pjxmjlzppo0aZLj/ovjyBEAAFB8RUdHKzAw0L59pVG2NWrU0LZt2xQbG6svv/xSgwcP1qpVq4pF4jY4OFi9e/d2dRgAAACApSxL2vr5+enAgQMqXbp0pn1ly5ZV27Zt1bZtW40bN06LFi1SdHR0jpK2uR05kpycrOTkZPv2f79aCAAAkG8snB4hY07/nPj3vK6NGjXSxo0bNWXKFL3//vvOxVIEzJw509UhAAAAAJazLGk7ceLEHLft1KlTjtvmduTIxIkTNX78+Bz3DwAAYB3j7+JsH86x2WwOH2IDAAAAKFrybSGyDGfOnNGGDRuUnp6uJk2aKDw8PFfH53bkyNixY/Xoo4/at+Pi4jLNCQcAAHCtGDt2rDp37qwKFSro4sWLmjt3rlauXKnFixe7OrR8c/3112vZsmUqWbKkGjZseMUFyLZs2VKAkQEAAADWyNek7VdffaV7771X1atXV2pqqvbu3at3331XQ4YMyXOfVxs5kpOVlQEAAPKFhdMj5NSpU6d011136cSJEwoKClL9+vW1ePFi3XLLLbnq5+LFi5owYYJWrlyp9PR0tWjRQuPGjVNISEiu+ikIPXv2tD/v9erVy7XBAAAAAPnA0qRtfHy8/P397dvjx4/Xb7/9purVq0uSfvzxR91///05TtoWx5EjAACgCHNB0vajjz5y7nx/u//+++Xr66vx48crNTVVM2bM0KBBgwrlc9e4ceOy/P+CcuzYMT355JNauHChEhMTVbVqVc2cOVONGzeWJJmmqXHjxumDDz7QhQsX1KJFC02fPl3VqlUr8FgBAABQNLlZ2VmjRo307bff2rc9PDx06tQp+/bJkyfl5eWV4/4yRo7UqFFD7dq108aNG/M0cgQAAACO3nrrLZmmad/euHGjPvzwQ3Xp0kU9e/bUG2+8oQ0bNrgwwpyJjo7W0aNH7du//fabRo8erRkzZuTL+c6fP68WLVrI09NTCxcu1O7du/XGG2+oZMmS9jaTJk3S22+/rffee08bNmyQn5+fOnbsqKSkpHyJCQAAANceS0faLl68WMOHD9esWbP07rvvasqUKerfv7/S09OVlpYmNzc3zZo1K8f9WTVyBAAAoCAYhiHDcO4z8SvNz2ql/fv3q2nTpnr//ffVsGFD3XLLLeratat69eql1NRUffrpp+rYsWOBxOKM22+/XUOHDtWdd96pmJgYtW/fXnXr1tWcOXMUExOj559/3tLzvfbaa4qMjNTMmTPtdVFRUfb/N01TkydP1rPPPquePXtKkj755BOFhobqm2++0YABAyyNBwAAANcmS0faVqpUST/++KP69eunVq1aadu2bfrrr7+0ZMkSLV26VEeOHFGXLl2sPCUAAADyYOrUqXr77bd1zz336NFHH9XEiRPVtWtXLVmyRMuWLdNtt92Wqw/bXWXXrl264YYbJEnz589XvXr19Msvv2jOnDn5Ev93332nxo0b67bbblPZsmXVsGFDffDBB/b9Bw8etCePMwQFBalp06b69ddfs+wzOTlZcXFxDgUAAADFm6VJ2wwDBw7Uxo0btX37drVu3Vo2m03XXXedfHx88uN0AAAAhYRhUSkYN954ozZu3KjSpUurWbNmqlSpkr766it98803GjNmjHx9fQsslrxKTU21L0q2dOlS9ejRQ5JUs2ZNnThxwvLzHThwwD4/7eLFi/Xggw9q5MiRmj17tiQpJiZGkhQaGupwXGhoqH3ff02cOFFBQUH2EhkZaXncAAAAKFosT9r+9NNPeuONN7Rp0yZ9+OGHmjRpkgYNGqQxY8bo0qVLVp8OAACg8DDcrCkFyMPDQ88884y+//57TZ48WX379s02uVgY1alTR++9957WrFmjJUuWqFOnTpKk48ePq3Tp0pafz2az6frrr9crr7yihg0baujQobr//vv13nvv5bnPsWPHKjY21l6io6MtjBgAAABFkaXvCh577DENGTJEGzdu1LBhw/Tiiy+qVatW2rJli3x8fNSwYUMtXLjQylMCAAAgD7Zv364mTZooICBALVq0kM1m07Jly9S1a1c1b95c06dPd3WIOfLaa6/p/fffV+vWrTVw4EA1aNBA0uVpDDKmTbBSeHi4ateu7VBXq1YtHTlyRJIUFhYm6fICvP928uRJ+77/8vb2VmBgoEMBAABA8WZp0nbWrFn66aefNG/ePG3cuFGffvqpJMnLy0svvviiFixYoFdeecXKUwIAABQiRWd6hHvuuUc33XSTNm7cqNtuu00PPPCAJGnIkCHasGGD1q1bp2bNmhVILM5o3bq1zpw5ozNnzujjjz+21w8dOtSp0a/ZadGihfbu3etQ9+eff6pixYqSLi9KFhYWpmXLltn3x8XFacOGDUXi9QQAAEDh4GFlZ35+fjp48KAaNWqk6OjoTHPY1q5dW2vWrLHylAAAAIWHm3G5ONtHAfjzzz/1v//9T1WrVlW1atU0efJk+74yZcros88+088//1wgsTjj0qVLMk1TJUuWlCQdPnxYX3/9tWrVqqWOHTtafr5HHnlEzZs31yuvvKJ+/frpt99+04wZMzRjxgxJkmEYGj16tF566SVVq1ZNUVFReu655xQREaFevXpZHg8AAACuTZYmbSdOnKi77rpLI0eOVGJion1BBgAAABQurVu31tChQzVgwAAtX75cLVq0yNSmQ4cOLogsd3r27Klbb71VDzzwgC5cuKCmTZvK09NTZ86c0ZtvvqkHH3zQ0vM1adJEX3/9tcaOHasJEyYoKipKkydP1qBBg+xtnnjiCSUkJGjo0KG6cOGCWrZsqUWLFrEoLwAAAHLM0ukRBg0apOjoaH377bc6dOiQevbsaWX3AAAAhVzRmR7hk08+0fXXX69vv/1WlStXLjJz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IUFhYWFq06aN3nrrLbVu3VpVqlRxdWi5smbNGv3yyy/y8vJyqK9UqZKOHTvmoqgAAAAA51iatL1WFrQAAADIC/PvP872URD+7//+T23atFH16tUL5Hz5xWazKT09PVP90aNHFRAQ4IKIAAAAAOe5WdlZxoIWr776qjZs2KAzZ85o0qRJKlGihCZNmqTy5curbt26Vp4SAACg0DBN05JSEIYNG1bkE7aS1KFDB02ePNm+bRiG4uPjNW7cOHXp0sV1gQEAAABOsHwhsn8rqgtaAAAAoGh444031LFjR9WuXVtJSUm6/fbbtW/fPoWEhOjzzz93dXgAAABAnliatL1WFrQAAADIC9O0yTRtTveBnCtfvry2b9+uefPmaceOHYqPj9e9996rQYMGydfX19XhAQAAAHliadL2WlnQAgAAIC+K0py21xIPDw/dcccdrg4DAAAAsIylSdtrZUELAAAAFF7fffddjtv26NEjHyMBAAAA8oelSdthw4ZZ2R0AAEAR4/xIWzHS9qp69eqVo3aGYSg9PT1/gwEAAADyQb4uRAYAAABYzWZj3l8AAABc20jaAgAAWIQ5bQEAAABYwc3VAQAAAFwrTNO0pCB3li1bpm7duqlKlSqqUqWKunXrpqVLl7o6LAAAACDPSNoCAACgyJo2bZo6deqkgIAAjRo1SqNGjVJgYKC6dOmid99919XhAQAAAHnC9AgAAACWsf1dnO0DOfXKK6/orbfe0ogRI+x1I0eOVIsWLfTKK69o+PDhLowOAAAAyBtG2gIAAFjEJtOSgpy7cOGCOnXqlKm+Q4cOio2NdUFEAAAAgPNI2gIAAKDI6tGjh77++utM9d9++626devmgogAAAAA5xXq6REmTpyoBQsW6I8//pCvr6+aN2+u1157TTVq1HB1aAAAAJmZ5uXibB/Isdq1a+vll1/WypUr1axZM0nS+vXrtW7dOj322GN6++237W1HjhzpqjABAACAXCnUSdtVq1Zp+PDhatKkidLS0vT000+rQ4cO2r17t/z8/FwdHgAAgAPTNGU6mXR19vji5qOPPlLJkiW1e/du7d69214fHBysjz76yL5tGAZJWwAAABQZhTppu2jRIoftWbNmqWzZstq8ebNuvvlmF0UFAACAwuLgwYOuDgEAAACwXKFO2v5XxmISpUqVyrZNcnKykpOT7dtxcXH5HhcAAIAkSxYSYyEyAAAAAEUmaWuz2TR69Gi1aNFCdevWzbbdxIkTNX78+AKMDAAA4DJXTGlb3NcAME1TX375pVasWKFTp07JZrM57F+wYIGLIgMAAADyzs3VAeTU8OHDtWvXLs2bN++K7caOHavY2Fh7iY6OLqAIAQAACl7GGgDr16/XkiVLlJqaqg4dOighIcHVoRWI0aNH684779TBgwfl7++voKAghwIAAAAURUVipO2IESP0ww8/aPXq1SpfvvwV23p7e8vb27uAIgMAAPiHKcl0cnqD3B5d3NcA+PTTT7VgwQJ16dLF1aEAAAAAlinUSVvTNPXwww/r66+/1sqVKxUVFeXqkAAAALJl/v3H2T6ckZM1AK4lQUFBqly5sqvDAAAAACxVqKdHGD58uD777DPNnTtXAQEBiomJUUxMjC5duuTq0AAAAPJVXFycQ/n3QqvZyekaANeSF154QePHj+f5EAAAANeUQj3Sdvr06ZKk1q1bO9TPnDlTd999d8EHBAAAcAWmacp0ciWyjOMjIyMd6seNG6cXXnjhisdmrAGwdu1ap2IoSvr166fPP/9cZcuWVaVKleTp6emwf8uWLS6KDAAAAMi7Qp20dfZNDwAAQFEVHR2twMBA+/bV5uzPzRoA15LBgwdr8+bNuuOOOxQaGirDMArs3K+++qrGjh2rUaNGafLkyZKkpKQkPfbYY5o3b56Sk5PVsWNHTZs2TaGhoQUWFwAAAIq+Qp20BQAAKEps5uXibB+SFBgY6JC0zU5xXwPgxx9/1OLFi9WyZcsCPe/GjRv1/vvvq379+g71jzzyiH788Ud98cUXCgoK0ogRI3Trrbdq3bp1BRofAAAAirZCPactAABAUWJa9Cc3ivsaAJGRkTlKblspPj5egwYN0gcffKCSJUva62NjY/XRRx/pzTffVNu2bdWoUSPNnDlTv/zyi9avX1+gMQIAAKBoI2kLAABQhE2fPl2xsbFq3bq1wsPD7eV///ufq0MrEG+88YaeeOIJHTp0qMDOOXz4cHXt2lXt27d3qN+8ebNSU1Md6mvWrKkKFSro119/LbD4AAAAUPQxPQIAAIBFrFyILL/aX2vuuOMOJSYmqkqVKipRokSmhcjOnTtn6fnmzZunLVu2aOPGjZn2xcTEyMvLS8HBwQ71oaGhiomJybbP5ORkJScn27fj4uIsixcAAABFE0lbAAAAi+RleoOs+kDOZSwAVhCio6M1atQoLVmyRD4+Ppb1O3HiRI0fP96y/gAAAFD0kbQFAABAkTV48OACO9fmzZt16tQpXX/99fa69PR0rV69WlOnTtXixYuVkpKiCxcuOIy2PXnypMLCwrLtd+zYsXr00Uft23FxcYqMjMyXawAAAEDRQNIWAADAIubfxdk+kDdJSUlKSUlxqLNykbJ27dpp586dDnVDhgxRzZo19eSTTyoyMlKenp5atmyZ+vTpI0nau3evjhw5ombNmmXbr7e3t7y9vS2LEwAAAEUfSVsAAACLmKZNNtPmdB/IuYSEBD355JOaP3++zp49m2l/enq6ZecKCAhQ3bp1Her8/PxUunRpe/29996rRx99VKVKlVJgYKAefvhhNWvWTDfeeKNlcQAAAODa5+bqAAAAAIC8euKJJ7R8+XJNnz5d3t7e+vDDDzV+/HhFRETok08+KfB43nrrLXXr1k19+vTRzTffrLCwMC1YsKDA4wAAAEDRxkhbAAAAi5jm5eJsH8i577//Xp988olat26tIUOG6KabblLVqlVVsWJFzZkzR4MGDcrX869cudJh28fHR++++67efffdfD0vAAAArm2MtAUAALCIadEf5Ny5c+dUuXJlSZfnrz137pwkqWXLllq9erUrQwMAAADyjKQtAAAAiqzKlSvr4MGDkqSaNWtq/vz5ki6PwA0ODnZhZAAAAEDekbQFAACwSMb0CM4W5NyQIUO0fft2SdJTTz2ld999Vz4+PnrkkUc0ZswYF0cHAAAA5A1z2gIAAFjElE2mbE73gZx75JFH7P/fvn177dmzR1u2bFHVqlVVv359F0YGAAAA5B1JWwAAAFwzKlWqpEqVKrk6DAAAAMApTI8AAABgEZskm+lkcfVFFBG//vqrfvjhB4e6Tz75RFFRUSpbtqyGDh2q5ORkF0UHAAAAOIekLQAAgEVM07Sk4OomTJig33//3b69c+dO3XvvvWrfvr2eeuopff/995o4caILIwQAAADyjqQtAAAAipxt27apXbt29u158+apadOm+uCDD/Too4/q7bff1vz5810YIQAAAJB3zGkLAABgEfPvP872gas7f/68QkND7durVq1S586d7dtNmjRRdHS0K0IDAAAAnMZIWwAAABQ5oaGhOnjwoCQpJSVFW7Zs0Y033mjff/HiRXl6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uUUBAQEKCwvTgw8+aO9oSZLNZtNrr72mmJgY+fr6KioqSi+//LJ9/c6dO9WjRw9ZrVaFhIToscceU05Ojn39+a9ivf7664qIiFBISIiGDh3q0IHNyMhQQkKCrFarGjRoUOQTemOMJkyYoKioKPn6+ioyMlJPPvmkfb2np6duvfVWffTRR5d8fQAAAOB6TZs2VUREhL3vLZ3tf99xxx1q0KCBNmzY4FDevXt3h/0DAwMVHh7usPj7+ztsExISovDwcLVo0ULPP/+8srKytHHjxmLjCQgIcDiWp6dnkXOcZ7PZ9Mwzzyg4OFjh4eGaMGGCw7EsFotmzJih3//+9/L397f3mxcsWKC2bdvKz89PDRs21MSJE+2DQi7X15WkU6dO6eGHH1ZgYKCioqL0zjvvOKy/XJ/8YidPntRDDz2kgIAARURE6I033ihx2/OOHDmilStXOoycTU5OVrdu3dS+fXvdf//9ql69uvbu3StJeuaZZ/THP/5RUVFRRY5F/x1ASUjaAlVIjx491Lp1a82fP/+K93322Wc1efJkJScnq1WrVsrJydGtt96qFStWaNu2berTp48SEhJ04MABSdL8+fOLfDJfnM8++0wjRozQU089paSkJD3++OMaPHiwEhMTHbabOHGi7r33Xu3YsUO33nqrBgwYoGPHjpUY79q1a9W+fXuHsqFDhyovL09r1qzRzp079eqrryogIEDS2WR1jx491KZNG3377bdasmSJ0tPTde+999r3f+655zR58mSNGzdOu3bt0ty5cxUWFibpbGevd+/eqlmzpjZv3qxPPvlEy5cv17BhwxxiSExMVGpqqhITE/Xvf/9bc+bMsSfRpbOJ3YMHDyoxMVH//e9/9c9//lMZGRn29Z9++qmmTp2qt99+W3v27NHnn3+uli1bOpzj+uuvv+TX3gAAAOA+unfv7tD3TUxMVLdu3RQfH28vz83N1caNG4skba9Ebm6u3n//fUmSj49P2YKW9O9//1v+/v7auHGjXnvtNb344otatmyZwzYTJkxQv379tHPnTj388MNau3atHnroIY0YMUK7du3S22+/rTlz5tgTuqXp677xxhtq3769tm3bpj/96U/64x//qJSUFEml75NfaMyYMVq9erUWLFigr776SqtWrdLWrVsvWfd169apWrVqatasmb2sdevW+vbbb3X8+HFt2bJFubm5iomJ0bp167R169YiyecL0X8HUCwDoNIZOHCgueOOO4pd179/f9OsWTNjjDF79+41ksy2bdvs648fP24kmcTERGOMMYmJiUaS+fzzzy973ri4OPPWW2/Zf46OjjZTp0512Gb27NkmKCjI/nPnzp3NkCFDHLa55557zK233mr/WZL5y1/+Yv85JyfHSDKLFy8uMZbWrVubF1980aGsZcuWZsKECcVu/9e//tXcfPPNDmUHDx40kkxKSorJysoyvr6+ZtasWcXu/84775iaNWuanJwce9mXX35pPDw8TFpamjHmbLtER0ebM2fOONS1f//+xhhjUlJSjCSzadMm+/rk5GQjyf46vvHGG6ZJkyYmPz+/xLovWLDAeHh4mMLCwhK3AQAAgHuYNWuW8ff3NwUFBSYrK8t4eXmZjIwMM3fuXNO1a1djjDErVqwwksz+/fvt+0VHRxsfHx/j7+/vsKxZs8YY81tf32q1Gn9/f2OxWIwk065du0v2JS9UXH/eGGPi4+PNjTfe6FDWoUMHM3bsWPvPkszIkSMdtunZs6d55ZVXHMr+85//mIiICGPM5fu60dHR5oEHHrD/bLPZTGhoqJkxY4YxpvR98vPvlbKzs42Pj4+ZN2+efftff/3VWK1WM2LEiGJjMMaYqVOnmoYNGxYpHz9+vGnUqJFp0aKFmT9/vsnLyzMtWrQw3377rXnrrbdMkyZNTOfOnU1SUpLDfvTfARSHkbZAFWOMuaoHCFw8ajUnJ0dPP/20mjVrpho1aiggIEDJycn2kballZycrC5dujiUdenSRcnJyQ5lrVq1sv+/v7+/qlev7jAC9WK5ubny8/NzKHvyySf10ksvqUuXLho/frx27NhhX/fdd98pMTFRAQEB9iU2NlaSlJqaquTkZOXl5alnz54l1qN169YOX0fr0qWLbDab/ZN/SYqLi5Onp6f954iICHs9kpOT5eXlpXbt2tnXx8bGOkwncc899yg3N1cNGzbUkCFD9NlnnxWZY9hqtcpmsykvL6/E1wcAAADuoVu3bjp58qQ2b96stWvXqkmTJqpdu7bi4+Pt89quWrVKDRs2LPL1+jFjxmj79u0Oy8X99o8//ljbtm3Tp59+qpiYGM2ZM0fe3t5ljvvC/rnk2K897+JYvvvuO7344osOfe4hQ4bo8OHDOnXqVKn6uhee12KxKDw83KE/XZo++XmpqanKz89Xx44d7WXBwcFq2rTpJete3HsN6ezI4h9//FE7d+5Uv379NGnSJPXq1Uve3t566aWXtG7dOj366KN66KGHHPaj/w6gOF6uDgBAxUpOTlaDBg0kyT5pvjHGvr6kBwRcPDfW008/rWXLlun1119XTEyMrFar7r77buXn55dL3Bd3LC0WyyWfsFqrVi0dP37coezRRx9V79699eWXX+qrr77SpEmT9MYbb2j48OHKyclRQkKCXn311SLHioiI0E8//eSSelysXr16SklJ0fLly7Vs2TL96U9/0t/+9jetXr3afuxjx47J399fVqvVKTEDAACg/MTExKhu3bpKTEzU8ePHFR8fL0mKjIxUvXr19M033ygxMVE9evQosm+tWrUUExNzyePXq1dPjRs3VuPGjXXmzBn169dPSUlJ8vX1LVPcpenXXvweIicnRxMnTtSdd95Z5Hh+fn6l6uuWtT/tDMW917jYDz/8oA8++EDbtm3Te++9p65du6p27dq699579fDDDys7O1uBgYGS6L8DKB4jbYEqZOXKldq5c6fuuusuSVLt2rUlyWG+2QsfSnYpX3/9tQYNGqR+/fqpZcuWCg8P1759+xy28fHxUWFh4SWP06xZM3399ddFjt28efNSxVGSNm3aaNeuXUXK69WrpyeeeELz58/XU089pVmzZkmS2rZtq++//17169dXTEyMw+Lv76/GjRvLarVqxYoVJdbju+++08mTJx3q4eHhcdlP6s+LjY3VmTNntGXLFntZSkqKMjMzHbazWq1KSEjQtGnTtGrVKq1fv147d+60r09KSlKbNm1KdU4AAAC4Xvfu3bVq1SqtWrVK3bp1s5d37dpVixcv1qZNm8o0n+15d999t7y8vPTPf/6zzMe6Gm3btlVKSkqR/nZMTIx9QMnl+rqXcqV98kaNGsnb29vhwWzHjx/X7t27L3meNm3aKC0trcTErTFGjz/+uKZMmaKAgAAVFhbaB8ec/++F75PovwMoDklboJLKy8tTWlqaDh06pK1bt+qVV17RHXfcodtvv93+dRyr1aobbrjB/oCx1atX6y9/+Uupjt+4cWPNnz9f27dv13fffac//OEPRT7hrl+/vtasWaNDhw7p6NGjxR5nzJgxmjNnjmbMmKE9e/ZoypQpmj9/vp5++uky1b93795av369Q2do5MiRWrp0qfbu3autW7cqMTHR/vCAoUOH6tixY7r//vu1efNmpaamaunSpRo8eLAKCwvl5+ensWPH6plnntH777+v1NRUbdiwQe+++64kacCAAfLz89PAgQOVlJSkxMREDR8+XA8++KD9YWWX07RpU/Xp00ePP/64Nm7cqC1btujRRx91+MR9zpw5evfdd5WUlKSffvpJH3zwgaxWq6Kjo+3brF27VjfffHOZXj8AAABUnO7du2vdunXavn27faStJMXHx+vtt99Wfn5+sUnb7OxspaWlOSxZWVklnsdisejJJ5/U5MmTderUqXKpy6W88MILev/99zVx4kR9//33Sk5O1kcffWR/D1Kavu6lXGmfPCAgQI888ojGjBmjlStXKikpSYMGDbInkEvSpk0b1apVq8jgk/P+9a9/qXbt2kpISJB0doqGlStXasOGDZo6daqaN2/uMAUa/XcAxSFpC1RSS5YsUUREhOrXr68+ffooMTFR06ZN04IFCxzmVH3vvfd05swZtWvXTiNHjtRLL71UquNPmTJFNWvWVOfOnZWQkKDevXurbdu2Dtu8+OKL2rdvnxo1amQf1Xuxvn376u9//7tef/11xcXF6e2339bs2bMdRhhcjVtuuUVeXl5avny5vaywsFBDhw5Vs2bN1KdPHzVp0sQ+yiAyMlJff/21CgsLdfPNN6tly5YaOXKkatSoYe+0jRs3Tk899ZReeOEFNWvWTP3797fPn1WtWjUtXbpUx44dU4cOHXT33XerZ8+e+sc//nFFcc+ePVuRkZGKj4/XnXfeqccee0yhoaH29TVq1NCsWbPUpUsXtWrVSsuXL9cXX3yhkJAQSdKhQ4f0zTffaPDgwWV6/QAAAFBxunfvrtzcXMXExDgkF+Pj45Wdna2mTZsqIiKiyH4vvPCCIiIiHJZnnnnmkucaOHCgCgoKrrif6gy9e/fWokWL9NVXX6lDhw664YYbNHXqVHtS9nJ93cu5mj753/72N910001KSEhQr169dOONNzo8Y6I4np6eGjx4sD788MMi69LT0/Xyyy9r2rRp9rLrr79eTz31lG677TbNmzdPs2fPtq+j/w6gJBZz4WSWAFCJTJ8+XQsXLtTSpUtdHUqFGTt2rI4fP6533nnH1aEAAAAAlVZaWpri4uK0devWUo8ELg79dwAl4UFkACqtxx9/XJmZmQ6T/Fd2oaGhGj16tKvDAAAAACq18PBwvfvuuzpw4ECZkrb03wGUhJG2AAAAAAAAAOBGmNMWAAAAAAAAANwISVsAAAAAAAAAcCMkbQEAAAAAAADAjZC0BQAAAAAAAAA3QtIWAAAAAAAAANwISVsAAAAAAAAAcCMkbQEAAAAAAADAjZC0BQAAAAAAAAA3QtIWAAAAAAAAANzI/wNcIjYjPXA1+wAAAABJRU5ErkJggg==", + "image/png": "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SktLc1lvz549uvfee1W+fHnZ7XaVLVtWbdq00ddff53rNn788UcdPXo0y7cOihUrpkaNGunHH39UYmKis33btm1KSEjQgAEDVKZMGZf3qfR/089ER0fneT/zIqfPuoLYv3+/pk2bpg4dOigkJESdO3fOMi1Bbi5evOhyXAoiLS1NDocjx+VJSUmSpJCQEEmSh4eHgoODlZCQ4Fxn1KhRqlSpkgYPHnzFbbVq1UrFihXTJ598clWZAQCAK4q2AAAUgsTERJ05c8blduHChQL3l5qamqW/M2fOFOqFfc6dO6ezZ886f6nPVKVKFUnS3LlzsxR48mvnzp2666671KhRI02dOlXt27fXnDlzNGLECOc6jz76qCTpvffey/L8+fPnKz09Pd/TMcybN09nz55Vnz59NH36dA0fPlx79+5V27Zt9d1332VZPyEhQbfddpuCg4M1efJkde/eXfPnz1f//v01ePBgff755xo8eLDGjx+vY8eOqXPnznl+vVNSUrR8+fI8nWW7detWtWvXTvv379dTTz2l0aNH66efflKfPn2yXf+hhx7SoEGDVLVqVb388ssaP3684uLidPvttzvn8AwODlaXLl309ddf6+zZsy7Pz8jI0MKFC1W3bt1sv2ZuhqCgIAUFBcnPz0+33367tm7dmmWdbdu2qXz58qpYsaJLe8WKFRUWFqZt27blup17771Xb775pu68805Nnz5dY8eOVePGjbOcHfrqq6+qZMmSGjJkiGbMmKH77rtPS5YsUbNmzbL9+fz555917733qnXr1poyZYqqVaump59+Wq+//rratm2rc+fOady4cXr88ce1YsWKHF/bPn36aMuWLc73wV9//aU77rgj23liL/f111+refPm2r9/v0aOHKk33nhDTZs21XPPPadevXo514uNjdVtt92mjRs3qn///po5c6ZGjBihUqVKZXvcL5f5R5Dspq9o06aNUlNTXf7AsX79egUEBKhhw4aKjo52OdaZZ+HWrVvXOTfupbL7fDxz5kyePqNy+qzLi6SkJC1fvlyDBw9WlSpVFBUVpeHDh+vvv//WkCFDtG7dOkVGRua5vylTpsjf31/FihVTxYoV9dxzzyk5OTlfmbZu3Sp/f38FBQUpODhYMTExWYr/DRo0kLe3t5599lkdPXpU8+fP1y+//OI8A33Dhg2aP3++3nnnHXl4XPlXRk9PTzVq1CjbP3oBAICrYAAAALdZt26dISnbW8+ePV3WlWR06tQp1z5z6k+SUaxYMZd1w8PDjfDw8Bz7iomJMSQZhw8fdraNHTvWkGSsXr3a+Oeff4wTJ04YmzZtMlq3bm1IMkaNGuXSx9mzZ42KFSsakozSpUsb99xzjzF58mTju+++M9LT03M/SJfsl81mM7Zs2eLSfueddxpeXl7GhQsXnG1NmzY1ypUrZ6SlpbmsW61aNaNmzZp53mam+Pj4LG0nT540QkNDjY4dO7q0R0dHG5KMl19+2aW9W7duhs1mMxo0aGCkpKQ425cuXWpIMmbNmpWnLMuXLzckGdu2bct13aZNmxre3t7Gvn37nG3JyclGo0aNDEnG2LFjne2ff/65IcmYPXu2Sx+pqalGgwYNjIiICCMjI8MwDMP46quvDEnGjBkzXNZdvXq1IcmYMmVKnvalMD311FPG8OHDjQ8++MBYsmSJMW7cOCM4ONjw9vY2Vq1a5bJuQECA0bhx42z7adSokVGuXLkrbuv8+fOGJOM///lPrrmyey9lHreXXnrJpT2793xycrJRtmxZw2azGYMHD3ZZf/jw4YYk4/fff3e2Zf68Nm7c2EhOTna2Hzt2zChWrJhRo0YNlz7Cw8ON6Oho5+OkpCSjTJkyRsuWLY3U1FSXdadOnWpIMtatW2cYxv+9lz/66KNcj0N2+vTpY0gy4uLisizLPEajR492trVv397o0KGDYRiG8dZbbxne3t7O4/vDDz8YkoyhQ4e69JP585nT7dKfq/x+1uUkKSnJeOONN4w77rjD8PX1dX4Wd+7c2Zg5c6bx559/5vdQGUePHjVuu+0244033jCWLl1qvPvuu0b79u0NSUa7du2yfPbl5M477zSef/5549NPPzU+/PBD47HHHjM8PT2N8uXLG3///bfLujNnzjTsdrvzWPXt29fIyMgwLl68aFSvXt3ltcnNI488Ykgyzpw5k6/9BgAAOaNoCwCAG2UWbQcMGGCsWrXK5bZr1y6XdfNTtG3SpEmW/latWuUsrmS6mqLt5Te73W489dRTWQo7hmEYp0+fNp566imjWrVqLs+JiIgwvv3221z3KXO/mjVrlqX91VdfNSS5HK+5c+cakoxly5Y52zZs2GBIMl599dU8bS8nFy5cMM6cOWP8888/xp133mmEhIS4LI+OjjY8PT2NpKQkl/bMAtc777zj0n727FlDkjFy5Mg8bX/AgAFGhQoVcl3v1KlThiSjR48eWZYtWrQoS9G2e/fuRvHixY1Tp04Z//zzj8tt3LhxhiRn8Tc1NdUoU6aM0aRJE5d++/TpY3h5eRknT57M075ca/v37zf8/f2NqlWrurR7eHgYLVu2zPY5LVu2NIKCgq7Yb3JysmG3241bbrnF5WflStLT043z5887j3FQUJDRvXt3l3Vyes936dLFkGQcOHDApT2z8P7ll1862zJ/Xj/88MMs/QwYMMCQZPz222/OtsuLtsuWLTMkGe+9916W98Xvv//uUkhdv369s5iXXeE1Nx07djS8vLyyXZaYmGj4+PgYTZs2NQzj3/dgsWLFjBdffNEwDMPYs2ePIcn5efLiiy8akowvvvjCpZ/o6GjD19c328/HVatWGQ6HI8uxy89nXXYOHz7sfK6Pj4/xxBNPFOj45MWjjz5qSDI++OCDAvexcOFCQ5LRv3//LMvOnj1rbN682aXQPGbMGKNq1apGUlKSERsbazz00ENG+fLljfr16xsff/xxttt48skns7z3AADA1eFCZAAAFIJq1apluSr61ShZsqRb+7PZbFnaZsyYoerVqysxMVHr1q3TG2+8oXPnzmV7NfBSpUpp8uTJmjx5smJjY7V582Z9/PHH+uCDD9StWzf98ssvqlq1aq45KleunKUt86vPl361vGfPnho2bJjmzJmjzp07S5LmzJkjHx+fHL8+fiWHDh3SmDFj9O233+r8+fMuy7I7NuXKlZOvr69LW4kSJSQpy1efM9vzMnVFRkaGli5dqnvvvTfXdf/44w9J/14Z/nK1atXK0rZ3715duHBBZcqUybHPU6dOqXr16vLy8lLv3r01depU7d+/X9WrV1dCQoI+//xztW/f/op9SFJ8fHyO8+rmhY+PT4G+ml6tWjXdd999mjdvnjO3JPn7++f4lfKLFy/K398/1zyZF9qLjIxUrVq1dNttt6lr165Z5nJeu3atJkyYoK1bt+rixYsuy86dO5el7+ze8wV5L9WsWTNLW+b74I8//sh2ufTv+0LSFeeBPnXqlCQpOjpaffr00bx587Rw4UI1atRI7dq1U8+ePbN9z10uu5+lTH5+frr11lv1ww8/KCEhQb/++qsSEhKc89XWqlVLpUqV0rp169S+fXutX79eHh4e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fJxZ8M1Uvnx5Pfjgg3nabo8ePVSyZElJ0mOPPab7779fH330kX788Uc1btw41+d7eXll2dbEiRM1efJkjR49Wo8++qg++ugj5zIfH5885SqojIwMpaSkyNfXV76+voW6rdzY7XZTtw8AAIq2w4cP64cfftDnn3+uxx57TAsXLtTYsWOvybYLYxxVvXr1LOPGyZMnq3Pnzho5cqRq1KihO++80y3bSkxMlL+//1X3Y7PZTB1TMtbOGWNtoGjhTywAirQWLVro559/VlJSkrPt+++/V+3atdWxY0dt2bLF5WtQ33//vWw2m5o3b+62DC1btpQkHTp06Kr6efrpp9W+fXt98skn2r9/v7M9u3m2pk+frtq1a8vf318lSpRQw4YNtWjRIkn/TuMwatQoSVJkZKTz62FHjhyR9O9AetCgQVq4cKFq164tu92uFStWOJdlNxfbmTNndN999ykwMFChoaEaOnSoLl686Fx+pbnLLu0zt2zZzbP1xx9/6N5771VISIj8/f1166236uuvv3ZZZ/369bLZbPr444/1wgsvqEKFCvL19VXbtm118ODBHI85AAC4vixcuFAlSpRQp06d1KNHDy1cuDDLOpnjhvXr17u05zSe+eKLL1SnTh35+vqqTp062U7NJWU/jvr555/VsWNHBQYGKiAgQG3bttWWLVuuZhcVGhqqxYsXy8vLSy+88IKzfd68eS7jqkzZ7W/r1q1Vp04dbd++Xa1atZK/v7/+97//SZKWLl2qTp06KSwsTHa7XVWqVNHzzz+v9PR0l+d//fXXOnr0qHM8lznHb07Hce3atWrZsqWKFSum4OBg3X333dq7d6/LOpnTkR08eNB5pmhQUJAefvhhJSYmXtVxY6zNWBsoajjTFkCR1qJFC73//vvaunWrc7D1/fffq1mzZmrWrJni4uK0e/du1a1b17msRo0aCg0NdeknNTU12wsAFCtWTH5+flfMkDkIKlGixFXvz0MPPaSVK1dq1apVql69erbrvPPOOxoyZIh69OjhHND9+uuv2rp1qx544AF1795d+/fv14cffqjXXnvNeVZwqVKlnH2sXbtWH3/8sQYNGqSSJUtmuZDG5e677z5FRERo0qRJ2rJli9544w2dO3dOCxYsyNf+5SXbpU6dOqVmzZopMTFRQ4YMUWhoqObPn68uXbro008/dZkWQ/r3zBMPDw898cQTiouL08svv6zevXtr69at+coJAACKpoULF6p79+7y8fFRr169NHPmTG3btk2NGjUqUH8rV67UPffco1q1amnSpEmKjY3Vww8/rAoVKuT63D179qhly5YKDAzUk08+KW9vb82ePVutW7fWhg0brmrO3UqVKik6Olrr1q2Tw+Fw+bp/XsXGxqpjx466//779eCDD6pMmTKS/i3+BgQEaMSIEQoICNDatWv13HPPyeFw6JVXXpEkjRkzRnFxcfrrr7/02muvSZICAgJy3Nbq1avVsWNHVa5cWePGjVNSUpKmT5+u5s2ba8eOHVnGovfdd58iIyM1adIk7dixQ++++65Kly6tl156Kd/7eSnG2q4YawPWRtEWQJF26by2rVu3VlpamrZu3aqYmBhVqVJFZcqU0aZNm1S3bl1duHBBu3btUr9+/bL0s3LlymwHM5MmTdLTTz/t0nb27FlJUkJCgtauXasZM2aoVKlSatWq1VXvT506dSRd+azdr7/+WrVr19Ynn3yS7fK6devqlltu0YcffqiuXbtmO0jct2+fdu3apVq1auUpV2RkpJYuXSpJGjhwoAIDA/XWW2/piSeecBbE8yIv2S41efJknTp1St99953ztX700UdVt25djRgxQnfffbfLvFwXL17Uzp07nV9zK1GihIYOHardu3c7jy0AALg+bd++Xb///rumT58u6d9xYoUKFbRw4cICF22feuop53gyKChIkhQdHa327dsrPDz8is995plnlJqaqk2bNqly5cqSpD59+igqKkpPPvmkNmzYUKBMmerUqaM1a9boyJEj+RqPZTp58qRmzZqlxx57zKV90aJFLictPP7443r88cf11ltvaeLEibLb7br99ttVvnx5nTt3Lk9TjI0aNUohISHavHmzQkJCJEldu3bVzTffrLFjx2r+/Pku6998882aM2eO83FsbKzmzJlz1UVbxtquGGsD1sb0CACKtJo1ayo0NNQ5V+0vv/yihIQENWvWTJLUrFkzff/995L+nes2PT09y3y2ktSkSROtWrUqy61Xr15Z1o2KilKpUqUUERGhfv36qWrVqvrmm2/cMgdY5hkKFy5cyHGd4OBg/fXXX9q2bVuBtxMdHZ3nQaT07+DxUoMHD5YkLV++vMAZ8mL58uVq3Lixy2sWEBCgAQMG6MiRI1munPzwww+7zEuW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FatcWbWeGe3S9tvESUr4449cnxt2d2eVv7tLgTPmxZgxYzRlyhSVKlVKjz/+uPr166fvv//eufzgwYP67LPP9PnnnzunELj33nvl5+enb775RkFBQZo9e7batm2r/fv3KyQkRL1799bNN9+smTNnytPTUzt37nQWMCUpMTFRr776qt5//315eHjowQcf1BNPPKGFCxdKkl5//XVNmTJFs2fP1s0336z33ntPXbp00Z49e1StWrUs+3Ds2DF1795dAwcO1IABA/TTTz9p5MiRue77d999pwceeCDbZfXr11dycrLq1KmjcePGqXnz5rn216VLF128eFHVq1fXk08+qS5d/n3tSpUqpXLlymnlypVq166dvvvuO8XExCg1NVX/+c9/9N577zmP7eUaNmyotLQ0bd26Va1bt841w+5nxirl/Hn5BAer0pO5HwMzHDhwQGFhYfL19VXTpk01adIkVapUKdt1k5OTlZyc7HzscDiuVUwAAABYFEXbQnIxJU1paRlu6cvLy0O+PrxUAIBrLz0xSSmxZ3Ndz57NWYRpDkeenpueWPhnV77wwguKjo6W9O/X9Dt16qSLFy86zz5NSUnRggULVKpUKUn/Tinw448/6vTp07Lb7ZKkV199VV988YU+/fRTDRgwQH/++adGjRrlnKv08kJramqqZs2apSpVqkiSBg0apAkTJjiXv/rqq3rqqad0//33S5JeeuklrVu3TtOmTdOMGTOy7MPMmTNVpUoVTZkyRZIUFRWlXbt26aWXXrrivh89elRhYWEubeXKldOsWbPUsGFDJScn691331Xr1q21detW3XLLLdn2ExAQoClTpqh58+by8PDQZ599pq5du+qLL75Qly5dZLPZ9PHHH2v48OEaOnSo7rzzTvXr10+TJ09WmzZt5Ovrq+bNm+vMmTMaPHiwc9oESfL391dQUFCW+W5zknT8uFJizyo9MTFP619rTZo00bx58xQVFaUTJ05o/PjxatmypXbv3q3ixYtnWX/SpEkaP368CUkBoOCS01KUmpHmtv68Pbxk93LP9ETuzObOXACQH1QCC0laWobmL/9NZ85f3S+iJYP9FHNnLYn/IwAAJvD095NPaEiu63ldMi/qpW15ea6nv1+BsuVH3bp1nffLlSsnSTp9+rTzzMfw8HBnwVb6d+qD+Ph453ytmZKSknTo0CFJ0ogR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/2nVqlX2vs+dOyc/Pz8StgAyYU5bAMhnbdq00cqVK7Vy5Uq1bt3aXn/zzTdr4cKF+u2335yazzZD37595eHhoWnTpmXbpkqVKgoMDNTu3buzbfPSSy+pU6dOuv7665Wenu6w4nBqaqrS09Pt27t27ZKnp6fq1KnjdPwAAAD4x/Lly7Vz50716dNH0j8fkv97vtl/L0p2JevWrdPdd9+t3r17q169egoLC8u0JoGXl5fDc15WatWqpXXr1mXqu3bt2jmKIzsNGzbM8vk0MjJSDzzwgBYsWKDHHntMH3zwgSTp+uuv1++//65KlSqpatWqDsXPz0/VqlWTr6+vli1blu11bN++XQkJCQ7X4ebmpho1auQo5po1ayotLU2bN2+21+3du1cXLlxwaOfr66vu3bvr7bff1sqVK/Xrr7/aR+tKl5+nGzZsmKNzAiheSNoCQD5r06aN1q5dq23bttlHrEpSq1at9P777yslJSXLpO3FixcVExPjUOLi4rI9j2EYGjlypF599dVspytwc3NT+/bttXbt2iz37969W//73/80YcIESZcfRt3c3PTRRx/pxx9/1B9//KEmTZrY269Zs0Y33XQTIwMAAACckJycrJiYGB07dkxbtmzRK6+8op49e6pbt2666667JF1O/t144432BcZWrVqlZ599Nkf9V6tWTQsWLNC2bdu0fft23X777ZlGjFaqVEmrV6/WsWPHdObMmSz7GTNmjGbNmqXp06dr3759evPNN7VgwQI9/vjjTl1/x44d9euvvzokjUePHq3Fixfr4MGD2rJli1asWKFatWpJurxI2blz5zRw4EBt3LhR+/fv1+LFizVkyBClp6fLx8dHTz75pJ544gl98skn2r9/v9avX6+PPvpIkjRo0CD5+Pho8ODB2rVrl1asWKGHH35Yd955p31qhKupUaOGOnXqpGHDhmnDhg3avHmz7rvvPofn4lmzZumjjz7Srl27dODAAX322Wfy9fVVxYoV7W3WrFmjDh06OPX6Abg2kbQFgHzWpk0bXbp0SVWrVnV4CGzVqpUuXryoGjVqKDw8PNNxzz//vMLDwx3KE088ccVzDR48WKmpqZo6dWq2be677z7Nmzcv04O6aZoaOnSo3nzzTftX6nx9fTVr1ixNmDBB9957r6ZOneowr+68efN0//335+h1AAAAQNYWLVqk8PBwVapUSZ06ddKKFSv09ttv69tvv3WYU/Xjjz9WWlqaGjVqpNGjR+ull17KUf9vvvmmSpYsqebNm6t79+7q2LGjrr/+eoc2EyZM0KFDh1SlSpVsp77q1auXpkyZotdff1116tTR+++/r5kzZzp8mywvOnfuLA8PDy1dutRel56eruHDh6tWrVrq1KmTqlevbv9GWUREhNatW6f09HR16NBB9erV0+jRoxUcHGyfRuK5557TY489pueff161atVS//797fPqlihRQosXL9a5c+fUpEkT9e3bV+3atbviM3RWZs6cqYiICLVq1Uq33nqrhg4dal/7QZKCg4P1wQcfqEWLFqpfv76WLl2q77//XqVLl5YkHTt2TL/88ouGDBni1OsH4NpkmP+eEAcAcM0zTVNNmzbVI488ooEDB+a5n4ULF+qxxx7Tjh07HBZTAAAAAHLr3Xff1XfffafFixe7OpQC8+STT+r8+fOaMWOGq0MBUAjxLhsAihnDMDRjxgyHubTyIiEhQTNnziRhCwAAAKcNGzZMFy5c0MWLFxUQEODqcApE2bJl9eijj7o6DACFFCNtAQAAAAAAAKAQYU5bAAAAAAAAAChESNoCAAAAAAAAQCFC0hYAAAAAAAAAChGStgAAAAAAAABQiJC0BQAAAAAAAIBChKQtAAAAAAAAABQiJG0BAAAAAAAAoBAhaQsAAAAAAAAAhQhJWwAAAAAAAAAoREjaAgAAAAAAAEAhQtIWAAAAAAAAAAoRkrYAAAAAAAAAUIiQtAUAAAAAAACAQoSkLQAAAAAAAAAUIiRtAaAQqVSpku6++25XhwEAAIBi6IUXXpBhGHk69u6771alSpWu2u7QoUMyDEOzZs26YrtZs2bJMAxt2rQpT/FYLeO1OXPmjKtDkZQ/8bRu3VqtW7e+aruVK1fKMAytXLnSsnMDyIykLVDEzZ8/X4Zh6Ouvv860r0GDBjIMQytWrMi0r0KFCmrevLl9u1KlSjIMI8vSqVMne7uMh4OM4unpqUqVKmnkyJG6cOFCvlxjbrVu3doen5ubmwIDA1WjRg3deeedWrJkiavD0y+//KIXXnih0LxeAAAA14qMRF9G8fHxUUREhDp27Ki3335bFy9ezHPfhe0Zbtq0aVdNfErSvHnzZBiG3n///Sz3P/jgg/L09NT27dstjrBwy0g85qQAgCt4uDoAAM5p2bKlJGnt2rXq3bu3vT4uLk67du2Sh4eH1q1bpzZt2tj3RUdHKzo6WgMGDHDo67rrrtNjjz2W6RwRERGZ6qZPny5/f38lJCRo2bJleuedd7RlyxatXbvWqktzSvny5TVx4kRJUkJCgv766y8tWLBAn332mfr166fPPvtMnp6eLontl19+0fjx43X33XcrODjYYd/evXvl5sbnaQAAAM6YMGGCoqKilJqaqpiYGK1cuVKjR4/Wm2++qe+++07169fPdZ9XeoZzhWnTpikkJOSq39IaMGCAZs+eraeeekq9evVSaGiofd9vv/2mGTNm6LHHHlODBg1Up04dPfXUU/kceeFQq1Ytffrppw51Y8eOlb+/v5555hkXRQUA/yBpCxRxERERioqKypQs/fXXX2Wapm677bZM+zK2MxK+GcqVK6c77rgjR+ft27evQkJCJEnDhg3TgAED9L///U+//fabbrjhhrxejmWCgoIyXcurr76qkSNHatq0aapUqZJee+01S86VkJAgPz8/S/ry9va2pB8AAIDirHPnzmrcuLF9e+zYsVq+fLm6deumHj16aM+ePfL19XVhhAVr+vTpqlOnjh555BHNnTtXkpSenq5hw4apQoUKeuGFFyRJHh4e8vAoHmmC0NDQLN8vhISE5Pg9UU7ZbDalpKTIx8fH0n4BXNsYzgVcA1q2bKmtW7fq0qVL9rp169apTp066ty5s9avXy+bzeawzzAMtWjRwrIYbrrpJknS/v37r9huxIgR8vf3V2JiYqZ9AwcOVFhYmNLT0yVJmzZtUseOHRUSEiJfX19FRUXpnnvuyXOM7u7uevvtt1W7dm1NnTpVsbGxkq48r5ZhGPaHWOmf6SF2796t22+/XSVLlrQnv3fs2KG7775blStXlo+Pj8LCwnTPPffo7NmzDsePGTNGkhQVFWX/ytWhQ4ckZT2n7YEDB3TbbbepVKlSKlGihG688Ub9+OOPDm0yvt41f/58vfzyyypfvrx8fHzUrl07/fXXX3l+zQAAAK4Vbdu21XPPPafDhw/rs88+s9db8Qw3c+ZMtW3bVmXLlpW3t7dq166t6dOnZ4ohJ8+3NptNkydPVp06deTj46PQ0FANGzZM58+ft7epVKmSfv/9d61atcoey5XmIq1UqZJeeOEFff755/bpwt5++21t27ZN06dPV4kSJezXmdV0AJ999pkaNWokX19flSpVSgMGDFB0dPRVXnHpwoULuvvuuxUUFKTg4GANHjw419NLJCYmatiwYSpdurQCAwN11113ObwWgwcPVkhIiFJTUzMd26FDB9WoUSNX57uajGsKDg5WUFCQhgwZkum9jWEYGjFihObMmaM6derI29tbixYtkiQdO3ZM99xzj0JDQ+Xt7a06dero448/znSed955R3Xq1FGJEiVUsmRJNW7c2J5wz208aWlpevHFF1WlShV5e3urUqVKevrpp5WcnHzV6z169Kh69eolPz8/lS1bVo888kiOjgPgvOLxERpwjWvZsqU+/fRTbdiwwf6wtm7dOjVv3lzNmzdXbGysdu3aZf8a2Lp161SzZk2VLl3aoZ/U1NQsJ7L38/O76kiEjAfWkiVLXrFd//799e677+rHH3/UbbfdZq9PTEzU999/r7vvvlvu7u46deqUOnTooDJlyuipp55ScHCwDh06pAULFlzt5bgid3d3DRw4UM8995zWrl2rrl275qmf2267TdWqVdMrr7wi0zQlSUuWLNGBAwc0ZMgQhYWF6ffff9eMGTP0+++/a/369TIMQ7feeqv+/PNPff7553rrrbfso5XLlCmT5XlOnjyp5s2bKzExUSNHjlTp0qU1e/Zs9ejRQ19++aXDlBjS5dEBbm5uevzxxxUbG6tJkyZp0KBB2rBhQ56uEwAA4Fpy55136umnn9bPP/+s+++/X5I1z3AZI1l79OghDw8Pff/993rooYdks9k0fPhwScrx8+2wYcM0a9YsDRkyRCNHjtTBgwc1depUbd26VevWrZOnp6cmT56shx9+2OGr/P+e9iArjzzyiObMmaMHH3xQixYt0vPPP68BAwY4rF+RlZdfflnPPfec+vXrp/vuu0+nT5/WO++8o5tvvllbt27NdqoI0zTVs2dPrV27Vg888IBq1aqlr7/+WoMHD77yTfqPESNGKDg4WC+88IL27t2r6dOn6/Dhw/ZBC3feeac++eQTLV68WN26dbMfFxMTo+XLl2vcuHG5Ot/V9OvXT1FRUZo4caK2bNmiDz/8UGXLls30Lb7ly5dr/vz5GjFihEJCQlSpUiWdPHlSN954oz2pW6ZMGS1cuFD33nuv4uLiNHr0aEnSBx98oJEjR6pv374aNWqUkpKStGPHDm3YsEG33357ruO57777NHv2bPXt21eP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v9q1a6eaNWvqzTffVGRkpLy8vPTTTz/prbfesveRk+dbm82msmXLas6cOVmeK7t1EPKLzWaTYRhauHBhls+ZzjyTW6l27dpq1KiRPvvsM91111367LPP5OXlpX79+ll+rpw+b//3/ULGz8Edd9yR7by+GWuQ1KpVS3v37tUPP/ygRYsW6auvvtK0adP0/PPPa/z48XmKJ7v3PAAKL5K2wDUiY+Ts2rVrtW7dOvsk9pLUqFEjeXt7a+XKldqwYYO6dOli6bn9/f01btw4DRkyRPPnz9eAAQOueky/fv00ZcoUxcXF6X//+58qVapk/xrav91444268cYb9fLLL2vu3LkaNGiQ5s2bp/vuuy9Psaanp2vu3LkqUaKE/TXL+DT6vyvZXulT5/86f/68li1bpvHjx+v555+31+/bty9T29w8MFWsWFF79+7NVP/HH3/Y9wMAACBnPv30U0lSx44dJVnzDPf9998rOTlZ3333ncOox+ymDrjS822VKlW0dOlStWjR4qrfYiuIJFyVKlVkmqaioqJUvXr1XB1bsWJFLVu2TPHx8Q7J3ayeba9k3759atOmjX07Pj5eJ06cyPSe5q677tKjjz6qEydOaO7cueratetVF0kuSGXKlFFAQIDS09PVvn37q7b38/NT//791b9/f6WkpOjWW2/Vyy+/rLFjx8rHxyfH561YsaJsNpv27dtn/7aedHnB4wsXLlzx/UTFihW1a9cumabp8POW23sIIG+YHgG4RjRu3Fg+Pj6aM2eOjh075jDS1tvbW9dff73effddJSQkZDk1grMGDRqk8uXLZ1o1NTv9+/dXcnKyZs+erUWLFmX6FPz8+fOZPh2+7rrrJCnPUySkp6dr5MiR2rNnj0aOHKnAwEBJUmBgoEJCQrR69WqH9tOmTctx3xmfcP835smTJ2dq6+fnJylzkjgrXbp00W+//aZff/3VXpeQkKAZM2aoUqVKDvNkAQAAIHvLly/Xiy++qKioKA0aNEiSNc9wWfURGxurmTNnOrTLyfNtv379lJ6erhdffDHT+dPS0hzO7efnl6PnSWfceuutcnd31/jx4zPFbpqmzp49m+2xXbp0UVpamqZPn26vS09P1zvvvJOrGGbMmOEwB/D06dOVlpamzp07O7QbOHCgDMPQqFGjdODAAd1xxx25Ok9+c3d3V58+ffTVV1/Zv/n3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U0mnzurspl0y3AyVblKvUCU1nZWWeOnyz2PsRQXVra6AKhWuflABc4ixTjUFVK3o6pCKBVf/e59x/k0PPyF/b2+n+opPTlbjdyYpOjra4Vq8vb3lnYO+L1y4oIoVK+rNN9/Uvffe61QscA1X/zwDAAAg/+T0WY+kLQAAKPJc/e99xvk3j7Qmadvo7UlOXUuTJk3Uvn37bEfnonBz9c8zAAAA8k9On/WYHgEAAOAaEh8fr/379ys83Pn5xwEAAAC4BklbAAAAi1i5EFlOPf7441q1apUOHTqkX375Rb1795a7u7sGDhyYPxcJoMibOnWqGjduLG9vb/Xq1cthX1xcnG6//XYFBgYqNDRUL774Yq72jxkzRqVKlVKDBg20e/due/2BAwd03XXXKSkpKd+uqyjiXhQu3I/Cg3tRuHA/XCPzMukAAADIG0PKxfqH2faRG0ePHtXAgQN19uxZlSlTRi1bttT69etVpkwZJwMBcK2KiIjQs88+q6VLl+ro0aMO+x5++GGdO3dOR44c0alTp9S+fXtVrFhRd91111X3b9y4Ud98840OHTqkWbNm6cknn9T3338vSXrooYf05ptvysfHp8CvtzDjXhQu3I/Cg3tRuHA/XIORtgAAAEXYvHnzdPz4cSUnJ+vo0aOaN2+eqlSp4uqwABRit956q3r16qWQkBCH+sTERM2bN08vvfSSgoODVb16dT388MP66KOPcrT/wIEDaty4sQIDA9WhQwft379fkjR37lyFhYWpbdu2BXuhRQD3onDhfhQe3IvChfvhGiRtAQAALGIY1hQAcIW9e/cqJSVF1113nb3uuuuu044dO3K0v27dutq0aZMuXLigpUuXql69ejp//rxeeeUVvfHGGwV5KUUe96Jw4X4UHtyLwoX7kb9I2gIAAFjEzbCmAIArxMfHy8/PTx4e/8yiFxwcrIsXL+Zof506dTRq1Ci1bt1aixcv1uuvv64xY8boySef1O7du9W2bVu1a9dOa9euLdgLK4K4F4UL96Pw4F4ULtyP/MWctgAAAAAA+fv7KzExUWlpafY32LGxsQoICMjRfkkaMWKERowYIUlavXq1jhw5okGDBqlixYpatWqVTNNU27ZtdejQIRl8tSBb3IvChftReHAvChfuR/5ipC0AAIBFmB4BQFFWo0YNeXp6avv27fa6bdu2qV69ejna/28p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Ud98840OHTqkWbNm6cknn9T3338vSXrooYf05ptvsugbAAAo8hhpCwCSjBLBMoIjCjRh63B+30AZJcuRsAWKOjc3awpQjPz222/avXu37r77bof6zZs3a9GiRXryyScd6g8cOKDGjRsrMDBQHTp00P79+yVJc+fOVVhYmNq2bVtQoQMAAOQb3hUAAAAAcJmPPvpInTt3VkREhL0uLS1N999/v9599115eTl+oFm3bl1t2rRJFy5c0NKlS1WvXj2dP39er7zyit54442CDh8AACBfkLQFAACwimFRAYqJhIQEzZs3T/fdd59D/f/93/+pYcOGuvnmmzMdU6dOHY0aNUqtW7fW4sWL9frrr2vMmDF68skntXv3brVt21bt2rXT2rVrC+oyAAAALMectgAAAFYxjMvF2T6AYuKLL75QiRIl1LVrV3vdX3/9pffee09bt27N9rgRI0ZoxIgRkqTVq1fryJEjGjRokCpWrKhVq1bJNE21bdtWhw4dksHfKQAAUASRtAUAAADgEh9++KEGDx4sD49/3pasXbtWJ0+eVPXq1SVJqampunjxokJCQvTjjz+qadOm9rYpKSkaPXq05s+fr9OnTystLU2VK1e27zt9+rTKli1bsBcFAABgAZK2AAAAVjEMyXBy9ilGBaKY2Lt3r3755RfNnDnTob5fv35q3769ffvXX3/Vfffdp23btmVKwE6cOFG33XabqlatqvT0dCUnJ2v79u0yDEMpKSkqXbp0gVwLAACA1UjaAgAAAChwH330kW666SZVq1bNob5EiRIqUaKEfbtMmTIyDEPly5d3aLd37159//33+vXXXyVJ7u7umj59ujp37izDMPT+++/L3d09/y8EAAAgH5C0BQAAsIoVC4kx0BbFxKRJk3LUrnXr1rpw4UKm+ho1amjTpk0Odf3791f//v2tCA8AAMClSNoCAABYxc24XJztAwAAAECxRtIWAAAARdKePXs0b948rVmzRocPH1ZiYqLKlCmjhg0bqmPHjurTp4+8vb1dHSYAAACQa06ulAEAAAA7w82agivasmWL2rdvr4YNG2rt2rVq2rSpRo8erRdffFF33HGHTNPUM888o4iICL322mtKTk52dcgAAABArjDSFkCRY6bES27uMjx8XXd+w02GZ4mrN0aRZKYlSempkpe/DIOvqiMXmNO2QPTp00djxozR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aQsAAGAVw4KFyJxeyKx4qlmzpmrWrOnqMAAAAABLkLQFAABAkZWenq5Zs2Zp2bJlOnXqlGw2m8P+5cuXuygyAAAAIO/4/h0AAIBVMkbaOltyYfr06apfv74CAwMVGBioZs2aaeHChfl0gYXPqFGjNGrUKKWnp6tu3bpq0KCBQwEAAACKIkbaAgAAWMb4uzjbR86VL19er776qqpVqybTNDV79mz17NlTW7duVZ06dZyMpfCbN2+e5s+fry5durg6FAAAAMAyhXqkbXEfOQIAAHA13bt3V5cuXVStWjVVr15dL7/8svz9/bV+/XpXh1YgvLy8VLVqVVeHAQAAAFgq30baHjlyRIcPH1ZiYqLKlCmjOnXqyNvbO1d9FPeRIwAAoIixcCGyuLg4h2pvb++rPkulp6friy++UEJCgpo1a+ZcHEXEY489pilTpmjq1KkyWMQNAAAA1whLk7aHDh3S9OnTNW/ePB09elSmadr3eXl56aabbtLQoUPVp08fubldfZBv9+7dHbZffvllTZ8+XevXrydpCwAACh/D7XJxtg9JkZGRDtXjxo3TCy+8kOUhO3fuVLNmzZSUlCR/f399/fXXql27tnNxFBFr167VihUrtHDhQtWpU0eenp4O+xcsWOCiyAAAAIC8syxpO3LkSM2ePVsdO3bUSy+9pBtuuEERERHy9fXVuXPntGvXLq1Zs0bPP/+8xo8fr5kzZ6pJkyY57r84jhwBAADFV3R0tAIDA+3bVxplW6NGDW3btk2xsbH68ssvNXjwYK1atapYJG6Dg4PVu3dvV4cBAAAAWMqypK2fn58OHDig0qVLZ9pXtmxZtW3bVm3bttW4ceO0aNEiRUdH5yhpm9uRI8nJyUpOTrZv//erhQAAAPnGwukRMub0z4l/z+vaqFEjbdy4UVOmTNH777/vXCxFwMyZM10dAgAAAGA5y5K2EydOzHHbTp065bhtbkeOTJw4UePHj89x/wAAANYx/i7O9uEcm83m8CE2AAAAgKIl3xYiy3DmzBlt2LBB6enpatKkicLDw3N1fG5HjowdO1aPPvqofTsuLi7TnHAAAADXirFjx6pz586qUKGCLl68qLlz52rlypVavHixq0PLN9dff72WLVumkiVLqmHDhldcgGzLli0FGBkAAABgjXxN2n711Ve69957Vb16daWmpmrv3r169913NWTIkDz3ebWRIzlZWRkAACBfWDg9Qk6dOnVKd911l06cOKGgoCDVr19fixcv1i233JKrfi5evKgJEyZo5cqVSk9PV4sWLTRu3DiFhITkqp+C0LNnT/vzXq9evVwbDAAAAJAPLE3axsfHy9/f3749fvx4/fbbb6pevbok6ccff9T999+f46RtcRw5AgAAijAXJG0/+ugj5873t/vvv1++vr4aP368UlNTNWPGDA0aNKhQPneNGzcuy/8vKMeOHdOTTz6phQsXKjExUVWrVtXMmTPVuHFjSZJpmho3bpw++OADXbhwQS1atND06dNVrVq1Ao8VAAAARZOblZ01atRI3377rX3bw8NDp06dsm+fPHlSXl5eOe4vY+RIjRo11K5dO23cuDFPI0cAAADg6K233pJpmvbtjRs36sMPP1SXLl3Us2dPvfHGG9qwYYMLI8yZ6OhoHT161L7922+/afTo0ZoxY0a+nO/8+fNq0aKFPD09tXDhQu3evVtvvPGGSpYsaW8zadIkvf3223rvvfe0YcMG+fn5qWPHjkpKSsqXmAAAAHDtsXSk7eLFizV8+HDNmjVL7777rqZMmaL+/fsrPT1daWlpcnNz06xZs3Lcn1UjRwAAAAqCYRgyDOc+E7/S/KxW2r9/v5o2bar3339fDRs21C233KKuXbuqV69eSk1N1aeffqqOHTsWSCzOuP322zV06FDdeeediomJUfv27VW3bl3NmTNHMTExev755y0932uvvabIyEjNnDnTXhcVFWX/f9M0NXnyZD377LPq2bOnJOmTTz5RaGiovvnmGw0YMMDSeAAAAHBtsnSkbaVKlfTjjz+qX79+atWqlbZt26a//vpLS5Ys0dKlS3XkyBF16dLFylMCAAAgD6ZOnaq3335b99xzjx599FFNnDhRXbt21ZIlS7Rs2TLddtttufqw3VV27dqlG264QZI0f/581atXT7/88ovmzJmTL/F/9913aty4sW677TaVLVtWDRs21AcffGDff/DgQXvyOENQUJCaNm2qX3/9Ncs+k5OTFRcX51AAAABQvFmatM0wcOBAbdy4Udu3b1fr1q1ls9l03XXXycfHJz9OBwAAUEgYFpWCceONN2rjxo0qXbq0mjVrpkqVKumrr77SN998ozFjxsjX17fAYsmr1NRU+6JkS5cuVY8ePSRJNWvW1IkTJyw/34EDB+zz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D9f9999v72hJks1m0yuvvKLY2Fj5+voqOjpaL774on39zp071aNHD1mtVoWGhuqRRx5Rbm6uff3Zr2K99tprioyMVGhoqIYOHerQgc3MzFRiYqKsVqsaNmxY7BN6Y4wmTJig6Oho+fr6KioqSo8//rh9vaenp2666SZ9+OGHF7w+AAAAcL1mzZopMjLS3veWzvS/b7vtNjVs2FAbNmxwKO/evbvD/oGBgYqIiHBY/P39HbYJDQ1VRESEWrZsqWeffVbZ2dnauHFjifEEBAQ4HMvT07PYOc6y2Wx66qmnFBISooiICE2YMMHhWBaLRTNmzNCtt94qf39/e795wYIFateunfz8/NSoUSNNnDjRPijkYn1dSTp58qQefPBBBQYGKjo6Wm+//bbD+ov1yc934sQJPfDAAwoICFBkZKRef/31Urc96/Dhw1q5cqXDyNmUlBR169ZNHTp00L333qugoCDt3btXkvTUU0/pT3/6k6Kjo4sdi/47gNKQtAWqkR49eqhNmzaaP3/+Je/79NNPa/LkyUpJSVHr1q2Vm5urm266SStWrNC2bdvUp08fJSYmav/+/ZKk+fPnF/tkviSffvqpRowYoSeeeELJycl69NFHNXjwYCUlJTlsN3HiRN19993asWOHbrrpJg0YMEBHjx4tNd61a9eqQ4cODmVDhw5Vfn6+1qxZo507d+rll19WQECApDPJ6h49eqht27b65ptvtGTJEmVkZOjuu++27//MM89o8uTJGjdunHbt2qW5c+cqPDxc0pnOXu/evVWrVi1t3rxZH3/8sZYvX65hw4Y5xJCUlKS0tDQlJSXp3//+t+bMmWNPoktnErsHDhxQUlKS/vvf/+qf//ynMjMz7es/+eQTTZ06VW+99Zb27Nmjzz77TK1atXI4x9VXX33Br70BAADAfXTv3t2h75uUlKRu3bopISHBXp6Xl6eNGzcWS9peiry8PL333nuSJB8fn/IFLenf//63/P39tXHjRr3yyit6/vnntWzZModtJkyYoH79+mnnzp168MEHtXbtWj3wwAMaMWKEdu3apbfeektz5syxJ3TL0td9/fXX1aFDB23btk1//vOf9ac//UmpqamSyt4nP9eYMWO0evVqLViwQF9++aVWrVqlrVu3XrDu69atU40aNdS8eXN7WZs2bfTNN9/o2LFj2rJli/Ly8hQbG6t169Zp69atxZLP56L/DqBEBkCVM3DgQHPbbbeVuK5///6mefPmxhhj9u7daySZbdu22dcfO3bMSDJJSUnGGGOSkpKMJPPZZ59d9Lzx8fHmzTfftP8cExNjpk6d6rDN7NmzTXBwsP3nzp07myFDhjhsc9ddd5mbbrrJ/rMk89e//tX+c25urpFkFi9eXGosbdq0Mc8//7xDWatWrcyECRNK3P5vf/ubueGGGxzKDhw4YCSZ1NRUk52dbXx9fc2sWbNK3P/tt982tWrVMrm5ufayL774wnh4eJj09HRjzJl2iYmJMadPn3aoa//+/Y0xxqSmphpJZtOmTfb1KSkpRpL9Or7++uumadOmpqCgoNS6L1iwwHh4eJiioqJStwEAAIB7mDVrlvH39zeFhYUmOzvbeHl5mczMTDN37lzTtWtXY4wxK1asMJLMvn377PvFxMQYHx8f4+/v77CsWbPGGPN7X99qtRp/f39jsViMJNO+ffsL9iXPVVJ/3hhjEhISzHXXXedQ1rFjRzN27Fj7z5LMyJEjHbbp2bOneemllxzK/vOf/5jIyEhjzMX7ujExMea+++6z/2yz2UxYWJiZMWOGMabsffKz75VycnKMj4+PmTdvnn37X3/91VitVjNixIgSYzDGmKlTp5pGjRoVKx8/frxp3LixadmypZk/f77Jz883LVu2NN9884158803TdOmTU3nzp1NcnKyw3703wGUhJG2QDVjjLmsBwicP2o1NzdXTz75pJo3b66aNWsqICBAKSkp9pG2ZZWSkqIuXbo4lHXp0kUpKSkOZa1bt7b/v7+/v4KCghxGoJ4vLy9Pfn5+DmWPP/64XnjhBXXp0kXjx4/Xjh077Ou+/fZbJSUlKSAgwL7ExcVJktLS0pSSkqL8/Hz17Nmz1Hq0adPG4etoXbp0kc1ms3/yL0nx8fHy9PS0/xwZGWmvR0pKiry8vNS+fXv7+ri4OIfpJO666y7l5eWpUaNGGjJkiD799NNicwxbrVbZbDbl5+eXen0AAADgHrp166YTJ05o8+bNWrt2rZo2bao6deooISHBPq/tqlWr1KhRo2Jfrx8zZoy2b9/usJzfb//oo4+0bds2ffLJJ4qNjdWcOXPk7e1d7rjP7Z9Ljv3as86P5dtvv9Xzzz/v0OceMmSIDh06pJMnT5apr3vueS0WiyIiIhz602Xpk5+VlpamgoICderUyV4WEhKiZs2aXbDuJb3XkM6MLP7hhx+0c+dO9evXT5MmTVKvXr3k7e2tF154QevWrdPDDz+sBx54wGE/+u8ASuLl6gAAVK6UlBQ1bNhQkuyT5htj7OtLe0DA+XNjPfnkk1q2bJlee+01xcbGymq16s4771RBQUGFxH1+x9JisVzwCau1a9fWsWPHHMoefvhh9e7dW1988YW+/PJLTZo0Sa+//rqGDx+u3NxcJSYm6uWXXy52rMjISP34448uqcf56tevr9TUVC1fvlzLli3Tn//8Z7366qtavXq1/dhHjx6Vv7+/rFarU2IGAABAxYmNjVW9evWUlJSkY8eOKSEhQZIUFRWl+vXr6+uvv1ZSUpJ69OhRbN/atWsrNjb2gsevX7++mjRpoiZNmuj06dPq16+fkpOT5evrW664y9KvPf89RG5uriZOnKjbb7+92PH8/PzK1Nctb3/aGUp6r3G+77//Xu+//762bdumd999V127dlWdOnV0991368EHH1ROTo4CAwMl0X8HUDJG2gLVyMqVK7Vz507dcccdkqQ6depIksN8s+c+lOxCvvrqKw0aNEj9+vVTq1atFBERoZ9++slhGx8fHxUVFV3wOM2bN9dXX31V7NgtWrQoUxyladu2rXbt2lWsvH79+nrsscc0f/58PfHEE5o1a5YkqV27dvruu+/UoEEDxcbGOiz+/v5q0qSJrFarVqxYUWo9vv32W504ccKhHh4eHhf9pP6suLg4nT59Wlu2bLGXpaamKisry2E7q9WqxMRETZs2TatWrdL69eu1c+dO+/rk5GS1bdu2TOcEAACA63Xv3l2rVq3SqlWr1K1bN3t5165dtXjxYm3atKlc89medeedd8rLy0v//Oc/y32sy9GuXTulpqYW62/HxsbaB5RcrK97IZfaJ2/cuLG8vb0dHsx27Ngx7d69+4Lnadu2rdLT00tN3Bpj9Oijj2rKlCkKCAhQUVGRfXDM2f+e+z6J/juAkpC0Baqo/Px8paen6+DBg9q6dateeukl3XbbbbrlllvsX8exWq265ppr7A8YW716tf7617+W6fhNmjTR/PnztX37dn377bf64x//WOwT7gYNGmjNmjU6ePCgjhw5UuJxxowZozlz5mjGjBnas2ePpkyZovnz5+vJJ58sV/179+6t9evXO3SGRo4cqaVLl2rv3r3aunWrkpKS7A8PGDp0qI4ePap7771XmzdvVlpampYuXarBgwerqKhIfn5+Gjt2rJ566im99957SktL04YNG/TOO+9IkgYMGCA/Pz8NHDhQycnJSkpK0vDhw3X//ffbH1Z2Mc2aNVOfPn306KOPauPGjdqyZYsefvhhh0/c58yZo3feeUfJycn68ccf9f7778tqtSomJsa+zdq1a3XDDTeU6/oBAACg8nTv3l3r1q3T9u3b7SNtJSkhIUFvvfWWCgoKSkza5uTkKD093WHJzs4u9TwWi0WPP/64Jk+erJMnT1ZIXS7kueee03vvvaeJEyfqu+++U0pKij788EP7e5Cy9HUv5FL75AEBAXrooYc0ZswYrVy5UsnJyRo0aJA9gVyatm3bqnbt2sUGn5z1r3/9S3Xq1FFiYqKkM1M0rFy5Uhs2bNDUqVPVokULhynQ6L8DKAlJW6CKWrJkiSIjI9WgQQP16dNHSUlJmjZtmhYsWOAwp+q7776r06dPq3379ho5cqReeOGFMh1/ypQpqlWrljp37qzExET17t1b7dq1c9jm+eef108//aTGjRvbR/Wer2/fvvr73/+u1157TfHx8Xrrrbc0e/ZshxEGl+PGG2+Ul5eXli9fbi8rKirS0KFD1bx5c/Xp00dNmza1jzKIiorSV199paKiIt1www1q1aqVRo4cqZo1a9o7bePGjdMTTzyh5557Ts2bN1f//v3t82fVqFFDS5cu1dGjR9WxY0fdeeed6tmzp/7xj39cUtyzZ89WVFSUEhISdPvtt+uRRx5RWFiYfX3NmjU1a9YsdenSRa1bt9by5cv1+eefKzQ0VJJ08OBBff311xo8eHC5rh8AAAAqT/fu3ZWXl6fY2FiH5GJCQoJycnLUrFkzRUZGFtvvueeeU2RkpMPy1FNPXfBcAwcOVGFh4SX3U52hd+/eWrRokb788kt17NhR11xzjaZOnWpPyl6sr3sxl9Mnf/XVV3X99dcrMTFRvXr10nXXXefwjImSeHp6avDgwfrggw+KrcvIyNCLL76oadOm2cuuvvpqPfHEE7r55ps1b948zZ49276O/juA0ljMuZNZAkAVMn36dC1cuFBLly51dSiVZuzYsTp27JjefvttV4cCAAAAVFnp6emKj4/X1q1byzwSuCT03wGUhgeRAaiyHn30UWVlZTlM8l/VhYWFafTo0a4OAwAAAKjSIiIi9M4772j//v3lStrSfwdQGkbaAgAAAAAAAIAbYU5bAAAAAAAAAHAjJG0BAAAAAAAAwI2QtAUAAAAAAAAAN0LSFgAAAAAAAADcCElbAAAAAAAAAHAjJG0BAAAAAAAAwI2QtAUAAAAAAAAAN0LSFgAAAAAAAADcCElbAAAAAAAAAHAj/w9PaDfql2wvCwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -526,78 +332,19 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", - "WER \u2014 min: 0.0%, max: 5.3%, mean: 2.6%, median: 3.7%\n", - "Duration \u2014 min: 3.66s, max: 19.20s, total: 554.0s\n" + "\nWER \u2014 min: 0.0%, max: 5.3%, mean: 2.6%, median: 3.7%\nDuration \u2014 min: 3.66s, max: 19.20s, total: 554.0s\n" ] } ], "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "wers = [r.get(\"wer_pct\", 0) for r in results]\n", - "durations = [r.get(\"duration\", 0) for r in results]\n", - "\n", - "if not wers:\n", - " print(\"No results to visualize. Try relaxing WER_THRESHOLD or re-running the pipeline.\")\n", - "else:\n", - " fig, axes = plt.subplots(2, 2, figsize=(14, 10))\n", - "\n", - " # 1. WER histogram with threshold line\n", - " ax = axes[0, 0]\n", - " ax.hist(wers, bins=30, color=\"#4C72B0\", edgecolor=\"white\", alpha=0.85)\n", - " ax.axvline(WER_THRESHOLD, color=\"#C44E52\", linestyle=\"--\", linewidth=2, label=f\"Threshold ({WER_THRESHOLD}%)\")\n", - " ax.set_xlabel(\"WER (%)\")\n", - " ax.set_ylabel(\"Count\")\n", - " ax.set_title(\"WER Distribution\")\n", - " ax.legend()\n", - "\n", - " # 2. Duration distribution\n", - " ax = axes[0, 1]\n", - " ax.hist(durations, bins=30, color=\"#55A868\", edgecolor=\"white\", alpha=0.85)\n", - " ax.set_xlabel(\"Duration (seconds)\")\n", - " ax.set_ylabel(\"Count\")\n", - " ax.set_title(\"Audio Duration Distribution\")\n", - "\n", - " # 3. WER vs Duration scatter\n", - " ax = axes[1, 0]\n", - " scatter = ax.scatter(durations, wers, c=wers, cmap=\"RdYlGn_r\", alpha=0.6, s=20, edgecolors=\"none\")\n", - " ax.axhline(WER_THRESHOLD, color=\"#C44E52\", linestyle=\"--\", linewidth=1.5, alpha=0.7)\n", - " ax.set_xlabel(\"Duration (seconds)\")\n", - " ax.set_ylabel(\"WER (%)\")\n", - " ax.set_title(\"WER vs Duration\")\n", - " plt.colorbar(scatter, ax=ax, label=\"WER %\")\n", - "\n", - " # 4. Pass rate at multiple thresholds\n", - " ax = axes[1, 1]\n", - " thresholds = [5, 10, 25, 50, 75, 100]\n", - " pass_rates = [sum(1 for w in wers if w <= t) / len(wers) * 100 for t in thresholds]\n", - " bars = ax.bar([str(t) for t in thresholds], pass_rates, color=\"#8172B2\", edgecolor=\"white\")\n", - " ax.set_xlabel(\"WER Threshold (%)\")\n", - " ax.set_ylabel(\"Samples Passing (%)\")\n", - " ax.set_title(\"Dataset Yield by Threshold\")\n", - " for bar, rate in zip(bars, pass_rates, strict=True):\n", - " ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 1, f\"{rate:.0f}%\", ha=\"center\", fontsize=9)\n", - " ax.set_ylim(0, 110)\n", - "\n", - " fig.suptitle(f\"FLEURS {LANG} / {SPLIT} \u2014 {len(results)} samples (WER \u2264 {WER_THRESHOLD}%)\", fontsize=13, y=1.01)\n", - " fig.tight_layout()\n", - " plt.show()\n", - "\n", - " print(\n", - " f\"\\nWER \u2014 min: {min(wers):.1f}%, max: {max(wers):.1f}%, mean: {np.mean(wers):.1f}%, median: {np.median(wers):.1f}%\"\n", - " )\n", - " print(f\"Duration \u2014 min: {min(durations):.2f}s, max: {max(durations):.2f}s, total: {sum(durations):.1f}s\")" + "import matplotlib.pyplot as plt\nimport numpy as np\n\nwers = [r.get(\"wer_pct\", 0) for r in results]\ndurations = [r.get(\"duration\", 0) for r in results]\n\nif not wers:\n print(\"No results to visualize. Try relaxing WER_THRESHOLD or re-running the pipeline.\")\nelse:\n fig, axes = plt.subplots(2, 2, figsize=(14, 10))\n\n # 1. WER histogram with threshold line\n ax = axes[0, 0]\n ax.hist(wers, bins=30, color=\"#4C72B0\", edgecolor=\"white\", alpha=0.85)\n ax.axvline(WER_THRESHOLD, color=\"#C44E52\", linestyle=\"--\", linewidth=2, label=f\"Threshold ({WER_THRESHOLD}%)\")\n ax.set_xlabel(\"WER (%)\")\n ax.set_ylabel(\"Count\")\n ax.set_title(\"WER Distribution\")\n ax.legend()\n\n # 2. Duration distribution\n ax = axes[0, 1]\n ax.hist(durations, bins=30, color=\"#55A868\", edgecolor=\"white\", alpha=0.85)\n ax.set_xlabel(\"Duration (seconds)\")\n ax.set_ylabel(\"Count\")\n ax.set_title(\"Audio Duration Distribution\")\n\n # 3. WER vs Duration scatter\n ax = axes[1, 0]\n scatter = ax.scatter(durations, wers, c=wers, cmap=\"RdYlGn_r\", alpha=0.6, s=20, edgecolors=\"none\")\n ax.axhline(WER_THRESHOLD, color=\"#C44E52\", linestyle=\"--\", linewidth=1.5, alpha=0.7)\n ax.set_xlabel(\"Duration (seconds)\")\n ax.set_ylabel(\"WER (%)\")\n ax.set_title(\"WER vs Duration\")\n plt.colorbar(scatter, ax=ax, label=\"WER %\")\n\n # 4. Pass rate at multiple thresholds\n ax = axes[1, 1]\n thresholds = [5, 10, 25, 50, 75, 100]\n pass_rates = [sum(1 for w in wers if w <= t) / len(wers) * 100 for t in thresholds]\n bars = ax.bar([str(t) for t in thresholds], pass_rates, color=\"#8172B2\", edgecolor=\"white\")\n ax.set_xlabel(\"WER Threshold (%)\")\n ax.set_ylabel(\"Samples Passing (%)\")\n ax.set_title(\"Dataset Yield by Threshold\")\n for bar, rate in zip(bars, pass_rates, strict=True):\n ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 1, f\"{rate:.0f}%\", ha=\"center\", fontsize=9)\n ax.set_ylim(0, 110)\n\n fig.suptitle(f\"FLEURS {LANG} / {SPLIT} \u2014 {len(results)} samples (WER \u2264 {WER_THRESHOLD}%)\", fontsize=13, y=1.01)\n fig.tight_layout()\n plt.show()\n\n print(\n f\"\\nWER \u2014 min: {min(wers):.1f}%, max: {max(wers):.1f}%, mean: {np.mean(wers):.1f}%, median: {np.median(wers):.1f}%\"\n )\n print(f\"Duration \u2014 min: {min(durations):.2f}s, max: {max(durations):.2f}s, total: {sum(durations):.1f}s\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 5: Experiment with different thresholds\n", - "\n", - "Try changing the WER threshold to see how it affects the dataset size:" + "## Step 5: Experiment with different thresholds\n\nTry changing the WER threshold to see how it affects the dataset size:" ] }, { @@ -605,10 +352,10 @@ "execution_count": 9, "metadata": { "execution": { - "iopub.execute_input": "2026-06-11T16:41:07.814658Z", - "iopub.status.busy": "2026-06-11T16:41:07.814444Z", - "iopub.status.idle": "2026-06-11T16:41:07.817820Z", - "shell.execute_reply": "2026-06-11T16:41:07.817294Z" + "iopub.execute_input": "2026-08-07T18:06:28.248007Z", + "iopub.status.busy": "2026-08-07T18:06:28.247758Z", + "iopub.status.idle": "2026-08-07T18:06:28.250978Z", + "shell.execute_reply": "2026-08-07T18:06:28.250431Z" } }, "outputs": [ @@ -616,30 +363,19 @@ "name": "stdout", "output_type": "stream", "text": [ - " WER \u2264 5.0%: 37 samples (74%)\n", - " WER \u2264 5.5%: 50 samples (100%)\n", - " WER \u2264 10.0%: 50 samples (100%)\n", - " WER \u2264 25.0%: 50 samples (100%)\n", - " WER \u2264 50.0%: 50 samples (100%)\n", - " WER \u2264 75.0%: 50 samples (100%)\n" + " WER \u2264 5.0%: 37 samples (74%)\n WER \u2264 5.5%: 50 samples (100%)\n WER \u2264 10.0%: 50 samples (100%)\n WER \u2264 25.0%: 50 samples (100%)\n WER \u2264 50.0%: 50 samples (100%)\n WER \u2264 75.0%: 50 samples (100%)\n" ] } ], "source": [ - "thresholds = [5, 5.5, 10, 25, 50, 75]\n", - "for t in thresholds:\n", - " passing = [r for r in results if r.get(\"wer_pct\", 100) <= t]\n", - " pct = len(passing) / len(results) * 100 if results else 0\n", - " print(f\" WER \u2264 {t:4.1f}%: {len(passing):4d} samples ({pct:.0f}%)\")" + "thresholds = [5, 5.5, 10, 25, 50, 75]\nfor t in thresholds:\n passing = [r for r in results if r.get(\"wer_pct\", 100) <= t]\n pct = len(passing) / len(results) * 100 if results else 0\n print(f\" WER \u2264 {t:4.1f}%: {len(passing):4d} samples ({pct:.0f}%)\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Cleanup\n", - "\n", - "Shut down the Ray cluster started by `RayClient`." + "## Cleanup\n\nShut down the Ray cluster started by `RayClient`." ] }, { @@ -647,15 +383,14 @@ "execution_count": 10, "metadata": { "execution": { - "iopub.execute_input": "2026-06-11T16:41:07.819207Z", - "iopub.status.busy": "2026-06-11T16:41:07.819060Z", - "iopub.status.idle": "2026-06-11T16:41:11.048717Z", - "shell.execute_reply": "2026-06-11T16:41:11.047890Z" + "iopub.execute_input": "2026-08-07T18:06:28.252266Z", + "iopub.status.busy": "2026-08-07T18:06:28.252127Z", + "iopub.status.idle": "2026-08-07T18:06:31.627246Z", + "shell.execute_reply": "2026-08-07T18:06:31.626551Z" } }, "outputs": [], "source": [ - "configure_loguru()\n", "ray_client.stop()" ] } diff --git a/tutorials/audio/fleurs/main.py b/tutorials/audio/fleurs/main.py index 9eb2051139..fabdeea277 100644 --- a/tutorials/audio/fleurs/main.py +++ b/tutorials/audio/fleurs/main.py @@ -30,7 +30,7 @@ --config-name pipeline \\ raw_data_dir=./example_audio/fleurs \\ lang=en_us \\ - stages.1.model_name=nvidia/parakeet-tdt-0.6b-v2 \\ + stages.1.model_id=nvidia/parakeet-tdt-0.6b-v2 \\ wer_threshold=25.0 \\ backend=ray_data """ diff --git a/tutorials/audio/fleurs/pipeline.yaml b/tutorials/audio/fleurs/pipeline.yaml index 97bd868bca..2f09915bfa 100644 --- a/tutorials/audio/fleurs/pipeline.yaml +++ b/tutorials/audio/fleurs/pipeline.yaml @@ -19,7 +19,7 @@ documentation: | 0. ``CreateInitialManifestFleursStage`` — Hugging Face download (once per language under ``//``) and manifest emission - 1. ``InferenceAsrNemoStage`` — GPU ASR inference (adds ``pred_text``) + 1. ``ASRStage`` + ``NeMoASRAdapter`` — GPU ASR inference (adds ``pred_text``) 2. ``GetPairwiseWerStage`` — pairwise WER (adds ``wer_pct``) 3. ``GetAudioDurationStage`` — audio duration in seconds 4. ``PreserveByValueStage`` — keep samples with ``wer_pct <= wer_threshold`` @@ -50,8 +50,16 @@ stages: raw_data_dir: ${raw_data_dir} batch_size: 4 - - _target_: nemo_curator.stages.audio.inference.asr.asr_nemo.InferenceAsrNemoStage - model_name: nvidia/stt_hy_fastconformer_hybrid_large_pc + - _target_: nemo_curator.stages.audio.inference.asr.stage.ASRStage + adapter_target: nemo_curator.models.asr.nemo_asr.NeMoASRAdapter + model_id: nvidia/stt_hy_fastconformer_hybrid_large_pc + audio_filepath_key: audio_filepath + target_sample_rate: 16000 + batch_size: 16 + adapter_kwargs: + # Avoid NeMo RNNT label-loop CUDA graphs, which are not supported by all + # CUDA runtime/driver combinations. This does not disable GPU inference. + use_cuda_graph_decoder: false resources: _target_: nemo_curator.stages.resources.Resources gpus: 1.0 diff --git a/tutorials/audio/nemo_fastconformer/README.md b/tutorials/audio/nemo_fastconformer/README.md new file mode 100644 index 0000000000..7a63b6b509 --- /dev/null +++ b/tutorials/audio/nemo_fastconformer/README.md @@ -0,0 +1,113 @@ +# NeMo FastConformer ASR through the shared adapter + +This is the smallest runnable NeMo FastConformer pipeline in Curator. It reads +a NeMo-style JSONL manifest, resamples every file to 16 kHz mono, transcribes +with the generic `ASRStage` configured with `NeMoASRAdapter`, and writes the +rows back to JSONL. + +There is no FastConformer-specific Curator stage. `ASRStage` owns task I/O, +audio preparation, batching, and output assembly; `NeMoASRAdapter` owns NeMo +checkpoint download, model lifecycle, and inference. Use this split for all +ordinary NeMo ASR transcription pipelines. The specialized forced-alignment +stage remains separate because it emits word timestamps rather than only a +transcript. + +## Requirements + +- x86_64 Linux +- `ffmpeg` +- NeMo Curator's audio dependencies +- One CUDA GPU is recommended; CPU inference is supported for a small smoke run + +From the Curator repository root: + +```bash +uv sync --extra audio_cuda12 +source .venv/bin/activate +``` + +For CPU-only use, install `audio_cpu` instead. + +## Run the bundled smoke input + +The repository already contains a two-row manifest and two short OPUS files: + +```bash +python nemo_curator/config/run.py \ + --config-path ../../tutorials/audio/nemo_fastconformer \ + manifest_path=tests/fixtures/audio/tagging/sample_input.jsonl \ + output_path=/tmp/nemo_fastconformer_output.jsonl \ + workspace_dir=/tmp/nemo_fastconformer_workspace +``` + +`--config-path` is relative to `nemo_curator/config/run.py`; manifest and +output paths are relative to the current working directory. Run the command +from the repository root as shown. The first run downloads +`nvidia/stt_en_fastconformer_ctc_large`. + +For a CPU smoke run, append `gpus_per_actor=0`. CPU execution is much slower +than GPU execution. + +## Input and output + +Each input row must contain `audio_filepath`: + +```json +{"audio_filepath": "/data/sample.opus"} +``` + +`ResampleAudioStage` preserves the source path and adds +`resampled_audio_filepath`, `audio_item_id`, and `duration`. It caches +16-bit, 16 kHz, mono WAV files under `workspace_dir`. + +`ASRStage` opens only the resampled files in its current batch and supplies +contiguous mono waveforms to `NeMoASRAdapter`. It adds `pred_text` by +default. The writer produces one JSON object per input row at `output_path`. +Inspect `_skipme` and `additional_notes` before consuming output; Curator +uses those fields to retain and explain rows that could not be transcribed. + +## Useful overrides + +| Setting | Default | Purpose | +|---|---|---| +| `model_id` | `nvidia/stt_en_fastconformer_ctc_large` | Any compatible pretrained NeMo ASR checkpoint | +| `pred_text_key` | `pred_text` | Output transcript column | +| `gpus_per_actor` | `1` | GPUs scheduled for each ASR worker; set `0` for CPU | +| `stages.2.batch_size` | `16` | Number of waveforms per NeMo transcription call | +| `stages.2.adapter_kwargs.num_workers` | `0` | NeMo transcription data-loader workers | +| `stages.2.adapter_kwargs.enable_local_attention` | `false` | Convert a compatible FastConformer checkpoint to local attention | + +When local attention is enabled, configure its left/right context with: + +```bash +stages.2.adapter_kwargs.enable_local_attention=true \ +'stages.2.adapter_kwargs.local_attention_context_size=[128,128]' +``` + +## Use the adapter in Python + +```python +from nemo_curator.stages.audio.inference.asr.stage import ASRStage + +asr = ASRStage( + adapter_target="nemo_curator.models.asr.nemo_asr.NeMoASRAdapter", + model_id="nvidia/stt_en_fastconformer_ctc_large", + audio_filepath_key="audio_filepath", + batch_size=16, +) +``` + +Normally place a `ResampleAudioStage` before this stage and keep the default +`audio_filepath_key="resampled_audio_filepath"`. The direct-file form above +is useful when upstream data is already readable; `ASRStage` still normalizes +audio to the configured `target_sample_rate` before calling the adapter. + +## Troubleshooting + +| Symptom | Action | +|---|---| +| `ffmpeg` is not found | Install `ffmpeg` and ensure it is on `PATH` | +| CUDA out of memory | Reduce `stages.2.batch_size` or select a smaller checkpoint | +| Model import fails | Install `audio_cuda12` or `audio_cpu` for your platform | +| First run appears idle | Wait for the NeMo checkpoint download and inspect the Ray logs | +| Local-attention conversion fails | Disable it or use a FastConformer checkpoint exposing the required conversion APIs | diff --git a/tutorials/audio/nemo_fastconformer/pipeline.yaml b/tutorials/audio/nemo_fastconformer/pipeline.yaml new file mode 100644 index 0000000000..e35bd67bae --- /dev/null +++ b/tutorials/audio/nemo_fastconformer/pipeline.yaml @@ -0,0 +1,54 @@ +# Minimal NeMo FastConformer ASR pipeline. +# +# Usage (from the Curator repository root): +# python nemo_curator/config/run.py \ +# --config-path ../../tutorials/audio/nemo_fastconformer \ +# manifest_path=tests/fixtures/audio/tagging/sample_input.jsonl + +defaults: + - _self_ + - override hydra/job_logging: none + - override hydra/hydra_logging: none + +hydra: + run: + dir: . + output_subdir: null + +manifest_path: ??? +output_path: ./nemo_fastconformer_output.jsonl +workspace_dir: /tmp/nemo_fastconformer_workspace +resampled_audio_dir: ${workspace_dir}/audio_resampled +model_id: nvidia/stt_en_fastconformer_ctc_large +pred_text_key: pred_text +gpus_per_actor: 1 +backend: ray_data +execution_mode: streaming + +stages: + - _target_: nemo_curator.stages.audio.common.ManifestReader + manifest_path: ${manifest_path} + files_per_partition: 1 + + - _target_: nemo_curator.stages.audio.tagging.ResampleAudioStage + name: ResampleAudio + resampled_audio_dir: ${resampled_audio_dir} + target_sample_rate: 16000 + target_format: wav + target_nchannels: 1 + + - _target_: nemo_curator.stages.audio.inference.asr.stage.ASRStage + adapter_target: nemo_curator.models.asr.nemo_asr.NeMoASRAdapter + model_id: ${model_id} + pred_text_key: ${pred_text_key} + batch_size: 16 + resources: + _target_: nemo_curator.stages.resources.Resources + gpus: ${gpus_per_actor} + adapter_kwargs: + num_workers: 0 + verbose: false + enable_local_attention: false + + - _target_: nemo_curator.stages.audio.common.ManifestWriterStage + output_path: ${output_path} diff --git a/tutorials/audio/qwen_asr/README.md b/tutorials/audio/qwen_asr/README.md index e246bff103..4a53bf3b6d 100644 --- a/tutorials/audio/qwen_asr/README.md +++ b/tutorials/audio/qwen_asr/README.md @@ -53,6 +53,10 @@ nkoluguri reference's vLLM backend and engine settings. The the shared `vllm` extra provides the same Curator-pinned engine stack used by Qwen-Omni. +The optional Hugging Face revision is adapter-owned. Set the tutorial's +top-level `model_revision` override to forward it through +`adapter_kwargs.revision` to both weight prefetch and model loading. + ## Effective defaults The tutorial caps vLLM's model context at 8,192 tokens so the bundled smoke @@ -63,6 +67,7 @@ input can run on a 12 GB GPU. This does not change the adapter's default. | Executor | Ray Data | | ASR stage batch size | `128` | | GPUs per ASR actor | `1` | +| Hugging Face model revision | `null` (Hugging Face default) | | GPU memory limit | `0.7` of device memory | | Maximum vLLM model length | `8192` tokens | | Maximum generated tokens | `4096` | diff --git a/tutorials/audio/qwen_asr/pipeline.yaml b/tutorials/audio/qwen_asr/pipeline.yaml index 10f249eb8f..0cc3cffb55 100644 --- a/tutorials/audio/qwen_asr/pipeline.yaml +++ b/tutorials/audio/qwen_asr/pipeline.yaml @@ -21,6 +21,7 @@ output_path: ./qwen_asr_output.jsonl workspace_dir: /tmp/qwen_asr_workspace resampled_audio_dir: ${workspace_dir}/audio_resampled model_id: Qwen/Qwen3-ASR-0.6B +model_revision: null default_language: null supported_language_codes: [zh, en, yue, ar, de, fr, es, pt, id, it, ko, ru, th, vi, ja, tr, hi, ms, nl, sv, da, fi, pl, cs, fil, fa, el, hu, mk, ro] pred_text_key: pred_text @@ -53,6 +54,7 @@ stages: _target_: nemo_curator.stages.resources.Resources gpus: ${gpus_per_actor} adapter_kwargs: + revision: ${model_revision} gpu_memory_utilization: 0.7 max_new_tokens: 4096 max_inference_batch_size: 128 diff --git a/tutorials/audio/qwen_omni_inprocess/README.md b/tutorials/audio/qwen_omni_inprocess/README.md index 0586fd7ec6..0705ac11e6 100644 --- a/tutorials/audio/qwen_omni_inprocess/README.md +++ b/tutorials/audio/qwen_omni_inprocess/README.md @@ -50,7 +50,7 @@ The first run downloads `Qwen/Qwen3-Omni-30B-A3B-Instruct`. The pipeline uses a batch size of 32 and allocates two GPUs to each ASR actor. `gpus_per_actor: 2` is the single GPU-count setting: Curator schedules that many GPUs, then `ASRStage` supplies the scheduled device count to the adapter -when it loads the model. The Qwen adapter uses that stage-owned value as +when it loads the model. The Qwen adapter uses that allocated value as vLLM's tensor-parallel size. ## Effective defaults @@ -73,9 +73,12 @@ explicit: Keeping these values in the YAML makes any future drift from the reference configuration visible in code review. -The engine settings live under `adapter_kwargs.vllm_kwargs`; sampling settings -live under `adapter_kwargs.sampling_kwargs`. They are forwarded to Curator's -shared vLLM construction path and vLLM's `SamplingParams`, respectively. +The optional Hugging Face model revision lives at `adapter_kwargs.revision` +(`model_revision` in the tutorial's top-level overrides), engine settings live +under `adapter_kwargs.vllm_kwargs`, and sampling settings live under +`adapter_kwargs.sampling_kwargs`. These are Qwen adapter settings, not generic +`ASRStage` fields. They are forwarded to the Hugging Face download, Curator's +shared vLLM construction path, and vLLM's `SamplingParams`, respectively. Do not put `tensor_parallel_size` in `vllm_kwargs`: `gpus_per_actor` is the single GPU-count setting and the stage derives tensor parallelism from it. @@ -124,7 +127,7 @@ contain `audio_filepath` and, by default, `source_lang`: `${workspace_dir}/audio_resampled` by default and reuses it on later runs. Only file paths and metadata travel between pipeline stages. `ASRStage` opens -`resampled_audio_filepath` with SoundFile only for its current batch and +`resampled_audio_filepath` with TorchAudio only for its current batch and preserves the decoded sample rate while normalizing each waveform to contiguous mono 16 kHz NumPy samples for the adapter. It never stores either the waveform or sample rate in `task.data`, so manifest size does not cause all decoded diff --git a/tutorials/audio/qwen_omni_inprocess/pipeline.yaml b/tutorials/audio/qwen_omni_inprocess/pipeline.yaml index 6147b02777..d3f20a0801 100644 --- a/tutorials/audio/qwen_omni_inprocess/pipeline.yaml +++ b/tutorials/audio/qwen_omni_inprocess/pipeline.yaml @@ -21,6 +21,7 @@ output_path: ./qwen_omni_output.jsonl workspace_dir: /tmp/qwen_omni_workspace resampled_audio_dir: ${workspace_dir}/audio_resampled model_id: Qwen/Qwen3-Omni-30B-A3B-Instruct +model_revision: null default_language: null supported_language_codes: [en, zh, ko, ja, de, ru, it, fr, es, pt, ms, nl, id, tr, vi, yue, ar, ur] prompt_text: Transcribe the audio. @@ -53,6 +54,7 @@ stages: _target_: nemo_curator.stages.resources.Resources gpus: ${gpus_per_actor} adapter_kwargs: + revision: ${model_revision} prompt_text: ${prompt_text} prompt_file: ${prompt_file} en_prompt_text: null diff --git a/uv.lock b/uv.lock index 0f8838e8a7..6301764627 100644 --- a/uv.lock +++ b/uv.lock @@ -59,7 +59,7 @@ overrides = [ { name = "sqlfluff", specifier = ">=4.2.0" }, { name = "torch", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')", specifier = "==2.11.0", index = "https://download.pytorch.org/whl/cu129" }, { name = "torchaudio", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')", specifier = "==2.11.0", index = "https://download.pytorch.org/whl/cu129" }, - { name = "torchcodec", marker = "platform_machine == 'x86_64' and sys_platform != 'darwin'", specifier = "~=0.11.0", index = "https://download.pytorch.org/whl/cu129" }, + { name = "torchcodec", marker = "platform_machine == 'x86_64' and sys_platform != 'darwin'", specifier = "~=0.11.0" }, { name = "torchvision", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')", specifier = "==0.26.0", index = "https://download.pytorch.org/whl/cu129" }, { name = "xgrammar", specifier = ">=0.1.32" }, ] @@ -5451,6 +5451,7 @@ audio-common = [ { name = "silero-vad" }, { name = "soundfile" }, { name = "torchaudio", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "torchcodec", marker = "platform_machine == 'x86_64' and sys_platform != 'darwin'" }, { name = "transformers" }, { name = "whisperx", marker = "platform_machine == 'x86_64' and sys_platform != 'darwin'" }, ] @@ -5468,6 +5469,7 @@ audio-cpu = [ { name = "silero-vad" }, { name = "soundfile" }, { name = "torchaudio", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "torchcodec", marker = "platform_machine == 'x86_64' and sys_platform != 'darwin'" }, { name = "transformers" }, { name = "whisperx", marker = "platform_machine == 'x86_64' and sys_platform != 'darwin'" }, ] @@ -5911,7 +5913,7 @@ requires-dist = [ { name = "torchaudio", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'video-cuda12') or (sys_platform == 'darwin' and extra == 'video-cuda12')", index = "https://pypi.org/simple" }, { name = "torchaudio", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'audio-common') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'audio-common')", index = "https://download.pytorch.org/whl/cu129" }, { name = "torchaudio", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'video-cuda12') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'video-cuda12')", index = "https://download.pytorch.org/whl/cu129" }, - { name = "torchcodec", marker = "platform_machine == 'x86_64' and sys_platform != 'darwin' and extra == 'audio-cuda12'", index = "https://download.pytorch.org/whl/cu129" }, + { name = "torchcodec", marker = "platform_machine == 'x86_64' and sys_platform != 'darwin' and extra == 'audio-common'", index = "https://pypi.org/simple", conflict = { package = "nemo-curator", extra = "audio-common" } }, { name = "torchvision", marker = "(platform_machine == 'aarch64' and sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'image-cpu') or (platform_machine == 'x86_64' and sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'image-cpu')" }, { name = "torchvision", marker = "(platform_machine == 'aarch64' and sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'video-cpu') or (platform_machine == 'x86_64' and sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'video-cpu')" }, { name = "torchvision", marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and extra == 'image-cpu') or (sys_platform == 'darwin' and extra == 'image-cpu')", index = "https://pypi.org/simple" }, @@ -10895,12 +10897,15 @@ wheels = [ [[package]] name = "torchcodec" -version = "0.11.1+cu129" -source = { registry = "https://download.pytorch.org/whl/cu129" } +version = "0.11.1" +source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://download.pytorch.org/whl/cu129/torchcodec-0.11.1%2Bcu129-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e58def3a347a7a0476d9d662ecc80bdfb679d0f821af175da439a3e5a534056e", upload-time = "2026-04-14T18:06:04Z" }, - { url = "https://download.pytorch.org/whl/cu129/torchcodec-0.11.1%2Bcu129-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:628ce609e90b6903230a398fa545a529c2a4bcc0564a0e3d9a72106c9e3ed51a", upload-time = "2026-04-14T18:06:04Z" }, - { url = "https://download.pytorch.org/whl/cu129/torchcodec-0.11.1%2Bcu129-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e5aa69a4c2157acbcb7550a765438c11f9151ceca55b6e093e8e13b2e45f9806", upload-time = "2026-04-14T18:06:04Z" }, + { url = "https://files.pythonhosted.org/packages/f6/50/bd8e96424e2ae403b4ef3e2cb839a0be8a685fa9f6f27482acdaad075845/torchcodec-0.11.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:dd17e1cb3b8c6cdd2f6a522d8822031b169fb10b7ff465d0de748df9af4ea930", size = 2310372, upload-time = "2026-04-14T18:24:47.75Z" }, + { url = "https://files.pythonhosted.org/packages/22/04/c53a64ff8161949726edaa70b00b282c100cbcaa63c4b2c9f4f33829055d/torchcodec-0.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:30e8fb461c4551c53b51bc19ab01e7a8c118aa89aa59e7ab110548c6b9ad01ae", size = 1915258, upload-time = "2026-04-14T18:24:49.739Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a9/a2b6ee3e84c55bdd0c45fd991dde71c95a99115ec9e26938b212b4545dcf/torchcodec-0.11.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6c26e90e7aa982302644d0af8cb706318682bb390f48a80ecbfeab03499acd04", size = 2329883, upload-time = "2026-04-14T18:24:55.467Z" }, + { url = "https://files.pythonhosted.org/packages/82/48/683114a4ed6b59f76b6919532a5db0f4068787be26bab92cc18a1dfa6794/torchcodec-0.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:3fd2d10e0e0a5f455c1c87dc1380b3bd43b77dd5eeeaf479470643b1c04a2dd2", size = 1921066, upload-time = "2026-04-14T18:24:57.102Z" }, + { url = "https://files.pythonhosted.org/packages/5d/b2/85ad7a81f387e40983c21bc94da0c333974afb41f38c3a85d25875274187/torchcodec-0.11.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5eee69971cec1147a03b8a6b678b5dfbeff0b2c71ed7929e488391f9fbcd630c", size = 2332721, upload-time = "2026-04-14T18:25:02.518Z" }, + { url = "https://files.pythonhosted.org/packages/ad/ca/5c66f21d2a12039450e9dd4d9d7c480019dfbe9e8a87696a3c3a827c1e37/torchcodec-0.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:67b34e5733636588ebe0f15082bbb90a8ce1472ccb8bb1a656ec28958a208919", size = 1920990, upload-time = "2026-04-14T18:25:04.269Z" }, ] [[package]]