Skip to content

Fused NeMo transcribe diarize actor#43

Merged
everettVT merged 1 commit into
mainfrom
everettVT/clean-up-dakar-models
Jul 10, 2026
Merged

Fused NeMo transcribe diarize actor#43
everettVT merged 1 commit into
mainfrom
everettVT/clean-up-dakar-models

Conversation

@everettVT

Copy link
Copy Markdown
Contributor

Summary

  • Add a fused TranscribeDiarizeVad Daft class that loads Parakeet, MarbleNet VAD, and Sortformer directly in __init__ and runs decode, VAD, ASR, diarization, speaker merge, and VAD stats in one process method.
  • Route the NeMo transcribe/diarize pipeline through that single actor method instead of split stateful UDF calls and removed the old resident-global handoff path.
  • Add word timestamp propagation, MarbleNet VAD configurability, and simplify defaults so model IDs live on class constructors instead of imported constants.
  • Remove explicit singleton batch_size=1 calls from the NeMo ASR/diarization path.

Why

The previous implementation kept model weights resident but still crossed Daft graph/host boundaries between VAD, ASR, and diarization. This PR makes the Daft actor itself the residency boundary and keeps model inference orchestration inside one device-resident class.

Validation

  • uv run --extra models python -m py_compile models/common/speech.py models/common/vad.py models/parakeet/model.py models/sortformer/model.py pipelines/transcribe_diarize/pipeline.py pipelines/transcribe_diarize/modal_app.py pipelines/transcribe_diarize/benchmark.py
  • uv run --extra lint ruff check models/common/speech.py models/common/vad.py models/parakeet/model.py models/sortformer/model.py pipelines/transcribe_diarize/pipeline.py pipelines/transcribe_diarize/modal_app.py pipelines/transcribe_diarize/benchmark.py
  • Modal smoke: MODAL_PROFILE=everett-38139 uv run --extra models modal run pipelines/transcribe_diarize/modal_app.py::measure --source '/audio/flac/Build_Scalable_Batch_Inference_Pipelines_in_3_Lines_Daft_GPT_vLLM_0.00_2.38.flac' --config parakeet+sortformer

Copy link
Copy Markdown
Contributor Author

Performance Results

These are the measurements captured while developing this PR. The smoke result is from the current pushed commit (426ea33); the larger scale artifacts were captured during the same PR work before the final no-globals cleanup, so they are useful as scale evidence but should be rerun if we need final apples-to-apples numbers on the exact PR commit.

Current fused actor smoke

Command:

MODAL_PROFILE=everett-38139 uv run --extra models modal run pipelines/transcribe_diarize/modal_app.py::measure \
  --source '/audio/flac/Build_Scalable_Batch_Inference_Pipelines_in_3_Lines_Daft_GPT_vLLM_0.00_2.38.flac' \
  --config parakeet+sortformer

Result:

  • First service call wall: 31.0s
  • Measured collect wall after warmup: 0.2s
  • Fused actor status: model_residency: TranscribeDiarizeVad.__init__
  • Warm fused process: 0.1704s on the 2.38s clip
  • Warm ASR stage: 0.0819s; warm diarization stage: 0.0565s
  • Output shape: 2 ASR segments, 1 speaker segment

This smoke is mainly a runtime/API validation because the clip is too small for stable throughput conclusions.

2-hour L40S scale run

Artifact: .context/transcribe_diarize/MODE_COMPARE_sports_basement_2h_L40S_linear_vad.json

  • Source: /audio/flac/sports_basement_2h.flac
  • Audio duration: 7200.0s
  • Wall time: 193.934s
  • Throughput: 37.13x realtime
  • Peak VRAM: 11.998 GB

The old linear path did not produce a comparable throughput number:

  • Daft linear comparison failed after 12.01s with Need at least 1 series to perform concat.
  • Direct whole-file compacted ASR diagnostic OOMed on the same 2h input after MarbleNet compaction: 5575.68s model audio, attempted 289.54 GiB allocation on an L40S (44.39 GiB).

