Curate AudioProcess DataQuality Assessment

Quality Assessment for Audio Data

View as Markdown

Filter audio quality using transcription accuracy metrics, duration analysis, and custom quality measures to ensure high-quality speech datasets for ASR training.

How it Works

Audio quality assessment in NeMo Curator focuses on speech-specific metrics that correlate with training data quality:

  1. Transcription Accuracy: Word Error Rate (WER) and Character Error Rate (CER) between ground truth and ASR predictions
  2. Duration Analysis: Audio length validation and speech rate calculations
  3. Value-based Filtering: Configurable filtering using comparison operators

Quality Metrics

Word Error Rate (WER)

The primary metric for assessing transcription quality:

1from nemo_curator.stages.audio.metrics.get_wer import GetPairwiseWerStage
2
3# Calculate WER for each audio sample
4wer_stage = GetPairwiseWerStage(
5 text_key="text", # Ground truth transcription
6 pred_text_key="pred_text", # ASR prediction
7 wer_key="wer" # Output WER field
8)

WER measures the percentage of words that differ between ground truth and predicted transcriptions:

  • WER = 0%: Perfect transcription match
  • WER = 25%: Good quality (1 in 4 words incorrect)
  • WER = 50%: Moderate quality
  • WER >75%: Poor quality (consider filtering)

Character Error Rate (CER)

More granular accuracy measurement at the character level. The get_cer() function is a utility for calculating CER programmatically::

1from nemo_curator.stages.audio.metrics.get_wer import get_cer
2
3# Calculate CER between two strings (for testing/validation)
4cer_value = get_cer("hello world", "helo world") # Returns 9.09

The WER and CER utilities depend on the editdistance package. These are utility functions typically used within custom stages rather than directly in pipelines.

Speech Rate Metrics

NeMo Curator provides utility functions for analyzing speaking speed and content density. These functions are designed for use in custom processing stages:

1from nemo_curator.stages.audio.metrics.get_wer import get_wordrate, get_charrate
2
3# Calculate words per second
4word_rate = get_wordrate("hello world example", 2.5) # 1.2 words/second
5
6# Calculate characters per second
7char_rate = get_charrate("hello world", 2.0) # 5.5 chars/second

For a complete example of using speech rate metrics in a pipeline, refer to the Duration Filtering guide.

Filtering Strategies

WER-based Filtering

Filter audio samples based on transcription accuracy:

1from nemo_curator.stages.audio.common import PreserveByValueStage
2
3# Keep samples with WER <= 30% (high quality)
4high_quality_filter = PreserveByValueStage(
5 input_value_key="wer",
6 target_value=30.0,
7 operator="le" # less than or equal
8)
9
10# Remove samples with WER >= 80% (very poor quality)
11poor_quality_filter = PreserveByValueStage(
12 input_value_key="wer",
13 target_value=80.0,
14 operator="lt" # less than
15)
16# Preserves only entries with WER < 80%

Duration-based Filtering

Filter by audio length to remove short or long samples:

1from nemo_curator.stages.audio.common import PreserveByValueStage
2
3# Keep samples between 1-30 seconds
4duration_min_filter = PreserveByValueStage(
5 input_value_key="duration",
6 target_value=1.0,
7 operator="ge" # greater than or equal
8)
9
10duration_max_filter = PreserveByValueStage(
11 input_value_key="duration",
12 target_value=30.0,
13 operator="le" # less than or equal
14)

Combined Quality Filtering

1from nemo_curator.pipeline import Pipeline
2from nemo_curator.stages.audio.metrics.get_wer import GetPairwiseWerStage
3from nemo_curator.stages.audio.common import GetAudioDurationStage, PreserveByValueStage
4
5# Create multi-stage quality pipeline
6quality_pipeline = Pipeline(name="audio_quality_assessment")
7
8# Calculate all metrics
9quality_pipeline.add_stage(GetPairwiseWerStage())
10quality_pipeline.add_stage(GetAudioDurationStage(
11 audio_filepath_key="audio_filepath",
12 duration_key="duration"
13))
14
15# Apply filters in sequence
16filters = [
17 PreserveByValueStage("wer", 50.0, "le"), # WER &lt;= 50%
18 PreserveByValueStage("duration", 1.0, "ge"), # Duration &gt;= 1s
19 PreserveByValueStage("duration", 20.0, "le"), # Duration &lt;= 20s
20]
21
22for filter_stage in filters:
23 quality_pipeline.add_stage(filter_stage)

Operator Options

The PreserveByValueStage supports several comparison operators:

OperatorDescriptionExample Use Case
"eq"Equal toExact duration matching
"ne"Not equal toExclude specific values
"lt"Less thanMax thresholds
"le"Less than or equalQuality thresholds
"gt"Greater thanMin thresholds
"ge"Greater than or equalMin requirements

Complete Quality Assessment Pipeline

Here’s a complete working example that demonstrates quality assessment:

1from nemo_curator.pipeline import Pipeline
2from nemo_curator.backends.xenna import XennaExecutor
3from nemo_curator.stages.audio.datasets.fleurs.create_initial_manifest import CreateInitialManifestFleursStage
4from nemo_curator.stages.audio.inference.asr_nemo import InferenceAsrNemoStage
5from nemo_curator.stages.audio.metrics.get_wer import GetPairwiseWerStage
6from nemo_curator.stages.audio.common import GetAudioDurationStage, PreserveByValueStage
7from nemo_curator.stages.audio.io.convert import AudioToDocumentStage
8from nemo_curator.stages.text.io.writer import JsonlWriter
9from nemo_curator.stages.resources import Resources
10
11# Create complete quality assessment pipeline
12pipeline = Pipeline(name="audio_quality_assessment")
13
14# 1. Load data
15pipeline.add_stage(CreateInitialManifestFleursStage(
16 lang="hy_am",
17 split="dev",
18 raw_data_dir="./audio_data"
19).with_(batch_size=4))
20
21# 2. ASR inference
22pipeline.add_stage(InferenceAsrNemoStage(
23 model_name="nvidia/stt_hy_fastconformer_hybrid_large_pc"
24).with_(resources=Resources(gpus=1.0)))
25
26# 3. Calculate quality metrics
27pipeline.add_stage(GetPairwiseWerStage())
28pipeline.add_stage(GetAudioDurationStage(
29 audio_filepath_key="audio_filepath",
30 duration_key="duration"
31))
32
33# 4. Apply quality filters
34pipeline.add_stage(PreserveByValueStage(
35 input_value_key="wer",
36 target_value=75.0,
37 operator="le" # Keep WER &lt;= 75%
38))
39
40pipeline.add_stage(PreserveByValueStage(
41 input_value_key="duration",
42 target_value=1.0,
43 operator="ge" # Keep duration &gt;= 1s
44))
45
46pipeline.add_stage(PreserveByValueStage(
47 input_value_key="duration",
48 target_value=30.0,
49 operator="le" # Keep duration &lt;= 30s
50))
51
52# 5. Export high-quality results
53pipeline.add_stage(AudioToDocumentStage())
54pipeline.add_stage(JsonlWriter(path="./high_quality_audio"))
55
56# Execute pipeline
57executor = XennaExecutor()
58pipeline.run(executor)