Skip to content

Commit 42cd142

Browse files
satraclaude
andauthored
Windowed auditory scene classification with AST (#493)
* Add windowed auditory scene classification with AST model New API: - classify_audios_in_windows(): sliding window classification with configurable window_size/hop_size, returns per-window labels with timestamps. Batched inference for memory efficiency. - scene_results_to_segments(): converts window results to plot_aligned_panels segment format for timeline visualization. Supports any HuggingFace audio-classification model: - MIT/ast-finetuned-audioset-10-10-0.4593 (521 AudioSet classes) - Any other HF audio-classification model Tutorial: auditory_scene_analysis.ipynb — windowed classification, timeline visualization, event filtering. 3 new tests, all pass. Pre-commit clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Refactor: windowed classification as parameters to classify_audios Instead of a separate classify_audios_in_windows(), windowed processing is now activated by passing win_length/hop_length to the existing classify_audios() function: - win_length=None (default): whole-audio classification (unchanged) - win_length=1.0: 1-second windows, hop defaults to win_length/2 - Provenance captured: win_length/hop_length in each result dict - top_k parameter works in both modes This pattern can be adopted by other senselab functions for consistent windowed processing across the library. 4 tests pass (basic, short audio, default hop, segment conversion). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix mypy: add type annotation to model variable in tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix review: per-audio memory-bounded windowed processing - Process one audio at a time instead of collecting all windows into a single list (memory-efficient for long recordings) - Guard against empty labels in scene_results_to_segments - hop_samples already had max(1, ...) guard against infinite loop Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Use Audio.window_generator lazily for memory-efficient windowed classification Instead of materializing all windows into a list, iterate the generator in batches of 32 — only one batch of Audio objects is in memory at a time. Reuses Audio.window_generator() for consistent windowed iteration across senselab (same pattern as quality_control). Tests updated for window_generator behavior (includes partial final window). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix PPG venv: remove unnecessary espnet/snorkel/lightning deps The ppgs package handles its own espnet dependency (pins espnet==202301). We were adding espnet, snorkel, and lightning explicitly which caused conflicts: the 'lightning' package was removed from PyPI, and espnet build failed on sentencepiece. Minimal requirements: ppgs + torch + torchaudio + numpy + soundfile. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix NeMo venv: pin 1.23 + torch<2.5, add pyarrow<18 + matplotlib Root cause: NeMo 2.0 removed SortformerEncLabelModel and pyarrow 24+ removed PyExtensionType. Also NeMo needs matplotlib at import time. - nemo_toolkit==1.23.0 (has SortformerEncLabelModel) - torch>=2.1,<2.5 (NeMo 1.23 not compatible with torch 2.8) - pyarrow<18 (24+ breaking change) - matplotlib (NeMo imports it) The ensure_venv function auto-recreates when requirements change, so stale CI venvs will be refreshed on next run. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Document NeMo lightning package removal, revert to torch 2.8 The `lightning` package was removed from PyPI (April 2026). NeMo depends on it but pytorch-lightning is not a drop-in replacement (NeMo accesses internal `lightning.pytorch._logger`). Reverted to nemo_toolkit[asr] (unversioned) + torch 2.8 + added pyarrow<18 + matplotlib. Existing cached venvs work; new venv creation blocked until NeMo fixes their lightning dependency. Added NOTE comments documenting the issue. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8eeffe6 commit 42cd142

16 files changed

Lines changed: 941 additions & 20 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Specification Quality Checklist: Auditory Scene Analysis
2+
3+
**Purpose**: Validate specification completeness and quality before proceeding to planning
4+
**Created**: 2026-04-29
5+
**Feature**: [spec.md](../spec.md)
6+
7+
## Content Quality
8+
9+
- [x] No implementation details (languages, frameworks, APIs)
10+
- [x] Focused on user value and business needs
11+
- [x] Written for non-technical stakeholders
12+
- [x] All mandatory sections completed
13+
14+
## Requirement Completeness
15+
16+
- [x] No [NEEDS CLARIFICATION] markers remain
17+
- [x] Requirements are testable and unambiguous
18+
- [x] Success criteria are measurable
19+
- [x] Success criteria are technology-agnostic (no implementation details)
20+
- [x] All acceptance scenarios are defined
21+
- [x] Edge cases are identified
22+
- [x] Scope is clearly bounded
23+
- [x] Dependencies and assumptions identified
24+
25+
## Feature Readiness
26+
27+
- [x] All functional requirements have clear acceptance criteria
28+
- [x] User scenarios cover primary flows
29+
- [x] Feature meets measurable outcomes defined in Success Criteria
30+
- [x] No implementation details leak into specification
31+
32+
## Notes
33+
34+
- All items pass. Spec is ready for `/speckit.plan`.
35+
- YAMNet may need subprocess venv if TensorFlow-based; HuggingFace AST models are PyTorch-native alternatives.
36+
- Windowed iteration pattern can reuse Audio chunking or simple tensor slicing.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Implementation Plan: Auditory Scene Analysis
2+
3+
**Branch**: `20260429-201758-auditory-scene-analysis` | **Date**: 2026-04-29 | **Spec**: [spec.md](spec.md)
4+
5+
## Summary
6+
7+
Add windowed audio scene classification using HuggingFace AST (Audio Spectrogram Transformer) and other audio-classification models. Sliding windows with configurable size/hop produce per-window event labels with timestamps. Integrates with existing classification and visualization infrastructure.
8+
9+
## Technical Context
10+
11+
**Language/Version**: Python 3.11-3.12
12+
**Primary Dependencies**: transformers (HuggingFace audio-classification pipeline), existing senselab classification module
13+
**Testing**: pytest + papermill for tutorial
14+
**Target Platform**: CPU (GPU optional), Google Colab
15+
**Project Type**: Library feature + tutorial
16+
**Constraints**: Must work on CPU; window processing must be memory-efficient
17+
18+
## Constitution Check
19+
20+
| Principle | Status | Notes |
21+
|-----------|--------|-------|
22+
| I. UV-Managed Python | PASS | All via uv |
23+
| II. Encapsulated Testing | PASS | pytest in uv venv |
24+
| IV. CI Must Stay Green | PASS | New tests + existing pass |
25+
| VII. Simplicity First | PASS | Reuses existing classification pipeline + plot_aligned_panels |
26+
| VIII. No Hardcoded Parameters | PASS | Window/hop/top_k configurable with defaults |
27+
28+
## Project Structure
29+
30+
```text
31+
src/senselab/audio/tasks/classification/
32+
├── api.py # UPDATED (add classify_audios_in_windows)
33+
├── huggingface.py # UPDATED (windowed iteration support)
34+
└── doc.md # UPDATED (scene classification docs)
35+
36+
tutorials/audio/
37+
└── auditory_scene_analysis.ipynb # NEW
38+
39+
src/tests/audio/tasks/
40+
└── classification_test.py # UPDATED (windowed classification tests)
41+
```
42+
43+
## Implementation Phases
44+
45+
### Phase 1: Windowed Classification API (P1)
46+
47+
1. Add `classify_audios_in_windows()` to `classification/api.py`:
48+
- Accepts: audios, model, window_size, hop_size, top_k, device
49+
- Slices each audio into windows (tensor slicing, not creating new files)
50+
- Creates lightweight Audio objects per window
51+
- Runs existing `classify_audios_with_transformers` in batches
52+
- Returns: List[List[Dict]] — per-audio, per-window results with start/end/labels/scores
53+
2. Test with AST model on sample audio
54+
3. Test with different window/hop configurations
55+
56+
### Phase 2: Multiple Models + Visualization (P2)
57+
58+
1. Test with at least 2 models (AST + another HuggingFace audio-classification model)
59+
2. Create visualization helper or show how to use `plot_aligned_panels` with scene results
60+
3. Update doc.md with supported models
61+
62+
### Phase 3: Tutorial (P2)
63+
64+
1. Create `auditory_scene_analysis.ipynb`:
65+
- Load audio (recording widget + sample)
66+
- Run windowed classification with AST
67+
- Visualize timeline of detected events
68+
- Compare with different models
69+
- Show integration with filtering/segmentation
70+
2. Add to manifest.json
71+
3. Test via papermill
72+
73+
### Phase 4: Polish
74+
75+
1. Pre-commit, tests, CI
76+
2. Push, check comments, merge
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Quickstart: Auditory Scene Analysis
2+
3+
## Run windowed classification
4+
```bash
5+
uv run python -c "
6+
from senselab.audio.data_structures import Audio
7+
from senselab.audio.tasks.classification.api import classify_audios_in_windows
8+
from senselab.utils.data_structures import HFModel
9+
10+
audio = Audio(filepath='tutorial_audio_files/audio_48khz_mono_16bits.wav')
11+
model = HFModel(path_or_uri='MIT/ast-finetuned-audioset-10-10-0.4593')
12+
results = classify_audios_in_windows([audio], model=model, window_size=1.0, hop_size=0.5)
13+
for r in results[0][:5]:
14+
print(f'{r[\"start\"]:.1f}-{r[\"end\"]:.1f}s: {r[\"labels\"][0]} ({r[\"scores\"][0]:.3f})')
15+
"
16+
```
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Research: Auditory Scene Analysis
2+
3+
**Date**: 2026-04-29
4+
5+
## R1: Primary Model Choice
6+
7+
**Decision**: Use HuggingFace Audio Spectrogram Transformer (AST) as the primary model instead of Google's TensorFlow-based YAMNet. Also support YAMNet via TFLite subprocess venv as secondary option.
8+
9+
**Rationale**: AST is natively supported in HuggingFace Transformers (PyTorch), achieves state-of-the-art 0.485 mAP on AudioSet (521 classes), and works with senselab's existing `audio-classification` pipeline. No TensorFlow dependency needed. YAMNet requires TF/TFLite which would conflict with the main PyTorch environment.
10+
11+
**Models to support**:
12+
1. `MIT/ast-finetuned-audioset-10-10-0.4593` — AST fine-tuned on AudioSet (PyTorch, HuggingFace pipeline)
13+
2. `google/yamnet` or `STMicroelectronics/yamnet` — YAMNet via HuggingFace if available, or TFLite subprocess venv
14+
3. Any HuggingFace `audio-classification` model — generic support via existing pipeline
15+
16+
**Alternatives considered**:
17+
- PANNs: Not natively on HuggingFace Transformers; would need custom loading
18+
- BEATs: Available on HuggingFace but fewer pre-trained checkpoints for AudioSet
19+
- CLAP: Good for zero-shot but different use case (text-audio retrieval)
20+
21+
## R2: Windowed Iteration Approach
22+
23+
**Decision**: Implement windowed classification by slicing the audio waveform tensor into overlapping windows, batching them, and running the classifier on each batch. Return results as a list of per-window classification outputs with timestamps.
24+
25+
**Rationale**: Simple tensor slicing is efficient and doesn't require creating separate Audio objects per window. The existing `classify_audios_with_transformers` can process a list of Audio objects, so we create lightweight Audio objects from window slices.
26+
27+
**Parameters**:
28+
- `window_size`: float (seconds), default 1.0
29+
- `hop_size`: float (seconds), default 0.5
30+
- `top_k`: int (number of top predictions per window), default 5
31+
32+
## R3: Output Format
33+
34+
**Decision**: Return `List[Dict]` where each dict has `start`, `end`, `labels`, `scores`. This is compatible with the `segments` panel type in `plot_aligned_panels`.
35+
36+
**Rationale**: The dict format is simple, JSON-serializable, and compatible with existing visualization patterns. It can be easily converted to DataFrames or segment annotations.
37+
38+
## R4: Visualization
39+
40+
**Decision**: Reuse `plot_aligned_panels` with a new panel approach — the "segments" panel type already supports colored bars with labels. For scene classification, we show the top-1 predicted class per window as a colored bar.
41+
42+
**Rationale**: No new plotting code needed — existing infrastructure handles this.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Feature Specification: Auditory Scene Analysis with YAMNet and Windowed Classification
2+
3+
**Feature Branch**: `20260429-201758-auditory-scene-analysis`
4+
**Created**: 2026-04-29
5+
**Status**: Draft
6+
**Input**: Add YAMNet and other related models for auditory scene analysis in iterated form over windows.
7+
8+
## User Scenarios & Testing *(mandatory)*
9+
10+
### User Story 1 - Classify Audio Scenes Over Time Windows (Priority: P1)
11+
12+
A researcher has a long audio recording (e.g., 30 minutes of environmental audio, a clinical interview, or a classroom recording) and wants to understand what sound events occur and when. They run an auditory scene classifier (YAMNet or similar) over sliding windows, producing a timeline of detected sound events — speech, music, laughter, traffic, silence, dog bark, etc. — with timestamps showing when each event occurs and how confident the model is.
13+
14+
**Why this priority**: Windowed audio classification is a fundamental building block for audio understanding. Current senselab classification is whole-file only — no temporal resolution. Windowed analysis is needed for long recordings where the acoustic environment changes over time.
15+
16+
**Independent Test**: Run YAMNet on a 30-second audio sample with 1-second windows, verify output contains per-window classifications with timestamps and confidence scores.
17+
18+
**Acceptance Scenarios**:
19+
20+
1. **Given** a long audio recording, **When** the user runs windowed scene classification, **Then** they receive a list of per-window results, each containing the top predicted sound event(s) with confidence scores and the time interval (start/end in seconds).
21+
2. **Given** a window size and hop size, **When** the user specifies them, **Then** windows are generated accordingly (e.g., 1s windows with 0.5s hop for overlapping analysis).
22+
3. **Given** default parameters, **When** the user runs without specifying window/hop, **Then** reasonable defaults are used (e.g., 1s window, 0.5s hop).
23+
4. **Given** the windowed results, **When** the user visualizes them, **Then** they see a timeline plot showing sound events over time aligned with the audio waveform.
24+
25+
---
26+
27+
### User Story 2 - Use Multiple Audio Scene Models (Priority: P2)
28+
29+
A user wants to compare different audio scene classifiers on the same recording. They can choose from multiple models (YAMNet, AudioSet-based models, PANNs, BEATs, etc.) through the same API, each providing different label sets and granularities. The API abstracts the model-specific details.
30+
31+
**Why this priority**: Different models have different strengths — YAMNet has 521 AudioSet classes, PANNs have fine-grained event detection, BEATs uses self-supervised pre-training. Users need to compare and choose the right model for their domain.
32+
33+
**Independent Test**: Run the same audio through 2 different scene classifiers and verify both return per-window classifications with their respective label sets.
34+
35+
**Acceptance Scenarios**:
36+
37+
1. **Given** an audio file, **When** the user runs the scene classifier with a YAMNet-family model, **Then** they receive predictions from the 521-class AudioSet ontology.
38+
2. **Given** the same audio file, **When** the user runs with a different model (e.g., a PANN or BEATs variant), **Then** they receive predictions from that model's label set.
39+
3. **Given** results from multiple models, **When** displayed together, **Then** the user can compare which events each model detects.
40+
41+
---
42+
43+
### User Story 3 - Integrate Scene Analysis into Quality Control and Pipelines (Priority: P3)
44+
45+
A researcher uses windowed scene classification as part of a larger pipeline — for example, detecting non-speech segments (music, noise) for quality control, or identifying when a speaker transitions from quiet speech to laughter. The per-window results can be used to filter, segment, or annotate audio programmatically.
46+
47+
**Why this priority**: Scene classification becomes most valuable when integrated into workflows — filtering out non-speech regions before ASR, detecting environmental noise for quality assessment, or segmenting recordings by acoustic context.
48+
49+
**Independent Test**: Use windowed classification to identify and extract only speech segments from a mixed audio recording.
50+
51+
**Acceptance Scenarios**:
52+
53+
1. **Given** windowed classification results, **When** the user filters for "Speech" labels above a confidence threshold, **Then** they get time segments containing speech.
54+
2. **Given** windowed results, **When** used as input to another senselab task (e.g., extract only speech segments for ASR), **Then** the integration works seamlessly with senselab's Audio chunking utilities.
55+
56+
---
57+
58+
### Edge Cases
59+
60+
- What happens when the audio is shorter than the window size? (Use the full audio as a single window.)
61+
- What happens when the model returns many low-confidence predictions? (Return top-k results per window, configurable.)
62+
- What happens with very long audio (hours)? (Process in batches; memory-efficient iteration over windows.)
63+
- What happens with multi-channel audio? (Require mono; raise error with guidance to downmix first.)
64+
65+
## Requirements *(mandatory)*
66+
67+
### Functional Requirements
68+
69+
- **FR-001**: The system MUST support windowed audio classification where the user specifies window size (in seconds) and hop size (in seconds), with reasonable defaults (1s window, 0.5s hop).
70+
- **FR-002**: The system MUST support YAMNet (521-class AudioSet ontology) as the primary auditory scene classifier, accessible through senselab's existing classification API or a new dedicated function.
71+
- **FR-003**: The system MUST support at least one additional audio scene model beyond YAMNet (e.g., a PANN, BEATs, or CLAP variant from HuggingFace) to demonstrate model flexibility.
72+
- **FR-004**: Each window's result MUST include: start time (seconds), end time (seconds), top-k predicted labels, and confidence scores.
73+
- **FR-005**: The system MUST provide a visualization function that plots detected sound events over time, aligned with the audio waveform (similar to plot_aligned_panels with a "segments" panel).
74+
- **FR-006**: The windowed classification MUST handle audio of any length efficiently, processing windows in batches rather than loading all windows into memory at once.
75+
- **FR-007**: The system MUST follow established senselab tutorial conventions with a tutorial demonstrating windowed scene analysis on sample audio.
76+
77+
### Key Entities
78+
79+
- **AudioWindow**: A segment of audio with defined start and end time, extracted from a longer recording.
80+
- **SceneClassificationResult**: Per-window classification output containing time interval, predicted labels, and confidence scores.
81+
- **AudioSet Ontology**: The 521-class label hierarchy used by YAMNet and many audio scene classifiers.
82+
83+
## Success Criteria *(mandatory)*
84+
85+
### Measurable Outcomes
86+
87+
- **SC-001**: Windowed classification on a 30-second sample produces at least 30 per-window results (with 1s window, 0.5s hop = ~59 windows).
88+
- **SC-002**: At least 2 different audio scene models are supported and produce results through the same API.
89+
- **SC-003**: The visualization function produces a timeline plot showing detected events aligned with the waveform.
90+
- **SC-004**: Processing a 5-minute audio file completes within 60 seconds on CPU.
91+
- **SC-005**: A tutorial notebook demonstrates windowed scene analysis and passes CI via papermill.
92+
93+
## Assumptions
94+
95+
- YAMNet is available as a TensorFlow/TFLite model or via a HuggingFace-compatible wrapper. If TensorFlow-only, it may need a subprocess venv to avoid TF/PyTorch conflicts.
96+
- HuggingFace has audio-classification models trained on AudioSet that can serve as alternatives to YAMNet (e.g., MIT/ast-finetuned-audioset-10-10-0.4593).
97+
- The windowed iteration uses senselab's existing Audio chunking utilities (chunk_audios) or a simple sliding window over the waveform tensor.
98+
- The output format is compatible with senselab's existing classification API (AudioClassificationResult) extended with time intervals.
99+
- Window size and hop size are specified in seconds and converted to samples internally based on sampling rate.

0 commit comments

Comments
 (0)