このシリーズでは、自然言語処理において主流であるTransformerを中心に、環境構築から学習の方法までまとめます。
今回の記事ではHuggingface Transformersによる日本語のマスク言語モデリングの実装について、学習から推論までの基本的な流れを紹介します。
学習済モデルによる推論を行った後、ニュース記事をデータセットに用いた学習(ファインチューニング)を実装し、推論の結果がどのように変わるのかを確かめてみましょう。
なお、英語のマスク言語モデリングの実装はこちらの記事をご覧ください。
Google colabを使用して、簡単に最新の自然言語処理モデルを実装することができますので、ぜひ最後までご覧ください。
今回の内容
・学習済モデルによるマスク言語モデリングの推論
・マスク言語モデリングのファインチューニング
・作成したモデルによる推論
言語モデリングとは
マスク言語モデリングは、文中の単語の一部をマスクし、それらのマスクを置き換える単語を予測するタスクです。
マスキング トークンを使用してシーケンス内のトークンをマスキングし、そのマスクを適切なトークンで埋めるようにモデルに指示することで、モデルは右側のコンテキスト (マスクの右側のトークン) と左側のコンテキスト (マスクの左側のトークン) の両方に対応できます。
例として、「つくもちブログでは ◯◯◯ に関する情報を発信しています」という文章が与えられた際に、「◯◯◯」部分の穴埋めの候補を出力します。
今回の記事では、学習済モデルによる推論を行った後、ニュース記事をデータセットに用いた学習(ファインチューニング)を実装し、推論の結果がどのように変わるのかを確かめてみることにします。
Transformerとは
概要
「Transformer」は2017年にGoogleが「Attention is all you need」で発表した深層学習モデルです。
現在では、自然言語処理に利用する深層学習モデルの主流になっています。
これまでの自然言語処理分野で多く使われていた「RNN」(Recurrent Neural Network)や「CNN」(Convolutional Neural Network)を利用せず、Attentionのみを用いたEncoder-Decoder型のモデルとなっています。
「Transformer」が登場して以降、多くの自然言語処理モデルが再構築され、過去を上回る成果を上げています。
最近では自然言語処理だけでなく、ViTやDETRなどといった画像認識にも応用されています。
詳細は以下の記事をご覧ください。
Huggingface Transformersとは
概要
「Hugging Face」とは米国のHugging Face社が提供している、自然言語処理に特化したディープラーニングのフレームワークです。
「Huggingface Transformers」は、先ほど紹介したTransformerを実装するためのフレームワークであり、「自然言語理解」と「自然言語生成」の最先端の汎用アーキテクチャ(BERT、GPT-2など)と、何千もの事前学習済みモデルを提供しています。
ソースコードは全てGitHub上で公開されており、誰でも無料で使うことができます。
事前学習済みモデル
Hugging Faceではタスクに応じた様々な事前学習済みモデルが提供されています。
こちらからご確認ください。
Google colabによる導入
ここからはGoogle colabを使用して実装していきます。
まずはGPUを使用できるように設定をします。
「ランタイムのタイプを変更」→「ハードウェアアクセラレータ」をGPUに変更
今回紹介するコードは以下のボタンからコピーして使用していただくことも可能です。
まずはGoogleドライブをマウントして、作業フォルダを作成します。
from google.colab import drive
drive.mount('/content/drive')
!mkdir -p '/content/drive/My Drive/huggingface_transformers_demo/'
%cd '/content/drive/My Drive/huggingface_transformers_demo/'
!git clone https://github.com/huggingface/transformers
%cd transformers
次に必要なライブラリをインストールします。
!pip install git+https://github.com/huggingface/transformers
!pip install -r ./examples/pytorch/language-modeling/requirements.txt
日本語の対応に必要なライブラリをインストールします。
!pip install fugashi[unidic-lite]
!pip install ipadic
学習済モデルによるマスク言語モデリングの推論
まずは学習済モデルを使って、簡単にマスク言語モデリングの推論を行なってみます。
ここでは「新しい趣味にどんどんチャレンジしていくことが出会いにつながりそうだ。◯○に向けて自分磨きをしたい!」という方は、「男性ウケ」も意識して選んでいこう」という記事の穴埋めを実装してみます。
学習済モデルは「cl-tohoku/bert-base-japanese-whole-word-masking」を使用します。
このモデルの詳細はこちらからご確認下さい。
import torch
from transformers import BertJapaneseTokenizer, AutoModelForMaskedLM
# トークナイザーとモデルをインスタンス化
tokenizer = BertJapaneseTokenizer.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking')
model = AutoModelForMaskedLM.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking')
次にマスク付きテキストを定義します。
# マスク付きテキスト
text = f'新しい趣味にどんどんチャレンジしていくことが出会いにつながりそうだ。「{tokenizer.mask_token}に向けて自分磨きをしたい!」という方は、「男性ウケ」も意識して選んでいこう。'
# テキストをテンソルに変換
input_ids = tokenizer.encode(text, return_tensors='pt')
# マスクのインデックスを取得
masked_index = torch.where(input_ids == tokenizer.mask_token_id)[1].tolist()[0]
# 推論
result = model(input_ids)
pred_ids = result[0][:, masked_index].topk(5).indices.tolist()[0]
for pred_id in pred_ids:
output_ids = input_ids.tolist()[0]
output_ids[masked_index] = pred_id
print(tokenizer.decode(output_ids))
実行すると、以下のような結果が出力されます。
[CLS] 新しい 趣味 に どんどん チャレンジ し て いく こと が 出会い に つながり そう だ 。 「 男性 に 向け て 自分 磨き を し たい!」 という 方 は 、 「 男性 ウケ 」 も 意識 し て 選ん で いこ う 。 [SEP]
[CLS] 新しい 趣味 に どんどん チャレンジ し て いく こと が 出会い に つながり そう だ 。 「 女性 に 向け て 自分 磨き を し たい!」 という 方 は 、 「 男性 ウケ 」 も 意識 し て 選ん で いこ う 。 [SEP]
[CLS] 新しい 趣味 に どんどん チャレンジ し て いく こと が 出会い に つながり そう だ 。 「 異性 に 向け て 自分 磨き を し たい!」 という 方 は 、 「 男性 ウケ 」 も 意識 し て 選ん で いこ う 。 [SEP]
[CLS] 新しい 趣味 に どんどん チャレンジ し て いく こと が 出会い に つながり そう だ 。 「 将来 に 向け て 自分 磨き を し たい!」 という 方 は 、 「 男性 ウケ 」 も 意識 し て 選ん で いこ う 。 [SEP]
[CLS] 新しい 趣味 に どんどん チャレンジ し て いく こと が 出会い に つながり そう だ 。 「 大人 に 向け て 自分 磨き を し たい!」 という 方 は 、 「 男性 ウケ 」 も 意識 し て 選ん で いこ う 。 [SEP]
穴埋めの単語の候補がいくつか挙げれらています。
マスク言語モデリングの学習
データセット取得
今回のこちらのサイトからニュース記事のデータセットを使用します。
(livedoor ニュースコーパス(https://www.rondhuit.com/download.html)より引用)
以下のコマンドを実行することで、データを取得することができます。
# livedoorニュースコーパスのダウンロード
!wget https://www.rondhuit.com/download/ldcc-20140209.tar.gz
!tar zxvf ldcc-20140209.tar.gz
サイトからニュース記事を取得する事ができました。
データは「huggingface_transformers_demo/transformers/text」に保存されます。
データセット作成
取得したデータから、学習用のデータセットを作成します。
まずは各テキストファイルを読み込んで、すべての文章を1つのファイルにまとめます。
今回は「dokujo-tsushin」のニュースを内容を読み込みます。
import os
path = 'text/dokujo-tsushin/'
title_list = []
filenames = os.listdir(path)
for filename in filenames:
with open(path+filename) as f:
datalist = f.readlines()
for data in datalist:
if data == '\n':
pass
else:
title_list.append(data)
読み込んだニュースデータを学習用と検証用ファイルに分割して出力します。
title_list = [s.replace('\n', '') for s in title_list]
num = len(title_list)
with open('dokujo_train.txt',mode='w', newline='') as f:
f.writelines(title_list[:int(num*0.8)])
with open('dokujo_val.txt',mode='w', newline='') as f:
f.writelines(title_list[int(num*0.8):])
学習の実行
先程作成したデータをもとに、学習を行います。
「train_file=dokujo.txt」、「dokujo_val.txt」とすることで、先程作成したデータセットを使用することができます。
%%time
# 事前学習の実行
!python ./examples/pytorch/language-modeling/run_mlm.py \
--model_name_or_path=cl-tohoku/bert-base-japanese-whole-word-masking \
--train_file=dokujo_train.txt \
--validation_file=dokujo_val.txt \
--do_train \
--do_eval \
--num_train_epochs=5 \
--save_steps=5000 \
--save_total_limit=3 \
--output_dir=language-modeling_ja/ \
--use_fast_tokenizer=False
実行すると、以下のような結果が出力されます。
***** eval metrics *****
epoch = 5.0
eval_accuracy = 0.6711
eval_loss = 1.5918
eval_runtime = 0:00:15.88
eval_samples = 349
eval_samples_per_second = 21.973
eval_steps_per_second = 2.77
perplexity = 4.912
「language-modeling_ja/」に結果が保存されました。
マスク言語モデリングの推論
ここからは、先程学習したモデルで推論をしてみましょう。
import torch
from transformers import BertJapaneseTokenizer, AutoModelForMaskedLM
# トークナイザーとモデルをインスタンス化
tokenizer = BertJapaneseTokenizer.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking')
model = AutoModelForMaskedLM.from_pretrained('language-modeling_ja/')
学習の効果を検証するため、「cl-tohoku/bert-base-japanese-whole-word-masking」モデルを使用した際と同じテキストで推論します。
# マスク付きテキスト
text = f'新しい趣味にどんどんチャレンジしていくことが出会いにつながりそうだ。「{tokenizer.mask_token}に向けて自分磨きをしたい!」という方は、「男性ウケ」も意識して選んでいこう。'
# テキストをテンソルに変換
input_ids = tokenizer.encode(text, return_tensors='pt')
# マスクのインデックスを取得
masked_index = torch.where(input_ids == tokenizer.mask_token_id)[1].tolist()[0]
# 推論
result = model(input_ids)
pred_ids = result[0][:, masked_index].topk(5).indices.tolist()[0]
for pred_id in pred_ids:
output_ids = input_ids.tolist()[0]
output_ids[masked_index] = pred_id
print(tokenizer.decode(output_ids))
実行すると、以下のような結果が出力されます。
[CLS] 新しい 趣味 に どんどん チャレンジ し て いく こと が 出会い に つながり そう だ 。 「 男性 に 向け て 自分 磨き を し たい!」 という 方 は 、 「 男性 ウケ 」 も 意識 し て 選ん で いこ う 。 [SEP]
[CLS] 新しい 趣味 に どんどん チャレンジ し て いく こと が 出会い に つながり そう だ 。 「 将来 に 向け て 自分 磨き を し たい!」 という 方 は 、 「 男性 ウケ 」 も 意識 し て 選ん で いこ う 。 [SEP]
[CLS] 新しい 趣味 に どんどん チャレンジ し て いく こと が 出会い に つながり そう だ 。 「 異性 に 向け て 自分 磨き を し たい!」 という 方 は 、 「 男性 ウケ 」 も 意識 し て 選ん で いこ う 。 [SEP]
[CLS] 新しい 趣味 に どんどん チャレンジ し て いく こと が 出会い に つながり そう だ 。 「 女性 に 向け て 自分 磨き を し たい!」 という 方 は 、 「 男性 ウケ 」 も 意識 し て 選ん で いこ う 。 [SEP]
[CLS] 新しい 趣味 に どんどん チャレンジ し て いく こと が 出会い に つながり そう だ 。 「 結婚 に 向け て 自分 磨き を し たい!」 という 方 は 、 「 男性 ウケ 」 も 意識 し て 選ん で いこ う 。 [SEP]
今回学習したモデルを使用することにより、学習済モデルでは候補に挙がらなかった、
「結婚」という選択肢が候補が出力されています。
ファインチューニングすることで、テーマに沿った出力を得られることがわかりました。
まとめ
最後までご覧いただきありがとうございました。
今回の記事ではHuggingface Transformersによる日本語のマスク言語モデリングの実装について、学習から推論までの基本的な流れを紹介しました。
このシリーズでは、自然言語処理全般に関するより詳細な実装や学習の方法を紹介しておりますので、是非ご覧ください。