Artifact: .context/transcribe_diarize/DIAG_LINEAR_ASR_2H_FULL.json

Real-file processing runs

IMG_3800:

  • Source: /Users/everettkleven/Desktop/IMG_3800.mov
  • Audio duration: 9377.19s (2:36:17)
  • Client wall: 259.35s
  • Throughput: 36.16x realtime
  • ASR segments: 2025
  • Word timestamps: 24967
  • Speaker turns: 1631
  • VAD removed: 974.20s

Artifacts:

  • .context/transcribe_diarize/IMG_3800_transcribe_summary.json
  • .context/transcribe_diarize/IMG_3800_report_summary.json

Zoom batch:

  • Source glob: /audio/flac/zoom_2026-06-*.flac
  • Files: 4
  • Total audio duration: 11616.21s (3:13:36)
  • Client wall: 268.48s
  • Throughput: 43.27x realtime
  • ASR segments: 2785
  • Speaker turns: 2932
  • VAD removed: 3464.03s

Artifact: .context/transcribe_diarize/zoom_marketing_launch_batch_transcribe_summary.json

MarbleNet VAD threshold bench

Artifact: .context/transcribe_diarize/VAD_BENCH_smoke.json

On the 155.64s sample, threshold 0.7 was selected by the current heuristic:

  • Removed: 32.40s (20.82%)
  • WER delta vs no VAD: 0.0445
  • Deletion-WER: 0.0157
  • Reason: largest seconds removed while staying within WER <= 0.050 and deletion-WER <= 0.020

Threshold 0.8 removed slightly more (33.68s) but exceeded the WER tolerance (0.0524).

Profiler smoke

Artifact: .context/transcribe_diarize/transcribe_diarize_profile_smoke_current.summary.txt

  • Self CPU total: 2.130s
  • Self CUDA total: 652.885ms
  • Top CUDA kernel: ampere_sgemm_128x32_tn, 181.528ms (27.80% self CUDA)

@everettVT everettVT changed the title [codex] Fuse NeMo transcribe diarize actor Fused NeMo transcribe diarize actor Jul 7, 2026
@everettVT everettVT marked this pull request as ready for review July 7, 2026 22:00

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 426ea33dc1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread models/parakeet/model.py
if not active:
return []
try:
raw = self.sortformer.diarize(audio=[path for path, _window in active])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve speaker identity across VAD chunks

When MarbleNet produces more than one window for a recording, paths contains separate VAD chunks from that same file, but this submits them to Sortformer as independent audio inputs. Sortformer speaker labels are local to each input, so offsetting timestamps later does not reconcile that speaker_0 in chunk 1 may be a different person than speaker_0 in chunk 2; the default parakeet+sortformer path now uses MarbleNet VAD, so multi-turn/multi-speaker files can get corrupted speaker assignments. Run diarization on the original recording or add a reliable cross-window speaker mapping before merging.

Useful? React with 👍 / 👎.

asr_kwargs=kwargs,
include_vad_stats=True,
)
return df.collect().to_pydict()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Apply VAD bench limit before collecting

When bench_vad --limit is used, this collect() still materializes the entire source, and each threshold does the same before filter_paths narrows the result. For large folders the advertised smoke-test limit still transcribes all audio for the baseline and every threshold, which can make the experiment much slower and more expensive than requested; apply df.limit(limit) inside collect() before calling collect().

Useful? React with 👍 / 👎.

@everettVT everettVT force-pushed the everettVT/clean-up-dakar-models branch from 426ea33 to ace200c Compare July 7, 2026 23:23
@everettVT everettVT force-pushed the everettVT/clean-up-dakar-models branch from ace200c to ca8f335 Compare July 7, 2026 23:35
@everettVT everettVT merged commit e6a400f into main Jul 10, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant