🤗 Transformersでn-gramを使ってWav2Vec2を強化する

'🤗 TransformersでWav2Vec2を強化するためにn-gramを使用する'

Wav2Vec2は音声認識のための人気のある事前学習モデルです。2020年9月にMeta AI Researchによってリリースされたこの新しいアーキテクチャは、音声認識のための自己教師あり事前学習の進歩を促進しました。例えば、G. Ng et al.、2021年、Chen et al、2021年、Hsu et al.、2021年、Babu et al.、2021年などが挙げられます。Hugging Face Hubでは、Wav2Vec2の最も人気のある事前学習チェックポイントは現在、月間ダウンロード数25万以上です。

コネクショニスト時系列分類(CTC)を使用して、事前学習済みのWav2Vec2のようなチェックポイントは、ダウンストリームの音声認識タスクで非常に簡単にファインチューニングできます。要するに、事前学習済みのWav2Vec2のチェックポイントをファインチューニングする方法は次のとおりです。

事前学習チェックポイントの上にはじめに単一のランダムに初期化された線形層が積み重ねられ、生のオーディオ入力を文字のシーケンスに分類するために訓練されます。これは以下のように行います。

  1. 生のオーディオからオーディオ表現を抽出する(CNN層を使用する)
  2. オーディオ表現のシーケンスをトランスフォーマーレイヤーのスタックで処理する
  3. 処理されたオーディオ表現を出力文字のシーケンスに分類する

以前のオーディオ分類モデルでは、分類されたオーディオフレームのシーケンスを一貫した転写に変換するために、追加の言語モデル(LM)と辞書が必要でした。Wav2Vec2のアーキテクチャはトランスフォーマーレイヤーに基づいているため、各処理されたオーディオ表現は他のすべてのオーディオ表現から文脈を得ることができます。さらに、Wav2Vec2はファインチューニングにCTCアルゴリズムを利用しており、変動する「入力オーディオの長さ」と「出力テキストの長さ」の比率の整列の問題を解決しています。

文脈化されたオーディオ分類と整列の問題がないため、Wav2Vec2には受け入れ可能なオーディオ転写を得るために外部の言語モデルや辞書は必要ありません。

公式論文の付録Cに示されているように、Wav2Vec2は言語モデルを使用せずにLibriSpeechで印象的なダウンストリームのパフォーマンスを発揮しています。ただし、付録からも明らかなように、Wav2Vec2を10分間の転写済みオーディオのみで訓練した場合、言語モデルと組み合わせると特に改善が見られます。

最近まで、🤗 TransformersライブラリにはファインチューニングされたWav2Vec2と言語モデルを使用してオーディオファイルをデコードするための簡単なユーザーインターフェースがありませんでした。幸いにも、これは変わりました。🤗 Transformersは現在、Kensho Technologiesのpyctcdecodeライブラリとの簡単な統合を提供しています。このブログ投稿は、🤗 Datasetsと🤗 Transformersを使用して既存のファインチューニングされたWav2Vec2チェックポイントと組み合わせるためのn-gram言語モデルを作成する方法をステップバイステップの技術ガイドとして説明します。

まず、次の作業から始めます:

  1. LMを使用したオーディオのデコードは、LMを使用しないオーディオのデコードとどのように異なるのか?
  2. 言語モデルに適したデータを取得する方法
  3. KenLMでn-gramを構築する方法
  4. n-gramをファインチューニングされたWav2Vec2チェックポイントに組み合わせる方法

Wav2Vec2の機能についての詳細な説明(このブログ投稿では必要ありません)については、以下の資料を参照してください:

  • wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations
  • Fine-Tune Wav2Vec2 for English ASR with 🤗 Transformers
  • An Illustrated Tour of Wav2vec 2.0

1. Wav2Vec2と言語モデルを使用したオーディオデータのデコード

🤗 TransformersのWav2Vec2の例のドキュメントに示されているように、オーディオは次のように転写できます。

まず、datasetstransformersをインストールします。

pip install datasets transformers

Wav2Vec2の音声転写の機能を示すために、Librispeechデータセットの一部を読み込みます。

