在🤗 Transformers中用n-gram提升Wav2Vec2

釋出於2022年1月12日
在 GitHub 上更新
Open In Colab

Wav2Vec2是用於語音識別的流行預訓練模型。該新穎架構於2020年9月由Meta AI Research釋出,它推動了語音識別自監督預訓練的進展,例如G. Ng et al., 2021Chen et al, 2021Hsu et al., 2021Babu et al., 2021。在Hugging Face Hub上,Wav2Vec2最受歡迎的預訓練檢查點目前每月下載量超過250,000

使用連線時序分類(CTC),Wav2Vec2類預訓練檢查點在下游語音識別任務上極易進行微調。簡而言之,微調預訓練Wav2Vec2檢查點的工作原理如下:

一個隨機初始化的線性層堆疊在預訓練檢查點之上,並經過訓練將原始音訊輸入分類為字母序列。它透過以下方式實現:

  1. 從原始音訊中提取音訊表示(使用CNN層),
  2. 使用一堆Transformer層處理音訊表示序列,以及
  3. 將處理後的音訊表示分類為輸出字母序列。

以前的音訊分類模型需要額外的語言模型(LM)和字典才能將分類的音訊幀序列轉換為連貫的轉錄。Wav2Vec2的架構基於Transformer層,因此為每個處理過的音訊表示提供了所有其他音訊表示的上下文。此外,Wav2Vec2利用CTC演算法進行微調,該演算法解決了可變“輸入音訊長度”-到-“輸出文字長度”比率之間的對齊問題。

由於具有語境化音訊分類且沒有對齊問題,Wav2Vec2不需要外部語言模型或字典即可生成可接受的音訊轉錄。

正如官方論文附錄C所示,Wav2Vec2在LibriSpeech上表現出令人印象深刻的下游效能,完全沒有使用語言模型。然而,從附錄中也可以清楚地看到,將Wav2Vec2與語言模型結合使用可以帶來顯著的改進,特別是當模型僅在10分鐘的轉錄音訊上進行訓練時。

直到最近,🤗 Transformers庫還沒有提供一個簡單的使用者介面來使用經過微調的Wav2Vec2語言模型解碼音訊檔案。幸運的是,這種情況已經改變了。🤗 Transformers現在提供了與Kensho Technologiespyctcdecode庫的易用整合。這篇部落格文章是一個分步技術指南,解釋如何建立n-gram語言模型並將其與現有的微調Wav2Vec2檢查點結合使用🤗 Datasets和🤗 Transformers。

我們首先:

  1. 使用LM解碼音訊與不使用LM解碼音訊有何不同?
  2. 如何為語言模型獲取合適的資料?
  3. 如何使用KenLM構建一個n-gram
  4. 如何將n-gram與微調的Wav2Vec2檢查點結合?

要深入瞭解Wav2Vec2的工作原理(對於本部落格文章來說不是必需的),建議讀者查閱以下材料:

1. 使用Wav2Vec2和語言模型解碼音訊資料

如🤗 Transformers Wav2Vec2的示例文件所示,音訊可以按以下方式轉錄。

首先,我們安裝 datasetstransformers

pip install datasets transformers

讓我們載入Librispeech資料集的一小部分,以演示Wav2Vec2的語音轉錄能力。

from datasets import load_dataset

dataset = load_dataset("hf-internal-testing/librispeech_asr_demo", "clean", split="validation")
dataset

輸出

    Reusing dataset librispeech_asr (/root/.cache/huggingface/datasets/hf-internal-testing___librispeech_asr/clean/2.1.0/f2c70a4d03ab4410954901bde48c54b85ca1b7f9bf7d616e7e2a72b5ee6ddbfc)

    Dataset({
        features: ['file', 'audio', 'text', 'speaker_id', 'chapter_id', 'id'],
        num_rows: 73
    })

我們可以選擇73個音訊樣本中的一個並聆聽它。

audio_sample = dataset[2]
audio_sample["text"].lower()

