faster-whisper на сервере: частые ошибки и решения
Модель скачалась, скрипт запустился — и падает на libcudnn_ops_infer.so.8, отдаёт пустой список сегментов или вместо речи пишет «Продолжение следует…». Почти все ошибки faster-whisper родом из трёх мест: нативной библиотеки CTranslate2, загрузчика моделей HuggingFace и параметров самого transcribe(). Разберём их по слоям — с дословными текстами и командами проверки.
Содержание
- Три слоя, в которых ломается faster-whisper
- GPU не заводится: cuDNN, cuBLAS и версии CTranslate2
- Модель не скачивается: HuggingFace, кэш и systemd без HOME
- Скрипт отработал, а транскрипта нет
- Галлюцинации и зацикливание: «Продолжение следует…»
- Прод: OOM, OpenMP и параллельные запросы
- Какой сервер под faster-whisper брать в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Три слоя, в которых ломается faster-whisper
faster-whisper — тонкая обёртка на Python. Считает не она: инференс делает нативная библиотека CTranslate2, веса тянутся с HuggingFace Hub, звук декодирует PyAV. Сначала определите слой, где родилась ошибка, и только потом чините: половина времени уходит на подбор параметров transcribe(), когда на деле не подгрузилась библиотека CUDA.
Первым делом снимите версии — они объясняют большинство несовместимостей.
python3 -c "import faster_whisper, ctranslate2; print(faster_whisper.__version__, ctranslate2.__version__)"
python3 -c "import ctranslate2; print('cuda devices:', ctranslate2.get_cuda_device_count())"
python3 -c "import ctranslate2; print(ctranslate2.get_supported_compute_types('cpu'))"
На серверном процессоре последняя команда выдаст набор вида {'int8', 'int8_float32', 'float32'} — float16 там нет и не появится. Дальше ошибка сама говорит, куда идти.
| Что вы видите | Слой | Куда смотреть |
|---|---|---|
Could not load library libcudnn_ops_infer.so.8 | CTranslate2 → CUDA | версия ctranslate2, LD_LIBRARY_PATH |
LocalEntryNotFoundError, We couldn't connect to 'https://huggingface.co' | загрузка весов | сеть, HF_HOME, права на кэш |
ValueError: Invalid model size 'large-v3-turbo' | версия faster-whisper | пакет старше 1.1.0 |
| Пустой список сегментов, ошибок нет | параметры transcribe() | генератор, VAD, язык |
Killed без traceback | ядро ОС | OOM-killer, dmesg |
Отдельная категория — падение на самом import faster_whisper: AttributeError: _ARRAY_API not found рядом с A module that was compiled using NumPy 1.x cannot be run in NumPy 2.x значит, что в venv встал NumPy второй ветки под колесо ctranslate2, собранное под первую — лечится pip install "numpy<2".
GPU не заводится: cuDNN, cuBLAS и версии CTranslate2
Факт, который экономит часы: cuBLAS подгружается при создании модели, а cuDNN — при первом прогоне энкодера. Картина «WhisperModel(...) отработал молча, падение — на первом файле» — это не аудио и не параметры, это несовпадающий cuDNN.
Could not load library libcudnn_ops_infer.so.8. Error: libcudnn_ops_infer.so.8:
cannot open shared object file: No such file or directory
Unable to load any of {libcudnn_cnn.so.9.1.0, libcudnn_cnn.so.9, libcudnn_cnn.so}
Invalid handle. Cannot load symbol cudnnCreateConvolutionDescriptor
Aborted (core dumped)
Первый текст: сборка ждёт cuDNN 8, а его нет — типично после обновления до девятого. Второй: ctranslate2 ждёт cuDNN 9 и не находит библиотеку в путях загрузчика. Aborted (core dumped) — не исключение Python: процесс умирает целиком, try/except его не поймает.
Совместимость жёстко привязана к версии ctranslate2.
Версия ctranslate2 | CUDA | cuDNN |
|---|---|---|
| 4.5.0 и новее | 12 | 9 |
| 4.4.0 | 12 | 8 |
| 3.24.0 | 11 | 8 |
Отсюда три сценария: поставить cuDNN 9, закрепить ctranslate2==4.4.0 под уже стоящий cuDNN 8 или на старом драйвере с CUDA 11 откатиться на ctranslate2==3.24.0. Предсказуемее всего не воевать с системными пакетами, а принести библиотеки колёсами.
pip install nvidia-cublas-cu12 nvidia-cudnn-cu12==9.*
export LD_LIBRARY_PATH=$(python3 -c 'import os, nvidia.cublas.lib, nvidia.cudnn.lib; print(os.path.dirname(nvidia.cublas.lib.__file__) + ":" + os.path.dirname(nvidia.cudnn.lib.__file__))')
Грабля вдогонку: export живёт в вашей сессии и до systemd-юнита не доходит — отсюда классическое «руками работает, сервисом нет». Переменные прописывают в юните.
[Service]
User=whisper
WorkingDirectory=/opt/whisper
Environment=LD_LIBRARY_PATH=/opt/whisper/venv/lib/python3.12/site-packages/nvidia/cublas/lib:/opt/whisper/venv/lib/python3.12/site-packages/nvidia/cudnn/lib
Environment=HF_HOME=/var/lib/whisper/hf
Environment=OMP_NUM_THREADS=4
ExecStart=/opt/whisper/venv/bin/python -m app.server
Ещё два текста того же слоя: CUDA driver version is insufficient for CUDA runtime version — драйвер старее, чем требует CUDA 12, обновлять его, а не пакеты; no CUDA-capable device is detected — карты не видно, в контейнере это забытый --gpus all, на VPS — отсутствие GPU вовсе.
И честное: на сервере без видеокарты device="cuda" не заработает никогда. Рабочий путь на CPU — WhisperModel("medium", device="cpu", compute_type="int8"): медленнее GPU, зато предсказуемо и без стека CUDA целиком.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть WhisperМодель не скачивается: HuggingFace, кэш и systemd без HOME
При первом запуске WhisperModel("large-v3") faster-whisper идёт на HuggingFace Hub за весами в формате CTranslate2 — в репозиторий Systran/faster-whisper-large-v3 — и складывает их в ~/.cache/huggingface/hub. Здесь ломается всё, что связано с сетью, правами и диском:
huggingface_hub.errors.LocalEntryNotFoundErrorилиOSError: We couldn't connect to 'https://huggingface.co' to load this file— до Hub не достучались, а кэш пуст. Это «сети нет», а не «модель битая».429 Client Error: Too Many Requests— анонимные скачивания лимитируются, заведите токен и положите вHF_TOKEN.PermissionError: [Errno 13] Permission denied: '/nonexistent/.cache/huggingface'— сервисный пользователь без домашнего каталога, частый спутникDynamicUser=yes.OSError: [Errno 28] No space left on device— место кончилось посреди загрузки, огрызок остался в кэше.
Приём для сервера — не полагаться на кэш в $HOME, а один раз выкачать модель в явный путь.
export HF_HOME=/var/lib/whisper/hf
python3 - <<'PY'
from huggingface_hub import snapshot_download
print(snapshot_download("Systran/faster-whisper-large-v3"))
PY
ls -lh /var/lib/whisper/hf/hub/models--Systran--faster-whisper-large-v3/snapshots/*/
В снапшоте — model.bin, config.json, tokenizer.json. Не докачался model.bin — CTranslate2 скажет прямо: RuntimeError: Unable to open file 'model.bin' in model '/var/lib/whisper/models/large-v3'.
Дальше в проде передавайте путь, а не алиас: WhisperModel("/var/lib/whisper/models/large-v3", device="cpu", compute_type="int8") плюс Environment=HF_HUB_OFFLINE=1 в юните — сервис перестанет ходить в сеть на каждом старте.
Ещё версионный случай, похожий на загрузочный: RuntimeError: Unsupported model binary version. This executable supports models with binary version v6 or below, but the model has binary version v7 — веса сконвертированы более свежим CTranslate2, чем стоит у вас; лечится pip install -U faster-whisper ctranslate2. Тем же способом чинится и ValueError: Invalid model size 'large-v3-turbo' на пакете старше 1.1.0, где алиаса turbo ещё не было.
Отдельно про доступ из России: huggingface.co отвечает неровно, и «модель не скачивается» часто означает именно это. Зеркало через HF_ENDPOINT работает, но веса — из непроверенного источника, для чужих разговоров внутри размен сомнительный.
Скрипт отработал, а транскрипта нет
Самая обидная категория: ошибок ноль, выход пустой.
Генератор. model.transcribe() ничего не транскрибирует. Он возвращает пару (segments, info), где segments — ленивый генератор, и работа начинается только при итерации. Классика: print(segments) печатает <generator object WhisperModel.generate_segments at 0x7f...>, скрипт завершается за доли секунды.
segments, info = model.transcribe("call.wav", language="ru", vad_filter=True)
print(info.language, info.language_probability, info.duration, info.duration_after_vad)
segments = list(segments) # вот здесь и происходит распознавание
print(len(segments), "".join(s.text for s in segments)[:200])
И он одноразовый: прошлись логированием, потом пошли собирать текст — на втором проходе пусто.
VAD съел запись. Поле info.duration_after_vad — самый быстрый детектор: если duration показывает 620 секунд, а duration_after_vad — 0.4, речь не найдена. Тихая запись, сильный фон, высокий порог.
segments, info = model.transcribe(
"call.wav",
vad_filter=True,
vad_parameters=dict(threshold=0.3, min_silence_duration_ms=500, speech_pad_ms=400),
)
Прогон с vad_filter=False разделяет две разные беды: «модель не слышит» и «VAD не пускает».
Звук не декодировался. faster-whisper читает аудио библиотекой PyAV, а не внешним бинарём — ffmpeg для декодирования не нужен, и его установка «на всякий случай» ничего не чинит. Битый файл даёт av.error.InvalidDataError: [Errno 1094995529] Invalid data found when processing input. Проверка входа до модели:
ls -l call.wav
ffprobe -v error -show_entries stream=codec_name,sample_rate,channels,duration -of default=nw=1 call.wav
Нулевой размер, обрезанный .webm из браузера, .mp3 с текстом HTTP-ошибки внутри — типичный набор. А FileNotFoundError: [Errno 2] No such file or directory: 'call.wav' под systemd — это относительный путь без WorkingDirectory.
Язык определился неправильно. Определение идёт по первым тридцати секундам: гудки, музыка или молчание в начале — и info.language случаен, текст выходит транслитерацией на чужом языке. info.language_probability ниже 0.6 — повод задать language="ru" явно. Проверьте и task: значение translate переводит на английский, что легко принять за поломку.
Телефония. Звонки в 8 кГц ресемплятся до 16 кГц внутри библиотеки, но потерянные частоты не возвращаются — ограничение модели, а не настроек. Стереозапись с разными собеседниками сведётся в моно с перемешанными репликами; разделите каналы заранее.
ffmpeg -i call.wav -filter_complex "channelsplit=channel_layout=stereo[l][r]" \
-map "[l]" -ar 16000 -ac 1 operator.wav -map "[r]" -ar 16000 -ac 1 client.wav
Галлюцинации и зацикливание: «Продолжение следует…»
Модель не молчит на тишине — она договаривает: субтитровые «Продолжение следует...» и «Субтитры сделал DimaTorzok» на русских записях, «Thank you for watching!» на английских, а второй формой той же болезни — фраза, повторённая десятки раз подряд. Причина — авторегрессионный декодер и condition_on_previous_text=True по умолчанию: одна выдумка попадает в контекст следующего окна и усиливает сама себя. Базовую связку vad_filter + condition_on_previous_text=False я разбирал в статье про установку faster-whisper на VPS — здесь то, что за пределами азов.
segments, info = model.transcribe(
"call.wav",
language="ru",
condition_on_previous_text=False,
temperature=[0.0, 0.2, 0.4, 0.6, 0.8, 1.0],
compression_ratio_threshold=2.4,
log_prob_threshold=-1.0,
repetition_penalty=1.1,
no_repeat_ngram_size=3,
)
temperature списком — не «креативность», а лестница пересчёта: окно, не прошедшее пороги compression_ratio_threshold и log_prob_threshold, декодируется заново с более высокой температурой. repetition_penalty и no_repeat_ngram_size штрафуют повтор n-грамм внутри одного окна — а не только между окнами, как condition_on_previous_text.
Отдельно — hallucination_silence_threshold: порог в секундах для вырезания подозрительных кусков, окружённых тишиной. Работает только с word_timestamps=True — без него исключение, а с ним прибавляется время выравнивания.
Постфильтр на своей стороне тоже работает: у сегмента есть no_speech_prob, avg_logprob и compression_ratio.
STOP = {"продолжение следует", "субтитры сделал dimatorzok", "thank you for watching"}
clean = [s for s in segments
if s.no_speech_prob < 0.6
and s.avg_logprob > -1.0
and s.text.strip().lower().strip(".!…") not in STOP]
Честно: галлюцинации у Whisper не лечатся полностью, параметры снижают частоту, а не отменяют явление. initial_prompt с именами и терминами помогает с жаргоном, но длинный промпт сам становится источником выдумок — модель начинает его продолжать.
Прод: OOM, OpenMP и параллельные запросы
Killed без traceback — это не Python, это ядро.
dmesg -T | grep -iE 'killed process|out of memory'
journalctl -k -g oom --since "1 hour ago"
Строка Out of memory: Killed process 8123 (python3) total-vm:9.6g, anon-rss:3.7g закрывает вопрос. Считать нужно от весов — large-v3 в int8 около 1,5 ГБ плюс процесс сверху; расчёт по всем моделям и режимам — в статье сколько RAM нужно для Whisper. Здесь — то, что превращает нехватку памяти в загадочный краш, а не в понятную.
Вот и первый: просите compute_type="float16" на процессоре и получаете в логе
Requested float16 compute type, but the target device or backend do not support
efficient float16 computation. The model weights have been automatically converted
to use the float32 compute type instead.
Модель вместо полутора гигабайт занимает шесть — падение «на ровном месте». На CPU берите int8, на GPU — int8_float16. На GPU своя версия той же беды — RuntimeError: CUDA failed with error out of memory, лечится меньшим batch_size у BatchedInferencePipeline.
Два конфликта потоков. OMP: Error #15: Initializing libiomp5.so, but found libiomp5.so already initialized — CTranslate2 и PyTorch со своими сборками OpenMP в одном окружении; KMP_DUPLICATE_LIB_OK=TRUE глушит симптом, правильнее убрать причину — faster-whisper не требует PyTorch, хватает ctranslate2 и onnxruntime для VAD. Рядом — cpu_threads=0 по умолчанию отдаёт CTranslate2 все ядра, параллельные процессы начинают толкаться за один пул; задавайте cpu_threads явно, значением «ядра ÷ число воркеров» — подробный тюнинг под конкретное число vCPU в статье Whisper медленно распознаёт речь.
Модель — один раз на процесс. Загрузка весов — секунды и гигабайты; создавать WhisperModel в обработчике запроса нельзя, в FastAPI — инстанс в lifespan. И воркеров тоже считайте: uvicorn --workers 4 — это уже четыре копии модели в памяти разом.
Таймауты. Расшифровка часового файла — минуты работы, и синхронный эндпоинт за Nginx закончится строкой upstream timed out (110: Connection timed out) while reading response header from upstream. Правильно — очередь: приняли файл, вернули 202 и task_id, обработали в фоне. Без неё спасают proxy_read_timeout 600s; и client_max_body_size 512m; — без второго получите 413 Request Entity Too Large раньше, чем модель что-то услышит.
Какой сервер под faster-whisper брать в MAATRIX
Всё выше делится на две группы: несовпадение версий и нехватка ресурсов. Первое чинится один раз руками, второе — выбором конфигурации.
Честный минимум: 2 vCPU, 4 ГБ RAM, 40 ГБ NVMe. small или medium в int8, один поток, файлы по очереди. Ограничение прямо: второй запрос встанет в очередь; large-v3 формально влезает — полтора гигабайта весов плюс процесс, — но на двух ядрах час аудио превращается в долгое ожидание, а всплеск памяти кончается тем самым Killed.
Комфортный вариант: 4–8 vCPU, 8–16 ГБ RAM, 80–160 ГБ NVMe. Помещаются large-v3 в int8, очередь на два-три воркера с cpu_threads=4 каждый, кэш моделей (HuggingFace незаметно набирает 5–8 ГБ на две-три штуки) и место под входящие файлы. Восемь гигабайт — запас, из-за которого перестают воспроизводиться и OOM-killer, и молчаливая конвертация во float32. Для near-realtime или сотен часов в сутки этого мало — там свой разговор про GPU, и раздел про cuDNN станет ежедневным; для пакетной расшифровки CPU в int8 надёжнее — меньше частей, нечему разъехаться по версиям.
Локация — UK (Лондон). С лондонского адреса huggingface.co, GitHub и PyPI отвечают штатно — половина раздела «модель не скачивается» просто не случается. Голос — персональные данные, и соседство с GDPR здесь уместнее случайного офшора, а низкий пинг до Европы важен именно при заливке часовых файлов. Для 152-ФЗ и данных внутри РФ — берите RU, модели просто выкачайте заранее.
Установка. Whisper есть в каталоге apps.maatrix.io: при заказе сервера он разворачивается автоматически, вручную ставить ничего не нужно — работает на Ubuntu и Debian. Адрес панели и ключи — в личном кабинете, раздел «Доступ». Оплата — картой российского банка, криптовалютой или токеном MAAT.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть WhisperОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Модель загрузилась без ошибок, а падает на первом файле — почему?
cuBLAS грузится при создании WhisperModel, cuDNN — когда энкодер считает свёртки, то есть на первом сегменте. Ищите Unable to load any of {libcudnn_cnn.so.9...} и сверьте LD_LIBRARY_PATH у сервиса: sudo tr '\0' '\n' < /proc/$(systemctl show -p MainPID --value whisper)/environ | grep LD_LIBRARY_PATH.
transcribe() отработал, ошибок нет, текста тоже нет. Что смотреть первым?
segments — генератор: без list() ничего не посчитано. Дальше info.duration_after_vad — близко к нулю при ненулевом info.duration значит, что речь вырезал VAD.
Нужны ли ffmpeg и PyTorch?
PyTorch не нужен: faster-whisper держится на ctranslate2 и onnxruntime, лишний torch приносит OMP: Error #15. Бинарь ffmpeg тоже не обязателен — декодирует PyAV, — но удобен для подготовки файлов: ресемпл, разделение каналов, нормализация громкости.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.