from datasets import load_dataset

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

出力:

    データセット librispeech_asr (/root/.cache/huggingface/datasets/hf-internal-testing___librispeech_asr/clean/2.1.0/f2c70a4d03ab4410954901bde48c54b85ca1b7f9bf7d616e7e2a72b5ee6ddbfc) を再利用します。

    データセット({
        features: ['file', 'audio', 'text', 'speaker_id', 'chapter_id', 'id'],
        num_rows: 73
    })

73のオーディオサンプルのうち1つを選んで聞くことができます。

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

出力:

    この年のこの祭りの季節に、クリスマスとローストビーフが私たちの前に迫っているということを彼は私たちに伝えています。食べることとその結果からの比喩は、思考に最も容易に浮かび上がります。

データサンプルを選んだら、ファインチューニングされたモデルとプロセッサをロードします。

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()

出力:

'彼は私たちに、クリスマスとローストビーフが私たちの前に迫っているこの年のこの祭りの季節に、食べることとその結果からの比喩が最も容易に思考に浮かび上がると伝えています'

上記のターゲットの転写と転写を比較すると、いくつかの単語は正しく聞こえますが、正しく綴られていません。例:

  • クリスマウス vs. クリスマス
  • ローズ vs. ロースト
  • シマリス vs. シミリス

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を使用する代わりに、今回は特徴抽出器とトークナイザーに加えて4-gramモデルをロードするためにWav2Vec2ProcessorWithLMを使用します。

from transformers import Wav2Vec2ProcessorWithLM

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

言語モデルなしでオーディオをデコードするのとは異なり、プロセッサは今回、argmax(logits)(上記のpredicted_idsと呼ばれる)の代わりにモデルの出力logitsを直接受け取ります。これは、言語モデルを使用してデコードする場合、各タイムステップで、プロセッサがすべての可能な出力文字の確率を考慮に入れるからです。出力のlogitsの次元を見てみましょう。

logits.shape

出力:

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

logitsは、32のエントリを持つ624のベクトルのシーケンスに対応していることがわかります。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のデコーディングプロセスは、n-gram言語モデルによって与えられる次の文字の確率を利用しながら、624×32の確率行列をビームサーチで適用していると理解できます。

では、デコーディングステップをもう一度実行しましょう。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つが修正され、christmasとsimilesが正しくトランスクライブされました。

興味深いことに、roseの誤ったトランスクリプションは続いています。しかし、これはあまり驚くべきことではありません。言語モデルのないオーディオのデコードは、christmausやsimilesのようなスペルミスを生じやすいです(私の知る限りではそれらの単語は英語に存在しません)。これは、音声認識システムがほとんどアコースティックな入力に基づいて予測し、実際には前後の予測された文字の言語モデリングコンテキストではありません。一方、言語モデルを追加すると、スペルミスを大幅に減らすことができます。なぜなら、十分に訓練されたn-gramモデルはスペルミスのある単語を予測しないからです。しかし、単語roseは有効な英単語であり、したがって4-gramはこの単語を無視できない確率で予測するでしょう。

言語モデル自体は、rose beefよりもroast beefの方が英語でははるかに一般的であるため、正しい単語roastを好む可能性があります。最終的なトランスクリプションは、facebook/wav2vec2-base-100hの出力確率とn-gram言語モデルの確率の加重組み合わせから派生するため、roseなどの間違ったトランスクリプションが見られることは非常に一般的です。

Wav2Vec2ProcessorWithLMでデコードする際にさまざまなパラメータを調整する方法の詳細については、公式のドキュメンテーションをご覧ください。


1 {}^1 1 一部の研究は、facebook/wav2vec2-base-100hのようなモデルは、十分に大きく十分なデータでトレーニングされると、言語モデルに似た中間オーディオ表現間の言語モデリングの依存関係を学習できる可能性があることを示しています。

素晴らしいですね。n-gram言語モデルを追加することで得られる利点を見たので、ゼロからn-gramとWav2Vec2ProcessorWithLMの作成方法について掘り下げてみましょう。

2. n-gramのデータ取得