輸出

    he tells us that at this festive season of the year with christmas and roast beef looming before us similes drawn from eating and its results occur most readily to the mind

選擇了資料樣本後,我們現在載入微調模型和處理器。

from transformers import Wav2Vec2Processor, Wav2Vec2ForCTC

processor = Wav2Vec2Processor.from_pretrained("facebook/wav2vec2-base-100h")
model = Wav2Vec2ForCTC.from_pretrained("facebook/wav2vec2-base-100h")

接下來,我們處理資料

inputs = processor(audio_sample["audio"]["array"], sampling_rate=audio_sample["audio"]["sampling_rate"], return_tensors="pt")

將其轉發給模型

import torch

with torch.no_grad():
  logits = model(**inputs).logits

並解碼它

predicted_ids = torch.argmax(logits, dim=-1)
transcription = processor.batch_decode(predicted_ids)

transcription[0].lower()

輸出

'he tells us that at this festive season of the year with christmaus and rose beef looming before us simalyis drawn from eating and its results occur most readily to the mind'

將轉錄與上面的目標轉錄進行比較,我們可以看到一些單詞聽起來正確,但拼寫不正確,例如:

  • christmaus vs. christmas
  • rose vs. roast
  • simalyis vs. similes

讓我們看看將Wav2Vec2與n-gram語言模型結合是否有幫助。

首先,我們需要安裝pyctcdecodekenlm

pip install https://github.com/kpu/kenlm/archive/master.zip pyctcdecode

為了演示目的,我們準備了一個新的模型庫patrickvonplaten/wav2vec2-base-100h-with-lm,它包含相同的Wav2Vec2檢查點,但額外包含一個用於英語的4-gram語言模型。

這次我們不使用Wav2Vec2Processor,而是使用Wav2Vec2ProcessorWithLM來載入4-gram模型以及特徵提取器和分詞器。

from transformers import Wav2Vec2ProcessorWithLM

processor = Wav2Vec2ProcessorWithLM.from_pretrained("patrickvonplaten/wav2vec2-base-100h-with-lm")

與不使用語言模型解碼音訊不同,現在處理器直接接收模型的輸出logits,而不是上面的argmax(logits)(稱為predicted_ids)。原因是,當使用語言模型解碼時,在每個時間步,處理器會考慮所有可能的輸出字元的機率。讓我們看一下logits輸出的維度。

logits.shape

輸出

    torch.Size([1, 624, 32])

我們可以看到logits對應於一個由624個向量組成的序列,每個向量有32個條目。其中每個32個條目代表模型32個可能輸出字元之一的邏輯機率

" ".join(sorted(processor.tokenizer.get_vocab()))

輸出

"' </s> <pad> <s> <unk> A B C D E F G H I J K L M N O P Q R S T U V W X Y Z |"

直觀地看,可以理解Wav2Vec2ProcessorWithLM的解碼過程,即在624 × 32機率矩陣上應用束搜尋,同時利用n-gram語言模型提供的下一個字母的機率。

好的,我們再執行一次解碼步驟。pyctcdecode語言模型解碼器不會自動將torch張量轉換為numpy,因此我們必須先自行轉換它們。

transcription = processor.batch_decode(logits.numpy()).text
transcription[0].lower()

輸出

'he tells us that at this festive season of the year with christmas and rose beef looming before us similes drawn from eating and its results occur most readily to the mind'

太棒了!回顧之前facebook/wav2vec2-base-100h在沒有語言模型時轉錄錯誤的單詞,例如:

  • christmaus vs. christmas
  • rose vs. roast
  • simalyis vs. similes

我們可以再次看一下帶4-gram語言模型的facebook/wav2vec2-base-100h的轉錄。3個錯誤中有2個被糾正;christmassimiles已被正確轉錄。

