Hugging Face TransformersとHabana Gaudiを使用して、BERTを事前に学習する
'Hugging Face TransformersとHabana Gaudiを使ってBERTの事前学習'
このチュートリアルでは、Habana GaudiベースのDL1インスタンスを使用してBERT-baseをゼロから事前トレーニングする方法を学びます。Gaudiのコストパフォーマンスの利点を活用するためにAWSで使用します。Hugging Face Transformers、Optimum Habana、およびDatasetsライブラリを使用して、マスクされた言語モデリングを使用してBERT-baseモデルを事前トレーニングします。これは、最初のBERT事前トレーニングタスクの一つです。始める前に、ディープラーニング環境をセットアップする必要があります。
コードを表示する
以下のことを学びます:
- データセットの準備
- トークナイザのトレーニング
- データセットの前処理
- Habana Gaudi上でBERTを事前トレーニングする
注意:ステップ1から3は、CPUを多く使用するタスクのため、異なるインスタンスサイズで実行することができます/すべきです。
要件
始める前に、以下の要件を満たしていることを確認してください
- DL1インスタンスタイプのクオータを持つAWSアカウント
- AWS CLIがインストールされていること
- AWS IAMユーザーがCLIで構成され、ec2インスタンスの作成と管理の権限を持っていること
役立つリソース
- Hugging Face TransformersとHabana Gaudiのためのディープラーニング環境のセットアップ
- EC2リモートランナーとHabana Gaudiを使用したディープラーニングセットアップの簡単な方法
- Optimum Habanaドキュメント
- 事前トレーニングスクリプト
- コード:pre-training-bert.ipynb
BERTとは何ですか?
BERTは、Transformerからの双方向エンコーダ表現を使用した自然言語処理のための機械学習(ML)モデルです。Google AI Languageの研究者によって2018年に開発され、感情分析や固有表現認識など、最も一般的な11以上の言語タスクに対するスイスアーミーナイフのような解決策として機能します。
BERTについて詳しくは、当社のBERT 101 🤗 State Of The Art NLP Model Explainedブログをご覧ください。
マスクされた言語モデリング(MLM)とは何ですか?
MLMは、文中の単語をマスク(非表示)にすることで、テキストからの双方向学習を可能に/強制するものであり、BERTにカバーされた単語の両側の単語を双方向に使用してマスクされた単語を予測するようにします。
マスクされた言語モデリングの例:
「うわっ!釣りをしていると、巨大なマスクされた単語が私のラインを[MASK]しました!」
マスクされた言語モデリングの詳細については、こちらをご覧ください。
さあ始めましょう。 🚀
注意:ステップ1から3はAWS c6i.12xlargeインスタンスで実行されました。
1. データセットの準備
このチュートリアルは「分割」されており、最初の部分(ステップ1-3)はデータセットとトークナイザの準備についてです。2番目の部分(ステップ4)は、準備したデータセットでBERTを事前トレーニングすることに関してです。データセットの準備を開始する前に、開発環境をセットアップする必要があります。導入で説明したように、データセットをDL1インスタンスで準備する必要はありません。ノートブックやデスクトップコンピュータを使用することもできます。
まず、transformers
、datasets
、およびgit-lfs
をインストールして、トークナイザとデータセットを後で使用するためにHugging Face Hubにプッシュします。
!pip install transformers datasets
!sudo apt-get install git-lfs
セットアップを完了するために、Hugging Face Hubにログインして、トレーニング中およびその後のモデルのアーティファクト、ログ、およびメトリクスをハブにプッシュします。
モデルをハブにプッシュできるようにするには、Hugging Face Hubに登録する必要があります。
アカウントにログインするために、huggingface_hub
パッケージのnotebook_login
ユーティリティを使用します。トークンは、アクセストークンの設定で取得できます。
from huggingface_hub import notebook_login
notebook_login()
ログインしたので、アーティファクトをプッシュするために使用されるuser_id
を取得しましょう。
from huggingface_hub import HfApi
user_id = HfApi().whoami()["name"]
print(f"user id '{user_id}' will be used during the example")
オリジナルのBERTは、WikipediaとBookCorpusのデータセットで事前学習されています。両方のデータセットはHugging Face Hubで利用可能であり、datasets
を使用して読み込むことができます。
注:Wikipediaでは20220301
を使用しますが、これは元の分割とは異なります。
最初のステップとして、データセットを読み込んで結合し、1つの大きなデータセットを作成します。
from datasets import concatenate_datasets, load_dataset
bookcorpus = load_dataset("bookcorpus", split="train")
wiki = load_dataset("wikipedia", "20220301.en", split="train")
wiki = wiki.remove_columns([col for col in wiki.column_names if col != "text"]) # 'text'列のみを保持する
assert bookcorpus.features.type == wiki.features.type
raw_datasets = concatenate_datasets([bookcorpus, wiki])
進んだデータセットの準備(重複削除、フィルタリング、その他の前処理など)は行いません。このノートブックを使用して独自のBERTモデルをゼロからトレーニングする予定の場合は、これらのデータの準備ステップをワークフローに含めることを強くお勧めします。これにより、言語モデルの性能を向上させることができます。
2. トークナイザーのトレーニング
モデルをトレーニングするためには、テキストをトークナイズ形式に変換する必要があります。ほとんどのTransformerモデルには、事前学習済みのトークナイザーが付属していますが、ゼロからモデルを事前学習する場合は、データに基づいてトークナイザーをトレーニングする必要があります。トークナイザーは、transformers
とBertTokenizerFast
クラスを使用してデータに基づいてトレーニングすることができます。
新しいトークナイザーのトレーニングに関する詳細は、Hugging Face Courseを参照してください。
from tqdm import tqdm
from transformers import BertTokenizerFast
# トークナイザーを保存するためのリポジトリID
tokenizer_id="bert-base-uncased-2022-habana"
# データを動的に読み込むためのPythonジェネレーターを作成する
def batch_iterator(batch_size=10000):
for i in tqdm(range(0, len(raw_datasets), batch_size)):
yield raw_datasets[i : i + batch_size]["text"]
# 既存のトークナイザーから特殊トークンを再利用してトークナイザーを作成する
tokenizer = BertTokenizerFast.from_pretrained("bert-base-uncased")
train_new_from_iterator()
を使用してトークナイザーのトレーニングを開始できます。
bert_tokenizer = tokenizer.train_new_from_iterator(text_iterator=batch_iterator(), vocab_size=32_000)
bert_tokenizer.save_pretrained("tokenizer")
トークナイザーをHugging Face Hubにプッシュして、後でモデルのトレーニングに使用します。
# トークナイザーをプッシュするためには、ログインする必要があります
bert_tokenizer.push_to_hub(tokenizer_id)
3. データセットの前処理
モデルのトレーニングを開始する前に、最後のステップはデータセットの前処理/トークナイズです。トレーニングの際に簡単に読み込めるように、トレーニング済みのトークナイザーを使用してデータセットをトークナイズします。トークナイズプロセスも非常にシンプルです。ドキュメントが512
トークンを超える場合は、トークンが切り詰められ、複数のドキュメントに分割されません。
from transformers import AutoTokenizer
import multiprocessing
# トークナイザーをロードする
tokenizer = AutoTokenizer.from_pretrained("tokenizer")
num_proc = multiprocessing.cpu_count()
print(f"The max length for the tokenizer is: {tokenizer.model_max_length}")
def group_texts(examples):
tokenized_inputs = tokenizer(
examples["text"], return_special_tokens_mask=True, truncation=True, max_length=tokenizer.model_max_length
)
return tokenized_inputs
# データセットを前処理する
tokenized_datasets = raw_datasets.map(group_texts, batched=True, remove_columns=["text"], num_proc=num_proc)
tokenized_datasets.features
データ処理関数では、データセットからすべてのテキストを連結し、tokenizer.model_max_length
(512)のチャンクを生成します。
from itertools import chain
# メインのデータ処理関数である。データセットからすべてのテキストを連結し、max_seq_lengthのチャンクを生成する。
def group_texts(examples):
# すべてのテキストを連結する
concatenated_examples = {k: list(chain(*examples[k])) for k in examples.keys()}
total_length = len(concatenated_examples[list(examples.keys())[0]])
# 余りが小さい場合は破棄する。パディングを追加することもできますが、モデルがサポートしている場合はこの破棄の代わりにカスタマイズできます。
if total_length >= tokenizer.model_max_length:
total_length = (total_length // tokenizer.model_max_length) * tokenizer.model_max_length
# max_lenのチャンクに分割する
result = {
k: [t[i : i + tokenizer.model_max_length] for i in range(0, total_length, tokenizer.model_max_length)]
for k, t in concatenated_examples.items()
}
return result
tokenized_datasets = tokenized_datasets.map(group_texts, batched=True, num_proc=num_proc)
# データセットをシャッフルする
tokenized_datasets = tokenized_datasets.shuffle(seed=34)
print(f"the dataset contains in total {len(tokenized_datasets)*tokenizer.model_max_length} tokens")
# データセットには合計で3417216000トークンが含まれています
トレーニングを開始する前に、準備したデータセットをハブにプッシュする必要があります。
# データセットをHugging Faceにプッシュする
dataset_id = f"{user_id}/processed_bert_dataset"
tokenized_datasets.push_to_hub(f"{user_id}/processed_bert_dataset")
4. Habana GaudiでBERTを事前学習する
この例では、AWSのDL1インスタンスを使用してHabana Gaudiを実行し、事前学習を実行します。ローカルセットアップからリモートのDL1インスタンスで事前学習を簡単に起動するために、リモートランナーツールキットを使用します。これがどのように機能するかについては、「EC2リモートランナーとHabana Gaudiで簡単に行うディープラーニングセットアップ」を参照してください。
!pip install rm-runner
GPUを使用する場合は、TrainerとTrainingArgumentsを使用します。Habana Gaudiでトレーニングを実行するためには、optimum-habana
ライブラリを活用して、GaudiTrainerとGaudiTrainingArgumentsを使用します。 GaudiTrainer
は、Habana Gaudiインスタンス上でトランスフォーマーモデルの事前学習またはファインチューニングを行うためのTrainerのラッパーです。
-from transformers import Trainer, TrainingArguments
+from optimum.habana import GaudiTrainer, GaudiTrainingArguments
# トレーニング引数を定義
-training_args = TrainingArguments(
+training_args = GaudiTrainingArguments(
+ use_habana=True,
+ use_lazy_mode=True,
+ gaudi_config_name=path_to_gaudi_config,
...
)
# Trainerを初期化
-trainer = Trainer(
+trainer = GaudiTrainer(
model=model,
args=training_args,
train_dataset=train_dataset
... # 他の引数
)
使用するDL1
インスタンスには、利用可能なHPUコアが8つあり、モデルの分散データ並列トレーニングに活用することができます。分散トレーニングとしてトレーニングを実行するには、すべてのHPUでマルチプロセッシングで使用できるトレーニングスクリプトを作成する必要があります。我々はGaudiTrainer
を使用してマスク言語モデリングを実装したrun_mlm.pyスクリプトを作成し、分散トレーニングを実行するためにoptimum-habana
のDistributedRunnerランナーを使用し、引数を渡します。代わりに、optimum-habanaリポジトリのgaudi_spawn.pyをご覧ください。
トレーニングを開始する前に、トレーニングに使用するハイパーパラメータ
を定義する必要があります。Hugging Face HubのGaudiTrainer
の統合を活用して、トレーニング中にチェックポイント、ログ、およびメトリクスを自動的にリポジトリにプッシュします。
from huggingface_hub import HfFolder
# ハイパーパラメータ
hyperparameters = {
"model_config_id": "bert-base-uncased",
"dataset_id": "philschmid/processed_bert_dataset",
"tokenizer_id": "philschmid/bert-base-uncased-2022-habana",
"gaudi_config_id": "philschmid/bert-base-uncased-2022-habana",
"repository_id": "bert-base-uncased-2022",
"hf_hub_token": HfFolder.get_token(), # `huggingface-cli login`でログインが必要
"max_steps": 100_000,
"per_device_train_batch_size": 32,
"learning_rate": 5e-5,
}
hyperparameters_string = " ".join(f"--{key} {value}" for key, value in hyperparameters.items())
EC2RemoteRunner
を作成し、launch
を使用してトレーニングを開始できます。これにより、AWS EC2 DL1インスタンスが起動し、run_mlm.py
スクリプトがhuggingface/optimum-habana:latest
コンテナを使用して実行されます。
from rm_runner import EC2RemoteRunner
# EC2リモートランナーを作成
runner = EC2RemoteRunner(
instance_type="dl1.24xlarge",
profile="hf-sm", # プロファイルを適宜調整
region="us-east-1",
container="huggingface/optimum-habana:4.21.1-pt1.11.0-synapse1.5.0"
)
# gaudi_spawnを使って分散トレーニングでスクリプトを実行
runner.launch(
command=f"python3 gaudi_spawn.py --use_mpi --world_size=8 run_mlm.py {hyperparameters_string}",
source_dir="scripts",
)
この実験は60kステップで実行されました。
hyperparameters
では、max_steps
プロパティを定義し、事前学習を100,000
ステップに制限しました。グローバルバッチサイズ256
の100,000
ステップは約12.5時間かかりました。
BERTは元々、グローバルバッチサイズ256
で100万ステップの事前学習が行われました:
私たちは、1回のバッチサイズ256シーケンス(256シーケンス * 512トークン = 128,000トークン/バッチ)で100万ステップトレーニングしました。これは、約33億の単語コーパスに対しておよそ40エポックに相当します。
つまり、完全な事前学習を行う場合には約125時間(12.5時間 * 10)かかり、Habana Gaudiを使用すると約1,650ドルの費用がかかります。これは非常に安価です。
比較のために、最速のBERT事前学習記録を持つDeepSpeedチームによると、1つのDGX-2(16個のNVIDIA V100 GPU、各32GBのメモリを搭載)でBERTを事前学習するのに約33.25時間かかります。
コストの比較には、8つのNVIDIA V100 32GB GPUを搭載し、約31.22ドル/時間かかるp3dn.24xlargeを参考にすることができます。DeepSpeedが報告したものと同じ「セットアップ」を持つためには、このインスタンスを2つ必要とします(マルチノードセットアップによって作成されるオーバーヘッド(I/O、ネットワークなど)は無視しています)。これにより、DeepSpeed GPUを使用したAWS上のトレーニングのコストは約2,075ドルになります。これはHabana Gaudiが現在提供しているものよりも25%高くなります。
ここで注目すべき点は、DeepSpeedの使用は一般的にパフォーマンスを約1.5〜2倍改善するということです。1.5〜2倍の係数は、DeepSpeedを使用しない場合の同じ事前学習ジョブがおそらく2倍の時間とコスト(約3,000〜4,000ドル)がかかることを意味します。
Habana Gaudiとの統合がより広く利用可能になると、実験を再度行うことを楽しみにしています。
結論
これでチュートリアルは終了です。Hugging Face TransformersとHabana Gaudiを使用してBERTをゼロから事前学習する方法の基礎を知りました。また、Trainer
からGaudiTrainer
への移行がどれほど簡単かも確認しました。
最速のBERT事前学習結果との実装を比較し、Habana Gaudiはまだ25%のコスト削減を実現し、BERTを約1,650ドルで事前学習できることがわかりました。
これらの結果は素晴らしいものであり、企業が言語とドメインに合わせて事前学習モデルを適応させ、一般的なBERTモデルと比較して精度を最大10%向上させることができます。
もし、コストを削減し精度を向上させるために自分自身でBERTや他のTransformersモデルをゼロからトレーニングすることに興味がある場合、当社の専門家に連絡してExpert Acceleration Programについて学びましょう。Habanaソリューションについてさらに詳しく知るには、当社のパートナーシップについて読み、彼らに連絡する方法について調べてください。
コード:pre-training-bert.ipynb
読んでいただきありがとうございます!ご質問がある場合は、Githubかフォーラムを通じてお気軽にお問い合わせください。また、TwitterやLinkedInでもご連絡いただけます。
We will continue to update VoAGI; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles