Audio-005, Whisper: Robust Speech Recognition via Large-Scale Weak Supervision, OpenAI 2022

◼ Comment

  • pretraining / sft 이런식으로 단계를 나누지 말고 한번에 학습하자
    • 와이? self-supervised 인코더만으로는 실제 사용가능한 출력으로 활용하기 어렵기 때문 (hubert 이런거 말하는듯)
    •  본 연구에서는 이 격차를 해소하여, 약한 감독 기반 음성 인식을 다음 차원으로 확장해 68만 시간 규모의 라벨된 오디오 데이터로 학습한다. 
    • 총 68만 시간 중 11만7천 시간은 96개 다른 언어를 포함하며, 데이터셋에는 X→en 번역 데이터 12만5천 시간도 포함된다.
    • 충분히 큰 모델의 경우, 다국어·다중 과제의 공동 학습에는 손해가 없을 뿐 아니라 오히려 이점이 있음을 확인했다.
  • Transformer encoder decoder 구조임
    • 그림보면, 구조가 특별히 다른게 없어보이긴함
  • 데이터 형식
    • <|startoftranscript|> : 모델이 출력을 시작한다는 신호.
    • <|nospeech|> : 주어진 오디오 구간(30초 세그먼트)에 음성이 없는 경우 예측하는 토큰.
    • <|transcribe|> : 동일 언어로 전사(transcription) 해야 한다는 지시.
    • <|translate|> : 영어로 번역(translation) 해야 한다는 지시.
    • <|notimestamps|> : 타임스탬프를 포함하지 말라는 옵션. (반대로 타임스탬프 모드를 켜면 <|t0.00|><|t1.20|> 같은 토큰이 함께 생성됨)
    • <|startoftranscript|><|ko|><|transcribe|><|notimestamps|> 안녕하세요, 반갑습니다. <|endoftranscript|>
    • <|startoftranscript|><|en|><|transcribe|> <|t0.00|> Hello <|t0.50|> world <|t1.00|> <|endoftranscript|>
  • 즉 다양한 멀티테스크 데이터 만들어서 학습했더니, 잘 되더라?

🔹 2. 인코더 입력 변환 (Conv Stem)

스펙트로그램은 Transformer 인코더에 바로 들어가지 않고,
먼저 2개의 1D Convolution 레이어를 거칩니다:

  • 첫 번째 Conv: 필터 폭 3, 활성함수 GELU

  • 두 번째 Conv: 필터 폭 3, stride=2 (시간축 길이 절반 축소)

  • 이후 sinusoidal positional encoding을 추가

이 과정을 통해 오디오가:

(시간 프레임, 80채널)(축소된 시간 프레임, hidden_dim)
형태의 continuous vector sequence로 변환됩니다.

Abstract

우리는 인터넷 상의 대규모 오디오에 대한 전사를 단순히 예측하도록 훈련된 음성 처리 시스템의 능력을 연구한다. 68만 시간 규모의 다국어·다중 과제 감독으로 학습하면, 이렇게 만들어진 모델은 표준 벤치마크에서 잘 일반화되며, 어떤 데이터셋별 미세조정(fine-tuning)도 없이 제로샷 전이 설정에서 기존의 완전 감독 방식 결과와 종종 경쟁한다. 인간과 비교했을 때, 이들 모델은 정확도와 견고성에서 인간 수준에 근접한다. 우리는 강인한 음성 처리를 위한 후속 연구의 토대가 되도록 모델과 추론 코드를 공개한다. 

1. Introduction

음성 인식의 발전은 Wav2Vec 2.0(Baevski et al., 2020)로 대표되는 비지도 사전학습 기법의 등장으로 활력을 얻었다. 이러한 방법들은 사람의 라벨 없이 원시 오디오에서 직접 학습하기 때문에, 대규모의 비라벨 음성 데이터를 효과적으로 활용할 수 있으며, 학습 데이터를 100만 시간 규모까지 신속히 확장해왔다(Zhang et al., 2021). 이는 전통적인 학술용 지도 데이터셋이 대략 1천 시간 수준인 것과 대조적이다. 표준 벤치마크에 대해 미세조정(fine-tuning)을 수행하면, 특히 데이터가 적은 설정에서 이 접근법은 최신 성능을 향상시켰다.

이렇게 사전학습된 오디오 인코더는 고품질의 음성 표현을 학습하지만, 순수 비지도 방식이기 때문에 그 표현을 사용 가능한 출력으로 사상하는 동등한 성능의 디코더가 없다. 

  • self-supervised 인코더만으로는 “representation은 좋지만 usable output(텍스트 등)”으로 바로 쓸 수 없음
  • 그래서 supervised fine-tuning을 해야 하고, 그게 연구/실무에서 병목이 된다는 점을 강조하는 거예요.

그 결과, 실제로 음성 인식과 같은 작업을 수행하려면 미세조정 단계가 필요하다. 이는 여전히 숙련된 실무자가 필요한 복잡한 과정일 수 있어, 활용성과 영향력을 제한한다. 또한 미세조정을 요구하는 데에는 추가적인 위험이 따른다. 머신러닝 방법은 같은 데이터셋에서 분리한 검증 데이터에 대해서는 성능을 끌어올려 주는 패턴을 학습하는 데 매우 능숙하지만, 그중 일부 패턴은 취약하고 허위이며 다른 데이터셋과 분포로는 일반화되지 않는다. (각주 1: Baevski et al. (2021)은 완전 비지도 음성 인식 시스템을 개발한 흥미로운 예외적 사례이다.)

특히 우려스러운 사례로, Radford et al. (2021)은 컴퓨터 비전 모델을 ImageNet(Russakovsky et al., 2015)에 미세조정했을 때 객체 분류 정확도가 9.2% 향상되었지만, 동일한 객체를 일곱 개의 다른 자연 이미지 데이터셋에서 분류할 때 평균 정확도 향상은 관찰되지 않았음을 보고했다. 특정 데이터셋에서 “초인간적” 성능을 달성한 모델도, 다른 데이터셋에서 평가하면 여전히 많은 기초적 오류를 저지를 수 있으며, 그 이유는 인간이 알아차리기 어려운 데이터셋 특유의 편향을 모델이 활용하고 있기 때문일 수 있다(Geirhos et al., 2020). 이는 비지도 사전학습이 오디오 인코더의 품질을 크게 개선했음에도, 동등한 수준의 고품질 사전학습된 디코더의 부재와 데이터셋별 미세조정을 권장하는 프로토콜이 결합되면, 유용성과 견고성을 제한하는 중대한 약점이 됨을 시사한다. 음성 인식 시스템의 목표는, 배포 대상 분포마다 디코더를 지도 미세조정할 필요 없이, 다양한 환경에서 “바로 쓸 수 있게(out of the box)” 안정적으로 동작하는 것이어야 한다.

Narayanan et al. (2018), Likhomanenko et al. (2020), Chan et al. (2021)이 보여주었듯이, 다수의 데이터셋/도메인에 걸쳐 지도 방식으로 사전학습된 음성 인식 시스템은 단일 소스에서 학습한 모델보다 더 높은 견고성을 보이고, 보류된(held-out) 데이터셋으로 더 효과적으로 일반화한다. 이들 연구는 가능한 한 많은 고품질 음성 인식 데이터셋을 결합함으로써 이를 달성했다. 그러나 쉽게 확보 가능한 이러한 데이터의 규모는 아직 중간 수준에 그친다. 예를 들어 SpeechStew(Chan et al., 2021)는 사전 존재하던 7개 데이터셋을 합쳐 총 5,140시간의 감독 신호를 제공한다. 이는 앞서 언급한 100만 시간 규모의 비라벨 음성 데이터(Zhang et al., 2021)에 비하면 여전히 매우 작은 수준이다.

기존의 고품질 지도 데이터셋의 한계를 인식하고, 최근에는 더 큰 음성 인식용 데이터셋을 구축하려는 노력이 있었다. 금표준의 사람 검증 전사를 반드시 요구하지 않음으로써, Chen et al. (2021)과 Galvez et al. (2021)은 정교한 자동화 파이프라인을 활용해 약한 감독(weak supervision)에 기반한 음성 인식을 각각 1만 시간과 3만 시간 규모의 더 잡음이 많은 학습 데이터로 확장했다. 이러한 품질과 양 사이의 절충은 종종 적절한 선택이다. 비록 음성 인식에서는 아직 충분히 연구되지 않았지만, 컴퓨터 비전의 최근 연구는 ImageNet과 같은 금표준 크라우드소싱 데이터셋(Russakovsky et al., 2015)을 넘어 훨씬 더 크지만 약하게 감독된 데이터셋으로 이동하면 모델의 견고성과 일반화가 크게 향상됨을 보여주었다(Mahajan et al., 2018; Kolesnikov et al., 2020).

