見出し画像

Simple Transformers 入門 (4) - 言語モデルの学習

Simple Transformers」で「言語モデルの学習」の方法をまとめました。

1. 言語モデル

「言語モデルの学習」は、文章の単語の自然な並びを学習するするタスクです。一般的なTransformerベースのモデルは、「言語モデル」で事前学習を行います。

サポートモデルは、次のとおりです。

・BERT
・CamemBERT
・DistilBERT
・ELECTRA
・GPT-2
・Longformer
・OpenAI GPT
・RoBERTa

文章の単語の自然な並びの学習手法には、次のようなものがあります。

・Masked Language Modeling : 文章内のマスクした(隠した)単語を予測(例:BERT)。
・Next word prediction : 文章に続く次の単語を予測(例:GPT-2)。
・ELECTRA : 各単語が生成された単語に置き換えられているかどうか、または元の単語であるかどうかを予測。

2. 転移学習

転移学習」(Transfer Learning)は、あるタスクで得られた知識を、別のタスクに活用する学習法です。現在、自然言語処理(NLP)のデファクトスタンダードであるモデル「Transformer」は、この手法によって、ベンチマークで高得点を獲得しています。

転移学習」は、「事前学習」と「ファインチューニング」の2段階で構成されています。

(1) 事前学習 : 大規模なラベルなしコーパスで文章の単語の自然な並びを学習。
(2) ファインチューニング : 事前学習済みモデルをターゲットタスクのコーパスで追加学習。

転移学習の利点は、事前学習で行う大量の計算は1回だけ行えばよく、各タスクの学習時は、事前学習の学習結果を再利用することができます。

3. 言語モデルファインチューニング

事前学習済み「言語モデル」は、様々なタスクやユースケースで大きな成功を収めてきました。しかし、医療データなど専門用語を使うテキストの場合、効果が出にくくなる可能性があります。このような場合は、関心のあるタスクのデータを使って、事前学習と同じアルゴリズム(「Masked Language Modeling」など)で追加で事前学習を行うことで、効果を発揮できる場合があります。これをは、「言語モデルファインチューニング」(language model fine-tuning)と呼びます。これによって、事前学習済みモデルにはない「専門用語」をより適切に表現する方法を学習させることができます。

4-1. 言語モデルの学習の最小限のコード

「言語モデルの学習」の最小限のコードは、次のとおりです。「WikiText-2データセット」をダウンロードしてあることを前提としています。

from simpletransformers.language_modeling import LanguageModelingModel
import logging

# ログの設定
logging.basicConfig(level=logging.INFO)
transformers_logger = logging.getLogger("transformers")
transformers_logger.setLevel(logging.WARNING)

# モデルの作成
train_args = {
    "reprocess_input_data": True,
    "overwrite_output_dir": True,
}
model = LanguageModelingModel('bert', 'bert-base-cased', args=train_args)

# 学習
model.train_model("wikitext-2/wiki.train.tokens", eval_file="wikitext-2/wiki.test.tokens")

# 評価
model.eval_model("wikitext-2/wiki.test.tokens")

4-2. ゼロからの言語モデルの学習 の最小限のコード

ゼロから言語モデルを学習するにも、任意のテキストファイルを使用できます。 model_nameNone 、vocab_size(args辞書内)に語彙数を指定することで、言語モデルを最初から学習する必要があることを示します。

「ゼロからの言語モデルの学習」の最小限のコードは、次のとおりです。

from simpletransformers.language_modeling import LanguageModelingModel
import logging

# ログの設定
logging.basicConfig(level=logging.INFO)
transformers_logger = logging.getLogger("transformers")
transformers_logger.setLevel(logging.WARNING)

# モデルの作成
train_args = {
    "reprocess_input_data": True,
    "overwrite_output_dir": True,
    "vocab_size": 52000,
}
model = LanguageModelingModel('roberta', None, args=train_args)

# 学習
model.train_model("wikitext-2/wiki.train.tokens", eval_file="wikitext-2/wiki.test.tokens")

# 評価
model.eval_model("wikitext-2/wiki.test.tokens")

4-3. ELECTRAによる言語モデルの学習 の最小限のコード

ELECTRA」は、Transformerの言語モデルを事前学習するための新しいアプローチです。この方法は、比較的計算量が少なくなります。

save_discriminator()save_generator()を使用して、事前学習されたモデルを抽出できます。2つのモデルは、デフォルトで<output_dir>/discriminator_model<output_dir>/generator_modelに保存されます。

from simpletransformers.language_modeling import LanguageModelingModel
import logging

# ログの設定
logging.basicConfig(level=logging.INFO)
transformers_logger = logging.getLogger("transformers")
transformers_logger.setLevel(logging.WARNING)

# モデルの作成
train_args = {
    "reprocess_input_data": True,
    "overwrite_output_dir": True,
    "vocab_size": 52000,
}
model = LanguageModelingModel('electra', None, args=train_args, train_files="wikitext-2/wiki.train.tokens")

# Mixing standard ELECTRA architectures example
# model = LanguageModelingModel(
#     "electra",
#     None,
#     generator_name="google/electra-small-generator",
#     discriminator_name="google/electra-large-discriminator",
#     args=train_args,
#     train_files="wikitext-2/wiki.train.tokens",
# )

