Как установить и настроить faster-whisper на VPS
Свой сервер распознавания речи заводят ради приватности и отсутствия платы за минуты, а упираются в обычный VPS без видеокарты, где оригинальный Whisper тянет за собой PyTorch на несколько гигабайт. faster-whisper снимает эту проблему: движок CTranslate2 считает на процессоре и без Torch. Ниже установка по шагам — что ставится, какую модель брать, как настроить compute_type и как превратить скрипт в сервис.
Содержание
- Что ставится вместе с faster-whisper и чего в нём нет
- Установка на VPS: venv, PEP 668 и проверка окружения
- Модели: имена, вес и куда всё скачивается
- Первый запуск на процессоре: compute_type, потоки и генератор
- Настройка качества: VAD, язык и борьба с галлюцинациями
- Из скрипта в сервис: systemd, HTTP-обёртка и Nginx
- Какой сервер под faster-whisper брать в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что ставится вместе с faster-whisper и чего в нём нет
faster-whisper — не обёртка над оригинальным Whisper, а другая реализация той же модели поверх CTranslate2, движка инференса из проекта OpenNMT. Для VPS это главное: PyTorch не нужен вообще. Актуальный релиз — 1.2.1 от 31 октября 2025 года, минимальный Python — 3.9, а зависимостей всего шесть.
| Пакет | Ограничение версии | За что отвечает |
|---|---|---|
ctranslate2 | >=4.0,<5 | движок инференса |
av (PyAV) | >=11 | декодирование аудио |
onnxruntime | >=1.14,<2 | модель Silero VAD |
tokenizers | >=0.13,<1 | токенизатор |
huggingface-hub | >=0.21 | скачивание весов |
tqdm | — | индикатор прогресса |
Свежая сборка движка — ctranslate2 4.8.1 (июль 2026), колёса собраны под тег manylinux_2_28: на Ubuntu 22.04/24.04 и Debian 11/12 встаёт готовый бинарник примерно на 39 МБ, для aarch64 есть своё. Ни torch, ни CUDA-довесков в списке нет — а один PyTorch занимает несколько гигабайт диска.
FFmpeg как программу ставить не нужно — это прямо оговорено в README: аудио декодирует PyAV, которая несёт библиотеки FFmpeg внутри пакета. Консольный ffmpeg всё равно пригодится, чтобы вырезать дорожку из видео, но это инструмент подготовки, а не зависимость.
Ещё про процессор: CPU-бэкенд CTranslate2 рассчитывает на AVX2, и без него загрузка модели обрывается на Illegal instruction (core dumped) без объяснений. Проверка — grep -m1 -o avx2 /proc/cpuinfo.
Установка на VPS: venv, PEP 668 и проверка окружения
Ubuntu 24.04 приезжает с Python 3.12, Debian 12 — с 3.11; хватает обоих.
apt update && apt install -y python3-venv python3-pip
Команда pip install faster-whisper от рута на свежей Ubuntu не сработает — это не поломка, а политика PEP 668:
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install python3-xyz...
Флаг --break-system-packages существует и делает ровно то, что написано в названии. Правильный путь — отдельное окружение под своего пользователя:
useradd -r -m -d /opt/whisper -s /usr/sbin/nologin whisper
sudo -u whisper python3 -m venv /opt/whisper/venv
sudo -u whisper /opt/whisper/venv/bin/pip install --no-cache-dir "faster-whisper==1.2.1"
Версию фиксируем сразу: библиотека разрешает любой ctranslate2 из ветки 4.x, и движок обновится молча при пересборке окружения. --no-cache-dir тоже не для красоты: на машине с 1 ГБ памяти сам pip умеет получить Killed на распаковке колёс, подтверждение в journalctl -k | grep -i oom.
/opt/whisper/venv/bin/pip show faster-whisper | head -3
/opt/whisper/venv/bin/python -c "import ctranslate2; print(ctranslate2.__version__)"
/opt/whisper/venv/bin/python -c "import ctranslate2; print(ctranslate2.get_supported_compute_types('cpu'))"
Третья команда — самая полезная: она говорит, какие типы вычислений реально потянет ваш процессор, и возвращает множество вроде {'int8', 'int8_float32', 'int16', 'float32'}. Обратите внимание, чего в нём нет: float16.
Заодно посмотрите nproc, free -m и df -h / — swap здесь не решение: модель, считающая из подкачки, а не из RAM, замедляется на порядок.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть WhisperМодели: имена, вес и куда всё скачивается
WhisperModel("small") — не путь к файлу, а короткое имя, которое библиотека разворачивает в репозиторий на Hugging Face и качает при первом обращении. Веса лежат в формате CTranslate2, файлы от openai-whisper сюда не подходят.
| Имя модели | Репозиторий | Вес model.bin |
|---|---|---|
tiny | Systran/faster-whisper-tiny | 0,08 ГБ |
base | Systran/faster-whisper-base | 0,15 ГБ |
small | Systran/faster-whisper-small | 0,48 ГБ |
medium | Systran/faster-whisper-medium | 1,53 ГБ |
large-v3 | Systran/faster-whisper-large-v3 | 3,09 ГБ |
turbo | mobiuslabsgmbh/faster-whisper-large-v3-turbo | 1,62 ГБ |
distil-large-v3 | Systran/faster-distil-whisper-large-v3 | 1,51 ГБ |
Опечатка обрывает запуск до всякой сети: ValueError: Invalid model size 'large-v4', expected one of: tiny.en, tiny, base.en, base, small.en, small, .... Полный список выдаёт python -c "from faster_whisper import available_models; print(available_models())".
Две ловушки выбора. Модели с суффиксом .en — только английские, и дистиллированные distil-large-v3 и distil-large-v3.5 тоже. Для русского остаются small, medium, large-v3 и мультиязычный turbo: при вдвое меньшем весе он близок к large-v3 на расшифровке, но хуже переводит.
Скачанное ложится в ~/.cache/huggingface/hub того пользователя, от которого запущен процесс. Отсюда регулярный сюрприз: прогрели модель под рутом, а сервис работает от whisper и качает всё заново к себе. Лечится переменной HF_HOME или аргументом download_root, заданными одинаково везде.
sudo -u whisper HF_HOME=/opt/whisper/hf /opt/whisper/venv/bin/python \
-c "from faster_whisper import download_model; download_model('small')"
du -sh /opt/whisper/hf
Прогрев при развёртывании решает три задачи разом: виден размер кеша, первый запрос не ждёт скачивания, и вы сразу узнаете, если до huggingface.co не достучаться. Дальше ставьте local_files_only=True, чтобы сетевой сбой не превращался в поход в интернет посреди очереди.
Первый запуск на процессоре: compute_type, потоки и генератор
Минимальный рабочий скрипт выглядит так:
from faster_whisper import WhisperModel
model = WhisperModel("small", device="cpu", compute_type="int8", cpu_threads=4)
segments, info = model.transcribe("call.m4a", language="ru", beam_size=5, vad_filter=True)
print(info.language, info.language_probability, info.duration)
for seg in segments:
print(f"[{seg.start:.2f} -> {seg.end:.2f}] {seg.text.strip()}")
Три параметра здесь неочевидны, и на них спотыкается настройка.
compute_type. По умолчанию auto. Но скопируйте пример из README, где для видеокарты указан float16, и на CPU прилетит ValueError: Requested float16 compute type, but the target device or backend do not support efficient float16 computation. На процессоре рабочие варианты — int8 и float32. По качеству на речи разница в пределах шума, по памяти — почти двукратная, поэтому на VPS берут int8: веса лежат в fp16, CTranslate2 квантует их при загрузке.
cpu_threads. Умолчание 0 означает «как решит CTranslate2», а движок берёт четыре потока и учитывает OMP_NUM_THREADS. На виртуалке с двумя vCPU это гарантированная толкотня за ядра: ставьте число ядер явно. Соседний num_workers влияет не на скорость одного файла, а на параллельные вызовы transcribe() из разных потоков, и каждый воркер добавляет свою память.
Генератор. segments — не список: расшифровка стартует только при переборе. Отсюда два следствия: time вокруг вызова transcribe() покажет доли секунды и ничего не значит, а try/except вокруг него не поймает ошибку, которая случится при итерации.
Про скорость честно. Разработчики публикуют в README замер на записи в 13 минут: small в int8 с beam_size=5 — 1 минута 42 секунды и около 1477 МБ памяти, в float32 — 2 минуты 37 секунд и 2257 МБ. Сделано это на десктопном Core i7-12700K в восемь потоков, так что переносить цифру на vCPU нельзя: считайте её верхней границей, а свою снимайте через time.
Настройка качества: VAD, язык и борьба с галлюцинациями
Установка заканчивается работающим скриптом, а полезный результат начинается с настройки. Четыре параметра дают почти весь эффект.
vad_filter=True подключает Silero VAD, который выбрасывает куски без речи; в версии 1.2.1 детектор обновили до шестой версии. Умолчание консервативное — вырезается тишина длиннее двух секунд, для звонков порог стоит ужесточить.
segments, info = model.transcribe(
"call.wav",
language="ru",
vad_filter=True,
vad_parameters=dict(min_silence_duration_ms=500),
condition_on_previous_text=False,
initial_prompt="MAATRIX, VPS, NVMe, тариф, Нью-Йорк",
)
Дело не только в скорости: на тишине и фоновой музыке Whisper склонен выдумывать текст, и вставки вроде «Продолжение следует» видел всякий, кто расшифровывал русские записи.
language="ru" экономит проход определения языка и защищает от классической ошибки: язык определяется по первым тридцати секундам, и запись с англоязычной заставкой уедет в английский целиком. info.language_probability ниже 0,7 — повод посмотреть файл руками.
condition_on_previous_text=False лечит зацикливание: одна фраза повторяется десятки раз, тайм-коды идут дальше, текст стоит на месте. Модель подаёт себе на вход собственный предыдущий вывод и на однообразном аудио сваливается в петлю.
initial_prompt и близкий к нему hotwords подсказывают написание имён и терминов — пара десятков слов заметно уменьшает объём правок.
Тайм-коды для субтитров берутся прямо из сегментов; word_timestamps=True даст разбивку по словам, но за это платят временем обработки.
def ts(t):
h, r = divmod(t, 3600)
m, sec = divmod(r, 60)
return f"{int(h):02}:{int(m):02}:{int(sec):02},{int(sec % 1 * 1000):03}"
with open("out.srt", "w", encoding="utf-8") as f:
for i, seg in enumerate(segments, 1):
f.write(f"{i}\n{ts(seg.start)} --> {ts(seg.end)}\n{seg.text.strip()}\n\n")
Не хочется писать код — поставьте в то же окружение whisper-ctranslate2: whisper-ctranslate2 call.m4a --model small --language ru --compute_type int8 --output_format srt.
Отдельно про пакетный режим. BatchedInferencePipeline с параметром batch_size ускоряет обработку в разы, VAD в нём включён по умолчанию. Плата — память: в тех же замерах README пакет из восьми поднял расход с 1477 МБ до 3608 МБ, на 4 ГБ это прямая дорога к OOM. И помните, чего faster-whisper не делает вовсе: он не разделяет говорящих, для диаризации нужен WhisperX или pyannote.
Из скрипта в сервис: systemd, HTTP-обёртка и Nginx
Загрузка модели занимает секунды и весь свой объём в памяти, поэтому её поднимают один раз при старте, а запросы ставят в очередь: два параллельных распознавания на двух ядрах ничего не ускорят, зато удвоят память.
# /opt/whisper/app.py
import asyncio, os, tempfile
from fastapi import FastAPI, File, Header, HTTPException, UploadFile
from faster_whisper import WhisperModel
MODEL = WhisperModel("small", device="cpu", compute_type="int8", cpu_threads=4)
LOCK = asyncio.Semaphore(1)
TOKEN = os.environ["WHISPER_TOKEN"]
app = FastAPI()
def run(path):
segments, info = MODEL.transcribe(path, language="ru", vad_filter=True)
return info.language, info.duration, " ".join(s.text.strip() for s in segments)
@app.post("/transcribe")
async def transcribe(file: UploadFile = File(...), authorization: str = Header("")):
if authorization != f"Bearer {TOKEN}":
raise HTTPException(401, "bad token")
with tempfile.NamedTemporaryFile(suffix=".audio", delete=False) as tmp:
tmp.write(await file.read())
path = tmp.name
try:
async with LOCK:
lang, dur, text = await asyncio.to_thread(run, path)
finally:
os.unlink(path)
return {"language": lang, "duration": dur, "text": text}
Обратите внимание на функцию run: перебор генератора идёт внутри неё, то есть в рабочем потоке. Вынесете сборку текста наружу — расшифровка выполнится в event loop и заблокирует сервис целиком.
[Unit]
Description=faster-whisper API
After=network-online.target
[Service]
User=whisper
WorkingDirectory=/opt/whisper
Environment=HF_HOME=/opt/whisper/hf
Environment=OMP_NUM_THREADS=4
EnvironmentFile=/etc/whisper/whisper.env
ExecStart=/opt/whisper/venv/bin/uvicorn app:app --host 127.0.0.1 --port 8001
Restart=on-failure
RestartSec=5
TimeoutStartSec=300
[Install]
WantedBy=multi-user.target
TimeoutStartSec=300 здесь не паранойя: если модели нет в кеше, старт займёт столько, сколько качается файл. Наружу сервис выставляют через Nginx, и там два умолчания ломают всё:
location / {
proxy_pass http://127.0.0.1:8001;
client_max_body_size 512m;
proxy_read_timeout 1800s;
proxy_send_timeout 1800s;
}
Без первой строки часовая запись отвалится с 413 Request Entity Too Large — по умолчанию Nginx принимает 1 МБ. Без второй расшифровка оборвётся на шестидесятой секунде: клиент получит 504 Gateway Time-out, а в /var/log/nginx/error.log появится upstream timed out (110: Connection timed out) while reading response header from upstream. Обиднее всего то, что сервер продолжает считать в пустоту, а клиент по таймауту шлёт файл заново. Для длинных записей правильнее возвращать идентификатор задачи и отдавать результат отдельным запросом.
Порт 8001 наружу не выставляем: ufw allow 22/tcp, ufw allow 'Nginx Full' — и всё. Открытый эндпоинт транскрибации — это бесплатный процессор для посторонних, который легко нагрузить одним большим файлом.
Писать своё не обязательно. Есть speaches — сервер с OpenAI-совместимым API поверх faster-whisper и выгрузкой простаивающих моделей. Есть контейнер onerahmet/openai-whisper-asr-webservice: порт 9000, переменные ASR_ENGINE=faster_whisper и ASR_MODEL=small, на выходе srt, vtt и json. Кеш пробрасывайте томом (-v $PWD/cache:/root/.cache/), иначе каждый перезапуск качает веса заново.
Какой сервер под faster-whisper брать в MAATRIX
Нагрузка тут процессорная и рваная: между запросами тишина, во время расшифровки ядра заняты полностью. Диск нужен под веса и временные файлы, сеть — только на приём аудио.
| Сценарий | vCPU | RAM | Диск |
|---|---|---|---|
Разовые файлы, small в int8 | 2 | 4 ГБ | 40 ГБ NVMe |
Регулярный поток, medium или turbo | 4 | 8 ГБ | 80 ГБ NVMe |
large-v3, очередь, пакетный режим | 8 | 16 ГБ | 160 ГБ NVMe |
Честный минимум — 2 vCPU, 4 ГБ RAM, 40 ГБ NVMe. Хватает для small в int8: у разработчиков связка укладывается в полтора гигабайта, остаётся запас на систему и буфер файла. Тариф на 2 ГБ выглядит соблазнительно и работать не будет — модель загрузится, а первый длинный файл принесёт Killed и запись oom-kill в journalctl -k.
Комфортный вариант — 4 vCPU, 8 ГБ RAM, 80 ГБ NVMe. Помещается turbo или medium, включается пакетный режим, очередь перестаёт быть узким местом. CPU-бэкенд CTranslate2 масштабируется по числу физических ядер, так что удвоение vCPU — самый прямой способ ускориться без смены модели.
Про large-v3 скажем прямо: на процессоре это разговор о работоспособности, а не о скорости. В модели 1550 миллионов параметров против 244 миллионов у small, и час записи будет считаться часами. Нужно такое качество на потоке — нужна видеокарта. Расчёт по памяти есть в материале про то, сколько RAM нужно для Whisper по моделям, а просадки скорости — в статье Whisper медленно распознаёт речь.
Локация — Лондон (UK). Причина прикладная: веса едут с huggingface.co, а с российских адресов этот хост отвечает через раз — первый же WhisperModel("small") зависает на скачивании. С британской площадки модели качаются напрямую, плюс низкий пинг до Европы и периметр GDPR для записей переговоров. Расшифровываете звонки российских клиентов под 152-ФЗ — берите Россию и прогревайте кеш заранее, переносом каталога HF_HOME.
Повторять всё это руками не обязательно: Whisper есть в каталоге приложений apps.maatrix.io. Он ставится автоматически при заказе сервера, работает на Ubuntu и Debian, а доступы появляются в личном кабинете, в разделе «Доступ». Оплата картами российских банков, по СБП, криптовалютой или токеном MAAT. Типовые сбои после запуска разобраны отдельно: faster-whisper на сервере: частые ошибки и решения.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть WhisperОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Нужно ли ставить ffmpeg перед установкой faster-whisper?
Для расшифровки нет: аудио декодирует PyAV, которая несёт библиотеки FFmpeg внутри пакета. Консольный ffmpeg полезен для подготовки: ffmpeg -i call.mp4 -vn -ac 1 -ar 16000 -c:a pcm_s16le call.wav.
Первый запуск висит несколько минут и ничего не пишет. Это нормально?
Да, если модели нет в кеше: библиотека молча качает веса, а large-v3 — это 3,09 ГБ. Проверьте du -sh ~/.cache/huggingface/hub. Правильный порядок — прогреть модель при развёртывании через download_model() и задать всем процессам одинаковый HF_HOME.
Как зафиксировать версии, чтобы обновление не сломало сервер?
Пропишите обе строки явно — faster-whisper==1.2.1 и ctranslate2==4.8.1 — в requirements.txt. Библиотека допускает любой ctranslate2 из ветки 4.x, поэтому движок может обновиться при пересборке окружения. Признак несовместимости — RuntimeError: Unsupported model binary version при загрузке модели из старого кеша.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.