그러나 이러한 새로운 데이터셋들도 기존의 고품질 데이터셋들을 모두 합한 것보다 몇 배 큰 수준에 그치며, 이전의 비지도 연구에서 사용된 규모에는 여전히 미치지 못한다. 본 연구에서는 이 격차를 해소하여, 약한 감독 기반 음성 인식을 다음 차원으로 확장해 68만 시간 규모의 라벨된 오디오 데이터로 학습한다. 우리는 이 접근법을 Whisper라고 부른다. 이 규모에서 학습된 모델은 데이터셋별 미세조정 없이도 기존 데이터셋으로의 제로샷 전이가 잘 이루어지며, 높은 품질의 결과에 도달한다.

규모 확대와 더불어, 영어 중심의 음성 인식 범위를 넘어 다국어·다중 과제 약한 감독 사전학습으로 영역을 넓혔다. 총 68만 시간 중 11만7천 시간은 96개 다른 언어를 포함하며, 데이터셋에는 X→en 번역 데이터 12만5천 시간도 포함된다. 충분히 큰 모델의 경우, 다국어·다중 과제의 공동 학습에는 손해가 없을 뿐 아니라 오히려 이점이 있음을 확인했다.

우리의 연구는 단순한 약한 감독 사전학습의 스케일링이 지금까지 음성 인식 연구에서 과소평가되어 왔음을 시사한다. 본 결과는 최근 대규모 음성 인식 연구의 상례였던 자기지도(self-supervision)나 자기학습(self-training) 기법 없이 달성되었다.

  • 위스퍼는 self-supervised pre-training → fine-tuning 단계를 분리하지 않고, 한 번의 학습으로 끝낸다는 거 같음.
  • 따라서 weakly supervised data 로 학습을 해야하는 것

2. 접근법

2.1. 데이터 처리

최근 인터넷의 웹 규모 텍스트를 기계학습에 활용하는 연구 흐름을 따라, 우리는 데이터 전처리에 대해 최소주의적 접근을 취한다. 음성 인식 분야의 많은 기존 작업과 달리, Whisper 모델은 전사문의 원시(raw) 텍스트를 별다른 표준화 없이 그대로 예측하도록 학습하며, 발화와 그 전사 형태 사이의 사상을 시퀀스-투-시퀀스 모델의 표현력이 스스로 배우도록 맡긴다. 이는 자연스러운 전사를 만들기 위해 별도의 역(逆) 텍스트 정규화 단계를 두지 않아도 되므로 음성 인식 파이프라인이 단순해진다. (이름의 약자나 근거가 필요하다면, “웹 규모 지도 사전학습 기반 음성 인식(Web-scale Supervised Pretraining for Speech Recognition)”을 뜻하는 WSPSR를 사용할 수 있다.)

데이터는 기본적으로 음성-텍스트로 쌍이 지어져있는데, 텍스트를 정규화한다거나 그렇지는 않은듯

우리는 인터넷에서 전사와 짝지어진 오디오를 모아 데이터셋을 구성한다. 이 결과물은 다양한 환경·녹음 설정·화자·언어를 폭넓게 포괄하는 매우 이질적인 분포의 오디오를 담는다. 오디오 품질의 다양성은 모델의 견고성 향상에 도움이 될 수 있지만, 전사 품질의 다양성은 같은 이득을 주지 못한다. 초기 점검에서 원시 데이터셋에 수준 이하의 전사가 많이 포함되어 있음을 확인했고, 이를 개선하기 위해 전사 품질을 높이는 여러 자동 필터링 방법을 개발했다.

인터넷의 전사 중 상당수는 실제 사람이 작성한 것이 아니라 기존 ASR 시스템의 출력이다. 최근 연구에 따르면 사람·기계 생성 전사가 섞인 데이터로 학습하면 번역 시스템 성능이 유의미하게 저하될 수 있다. 우리는 이른바 “transcript-ese”를 모델이 배우지 않도록, 기계 생성 전사를 탐지·제거하기 위한 다양한 휴리스틱을 설계했다. 예를 들어 많은 ASR 시스템은 복잡한 문장부호(느낌표, 쉼표, 물음표 등), 문단과 같은 공백 서식, 대소문자와 같은 문체적 요소를 삭제하거나 규격화해, 문자 언어의 일부만 출력하는 경향이 있다. 모든 글자가 대문자이거나 소문자인 전사는 사람이 작성했을 가능성이 매우 낮다. 다수의 ASR 시스템이 어느 정도의 역 텍스트 정규화를 포함하긴 하지만, 보통은 단순하거나 규칙 기반이어서(예: 쉼표를 절대 쓰지 않음) 다른 흔적을 통해 여전히 식별 가능하다.

또한 우리는 음성 언어 감지기를 사용해, CLD2에 따른 전사 언어와 실제 발화 언어가 일치하는지 확인했다. 이 감지기는 본 데이터셋의 프로토타입 버전으로 학습한 프로토타입 모델을 VoxLingua107에 미세조정해 만들었다. 두 언어가 일치하지 않으면 해당 (오디오, 전사) 쌍은 음성 인식 학습 예제로 포함하지 않는다. 단, 전사 언어가 영어일 경우에는 예외적으로 이 쌍을 X→en 음성 번역 학습 예제로 포함한다. 또한 전사 텍스트의 퍼지(fuzzy) 중복 제거를 통해 학습 데이터셋 내 중복과 자동 생성 콘텐츠의 양을 줄였다.

오디오 파일은 30초 길이의 세그먼트로 분할하고, 각 구간에 해당하는 전사 일부를 짝지었다. 우리는 모든 오디오(발화가 없는 구간도 포함하여, 다만 하위샘플링된 확률로)를 학습에 사용하며, 이러한 무발화 세그먼트는 음성 활동 탐지(VAD) 학습 데이터로 활용한다.

추가적인 필터링 단계로, 초기 모델을 한 차례 학습한 뒤에는 학습 데이터 소스별 오류율 정보를 취합해, 오류율이 높고 규모도 큰 소스부터 수작업 점검을 수행하여 저품질 소스를 효율적으로 제거했다. 이 점검에서 부분 전사만 존재하거나 정렬이 부정확/불일치한 전사, 그리고 자동 필터링 휴리스틱을 피해 남아 있던 저품질 기계 생성 캡션이 다수 확인되었다.

평가 데이터와의 혼입을 피하기 위해, 중복 위험이 높다고 판단한 평가 세트—예컨대 TED-LIUM 3—와 학습 데이터셋 사이에서는 전사 수준의 중복 제거를 수행했다. 

  • “Well, I think it’s going to rain, isn’t it?” vs “well i think its going to rain isnt it”
  • 예를 들어, 오디오가 스페인어인데 전사가 영어라면 ASR 데이터로는 부적합
  • 수작업
    • 오디오 길이 30초인데 텍스트가 5단어밖에 없음 → 부분 전사
    • 오디오와 전사가 타이밍이 맞지 않음 → 불일치 데이터
  • 발화가 없는 데이터는 VAD 데이터로 학습

2.2. 모델

본 연구의 초점은 대규모 감독 학습 사전훈련(supervised pre-training)이 음성 인식에서 어떤 능력을 가지는지를 탐구하는 데 있으므로, 모델 개선과 혼동을 피하기 위해 기성(off-the-shelf) 아키텍처를 사용하였다. 우리는 신뢰성 있게 확장(scale)됨이 잘 검증된 인코더-디코더 트랜스포머(Transformer) 아키텍처(Vaswani et al., 2017)를 선택하였다.

모든 오디오는 16,000 Hz로 리샘플링되며, 25밀리초 창(window)과 10밀리초 보폭(stride)으로 계산된 80채널 로그-크기 멜 스펙트로그램(log-magnitude Mel spectrogram) 표현으로 변환된다. 특징 정규화를 위해, 입력 전체를 -1과 1 사이로 전역 스케일링하고 사전훈련 데이터셋 전체에서 평균이 대략 0이 되도록 조정한다.

인코더는 작은 스템(stem) 구조로 이 입력 표현을 처리한다. 스템은 두 개의 합성곱(convolution) 층으로 구성되며, 커널 너비는 3이고 활성화 함수로는 GELU(Hendrycks & Gimpel, 2016)를 사용한다. 두 번째 합성곱 층은 보폭(stride) 2를 가진다. 이 출력에 사인 기반 위치 임베딩(sinusoidal positional embedding)을 추가한 뒤, 인코더 트랜스포머 블록을 적용한다. 트랜스포머는 사전-활성화(pre-activation) 잔차 블록(Child et al., 2019)을 사용하며, 최종적으로 인코더 출력에 레이어 정규화(layer normalization)를 적용한다.

디코더는 학습된 위치 임베딩(learned positional embeddings)을 사용하며, 입력과 출력 토큰 표현을 공유(tied input-output representations)한다 (Press & Wolf, 2017). 인코더와 디코더는 동일한 폭(width)과 트랜스포머 블록 수를 가진다. 모델 아키텍처의 개요는 그림 1에 정리되어 있다.