5. 言語モデルの学習のデータセット

主な「言語モデルの学習」のデータセットは、次のとおりです。

WikiText-2 
Esparanto Model trained with ELECTRA

6-1. LanguageModelingMode

「LanguageModelingMode」は、「言語モデルの学習」で使用するクラスです。

◎ コンストラクタ
コンストラクタの書式は、次のとおりです。

LanguageModelingModel (model_type, model_name, generator_name=None, discriminator_name=None, args=None, use_cuda=True, cuda_device=-1)

パラメータは、次のとおりです。

・model_type : (required) str - モデル種別。
・model_name : (required) str - Huggingface Transformersの事前学習済みモデル名、またはモデルファイルを含むディレクトリへのパス。
・generator_name : (optional) - 事前学習モデル名、またはELECTRAジェネレータモデルを含むディレクトリへのパス。
・discriminator_name : (optional) - 事前学習モデル名、またはELECTRAディスクリミネーターモデルを含むディレクトリへのパス。
・args : (optional) dic - オプション引数。
・train_files : (optional) - 学習ファイルのリスト。
・use_cuda : (optional) bool - CUDAを使用するかどうか。
・cuda_device : (optional) - CUDAデバイス。

◎ クラス属性
クラス属性は、次のとおりです。

・tokenizer : トークナイザー。
・model : モデル。
・model_name : Huggingface Transformersの事前学習済みモデル名、またはモデルファイルを含むディレクトリへのパス。
・device : デバイス。
・results : 評価結果。
・args : オプション引数。
・cuda_device : (optional) - CUDAデバイス(-1=CPU)。

◎ train_model()
学習します。

train_model(self, train_file, output_dir=None, show_running_loss=True, args=None, eval_file=None, verbose=True,)

パラメータは、次のとおりです。

・train_file : 学習ファイルのパス。
・output_dir : (optional) - 出力ディレクトリ。
・show_running_loss : (Optional) - 損失出力。
・args : (optional) - オプション引数。
・eval_file : (optional) - 評価ファイルのパス。

◎ eval_model()
評価します。

eval_model(self, eval_file, output_dir=None, verbose=True, silent=False,)

パラメータは、次のとおりです。

・eval_file : 評価ファイルのパス。
・output_dir : (optional) - 出力ディレクトリ。
・verbose : 詳細出力。
・silent : プログレスバーの非表示。

戻り値は、次のとおりです。

・result : 評価結果。(correct, similar, incorrect)
・text : correct_text、similar_text、incorrect_textを含む辞書。

◎ train_tokenizer()
トークナイザーを学習します。

**train_tokenizer(self, train_files, tokenizer_name=None, output_dir=None, use_trained_tokenizer=True)

パラメータは、次のとおりです。

・train_files : トークナイザーの学習ファイルのパス。
・tokenizer_name : 事前学習済みのトークナイザーの名前、またはトークナイザーを含むディレクトリへのパス。
・output_dir : (optional) - 出力ディレクトリ。
・use_trained_tokenizer : (optional) - 学習完了したら、学習済みのトークナイザーをロード。

6-2. LanguageModelingModeの追加パラメータ引数

デフォルト値は、次のとおりです。

"dataset_type": "None",
"dataset_class": None,
"custom_tokenizer": None,
"block_size": 512,
"mlm": True,
"mlm_probability": 0.15,
"max_steps": -1,
"config_name": None,
"tokenizer_name": None,
"min_frequency": 2,
"special_tokens": ["<s>", "<pad>", "</s>", "<unk>", "<mask>"],
"sliding_window": False,
"stride": 0.8
"config": {},
"generator_config": {},
"discriminator_config": {},

パラメータは、次のとおりです。

・dataset_type : str - データセット種別。
 - simple (or None) : 学習ファイルの各行は、単一の個別のサンプルと見なされる。slide_windowをTrueに設定すると、長いシーケンスを長さmax_seq_lengthのサンプルに自動的に分割できる。マルチプロセッシングを使用して、マルチコアシステムのパフォーマンスを大幅に向上させる。
 - line_by_line : 学習ファイルの各行を個別のサンプルとして扱う。
 - text : 学習ファイル内の各ファイルを個別のサンプルとして扱う。
