Halucynacje Whispera: dlaczego powtarza linijki i zmyśla tekst
Halucynacje Whispera wyjaśnione: dlaczego pisze „Thank you for watching” w ciszy lub zapętla linijkę, ile kosztuje każda poprawka i jak znaleźć je w pliku SRT.
Halucynacje Whispera (ang. hallucinations) to tekst, który model zapisuje, choć nikt go nie wypowiedział: „Thank you for watching” w ciszy, podpis autorów napisów albo jedna linijka powtarzana przez minutę. Większości z nich zapobiegają dwa ustawienia — odfiltrowanie dźwięku bez mowy i odcięcie modelu od jego własnego poprzedniego wyniku — a standardowe narzędzia Whisper nie mają włączonego żadnego z nich.
Poniżej: oba rodzaje obok siebie, dlaczego każdy się zdarza, co zmierzyliśmy, gdy jeden z nich dotknął naszej własnej aplikacji, ile kosztuje każda poprawka, ustawienia dla openai-whisper, faster-whisper i whisper.cpp oraz jak znaleźć ocalałe halucynacje w gotowym pliku z napisami.
Halucynacje Whispera obok siebie
| Fantomowa fraza | Pętla powtórzeń | Pominięta mowa | |
|---|---|---|---|
| Co widzisz | „Thank you for watching”, „Thanks for watching”, podpis autorów napisów | Jedna linijka zapisywana raz po raz, często bez interpunkcji | Zdanie brakujące w transkrypcie |
| Gdzie się pojawia | Cisza, muzyka, oklaski, szum pomieszczenia | Wszędzie; gdy się zacznie, trwa dalej | Ciche początki, krótkie wykrzyknienia |
| Co ją powoduje | Dźwięk bez mowy dociera do dekodera | Każde okno jest dekodowane z poprzednim wynikiem jako promptem | To, jak konkretny model radzi sobie z takim dźwiękiem |
| Pierwsza poprawka | Filtr aktywności głosowej (VAD) | Wyłączenie kontekstu poprzedniego tekstu | Spróbuj drugiego modelu na tym samym klipie |
| Jak wygląda w napisach | Dodatkowa linijka w pauzie | Linijka zacięta na jednej frazie albo linijki bez podziałów na zdania | Luka tam, gdzie powinna być linijka |
Trzecia kolumna to błąd odwrotny: mowa, która została pominięta, zamiast tekstu, który został wymyślony. Ma inne przyczyny i inne poprawki, opisane w porównaniu modeli Whisper. Wszystko poniżej dotyczy pierwszych dwóch.
Dlaczego Whisper zapisuje tekst, którego nikt nie powiedział?
Whisper przetwarza dźwięk w 30-sekundowych oknach, a jego dekoder zapisuje tekst dla każdego z nich. Istnieje kontrola braku mowy, ale to tylko próg na prawdopodobieństwie, więc okna z muzyką, oklaskami czy szumem pomieszczenia regularnie ją przechodzą i wychodzą jako słowa. Wybierane słowa zdradzają przyczynę. Whisper wytrenowano na 680 000 godzin dźwięku z internetu sparowanego z transkrypcjami, a formułki pożegnalne i podpisy autorów napisów, częste w tych tekstach, to powszechnie podawane wyjaśnienie tego, co model zapisuje, gdy nie ma nic do transkrypcji.
Te liczby nie są małe. W badaniu z 2025 roku naukowcy z Akademii Górniczo-Hutniczej w Krakowie (AGH) uruchomili large-v3 na dźwięku bez mowy — szumie, muzyce, dźwiękach otoczenia — 301 317 razy. Model zapisał tekst w 40,3% przypadków, a 9,1% tych halucynacji to pętle. Najczęstszymi wynikami były „thank you” (24,76% halucynacji) i „thanks for watching” (10,32%).
Przy prawdziwej mowie odsetek jest znacznie niższy, a szkody poważniejsze. Badanie Careless Whisper z 2024 roku wykazało, że około 1% transkrypcji zawierało całe frazy lub zdania, których nie było w nagraniu, że 38% z nich zawierało jawnie szkodliwe treści, takie jak utrwalanie przemocy, zmyślanie powiązań czy sugerowanie fałszywego autorytetu, oraz że zdarzały się nieproporcjonalnie często u mówców z długimi pauzami.
W napisach koszt jest konkretny. Halucynacja trafia do nich jako idealnie sformatowana linijka w pauzie, a widz czyta ją jak dialog.
Dlaczego jedna zła linijka zamienia się w czterdzieści
Pętla ma inną przyczynę. Domyślnie Whisper dekoduje każde okno z własnym poprzednim wynikiem jako promptem, więc kontekst przechodzi z okna do okna: imiona zachowują jedną pisownię, a zdania mają ciągłość. Ta sama cecha pozwala jednemu złemu oknu zatruć następne. Gdy dekoder zapisze linijkę dwa razy, następne okno dostaje tę linijkę jako prompt i zapisuje ją znowu. Dokumentacja faster-whisper do condition_on_previous_text mówi to wprost: po wyłączeniu model „staje się mniej podatny na utknięcie w pętli błędów, takiej jak zapętlone powtórzenia czy rozjeżdżające się znaczniki czasu”.
Trafiliśmy na to we własnej aplikacji przed wydaniem, więc to zmierzyliśmy: ten sam 101-sekundowy turecki klip, którego użyliśmy w naszym porównaniu modeli, na RTX 3060 Ti z float16, zmieniając tylko tę jedną opcję — czy poprzedni tekst służy jako kontekst.
large-v3, kontekst włączony | large-v3, kontekst wyłączony | medium, kontekst włączony | medium, kontekst wyłączony | |
|---|---|---|---|---|
| Znaki końca zdania w transkrypcie | 0 | 30 | 47 | 30 |
| Powtórzone frazy (6-gramy) | 9 | 0 | 0 | 0 |
Ustawienie domyślne zrujnowało large-v3 i w niczym nie zaszkodziło medium. Przy włączonym kontekście większy model nie zapisał w ogóle interpunkcji kończącej zdania i wytworzył dziewięć powtórzonych fraz; mniejszy, na tym samym nagraniu i z tymi samymi ustawieniami, radził sobie dobrze. W jednym z uruchomień pojedyncza linijka zawierała to, na 0,12 sekundy dźwięku:
[58.26 -> 58.38] bir level oldu bir level oldu bir level oldu bir level oldu
bir level oldu bir level oldu bir level oldu bir level oldu
Brak interpunkcji jest tak samo istotny jak powtórzenia. Narzędzia do napisów dzielą transkrypt na linijki na granicach zdań, a transkrypt bez kropek nie daje im niczego, po czym mogłyby ciąć: powstają gigantyczne linijki albo, przy niedbałym mechanizmie dzielenia, jednowyrazowe. Wyłączenie kontekstu przywróciło interpunkcję bez zmiany modelu.
Jeden klip to nie benchmark. Pokazuje jednak dwie rzeczy: rozmiar modelu nie chroni, a najtańszą poprawką jest ustawienie.
Czy wyłączenie kontekstu poprzedniego tekstu coś kosztuje?
Tak. Każda poprawka na halucynacje ma swój koszt i warto go znać, zanim ją zastosujesz:
- Spójność między oknami. Bez poprzedniego tekstu jako kontekstu pisownia i styl interpunkcji mogą się rozjeżdżać; dokumentacja ostrzega, że wyłączenie tej opcji „może sprawić, że tekst będzie niespójny między oknami”. W praktyce: imię zapisane na dwa sposoby w długim pliku.
- Initial prompt działa tylko w pierwszym oknie. Narzędzia przekazują Whisperowi listę słownictwa — imiona, marki, żargon — jako initial prompt (początkowy prompt), a przy wyłączonym kontekście poprzedniego tekstu wpływa on tylko na pierwsze okno.
--carry_initial_prompt Truew openai-whisper i--carry-initial-promptw whisper.cpp wysyłają go ponownie dla każdego okna; w faster-whisper robi to opcjahotwords. - Kary za powtórzenia usuwają prawdziwe powtórzenia.
repetition_penaltyino_repeat_ngram_sizepotrafią zdusić pętlę, ale nie odróżnią jej od mówcy, który się powtarza. Nasz klip testowy ma dokładnie coś takiego: jedno zdanie powiedziane dwa razy z rzędu, celowo. Kara, która je usuwa, kasuje dialog. - Filtr aktywności głosowej może uciąć cichą mowę. VAD decyduje, co jest mową, zanim Whisper cokolwiek usłyszy, a ciche początki i dźwięk o ograniczonym paśmie, jak rozmowy telefoniczne, to miejsca, w których gubi słowa. AutoSubs dodał we wrześniu 2026 przełącznik, który wyłącza pomijanie ciszy właśnie na taki przypadek.
hallucination_silence_thresholdwymaga znaczników czasu słów i nie jest lekarstwem. Pomija długie fragmenty ciszy wokół podejrzewanej halucynacji. Na naszym klipie nie miał mierzalnego wpływu: linijka, którą podejrzewaliśmy o wymyślenie, okazała się prawdziwą mową.
Żaden z tych kosztów nie dorównuje kosztowi pętli. Źle zapisane imię to jedno „znajdź i zamień”; pętla powtórzeń to fragment, który trzeba transkrybować od nowa.
Jak powstrzymać halucynacje Whispera, narzędzie po narzędziu
| openai-whisper | faster-whisper | whisper.cpp | Sablate | |
|---|---|---|---|---|
| Filtr aktywności głosowej | Brak wbudowanego | vad_filter=True, domyślnie włączony tylko w potoku wsadowym | --vad z modelem Silero | Zawsze włączony |
| Wyłączenie kontekstu poprzedniego tekstu | --condition_on_previous_text False | condition_on_previous_text=False | -mc 0 | Zawsze wyłączony |
| Pomijanie ciszy po podejrzewanej halucynacji | --hallucination_silence_threshold | hallucination_silence_threshold | Brak odpowiednika | Nie |
| Ponowne wysyłanie promptu w każdym oknie | --carry_initial_prompt True | hotwords | --carry-initial-prompt | Nie |
| Możesz zmieniać te ustawienia | Tak | Tak | Tak | Nie |
Ostatnie trzy wiersze to szczerze przyznany słaby punkt Sablate: oba rozwiązania są zawsze włączone, a żadne z tych ustawień nie jest udostępnione. Jeśli chcesz dostroić filtr albo przenosić prompt między oknami, otwarte narzędzia na to pozwalają.
Dla openai-whisper na pliku z wywiadem:
whisper talk.mp4 --model turbo --output_format srt --condition_on_previous_text False
openai-whisper nie ma własnego filtra aktywności głosowej, więc ta komenda naprawia pętlę, ale nie fantomowe frazy; --hallucination_silence_threshold z --word_timestamps True to jego częściowa odpowiedź na nie. whisper.cpp ma obie poprawki, a jego narzędzie wiersza poleceń oczekuje 16-bitowego WAV:
ffmpeg -i talk.mp4 -ar 16000 -ac 1 -c:a pcm_s16le talk.wav
./build/bin/whisper-cli -m models/ggml-large-v3-turbo.bin -f talk.wav -osrt -mc 0 --vad -vm models/ggml-silero-v6.2.0.bin
-mc 0 nie zachowuje kontekstu tekstowego między oknami, a model Silero pochodzi ze skryptu download-vad-model.sh z repozytorium. W Pythonie faster-whisper przyjmuje oba jako argumenty:
from faster_whisper import WhisperModel
model = WhisperModel("large-v3-turbo")
segments, info = model.transcribe("talk.mp4", vad_filter=True, condition_on_previous_text=False)
Jak znaleźć halucynacje w gotowym pliku SRT?
Żadne ustawienie nie usuwa wszystkich halucynacji, więc sprawdź plik. Trzy komendy wyłapują większość ocalałych halucynacji, w systemach macOS i Linux albo w Git Bash i WSL w Windows:
grep -n -i -E "thank(s| you) for watching|amara\.org|subtitles by" talk.srt
awk '{ sub(/\r$/, "") } NF && !/-->/ && !/^[0-9]+$/ { if ($0 == prev) print NR": "$0; prev = $0 }' talk.srt
perl -ne 'print "$.: $_" if /(\S+(?: \S+){1,4}) \1 \1/' talk.srt
Pierwsza znajduje gotowe pożegnania i podpisy autorów napisów. Druga wypisuje każdy wiersz napisów identyczny z poprzednim, tak zwykle wygląda pętla po pocięciu na linijki. Trzecia wyłapuje frazę o długości od dwóch do pięciu słów, powtórzoną trzy razy w jednym wierszu.
Traktuj każde trafienie jako pytanie, a nie wyrok. Ludzie naprawdę mówią „thank you” i naprawdę się powtarzają. Odtwórz linijkę razem z dźwiękiem, a potem zostaw ją albo usuń. Fantomowe linijki w długich pauzach i na muzyce nie pasują do żadnego wzorca; jedyną kontrolą jest przeczytanie linijek wypadających na fragmentach bez mowy.
Kiedy użyć której poprawki
„Robię napisy do wystąpień, wywiadów albo wykładów”. Włącz filtr aktywności głosowej i wyłącz kontekst poprzedniego tekstu. Ta para to rozsądne ustawienie domyślne dla każdej mowy, do której zamierzasz zrobić napisy.
„Nagranie ma długie fragmenty ciszy albo podkład muzyczny”. Tu filtr jest najważniejszy. I tak przeczytaj linijki wypadające na muzyce.
„To rozmowa telefoniczna albo ciche nagranie o ograniczonym paśmie”. Uruchom je raz z filtrem i raz bez, i porównaj, czego brakuje. Filtr, który gubi ciche słowa, jest gorszy niż zabłąkane „thank you”.
„Imiona i nazwy podaję przez initial prompt”. Wyłącz kontekst poprzedniego tekstu i wysyłaj prompt przy każdym oknie za pomocą flag opisanych wyżej albo popraw imiona potem przez „znajdź i zamień”.
„Linijki wciąż się powtarzają mimo obu poprawek”. Spróbuj innego modelu na tym samym pliku, zanim sięgniesz po karę za powtórzenia; nasz klip zapętlił się na large-v3, a na medium nie. Jeśli mimo to potrzebujesz no_repeat_ngram_size, przesłuchaj nagranie pod kątem linijek, które mógł usunąć.
Jak radzi sobie z tym Sablate
W Sablate oba rozwiązania są zawsze włączone: filtr aktywności głosowej przed modelem i brak kontekstu poprzedniego tekstu. Sablate uruchamia Whisper na twoim komputerze, a kontekst wyłączyliśmy po pomiarze opisanym wyżej. Naprawiliśmy też mechanizm dzielenia linijek, który zamieniał transkrypt bez interpunkcji w jednowyrazowe linijki.
Warto znać dwie konsekwencje. Własny słownik w Defaults → Custom vocabulary trafia do Whispera jako initial prompt, więc przy wyłączonym kontekście wpływa tylko na pierwsze okno, mniej więcej pierwsze 30 sekund mowy; imiona i nazwy w dalszej części długiego nagrania to zadanie dla funkcji Find & replace w edytorze, a ta działa na jednym języku naraz. A ponieważ ustawienia są stałe, nie ma czego dostrajać. Jeśli nagranie wymaga wyłączenia filtra, użyj jednego z otwartych narzędzi opisanych wyżej.
W edytorze możesz przechodzić po linijkach przy odtwarzanym wideo, co jest najszybszym sposobem oceny trafień z powyższych komend, a eksport zapisuje poprawione napisy jako .srt, .vtt albo wideo z wypalonymi napisami. Fast i Balanced działają w darmowym planie; Accurate i Best są częścią Pro. Pobierz Sablate na Windows albo Mac i wypróbuj go na własnym materiale.
W skrócie
Whisper halucynuje na dwa sposoby: zapisuje gotowe frazy na dźwięku bez mowy i zapętla się, gdy jedno złe okno karmi następne. Pierwszy problem naprawia filtr aktywności głosowej, drugi — wyłączenie condition_on_previous_text, a standardowe narzędzia nie mają włączonego żadnego z nich. Obie poprawki kosztują niewiele w porównaniu z pętlą. Większy model nie jest bezpieczniejszy. I cokolwiek zmienisz, przeczytaj gotowy plik z napisami, zanim zrobi to ktokolwiek inny — poradnik o robieniu plików SRT zawiera kontrole samego formatu.