「マスク言語モデリングタスクのBERTトレーニング方法」

「マスク言語モデリングタスクのBERTトレーニング手法の改善」

PythonとTransformersライブラリを使用して、ゼロからMLMタスクのための言語モデルを構築する実践ガイド

はじめに

近年、大規模な言語モデル(LLMs)が機械学習コミュニティの注目を集めています。LLMsが登場する前に、マスクされた言語モデリング、因果関係のある言語モデリング、シーケンス・トゥ・シーケンスの言語モデリングなど、さまざまな言語モデリング技術について重要な研究フェーズがありました。

上記のリストから、BERTなどのマスクされた言語モデルが、分類やクラスタリングなどの後続のNLPタスクでより使いやすくなりました。Hugging Face Transformersなどのライブラリのおかげで、これらのモデルを後続タスクに適応させることがより容易になりました。また、オープンソースコミュニティのおかげで、幅広い言語とドメインをカバーする多くの言語モデルを選ぶことができます。

ファインチューニングするか、ゼロから構築するか?

既存の言語モデルを特定のユースケースに適応させる場合、時には追加のチューニングなしで既存のモデルを使用することができます(いわゆるファインチューニング)。例えば、英語の感情/意図検出モデルが必要な場合、HuggingFace.coにアクセスして適切なモデルを探すことができます。

ただし、実世界で遭遇するタスクの一部に対してのみそれを期待できます。そのため、ファインチューニングと呼ばれる追加のテクニックが必要です。まず、ファインチューニングされるベースモデルを選択する必要があります。ここでは、選択したモデルと対象言語の語彙の類似性に注意する必要があります。

しかし、望ましい言語で再トレーニングされた適切なモデルを見つけることができない場合は、ゼロから構築することを検討してください。このチュートリアルでは、マスクされた言語モデルのためにBERTモデルを実装します。

BERTのアーキテクチャ

BERTのアーキテクチャについて詳しく説明することは、このチュートリアルの範囲外ですが、明確さのために狭く説明しましょう。BERT、またはBidirectional Encoder Representations from Transformersは、エンコーダー専用のトランスフォーマーファミリーに属しています。これはGoogleの研究者によって2018年に導入されました。

ペーパー要約:

BERTという新しい言語表現モデルを紹介します。BERTは、双方向のエンコーダー表現がトランスフォーマーから得られる、という意味です。最近の言語表現モデルとは異なり、BERTはすべてのレイヤーで左右の文脈の両方に共同で依存しながら、未ラベルのテキストから深い双方向表現を事前トレーニングするように設計されています。そのため、事前トレーニングされたBERTモデルは、追加の出力レイヤーをわずかに1つだけ持つことで、質問応答や言語推論など、さまざまなタスクの最先端モデルを作成するためにファインチューニングできます。BERTは概念的にシンプルで経験的にパワフルです。GLUEスコアを80.5%(絶対値改善率7.7%)、MultiNLIの正確性を86.7%(絶対値改善率4.6%)、SQuAD v1.1の質問応答テストF1を93.2(絶対値改善率1.5)およびSQuAD v2.0の質問応答テストF1を83.1(絶対値改善率5.1)に押し上げるなど、11の自然言語処理タスクで新しい最先端の結果を得ました。ペーパー:https://arxiv.org/abs/1810.04805

上記から、興味深いキーワードであるBidirectional(双方向)がわかります。双方向性はBERTに人間のような力を与えます。以下のような空欄を埋める必要がある場合を想像してみてください。

「戦争は時には必要な悪です。しかし、必然的であるとしても、それは常に良いものではありません。」

空欄の位置に入る単語を推測するには、いくつかのことに注意する必要があります:空白の前の単語、空白の後の単語、文全体の文脈。この人間の特性を応用して、BERTは同じように機能します。トレーニング中に、いくつかの単語を隠し、BERTにそれらを予測するように要求します。トレーニングが終了すると、BERTは前後の単語に基づいてマスクされたトークンを予測できます。これには、モデルが入力シーケンスに提示される単語に異なる注意を割り当てる必要があり、マスクされたトークンの予測に重要な影響を与える可能性があります。

Image by Author via https://huggingface.co/spaces/exbert-project/exbert