有趣的是,rose的錯誤轉錄依然存在。然而,這不應該讓我們感到非常驚訝。不帶語言模型解碼音訊更容易產生拼寫錯誤,例如christmaussimiles(據我所知,這些詞在英語中不存在)。這是因為語音識別系統幾乎完全基於其獲得的聲學輸入進行預測,而不是真正基於先前和後續預測字母的語言建模上下文1 {}^1 。另一方面,如果我們新增語言模型,我們可以相當確定語音識別系統會大大減少拼寫錯誤,因為一個訓練有素的n-gram模型肯定不會預測帶有拼寫錯誤的單詞。但是rose是一個有效的英語單詞,因此4-gram模型會以不低的機率預測這個單詞。

語言模型本身最有可能支援正確的單詞roast,因為單詞序列roast beef在英語中比rose beef更常見。因為最終的轉錄是根據facebook/wav2vec2-base-100h輸出機率和n-gram語言模型的加權組合得出的,所以看到rose這樣錯誤轉錄的單詞是很常見的。

有關如何在使用Wav2Vec2ProcessorWithLM解碼時調整不同引數的更多資訊,請參閱此處的官方文件。


1{}^1 一些研究表明,像facebook/wav2vec2-base-100h這樣的模型——當足夠大且在足夠多的資料上訓練時——可以學習中間音訊表示之間的語言建模依賴性,類似於語言模型。

太棒了,現在你已經看到了新增n-gram語言模型所帶來的優勢,讓我們深入瞭解如何從頭開始建立n-gramWav2Vec2ProcessorWithLM

2. 獲取語言模型所需資料

對語音識別系統有用的語言模型應該支援聲學模型(例如Wav2Vec2)預測下一個單詞(或標記、字母),因此應該建模以下分佈:P(wnw0t1) \mathbf{P}(w_n | \mathbf{w}_0^{t-1}) ,其中wn w_n 是下一個單詞,而w0t1 \mathbf{w}_0^{t-1} 是從話語開始以來所有先前單詞的序列。簡單來說,語言模型應該善於根據所有先前轉錄的單詞預測下一個單詞,而不管給語音識別系統的音訊輸入是什麼。

與往常一樣,語言模型的好壞取決於其訓練資料。在語音識別的情況下,我們應該問自己語音識別將用於哪種資料:對話有聲讀物電影演講等等……?

語言模型應善於對與語音識別系統目標轉錄相對應的語言進行建模。為演示目的,我們假設這裡我們已經在一個預訓練的facebook/wav2vec2-xls-r-300m上對瑞典語的Common Voice 7進行了微調。微調後的檢查點可在此處找到。Common Voice 7是一個相對眾包的朗讀音訊資料集,我們將在其測試資料上評估模型。

現在讓我們在Hugging Face Hub上尋找合適的文字資料。我們搜尋所有包含瑞典語資料的資料集。瀏覽了一下資料集後,我們正在尋找一個與Common Voice的朗讀音訊資料相似的資料集。明顯的選擇oscarmc4可能不是最合適的,因為它們

  • 由網路爬取生成,可能不夠乾淨,與口語不太對應
  • 需要大量的預處理
  • 體量非常大,不適合這裡的演示目的 😉

europarl_bilingual資料集在這裡看起來很合理,它相對乾淨且易於預處理,因為它是一個基於歐洲議會討論和演講的資料集。因此,它應該相對乾淨,並且與朗讀音訊資料很好地對應。該資料集最初是為機器翻譯設計的,因此只能以翻譯對的形式訪問。我們將只從英語到瑞典語的翻譯中提取目標語言(瑞典語,sv)的文字。

target_lang="sv"  # change to your target lang

讓我們下載資料。

from datasets import load_dataset

dataset = load_dataset("europarl_bilingual", lang1="en", lang2=target_lang, split="train")

我們看到資料量相當大——它有超過一百萬條翻譯。不過,由於它只是文字資料,處理起來應該相對容易。

接下來,我們看看在瑞典語微調XLS-R檢查點時資料是如何預處理的。檢視run.sh檔案,我們可以看到以下字元已從官方轉錄中刪除:

chars_to_ignore_regex = '[,?.!\-\;\:"“%‘”�—’…–]'  # change to the ignored characters of your fine-tuned model