音声認識システムに役立つ言語モデルは、次の単語(またはトークン、文字)を予測することで、音響モデル(例:Wav2Vec2)をサポートする必要があります。したがって、次の分布をモデル化する必要があります:P ( w n ∣ w 0 t − 1 ) \mathbf{P}(w_n | \mathbf{w}_0^{t-1}) P ( w n ​ ∣ w 0 t − 1 ​ ) ここで、w n w_n w n ​ は次の単語であり、w 0 t − 1 \mathbf{w}_0^{t-1} w 0 t − 1 ​ は発話の開始以来のすべての前の単語のシーケンスです。言い換えると、音声認識システムに与えられたオーディオ入力に関係なく、言語モデルは以前にトランスクライブされたすべての単語から次の単語を正確に予測する能力が必要です。

いつものように、言語モデルは訓練に使用されるデータが良好であるかに依存します。音声認識の場合、音声認識が使用されるデータの種類について考える必要があります:会話、オーディオブック、映画、スピーチなど、…?

言語モデルは、音声認識システムのターゲット転写に対応する言語をモデル化するのに適している必要があります。デモンストレーションの目的で、我々は事前学習済みのfacebook/wav2vec2-xls-r-300mをスウェーデン語のCommon Voice 7でファインチューニングしたと仮定します。ファインチューニングされたチェックポイントはこちらで見つけることができます。Common Voice 7は比較的にクラウドソーシングされた音声データセットであり、このモデルをそのテストデータで評価します。

では、Hugging Face Hubで適切なテキストデータを探してみましょう。スウェーデン語のデータを含むデータセットをすべて検索します。データセットを少しブラウズして、Common Voiceの音声データに似たデータセットを探します。OSCARやMC4のような明らかな選択肢はここでは最適ではないかもしれません。なぜなら、それらは次の理由からです:

  • ウェブのクローリングから生成されており、話される言語に対して非常にクリーンで対応しているとは言えない可能性がある
  • 多くの前処理が必要となる
  • 非常に大きいため、デモンストレーションの目的では理想的ではないこと 😉

ここでは比較的クリーンで前処理が容易なデータセットであるeuroparl_bilingualが適切な選択肢に見えます。これはヨーロッパ議会の議論やトークに基づいたデータセットであり、比較的クリーンで読み上げオーディオデータに対応しているはずです。このデータセットはもともと機械翻訳向けに設計されているため、翻訳ペアのテキストのみにアクセスできます。ここでは、英語からスウェーデン語への翻訳のテキストのみを抽出します。

target_lang="sv"  # ターゲット言語に変更

データをダウンロードしましょう。

from datasets import load_dataset

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

データがかなり大きいことがわかります – 100万以上の翻訳があります。ただし、テキストデータのみであるため、比較的簡単に処理できるはずです。

次に、スウェーデン語でファインチューニングされたXLS-Rチェックポイントの訓練時にデータが前処理された方法を見てみましょう。run.shファイルを見ると、公式の転写から次の文字が削除されていることがわかります:

chars_to_ignore_regex = '[,?.!\-\;\:"“%‘”�—’…–]'  # ファインチューニングされたモデルの無視する文字に変更

ここでも同じ処理を行い、言語モデルのアルファベットがファインチューニングされた音響チェックポイントのアルファベットと一致するようにします。

スウェーデン語のテキストを抽出し、直ちに処理するために単一のmap関数を作成できます。

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()

出力:

    ログインに成功しました
    トークンは /root/.huggingface/token に保存されました
    git-credentialストアを介して認証済みですが、これはマシン上で定義されたヘルパーではありません。
    Hugging Face Hubにプッシュする際に再認証が必要かもしれません。この資格情報ヘルパーをデフォルトに設定する場合は、ターミナルで次のコマンドを実行してください。

    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アーキテクチャに基づく大規模な言語モデルがNLPの標準となった一方で、音声認識システムを強化するためにn-gram LMを使用することはまだ非常に一般的です(セクション1を参照)。

公式のWav2Vec2論文の付録Cの表9を再度見ると、TransformerベースのLMをデコーディングに使用すると、n-gramモデルを使用するよりも明らかに良い結果が得られることがわかりますが、n-gramとTransformerベースのLMの間の違いは、n-gramとLMを使用しない場合の違いほど顕著ではありません。

