راه اندازی Whisper و Piper روی VPS برای تبدیل صوت
با اجرای Whisper و Piper روی سرور شخصی، سیستم STT و TTS ارزان بسازید. این راهنما نحوه راه اندازی endpoint سازگار با OpenAI، میزان مصرف CPU و فضای دیسک تا اوت 2026 را بررسی میکند.
تبدیل گفتار به متن و متن به گفتار به صورت self-hosted، به زبان ساده
سرویسهای self-hosted تبدیل گفتار به متن (STT) و متن به گفتار (TTS)، ارزانترین نوع هوش مصنوعی هستند که میتوانید روی سرور شخصی خود اجرا کنید. برای تبدیل گفتار به متن از Whisper با استفاده از runtime مدل faster-whisper و برای تولید صدا از Piper استفاده میشود. هر دو ابزار روی یک VPS معمولی با CPU و بدون نیاز به GPU کار میکنند. مدل کوچک Whisper به حدود 484 مگابایت فضای دیسک نیاز دارد و هر صدای Piper نیز یک فایل واحد با حجم کمتر از 150 مگابایت است.
به همین دلیل، پردازش صوت بهترین نقطه برای شروع است. تولیدکننده تصویر self-hosted و تولید ویدیو به صورت self-hosted، هر دو پیش از آنکه قابل استفاده باشند به GPU نیاز دارند، اما پردازش صوت نیازی به آن ندارد.
این راهنما هر دو جهت پردازش و لایهای که آنها را به هم متصل میکند، پوشش میدهد. Whisper صوت را به متن تبدیل میکند و Piper متن را به صوت. یک HTTP server سازگار با OpenAI که در مقابل هر دو قرار میگیرد، به کلاینتهای موجود اجازه میدهد بدون هیچ تغییری جز تغییر base URL، به سرور شما متصل شوند.
تمام نسخههای ذکر شده در این راهنما، تا اوت 2026 معتبر بودهاند.
چرا faster-whisper و نه بسته مرجع Whisper
بسته whisper شرکت OpenAI مدل را در PyTorch اجرا میکند. بسته faster-whisper همان وزنهای مدل را روی CTranslate2 اجرا میکند که یک موتور استنتاج است که بهطور اختصاصی برای مدلهای ترنسفورمر نوشته شده است. وزنها یکسان هستند، بنابراین متن خروجی (ترانسکریپت) نیز دقیقاً همان است. تفاوت کاملاً مربوط به زمان اجرا (runtime) است.
موتور CTranslate2 وزنها را هنگام بارگذاری کوانتایز (quantize) میکند، به همین دلیل است که compute_type="int8" یک آرگومان است و نه یک مرحله تبدیل جداگانه. این موتور همچنین هیچ وابستگی به PyTorch ندارد. بسته pip install faster-whisper شامل CTranslate2، یک توکنایزر و PyAV برای دیکد کردن صدا است، بنابراین حجم محیط مجازی (virtual environment) به جای چندین گیگابایت، در حد چند صد مگابایت باقی میماند. روی یک VPS با دیسک 40 گیگابایتی، این تفاوت بین فضای کافی و فضای محدود است.
در اینجا ارقام منتشرشده توسط خود پروژه برای مدل small روی CPU آمده است. این بنچمارک 13 دقیقه صدا را با استفاده از 8 ترد روی یک پردازنده Intel Core i7-12700K پردازش میکند. ستون x_realtime همان 13 دقیقه تقسیم بر زمان اندازهگیری شده است: عدد 7.6 به این معنی است که یک فایل صوتی 13 دقیقهای در کمی بیش از 1 دقیقه و 40 ثانیه به پایان رسیده است.
The data behind this chart
[
{
"label": "openai/whisper, fp32",
"x_realtime": 1.9,
"seconds": 418,
"memory_mb": "2,335"
},
{
"label": "whisper.cpp, fp32",
"x_realtime": 6.2,
"seconds": 125,
"memory_mb": "1,049"
},
{
"label": "faster-whisper, fp32",
"x_realtime": 5.0,
"seconds": 157,
"memory_mb": "2,257"
},
{
"label": "faster-whisper, int8",
"x_realtime": 7.6,
"seconds": 102,
"memory_mb": "1,477"
},
{
"label": "faster-whisper, int8, batch 8",
"x_realtime": 15.3,
"seconds": 51,
"memory_mb": "3,608"
}
]ردیف دوم را با دقت بخوانید. در حالت fp32، بسته whisper.cpp روی این CPU سریعتر از faster-whisper عمل میکند، 6.2 برابر در مقابل 5.0 برابر، و این کار را با کمتر از نصف حافظه انجام میدهد. این همان خانواده ggml است که در بخش llama.cpp از پشته LLM محلی قرار دارد. بسته faster-whisper زمانی که int8 و batching فعال باشند پیش میافتد و به 15.3 برابر میرسد و برای این کار 3,608 مگابایت رم مصرف میکند. بنابراین: برای استفاده از API پایتون و قابلیت batching، بسته faster-whisper را انتخاب کنید؛ زمانی که محدودیت رم دارید و نمیتوانید آن را افزایش دهید، whisper.cpp را انتخاب کنید.
ردیف اول، نکته اصلی این بخش است. بسته مرجع روی همان دستگاه 1.9 برابر زمان واقعی است، که یعنی پردازش یک ساعت صدا، نیم ساعت از زمان CPU را میگیرد.
مدلهای Whisper به چه مقدار فضای دیسک نیاز دارند؟
The data behind this chart
[
{
"label": "tiny",
"weights_mb": 75.5
},
{
"label": "base",
"weights_mb": 145
},
{
"label": "small",
"weights_mb": 484
},
{
"label": "medium",
"weights_mb": "1,530"
},
{
"label": "large-v3",
"weights_mb": "3,090"
}
]این مقادیر مربوط به تبدیلهای CTranslate2 منتشرشده در فرمت float16 هستند. توجه داشته باشید که compute_type="int8" چه کاری انجام نمیدهد: این ابزار حجم فایل دانلودی را کاهش نمیدهد. وزنها در قالب float16 دریافت میشوند و CTranslate2 آنها را در زمان بارگذاری در حافظه به فرمت int8 کوانتایز میکند؛ بنابراین مدل large-v3 چه در حالت float16 اجرا شود و چه در حالت int8، روی دیسک 3,090 مگابایت فضا اشغال میکند. استفاده از int8 باعث صرفهجویی در RAM و افزایش سرعت میشود، نه کاهش فضای دیسک.
مدلها در اولین استفاده در مسیر ~/.cache/huggingface/hub دانلود میشوند. اگر از یک VPS با حجم دیسک root محدود استفاده میکنید، با استفاده از آرگومان download_root یا متغیر محیطی HF_HOME، مسیر ذخیرهسازی را به محلی با فضای کافی تغییر دهید؛ در غیر این صورت، اولین اجرای شما باعث پر شدن دیسک و متوقف شدن فرآیند در حین دانلود خواهد شد.
نصب faster-whisper بدون آسیب به Python سیستم
در Ubuntu 24.04 و Debian 13، پایتون سیستم به عنوان یک محیط مدیریتشده توسط سیستمعامل (externally managed) شناخته میشود. اجرای pip install faster-whisper خارج از یک محیط مجازی (virtual environment) بلافاصله با خطای زیر متوقف میشود:
error: externally-managed-environmentاین مکانیزم بستهبندی برای محافظت از فایلهایی است که apt مالکیت آنها را بر عهده دارد. از یک محیط مجازی استفاده کنید.
sudo apt update
sudo apt install -y python3-venv ffmpeg
python3 -m venv ~/stt
~/stt/bin/pip install --upgrade pip
~/stt/bin/pip install faster-whisper==1.2.1نسخه 1.2.1 آخرین release منتشر شده در اکتبر 2025 است. کتابخانه faster-whisper صدا را از طریق PyAV رمزگشایی میکند که کتابخانههای ffmpeg اختصاصی خود را به همراه دارد؛ بنابراین فایلهای mp3 یا m4a را بدون نیاز به باینری جداگانه ffmpeg میخواند. بسته ffmpeg در بالا، برای پردازشهای ویدیویی در مراحل بعدی این راهنما در نظر گرفته شده است.
پیش از دانلود سه گیگابایت وزنهای مدل (weights)، نصب را بررسی کنید:
~/stt/bin/python -c "from faster_whisper import WhisperModel; print('ok')"مشاهده خطی که شامل ok باشد به این معنی است که بستهها با موفقیت نصب شدهاند. بروز خطای ImportError که نام ctranslate2 را ذکر میکند، به این معناست که بسته (wheel) مربوط به معماری پردازنده شما نصب نشده است؛ این اتفاق معمولاً در ایمیجهای 32-bit ARM رخ میدهد.
رونویسی فایل ضبطشدهٔ جلسه یا یادداشت صوتی
این کد را با نام transcribe.py ذخیره کنید:
from faster_whisper import WhisperModel
model = WhisperModel("small", device="cpu", compute_type="int8", cpu_threads=4)
segments, info = model.transcribe("meeting.m4a", beam_size=5, vad_filter=True)
print("language: %s (%.2f)" % (info.language, info.language_probability))
for segment in segments:
print("[%.2fs -> %.2fs] %s" % (segment.start, segment.end, segment.text))آن را با ~/stt/bin/python transcribe.py اجرا کنید. در اولین اجرا، وزنهای مدل دانلود میشوند، بنابراین مدتی چیزی در خروجی چاپ نمیشود. پس از آن، مدل در چند ثانیه از حافظهٔ کش بارگذاری میشود.
segments یک generator است، بنابراین رونویسی تا زمانی که روی آن iterate نکنید، آغاز نمیشود. برخی افراد زمان اجرای فراخوانی transcribe() را اندازهگیری میکنند، میبینند که بلافاصله برمیگردد و تصور میکنند مشکلی وجود دارد. هیچ مشکلی وجود ندارد. پردازش اصلی در داخل حلقه انجام میشود.
vad_filter=True ابتدا Silero VAD (تشخیص فعالیت صوتی) را اجرا میکند و بخشهای سکوت را پیش از آنکه Whisper آنها را ببیند، حذف میکند. در فایلهای ضبطشدهٔ جلسات که وقفههای طولانی دارند، این بزرگترین بهینهسازی سرعت است، زیرا Whisper هیچ زمانی را صرف پردازش بخشهای بدون گفتار نمیکند. این کار همچنین از تکرار جملات که Whisper هنگام دریافت سکوت و تلاش برای یافتن کلمات در آن تولید میکند، جلوگیری میکند.
مقدار cpu_threads را روی تعداد هستههای واقعی خود تنظیم کنید. تنظیم آن روی عددی بیشتر از تعداد vCPU، سرعت رونویسی را کاهش میدهد، زیرا تردهای اضافی برای استفاده از یک هسته با هم رقابت میکنند و scheduler هزینهٔ هر سوئیچ را پرداخت میکند.
زیرنویس برای کتابخانه Jellyfin
Jellyfin فایلهای زیرنویس خارجی را که در کنار فایل ویدیو قرار دارند و نامی مشابه آن دارند، میخواند. بنابراین Movie (2019).en.srt در کنار Movie (2019).mkv بهعنوان یک ترک انگلیسی بدون نیاز به transcoding و بازسازی کتابخانه نمایش داده میشود.
ابتدا صدا را استخراج کنید. Whisper بهصورت داخلی همه فایلها را به 16 kHz مونو تبدیل میکند، بنابراین ارائه فایل 16 kHz مونو از ابتدا، بار پردازشی را در هر دو سمت کاهش میدهد:
ffmpeg -i "Movie (2019).mkv" -vn -ac 1 -ar 16000 -c:a pcm_s16le "Movie (2019).wav"ابزار faster-whisper قابلیت نوشتن فایل SRT ندارد، بنابراین باید segmentها را خودتان فرمت کنید. این کد را با نام srt.py ذخیره کنید:
import sys
from faster_whisper import WhisperModel
def ts(seconds):
ms = int(round(seconds * 1000))
hours, ms = divmod(ms, 3600000)
minutes, ms = divmod(ms, 60000)
secs, ms = divmod(ms, 1000)
return "%02d:%02d:%02d,%03d" % (hours, minutes, secs, ms)
model = WhisperModel("small", device="cpu", compute_type="int8")
segments, info = model.transcribe(sys.argv[1], vad_filter=True)
with open(sys.argv[2], "w", encoding="utf-8") as out:
for index, segment in enumerate(segments, start=1):
out.write("%d\n" % index)
out.write("%s --> %s\n" % (ts(segment.start), ts(segment.end)))
out.write("%s\n\n" % segment.text.strip())سپس در کتابخانه پیمایش کنید:
for f in /srv/media/films/*.mkv; do
ffmpeg -nostdin -y -i "$f" -vn -ac 1 -ar 16000 -c:a pcm_s16le "${f%.mkv}.wav"
nice -n 15 ~/stt/bin/python srt.py "${f%.mkv}.wav" "${f%.mkv}.en.srt"
rm -f "${f%.mkv}.wav"
doneاستفاده از -nostdin صرفاً برای زیبایی نیست. بدون آن، ffmpeg ورودی استاندارد (stdin) حلقه را میخواند، باقی لیست فایلها را مصرف میکند و حلقه پس از پردازش اولین فیلم بدون هیچ پیام خطایی متوقف میشود.
پیش از شروع، زمان مورد نیاز را تخمین بزنید. با توجه به نرخ 7.6x که در بالا ذکر شد، یک فیلم 100 دقیقهای تقریباً به 13 دقیقه زمان CPU نیاز دارد؛ بنابراین پردازش یک کتابخانه 50 فیلمی یک کار شبانه است. در پلنهای vCPU اشتراکی، سرعت از این هم کمتر خواهد بود؛ این همان دلیلی است که nice برای آن در نظر گرفته شده است: با این کار، پردازش زیرنویس به هر فعالیت دیگری که سرور در حال انجام آن است، اولویت کمتری میدهد.
تبدیل متن به گفتار با Piper
Piper یک موتور عصبی تبدیل متن به گفتار است که مدل صوتی ONNX را روی CPU اجرا میکند. این موتور شامل espeak-ng برای تبدیل متن به واج است، بنابراین نیازی به نصب جداگانه phonemizer نیست. نسخه فعلی 1.6.0 است که در ژوئیه 2026 منتشر شده است.
python3 -m venv ~/tts
~/tts/bin/pip install piper-tts==1.6.0
~/tts/bin/python -m piper.download_voices en_US-lessac-medium
~/tts/bin/python -m piper -m en_US-lessac-medium -f test.wav -- 'This is a test.'download_voices دو فایل را در دایرکتوری کاری مینویسد: وزنهای .onnx و یک فایل پیکربندی .onnx.json که نرخ نمونهبرداری و لیست گویندگان را نگه میدارد. این فایلها باید در کنار هم باقی بمانند. اگر صداها را در مسیر ثابتی نگهداری میکنید، --data-dir را به هر دو دستور پاس دهید، زیرا در غیر این صورت پخشکننده در دایرکتوری کاری جستجو میکند و نمیتواند صدایی که در آنجا نیست را پیدا کند.
استفاده از -- پیش از متن نیز اهمیت دارد. بدون آن، هر جملهای که با خط تیره شروع شود، به عنوان یک گزینه خط فرمان تفسیر میشود.
صداها در سطوح کیفی مختلف عرضه میشوند. یک صدای انگلیسی با کیفیت متوسط حدود 60 MB و یک صدای با کیفیت بالا تقریباً دو برابر آن حجم دارد. کیفیت بالاتر به معنای مدل بزرگتر و مصرف CPU بیشتر در هر ثانیه از گفتار است، نه لزوماً گویندهای متفاوت.
CLI را در یک حلقه فراخوانی نکنید. این برنامه در هر بار اجرا مدل را بارگذاری میکند و بارگذاری مدل، هزینه اصلی برای جملات کوتاه است. به جای آن، سرور HTTP را اجرا کنید:
~/tts/bin/pip install 'piper-tts[http]==1.6.0'
~/tts/bin/python -m piper.http_server -m en_US-lessac-medium --host 127.0.0.1 --port 5000curl -X POST -H 'Content-Type: application/json' \
-d '{ "text": "This is a test." }' \
-o test.wav localhost:5000/synthesizeیک test.wav که بتوانید پخش کنید به این معنی است که سیستم کار میکند. آن endpoint ساختار اختصاصی Piper است، نه OpenAI، بنابراین کلاینتی که انتظار /v1/audio/speech را دارد با آن ارتباط برقرار نخواهد کرد. بخش بعدی این مشکل را حل میکند.
آن را با یک فایل unit به جای ترمینالی که میبندید، در حال اجرا نگه دارید:
[Unit]
Description=Piper text to speech HTTP server
After=network-online.target
[Service]
User=piper
ExecStart=/home/piper/tts/bin/python -m piper.http_server -m en_US-lessac-medium --data-dir /home/piper/voices --host 127.0.0.1 --port 5000
Restart=on-failure
[Install]
WantedBy=multi-user.targetsudo systemctl enable --now piper آن را شروع کرده و پس از reboot دوباره بالا میآورد. اگر دستور curl بالا چیزی برنگرداند، journalctl -u piper -n 50 دلیل آن را نشان میدهد و معمولاً علت آن نبود فایل صوتی است.
ساختار سرور سازگار با OpenAI
بیشتر نرمافزارهایی که صوت را پردازش میکنند، از قبل با API صوتی OpenAI سازگار هستند: یک درخواست multipart POST به /v1/audio/transcriptions برای فایل، و یک JSON POST به /v1/audio/speech برای متن. اگر خودتان این دو مسیر را میزبانی کنید، کلاینت تنها به یک تغییر نیاز دارد: آدرس پایه (base URL).
Speaches سروری است که هر دو جهت را پشتیبانی میکند. این سرور از faster-whisper برای تبدیل گفتار به متن و از Piper یا Kokoro برای تولید گفتار، در پشت مسیرهای OpenAI استفاده میکند. نسخه فعلی v0.9.0-rc.3 است که در دسامبر 2025 منتشر شده و هنوز به 1.0 نرسیده است؛ بنابراین تگ image خود را ثابت (pin) کنید و پیش از ارتقا، یادداشتهای انتشار (release notes) را بخوانید.
curl --silent --remote-name https://raw.githubusercontent.com/speaches-ai/speaches/master/compose.yaml
curl --silent --remote-name https://raw.githubusercontent.com/speaches-ai/speaches/master/compose.cpu.yaml
export COMPOSE_FILE=compose.cpu.yaml
docker compose up --detachشکل تککانتینری، اگر ترجیح میدهید فایلهای compose را نگه ندارید:
docker run --rm --detach --publish 8000:8000 --name speaches \
--volume hf-hub-cache:/home/ubuntu/.cache/huggingface/hub \
ghcr.io/speaches-ai/speaches:latest-cpuvolume نامگذاریشده بخشی است که کاربران فراموش میکنند. بدون آن، کش مدل درون کانتینر باقی میماند و با هر بار راهاندازی مجدد، گیگابایتها وزن (weights) پیش از پاسخ به اولین درخواست، دوباره دانلود میشوند.
سرویس Speech پیش از آنکه /v1/audio/speech پاسخ دهد، به یک صدا (voice) دانلودشده نیاز دارد:
uvx speaches-cli model download speaches-ai/Kokoro-82M-v1.0-ONNXپس از آن، هر کلاینت OpenAI با تغییر آدرس پایه کار میکند:
from pathlib import Path
from openai import OpenAI
openai = OpenAI(base_url="http://localhost:8000/v1", api_key="cant-be-empty")
res = openai.audio.speech.create(
model="speaches-ai/Kokoro-82M-v1.0-ONNX",
voice="af_heart",
input="Hello, world!",
response_format="mp3",
speed=1,
)
with Path("output.mp3").open("wb") as f:
f.write(res.response.read())مقدار جایگیر api_key الزامی است، زیرا کتابخانه کلاینت OpenAI بدون آن از ارسال درخواست خودداری میکند. سرور تا زمانی که یک کلید واقعی پیکربندی نکنید، این مقدار را نادیده میگیرد.
vox-box پروژه دیگری است که ارزش نام بردن دارد. این یک بسته پایتونی است تا یک کانتینر، و همان مسیرها را با استفاده از Whisper، FunASR، Bark، Dia یا CosyVoice ارائه میدهد. نسخه 0.0.21 نسخه فعلی است که در دسامبر 2025 منتشر شده و به پایتون 3.10 یا بالاتر نیاز دارد.
python3 -m venv ~/voice
~/voice/bin/pip install vox-box==0.0.21
~/voice/bin/vox-box start --huggingface-repo-id Systran/faster-whisper-small \
--data-dir ~/voice/data --host 127.0.0.1 --port 8010مثال خود پروژه پورت 80 را bind میکند که نیازمند دسترسی root است. استفاده از یک پورت بالا در پشت یک reverse proxy، ساختار بهتری برای سروری است که کارهای دیگری نیز انجام میدهد. vox-box start تنها یک مدل را میپذیرد، بنابراین پوشش هر دو جهت به معنای اجرای یک نمونه دوم روی پورت دوم با شناسه مخزن صوتی است.
از سرور بپرسید چه چیزی را بارگذاری کرده است، سپس از آن شناسه در فیلد model استفاده کنید:
curl http://127.0.0.1:8010/v1/modelscurl http://127.0.0.1:8010/v1/audio/transcriptions \
-H "Content-Type: multipart/form-data" \
-F file="@voice-note.m4a" \
-F model="faster-whisper-small"یک بدنه JSON به فرم {"text": "..."} به این معنی است که کل مسیر به درستی کار میکند. خطای 404 روی نام مدل به این معنی است که شما به جای خواندن خروجی /v1/models، حدس زدهاید.
هیچکدام از این سرورها بهطور پیشفرض احراز هویت را فعال نمیکنند. آنها را به 127.0.0.1 متصل کنید و از طریق VPN یا یک reverse proxy که درخواست اعتبارنامه میکند، به آنها دسترسی داشته باشید. یک /v1/audio/transcriptions باز روی یک IP عمومی، CPU رایگان برای هر کسی است که آن را پیدا کند، و آنها حتماً آن را پیدا خواهند کرد.
یک رابط کاربری صوتی برای دستیار شخصی
هنگامی که هر دو مسیر در مسیرهای OpenAI پاسخگو باشند، یک رابط کاربری چت میتواند آنها را هدایت کند. Open WebUI و جایگزینهای آن یک base URL سازگار با OpenAI برای صوت در تنظیمات خود میپذیرند، بنابراین یک سیستم میتواند یک LLM محلی را با Ollama اجرا کند و حلقه صوتی را در هر دو انتها ببندد.
تأخیر را صادقانه برآورد کنید، زیرا این سه مرحله یکی پس از دیگری روی همان هستهها اجرا میشوند. یک پرسش 10 ثانیهای حدود 1.3 ثانیه زمان میبرد تا با نرخ 7.6x که در بالا ذکر شد، تبدیل به متن شود و این پیش از آن است که مدل حتی یک توکن را خوانده باشد. تولید توکن توسط CPU را به آن اضافه کنید؛ رفت و برگشت آنقدر کند است که آزمایشکنندگان تصور میکنند سیستم کرش کرده است. تبدیل متن به صورت دستهای (Batch) روی CPU مناسب است. مکالمه اینگونه نیست و این همان نقطهای است که یک VPS دارای GPU ارزش هزینه کردن را پیدا میکند.
چه زمانی استفاده از GPU واقعاً ارزشش را دارد؟
The data behind this chart
[
{
"label": "openai/whisper, fp16",
"x_realtime": 5.5,
"seconds": 143,
"memory_mb": "4,708"
},
{
"label": "faster-whisper, fp16",
"x_realtime": 12.4,
"seconds": 63,
"memory_mb": "4,525"
},
{
"label": "faster-whisper, int8",
"x_realtime": 13.2,
"seconds": 59,
"memory_mb": "2,926"
},
{
"label": "faster-whisper, int8, batch 8",
"x_realtime": 48.8,
"seconds": 16,
"memory_mb": "4,500"
}
]روی GPU، مدل بزرگ با فرمت int8 با سرعت 13.2 برابر زمان واقعی و در فضای 2,926 مگابایت VRAM اجرا میشود و با دستهبندی (batching) این سرعت به 48.8 برابر میرسد. به آنچه در این دو نمودار ذکر نشده است، بهدقت توجه کنید. آنها مدلهای متفاوتی را اجرا میکنند: ردیفهای GPU مربوط به large-v2 و ردیفهای CPU مربوط به مدل small هستند. GPU مدل کوچک را شش برابر سریعتر نمیکند، بلکه مدل دقیق را قابلاستفاده میکند.
این اعداد از کجا آمدهاند
هر دو نمودار، بنچمارک منتشرشده در README پروژه faster-whisper را بازتولید میکنند. فایل صوتی، یک فایل واحد 13 دقیقهای است. ردیفهای CPU از 8 ترد روی پردازنده Intel Core i7-12700K استفاده کردهاند و ردیفهای GPU از CUDA 12.4 روی کارت گرافیک NVIDIA RTX 3070 Ti با 8 گیگابایت VRAM بهره بردهاند. ستونهای ثانیه و حافظه، ارقام منتشرشده هستند. ستون x_realtime حاصل محاسبات ریاضی روی آنهاست: 780 ثانیه صدا تقسیم بر زمان اندازهگیریشده، که به یک رقم اعشار گرد شده است. ستون حافظه برای نمودار CPU نشاندهنده RAM سیستم و برای نمودار GPU نشاندهنده VRAM است.
یک پلن vCPU اشتراکی به ارقام CPU نخواهد رسید. آن بنچمارک از 8 ترد یک پردازنده دسکتاپ قدرتمند بهصورت اختصاصی استفاده کرده است. عدد 7.6 برابر را بهعنوان سقف در نظر بگیرید و پیش از هرگونه برنامهریزی، سیستم خود را با استفاده از time روی یک فایل صوتی واقعی بسنجید.
چهار قاعده کلی که در عمل صادق هستند:
- رونویسی گاهبهگاه از ضبطهای شخصی: CPU، مدل small، فرمت int8. دو vCPU اختصاصی کافی است.
- کارهای دستهای شبانه مانند تولید زیرنویس: CPU، مدل small یا medium، فرمت int8، اجرا شده در
nice. - هر کار تعاملی، یا پردازش یک کتابخانه کامل در یک شب: GPU.
- برای Piper: همیشه CPU. یک مدل صوتی با این ابعاد، تقریباً هیچ بهرهای از GPU نمیبرد.
اگر در حال بررسی این هستید که سختافزار شما چه کارهای دیگری را میتواند پشتیبانی کند، پرسش کلیتر درباره اینکه کدام مدلهای هوش مصنوعی را میتوانید خودمیزبانی کنید، ابعاد مدلهایی که در سختافزار شما جا میشوند یا نمیشوند را پوشش میدهد.
حالتهای شکست و پیامهای مربوطه
error: externally-managed-environment در هنگام نصب. پایتونِ سیستم توسط توزیع لینوکس محافظت میشود. مطابق دستورالعمل بالا، یک محیط مجازی (virtual environment) ایجاد کنید.
عدم تطابق cuDNN در سیستمهای دارای GPU. این خطا به شکل زیر ظاهر میشود:
Unable to load any of {libcudnn_ops.so.9.1.0, libcudnn_ops.so.9.1, libcudnn_ops.so.9, libcudnn_ops.so}
Invalid handle. Cannot load symbol cudnnCreateTensorDescriptorنسخه CTranslate2 4.5.0 و بالاتر برای CUDA 12 به cuDNN 9 نیاز دارند، در حالی که میزبان از cuDNN 8 استفاده میکند. یا cuDNN 9 را نصب کنید، یا نسخه قدیمیتر runtime را با pip install --force-reinstall ctranslate2==4.4.0 ثابت (pin) کنید. یکی از این دو کار را انجام دهید. انجام همزمان هر دو، شما را به نقطه اول بازمیگرداند.
This CTranslate2 package was not compiled with CUDA support خطای متفاوتی است که ظاهری مشابه دارد. پکیجی که نصب شده، نسخه مخصوص CPU است. محیط مجازی را روی میزبان دارای GPU بازسازی کنید تا pip دوباره نسخه مناسب (wheel) را انتخاب کند.
تکرار عبارات در متن خروجی. تکرار یک جمله برای ده بار، تقریباً همیشه به این معناست که سکوت یا موسیقی به اشتباه به عنوان گفتار شناسایی شده است. ابتدا vad_filter=True را فعال کنید. اگر مشکل باقی ماند، به آن بخش از فایل صوتی گوش دهید: صدای نزدیک به سکوت باعث میشود Whisper هیچ نقطه اتکایی برای پردازش نداشته باشد و آخرین حدس مطمئن خود را تکرار کند.
تشخیص اشتباه زبان. Whisper زبان را فقط بر اساس 30 ثانیه اول حدس میزند. مقدار info.language_probability بسیار کمتر از 1.0 به این معناست که سیستم در تشخیص تردید داشته است؛ این اتفاق زمانی رخ میدهد که فایل صوتی با موسیقی یا همصحبتی چند نفر شروع شود. اگر از قبل زبان را میدانید، از language="en" استفاده کنید.
پردازش عبارت Killed را چاپ کرده و متوقف میشود. این پیام نشاندهنده عملکرد OOM-killer (قاتل حافظه) در هسته سیستمعامل است و dmesg خط مربوط به oom-kill را نشان خواهد داد. مدل large-v3 پیش از هرگونه پردازش، به بیش از 3 گیگابایت حافظه فقط برای وزنها نیاز دارد. روی یک VPS با 2 گیگابایت رم، مدل small با فرمت int8 بزرگترین مدلی است که اجرا میشود.
Piper نمیتواند صدا (voice) را پیدا کند. پخشکننده در دایرکتوری جاری جستجو میکند، مگر اینکه --data-dir را تعیین کنید. دستور ls را در دایرکتوری مورد نظر اجرا کنید و مطمئن شوید که .onnx و .onnx.json هر دو موجود هستند؛ زیرا نبود یکی از آنها به اندازه نبود هر دو، باعث شکست عملیات میشود.
FAQ
آیا میتوانم تبدیل گفتار به متن را روی یک VPS بدون GPU اجرا کنم؟
بله، و برای پردازشهای دستهای (batch)، این انتخاب معقولی است. با استفاده از faster-whisper و مدل small در حالت int8، بنچمارک منتشرشده توسط پروژه نشان میدهد که 13 دقیقه صوت در 102 ثانیه روی 8 ترد یک پردازنده دسکتاپ i7 پردازش میشود که حدود 7.6 برابر سرعت واقعی است و 1,477 مگابایت رم مصرف میکند. پلنهای vCPU اشتراکی کندتر از این عمل میکنند، بنابراین عملکرد را روی سرور خودتان بسنجید. تبدیل متن به گفتار با Piper حتی سادهتر است و تحت هیچ شرایطی به GPU نیاز ندارد.
از کدام اندازه مدل Whisper باید استفاده کنم؟
با مدل small در حالت int8 شروع کنید. این مدل 484 مگابایت حجم دارد و گفتار ضبطشده شفاف را بهخوبی پردازش میکند. اگر لهجهها یا نویز پسزمینه باعث خطاهایی شد که قابل چشمپوشی نیستند، به مدل medium بروید و تنها زمانی که دقت از هر چیز دیگری مهمتر است از large-v3 استفاده کنید، زیرا این مدل به 3,090 مگابایت فضای دیسک و بیش از 3 گیگابایت حافظه نیاز دارد. در سمت دیگر، مدل tiny با حجم 75.5 مگابایت برای تشخیص زبان و تست کردن پایپلاین مفید است، نه برای متونی که قرار است توسط انسان خوانده شوند.
چرا faster-whisper سریعتر از بسته اصلی Whisper است؟
مدل یکسان است، اما محیط اجرا (runtime) متفاوت است. بسته مرجع، Whisper را در PyTorch اجرا میکند، در حالی که faster-whisper همان وزنها را روی CTranslate2 اجرا میکند؛ موتوری که برای استنتاج ترنسفورمر ساخته شده، وزنها را در زمان بارگذاری کوانتیزه میکند و نیازی به نصب PyTorch ندارد. در بنچمارک CPU منتشرشده، سرعت بسته مرجع 1.9 برابر سرعت واقعی است، در حالی که faster-whisper در حالت int8 به 7.6 برابر میرسد و حافظه کمتری نیز مصرف میکند.
چرا متن خروجی من یک جمله را مدام تکرار میکند؟
Whisper سکوت یا موسیقی را به عنوان گفتار تفسیر میکند و به آخرین حدس مطمئن خود بازمیگردد. پارامتر vad_filter=True را در فراخوانی transcribe() تنظیم کنید؛ این کار باعث میشود ابتدا تشخیص فعالیت صوتی (VAD) توسط Silero انجام شود و بخشهای ساکت پیش از رسیدن به مدل حذف شوند. اگر همچنان تکرار وجود دارد، سطح صدا را بررسی کنید، زیرا ضبطی که تقریباً در تمام طول خود ساکت است، دادهای برای پردازش به مدل نمیدهد.
چگونه میتوانم یک اندپوینت صوتی سازگار با OpenAI روی سرور خودم داشته باشم؟
سروری را اجرا کنید که POST /v1/audio/transcriptions و POST /v1/audio/speech را پیادهسازی میکند، سپس کلاینت را با یک URL پایه جدید به آن متصل کنید. Speaches یکی از گزینههاست که به صورت ایمیج کانتینر با بیلد CPU منتشر شده و از faster-whisper برای تبدیل گفتار و از Piper یا Kokoro برای تولید گفتار استفاده میکند. vox-box گزینه دیگری است که با pip install vox-box نصب شده و با vox-box start --huggingface-repo-id اجرا میشود و هر مدل را در یک پروسه مجزا سرویسدهی میکند. هیچکدام از اینها بهصورت پیشفرض احراز هویت ندارند، بنابراین آنها را روی localhost بایند کنید و یک پروکسی یا VPN در مقابلشان قرار دهید.