我們在這裡也這樣做,以便我們的語言模型的字母表與微調聲學檢查點的字母表匹配。

我們可以編寫一個簡單的對映函式來提取瑞典語文字並立即處理它。

import re

def extract_text(batch):
  text = batch["translation"][target_lang]
  batch["text"] = re.sub(chars_to_ignore_regex, "", text.lower())
  return batch

讓我們應用.map()函式。這應該需要大約5分鐘。

dataset = dataset.map(extract_text, remove_columns=dataset.column_names)

太棒了。讓我們把它上傳到Hub,以便我們更好地檢查和重用它。

您可以透過執行以下單元格來登入。

from huggingface_hub import notebook_login

notebook_login()

輸出

    Login successful
    Your token has been saved to /root/.huggingface/token
    Authenticated through git-credential store but this isn't the helper defined on your machine.
    You might have to re-authenticate when pushing to the Hugging Face Hub. Run the following command in your terminal in case you want to set this credential helper as the default

    git config --global credential.helper store

接下來,我們呼叫 🤗 Hugging Face 的 push_to_hub 方法,將資料集上傳到倉庫 "sv_corpora_parliament_processed"

dataset.push_to_hub(f"{target_lang}_corpora_parliament_processed", split="train")

那太容易了!上傳新資料集時,資料集檢視器會自動啟用,這非常方便。您現在可以直接線上檢查資料集。

歡迎直接在hf-test/sv_corpora_parliament_processed上瀏覽我們預處理過的資料集。即使我們不是瑞典語母語者,我們也可以看到資料處理得很好,並且看起來很乾淨。

接下來,我們使用資料構建一個語言模型。

3. 使用KenLM構建一個n-gram

儘管基於Transformer架構的大型語言模型已成為自然語言處理的標準,但使用n-gram語言模型來提升語音識別系統仍然非常普遍——如第1節所示。

再次檢視官方Wav2Vec2論文附錄C的表9,可以注意到,使用基於Transformer的語言模型進行解碼明顯優於使用n-gram模型,但n-gram與基於Transformer的語言模型之間的差異遠小於n-gram與無語言模型之間的差異。

例如,對於僅在10分鐘資料上進行微調的大型Wav2Vec2檢查點,n-gram與無語言模型相比,詞錯誤率(WER)降低了約80%,而基於Transformer的語言模型與n-gram相比,WER額外降低了23%。這種相對WER降低的幅度會隨著聲學模型訓練資料量的增加而減小。例如,對於大型檢查點,基於Transformer的語言模型與n-gram語言模型相比,WER僅降低了8%,而n-gram與無語言模型相比,WER仍降低了21%。

n-gram模型優於基於Transformer的語言模型的原因在於,n-gram模型的計算成本顯著更低。對於n-gram模型,給定先前單詞獲取單詞機率的計算開銷幾乎只相當於查詢一個查詢表或樹狀資料儲存——也就是說,與現代基於Transformer的語言模型相比,n-gram模型非常快,後者需要完整的正向傳播才能獲取下一個單詞的機率。

有關n-gram如何工作以及為何它們(仍然)對語音識別如此有用的更多資訊,建議讀者查閱斯坦福大學的這份優秀總結

太棒了,讓我們一步步看看如何構建一個n-gram。我們將使用流行的KenLM庫來實現。首先安裝Ubuntu庫的先決條件:

sudo apt install build-essential cmake libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-test-dev libeigen3-dev zlib1g-dev libbz2-dev liblzma-dev

在下載並解壓KenLM倉庫之前。

wget -O - https://kheafield.com/code/kenlm.tar.gz | tar xz

KenLM是用C++編寫的,所以我們將使用cmake來構建二進位制檔案。

mkdir kenlm/build && cd kenlm/build && cmake .. && make -j2
ls kenlm/build/bin

太好了,正如我們所見,可執行函式已成功構建在kenlm/build/bin/下。