例えば、10分だけでファインチューニングされた大規模なWav2Vec2チェックポイントの場合、n-gramはLMを使用しない場合の単語エラーレート(WER)を約80%削減しますが、TransformerベースのLMはn-gramに比べてWERをさらに23%削減します。この相対的なWERの削減は、音響モデルにトレーニングデータが与えられた場合にはより少なくなります。例えば、大規模なチェックポイントの場合、TransformerベースのLMはn-gram LMに比べてWERをわずか8%削減しますが、n-gramは言語モデルを使用しない場合に比べて21%のWER削減を提供します。

n-gramがTransformerベースのLMよりも好まれる理由は、n-gramの計算コストがはるかに小さいことです。n-gramでは、前の単語からの単語の確率を取得するのは、ルックアップテーブルまたはツリー状のデータストレージをクエリするのとほぼ同じくらいの計算コストしかかかりません。つまり、次の単語の確率を取得するにはフルフォワードパスが必要な現代のTransformerベースの言語モデルに比べて非常に高速です。

n-gramが音声認識においてなぜ(まだ)非常に有用であるか、およびn-gramがどのように機能するかについての詳細な情報については、Stanfordのこの優れた要約を参照することをお勧めします。

素晴らしいですね、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"  # ご自身のユーザー名に変更してください

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コマンドを実行して、"5gram.arpa"という名前のn-gramを構築するだけです。音声認識では比較的一般的なので、-o 5パラメータを渡して5-gramを構築します。KenLMで構築できるさまざまなn-gram LMについての詳細な情報については、KenLMの公式ウェブサイトをご覧ください。

以下のコマンドを実行すると、1分ほどかかる場合があります。

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

出力:

    === 1/5 n-gramのカウントとソート ===
    /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: 大きな割り当て 1918697472 バイト == 0x55d40d0f0000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b28c51e 0x55d40b26b2eb 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    tcmalloc: 大きな割り当て 8953896960 バイト == 0x55d47f6c0000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b2e07ca 0x55d40b2e1208 0x55d40b26b308 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    ****************************************************************************************************
    ユニグラムトークン 42153890 タイプ 360209
    === 2/5 調整されたカウントの計算とソート ===
    チェーンのサイズ: 1:4322508 2:1062772928 3:1992699264 4:3188318720 5:4649631744
    tcmalloc: 大きな割り当て 4649631744 バイト == 0x55d40d0f0000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b2e07ca 0x55d40b2e1208 0x55d40b26b8d7 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    tcmalloc: 大きな割り当て 1992704000 バイト == 0x55d561ce0000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b2e07ca 0x55d40b2e1208 0x55d40b26bcdd 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    tcmalloc: 大きな割り当て 3188326400 バイト == 0x55d695a86000 @  0x7fdccb1a91e7 0x55d40b2f17a2 0x55d40b2e07ca 0x55d40b2e1208 0x55d40b26bcdd 0x55d40b257066 0x7fdcc9342bf7 0x55d40b258baa
    統計:
    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
    バイナリLMのメモリ推定:
    タイプ      MB
    探索 1884 -p 1.5を仮定
    探索 2195 -r models -p 1.5を仮定
    トライ 922 量子化なし
    トライ 518 -q 8 -b 8量子化を仮定
    トライ 806 -a 22配列ポインタ圧縮を仮定
    トライ 401 -a 22 -q 8 -b 8配列ポインタ圧縮と量子化を仮定
    === 3/5 初期確率の計算とソート ===
    チェーンのサイズ: 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 順序補間された確率の計算と書き込み ===
    チェーンのサイズ: 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 ARPAモデルの書き込み ===
    ----5---10---15---20---25---30---35---40---45---50---55---60---65---70---75---80---85---90---95--100
    ****************************************************************************************************
    名前:lmplz  VmPeak:14181536 kB  VmRSS:2199260 kB    RSSMax:4160328 kB   user:120.598    sys:26.6659 CPU:147.264 real:136.344

