SSD Nodes Learn Hosting plans →
가이드 Matt Connor작성자 Matt Connor

VPS에서 Whisper와 Piper로 STT 및 TTS 자체 호스팅하기

GPU 없이 CPU 기반 VPS에서 faster-whisper와 Piper를 구동하는 방법을 다룹니다. OpenAI 호환 엔드포인트 설정법과 디스크 사용량 및 CPU 리소스 점유율 등 실제 운영에 필요한 구체적인 수치를 확인하고 직접 구축해 보시기 바랍니다.

자체 호스팅 음성 인식(STT) 및 음성 합성(TTS) 개요

자체 호스팅 음성 인식(STT) 및 음성 합성(TTS)은 직접 운영하는 서버에서 실행할 수 있는 가장 저렴한 형태의 AI입니다. 음성 인식은 faster-whisper 런타임을 통해 Whisper를 실행하며, 음성 합성은 Piper를 사용합니다. 두 서비스 모두 GPU가 없는 일반적인 CPU VPS에서 원활하게 작동합니다. 소형 Whisper 모델은 약 484 MB의 디스크 공간을 차지하며, Piper 음성 데이터는 ONNX 모델 파일과 작은 JSON 설정 파일로 구성되어 총 150 MB 미만입니다.

이러한 이유로 오디오 관련 서비스가 시작하기에 가장 적합합니다. 자체 호스팅 이미지 생성기와 자체 호스팅 비디오 생성은 모두 사용 가능한 수준의 성능을 내려면 GPU가 필수적이지만, 오디오 서비스는 그렇지 않습니다.

이 가이드에서는 두 가지 방향의 서비스와 이를 연결하는 계층을 다룹니다. Whisper는 오디오를 텍스트로 변환하고, Piper는 텍스트를 오디오로 변환합니다. 두 서비스 앞에 OpenAI 호환 HTTP 서버를 배치하면, 기존 클라이언트에서 베이스 URL만 변경하여 사용자의 서버를 바로 이용할 수 있습니다.

이 문서의 명령어에 명시된 모든 버전은 2026년 10월 11일 기준으로 각 프로젝트의 릴리스 페이지를 확인한 결과입니다. 실패 모드 항목에서 언급된 CTranslate2 버전은 호환성 확인을 위한 지표이며, 최신 릴리스를 의미하지 않습니다.

왜 reference Whisper 패키지가 아닌 faster-whisper인가

OpenAI의 whisper 패키지는 PyTorch에서 모델을 실행합니다. faster-whisper는 동일한 모델 가중치를 transformer 모델 전용으로 작성된 추론 엔진인 CTranslate2에서 실행합니다. 가중치가 동일하므로 전사 결과도 같습니다. 차이점은 전적으로 런타임에 있습니다.

CTranslate2는 가중치를 로드할 때 양자화하므로 compute_type="int8"은 별도의 변환 단계가 아닌 하나의 인자로 처리됩니다. 또한 PyTorch 의존성이 없습니다. pip install faster-whisper는 CTranslate2, 토크나이저, 오디오 디코딩을 위한 PyAV를 가져오므로 가상 환경의 크기가 수 기가바이트가 아닌 수백 메가바이트 수준으로 유지됩니다. 40 GB 디스크를 사용하는 VPS 환경에서 이 차이는 여유로운 공간과 부족한 공간을 가르는 기준이 됩니다.

다음은 small 모델에 대해 CPU 환경에서 프로젝트가 직접 공개한 수치입니다. 이 벤치마크는 Intel Core i7-12700K에서 8개의 스레드를 사용하여 13분 분량의 오디오를 전사합니다. x_realtime 열은 13분을 측정된 시간으로 나눈 값입니다. 예를 들어 7.6은 13분짜리 녹음 파일을 1분 40초 남짓 만에 완료했음을 의미합니다.