KenLM預設使用Kneser-Ney平滑計算n-gram。所有用於建立n-gram的文字資料都應儲存在一個文字檔案中。我們下載資料集並將其儲存為.txt檔案。

from datasets import load_dataset

username = "hf-test"  # change to your username

dataset = load_dataset(f"{username}/{target_lang}_corpora_parliament_processed", split="train")

with open("text.txt", "w") as file:
  file.write(" ".join(dataset["text"]))

現在,我們只需執行KenLM的lmplz命令來構建我們的n-gram,名為"5gram.arpa"。在語音識別中,構建5-gram相對常見,我們透過傳入-o 5引數來實現。有關KenLM可構建的不同n-gram語言模型的更多資訊,可以檢視KenLM的官方網站

執行以下命令可能需要大約一分鐘。

kenlm/build/bin/lmplz -o 5 <"text.txt" > "5gram.arpa"

輸出

    === 1/5 Counting and sorting n-grams ===
    Reading /content/swedish_text.txt
    ----5---10---15---20---25---30---35---40---45---50---55---60---65---70---75---80---85---90---95--100
    tcmalloc: large alloc 1918697472 bytes == 0x55d40d0f0000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b28c51e 0x55d40b26b2eb 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    tcmalloc: large alloc 8953896960 bytes == 0x55d47f6c0000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b2e07ca 0x55d40b2e1208 0x55d40b26b308 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    ****************************************************************************************************
    Unigram tokens 42153890 types 360209
    === 2/5 Calculating and sorting adjusted counts ===
    Chain sizes: 1:4322508 2:1062772928 3:1992699264 4:3188318720 5:4649631744
    tcmalloc: large alloc 4649631744 bytes == 0x55d40d0f0000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b2e07ca 0x55d40b2e1208 0x55d40b26b8d7 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    tcmalloc: large alloc 1992704000 bytes == 0x55d561ce0000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b2e07ca 0x55d40b2e1208 0x55d40b26bcdd 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    tcmalloc: large alloc 3188326400 bytes == 0x55d695a86000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b2e07ca 0x55d40b2e1208 0x55d40b26bcdd 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    Statistics:
    1 360208 D1=0.686222 D2=1.01595 D3+=1.33685
    2 5476741 D1=0.761523 D2=1.06735 D3+=1.32559
    3 18177681 D1=0.839918 D2=1.12061 D3+=1.33794
    4 30374983 D1=0.909146 D2=1.20496 D3+=1.37235
    5 37231651 D1=0.944104 D2=1.25164 D3+=1.344
    Memory estimate for binary LM:
    type      MB
    probing 1884 assuming -p 1.5
    probing 2195 assuming -r models -p 1.5
    trie     922 without quantization
    trie     518 assuming -q 8 -b 8 quantization 
    trie     806 assuming -a 22 array pointer compression
    trie     401 assuming -a 22 -q 8 -b 8 array pointer compression and quantization
    === 3/5 Calculating and sorting initial probabilities ===
    Chain sizes: 1:4322496 2:87627856 3:363553620 4:728999592 5:1042486228
    ----5---10---15---20---25---30---35---40---45---50---55---60---65---70---75---80---85---90---95--100
    ####################################################################################################
    === 4/5 Calculating and writing order-interpolated probabilities ===
    Chain sizes: 1:4322496 2:87627856 3:363553620 4:728999592 5:1042486228
    ----5---10---15---20---25---30---35---40---45---50---55---60---65---70---75---80---85---90---95--100
    ####################################################################################################
    === 5/5 Writing ARPA model ===
    ----5---10---15---20---25---30---35---40---45---50---55---60---65---70---75---80---85---90---95--100
    ****************************************************************************************************
    Name:lmplz	VmPeak:14181536 kB	VmRSS:2199260 kB	RSSMax:4160328 kB	user:120.598	sys:26.6659	CPU:147.264	real:136.344

太棒了,我們已經構建了一個5-gram語言模型!讓我們檢查一下前幾行。

head -20 5gram.arpa

