Whisper語音大模型:弱監(jiān)督scaling law的威力

本期介紹OpenAI在ICML 2023發(fā)布的語音大模型Whisper: Robust Speech Recognition via Large-Scale Weak Supervision。

一、弱監(jiān)督做語音識別

ASR(Automatic Speech Recognition, 自動語音識別),就是傳入聲音波形,傳出對應(yīng)的字幕。傳統(tǒng)的自監(jiān)督預(yù)訓(xùn)練+有監(jiān)督微調(diào)(如wav2vec 2.0, Neurips 2020)這條路和NLP、CV一樣似乎走得很順。自監(jiān)督預(yù)訓(xùn)練學(xué)習(xí)通用的聲學(xué)表征,有監(jiān)督微調(diào)得找些人工標(biāo)注的數(shù)據(jù),最后可能再加一個糾錯處理(比如掛一個外部語言模型,或者整點(diǎn)后處理規(guī)則。

語音比NLP走得慢,涌現(xiàn)能力出現(xiàn)得晚,一個很大的原因是數(shù)據(jù)少很多。NLP里,GPT2到3的時(shí)候,呼啦一下把整個互聯(lián)網(wǎng)的數(shù)據(jù)都盤下來了,一下子聰明了好幾檔。反觀那時(shí)候語音還在吭哧吭哧給數(shù)據(jù)打標(biāo)簽。那么,為何不直接用從互聯(lián)網(wǎng)去找海量音頻來訓(xùn)練?Whisper就做出來了,它收集了網(wǎng)上68萬小時(shí)弱標(biāo)注音頻-文本對,比如YouTube視頻配上自動字幕,播客和文字轉(zhuǎn)錄等等,這些數(shù)據(jù)的質(zhì)量自然是比不上精心標(biāo)注的,但勝在量大覆蓋廣管飽。接下來看看量大的弱監(jiān)督如何匹敵精選的全監(jiān)督。

二、架構(gòu)老兩樣:Encoder-Decoder Transformer

Whisper的模型架構(gòu)幾乎沒有什么新花樣,就是一個標(biāo)準(zhǔn)的Encoder-Decoder Transformer,結(jié)構(gòu)上和翻譯模型一脈相承。具體的結(jié)構(gòu)流程我們稍后從頭到尾細(xì)講。

2.1 音頻預(yù)處理

原始音頻首先被重采樣到16kHz單聲道(這樣人能聽到的最高頻是8kHz,反正比瑪利亞·凱麗的3kHz海豚音要高多了),然后通過短時(shí)傅里葉變換(STFT, n_fft=400, hop_length=160)提取頻譜,再經(jīng)過Mel濾波器組投影并取對數(shù),得到log-Mel頻譜圖。例如,Whisper接受的輸入都是裁成30秒音頻,這30秒在16kHz采樣率下有480000個采樣點(diǎn),經(jīng)STFT后得到約3000幀。每一幀通過Mel濾波器用一個向量表示,Whisper-v1/v2中這個向量的維度是80,v3升級到了128。接著這個形狀是[n_mels, 3000]的頻譜圖就作為輸入送入Encoder了。(音頻的慣用預(yù)處理,可以參見Grad-TTS的科普)

2.2 Audio Encoder

Encoder首先用兩層一維卷積對頻譜做下采樣。第一層卷積將n_mels維投影到d_model維,第二層卷積通過stride=2實(shí)現(xiàn)2倍下采樣,將3000幀壓縮為1500幀。然后加上正弦位置編碼(不學(xué)習(xí)的、固定的sinusoidal編碼,好處是30秒固定長度也玩不出什么花兒來,又少了一些要優(yōu)化的東西),再過N層標(biāo)準(zhǔn)Transformer Encoder Block(Self-Attention + FFN,Pre-LayerNorm結(jié)構(gòu)),最后一個LayerNorm收尾:

class AudioEncoder(nn.Module):
    def __init__(self, n_mels, n_ctx, n_state, n_head, n_layer):
        self.conv1 = Conv1d(n_mels, n_state, kernel_size=3, padding=1)
        self.conv2 = Conv1d(n_state, n_state, kernel_size=3, stride=2, padding=1)
        self.register_buffer("positional_embedding", sinusoids(n_ctx, n_state))
        self.blocks = nn.ModuleList(
            [ResidualAttentionBlock(n_state, n_head) for _ in range(n_layer)]
        )
        self.ln_post = LayerNorm(n_state)

ViT的patch embedding也是這么干的,連續(xù)信號離散化為token序列,再交給Transformer處理。

2.3 Text Decoder

Decoder則是一個標(biāo)準(zhǔn)的自回歸Transformer Decoder。
與Encoder不同的是,位置編碼是可學(xué)習(xí)的,因?yàn)檫@時(shí)候語種token、任務(wù)token、時(shí)間戳、文本……什么亂七八糟的符號都進(jìn)來了,它們互相交織在一起,其實(shí)也未必是一個順序的關(guān)系,還是學(xué)一學(xué)更能領(lǐng)悟任務(wù)的實(shí)質(zhì)。由于支持最大長度448個token,這部分的計(jì)算開銷也不容小覷。
第二個不同是每個Block多了一個Cross-Attention層,這是自然的,下一個生成什么字,除了看字本身,還得看原來的語音長什么樣。Q來自Decoder的隱狀態(tài),K和V來自Encoder的輸出,NLP的慣常操作。
另一個慣常操作是因果掩碼(causal mask),防止看到未來token,不多講了。
輸出層與token embedding共享權(quán)重,這也很自然,上一個文字token和自回歸的這一個文字token都在一個embedding空間里,誰和誰又有差別呢,文字乘到embedding的,再用轉(zhuǎn)置乘回來回到原來的空間。即輸出logits = x @ token_embedding.weight.T

class TextDecoder(nn.Module):
    def __init__(self, n_vocab, n_ctx, n_state, n_head, n_layer):
        self.token_embedding = nn.Embedding(n_vocab, n_state)
        self.positional_embedding = nn.Parameter(torch.empty(n_ctx, n_state))
        self.blocks = nn.ModuleList(
            [ResidualAttentionBlock(n_state, n_head, cross_attention=True)
             for _ in range(n_layer)]
        )
        self.ln = LayerNorm(n_state)
        ...
    def forward(self, x: Tensor, xa: Tensor, kv_cache: Optional[dict] = None):
        ...
        offset = next(iter(kv_cache.values())).shape[1] if kv_cache else 0
        x = (
            self.token_embedding(x)
            + self.positional_embedding[offset : offset + x.shape[-1]]
        )
        ...
        logits = (
            x @ torch.transpose(self.token_embedding.weight.to(x.dtype), 0, 1)
        ).float()
        return logits

2.4 訓(xùn)好的現(xiàn)成果實(shí),后面有誰來摘?

Whisper的Encoder和Decoder在后續(xù)研究中被分別復(fù)用于不同場景:

Encoder被用作通用音頻特征提取器。Qwen-Audio系列直接凍結(jié)Whisper large-v2的Encoder(32層Transformer),接一個投影層映射到LLM的嵌入空間,再用Qwen LLM做Decoder。這種做法保留了Whisper的聲學(xué)理解能力,同時(shí)獲得了LLM的語言生成能力,可以做語音問答、音頻理解等更復(fù)雜任務(wù)。類似地,許多多模態(tài)大模型也把Whisper Encoder當(dāng)作現(xiàn)成的audio backbone。

Decoder被蒸餾或替換。Whisper-large-v3-turbo直接把Decoder從32層剪枝到4層,通過知識蒸餾保留了大部分能力。Distil-Whisper也是類似思路,壓縮Decoder以提高推理速度。

三、模型家族&任務(wù)

Whisper提供了一系列不同規(guī)模的模型,結(jié)構(gòu)差異主要體現(xiàn)在層數(shù)和隱藏維度上:

模型 參數(shù)量 Enc層數(shù) Dec層數(shù) d_model 注意力頭 FFN維度 Mel維度
tiny 39M 4 4 384 6 1536 80
base 74M 6 6 512 8 2048 80
small 244M 12 12 768 12 3072 80
medium 769M 24 24 1024 16 4096 80
large (v1/v2) 1550M 32 32 1280 20 5120 80
large-v3 1550M 32 32 1280 20 5120 128
large-v3-turbo 809M 32 4 1280 20 5120 128

