チュートリアルスペイン語のRoBERTa言語モデルの学習方法
SpanBERTa:スペイン語用RoBERTa言語モデルをゼロからトレーニングした方法
原文はSkim AIの機械学習研究インターン、クリス・トラン。
はじめに¶
変換モデルを使った自己学習法は、ほとんどの自然言語処理タスクで最先端の性能を達成している。しかし、変換モデルの学習には計算コストがかかるため、現在利用可能な事前学習済み変換モデルのほとんどは英語用しかない。そのため、スペイン語を対象としたプロジェクトで自然言語処理タスクのパフォーマンスを向上させるために、私のチームである スキムAI を訓練することにした。 ロベルタ スペイン語の言語モデルをゼロから作成し、SpanBERTaと呼ぶ。
SpanBERTa は RoBERTa-base と同じサイズである。RoBERTaのトレーニングスキーマに従い、18GBの オスカーのスペイン語コーパスを、4つのTesla P100 GPUを使用して8日間で処理しました。
このブログポストでは、以下を使用してBERTのような言語モデルをゼロから訓練するエンドツーエンドのプロセスを説明する。 変圧器
そして トークナイザ
ライブラリはHugging Faceによる。この記事のコードを直接実行するためのGoogle Colabノートブックもある。また、ノートブックを適宜修正して、他の言語用のBERTライクなモデルを訓練したり、カスタマイズしたデータセットで微調整したりすることもできる。
次に進む前に、最先端のNLPモデルを誰にでも利用できるようにしてくれたHugging Faceチームに心から感謝したい。
セットアップ¶
1.依存関係のインストール¶
0]である:
%pture !pip uninstall -y tensorflow !pip transformers==2.8.0 をインストールします。
2.データ¶
我々は、SpanBERTaを オスカーのスペイン語コーパスである。データセットの全容量は150GBで、学習に使用したのは18GBの一部である。
この例では、簡単のため、以下のスペイン語映画字幕のデータセットを使用します。 OpenSubtitles.このデータセットのサイズは5.4GBで、我々は~300MBのサブセットで学習する。
0]である:
インポートOS # 映画の字幕データセットをダウンロードして解凍する if not os.path.exists('data/dataset.txt'): !wget "https://object.pouta.csc.fi/OPUS-OpenSubtitles/v2016/mono/es.txt.gz" -O dataset.txt.gz !.gzip -d dataset.txt.gz データをmkdirする mv dataset.txt data
--2020-04-06 15:53:04-- https://object.pouta.csc.fi/OPUS-OpenSubtitles/v2016/mono/es.txt.gz object.pouta.csc.fiの解決 (object.pouta.csc.fi)...86.50.254.18, 86.50.254.19 object.pouta.csc.fi (object.pouta.csc.fi)|86.50.254.18|:443...に接続中。 HTTP リクエストが送信されました。 長さ: 1859673728 (1.7G) [application/gzip] 保存先データセット.txt.gz' dataset.txt.gz 100%[===================] 1.73G 17.0MB/s 1分46秒 2020-04-06 15:54:51 (16.8 MB/s) - 'dataset.txt.gz' saved [1859673728/1859673728].
0]である:
# 総行数とランダム行数 !.wc -l data/dataset.txt !shuf -n 5 data/dataset.txt
179287150 データ/データセット.txt そうだね、僕のヒーローと闘うには、もっと多くの敵がいると思ってたよ。 エルフの男やオークのすべての言語で、すべての魅力を紹介します。 前作は『ブルーブラッド』: ダニエル・スタッフォードとは何の関係もありません。 コミカルだった。
0]である:
# トレーニング用に最初の100万行のサブセットを取得する。 TRAIN_SIZE = 1000000 #@param {type: "整数"}。 !(head -n $TRAIN_SIZE data/dataset.txt) > data/train.txt
0]である:
# 検証のために次の10,000行のサブセットを取得する VAL_SIZE = 10000 #@param {type: "integer"}。 !(sed -n {TRAIN_SIZE + 1},{TRAIN_SIZE + VAL_SIZE}p data/dataset.txt) > data/dev.txt
3.トーケナイザーをトレーニングする¶
元の BERT 実装は、32K サブワード単位の語彙を持つ WordPiece トークン化器を使用している。しかし、この方法は、希少語を処理するときに「未知の」トークンを導入する可能性がある。
この実装では、50,265サブワード単位(RoBERTa-baseと同じ)の語彙を持つバイトレベルBPEトークナイザを使用する。バイトレベルのBPEを使用することで、「未知の」トークンを得ることなく、どのような入力もエンコードできる適度なサイズのサブワード語彙を学習することができる。
なぜなら バイトレベルBPETokenizer
2つのファイルが作成される ["vocab.json"、"merges.txt"]]。
同時に BertWordPieceTokenizer
生成されるファイルは1つだけ 語彙.txt
を使うとエラーになる。 BertWordPieceTokenizer
を使用して、BPEトークナイザの出力をロードします。
0]である:
%%time from tokenizers import ByteLevelBPETokenizer パス = "data/train.txt" #トークナイザーの初期化 tokenizer = ByteLevelBPETokenizer() # トレーニングのカスタマイズ tokenizer.train(files=path、 vocab_size=50265、 min_frequency=2、 special_tokens=["", "", "", "", ""]) # ファイルをディスクに保存する mkdir -p "models/roberta" tokenizer.save("models/roberta")
CPU時間:ユーザー1分37秒、システム1分02秒、合計1分38秒1.02秒、合計:1分38秒 ウォール時間:1分38秒
超高速!1,000万行のトレーニングにかかる時間はわずか2分。
ゼロから言語モデルを作る¶
1.モデル・アーキテクチャ¶
RoBERTaはBERTと全く同じアーキテクチャを持つ。唯一の違いは
- RoBERTaは、より大きなサブワード語彙(50k対32k)を持つバイトレベルBPEトークナイザーを使用しています。
- RoBERTaは、動的な単語マスキングと次文予測タスクを実装している。
- RoBERTaのトレーニングハイパーパラメータ。
その他のアーキテクチャ構成については、ドキュメント(ロベルタ, バート).
0]である:
インポート json コンフィグ = { "アーキテクチャ":[ "RobertaForMaskedLM" ], "attention_probs_dropout_prob":0.1, "hidden_act":"gelu"、 "hidden_dropout_prob":0.1, "hidden_size":768, "initializer_range":0.02, "intermediate_size":3072, "layer_norm_eps":1e-05, "max_position_embeddings":514, "model_type":"roberta"、 「num_attention_heads":12, 「num_hidden_layers":12, "type_vocab_size":1, "vocab_size":50265 } with open("models/roberta/config.json", 'w') as fp: json.dump(config, fp) tokenizer_config = {"max_len":512} with open("models/roberta/tokenizer_config.json", 'w') as fp: json.dump(tokenizer_config, fp)
2.トレーニングハイパーパラメータ¶
ハイパーパラム | BERTベース | ロベルタ・ベース |
---|---|---|
シーケンス長 | 128, 512 | 512 |
バッチサイズ | 256 | 8K |
ピーク学習率 | 1e-4 | 6e-4 |
最大歩数 | 1M | 500K |
ウォームアップ・ステップ | 10K | 24K |
体重減少 | 0.01 | 0.01 |
アダム1TP4テプシロン$ | 1e-6 | 1e-6 |
アダム $beta_1$ | 0.9 | 0.9 |
アダム $beta_2$ | 0.999 | 0.98 |
グラデーションクリッピング | 0.0 | 0.0 |
なお、RoBERTa を訓練する際のバッチサイズは 8000 である。したがって、RoBERTa-base は 500K ステップで学習されたが、その学習計算コストは BERT-base の 16 倍である。また ロベルタ紙バッチサイズを大きくすることで、マスクされた言語モデリング目的に対する当惑度(perplexity)が向上し、終了タスクの精度も向上することが示された。より大きなバッチサイズは 勾配蓄積ステップ
.
計算量の制約のため、BERT-base の学習スキーマに従い、4 台の Tesla P100 GPU を使用して SpanBERTa モデルを 8 日間で 200K ステップ学習しました。
3.トレーニング開始¶
を使用してゼロからモデルをトレーニングする。 run_language_modeling.py
HuggingFaceが提供するスクリプトで、コーパスの前処理、トークン化、モデルの学習を行う。 マスク言語モデリング タスクを実行する。このスクリプトは、1つの大きなコーパスで学習するように最適化されている。したがって、データセットが大きく、それを分割して逐次学習したい場合は、スクリプトを修正するか、大容量メモリを搭載したモンスターマシンを用意する必要がある。
0]である:
#2020年4月22日更新:Hugging Face の run_language_modeling.py スクリプトを更新しました。 # アップデート前のバージョンをご利用ください。 !.wget -c https://raw.githubusercontent.com/chriskhanhtran/spanish-bert/master/run_language_modeling.py
--2020-04-24 02:28:21-- https://raw.githubusercontent.com/chriskhanhtran/spanish-bert/master/run_language_modeling.py raw.githubusercontent.com (raw.githubusercontent.com) の解決...151.101.0.133, 151.101.64.133, 151.101.128.133, ... raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443 に接続中... 接続されました。 HTTP リクエストが送信されました。 長さ: 34328 (34K) [text/plain] 保存先'run_language_modeling.py' に保存します。 run_language_modeli 100%[===================] 33.52K --.-KB/s in 0.003s 2020-04-24 02:28:21 (10.1 MB/s) - 'run_language_modeling.py' saved [34328/34328].
重要な議論
--line_by_line
データセット中の異なるテキスト行を、異なるシーケンスとして扱うかどうか。データセットの各行が長く、~512トークン以上の場合は、この設定を使うべきである。各行が短い場合は、デフォルトのテキスト前処理ですべての行を連結してトークン化し、トークン化された出力を512トークンのブロックに分割します。データセットを小さな塊に分割し、別々に前処理を行うこともできます。3GBのテキストをデフォルトのテキストデータセット
クラスである。--should_continue
output_dir にある最新のチェックポイントから続行するかどうか。--モデル名またはパス
重みを初期化するためのモデルのチェックポイント。ゼロからモデルをトレーニングする場合はNoneのままにします。--mlm
言語モデリングではなく、マスクされた言語モデリングロスでトレーニングする。-設定名, -トーケナイザー名
model_name_or_path と同じでない場合、オプションで事前学習された config とトークナイザ名またはパス。両方が None の場合、新しい config を初期化します。--per_gpu_train_batch_size
トレーニングのGPU/CPUあたりのバッチサイズ。GPUに搭載可能な最大数を選択してください。バッチサイズが大きすぎるとエラーが表示されます。--gradient_accumulation_steps
後方/更新パスを実行する前に蓄積する更新ステップ数。このトリックを使ってバッチサイズを大きくすることができる。例えばper_gpu_train_batch_size = 16
そしてgradient_accumulation_steps = 4
この場合、列車バッチの合計サイズは64となる。--overwrite_output_dir
出力ディレクトリの内容を上書きする。--no_cuda、--fp16、--fp16_opt_level
GPU/CPU でのトレーニングに関する議論。- その他の引数は、モデル・パスとトレーニング・ハイパー・パラメータである。
スクリプトは、モデル・パスにモデル・タイプ(例えば "roberta"、"bert"、"gpt2 "など)を含めることを強く推奨する。 オートモデル
クラスは、指定されたパスのパターンマッチングを使ってモデルのコンフィギュレーションを推測します。
0]である:
# モデルパス MODEL_TYPE = "roberta" #@param ["roberta", "bert"]. MODEL_DIR = "models/roberta" #@param {type:「文字列} OUTPUT_DIR = "models/roberta/output" #@param {type:"文字列"}。 TRAIN_PATH = "data/train.txt" #@param {type:「文字列"}。 EVAL_PATH = "data/dev.txt" #@param {type:「文字列"}。
この例では、Colabから提供されたTesla P4 GPUで25ステップだけトレーニングする。
0]である:
ンビディア・スミ
4月6日(月)15:59:35 2020 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 440.64.00 ドライババージョン:418.67 CUDAバージョン:10.1 |-------------------------------+----------------------+----------------------+ | GPU名 Persistence-M|Bus-Id Disp.A|Volatile Uncorr.ECC |ファン温度 Perf Pwr:Usage/Cap|メモリ使用量| GPU-Util Compute M.| |===============================+======================+======================| | 0 Tesla P4 オフ|00000000:00:04.0 オフ|0|0|0 | N/A 31C P8 7W / 75W | 0MiB / 7611MiB | 0% Default | | 0 +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | プロセス GPU メモリ | GPU PID タイプ プロセス名 使用状況 |=============================================================================| | 実行中のプロセスは見つかりませんでした。 +-----------------------------------------------------------------------------+
0]である:
# コマンドライン cmd = """python run_language_modeling.py --output_dir {output_dir} -model_type{model_type}。 --model_type {model_type} --mlm --mlm --コンフィグ名 {config_name} -トーケナイザー名 {tokenizer_name --tokenizer_name {トーケナイザー名} -mlm {line_by_line} {should_continue} {モデル名またはパス} --train_data_file -train_data_file{train_path}。 --eval_data_file {eval_path} -do_train {do_eval} トレーニング中に評価} {evaluate_during_training --overwrite_output_dir --ブロックサイズ 512 --最大ステップ数 25 --warmup_steps 10 --学習速度 5e-5 --per_gpu_train_batch_size 4 --gradient_accumulation_steps 4 --weight_decay 0.01 --adam_epsilon 1e-6 -max_grad_norm 100.0 -セーブ_トータル_リミット 10 -セーブステップ数 10 --ロギングステップ 2 --seed 42 """
0]である:
# ゼロからのトレーニングのための引数。evaluate_during_trainingはオフにしている、 # line_by_line、should_continue、model_name_or_pathをオフにする。 train_params = { "output_dir":OUTPUT_DIR、 "model_type":MODEL_TYPE、 "config_name":MODEL_DIR、 "tokenizer_name":MODEL_DIR、 "train_path":TRAIN_PATH、 "eval_path":eval_path": EVAL_PATH、 "do_eval":do_eval": "--do-eval"、 "evaluate_during_training":"", 「line_by_line":"", "should_continue":"", "model_name_or_path":"", }
仮想マシン上でトレーニングを行っている場合は、tensorboardをインストールしてトレーニングプロセスを監視することができます。以下は私たちの テンソルボード SpanBERTaのトレーニングのために。
pip install tensorboard==2.1.0 tensorboard dev upload --logdir runs
200kステップの後、損失は1.8に達し、当惑度は5.2に達した。
さあ、トレーニングを始めよう!
で[ ]:
!!{cmd.format(**train_params)}。
04/06/2020 15:59:55 - INFO - __main__ - dataのデータセットファイルから特徴量を作成する
04/06/2020 16:04:43 - INFO - __main__ - 特徴をキャッシュファイル data/roberta_cached_lm_510_train.txt に保存します。
04/06/2020 16:04:46 - INFO - __main__ - ***** トレーニングの実行 *****
04/06/2020 16:04:46 - INFO - __main__ - サンプル数 = 165994
04/06/2020 16:04:46 - INFO - __main__ - エポック数 = 1
04/06/2020 16:04:46 - INFO - __main__ - GPU あたりの瞬間バッチサイズ = 4
04/06/2020 16:04:46 - INFO - __main__ - 訓練の総バッチサイズ (並列、分散、累積) = 16
04/06/2020 16:04:46 - INFO - __main__ - 勾配累積ステップ = 4
04/06/2020 16:04:46 - INFO - __main__ - 最適化の総ステップ数 = 25
エポック: 0% 0/1 [00:00<?, ?it/s].
反復: 0% 0/41499 [00:00<?, ?it/s] イテレーション: 0% 0/41499 [00:00<?, ?it/s
反復: 0% 1/41499 [00:01<13:18:02, 1.15s/it] イテレーション: 0% 1/41499 [00:00<?
反復: 0% 2/41499 [00:01<11:26:47, 1.01it/s] イテレーション: 0% 2/41499 [00:01<11:26:47, 1.01it/s
反復: 0% 3/41499 [00:02<10:10:30, 1.13it/s] イテレーション:0% 3/41499 [00:02<10:10:30, 1.13it/s
反復: 0% 4/41499 [00:03<9:38:10, 1.20it/s]の場合
反復: 0% 5/41499[00:03<8:52:44, 1.30it/s]
反復: 0% 6/41499[00:04<8:22:47, 1.38it/s]
反復: 0% 7/41499 [00:04<8:00:55, 1.44it/s] イテレーション:0% 7/41499 [00:04<8:00:55, 1.44it/s
反復: 0% 8/41499 [00:05<8:03:40, 1.43it/s] イテレーション:0% 8/41499 [00:05<8:03:40, 1.43it/s
反復: 0% 9/41499 [00:06<7:46:57, 1.48it/s] イテレーション:0% 9/41499 [00:05<8:03:40, 1.43it/s
反復: 0% 10/41499 [00:06<7:35:35, 1.52it/s] イテレーション:0% 10/41499 [00:06<7:35:35, 1.52it/s
反復: 0% 11/41499 [00:07<7:28:29, 1.54it/s]の場合
反復: 0% 12/41499 [00:08<7:41:41, 1.50it/s]の場合
反復: 0% 13/41499[00:08<7:34:28, 1.52it/s]
反復: 0% 14/41499[00:09<7:28:46, 1.54it/s]
反復: 0% 15/41499[00:10<7:23:29, 1.56it/s]
反復: 0% 16/41499[00:10<7:38:06, 1.51it/s]
反復: 0% 17/41499[00:11<7:29:13, 1.54it/s]
反復: 0% 18/41499[00:12<7:24:04, 1.56it/s]
反復: 0% 19/41499[00:12<7:21:59, 1.56it/s]
反復: 0% 20/41499 [00:13<7:38:06, 1.51it/s] イテレーション:0% 20/41499 [00:13<7:38:06, 1.51it/s
04/06/2020 16:06:23 - INFO - __main__ - ***** 評価の実行中 *****
04/06/2020 16:06:23 - INFO - __main__ - 例の数 = 156
04/06/2020 16:06:23 - INFO - __main__ - バッチサイズ = 4
評価中:100% 39/39 [00:08<00:00, 4.41it/s].
04/06/2020 16:06:32 - INFO - __main__ - ***** 評価結果 *****
04/06/2020 16:06:32 - INFO - __main__ - perplexity = tensor(6077.6812)
4.マスクされた単語を予測する¶
言語モデルをトレーニングした後、モデルをアップロードしてコミュニティと共有することができます。私たちはSpanBERTaモデルをHugging Faceのサーバーにアップロードしました。下流のタスクでモデルを評価する前に、文脈を与えられたマスクされた単語を埋めることをどのように学習したかを見てみましょう。
0]である:
%%キャプチャ %%time from transformers import pipeline fill_mask = パイプライン( "fill-mask"、 model="chriskhanhtran/spanberta"、 tokenizer="chriskhanhtran/spanberta" )
ウィキペディアのCOVID-19に関する記事から一文を抜粋する。
原文は"水とジャボンで頻繁に手を洗うこと、「を意味する。石鹸と水で頻繁に手を洗う。“
マスクされた単語は 「ジャボン(石鹸) そしてトップ5の予想は以下の通り。 石鹸、塩、蒸気、レモン そして ビネガー.このモデルが、細菌を殺すことができるものや酸を含むもので手を洗うべきだと学習しているのは興味深い。
0]である:
fill_mask("Lavarse las manos incuentemente las agua y .")
アウト[0]:
[{'score':0.6469631195068359, 'sequence': 'Lavarse las manos with agua y jabón.'、 'token':18493}, {'score':0.06074320897459984, 'sequence': 'Lavarse frecuentemente las manos con agua y sal.'、 'token':619}、 {'score':0.029787985607981682, 'sequence': 'Lavarse frecuentemente las manos con agua y vapor.'、 'token':11079}, {'score':0.026410052552819252, 'sequence': 'Lavarse las manos with agua y limón.'、 'token':12788}, {'score':0.017029203474521637, 'sequence': 'Lavarse las manos con agua y vinagre.'、 'token':18424}]
結論¶
スペイン語の BERT 言語モデルをゼロから訓練する方法を説明し、文脈が与えられたマスクされた単語を予測しようとすることで、モデルが言語の特性を学習していることを確認した。この記事に従って、カスタマイズしたデータセットで事前に訓練した BERT ライクなモデルを微調整することもできます。
次に、シーケンス分類、NER、品詞タグ付け、および NLI を含む下流のタスクに事前訓練されたモデルを実装し、モデルの性能を BERT 以外のモデルと比較する。
次回の記事にご期待ください!