輸出

    \data\
    ngram 1=360208
    ngram 2=5476741
    ngram 3=18177681
    ngram 4=30374983
    ngram 5=37231651

    \1-grams:
    -6.770219	<unk>	0
    0	<s>	-0.11831701
    -4.6095004	återupptagande	-1.2174699
    -2.2361007	av	-0.79668784
    -4.8163533	sessionen	-0.37327805
    -2.2251768	jag	-1.4205662
    -4.181505	förklarar	-0.56261665
    -3.5790775	europaparlamentets	-0.63611007
    -4.771945	session	-0.3647111
    -5.8043895	återupptagen	-0.3058712
    -2.8580177	efter	-0.7557702
    -5.199537	avbrottet	-0.43322718

有一個小問題,🤗 Transformers之後會不高興。這個5-gram正確地包含了“未知”或<unk>,以及句首標記<s>,但沒有句尾標記</s>。不幸的是,目前必須在構建後進行修正。

我們可以簡單地在“句首”標記下方新增一行0 </s> -0.11831701,並將ngram 1計數增加1,從而新增“句尾”標記。由於檔案大約有1億行,此命令將耗時約2分鐘。

with open("5gram.arpa", "r") as read_file, open("5gram_correct.arpa", "w") as write_file:
  has_added_eos = False
  for line in read_file:
    if not has_added_eos and "ngram 1=" in line:
      count=line.strip().split("=")[-1]
      write_file.write(line.replace(f"{count}", f"{int(count)+1}"))
    elif not has_added_eos and "<s>" in line:
      write_file.write(line)
      write_file.write(line.replace("<s>", "</s>"))
      has_added_eos = True
    else:
      write_file.write(line)

現在讓我們檢查更正後的5-gram

head -20 5gram_correct.arpa

輸出

    \data\
    ngram 1=360209
    ngram 2=5476741
    ngram 3=18177681
    ngram 4=30374983
    ngram 5=37231651

    \1-grams:
    -6.770219	<unk>	0
    0	<s>	-0.11831701
    0	</s>	-0.11831701
    -4.6095004	återupptagande	-1.2174699
    -2.2361007	av	-0.79668784
    -4.8163533	sessionen	-0.37327805
    -2.2251768	jag	-1.4205662
    -4.181505	förklarar	-0.56261665
    -3.5790775	europaparlamentets	-0.63611007
    -4.771945	session	-0.3647111
    -5.8043895	återupptagen	-0.3058712
    -2.8580177	efter	-0.7557702

太棒了,這樣看起來好多了!我們到此為止,剩下的就是將"ngram"正確地整合到pyctcdecode和🤗 Transformers中。

4. 將n-gram與Wav2Vec2結合

最後一步,我們將5-gram封裝到Wav2Vec2ProcessorWithLM物件中,使5-gram增強解碼像第1節所示那樣無縫。我們首先下載xls-r-300m-sv當前“無LM”的處理器。

from transformers import AutoProcessor

processor = AutoProcessor.from_pretrained("hf-test/xls-r-300m-sv")

接下來,我們提取其分詞器的詞彙表,因為它代表了pyctcdecodeBeamSearchDecoder類的"labels"

vocab_dict = processor.tokenizer.get_vocab()
sorted_vocab_dict = {k.lower(): v for k, v in sorted(vocab_dict.items(), key=lambda item: item[1])}

"labels"和之前構建的5gram_correct.arpa檔案是構建解碼器所需的全部。

from pyctcdecode import build_ctcdecoder

decoder = build_ctcdecoder(
    labels=list(sorted_vocab_dict.keys()),
    kenlm_model_path="5gram_correct.arpa",
)

輸出

    Found entries of length > 1 in alphabet. This is unusual unless style is BPE, but the alphabet was not recognized as BPE type. Is this correct?
    Unigrams and labels don't seem to agree.

我們可以安全地忽略警告,現在剩下的就是將剛剛建立的decoder與處理器的tokenizerfeature_extractor一起封裝到Wav2Vec2ProcessorWithLM類中。