幾個值得注意的設(shè)計(jì):

  • 每個注意力頭的維度始終為64(d_model / n_head = 64)
  • FFN維度始終為4×d_model
  • 從tiny到large,寬度增長3.3倍(從384到1280),深度增長8倍(從4到32)
  • turbo特殊一點(diǎn),保留了32層Encoder但把Decoder砍到只剩4層,參數(shù)量減半但推理速度提升8倍

適合什么硬件?

模型 推理顯存 微調(diào)顯存(Full) 微調(diào)顯存(LoRA) 推薦推理卡 推薦訓(xùn)練卡
tiny ~1GB ~2GB ~1.5GB 任意GPU/CPU 任意GPU
base ~1GB ~3GB ~2GB 任意GPU/CPU 任意GPU
small ~2GB ~6GB ~3GB RTX 3060+ RTX 3080+
medium ~5GB ~12GB ~6GB RTX 3080+ RTX 3090/A100
large ~10GB ~24GB+ ~12GB A100/RTX 4090 A100 80GB
turbo ~6GB ~16GB ~8GB RTX 3090+ RTX 4090/A100

medium需要3090/A100級別的顯卡,但在多數(shù)任務(wù)上和large差距不大。large系列通常需要多卡或者至少A100 80GB才能做全參數(shù)微調(diào),但LoRA微調(diào)的話單卡4090也勉強(qiáng)可以。

訓(xùn)練了多久?

OpenAI沒公開各模型的確切訓(xùn)練時(shí)長和GPU-hours。Whisper-large-v2說v2在v1的基礎(chǔ)上又訓(xùn)了2.5倍的時(shí)間。根據(jù)社區(qū)估計(jì)和Epoch AI的數(shù)據(jù),large模型的訓(xùn)練量級大約在數(shù)千到數(shù)萬GPU-hours。對于小模型,社區(qū)微調(diào)的經(jīng)驗(yàn)是:在單卡A100上,small模型對幾百小時(shí)的領(lǐng)域數(shù)據(jù)做LoRA微調(diào),通常幾天就可以收斂。

不同模型能做的任務(wù)

所有多語言模型(tiny到large)理論上都支持這些任務(wù):轉(zhuǎn)錄、翻譯、99種語言識別、時(shí)間戳對齊。不過在實(shí)踐中:

  • tiny/base:英語轉(zhuǎn)錄尚可,多語言和翻譯能力較弱,時(shí)間戳精度低,適合對延遲和資源敏感的場景
  • small/medium:多語言能力提升,翻譯質(zhì)量好用,時(shí)間戳也可靠,是大多數(shù)應(yīng)用的主力
  • large :多語言和翻譯能力最強(qiáng),低資源語言表現(xiàn)最好
  • turbo:推理速度最快,可惜不支持做翻譯任務(wù),只能做轉(zhuǎn)錄

此外,tiny和base有專門的English-only版本(tiny.en、base.en等),在純英語場景下性能略優(yōu)于同級別的多語言版本,因?yàn)樗鼈兊脑~表中沒有99種語言的token,所有容量都專注于英語。

四、一些細(xì)節(jié)魔鬼

4.1 SOT token

Whisper用一套特殊Start-of-Transcript (SOT) token序列統(tǒng)一多個任務(wù)。當(dāng)然我們熟知的GPT-4, T5, Flamingo都這么干,只不過Whisper的token更結(jié)構(gòu)化一點(diǎn)。解碼器的輸入格式是:

<|startoftranscript|> <|語言|> <|任務(wù)|> [時(shí)間戳/文本] <|endoftext|>

具體來說,

  • 中文轉(zhuǎn)錄:<|startoftranscript|><|zh|><|transcribe|><|0.00|>今天天氣很好<|1.20|><|endoftext|>
  • 中譯英:<|startoftranscript|><|zh|><|translate|>The weather is nice today<|endoftext|>
  • 語言識別:輸入<|startoftranscript|>,看下一個token預(yù)測為哪個語言token

