Load the diarization waveform with soundfile instead of torchaudio#326
Load the diarization waveform with soundfile instead of torchaudio#326happyarts wants to merge 1 commit into
Conversation
6f17d03 to
24d06f1
Compare
/simplify on PR kaixxx#326 found that data.T.copy() doubled the worker's peak memory (~2x the waveform, ~460 MB extra on 2 h of audio): for mono the (frames, 1) transpose is already contiguous, so .contiguous() is a zero-copy no-op and only copies in the hypothetical multichannel case. Also simplifies the test fixture and marks the torchaudio bit-identity test as a migration-time proof. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
23a15b5 to
8a11850
Compare
/code-review on PR kaixxx#326: the diarization worker now imports soundfile directly, but only the Linux/macOS requirements listed it explicitly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The pyannote worker only ever loads noScribe's own converted audio (16 kHz mono pcm_s16le WAV) and already passes it to the pipeline as an in-memory waveform dict. Reading that file needs no decoding backend, so plain soundfile replaces torchaudio.load here. Why: torchaudio.load is deprecated in favour of torchcodec in the upcoming torchaudio releases, and torchcodec is hard-paired to both the torch version and the installed FFmpeg major. Dropping the call removes the last direct torchaudio use from noScribe's own code, so those version pairings become pyannote's internal concern only. soundfile is added to the two Windows requirements files -- Linux and macOS already list it explicitly. The new test proves the swap is a drop-in: the soundfile-loaded tensor is bit-for-bit identical to what torchaudio.load returned, with no extra waveform-sized copy (zero-copy for mono). Verified with a full diarization run (242 segments, 4 speakers) on real audio. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8a11850 to
36833e3
Compare
/code-review findings 2+3 on PR kaixxx#326: a non-converted input now fails with a message pointing at the conversion contract (audio/convert.py) instead of a bare LibsndfileError, and the loader test skips cleanly on a Python built without tkinter instead of erroring at collection. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Kurzer Kontext zu diesem PR: Der neue Loader ist bit-identisch zu |
|
@happyarts Thank you, that looks interesting. However, I will be away on holidays for a few weeks. I will take a look after my return by the end of August, ok? |
|
Klar, selbstverständlich. Genieße deinen Urlaub. Ich denke, da kommen noch ein paar Sachen von mir. Der große Brocken, die Integration von Voxtral kommt erst noch - den Teste ich noch ausführlich. Das wird spannend, weil auf Mac 10x so schnell und bessere Qualität als Whisper. |
Nun, da bin ich gespannt. Allerdings wäre es gut, vor solchen großen Änderungen die Architektur gemeinsam zu besprechen. Die eigentliche Transkription ist ja jetzt schon im "transcription_worker" gekapselt. Ich könnte mir vorstellen, hier einen alternativen voxtral worker zu erstellen, mit identischer Kommunikationsschnittstelle. So ließe sich das Transkriptionsbackend leicht wechseln. |
|
Hi Kai, selbstverständlich, ein neues Modul sollte in die Architektur passen. Die Voxtral-Geschichte war eigentlich eine schnelle Idee, ist dann aber doch größer und komplexer geworden als gedacht. Ich habe ein paar handoptimierte Modellgewichts-Varianten gebaut und auf HF hochgeladen (alle getestet), die Erkennung von Wortwiederholungen und das saubere Lösen derselben ist echt tricky, ich (genauer: die KI für mich) habe einen Bug im torchaudio gefunden und ich tune das Modul gerade noch in einigen Kleinigkeiten. Damit das sauber ist halte ich den Voxtral-Teil ja zurück, bis die kleinen PRs durch sind. Du kannst schon schauen: https://github.com/happyarts/noScribe/tree/feature/voxtral-engine und gern Wünsche / Vorschläge / Ideen äußern. Zur Beruhigung vorab: Die Integration folgt exakt dem Muster, das du beschreibst. Es gibt einen eigenen voxtral_mp_worker als Subprozess, der das Message-Protokoll des whisper_mp_worker 1:1 spiegelt (log/progress/segment/result) — im Hauptprogramm wählt die Engine-Auswahl nur den Entrypoint, beide laufen durch denselben on_segment-Pfad. Die Kombinationslogik mit den PyAnnote-Segmenten (Pausen, überlappende Sprache etc.) bleibt unangetastet; die Engine liefert lediglich Segmente mit Wort-Timestamps in demselben Format. Markus |
/simplify on PR kaixxx#326 found that data.T.copy() doubled the worker's peak memory (~2x the waveform, ~460 MB extra on 2 h of audio): for mono the (frames, 1) transpose is already contiguous, so .contiguous() is a zero-copy no-op and only copies in the hypothetical multichannel case. Also simplifies the test fixture and marks the torchaudio bit-identity test as a migration-time proof. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
/code-review on PR kaixxx#326: the diarization worker now imports soundfile directly, but only the Linux/macOS requirements listed it explicitly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
/code-review findings 2+3 on PR kaixxx#326: a non-converted input now fails with a message pointing at the conversion contract (audio/convert.py) instead of a bare LibsndfileError, and the loader test skips cleanly on a Python built without tkinter instead of erroring at collection. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
36833e3 to
72fc97f
Compare
/simplify on PR kaixxx#326 found that data.T.copy() doubled the worker's peak memory (~2x the waveform, ~460 MB extra on 2 h of audio): for mono the (frames, 1) transpose is already contiguous, so .contiguous() is a zero-copy no-op and only copies in the hypothetical multichannel case. Also simplifies the test fixture and marks the torchaudio bit-identity test as a migration-time proof. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
/code-review on PR kaixxx#326: the diarization worker now imports soundfile directly, but only the Linux/macOS requirements listed it explicitly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
/code-review findings 2+3 on PR kaixxx#326: a non-converted input now fails with a message pointing at the conversion contract (audio/convert.py) instead of a bare LibsndfileError, and the loader test skips cleanly on a Python built without tkinter instead of erroring at collection. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Alles klar, das hört sich interessant an. Dann schauen wir mal. |
What
The pyannote worker loads the audio for diarization with
torchaudio.loadand passes it to the pipeline as an in-memory waveform dict. This PR replaces that one call withsoundfile— the file at this point is always noScribe's own converted 16 kHz mono PCM WAV, so no decoding backend is needed at all.Since the worker now imports soundfile directly, it is added to the two Windows requirements files; Linux and macOS already list it explicitly.
Why
torchaudio.loadis deprecated: starting with torchaudio 2.9 it delegates to torchcodec, and torchcodec is hard-paired to both the installed torch version and the system FFmpeg major (e.g. torchcodec 0.7 supports FFmpeg 4–7 only, so it fails to load against current Homebrew FFmpeg 8 and prints a scary-looking warning at startup).Scope note
The
torchaudio/torchcodecrequirement pins are deliberately left untouched here: pyannote.audio declares both as hard dependencies, so they stay installed either way. This PR only removes noScribe's direct use, which is what makes a later pin bump (or dropping the explicit pins) a self-contained follow-up.Proof
tests/test_pyannote_waveform_load.py: the soundfile-loaded tensor is bit-for-bit identical (torch.equal, not justallclose) to whattorchaudio.loadreturns for the WAV format noScribe produces.No behavior change intended; the waveform reaching pyannote is byte-identical to before.
🤖 Generated with Claude Code