Whisper 코드 리뷰 — Open AI STT 모델의 내부 구조 해부

OpenAI의 **Whisper**는 오픈소스로 공개된 음성 인식(STT, Speech-to-Text) 모델입니다. 겉으로는 “그냥 음성을 텍스트로 바꿔주는 모델”처럼 보이지만, 실제로 코드를 들여다보면 Transformer 기반 멀티모달 인퍼런스 엔진에 가깝습니다. 이번 글에서는 Whisper의 코드를 직접 뜯어보며 구조를 해부해보겠습니다.

screenshot 2025 10 31 at 12.20.45\u202fam

🎯 1. 전체 구조 개요

Whisper 레포지토리의 핵심은 단 3개의 파일에 있습니다.

  • model.py — 모델 정의 (Transformer encoder-decoder)

  • audio.py — 오디오 전처리 (FFT, mel spectrogram)

  • transcribe.py — 실제 inference 파이프라인

이 단순한 구조 덕분에 Whisper는 PyTorch 모델 중 가장 읽기 쉬운 코드 중 하나입니다.

🎧 2. 오디오 처리 파이프라인 (audio.py)

먼저 오디오를 처리하는 부분을 봅시다.

def load_audio(file: str, sr: int = 16000): out = subprocess.run( [“ffmpeg”, “-i”, file, “-f”, “s16le”, “-ac”, “1”, “-acodec”, “pcm_s16le”, “-ar”, str(sr), “-”], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, ) return np.frombuffer(out.stdout, np.int16).astype(np.float32) / 32768.0

핵심 포인트:

  • Whisper는 모든 입력 오디오를 16kHz mono float32로 맞춥니다.

  • ffmpeg를 직접 호출해 다양한 포맷을 호환합니다.

  • 출력은 [-1, 1] 범위의 float32 numpy array입니다.

다음은 멜 스펙트로그램 변환 부분입니다.

def log_mel_spectrogram(audio): spec = librosa.feature.melspectrogram( y=audio, sr=16000, n_fft=400, hop_length=160, n_mels=80 ) return np.log10(np.maximum(spec, 1e-10))

여기서 중요한 건 80채널 Mel spectrogram을 생성한다는 점입니다. 이는 Whisper의 인코더 입력 토큰 역할을 합니다 — 즉, 오디오를 “이미지처럼” 본다는 개념이죠.

🧠 3. 모델 정의 (model.py)

Whisper의 핵심은 Transformer입니다. 코드를 보면 거의 GPT 스타일의 디코더와, BERT 스타일의 인코더가 짝을 이룹니다.

class Whisper(nn.Module): def init(self, dims): super().init() self.encoder = AudioEncoder(dims) self.decoder = TextDecoder(dims)

🎙️ 인코더

AudioEncoder는 Mel spectrogram을 입력받아 latent representation을 만듭니다.

class AudioEncoder(nn.Module): def init(self, dims): super().init() self.conv1 = Conv1d(80, dims.n_audio_state, kernel_size=3, stride=1, padding=1) self.blocks = nn.ModuleList([ResidualAttentionBlock(…) for _ in range(dims.n_audio_layer)])

이 구조는 Conv → Self-Attention 반복으로, 시간축의 특징을 추출하며 “음성 문맥 벡터”를 만듭니다.

✍️ 디코더

TextDecoder는 GPT와 거의 동일합니다. 차이점은 Cross-Attention으로 오디오 인코딩을 참조한다는 점입니다.

class TextDecoder(nn.Module): def forward(self, tokens, audio_features): for block in self.blocks: x = block(x, cross_kv=audio_features) return self.ln(x)

즉, Whisper는 **“오디오를 보고 문장을 예측하는 GPT”**입니다.

⚙️ 4. 추론 파이프라인 (transcribe.py)

전체 파이프라인은 이렇게 단순합니다.

def transcribe(model, audio): mel = log_mel_spectrogram(audio) mel = torch.from_numpy(mel).to(model.device) result = model.decode(mel) return decode_tokens(result)

단 세 단계입니다:

  • 오디오 로드 + Mel 변환

  • Transformer 인코딩 + 디코딩

  • 토큰을 텍스트로 디코딩

여기에 beam search, temperature, language detection 등의 옵션이 붙으면 Whisper CLI에서 사용하는 --task translate, --temperature 0.2 같은 기능이 됩니다.

🌍 5. 다국어 지원

Whisper STT의 가장 큰 장점 중 하나는 다국어 인식입니다. 모델은 98개 이상의 언어를 지원하며, 자동 언어 감지 기능도 탑재되어 있습니다. 즉, 입력 오디오 언어를 미리 지정하지 않아도 모델이 판단하여 텍스트로 변환합니다.

코드 레벨에서는 language 파라미터와 --task transcribe 옵션이 이를 가능하게 합니다. 모델이 학습한 멀티링구얼 데이터 덕분에, 영어 외에도 스페인어, 중국어, 한국어 등 다양한 언어에서 높은 정확도를 보여줍니다.

⚡ 6. Whisper.cpp 포팅

Whisper 모델은 PyTorch 기반이지만, C++로 포팅된 Whisper.cpp 프로젝트가 있습니다. 주요 장점:

  • CPU 환경에서도 빠른 추론 가능

  • 모바일 및 임베디드 기기에서도 실행 가능

  • PyTorch 설치 없이 사용 가능

실제로 Whisper.cpp는 quantization, 메모리 최적화 등 다양한 기법을 적용해 속도와 효율을 극대화했습니다. Whisper STT를 서버가 아닌 로컬 장치에서 활용하고자 할 때 훌륭한 대안이 됩니다.

💡 7. Whisper의 설계 철학

코드를 읽다 보면 Whisper 팀의 철학이 느껴집니다:

  • Simple > Clever — 복잡한 트릭보다 일관된 설계

  • 모듈화된 파이프라인 — 오디오 → 멜 → 인코더 → 디코더 → 텍스트

  • End-to-End Differentiable — 전처리까지 포함한 end-to-end 설계

Whisper는 “거대한 모델을 단순한 구조로 구현하는 방법”의 모범 사례입니다. 덕분에 모델 크기에 비해 읽기 쉽고 유지보수가 쉬운 코드베이스가 되었죠.

🏁 8. 마무리

Whisper STT의 코드는 “STT의 표준 교과서”라고 할 수 있습니다. Transformer를 이용해 음성을 텍스트로 변환하는 전체 과정이 간결하고 직관적으로 담겨 있기 때문입니다. 다국어 지원과 Whisper.cpp 포팅 덕분에 활용 범위도 넓습니다.

📚 더 깊이 보고 싶다면:

  • Beam Search가 Whisper에서 어떻게 구현되어 있는가

  • Whisper 모델의 다국어 처리 방식

  • Whisper.cpp나 MLX 포팅 버전의 최적화 비교

참고 자료