whisper/tokenizer.py代碼中可以看到,詞表包含:

  • 51865個基礎(chǔ)token(GPT-2的BPE分詞器擴(kuò)展到多語言)
  • 99個語言token(<|en|>、<|zh|>、<|ja|>等)
  • 任務(wù)token(<|transcribe|>、<|translate|>
  • 1501個時(shí)間戳token(<|0.00|><|30.00|>,精度20ms)
  • 一些些輔助token(<|nospeech|>、<|notimestamps|>等)

4.2 這些任務(wù)從機(jī)理上是如何實(shí)現(xiàn)的?

對于ASR,Decoder看到<|transcribe|>這個條件token后,生成的分布會偏向源語言的token。
對于翻譯,因?yàn)橛?xùn)練數(shù)據(jù)里面有大量翻譯對(非英語視頻配有英語字幕),模型靠在這些數(shù)據(jù)上訓(xùn)練學(xué)會了在<|translate|>條件下把源語言語音映射到英語文本。
對于自動語言識別,Decoder輸入<|startoftranscript|>這一個token,對下一個位置的logits在所有99個語言token上做softmax,argmax就可以得到最可能的語言。在轉(zhuǎn)錄中,如果你不指定語言,transcribe()函數(shù)也用前30秒做語言檢測,然后用檢測到的語言做后續(xù)轉(zhuǎn)錄。(這樣的話對中英混合有一定的處理能力)
對于時(shí)間戳對齊,Whisper通過Cross-Attention權(quán)重和DTW(Dynamic Time Warping,動態(tài)時(shí)間規(guī)整)算法實(shí)現(xiàn)。先提取Decoder中特定Cross-Attention頭的注意力權(quán)重,這些權(quán)重反映了文本token和音頻幀之間的對應(yīng)關(guān)系,再通過DTW找到最優(yōu)對齊路徑,從而得到每個詞的起止時(shí)間。

Whisper也有不能做的。它不支持說話人區(qū)分。因?yàn)樗?xùn)練的時(shí)候就沒有speaker embedding或者speaker標(biāo)簽。的輸出,也沒有說話人切換的標(biāo)注。

能實(shí)現(xiàn)說話人區(qū)分的主流方案有:

  • pyannote-audio:先用pyannote做說話人分割,得到"誰在什么時(shí)間段說話"的信息,再用Whisper對每個片段做轉(zhuǎn)錄,最后合并。
  • WhisperX:在Whisper基礎(chǔ)上集成了forced alignment和pyannote diarization,所以提供word-level的時(shí)間戳和說話人標(biāo)簽。
  • NeMo:NVIDIA的框架也提供了端到端的ASR+Diarization pipeline。

效果方面,pyannote在DER(Diarization Error Rate)上通??梢赃_(dá)到5-10%的水平,配合Whisper做轉(zhuǎn)錄的整體效果,那就要取決于音頻質(zhì)量和說話人重疊程度了。要是兩人清晰對話場景下,那還表現(xiàn)不錯,要是多人重疊交談場景可就是業(yè)界難題了。

4.3 30秒窗口

Whisper把音頻切分為30秒的片段,生成好后拼接結(jié)果。這個設(shè)計(jì)壞處是跨片段的上下文被截?cái)?。為了緩解這個問題,transcribe()函數(shù)實(shí)現(xiàn)了一個condition_on_previous_text機(jī)制:它把上一個片段的輸出文本作為prompt喂給下一個片段的Decoder,幫助保持上下文的連貫性。

4.4 解碼策略

Whisper支持Greedy Decoding和Beam Search兩種解碼策略,greedy直接取argmax,Beam Search選beam_size=5,但可以超過5,也就是支持patience機(jī)制,允許在max_candidates = beam_size × patience個候選收集了再挑后面最好的,拿時(shí)間換質(zhì)量。

greedy溫度是0,beam溫度是5,Whisper還可以采用溫度回退的策略,先用temperature=0做greedy解碼,如果檢測到輸出質(zhì)量不好就逐步升高溫度重試,直到得到一個可接受的結(jié)果。

五、性能表現(xiàn)

Whisper large-v2的zero-shot表現(xiàn)如下:

  • 英語(LibriSpeech test-clean):WER約4.2%,接近人類水平(約5.2%)。

  • 中文(Common Voice / Fleurs):CER約10-12%,屬于可用但不頂尖的水平。中文在Whisper的訓(xùn)練數(shù)據(jù)中占比不高(遠(yuǎn)少于英語的65%),所以原生表現(xiàn)中規(guī)中矩。相比之下,同時(shí)期專門在中文數(shù)據(jù)上訓(xùn)練的模型表現(xiàn)更好:

    • 訊飛、阿里FunASR(Paraformer)、百度DeepSpeech等,CER通常在3-5%
    • Whisper large-v3微調(diào)后、騰訊ASR等,CER在5-8%
    • Whisper原生(不微調(diào))、Google Speech-to-Text等,CER在10-15%
  • 低資源語言:表現(xiàn)參差不齊,數(shù)據(jù)量大的語言(西班牙語、法語等)WER在5-8%,數(shù)據(jù)量小的語言WER可能高達(dá)30%+。