from transformers import Wav2Vec2ProcessorWithLM

processor_with_lm = Wav2Vec2ProcessorWithLM(
    feature_extractor=processor.feature_extractor,
    tokenizer=processor.tokenizer,
    decoder=decoder
)

我們希望將LM增強的處理器直接上傳到xls-r-300m-sv的模型資料夾中,以便將所有相關檔案放在一處。

讓我們克隆倉庫,新增新的解碼器檔案,然後上傳它們。首先,我們需要安裝git-lfs

sudo apt-get install git-lfs tree

使用huggingface_hubRepository類可以方便地克隆和上傳建模檔案。

有關如何使用huggingface_hub上傳任何檔案的更多資訊,請參閱官方文件

from huggingface_hub import Repository

repo = Repository(local_dir="xls-r-300m-sv", clone_from="hf-test/xls-r-300m-sv")

輸出

    Cloning https://huggingface.co/hf-test/xls-r-300m-sv into local empty directory.

克隆xls-r-300m-sv後,讓我們將新的帶有LM的處理器儲存到其中。

processor_with_lm.save_pretrained("xls-r-300m-sv")

讓我們檢查一下本地倉庫。tree命令可以方便地顯示不同檔案的大小。

tree -h xls-r-300m-sv/

輸出

    xls-r-300m-sv/
    ├── [  23]  added_tokens.json
    ├── [ 401]  all_results.json
    ├── [ 253]  alphabet.json
    ├── [2.0K]  config.json
    ├── [ 304]  emissions.csv
    ├── [ 226]  eval_results.json
    ├── [4.0K]  language_model
    │   ├── [4.1G]  5gram_correct.arpa
    │   ├── [  78]  attrs.json
    │   └── [4.9M]  unigrams.txt
    ├── [ 240]  preprocessor_config.json
    ├── [1.2G]  pytorch_model.bin
    ├── [3.5K]  README.md
    ├── [4.0K]  runs
    │   └── [4.0K]  Jan09_22-00-50_brutasse
    │       ├── [4.0K]  1641765760.8871996
    │       │   └── [4.6K]  events.out.tfevents.1641765760.brutasse.31164.1
    │       ├── [ 42K]  events.out.tfevents.1641765760.brutasse.31164.0
    │       └── [ 364]  events.out.tfevents.1641794162.brutasse.31164.2
    ├── [1.2K]  run.sh
    ├── [ 30K]  run_speech_recognition_ctc.py
    ├── [ 502]  special_tokens_map.json
    ├── [ 279]  tokenizer_config.json
    ├── [ 29K]  trainer_state.json
    ├── [2.9K]  training_args.bin
    ├── [ 196]  train_results.json
    ├── [ 319]  vocab.json
    └── [4.0K]  wandb
        ├── [  52]  debug-internal.log -> run-20220109_220240-1g372i3v/logs/debug-internal.log
        ├── [  43]  debug.log -> run-20220109_220240-1g372i3v/logs/debug.log
        ├── [  28]  latest-run -> run-20220109_220240-1g372i3v
        └── [4.0K]  run-20220109_220240-1g372i3v
            ├── [4.0K]  files
            │   ├── [8.8K]  conda-environment.yaml
            │   ├── [140K]  config.yaml
            │   ├── [4.7M]  output.log
            │   ├── [5.4K]  requirements.txt
            │   ├── [2.1K]  wandb-metadata.json
            │   └── [653K]  wandb-summary.json
            ├── [4.0K]  logs
            │   ├── [3.4M]  debug-internal.log
            │   └── [8.2K]  debug.log
            └── [113M]  run-1g372i3v.wandb

    9 directories, 34 files

如您所見,5-gram LM相當大——它超過4GB。為了減小n-gram的大小並加快載入速度,kenLM允許使用build_binary可執行檔案將.arpa檔案轉換為二進位制檔案。

讓我們在這裡利用它。

kenlm/build/bin/build_binary xls-r-300m-sv/language_model/5gram_correct.arpa xls-r-300m-sv/language_model/5gram.bin