ここで見るように、このモデルは隠されたポジションの適切な単語を「悪」と見ており、最初の文の「悪」もこの予測を行うために必要とされていることがわかります。これは注目すべき点であり、モデルが入力シーケンスの文脈を理解していることを示しています。この文脈の意識により、BERTは与えられたタスクに対して意味のある文の埋め込みを生成することができます。さらに、これらの埋め込みはクラスタリングや分類などの下流タスクで使用することができます。BERTについては十分です。では、ゼロから作ってみましょう。

BERTモデルの定義

一般的にはBERT(base)とBERT(large)があります。どちらもヘッドごとに64次元を持っています。largeバリアントは24のエンコーダーレイヤーを含んでいますが、baseバリアントは12しかありません。ただし、これらの設定に制限されるわけではありません。驚くほど、Hugging Face Transformersライブラリを使用してモデルを定義することで、モデルの設定を完全に制御することができます。やるべきことは、BertConfigクラスを使用して望むモデルの設定を定義するだけです。

オリジナルの実装と合わせるために、私は6つのヘッドと合計384のモデル次元を選びました。この方法で、各ヘッドはオリジナルの実装と同様に64次元を持ちます。BERTモデルを初期化しましょう。

from transformers import BertConfig, BertForMaskedLMconfig = BertConfig(    hidden_size = 384,    vocab_size= tokenizer.vocab_size,    num_hidden_layers = 6,    num_attention_heads = 6,    intermediate_size = 1024,    max_position_embeddings = 256)model = BertForMaskedLM(config=config)print(model.num_parameters()) #10457864

トークナイザの訓練

ここでは、トークナイゼーションがどのように動作するかを詳しく説明しません。代わりに、Hugging Face tokenizersライブラリを使用してゼロからトレーニングしてみましょう。注意:オリジナルのBERTの実装で使用されているトークナイザはWordPieceトークナイザです。これは別のサブワードベースのトークナイゼーション方法です。以下の素晴らしいHuggingFaceリソースを使用してこのトークナイゼーションについて詳しく学ぶことができます。

WordPieceトークナイゼーション — Hugging Face NLPコース

われわれはオープンソースとオープンサイエンスを通じて人工知能の進化と民主化を推進しています。

huggingface.co

ここで使用するデータセットはSinhala-400Mデータセット(apache-2.0の下)です。お持ちのデータセットでも同じ手順で実施できます。

注意していただきたいのは、いくつかのシンハラ語の単語が英語でタイプされていることです。これらのコーパスのためにトークナイザを訓練しましょう。

まず必要なモジュールをインポートしましょう。Hugging Face Tokenizersライブラリを使用してトークナイザをトレーニングする利点は、既存のトークナイザを使用し、トレーニングコーパスに基づいて語彙を置き換えること(適用可能な場合にはマージも行う)ができることです。これにより、プリトークナイゼーションやポストトークナイゼーションなどのトークナイゼーション手順が保持されます。これには、BertTokenizerクラスのメソッドtrain_new_from_iteratorを使用できます。

from tokenizers.implementations import ByteLevelBPETokenizerfrom tokenizers.processors import BertProcessingfrom transformers import AutoTokenizerfrom datasets import Datasetimport pandas as pd#訓練するベーストークナイザをロードtokenizer_base = AutoTokenizer.from_pretrained("bert-base-cased")# パンダデータセットをHFデータセットに変換するdataset = Dataset.from_pandas(df.rename(columns={"comment":'text'}))# イテレータを定義するtraining_corpus = (    dataset[i : i + 1000]["text"]    for i in range(0, len(dataset), 1000))#データセットのための新しいトークナイザをトレーニングするtokenizer = tokenizer_base.train_new_from_iterator(training_corpus, 5000)#サンプルテキストに対してトレーニングされたトークナイザをテストするtext = dataset['text'][123]print(text)

# トークン化プロセスを確認しよう
input_ids = tokenizer(text).input_ids
subword_view = [tokenizer.convert_ids_to_tokens(id) for id in input_ids]
np.array(subword_view)