large-v3相比v2在中文上有明顯進(jìn)步(從CER12.5%降到10.8%),主要得益于Mel濾波器從80維升級到128維——更細(xì)的頻率分辨率對中文聲調(diào)語言更敏銳,能捕捉更多特質(zhì)。

七、評價(jià)

對學(xué)術(shù)界的影響

Whisper對后續(xù)研究的影響是深遠(yuǎn)的:

  1. 驗(yàn)證了弱監(jiān)督scaling law,證明了語音領(lǐng)域同樣適用"大數(shù)據(jù)+大模型"的范式,無需精心標(biāo)注的小數(shù)據(jù)集;
  2. 成為事實(shí)上的baseline,幾乎所有新的ASR論文都會和Whisper做對比;
  3. 催生了一系列衍生工作,WhisperX(精細(xì)對齊+說話人分離)、Distil-Whisper(蒸餾加速)、faster-whisper(推理優(yōu)化)、whisper.cpp(輕量化的C++移植,可在手機(jī)上運(yùn)行);
  4. 推動了多模態(tài)研究,Whisper Encoder成為音頻多模態(tài)模型的標(biāo)準(zhǔn)組件(Qwen-Audio、SALMONN等);
  5. 降低了ASR的門檻,開源、免費(fèi)、多語言,而且有標(biāo)準(zhǔn)化的微調(diào)流程,讓語音技術(shù)有種飛入尋常百姓家的感覺。

優(yōu)點(diǎn)

剛才已經(jīng)說了,零樣本就能開做、多語言多任務(wù)、開源免費(fèi)、微調(diào)友好,好處太多。

缺點(diǎn)

不支持說話人區(qū)分、流式推理(有30秒窗口限制),非英語性能有限、混合語種處理欠佳。

展望

在Whisper之后,OpenAI在其API中持續(xù)迭代語音能力,GPT-4o已經(jīng)支持原生語音輸入輸出。而開源社區(qū)的Whisper生態(tài)也在不斷壯大(見上文的衍生工作),各類多模態(tài)大模型借助Whisper Encoder實(shí)現(xiàn)了各顯神通的音頻理解能力??梢哉f,Whisper的真正貢獻(xiàn)不僅是一個高質(zhì)量的ASR模型,更像是為整個社區(qū)提供了一個基礎(chǔ)設(shè)施。就像GPT-3之于NLP、CLIP之于視覺語言,Whisper之于語音識別,也是一個劃時(shí)代的錨點(diǎn)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • """1.個性化消息: 將用戶的姓名存到一個變量中,并向該用戶顯示一條消息。顯示的消息應(yīng)非常簡單,如“Hello ...
    她即我命閱讀 5,349評論 0 6
  • 1、expected an indented block 冒號后面是要寫上一定的內(nèi)容的(新手容易遺忘這一點(diǎn)); 縮...
    庵下桃花仙閱讀 1,103評論 1 2
  • 一、工具箱(多種工具共用一個快捷鍵的可同時(shí)按【Shift】加此快捷鍵選取)矩形、橢圓選框工具 【M】移動工具 【V...
    墨雅丫閱讀 1,620評論 0 0
  • 跟隨樊老師和伙伴們一起學(xué)習(xí)心理知識提升自已,已經(jīng)有三個月有余了,這一段時(shí)間因?yàn)樘鞖獾脑蛐菡n,順便整理一下之前學(xué)習(xí)...
    學(xué)習(xí)思考行動閱讀 1,022評論 0 2
  • 一臉憤怒的她躺在了床上,好幾次甩開了他抱過來的雙手,到最后還堅(jiān)決的翻了個身,只留給他一個冷漠的背影。 多次嘗試抱她...
    海邊的藍(lán)兔子閱讀 1,026評論 1 4

友情鏈接更多精彩內(nèi)容