chore: import upstream snapshot with attribution
Create PR to main with cherry-pick from release / cherry-pick (push) Failing after 0s
CICD NeMo / pre-flight (push) Failing after 0s
CICD NeMo / configure (push) Has been skipped
Build, validate, and release Neural Modules / pre-flight (push) Failing after 1s
CICD NeMo / code-linting (push) Has been skipped
Build, validate, and release Neural Modules / release (push) Has been skipped
Build, validate, and release Neural Modules / release-summary (push) Has been cancelled
CICD NeMo / cicd-test-container-build (push) Has been cancelled
CICD NeMo / cicd-import-tests (push) Has been cancelled
CICD NeMo / L0_Setup_Test_Data_And_Models (push) Has been cancelled
CICD NeMo / cicd-main-unit-tests (push) Has been cancelled
CICD NeMo / cicd-main-speech (push) Has been cancelled
CICD NeMo / Nemo_CICD_Test (push) Has been cancelled
CICD NeMo / Coverage (e2e) (push) Has been cancelled
CICD NeMo / Coverage (unit-test) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
CICD NeMo / cicd-wait-in-queue (push) Has been cancelled
Create PR to main with cherry-pick from release / cherry-pick (push) Failing after 0s
CICD NeMo / pre-flight (push) Failing after 0s
CICD NeMo / configure (push) Has been skipped
Build, validate, and release Neural Modules / pre-flight (push) Failing after 1s
CICD NeMo / code-linting (push) Has been skipped
Build, validate, and release Neural Modules / release (push) Has been skipped
Build, validate, and release Neural Modules / release-summary (push) Has been cancelled
CICD NeMo / cicd-test-container-build (push) Has been cancelled
CICD NeMo / cicd-import-tests (push) Has been cancelled
CICD NeMo / L0_Setup_Test_Data_And_Models (push) Has been cancelled
CICD NeMo / cicd-main-unit-tests (push) Has been cancelled
CICD NeMo / cicd-main-speech (push) Has been cancelled
CICD NeMo / Nemo_CICD_Test (push) Has been cancelled
CICD NeMo / Coverage (e2e) (push) Has been cancelled
CICD NeMo / Coverage (unit-test) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
CICD NeMo / cicd-wait-in-queue (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
# Copyright (c) 2025, 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 json
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
|
||||
import hydra
|
||||
from convert_to_tarred_audio_dataset import ASRTarredDatasetBuilder, ASRTarredDatasetMetadata
|
||||
from hydra.core.config_store import ConfigStore
|
||||
from joblib import Parallel, delayed
|
||||
from omegaconf import MISSING
|
||||
from tqdm import tqdm
|
||||
|
||||
"""
|
||||
# Partial Tarred Audio Dataset Creator
|
||||
|
||||
## Overview
|
||||
|
||||
This script facilitates the creation of tarred and sharded audio datasets from existing tarred manifests. It allows you to select specific shards from a manifest file and then tar them separately.
|
||||
|
||||
This is useful in several scenarios:
|
||||
- When you only need to process a specific subset of shards (e.g., for debugging or incremental dataset preparation).
|
||||
- When you want to parallelize shard creation across multiple SLURM jobs to accelerate the dataset generation process and overcome per-job time limits.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Ensure that the `convert_to_tarred_audio_dataset` script is correctly configured and run with the `--only_manifests` flag to generate the necessary manifest files.
|
||||
- Make sure the paths to the manifest and metadata files are correct and accessible.
|
||||
|
||||
## Usage
|
||||
|
||||
### Script Execution
|
||||
|
||||
To run the script, use the following command:
|
||||
|
||||
python partial_convertion_to_tarred_audio_dataset.py \
|
||||
# the path to the tarred manifest file that contains the entries for the shards you want to process. This option is mandatory.
|
||||
--tarred_manifest_filepath=<path to the tarred manifest file > \
|
||||
# any other optional argument
|
||||
--output_dir=<output directory for tarred shards> \
|
||||
--shards_to_tar=<shard IDs to be tarred> \
|
||||
--num_workers=-1 \
|
||||
--dataset_metadata_filepath=<dataset metadata YAML filepath>
|
||||
|
||||
Example:
|
||||
python partial_convertion_to_tarred_audio_dataset.py \
|
||||
tarred_manifest_filepath="path/to/manifest.json" \
|
||||
shards_to_tar="0:3"
|
||||
"""
|
||||
|
||||
|
||||
def select_shards(manifest_filepath: str, shards_to_tar: str, slice_with_offset: bool = False):
|
||||
"""
|
||||
Selects and returns a subset of shards from the tarred manifest file.
|
||||
|
||||
Args:
|
||||
manifest_filepath (str): The path to the tarred manifest file.
|
||||
shards_to_tar (str): A range or list of shard IDs to select, e.g., "0:5" or "0,1,2".
|
||||
slice_with_offset (bool, optional): If True, slices entries based on audio offsets. Defaults to False.
|
||||
|
||||
Raises:
|
||||
FileNotFoundError: If the manifest file does not exist.
|
||||
KeyError: If `slice_with_offset` is enabled but required fields are missing in the manifest entries.
|
||||
|
||||
Returns:
|
||||
Dict[int, List[Dict[str, any]]]: A dictionary where the keys are shard IDs and the values are lists of entries for those shards.
|
||||
"""
|
||||
shard_ids = []
|
||||
if shards_to_tar != "all":
|
||||
if ":" not in shards_to_tar:
|
||||
shard_ids = [int(shards_to_tar)]
|
||||
else:
|
||||
start_shard_idx, end_shard_idx = map(
|
||||
lambda x: int(x.strip()) if x.strip() else None, shards_to_tar.split(":")
|
||||
)
|
||||
shard_ids = list(range(start_shard_idx, end_shard_idx))
|
||||
|
||||
entries_to_shard = {}
|
||||
with open(manifest_filepath, 'r') as manifest:
|
||||
for line in tqdm(manifest, desc="Selecting shards"):
|
||||
entry = json.loads(line)
|
||||
if shards_to_tar == "all" or entry['shard_id'] in shard_ids:
|
||||
if entry['shard_id'] not in entries_to_shard:
|
||||
entries_to_shard[entry['shard_id']] = []
|
||||
|
||||
if slice_with_offset:
|
||||
if 'abs_audio_filepath' not in entry or 'source_audio_offset' not in entry:
|
||||
raise KeyError(
|
||||
f"`slice_with_offset` is enabled, but `abs_audio_filepath` and/or `source_audio_offset` are not found in the entry:\n{entry}."
|
||||
)
|
||||
entry['audio_filepath'] = entry.pop('abs_audio_filepath')
|
||||
entry['offset'] = entry.pop('source_audio_offset')
|
||||
|
||||
entries_to_shard[entry['shard_id']].append(entry)
|
||||
|
||||
return entries_to_shard
|
||||
|
||||
|
||||
@dataclass
|
||||
class PartialASRTarredDatasetConfig:
|
||||
"""
|
||||
Configuration class for creating partial tarred audio dataset shards.
|
||||
|
||||
Attributes:
|
||||
tarred_manifest_filepath (str): The path to the tarred manifest file.
|
||||
output_dir (Optional[str]): Directory where the output tarred shards will be saved.
|
||||
shards_to_tar (Optional[str]): A range or list of shard IDs to tar.
|
||||
num_workers (int): Number of parallel workers to use for tar file creation.
|
||||
dataset_metadata_filepath (Optional[str]): Path to the dataset metadata YAML file.
|
||||
dataset_metadata (ASRTarredDatasetMetadata): Dataset metadata configuration.
|
||||
"""
|
||||
|
||||
tarred_manifest_filepath: str = MISSING
|
||||
output_dir: Optional[str] = None
|
||||
shards_to_tar: Optional[str] = "all"
|
||||
num_workers: int = 1
|
||||
dataset_metadata_filepath: Optional[str] = None
|
||||
dataset_metadata: ASRTarredDatasetMetadata = field(default=ASRTarredDatasetMetadata)
|
||||
slice_with_offset: bool = False
|
||||
|
||||
|
||||
def create_shards(cfg: PartialASRTarredDatasetConfig):
|
||||
"""
|
||||
Creates tarred shards based on the provided configuration.
|
||||
|
||||
Args:
|
||||
cfg (PartialASRTarredDatasetConfig): The configuration object containing paths, shard IDs, and metadata.
|
||||
|
||||
Raises:
|
||||
ValueError: If the `tarred_manifest_filepath` is None.
|
||||
FileNotFoundError: If the tarred manifest file or dataset metadata file does not exist.
|
||||
|
||||
Notes:
|
||||
- Reads the tarred manifest file and selects the specified shards.
|
||||
- Creates tarred shards in parallel using the `ASRTarredDatasetBuilder`.
|
||||
- The `dataset_metadata_filepath` is inferred if not provided.
|
||||
"""
|
||||
if cfg.tarred_manifest_filepath is None:
|
||||
raise ValueError("The `tarred_manifest_filepath` cannot be `None`. Please check your configuration.")
|
||||
|
||||
if not os.path.exists(cfg.tarred_manifest_filepath):
|
||||
raise FileNotFoundError(
|
||||
f"The `tarred_manifest_filepath` was not found: {cfg.tarred_manifest_filepath}. Please verify that the filepath is correct."
|
||||
)
|
||||
|
||||
if cfg.dataset_metadata_filepath is None:
|
||||
cfg.dataset_metadata_filepath = os.path.join(os.path.dirname(cfg.tarred_manifest_filepath), "metadata.yaml")
|
||||
|
||||
if cfg.output_dir is None:
|
||||
cfg.output_dir = os.path.dirname(cfg.tarred_manifest_filepath)
|
||||
|
||||
if not os.path.exists(cfg.dataset_metadata_filepath):
|
||||
raise FileNotFoundError(
|
||||
f"The `dataset_metadata_filepath` was not found: {cfg.dataset_metadata_filepath}. Please verify that the filepath is correct."
|
||||
)
|
||||
else:
|
||||
cfg.dataset_metadata = ASRTarredDatasetMetadata.from_file(cfg.dataset_metadata_filepath)
|
||||
|
||||
entries_to_shard = select_shards(
|
||||
cfg.tarred_manifest_filepath, cfg.shards_to_tar, cfg.dataset_metadata.dataset_config.slice_with_offset
|
||||
)
|
||||
|
||||
builder = ASRTarredDatasetBuilder()
|
||||
builder.configure(cfg.dataset_metadata.dataset_config)
|
||||
|
||||
with Parallel(n_jobs=cfg.num_workers, verbose=len(entries_to_shard)) as parallel:
|
||||
# Call parallel tarfile construction
|
||||
_ = parallel(
|
||||
delayed(builder._create_shard)(
|
||||
entries=entries_to_shard[shard_id],
|
||||
target_dir=cfg.output_dir,
|
||||
shard_id=shard_id,
|
||||
)
|
||||
for shard_id in entries_to_shard
|
||||
)
|
||||
|
||||
|
||||
@hydra.main(config_path=None, config_name='partial_tar_config')
|
||||
def main(cfg: PartialASRTarredDatasetConfig):
|
||||
create_shards(cfg)
|
||||
|
||||
|
||||
ConfigStore.instance().store(name='partial_tar_config', node=PartialASRTarredDatasetConfig)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user