차트Whisper small on CPU, 13 minutes of audio (published project figures)
이 차트의 데이터
[
  {
    "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.2x 대 5.0x의 성능을 보이고 메모리는 절반 이하로 사용합니다. 이는 로컬 LLM 스택의 llama.cpp와 동일한 ggml 계열입니다. faster-whisper는 int8과 배치 처리를 활성화하면 15.3x까지 속도가 올라가며, 이때 3,608 MB의 RAM을 사용합니다. 따라서 Python API와 배치 처리가 필요하다면 faster-whisper를 선택하고, RAM 제약이 절대적이라면 whisper.cpp를 선택하십시오.

첫 번째 행이 이 섹션의 핵심입니다. reference 패키지는 동일한 머신에서 1.9x 실시간 성능을 보이는데, 이는 1시간 분량의 오디오를 처리하는 데 30분의 CPU 시간이 소요됨을 의미합니다.

Whisper 모델 가중치는 어느 정도의 디스크 공간을 요구합니까?

차트faster-whisper model weights on disk (Systran CTranslate2 conversions, float16)
이 차트의 데이터
[
  {
    "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가 로드 시점에 메모리 내에서 양자화를 수행합니다. 따라서 large-v3 모델은 float16으로 실행하든 int8로 실행하든 디스크에서 3,090 MB의 공간을 차지합니다. int8은 RAM 사용량과 속도를 개선할 뿐, 디스크 공간을 절약해주지는 않습니다.

모델은 최초 사용 시 ~/.cache/huggingface/hub 경로로 다운로드됩니다. 루트 볼륨이 작은 VPS를 사용하는 경우, download_root 인수나 HF_HOME 환경 변수를 사용하여 충분한 공간이 있는 경로를 지정하십시오. 그렇지 않으면 첫 실행 시 디스크가 가득 차서 다운로드 도중 프로세스가 종료될 수 있습니다.

시스템 Python을 손상하지 않고 faster-whisper 설치하기

Ubuntu 24.04와 Debian 13은 시스템 Python을 외부에서 관리되는 환경으로 지정합니다. 가상 환경 외부에서 pip install faster-whisper를 실행하면 즉시 다음 오류가 발생하며 중단됩니다.

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은 2025년 10월에 배포된 최신 릴리스입니다. faster-whisper는 자체 ffmpeg 라이브러리를 포함하는 PyAV를 통해 오디오를 디코딩하므로, 별도의 ffmpeg 바이너리 없이도 mp3나 m4a 파일을 읽을 수 있습니다. 위의 ffmpeg 패키지는 이 가이드 뒷부분에서 다룰 비디오 작업을 위한 것입니다.

3GB에 달하는 가중치 파일을 다운로드하기 전에 설치 상태를 확인하십시오.

~/stt/bin/python -c "from faster_whisper import WhisperModel; print('ok')"

ok이라는 줄이 출력되면 설치가 성공한 것입니다. ctranslate2를 언급하는 ImportError 오류가 발생하면 런타임이 없거나 컴파일된 라이브러리를 로드할 수 없는 상태이며, 메시지 뒷부분에 구체적인 원인이 나타납니다. 32비트 ARM 이미지에는 CTranslate2 휠이 존재하지 않으므로, 이 경우 pip 설치 단계에서 실패하게 됩니다.

회의 녹음이나 음성 메모 전사하기

이 내용을 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는 제너레이터이므로 반복문을 돌기 전까지는 전사가 시작되지 않습니다. transcribe() 호출이 즉시 반환되는 것을 보고 무언가 고장 났다고 생각하는 경우가 많지만, 고장 난 것이 아닙니다. 실제 작업은 루프 안에서 수행됩니다.

vad_filter=True은 Silero VAD(음성 활동 감지)를 먼저 실행하여 Whisper가 처리하기 전에 무음 구간을 제거합니다. 긴 공백이 포함된 회의 녹음의 경우, Whisper가 음성이 없는 오디오에 시간을 낭비하지 않으므로 가장 큰 속도 향상을 얻을 수 있습니다. 또한 Whisper가 무음 구간에서 단어를 찾으려 할 때 발생하는 문장 반복 루프 현상도 억제합니다.

cpu_threads는 실제 보유한 코어 수로 설정하십시오. vCPU 개수보다 높게 설정하면 추가 스레드가 동일한 코어를 두고 경쟁하며 스케줄러가 컨텍스트 스위칭 비용을 지불하게 되어 전사 속도가 오히려 느려집니다.

Jellyfin 라이브러리의 자막

Jellyfin은 비디오 파일과 같은 경로에 있고 파일명이 동일한 외부 자막 파일을 읽어 들입니다. 따라서 Movie (2019).en.srt 옆에 Movie (2019).mkv을 두면 라이브러리를 다시 빌드하지 않아도 영어 자막 트랙으로 나타납니다. 특정 클라이언트가 이를 직접 재생할지, 서버가 리먹싱(remuxing)을 수행할지, 혹은 비디오에 자막을 입힐(burn-in)지는 해당 클라이언트의 지원 여부에 따라 결정됩니다.

먼저 오디오를 추출합니다. 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 작성 기능이 없으므로 세그먼트를 직접 포맷해야 합니다. 이 내용을 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가 루프의 표준 입력(standard input)으로부터 데이터를 읽어 들여 나머지 파일 목록을 모두 삼켜버리며, 루프는 오류 메시지 없이 영화 한 편만 처리하고 종료됩니다.

시작하기 전에 소요 시간을 계산하십시오. 위에서 언급한 7.6x 속도를 기준으로 100분짜리 영화는 약 13분의 CPU 시간이 필요하므로, 영화 50편 분량의 라이브러리는 하룻밤이 걸리는 작업입니다. 공유 vCPU 플랜에서는 이보다 더 느리게 작동하며, 이때 nice이 필요합니다. 이 옵션을 사용하면 자막 생성 작업이 서버에서 실행 중인 다른 작업에 자원을 양보하게 됩니다.

Piper를 이용한 텍스트 음성 변환(TTS)

Piper는 CPU에서 ONNX 음성 모델을 구동하는 신경망 기반 텍스트 음성 변환 엔진입니다. espeak-ng를 내장하여 텍스트를 음소로 변환하므로 별도의 음소 변환기를 설치할 필요가 없습니다. 현재 릴리스는 2026년 9월에 발표된 1.8.0 버전입니다.

python3 -m venv ~/tts
~/tts/bin/pip install piper-tts==1.8.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.8.0'
~/tts/bin/python -m piper.http_server -m en_US-lessac-medium --host 127.0.0.1 --port 5000
curl -X POST -H 'Content-Type: application/json' \
  -d '{ "text": "This is a test." }' \
  -o test.wav localhost:5000/synthesize

test.wav을 재생할 수 있다면 정상적으로 작동하는 것입니다. 해당 엔드포인트는 OpenAI 형식이 아닌 Piper 고유의 형식이므로, /v1/audio/speech을 기대하는 클라이언트는 통신할 수 없습니다. 다음 섹션에서 이를 해결합니다.

터미널을 닫아도 서비스가 유지되도록 유닛 파일을 사용하십시오. 유닛은 Piper를 로그인할 수 없는 piper 사용자로, 해당 사용자의 홈 디렉터리에서 실행하므로 서비스가 귀하의 계정에 의존하지 않습니다. 사용자를 생성하고 해당 위치에 Piper와 음성 파일을 설치하십시오.

sudo useradd --system --create-home --home-dir /home/piper --shell /usr/sbin/nologin piper
sudo -u piper python3 -m venv /home/piper/tts
sudo -u piper /home/piper/tts/bin/pip install 'piper-tts[http]==1.8.0'
sudo -u piper /home/piper/tts/bin/python -m piper.download_voices --data-dir /home/piper/voices en_US-lessac-medium

터미널에서 실행 중인 서버를 중단한 뒤 유닛 파일을 작성하십시오.

[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.target

sudo systemctl enable --now piper로 서비스를 시작하고 재부팅 후에도 자동으로 실행되도록 설정하십시오. 위에서 실행한 curl 명령이 아무런 응답을 반환하지 않는다면 journalctl -u piper -n 50에서 원인을 확인할 수 있으며, 보통 음성 파일이 누락된 경우가 많습니다.

OpenAI 호환 서버 구성

오디오를 처리하는 대부분의 소프트웨어는 이미 OpenAI 오디오 API를 지원합니다. 파일 처리를 위해 /v1/audio/transcriptions로 multipart POST 요청을 보내고, 문장 처리를 위해 /v1/audio/speech로 JSON POST 요청을 보냅니다. 이 두 경로를 직접 서비스하면 클라이언트는 기본 URL만 변경하면 됩니다.

Speaches는 양방향 처리를 모두 지원하는 서버입니다. 이 서버는 OpenAI 경로 뒤에서 전사(transcription)를 위해 faster-whisper를, 음성 합성을 위해 Piper나 Kokoro를 실행합니다. 현재 릴리스는 2025년 12월에 나온 v0.9.0-rc.3이며, 아직 1.0 버전 이전이므로 이미지 태그를 고정하고 업그레이드 전 릴리스 노트를 확인하십시오.

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-cpu

명명된 볼륨(named volume)은 사용자가 자주 누락하는 부분입니다. 볼륨이 없으면 모델 캐시가 컨테이너 내부에 저장되므로, 재시작할 때마다 첫 번째 요청에 응답하기 전에 수 기가바이트의 가중치 파일을 다시 다운로드하게 됩니다.

Speech는 /v1/audio/speech이 응답하기 전에 음성 데이터가 먼저 다운로드되어야 합니다:

uvx speaches-cli model download speaches-ai/Kokoro-82M-v1.0-ONNX

그 후에는 기본 URL만 변경하면 모든 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는 여기서 언급할 가치가 있는 또 다른 프로젝트입니다. 이 프로젝트는 컨테이너가 아닌 Python 패키지 형태이며, Whisper, FunASR, Bark, Dia 또는 CosyVoice를 사용하여 동일한 경로를 서비스합니다. 2025년 12월 기준 최신 버전은 0.0.21이며, Python 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번 포트를 바인딩하는데, 이를 위해서는 root 권한이나 CAP_NET_BIND_SERVICE 기능이 필요합니다. 다른 작업을 수행하는 서버라면 리버스 프록시 뒤에서 높은 포트를 사용하는 것이 더 나은 구성입니다. vox-box start은 하나의 모델만 처리하므로, 양방향을 모두 지원하려면 음성 저장소 ID를 사용하여 두 번째 포트에서 두 번째 인스턴스를 실행해야 합니다.

서버에 로드된 모델을 확인한 다음, 해당 ID를 model 필드에 사용하십시오:

curl http://127.0.0.1:8010/v1/models
curl 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"

{"text": "..."} 형태의 JSON 본문이 반환되면 전체 경로가 정상 작동하는 것입니다. 모델 이름에서 404 오류가 발생한다면 /v1/models 출력을 확인하지 않고 추측했다는 의미입니다.

이 서버들은 기본적으로 인증이 활성화되어 있지 않습니다. 127.0.0.1에 바인딩하고 VPN이나 자격 증명을 요구하는 리버스 프록시를 통해 접근하십시오. 공인 IP에서 /v1/audio/transcriptions을 열어두면 누구나 CPU 자원을 무단으로 사용할 수 있으며, 공격자는 반드시 이를 찾아낼 것입니다.

셀프 호스팅 어시스턴트를 위한 음성 프론트엔드

두 방향 모두 OpenAI 경로에서 응답이 확인되면, 채팅 프론트엔드를 통해 이를 구동할 수 있습니다. Open WebUI 및 대안들은 설정에서 오디오를 위한 OpenAI 호환 베이스 URL을 입력받으므로, 하나의 박스에서 Ollama로 로컬 LLM을 실행하고 양쪽 끝에서 음성 루프를 완성할 수 있습니다.

이 세 단계가 동일한 코어에서 순차적으로 실행되므로 지연 시간을 현실적으로 계산해야 합니다. 10초 분량의 질문을 위에서 언급한 7.6x 속도로 변환하는 데 약 1.3초가 소요되며, 이는 모델이 토큰을 하나도 읽기 전의 시간입니다. 여기에 CPU 토큰 생성 시간을 더하면 왕복 시간이 너무 길어져 테스트 사용자는 시스템이 멈췄다고 판단하게 됩니다. 배치 방식의 전사는 CPU에서도 무리가 없지만, 대화형 서비스는 그렇지 않습니다. 바로 이 지점에서 GPU가 탑재된 VPS가 비용 값을 하기 시작합니다.

GPU가 실제로 가치 있는 경우는 언제입니까?

차트Whisper large-v2 on an RTX 3070 Ti, 13 minutes of audio (published project figures)
이 차트의 데이터
[
  {
    "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로 양자화된 대형 모델은 2,926 MB의 VRAM을 사용하여 13.2배 실시간 속도로 실행되며, 배치 처리를 적용하면 48.8배까지 빨라집니다. 두 차트에서 언급하지 않는 내용을 주의 깊게 확인하십시오. 두 차트는 서로 다른 모델을 사용합니다. GPU 행은 large-v2 모델을, CPU 행은 small 모델을 기준으로 합니다. GPU가 small 모델을 6배 더 빠르게 만드는 것이 아닙니다. GPU는 정확도가 높은 모델을 실무에서 사용할 수 있게 만들어 줍니다.

이 수치의 출처

두 차트 모두 faster-whisper README에 게시된 벤치마크를 재현한 것입니다. 오디오는 13분짜리 단일 파일입니다. CPU 행은 Intel Core i7-12700K에서 8개의 스레드를 사용했고, GPU 행은 8 GB VRAM을 탑재한 NVIDIA RTX 3070 Ti에서 CUDA 12.4를 사용했습니다. 초(seconds)와 메모리(memory) 열은 게시된 수치입니다. x_realtime 열은 780초 분량의 오디오를 측정된 시간으로 나눈 뒤 소수점 첫째 자리까지 반올림하여 계산한 값입니다. 메모리 열은 CPU 차트의 경우 시스템 RAM을, GPU 차트의 경우 VRAM을 의미합니다.

공유 vCPU 플랜은 위 CPU 벤치마크 수치에 도달할 수 없습니다. 해당 벤치마크는 고성능 데스크톱 프로세서의 8개 스레드를 독점적으로 사용했기 때문입니다. 7.6배를 최대 성능으로 간주하고, 관련 계획을 세우기 전에 실제 녹음 파일을 사용하여 time로 직접 본인의 서버 성능을 측정하십시오.

실무에서 유효한 4가지 경험 법칙은 다음과 같습니다.

  • 본인 녹음 파일의 간헐적인 전사: CPU, small 모델, int8. 전용 vCPU 2개면 충분합니다.
  • 자막 생성과 같은 야간 배치 작업: CPU, small 또는 medium 모델, int8, nice로 래핑.
  • 대화형 작업 또는 하룻밤 사이에 전체 라이브러리를 처리해야 하는 경우: GPU.
  • Piper: 항상 CPU. 이 정도 크기의 음성 모델은 GPU를 사용해도 거의 이득이 없습니다.

동일한 하드웨어에서 다른 어떤 작업을 수행할 수 있을지 고민 중이라면, 자체 호스팅 가능한 AI 모델에 대한 더 넓은 범위의 질문에서 수용 가능한 모델 크기를 확인할 수 있습니다.

실패 유형 및 확인되는 메시지

error: externally-managed-environment 설치 시 발생합니다. 시스템 Python은 배포판에 의해 보호됩니다. 위에서 설명한 대로 가상 환경을 생성하십시오.

GPU 서버에서의 cuDNN 불일치. 실패 메시지는 다음과 같습니다.

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를 설치하거나 pip install --force-reinstall ctranslate2==4.4.0을 사용하여 이전 런타임 버전을 고정하십시오. 둘 중 하나만 수행해야 합니다. 두 가지를 모두 수행하면 원래 상태로 돌아갑니다.

This CTranslate2 package was not compiled with CUDA support는 비슷해 보이지만 다른 오류입니다. 설치된 휠(wheel) 파일이 CPU 전용 빌드입니다. GPU 호스트에서 가상 환경을 다시 빌드하여 pip가 올바른 휠을 다시 선택하도록 하십시오.

전사 내용의 문구 반복. 문장이 10번 반복되는 현상은 거의 항상 침묵이나 음악이 음성으로 잘못 인식될 때 발생합니다. 먼저 vad_filter=True를 활성화하십시오. 그래도 문제가 지속되면 해당 구간을 들어보십시오. 오디오가 거의 침묵 상태이면 Whisper가 기준점을 잡지 못해 마지막으로 확신했던 추측을 반복하게 됩니다.

잘못된 언어 감지. 기본적으로 faster-whisper는 처음 30초 구간만으로 언어를 추측합니다. info.language_probability 값이 1.0보다 훨씬 낮다면 확신이 없다는 뜻이며, 이는 녹음이 음악이나 여러 사람의 대화로 시작될 때 발생합니다. 언어를 이미 알고 있다면 language="en"을 전달하거나, language_detection_segments 값을 높여 더 많은 구간을 검토한 뒤 결정하도록 하십시오.

프로세스가 Killed를 출력하고 중단됨. 이는 커널의 OOM(Out-Of-Memory) 킬러가 작동한 것이며, dmesg을 실행하면 관련 oom-kill 로그를 확인할 수 있습니다. large-v3 모델은 작업 메모리 외에도 가중치 로드에만 3 GB 이상의 메모리가 필요합니다. 2 GB VPS 환경에서는 int8로 양자화된 small 모델이 적재 가능한 최대 크기입니다.

Piper가 음성 파일을 찾을 수 없음. 플레이어는 --data-dir을 전달하지 않으면 현재 작업 디렉터리에서 파일을 찾습니다. 예상되는 디렉터리에서 ls를 실행하여 .onnx과 .onnx.json가 모두 존재하는지 확인하십시오. 둘 중 하나라도 없으면 정상적으로 작동하지 않습니다.

FAQ

CPU 전용 VPS에서 음성 인식(Speech-to-Text)을 실행할 수 있습니까?

네, 배치 작업을 수행할 때 합리적인 선택입니다. int8 양자화된 small 모델을 사용하여 faster-whisper를 실행하면, 프로젝트에 공개된 벤치마크 기준 데스크톱 i7의 8개 스레드에서 13분 분량의 오디오를 102초 만에 처리합니다. 이는 실시간 대비 약 7.6배 속도이며, 1,477 MB의 RAM을 사용합니다. 공유 vCPU 플랜은 이보다 느리게 작동하므로 본인의 서버에서 직접 측정하십시오. Piper를 이용한 음성 합성(Text-to-Speech)은 훨씬 더 가벼우며 어떤 상황에서도 GPU가 필요하지 않습니다.

어떤 Whisper 모델 크기를 사용해야 합니까?

int8 양자화된 small 모델로 시작하십시오. 디스크 용량은 484 MB이며, 깨끗하게 녹음된 음성을 잘 처리합니다. 억양이나 배경 소음으로 인해 허용하기 어려운 오류가 발생하면 medium 모델로 올리고, 정확도가 무엇보다 중요할 때만 large-v3 모델을 사용하십시오. large-v3는 3,090 MB의 디스크 공간과 3 GB 이상의 메모리를 요구합니다. 반대로 75.5 MB 크기의 tiny 모델은 언어 감지나 파이프라인 테스트에는 유용하지만, 사람이 읽을 용도의 전사(transcript)에는 적합하지 않습니다.

왜 faster-whisper가 원본 Whisper 패키지보다 빠릅니까?

모델은 동일하지만 런타임이 다릅니다. 참조 패키지는 PyTorch에서 Whisper를 실행하는 반면, faster-whisper는 동일한 가중치를 CTranslate2에서 실행합니다. CTranslate2는 트랜스포머 추론을 위해 설계된 엔진으로, 로드 시점에 가중치를 양자화하며 PyTorch 설치가 필요 없습니다. 공개된 CPU 벤치마크에서 원본 패키지는 실시간 대비 1.9배인 반면, faster-whisper(int8)는 7.6배의 속도를 내며 메모리 사용량도 더 적습니다.

왜 전사 결과에서 같은 문장이 계속 반복됩니까?

Whisper가 침묵이나 음악을 음성으로 잘못 해석하여 마지막으로 확신했던 추측을 반복하기 때문입니다. transcribe() 호출 시 vad_filter=True 옵션을 설정하십시오. 이 옵션은 Silero 음성 활동 감지(VAD)를 먼저 실행하여 모델이 입력받기 전에 침묵 구간을 제거합니다. 그래도 반복된다면 오디오 레벨을 확인하십시오. 전체적으로 거의 침묵에 가까운 녹음은 모델이 작업할 데이터를 제공하지 못합니다.

내 서버에서 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을 배치하십시오.

#whisper#tts#piper#speech-to-text#self-hosted-ai