素晴らしいです、5-gram LMを構築しました!最初の数行を調べましょう。

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オブジェクトでラップして、セクション1で示したように5-gramブーストデコーディングをシームレスに行いたいと思います。まず、xls-r-300m-svの現在の「LMなし」プロセッサをダウンロードします。

from transformers import AutoProcessor

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

次に、トークナイザーの語彙を抽出します。これはpyctcdecodeBeamSearchDecoderクラスの「ラベル」を表します。

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])}

「ラベル」と先に構築した5gram_correct.arpaファイルは、デコーダーを構築するために必要なものです。

from pyctcdecode import build_ctcdecoder

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

出力:

    アルファベットの長さが1を超えるエントリーが見つかりました。これはBPEスタイルでない場合は異常ですが、アルファベットがBPEタイプとして認識されませんでした。これは正しいですか?
    ユニグラムとラベルが一致しないようです。

この警告は無視して問題ありません。今作成した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のモデルフォルダにアップロードすることで、関連するファイルを1か所にまとめます。

リポジトリをクローンし、新しいデコーダーファイルを追加してからアップロードします。まず、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")

出力:

    https://huggingface.co/hf-test/xls-r-300m-svをローカルの空のディレクトリにクローン中。

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では.arpaファイルをbuild_binary実行可能ファイルを使用してバイナリ形式に変換することができます。

ここでそれを利用しましょう。

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

出力:

    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
    ****************************************************************************************************
    成功

素晴らしい、うまくいきました!では、.arpaファイルを削除し、バイナリ形式の5-gram LMのサイズを確認しましょう。

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
    オブジェクトをカウント中: 9 個完了しました。
    最大2つのスレッドを使用してデルタ圧縮中です。
    オブジェクトを圧縮中: 100% (9/9) 完了しました。
    オブジェクトを書き込んでいます: 100% (9/9)、1.23 MiB | 1.92 MiB/s、完了しました。
    合計 9 (デルタ 3)、再利用 0 (デルタ 0)
    https://huggingface.co/hf-test/xls-r-300m-sv に向けて送信中
       27d0c57..5a191e2  main -> main

以上です。これでセクション1に示されているように、5gram を LM-boosted デコーディングに使用できるはずです。

「xls-r-300m-sv」のモデルカードで確認できるように、5gram LM-boosted デコーダーはCommon Voiceの7つのテストセットで18.85%の WER を実現しており、相対パフォーマンスは約30%です🔥。

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

人工知能

ピーター・マッキー、Sonarの開発者担当責任者-インタビューシリーズ

ピーター・マッキーはSonarのDeveloper Relationsの責任者です Sonarは、悪いコードの1兆ドルの課題を解決するプラットフォー...

人工知能

「アナコンダのCEO兼共同創業者、ピーターウォングによるインタビューシリーズ」

ピーター・ワンはAnacondaのCEO兼共同創設者ですAnaconda(以前はContinuum Analyticsとして知られる)を設立する前は、ピー...

機械学習

もし芸術が私たちの人間性を表現する方法であるなら、人工知能はどこに適合するのでしょうか?

MITのポストドクターであるジヴ・エプスタイン氏(SM '19、PhD '23)は、芸術やその他のメディアを作成するために生成的AIを...

人工知能

「スノーケルAIのCEO兼共同創設者、アレックス・ラットナー - インタビューシリーズ」

アレックス・ラトナーは、スタンフォードAIラボを母体とする会社、Snorkel AIのCEO兼共同創設者ですSnorkel AIは、手作業のAI...

人工知能

「Ntropyの共同創設者兼CEO、ナレ・ヴァルダニアンについて - インタビューシリーズ」

「Ntropyの共同創設者兼CEOであるナレ・ヴァルダニアンは、超人的な精度で100ミリ秒以下で金融取引を解析することを可能にす...

人工知能

ムーバブルインクのCEO兼共同創設者であるヴィヴェク・シャルマ氏についてのインタビュー・シリーズ

ビヴェクは2010年にムーバブルインクを共同設立し、急速な成長を遂げながら、600人以上の従業員を擁し、世界有数の革新的なブ...