輸出

    Reading xls-r-300m-sv/language_model/5gram_correct.arpa
    ----5---10---15---20---25---30---35---40---45---50---55---60---65---70---75---80---85---90---95--100
    ****************************************************************************************************
    SUCCESS

太棒了,成功了!讓我們刪除.arpa檔案,並檢查二進位制5-gram語言模型的大小。

rm xls-r-300m-sv/language_model/5gram_correct.arpa && tree -h xls-r-300m-sv/

輸出

    xls-r-300m-sv/
    ├── [  23]  added_tokens.json
    ├── [ 401]  all_results.json
    ├── [ 253]  alphabet.json
    ├── [2.0K]  config.json
    ├── [ 304]  emissions.csv
    ├── [ 226]  eval_results.json
    ├── [4.0K]  language_model
    │   ├── [1.8G]  5gram.bin
    │   ├── [  78]  attrs.json
    │   └── [4.9M]  unigrams.txt
    ├── [ 240]  preprocessor_config.json
    ├── [1.2G]  pytorch_model.bin
    ├── [3.5K]  README.md
    ├── [4.0K]  runs
    │   └── [4.0K]  Jan09_22-00-50_brutasse
    │       ├── [4.0K]  1641765760.8871996
    │       │   └── [4.6K]  events.out.tfevents.1641765760.brutasse.31164.1
    │       ├── [ 42K]  events.out.tfevents.1641765760.brutasse.31164.0
    │       └── [ 364]  events.out.tfevents.1641794162.brutasse.31164.2
    ├── [1.2K]  run.sh
    ├── [ 30K]  run_speech_recognition_ctc.py
    ├── [ 502]  special_tokens_map.json
    ├── [ 279]  tokenizer_config.json
    ├── [ 29K]  trainer_state.json
    ├── [2.9K]  training_args.bin
    ├── [ 196]  train_results.json
    ├── [ 319]  vocab.json
    └── [4.0K]  wandb
        ├── [  52]  debug-internal.log -> run-20220109_220240-1g372i3v/logs/debug-internal.log
        ├── [  43]  debug.log -> run-20220109_220240-1g372i3v/logs/debug.log
        ├── [  28]  latest-run -> run-20220109_220240-1g372i3v
        └── [4.0K]  run-20220109_220240-1g372i3v
            ├── [4.0K]  files
            │   ├── [8.8K]  conda-environment.yaml
            │   ├── [140K]  config.yaml
            │   ├── [4.7M]  output.log
            │   ├── [5.4K]  requirements.txt
            │   ├── [2.1K]  wandb-metadata.json
            │   └── [653K]  wandb-summary.json
            ├── [4.0K]  logs
            │   ├── [3.4M]  debug-internal.log
            │   └── [8.2K]  debug.log
            └── [113M]  run-1g372i3v.wandb

    9 directories, 34 files

太棒了,我們將n-gram的大小減少了一半以上,現在不到2GB。最後一步,讓我們上傳所有檔案。

repo.push_to_hub(commit_message="Upload lm-boosted decoder")

輸出

    Git LFS: (1 of 1 files) 1.85 GB / 1.85 GB
    Counting objects: 9, done.
    Delta compression using up to 2 threads.
    Compressing objects: 100% (9/9), done.
    Writing objects: 100% (9/9), 1.23 MiB | 1.92 MiB/s, done.
    Total 9 (delta 3), reused 0 (delta 0)
    To https://huggingface.co/hf-test/xls-r-300m-sv
       27d0c57..5a191e2  main -> main

就這樣。現在你應該能夠像第1節中所示那樣使用5gram進行LM增強解碼了。

正如xls-r-300m-sv的模型卡所示,我們的5gram LM增強解碼器在Common Voice的7個測試集上獲得了18.85%的WER,這是一個相對約30%的效能提升🔥。

社群

註冊登入 發表評論

© . This site is unofficial and not affiliated with Hugging Face, Inc.