・dataset_class: 使用するカスタムデータセットクラス。
・block_size : int - トークン化後のオプションの入力シーケンスの長さ。学習データセットは、学習のためにこのサイズのブロックに切り捨てられる。デフォルトでは、単一文入力のモデルの最大入力長になる(スペシャルトークンを考慮に入れること)。
・mlm : bool - 言語モデルの代わりにマスクされたmasked-language modelingの損失で学習。
・mlm_probability : float - masked-language modelingの損失に対するトークンとマスクの比率。
・max_steps : int - > 0の場合、実行する学習ステップの総数を設定。num_train_epochsをオーバーライド。
・config_name : str - 事前学習されたコンフィグの名前、またはconfig.jsonファイルを含むディレクトリへのパス。
・tokenizer_name : str - 事前学習されたトークナイザーの名前、またはトークナイザーファイルを含むディレクトリへのパス。
・min_frequencey : int - 単語を語彙に追加するために必要な最小頻度。
・special_tokens : list - 新しいトークナイザーを学習する時に使用されるスペシャルトークンのリスト。
・sliding_window : bool - データを準備するときにスライディングウィンドウ手法を使用する必要があるかどうか。SimpleDatasetでのみ機能する。
・stride : float - スライディングウィンドウを使用するときにストライドとして使用するmax_seq_lengthの一部。
・config : ここで指定されたキー値は、モデル構成で使用されるデフォルト値をオーバーライド。
・generator_config : dict - ここで指定されたキー値は、Electraジェネレータモデルの構成で使用されるデフォルト値を上書き。
・discriminator_config : dict - ここで指定されたキー値は、Electraディスクリミネーターモデルの構成で使用されるデフォルト値を上書き。

7. 日本語のデータセットでの言語モデルの学習

日本語のデータセットでの「言語モデルの学習」を行います。

◎ Simple Transformersのインストール
以下のコマンドでSimple Transformersをインストールします。

# Simple Transformersのインストール
!pip install transformers
!pip install simpletransformers

◎ データセットの準備
Wikipediaの戦国武将の記事からデータセット(wiki_train.txt, wiki_val.txt, wiki_test.txt)を作成します。練習用のためデータセットはかなり少なめです。

%%time
import codecs
import re
import requests
from bs4 import BeautifulSoup

# Wikipediaの小説家の記事のダウンロード
def download_wikipedia(keyword_list, file_name):
    url = "https://ja.wikipedia.org/wiki/"
    corpus = []
    for keyword in keyword_list:
        response = requests.get(url + keyword)
   
        soup = BeautifulSoup(response.text, 'lxml')
        for p_tag in soup.find_all('p'):
            # 空白の削除
            text = "".join(p_tag.text.strip().split(" "))

            # 空行は無処理
            if len(text) == 0:
                continue

            # 注釈の削除 (例: [注釈1], [注釈1], [1])
            text = re.sub(r"\[注釈[0-9]+\]", "", text)
            text = re.sub(r"\[注[0-9]+\]", "", text)
            text = re.sub(r"\[[0-9]+\]", "", text)
 
            # 行の追加
            corpus.append(text)

    # ファイルの保存       
    print(*corpus, sep="\n", file=codecs.open(file_name, "w", "utf-8"))

# 学習データ
download_wikipedia([
    "秋田実季", "明智秀満", "明智光秀", "浅井長政", "浅野長政 ", "朝倉宗滴", "朝倉義景", "粟野勝久", "井伊直政", "石田三成", "今川義元", "上杉景勝", "上杉謙信", "宇喜多秀家", "大内義隆", "大谷吉継", "大友宗麟", "織田信長", "片桐且元", "片倉景綱", "加藤清正", "加藤嘉明", "蒲生氏郷", "吉川元春", "黒田官兵衛", "黒田長政", "小早川隆景", "小早川秀秋", "後藤基次", "斉藤道三", "酒井忠次", "榊原康政", "佐竹義重", "真田信之", "真田昌幸", "真田幸村", "柴田勝家", "島清興", "島津義弘", "清水宗治", "鈴木重秀(孫一)", "仙石秀久", "相馬義胤", "高橋紹運", "滝川一益", "武田勝頼", "武田信玄", "竹中半兵衛", "立花宗茂", "伊達成実", "伊達政宗", "長宗我部元親", "津軽為信", "藤堂高虎", "徳川家康", "豊臣秀長", "豊臣秀吉", "鳥居元忠", "直江兼続", "鍋島直茂", 
], 'wiki_train.txt')

# 検証データ
download_wikipedia([
    "南部信直", "蜂須賀正勝", "平塚為広", "北条氏康", "本願寺顕如", "本多忠勝", "福島正則", "細川忠興", "前田利家", "前田利益", 
], 'wiki_val.txt')

# 評価データ
download_wikipedia([
    "真柄直隆", "毛利元就", "最上義光", "山内一豊", "山県昌景", "山中幸盛", "山本勘助", "龍造寺隆信", "六角義賢", "脇坂安治"
], 'wiki_test.txt')

◎ 学習と評価
学習と評価を実行します。

%%time
from simpletransformers.language_modeling import LanguageModelingModel
import logging

# ログの設定
logging.basicConfig(level=logging.INFO)
transformers_logger = logging.getLogger("transformers")
transformers_logger.setLevel(logging.WARNING)

# モデルの作成
train_args = {
    "reprocess_input_data": True,
    "overwrite_output_dir": True,
    "mlm" : False,
    "vocab_size": 52000,
    "num_train_epochs": 10
}
model = LanguageModelingModel('gpt2', None, args=train_args, train_files='wiki_train.txt')

# 学習
model.train_model("wiki_train.txt")

# 評価
model.eval_model("wiki_test.txt")

◎ 予測
outputsフォルダにモデルが出力されるので、「テキスト生成」で利用します。

8. 参照



この記事が気に入ったらサポートをしてみませんか?