텍스트 토크나이저는 GPT-2에서 사용된 바이트 단위 BPE 토크나이저(Sennrich et al., 2015; Radford et al., 2019)를 영어 전용 모델에 그대로 사용한다. 다국어 모델의 경우, 어휘 집합 크기는 동일하게 유지하되, 영어에만 맞춰진 GPT-2 BPE 어휘가 다른 언어에서 과도하게 쪼개지는(fragmentation) 문제를 피하기 위해 새로운 어휘로 재적합(refit)하였다.

# whisper_like.py
# Reference implementation of Whisper (Section 2.2) style model in PyTorch.
# - Audio: 16kHz, 80-ch log-Mel spectrogram (25 ms window, 10 ms hop)
# - Encoder: 2x Conv1D stem (k=3; 2nd has stride=2) + GELU, sinusoidal pos-emb, Transformer (pre-LN)
# - Decoder: learned pos-emb, tied input-output embeddings, cross-attention

from dataclasses import dataclass
from typing import Optional, Tuple
import math
import torch
import torch.nn as nn
import torch.nn.functional as F

# =========================
# Audio frontend (log-Mel)
# =========================

try:
import torchaudio
_HAS_TORCHAUDIO = True
except Exception:
_HAS_TORCHAUDIO = False

class LogMelSpectrogram(nn.Module):
"""
80-ch log-magnitude Mel spectrogram:
- sample_rate: 16000
- win_length: 25 ms
- hop_length: 10 ms
- n_mels: 80
- power: 2.0 (magnitude^2), then log
"""
def __init__(
self,
sample_rate: int = 16000,
n_mels: int = 80,
win_ms: float = 25.0,
hop_ms: float = 10.0,
n_fft: Optional[int] = None,
f_min: float = 0.0,
f_max: Optional[float] = None,
eps: float = 1e-10,
):
super().__init__()
assert _HAS_TORCHAUDIO, "Install torchaudio to use LogMelSpectrogram."
self.sample_rate = sample_rate
self.n_mels = n_mels
self.win_length = int(round(win_ms / 1000 * sample_rate))
self.hop_length = int(round(hop_ms / 1000 * sample_rate))
self.n_fft = n_fft or 2 ** math.ceil(math.log2(self.win_length))
self.f_min = f_min
self.f_max = f_max or (sample_rate / 2)
self.eps = eps

self.melspec = torchaudio.transforms.MelSpectrogram(
sample_rate=sample_rate,
n_fft=self.n_fft,
win_length=self.win_length,
hop_length=self.hop_length,
f_min=self.f_min,
f_max=self.f_max,
n_mels=self.n_mels,
power=2.0, # magnitude^2
center=True,
pad_mode="reflect",
norm=None,
mel_scale="htk",
)

def forward(self, wav: torch.Tensor) -> torch.Tensor:
"""
Args:
wav: (B, T) float32 in [-1, 1] at 16kHz
Returns:
log_mel: (B, n_mels=80, frames)
"""
# global scale to [-1,1] and ~zero-mean is expected at dataset-level.
mel = self.melspec(wav) # (B, n_mels, frames)
log_mel = torch.log(mel + self.eps)
return log_mel


# =========================
# Positional embeddings
# =========================

class SinusoidalPositionalEmbedding(nn.Module):
"""Sinusoidal PE added to encoder features."""
def __init__(self, dim: int, max_len: int = 3000):
super().__init__()
pe = torch.zeros(max_len, dim)
position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, dim, 2).float() * (-math.log(10000.0) / dim))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
self.register_buffer("pe", pe) # (max_len, dim)