‘cricketer’という単語がcricketと##erに分解されているのが確認できます。これは、トークナイザーが適切に訓練されていることを示しています。ただし、異なる語彙サイズを試してみてください。私の場合は5000ですが、これは比較的小さなサイズで、このおもちゃの例には適しています。

最後に、訓練済みのトークナイザーをディレクトリに保存できます。

tokenizer.save_pretrained("tokenizer/sinhala-wordpiece-yt-comments")

データコレーターを定義し、データセットをトークン化しましょう。

MLMタスク用のコレーターを定義しましょう。ここでは、トークンの15%をマスクしますが、マスキング確率を異なる値に設定することもできます。

from transformers import DataCollatorForLanguageModeling
data_collator = DataCollatorForLanguageModeling(
    tokenizer=tokenizer, mlm=True, mlm_probability=0.15)

前に作成したトークナイザーを使用してデータセットをトークン化しましょう。Hugging Faceのアクセラレータを利用したカスタムクラスを使用して、元のLineByLineTextDatasetを置き換えています。

import torch
from torch.utils.data import Dataset
from accelerate import Accelerator, DistributedType

class LineByLineTextDataset(Dataset):
    def __init__(self, tokenizer, raw_datasets, max_length: int):
        self.padding = "max_length"
        self.text_column_name = 'text'
        self.max_length = max_length
        self.accelerator = Accelerator(gradient_accumulation_steps=1)
        self.tokenizer = tokenizer
        with self.accelerator.main_process_first():
            self.tokenized_datasets = raw_datasets.map(
                self.tokenize_function,
                batched=True,
                num_proc=4,
                remove_columns=[self.text_column_name],
                desc="Running tokenizer on dataset line_by_line",
            )
            self.tokenized_datasets.set_format('torch',columns=['input_ids'],dtype=torch.long)
            
    def tokenize_function(self, examples):
        examples[self.text_column_name] = [
            line for line in examples[self.text_column_name] if len(line[0]) > 0 and not line[0].isspace()
        ]
        return self.tokenizer(
            examples[self.text_column_name],
            padding=self.padding,
            truncation=True,
            max_length=self.max_length,
            return_special_tokens_mask=True,
        )

    def __len__(self):
        return len(self.tokenized_datasets)

    def __getitem__(self, i):
        return self.tokenized_datasets[i]

データセットをトークン化しましょう。

tokenized_dataset_train = LineByLineTextDataset(
    tokenizer= tokenizer,
    raw_datasets = dataset,
    max_length=256,)

では、トレーニングループのコードを書いてみましょう。

from transformers import Trainer, TrainingArguments

training_args = TrainingArguments(
    output_dir="./model",
    overwrite_output_dir=True,
    push_to_hub=True,
    hub_model_id="Ransaka/sinhala-bert-yt-comments",
    num_train_epochs=2,
    per_device_train_batch_size=32,
    save_steps=5_000,
    logging_steps = 1000,
    save_total_limit=2,
    use_mps_device = True, # disable this if you're running non-mac env
    hub_private_repo = False, # please set true if you want to save model privetly
    save_safetensors= True,
    learning_rate = 1e-4,
    report_to='wandb')

trainer = Trainer(
    model=model,
    args=training_args,
    data_collator=data_collator,
    train_dataset=tokenized_dataset_train)

trainer.train()

トレーナーをtrain()メソッドで呼び出すことができます。

trainer.train()

十分なトレーニングが終了したら、モデルはゼロショット分類やクラスタリングなどのダウンストリームタスクに使用できます。詳細については、このHugging Faceスペースの例をご覧ください。

シンハラ埋め込みスペース – Ransakaによるハグフェイススペース

コミュニティによって作成された素晴らしいMLアプリを見つける

huggingface.co

結論

限られたリソースでは、事前学習済みモデルは特定の言語パターンのみを認識できる場合がありますが、特定のユースケースには依然として役立つことがあります。可能な場合は、微調整を強くおすすめします。

この記事では、特に記載のない限り、すべての画像は著者によるものです。

参考文献

  1. Explorable BERT — https://huggingface.co/spaces/exbert-project/exbert
  2. BERT Paper — https://arxiv.org/abs/1810.04805
  3. データセット — https://huggingface.co/datasets/Ransaka/Sinhala-400M

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