def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
x: (B, T, D)
"""
T = x.size(1)
return x + self.pe[:T].unsqueeze(0)


# =========================
# Transformer (pre-LN)
# =========================

class PreNormResidual(nn.Module):
def __init__(self, dim: int, sublayer: nn.Module, dropout: float = 0.0):
super().__init__()
self.norm = nn.LayerNorm(dim)
self.sublayer = sublayer
self.dropout = nn.Dropout(dropout)

def forward(self, x, *args, **kwargs):
return x + self.dropout(self.sublayer(self.norm(x), *args, **kwargs))

def build_mha(dim: int, heads: int, dropout: float) -> nn.MultiheadAttention:
# batch-first for convenience
return nn.MultiheadAttention(embed_dim=dim, num_heads=heads, dropout=dropout, batch_first=True)

class EncoderBlock(nn.Module):
def __init__(self, dim: int, heads: int, mlp_ratio: float, dropout: float):
super().__init__()
self.self_attn = PreNormResidual(dim, build_mha(dim, heads, dropout))
hidden = int(dim * mlp_ratio)
self.ff = PreNormResidual(dim, nn.Sequential(
nn.Linear(dim, hidden),
nn.GELU(), # GELU in FFN
nn.Linear(hidden, dim),
), dropout=dropout)

def forward(self, x, key_padding_mask=None, attn_mask=None):
x = self.self_attn(x, x, x, key_padding_mask=key_padding_mask, attn_mask=attn_mask)[0]
x = self.ff(x)
return x

class DecoderBlock(nn.Module):
def __init__(self, dim: int, heads: int, mlp_ratio: float, dropout: float):
super().__init__()
self.self_attn = PreNormResidual(dim, build_mha(dim, heads, dropout))
self.cross_attn = PreNormResidual(dim, build_mha(dim, heads, dropout))
hidden = int(dim * mlp_ratio)
self.ff = PreNormResidual(dim, nn.Sequential(
nn.Linear(dim, hidden),
nn.GELU(),
nn.Linear(hidden, dim),
), dropout=dropout)

def forward(
self,
x,
enc_out,
tgt_key_padding_mask=None,
tgt_attn_mask=None,
memory_key_padding_mask=None,
memory_attn_mask=None,
):
x = self.self_attn(x, x, x, key_padding_mask=tgt_key_padding_mask, attn_mask=tgt_attn_mask)[0]
x = self.cross_attn(x, enc_out, enc_out,
key_padding_mask=memory_key_padding_mask,
attn_mask=memory_attn_mask)[0]
x = self.ff(x)
return x


# =========================
# Conv stem (2x Conv1d)
# =========================

class ConvStem(nn.Module):
"""
Two 1D conv layers over time axis of mel features.
Input shape: (B, n_mels=80, T_frames)
Conv1: k=3, stride=1, padding=1 + GELU
Conv2: k=3, stride=2, padding=1 + GELU (time downsample /2)
Then transpose to (B, T', D) with D = channels.
"""
def __init__(self, n_mels: int, width: int):
super().__init__()
self.conv1 = nn.Conv1d(n_mels, width, kernel_size=3, stride=1, padding=1)
self.conv2 = nn.Conv1d(width, width, kernel_size=3, stride=2, padding=1)
self.act = nn.GELU()

def forward(self, x: torch.Tensor) -> torch.Tensor:
# x: (B, n_mels, T)
x = self.act(self.conv1(x))
x = self.act(self.conv2(x)) # (B, width, T//2)
x = x.transpose(1, 2) # (B, T', width)
return x


# =========================
# Encoder / Decoder stacks
# =========================

@dataclass
class ModelConfig:
n_mels: int = 80
width: int = 512 # model dimension
enc_layers: int = 6
dec_layers: int = 6
heads: int = 8
mlp_ratio: float = 4.0
dropout: float = 0.0
vocab_size: int = 50257 # GPT-2 BPE default
max_enc_len: int = 3000
max_dec_len: int = 448

class WhisperLikeEncoder(nn.Module):
def __init__(self, cfg: ModelConfig):
super().__init__()
self.stem = ConvStem(cfg.n_mels, cfg.width)
self.pos = SinusoidalPositionalEmbedding(cfg.width, max_len=cfg.max_enc_len)
self.blocks = nn.ModuleList([
EncoderBlock(cfg.width, cfg.heads, cfg.mlp_ratio, cfg.dropout)
for _ in range(cfg.enc_layers)
])
self.final_ln = nn.LayerNorm(cfg.width)

def forward(self, mel: torch.Tensor, key_padding_mask: Optional[torch.Tensor] = None):
"""
mel: (B, n_mels, T)
key_padding_mask: (B, T') where T' is time after /2 by stem
"""
x = self.stem(mel) # (B, T', D)
x = self.pos(x)
for blk in self.blocks:
x = blk(x, key_padding_mask=key_padding_mask)
x = self.final_ln(x)
return x # (B, T', D)

class WhisperLikeDecoder(nn.Module):
def __init__(self, cfg: ModelConfig):
super().__init__()
self.cfg = cfg
self.token_emb = nn.Embedding(cfg.vocab_size, cfg.width)
self.pos_emb = nn.Embedding(cfg.max_dec_len, cfg.width) # learned positional embeddings
self.blocks = nn.ModuleList([
DecoderBlock(cfg.width, cfg.heads, cfg.mlp_ratio, cfg.dropout)
for _ in range(cfg.dec_layers)
])
self.ln_f = nn.LayerNorm(cfg.width)
self.lm_head = nn.Linear(cfg.width, cfg.vocab_size, bias=False) # tied later

def forward(
self,
tokens: torch.Tensor,
enc_out: torch.Tensor,
tgt_key_padding_mask: Optional[torch.Tensor] = None,
memory_key_padding_mask: Optional[torch.Tensor] = None,
):
"""
tokens: (B, L)
enc_out: (B, T_enc, D)
"""
B, L = tokens.shape
tok = self.token_emb(tokens) + self.pos_emb(torch.arange(L, device=tokens.device))[None, :, :]
# causal mask for self-attn
causal = torch.full((L, L), float("-inf"), device=tokens.device)
causal = torch.triu(causal, diagonal=1)
x = tok
for blk in self.blocks:
x = blk(
x, enc_out,
tgt_key_padding_mask=tgt_key_padding_mask,
tgt_attn_mask=causal,
memory_key_padding_mask=memory_key_padding_mask,
)
x = self.ln_f(x)
logits = self.lm_head(x) # (B, L, V)
return logits


# =========================
# Full model
# =========================

class WhisperLikeModel(nn.Module):
"""
End-to-end seq2seq model with:
- audio -> log-mel -> encoder
- text tokens -> decoder (audio-conditional LM)
- tied input-output embeddings in decoder (Press & Wolf, 2017)
"""
def __init__(self, cfg: ModelConfig):
super().__init__()
self.cfg = cfg
self.encoder = WhisperLikeEncoder(cfg)
self.decoder = WhisperLikeDecoder(cfg)
# tie weights
self.decoder.lm_head.weight = self.decoder.token_emb.weight

@staticmethod
def length_after_stem(T_frames: int) -> int:
# stem stride=2 on time axis
return (T_frames + 1) // 2

def forward(
self,
mel: torch.Tensor, # (B, 80, T)
tokens: torch.Tensor, # (B, L) teacher-forced input ids
mel_padding_mask: Optional[torch.Tensor] = None, # (B, T') after stem
token_padding_mask: Optional[torch.Tensor] = None # (B, L)
):
enc = self.encoder(mel, key_padding_mask=mel_padding_mask) # (B, T', D)
logits = self.decoder(tokens, enc, tgt_key_padding_mask=token_padding_mask,
memory_key_padding_mask=mel_padding_mask) # (B, L, V)
return logits


# =========================
# Example usage
# =========================

if __name__ == "__main__":
cfg = ModelConfig(
n_mels=80, width=512, enc_layers=6, dec_layers=6, heads=8, mlp_ratio=4.0,
vocab_size=50257, max_enc_len=3000, max_dec_len=448
)
model = WhisperLikeModel(cfg)

B, T_wav = 2, 16000 * 30 # 30 s chunk at 16 kHz
if _HAS_TORCHAUDIO:
fe = LogMelSpectrogram()
wav = torch.randn(B, T_wav) * 0.1 # dummy [-1,1] scaled audio
wav = torch.clamp(wav, -1.0, 1.0)
mel = fe(wav) # (B, 80, T_frames)
else:
# fallback dummy mel (B, 80, 3000)
mel = torch.randn(B, 80, 3000)

L = 128
tokens = torch.randint(0, cfg.vocab_size, (B, L))

# create padding masks if needed (True = pad)
T_enc = WhisperLikeModel.length_after_stem(mel.size(-1))
mel_pad = torch.zeros(B, T_enc, dtype=torch.bool)
tok_pad = torch.zeros(B, L, dtype=torch.bool)

logits = model(mel, tokens, mel_padding_mask=mel_pad, token_padding_mask=tok_pad)
print("logits:", logits.shape) # (B, L, vocab_size)

2.3. 멀티태스크 포맷

주어진 오디오 조각에서 어떤 단어가 말해졌는지를 예측하는 것은 전체 음성 인식 문제의 핵심 요소이며, 연구에서도 광범위하게 다뤄져 왔다. 그러나 그것이 전부는 아니다. 

완전한 음성 인식 시스템에는 

  • 음성 활동 탐지(voice activity detection), 
  • 화자 분리(speaker diarization), 
  • 역 텍스트 정규화(inverse text normalization) 등 여러 추가 구성 요소들이 포함될 수 있다. 

이러한 구성 요소들은 종종 별도로 처리되며, 그 결과 핵심 음성 인식 모델 주위에 상대적으로 복잡한 시스템이 형성된다. 우리는 이러한 복잡성을 줄이기 위해 단일 모델이 단순히 핵심 인식만 수행하는 것이 아니라 전체 음성 처리 파이프라인을 처리하기를 원한다.

위스퍼는 한 모델로 모든걸 다하겠다라는 동기가 있는거 같음

여기서 중요한 고려 사항은 모델의 인터페이스이다. 동일한 입력 오디오 신호에 대해 수행될 수 있는 작업은 매우 다양하다. 

  • 예를 들어, 전사(transcription), 
  • 번역(translation), 
  • 음성 활동 탐지, 
  • 정렬(alignment), 
  • 언어 식별(language identification) 등이 있다.

이러한 일대다(one-to-many) 매핑을 단일 모델로 수행하기 위해서는 **작업 지정(task specification)**의 형태가 필요하다. 우리는 모든 작업과 조건 정보를 디코더에 입력할 토큰 시퀀스로 지정하는 간단한 포맷을 사용한다. 우리의 디코더는 오디오 조건부 언어 모델(audio-conditional language model)이므로, 전사 텍스트의 이전 히스토리를 조건으로 삼아 학습시켜, 더 긴 텍스트 문맥을 활용하여 모호한 오디오를 해소할 수 있기를 기대한다. 구체적으로는, 일정 확률로 현재 오디오 구간 앞에 위치한 전사 텍스트를 디코더의 문맥에 추가한다. 예측의 시작은 <|startoftranscript|> 토큰으로 표시한다.

먼저, 말해진 언어를 예측하는데, 이는 학습 세트에 있는 각 언어(총 99개)에 대해 고유한 토큰으로 표현된다. 이 언어 레이블은 앞서 언급한 VoxLingua107 모델에서 얻은 것이다. 만약 오디오 구간에 음성이 없는 경우, 모델은 <|nospeech|> 토큰을 예측하도록 학습되어 이를 표시한다.

다음 토큰은 작업을 지정한다. 전사의 경우 <|transcribe|> 토큰, 번역의 경우 <|translate|> 토큰이다. 이후에는 타임스탬프를 예측할지 여부를 지정한다. 타임스탬프를 예측하지 않을 경우 <|notimestamps|> 토큰을 넣는다. 이 시점에서 작업과 출력 형식은 모두 완전히 지정되었고, 실제 출력이 시작된다.

즉 주어진 음성에 대해 모델이 어떤 출력을 내뱉을지를 special token으로 지정했다는거 같음

  • <|startoftranscript|> : 모델이 출력을 시작한다는 신호.
  • <|nospeech|> : 주어진 오디오 구간(30초 세그먼트)에 음성이 없는 경우 예측하는 토큰.
  • <|transcribe|> : 동일 언어로 전사(transcription) 해야 한다는 지시.
  • <|translate|> : 영어로 번역(translation) 해야 한다는 지시.
  • <|notimestamps|> : 타임스탬프를 포함하지 말라는 옵션. (반대로 타임스탬프 모드를 켜면 <|t0.00|>, <|t1.20|> 같은 토큰이 함께 생성됨)
예시
  • 디코더 타겟: 
    • <|startoftranscript|><|ko|><|transcribe|><|notimestamps|> 안녕하세요, 반갑습니다. <|endoftranscript|>
    • <|startoftranscript|><|en|><|transcribe|> <|t0.00|> Hello <|t0.50|> world <|t1.00|> <|endoftranscript|>
  • 인코더쪽은 오디오가 입력으로 들어가는 것

타임스탬프 예측의 경우, 현재 오디오 구간을 기준으로 상대적인 시간을 예측하며, 모든 시간을 20밀리초 단위로 양자화한다. 이는 Whisper 모델의 기본 시간 해상도와 일치한다. 이에 따라 어휘에 이러한 타임스탬프 토큰들을 추가한다. 우리는 타임스탬프 예측을 캡션 토큰과 교차(interleave)시킨다. 즉, 각 캡션 텍스트 앞에는 시작 시각 토큰을, 끝에는 종료 시각 토큰을 예측한다.

만약 최종 전사 세그먼트가 현재 30초 오디오 구간에 부분적으로만 포함되어 있을 경우, 타임스탬프 모드에서는 그 세그먼트의 시작 시각 토큰만 예측해 이후 디코딩이 그 시각에 맞춰진 새로운 오디오 윈도우에서 수행되어야 함을 나타낸다. 타임스탬프 모드가 아닐 경우에는 해당 구간을 잘라내어 포함하지 않는다.

마지막으로 <|endoftranscript|> 토큰을 추가한다. 우리는 이전 문맥 텍스트에 대해서만 학습 손실을 마스킹(mask out)하고, 나머지 모든 토큰은 모델이 예측하도록 학습한다. 그림 1에서 이러한 포맷과 학습 설정에 대한 개요를 확인할 수 있다.

2.4. 학습 세부사항

우리는 Whisper의 스케일링 특성을 연구하기 위해 여러 크기의 모델을 학습했다. 전체 개요는 표 1을 참조하라. 

모델은 FP16(half precision) 연산과 동적 손실 스케일링(dynamic loss scaling), activation checkpointing(Griewank & Walther, 2000; Chen et al., 2016)을 사용하여 가속기(예: GPU) 간의 데이터 병렬(data parallelism) 방식으로 학습되었다.

최적화에는 AdamW(Loshchilov & Hutter, 2017)를 사용했고, gradient norm clipping(Pascanu et al., 2013)을 적용했다. 학습률은 처음 2,048 업데이트 동안 warmup을 거쳐 선형적으로 0까지 감소(linear decay)하도록 스케줄링하였다.

배치 크기는 256 세그먼트(즉, 30초 오디오 조각 256개)로 설정했으며, 모델은 총 220 업데이트 동안 학습되었다. 이는 데이터셋 전체를 두세 번 정도(epoch) 반복한 것에 해당한다.

학습 epoch 수가 적기 때문에 overfitting은 큰 문제가 아니었으며, 별도의 데이터 증강(data augmentation)이나 규제(regularization)를 사용하지 않았다. 대신, 대규모 데이터셋 자체의 다양성이 일반화와 강건성을 이끌어내도록 했다.

훈련 하이퍼파라미터 전체는 부록 F(Appendix F)에 제시되어 있다.


⚠️ 추가로, 본문 각주에 따르면 Whisper Large V2 모델은 이후에 2.5배 더 많은 epoch 동안 학습하면서, SpecAugment, Stochastic Depth, BPE Dropout 같은 정규화를 추가했다고 합니다.

3. 실험

3.1. 제로샷 평가

Whisper의 목표는 데이터셋에 특화된 파인튜닝 없이도 신뢰할 수 있는 고품질 결과를 낼 수 있는 단일 강건한 음성 처리 시스템을 개발하는 것이다. 이러한 능력을 연구하기 위해, 우리는 Whisper가 도메인, 과제, 언어 전반에 걸쳐 잘 일반화할 수 있는지를 확인하기 위해 기존의 다양한 음성 처리 데이터셋을 재사용하였다.

표준적인 평가 프로토콜에서는 이러한 데이터셋을 학습(split train)과 테스트(split test)로 나누어 사용한다. 하지만 우리는 Whisper를 제로샷(Zero-shot) 설정에서 평가하였다. 즉, 각 데이터셋의 학습 데이터를 전혀 사용하지 않고, 테스트 데이터만으로 성능을 측정함으로써 광범위한 일반화 능력을 평가했다.

3.2. 평가 지표

음성 인식 연구에서는 일반적으로 시스템을 평가하고 비교할 때 단어 오류율(Word Error Rate, WER) 지표를 사용한다. 그러나 WER은 문자열 편집 거리(string edit distance)에 기반하기 때문에, 모델 출력과 기준 전사(reference transcript) 사이의 모든 차이를 동일하게 벌점화한다. 이에는 실제 의미와는 무관한 전사 스타일 차이도 포함된다. 그 결과, 사람이 보기에 정답으로 판단할 수 있는 전사도 사소한 형식상의 차이 때문에 높은 WER을 기록할 수 있다.

이 문제는 모든 전사 시스템에서 발생할 수 있지만, 특히 Whisper처럼 특정 데이터셋의 전사 스타일을 학습 데이터에서 전혀 보지 못한 제로샷 모델에서는 더 심각하다.

이는 새로운 관찰은 아니며, 인간 판단과 더 잘 상관하는 평가 지표를 개발하는 것은 활발히 연구되고 있는 분야다. 일부 유망한 방법들이 제안되었지만, 아직 음성 인식 분야에서 널리 채택된 기준은 없다.

우리는 이 문제를 해결하기 위해 WER 계산 전에 전사 텍스트를 광범위하게 표준화(standardization) 하는 접근을 취했다. 이렇게 하면 의미와 무관한 비본질적 차이(non-semantic differences)에 대한 불필요한 벌점을 최소화할 수 있다.

텍스트 표준화기는 사람이 직접 반복적으로 검사하여, Whisper 모델이 사소한 차이 때문에 불필요하게 높은 WER을 기록하는 일반적인 패턴을 찾아내고 수정하는 방식으로 개발되었다. (부록 C에서 전체 세부사항 제공)

  • WER 메트릭을 변경하는게 아니라, WER이 잘되도록 정규화하는 작업을 했다는 것
  • 즉, WER 메트릭 자체는 그대로 두고 → 입력/출력 텍스트를 정규화 → 그 결과로 WER 점수가 더 합리적으로 나오게 한 것입니다.
  • 부록 C에서는 Whisper에서 사용한 텍스트 표준화 규칙을 자세히 설명합니다.

영어(English) 텍스트 표준화 단계

  1. 대괄호 [] 안의 구문 제거

  2. 소괄호 () 안의 구문 제거

  3. 불필요한 채움 말(예: hmm, mm, uh, um 등) 제거

  4. 아포스트로피 ' 앞의 공백 제거

  5. 축약형(contractions, e.g., “you’re”)을 원래 형태로 변환 (“you are”)

  6. 숫자 사이의 콤마 제거

  7. 숫자 뒤가 아닌 마침표 제거

  8. 기호·발음 구별 부호(diacritics) 제거 (단, . % 화폐 기호 등은 예외)

  9. 숫자·화폐 표현을 아라비아 숫자로 통일 (“Ten thousand dollars” → “$10000”)

  10. 영국식 철자 → 미국식 철자로 변환

  11. 남은 기호 제거

  12. 연속된 공백을 단일 공백으로 축소

비영어(non-English) 텍스트 표준화 (간단 버전)

  1. 대괄호·소괄호 안 구문 제거

  2. 기호·문장 부호 → 공백으로 대체

  3. 전체 소문자로 변환

  4. 연속 공백을 단일 공백으로 축소

  5. 띄어쓰기를 안 쓰는 언어(중국어, 일본어, 태국어, 라오어, 버마어 등)는 문자 단위로 분리 → 사실상 CER(Character Error Rate)에 해당

여러 데이터셋에서, 이러한 표준화를 적용한 결과 WER이 최대 50%까지 감소하는 것을 관찰했다. 주로 전사 규칙상의 사소한 관례 때문이었는데, 예를 들어 일부 데이터셋에서는 수축형(contractions)을 공백으로 분리해 표기한 경우 등이 있었다.

다만 우리는 이 과정이 Whisper 모델의 전사 스타일에 과적합(overfitting)될 위험이 있다고 경고한다. 따라서 Section 4.4에서 이를 추가로 조사했다.

우리의 텍스트 표준화 코드를 공개하여, 다른 연구자들이 쉽게 비교하거나 분포 외(out-of-distribution) 환경에서 음성 인식 시스템의 성능을 연구할 수 있도록 했다.

3.3. 영어 음성 인식

2015년, Deep Speech 2(Amodei et al., 2015)는 LibriSpeech의 test-clean 분할을 전사할 때 인간 수준의 성능에 도달한 음성 인식 시스템을 보고했다. 그들은 분석에서 다음과 같이 결론지었다. “이 결과를 고려하면, 추가적인 도메인 적응 없이 깨끗한 낭독 음성에 대해 범용 음성 시스템이 더 개선할 여지는 거의 없다고 의심한다.” 그러나 7년 뒤, LibriSpeech test-clean의 최신 SOTA WER(단어 오류율)는 5.3%에서 1.4%로 추가로 73% 하락하여( Zhang et al., 2021) 그들이 보고한 인간 수준 오류율 5.8%를 한참 밑돌게 되었다. 이렇게 보류(held-out)되었지만 분포 내(in-distribution) 데이터에서의 성능이 예상 밖으로 대폭 개선되었음에도, LibriSpeech로 학습된 음성 인식 모델들은 다른 환경에서 사용되면 여전히 인간 오류율보다 훨씬 높다. 분포 내에서의 ‘초인간적’ 성능과 분포 밖(out-of-distribution)에서의 ‘인간 이하’ 성능 사이의 이 격차는 무엇으로 설명될까?

ASR 성능은 엄청 좋지만, 다른 테스크? OOD 상황에서는 성능은 별로다

우리는 이 격차의 큰 부분이, 동일한 시험에서 측정되는 인간과 기계의 “능력”이 서로 다른데도 이를 혼동하기 때문이라고 본다. 같은 시험을 치른다면 어떻게 다른 기술이 측정된다고 말할 수 있을까? 차이는 시험 그 자체가 아니라 훈련 방식에서 생긴다. 인간은 대개 특정 데이터 분포에 대한 감독(supervision)이 거의 없거나 전혀 없는 상태에서 과제를 수행하라는 요구를 받는다. 따라서 인간 성능은 분포 밖 일반화의 척도다. 반면 기계학습 모델은 보통 평가 분포에서 나온 대량의 감독으로 훈련된 뒤 평가되므로, 기계 성능은 분포 내 일반화의 척도다. 즉 같은 테스트 데이터로 평가하더라도, 훈련 데이터의 차이 때문에 사실은 꽤 다른 두 능력을 재고 있는 셈이다.

넓고 다양한 오디오 분포로 훈련되고 제로샷 설정에서 평가되는 Whisper 모델은, 기존 시스템보다 인간의 행동을 훨씬 더 잘 닮을 잠재력이 있다. 이것이 사실인지(아니면 기계와 인간 성능의 차이가 아직 이해되지 않은 요인들 때문인지) 확인하기 위해, 우리는 Whisper 모델을 인간 성능표준적으로 미세조정된 기계학습 모델 양쪽과 비교하여 어느 쪽에 더 가까운지 살펴볼 수 있다.


이 차이를 정량화하기 위해 우리는 두 가지를 본다. 

  • (1) 여러 분포/데이터셋에 걸친 평균 성능으로서의 전반적 강건성(robustness)
  • (2) Taori et al.(2020)이 도입한 유효 강건성(effective robustness) 으로, 이는 보통 분포 내 기준(reference) 데이터셋과 하나 이상의 분포 밖 데이터셋 사이의 예상 성능 차이를 측정한다. 
유효 강건성이 높은 모델은 기준 데이터셋에서의 성능을 감안할 때 기대치보다 분포 밖 데이터셋에서 더 잘 동작하며, 모든 데이터셋에서 같은 성능에 가까워진다. 우리의 분석에서 기준 데이터셋은 LibriSpeech로, 이는 현대 음성 인식 연구의 중심적 역할과 그로 훈련된 공개 모델이 많아 강건성 특성을 파악하기에 적합하기 때문이다. 분포 밖 행동을 연구하기 위해 우리는 12개의 다른 학술 음성 인식 데이터셋 묶음을 사용했다(자세한 목록은 부록 A).

주요 발견그림 2표 2에 요약했다. 

최고 제로샷 Whisper 모델의 LibriSpeech test-clean WER는 2.5로(현대의 지도학습 기준선이나 2019년 중반 SOTA 수준에 해당) 그다지 눈에 띄지 않지만, 제로샷 WhisperLibriSpeech로 미세조정된 모델들과 전혀 다른 강건성 특성을 보이며, 

  • 다른 데이터셋에서는 모든 LibriSpeech 모델들을 큰 폭으로 앞선다
  • 파라미터 3,900만 개인 가장 작은 제로샷 Whisper조차 LibriSpeech test-clean WER가 6.7인데, 다른 데이터셋으로 평가하면 최고의 LibriSpeech 지도 모델과 대략 비슷하게 경쟁한다. 
  • 그림 2에서 인간과 비교하면, 최고 제로샷 Whisper 모델들은 정확도와 강건성에서 인간을 대략적으로 맞춘다
강건성 향상의 세부 분해는 표 2가 보여준다. 
  • 여기서는 LibriSpeech test-clean에서 성능이 가장 가까운 지도 LibriSpeech 모델최고 제로샷 Whisper를 비교한다. 
  • 기준 분포에서의 성능은 거의 같음에도, 제로샷 Whisper는 다른 음성 인식 데이터셋들에서 평균 상대 오류 55.2% 감소를 달성한다.

이 발견은, 특히 인간과 비교하려는 경우 제로샷 및 분포 밖 평가를 강조해야 함을 시사한다. 그렇지 않으면 오해를 부르는 비교 때문에 기계학습 시스템의 능력을 과대평가할 수 있다.

논문에서 말하는 핵심은 단순히 ASR 성능(LibriSpeech 같은 분포 내 데이터)만 가지고 평가하면 모델 능력을 과대평가할 수 있다는 거예요.

  • 예를 들어, LibriSpeech에서 인간 수준 WER을 넘었다고 해도, 다른 데이터셋(잡음 환경, 다른 도메인 발화 등)에서는 성능이 크게 떨어집니다.
  • 그래서 분포 밖(OOD) 평가가 중요하다는 거죠.

Whisper는 넓고 다양한 음성 데이터로 학습했기 때문에, 별도의 fine-tuning 없이 제로샷 평가에서도 OOD 상황에서 강건성이 높습니다.

  • 즉, Whisper는 LibriSpeech에서의 성능은 최신 fine-tuned 모델들과 비슷하거나 조금 뒤지지만, **다른 데이터셋(OOD)**에서는 fine-tuning 기반 모델들을 압도합니다.

3.4. 다국어 음성 인식

우리는 Whisper 모델의 다국어 음성 인식 능력을, **제로샷 전이(transfer)**와 언어별 성능이라는 두 가지 차원에서 분석한다. Whisper 모델은 학습 데이터 분포 내의 거의 모든 언어에서 제로샷 전이가 잘 작동하는데, 이는 (음성 인식뿐만 아니라) 음성-텍스트 번역에서도 이미 증명된 바 있다. 모델은 원본 음성이 어떤 언어로 되어 있는지를 가리키는 언어 토큰을 출력으로 내도록 설계되었고, 이후의 전사 과정은 다른 언어 전사에서 훈련된 것과 동일한 디코더 메커니즘을 재사용한다. 따라서 모델은 영어 음성 인식에서 학습된 디코딩 능력을, 데이터가 더 적은 언어의 인식에도 곧바로 적용할 수 있다.

그림 3은 9가지 대표적인 언어 데이터셋에서의 전사 성능을 보여준다. 

  • 가로축은 학습된 언어에 대한 양이고, 세로축은 성능(WER)이다.
  • 즉 학습이 많이되는 언어일수록 그 언어의 성능은 향상됨
  • 한국어는 약간 추세선에 벗어나있는군..?

모델은 모든 언어에서 분명히 강건한 제로샷 성능을 보였고, 영어와 가장 가까운 성능은 스페인어였다. 이는 스페인어가 학습 데이터에서 영어 다음으로 가장 많이 등장한 언어이기 때문이다. 반대로, 상대적으로 데이터가 적었던 태갈로그어나 스와힐리어 같은 언어는 성능이 뒤처졌지만, 여전히 기존의 지도학습 기반 접근법과 견줄 수 있는 성능을 보였다.

언어별 세부적인 성능을 보면, Whisper 모델은 데이터 크기에 비례해 성능이 점진적으로 향상되는 경향을 보인다. 즉, 데이터가 많은 언어일수록 인식 오류율(WER)이 낮고, 데이터가 적은 언어일수록 성능이 떨어진다. 그러나 중요한 점은, 데이터가 충분히 부족한 언어라 해도 Whisper는 단순한 지도학습 모델을 초과하는 강건성을 유지한다는 것이다. 이는 Whisper가 **다국어 학습의 이점을 공유하는 다언어 표현(multilingual representation)**을 효과적으로 학습했음을 의미한다.

이러한 결과는 Whisper가 단순히 영어 음성 인식에서만 뛰어난 것이 아니라, 광범위한 다국어 환경에서도 제로샷 강건성을 확보하고 있음을 보여준다. 이는 곧 Whisper가 전 세계 다양한 언어 환경에서 음성 인식 시스템을 구축하는 데 유용할 잠재력을 지닌다는 점을 시사한다.

3.5. 번역

Whisper 모델은 전사뿐 아니라 **음성 번역(speech translation)**도 수행한다. 모델은 입력 음성을 원래 언어로 전사하는 대신, 영어로 번역된 텍스트를 출력하도록 학습되었다. 훈련 과정에서 번역 작업을 위한 **특수 토큰(<|translate|>)**을 제공받으며, 이는 전사 태스크(<|transcribe|>)와 병렬적으로 학습된다.

제로샷 설정에서 Whisper는 다국어 음성을 입력받아 영어 번역을 생성할 수 있으며, 이는 특히 영어를 모국어로 사용하지 않는 사용자들에게 강력한 기능이 될 수 있다. 번역 능력은 데이터셋 크기와 언어 자원에 따라 차이를 보이지만, 대체로 기존의 음성 번역(SLT: Speech-to-Text Translation) 시스템과 경쟁할 수 있는 성능을 달성한다.

학습데이터에 스페셜토큰으로 타언어->영어 번역 데이터를 넣었는데, 잘 발현되고, 기존의 S2T translation 시스템과 비슷한 수준이라고 하는듯

또한 Whisper는 텍스트 번역기와 달리 직접 음성에서 영어 텍스트로 번역하기 때문에, 중간에 원문 전사 단계가 필요하지 않다. 이 방식은 특히 저자원 언어에서, 전사 모델과 번역 모델을 별도로 연결할 때 발생할 수 있는 누적 오류(error propagation)를 줄여준다.

실험적으로, Whisper는 다수의 공용 음성 번역 벤치마크에서 기존의 **파이프라인 접근법(ASR + MT)**에 필적하거나 이를 능가하는 성능을 보였으며, 이는 종단간(end-to-end) 음성 번역 접근법의 장점을 잘 보여준다. Whisper의 대규모 다국어 학습이 이러한 일반화 능력에 중요한 역할을 했음을 알 수 있다.

3.6. 언어 식별(Language Identification)

Whisper 모델은 음성 인식이나 번역을 하기 전에, 먼저 입력 음성이 어떤 언어인지 식별해야 한다. 이를 위해 모델은 디코딩을 시작하기 전에 몇 초 분량의 오디오를 받아, 출력할 언어 토큰을 예측한다. 이 과정은 Whisper 학습에 포함된 다국어 태스크의 일부로 통합되어 있으며, 별도의 추가 훈련 없이 모델이 스스로 학습한다.

우리는 Whisper의 언어 식별 성능을 **FLEURS 데이터셋(Conneau et al., 2022)**에서 평가했다. Whisper는 63개 언어에 대해 제로샷 언어 식별을 수행했으며, 전체 평균 정확도는 99% 이상으로 나타났다. 즉, Whisper는 대부분의 경우 입력 음성이 어떤 언어인지 매우 정확하게 맞출 수 있다.

특히, 저자원 언어에 대해서도 Whisper는 기존의 공개 언어 식별 모델을 초과하는 성능을 보였다. 이는 Whisper가 단순히 음성 인식만 잘하는 것이 아니라, 다국어 음성 전처리(front-end) 기능을 강하게 내재화하고 있음을 보여준다. 이러한 특성 덕분에 Whisper는 완전한 종단간 다국어 음성 처리 시스템으로서 활용될 수 있는 가능성을 갖춘다.

  • 예: 스페인어 음성이면 <|es|><|transcribe|> 같은 조건 하에 학습.
  • 논문에 따르면, 디코딩을 시작하기 전에 몇 초 분량 오디오만 보고 모델에게 언어 토큰을 먼저 출력하게 합니다.
  • 별도 classifier를 두지 않고, 그냥 Whisper의 디코더가 첫 토큰으로 언어를 내뱉도록 유도하는 거예요.

3.7. 가산 잡음(Additive Noise)에 대한 견고성

우리는 Whisper 모델과 LibriSpeech로 학습된 14개의 모델을 대상으로, 오디오에 백색 잡음(white noise) 또는 Audio Degradation Toolbox(Mauch & Ewert, 2013)의 펍 소음(pub noise)을 합성하여 추가했을 때의 WER(단어 오류율)를 측정함으로써 잡음 견고성을 평가했다. 

여기서 펍 소음은 붐비는 식당이나 펍에서 흔히 나타나는 환경음과 알아듣기 힘든 잡담이 섞인, 보다 자연스러운 소음 환경을 나타낸다. 14개 모델 가운데 12개는 LibriSpeech로 사전학습 및/또는 미세조정된 모델이며, 나머지 2개는 LibriSpeech를 포함한 SpeechStew류의 혼합 데이터셋으로 학습된 NVIDIA STT 모델이다. 주어진 신호대잡음비(SNR)에 대응하는 가산 잡음의 세기는 각 예제의 신호 세기에 기반해 계산하였다. 

그림 5는 가산 잡음이 강해질수록 ASR 성능이 어떻게 저하되는지를 보여준다. 낮은 잡음(40 dB SNR) 구간에서는, 해당 모델들이 주로 LibriSpeech로 학습되었다는 점을 감안하면 놀랍지 않게, 우리의 제로샷 성능을 능가하는 모델들이 여럿 존재한다. 그러나 잡음이 더 강해지면 모든 모델의 성능이 빠르게 저하되어, SNR이 10 dB 미만인 펍 소음 조건의 경우 Whisper 모델보다 더 나쁜 성능을 보인다. 이는 특히 펍 소음처럼 보다 자연스러운 분포 변화를 겪을 때 Whisper의 잡음에 대한 견고성을 보여준다.

(참고: 그림 5는 8쪽—백색 잡음/펍 소음에서 SNR 감소에 따라 WER가 증가하는 추세를 비교하며, 낮은 잡음에서는 NVIDIA STT가 우세하지만 높은 잡음(SNR < 10 dB)에서는 Whisper가 앞섬.)

  • SNR이 낮아지는것은, 신호대비 노이즈가 커지기 때문에  WER도 증가하는 그림임
  • Whisper가 노이즈가 클때 WER 성능이 좋게 나오는 형식이라는 것

3.8. 장문 전사(Long-form Transcription)

지금까지의 벤치마크 과제들은 비교적 짧은 길이의 클립으로 이루어져 있었는데, Whisper 모델은 훨씬 긴 입력을 처리할 수 있다. 긴 오디오를 전사하기 위해서는 두 가지 어려움이 따른다.

첫째, 입력이 모델의 맥락 윈도우(context window)를 초과하는 경우, 오디오를 분할(chunking)해야 한다. 분할의 단점은 모델이 이전 분할에 대한 정보가 없기 때문에, 인접한 구간에서 동일한 말뭉치가 중복되거나(말을 반복해서 전사) 빠져버리는(말이 누락되는) 오류가 발생할 수 있다는 점이다.

둘째, 사람이 발화할 때 흔히 나타나는 주저함, 반복, 자기 수정과 같은 현상을 모델이 문자 그대로 전사할 수도 있다는 것이다. 이는 정확한 기록이 필요한 회의록 같은 경우에는 유용할 수 있지만, 깔끔한 읽기용 전사가 필요한 상황에서는 문제가 된다.

이 문제들을 해결하기 위해 우리는 두 가지 기법을 적용했다.

  1. 컨텍스트 보강(contextual biasing): 이전 분할에서 모델이 생성한 텍스트 일부를 현재 분할의 프롬프트로 제공하여, 전사가 일관되게 이어지도록 한다.

  2. 텍스트 후처리(post-processing): 단어 반복, 간단한 실수, 불필요한 주저함 등을 규칙 기반으로 제거하여 가독성을 개선한다.

우리는 이러한 방식을 적용해 한 시간 길이의 팟캐스트, 강연, 인터뷰를 전사해 보았고, Whisper가 긴 맥락에서도 안정적인 전사를 생성할 수 있음을 확인했다. 특히 잡음 환경이나 발화자가 여러 명일 때에도 비교적 잘 작동했다.

(참고: 부록 D에서는 긴 오디오 전사 실험에 대한 구체적인 예시를 포함한다.) 

학습 데이터에 긴 오디오 샘플들이 있었기도 했고, 인퍼런스시 chunking, 컨텍스트보강, 텍스트 후처리를 통해 가독성을 늘렸다다는 것

3.9. 인간 성능과의 비교 (Comparison with Human Performance)

ASR 시스템의 성능을 평가할 때 흔히 **인간 전사자(human transcriber)**와 비교한다. 그러나 이 비교는 몇 가지 주의할 점이 있다.
첫째, 인간 전사자의 성능은 상황과 과제에 따라 크게 달라진다. 전문적으로 숙련된 전사자는 매우 낮은 WER(단어 오류율)을 보일 수 있지만, 그렇지 않은 사람은 훨씬 높은 오류율을 낼 수 있다.
둘째, 인간 전사는 보통 단순히 오디오만 듣고 이루어지는 것이 아니라, 컨텍스트, 화자의 배경지식, 주제에 대한 이해 등을 활용하기 때문에 기계 전사와는 조건 자체가 다르다.

우리는 기존 연구에서 보고된 인간 전사 성능 수치를 수집해 Whisper와 비교하였다. LibriSpeech test-clean 세트에서 전문가 전사자의 WER는 약 5.5%이고, 일반 아마추어 전사자는 약 8.0%로 보고되었다(Panayotov et al., 2015). 

  • 반면, 우리의 Whisper 모델은 동일한 세트에서 제로샷(추가 학습 없이) 약 2.7%의 WER을 기록했다. 이는 인간 전사자의 평균을 능가하는 결과다.
  • WER이 대략 5%면 사람성능 정도라 볼 수 있나봄

하지만 LibriSpeech는 비교적 깨끗한 오디오 환경이기 때문에, 다른 데이터셋에서 인간과 모델을 비교하는 것이 더 의미 있다. 

  • Switchboard(전화 대화) 데이터셋에서는 인간 전사자의 WER가 약 5.1%로 알려져 있으며(Xie et al., 2021), Whisper의 제로샷 성능은 그보다 높았다(즉, 더 많은 오류). 
  • 이는 Whisper가 특정 도메인(예: 전화 대화)에 대해 인간보다 여전히 뒤처진다는 점을 보여준다.
  • 다른 데이터에서는 인간이 Whisper보다 좋았다

따라서 Whisper는 깨끗하고 명확한 발화에서는 이미 인간 수준을 넘어서지만, 잡음이 많거나 구어체적이고 도메인 특화된 상황에서는 여전히 인간 전사자의 강점을 따라잡지 못한다는 결론을 얻을 수 있다.

잡음 환경에서는 Whisper < 인간 이라는 결과. 근데, 다른 모델들보다는 잡음에 강건하긴 했음

4. 분석 및 절제(Analysis and Ablations)

4.1. 모델 스케일링 (Model Scaling)

  • 약한(supervised but noisy) 대규모 데이터 학습의 핵심 가치는 훨씬 큰 데이터셋을 활용할 수 있다는 점.

  • 하지만 데이터 품질이 낮을 수 있어 모델이 한계에 도달하거나 데이터 특이성에 과적합할 우려가 있음.

  • Whisper 모델의 제로샷 일반화를 모델 크기별로 분석한 결과:

    • 다국어 음성 인식, 음성 번역, 언어 식별은 모델 크기가 커질수록 성능 계속 향상.

    • 영어 음성 인식은 수익 체감(diminishing returns)이 나타남 → 이미 인간 수준 성능에 근접했기 때문일 수 있음.

  • 그림 8 (p.11): 모델 크기(매개변수 수)에 따라 WER/ BLEU/ 정확도가 꾸준히 개선되는 추세를 보여줌.


4.2. 데이터셋 스케일링 (Dataset Scaling)

  • Whisper는 68만 시간으로, 가장 큰 감독 학습 기반 음성 데이터셋 중 하나.

  • 동일한 모델(중간 크기)을 이용해 데이터셋 크기를 0.5% ~ 8% 수준으로 줄여 학습 → 전체 데이터셋 학습 결과와 비교.

  • 결과 (표 6, p.11):

    • 영어 음성 인식은 3천~1.3만 시간까지 급격히 개선, 이후 개선 폭 줄어듦. 전체 데이터 사용 시에도 WER이 추가 1%p만 감소.

    • 다국어 음성 인식은 5.4만 시간까지는 power-law 개선, 그 이후에는 둔화.

    • X→En 번역은 7천 시간 이하는 거의 학습 불가, 이후 로그-선형적으로 개선하다가 역시 둔화.

  • 결론: 54,000시간 이상부터는 체감 효과, 더 큰 모델/더 긴 학습 필요.

약간 특정 포인트까진 데이터 증가시키는게 효과적인데, 그 지점을 넘어가면 효율성이 떨어지는 느낌인가봄

4.3. 멀티태스크·다국어 전이 (Multitask and Multilingual Transfer)

  • 한 모델이 여러 언어·태스크를 동시에 학습하면 부정적 전이(negative transfer) 가능성 있음.

  • 분석 결과 (그림 9, p.12):

    • 작은 모델에서는 실제로 부정적 전이 발생 → 영어 전용 모델보다 성능 떨어짐.

    • 하지만 큰 모델에서는 긍정적 전이(positive transfer) 가 나타나 오히려 영어 전용 모델보다 우수.

    • 즉, 스케일이 커질수록 멀티태스크 학습이 유리.

모델 사이즈가 너무 작으면, 한계가 있는 느낌. 여러 언어를 처리하는 모델을 만들거면 모델 사이즈가 크긴 해야한다

4.4. 텍스트 정규화 (Text Normalization)

  • Whisper에 맞춰 텍스트 정규화를 개발했는데, 모델 특이성에 과적합되었을 위험 존재.

  • FairSpeech 프로젝트의 별도 정규화기와 비교 (그림 10, p.12):

    • 대부분 데이터셋에서는 두 정규화기의 효과 유사.

    • 하지만 WSJ, CallHome, Switchboard에서는 Whisper용 정규화기가 WER을 훨씬 더 많이 줄임.

    • 예: "you’re vs you are", "$68M vs sixty-eight million dollars" 같은 경우에 차이 발생.

  • 결론: Whisper용 정규화기가 일부 데이터셋에서는 유리하게 작동했음.


4.5. 장문 전사를 위한 전략 (Strategies for Reliable Long-form Transcription)

  • Whisper는 30초 단위만 입력 가능 → 장문 오디오(분~시간 단위) 전사에는 추가 전략 필요.

  • 개발한 휴리스틱들:

    • 빔 서치(beam search, 5 beams) → 반복 루프 줄임.

    • 온도 스케줄링(temperature fallback) → 로그 확률이 낮거나 텍스트 압축률이 높으면 온도 증가.

    • 이전 윈도우 텍스트를 컨텍스트로 제공(previous-text conditioning).

    • 무음 감지: <|nospeech|> 토큰 확률과 로그 확률 함께 사용.

    • 시작 구간 누락 방지: 첫 타임스탬프를 0~1초로 강제.

  • 표 7 (p.13): 각 기법을 점진적으로 추가할 때 성능(WER)이 개선되는 모습.

👉 요약하면, 모델/데이터 규모 확대는 분명한 성능 개선을 가져왔으나, 영어 음성 인식에서는 인간 성능에 근접하면서 개선 폭이 줄었고, 멀티태스크/다국어 학습은 스케일이 클수록 긍정적 효과를 발휘했습니다. 또한 정규화와 장문 처리 전략이 Whisper의 실용성에 중요한 역할을 했습니다.

6. 한계와 향후 과제 (Limitations and Future Work)

우리의 실험 결과, 분석, 그리고 절제(ablation) 연구를 통해 몇 가지 한계와 향후 연구 과제를 확인하였다.

  1. 개선된 디코딩 전략

    • Whisper 모델이 커질수록 비슷하게 들리는 단어를 혼동하는 지각(perceptual) 관련 오류는 줄어들었음.

    • 하지만 장문 전사(long-form transcription)에서는 여전히 비인간적이고 비지각적(non-human/perceptual) 오류가 남아 있음.

    • 대표적인 오류 유형:

      • 반복 루프에 빠짐.

      • 입력 오디오의 처음/마지막 단어 누락.

      • 오디오와 무관한 전혀 다른 텍스트(환각) 생성.

    • 4.5절에서 논의한 디코딩 기법들이 이를 완화하긴 했으나,

      • 고품질 지도 데이터로 파인튜닝하거나,

      • 강화학습을 통해 디코딩 성능 최적화하는 방식이 필요할 수 있음.

  2. 저자원 언어에 대한 학습 데이터 확충

    • 그림 3에서 보듯, Whisper는 여전히 많은 언어에서 성능이 낮음.

    • 그러나 특정 언어에서의 성능은 그 언어의 학습 데이터 양과 강한 상관관계가 있음.

    • 현재 데이터셋은 인터넷에서 영어 중심으로 수집되어 대부분의 언어가 1,000시간 미만 데이터만 확보.

    • 따라서 저자원 언어 데이터를 추가로 확보하면, 전체 데이터 규모를 크게 늘리지 않고도 평균 성능을 크게 향상시킬 수 있음.

  3. 파인튜닝(fine-tuning)에 대한 연구 필요

    • 본 연구에서는 제로샷 전이 성능에 집중했음. 이는 일반적이고 광범위한 신뢰성을 평가하는 데 중요.

    • 그러나 고품질 음성 데이터가 존재하는 특정 도메인에서는 파인튜닝을 통해 더 나은 결과를 얻을 수 있음.

    • 또한 파인튜닝은 기존 연구와 직접 비교할 수 있는 더 일반적인 평가 설정이라는 장점도 있음.

  4. 언어 모델이 강건성에 미치는 영향 연구

    • Whisper의 강건성은 강력한 디코더(오디오 조건부 언어모델) 덕분이라고 가정.

    • 그러나 실제로는 인코더 학습, 디코더 학습, 또는 둘 다의 효과가 얼마인지 불분명.

    • 이를 알아보기 위해:

      • CTC 기반 디코더 없는 모델을 학습해보거나,

      • 기존 음성 인식 인코더(wav2vec 2.0 등)를 언어모델과 결합했을 때 성능 변화를 연구할 수 있음.

  5. 보조 학습 목표 추가

    • Whisper는 최근 음성 인식 SOTA 시스템들과 달리 비지도 사전학습이나 자기학습(self-teaching) 기법을 사용하지 않음.

    • 본 연구에서는 그 없이도 좋은 성능을 얻었지만,

    • 이러한 기법을 통합하면 성능을 더 끌어올릴 가능성이 있음.

7. Conclusion

위스퍼는 약지도 학습 사전 학습의 확장이 음성 인식 연구에서 지금까지 과소평가되어 왔다고 주장합니다. 본 연구에서는 최근 대규모 음성 인식 연구의 핵심이었던 자가 지도 학습 및 자가 학습 기법을 사용하지 않고도 결과를 도출했으며, 대규모의 다양한 지도 학습 데이터셋을 기반으로 학습하고 제로 샷 전이에 집중하는 것만으로도 음성 인식 시스템의 강건성을 크게 향상시킬 수 있음을 보여줍니다.

Reference

댓글