huggingface transformers を使って日本語 BERT モデルをファインチューニングして感情分析 (with google colab) part01
March 12, 2021
こちらの記事の内容は古くなっています。最新版は以下のページをご覧ください
https://jupyterbook.hnishi.com/language-models/fine_tune_jp_bert_part01.html
本記事では、日本語 BERT モデルをファインチューニングして感情分析する方法を解説します。
BERT の詳細な解説は、この記事のスコープ外とします。
この記事は、part01 です。
part02 では、まとまったデータセットを使って実際に学習と評価を行っています。
すべての記事の目次は以下をご参照ください。
https://github.com/hnishi/handson-language-models/blob/main/README.md
参考
必要なライブラリのインストール
!pip install -q transformers
[K |████████████████████████████████| 1.9MB 5.4MB/s[K |████████████████████████████████| 890kB 23.9MB/s[K |████████████████████████████████| 3.2MB 25.4MB/s[?25h Building wheel for sacremoses (setup.py) ... [?25l[?25hdone
import pandas as pdimport torchfrom transformers import BertTokenizer, BertForSequenceClassification, pipelinefrom transformers import AdamW
日本語 BERT の簡単なチュートリアル
最初に、huggingface transformers を使った日本語 BERT pre-trained model の使い方や fine tuning の方法を、簡単に見ていくことにします。
今回試す事前学習済みモデルとしては、 bert-large-japanese を利用してみたいと思います。
補足
最近 (2021-03-05)、東北大学のグループから BERT の日本語 pre-trained models の version 2 が公開されています。
このリリースでは、より大きなアーキテクチャの bert-large-japanese モデルも公開されています。
- cl-tohoku/bert-base-japanese-v2
- cl-tohoku/bert-large-japanese
BERT-base models consist of 12 layers, 768 dimensions of hidden states, and 12 attention heads.BERT-large models consist of 24 layers, 1024 dimensions of hidden states, and 16 attention heads.
Pre-trained Model を使って推論
BERT なので、mask された token を予測するように学習されています。
したがって、pre-trained model を使って、文章中の穴埋め (文章中の欠損箇所の予測) を行うことができます。
以下の2種類のモデルを使って推論してみました。
- cl-tohoku/bert-large-japanese
- bert-base-multilingual-uncased (BERT の多言語モデル)
結果、 bert-base-multilingual-uncased
のほうが自然な文章となりました。
この違いは、学習に使用されたデータセットに依存しているのかと思いましたが、どちらのモデルも wikipedia をデータセットとして利用しているので、謎です。
model_name = "cl-tohoku/bert-large-japanese"unmasker = pipeline('fill-mask', model=model_name)unmasker("こんにちは、私は[MASK]モデルです。")
[{'score': 0.13797800242900848,'sequence': 'こんにちは 、 私 は お モデルです 。','token': 860,'token_str': 'お'},{'score': 0.09143581241369247,'sequence': 'こんにちは 、 私 は う モデルです 。','token': 856,'token_str': 'う'},{'score': 0.03621169179677963,'sequence': 'こんにちは 、 私 は こう モデルです 。','token': 11668,'token_str': 'こう'},{'score': 0.028521882370114326,'sequence': 'こんにちは 、 私 は 、 モデルです 。','token': 828,'token_str': '、'},{'score': 0.02647402137517929,'sequence': 'こんにちは 、 私 は いら モデルです 。','token': 24523,'token_str': 'いら'}]
model_name = "bert-base-multilingual-uncased"unmasker = pipeline('fill-mask', model=model_name)unmasker("こんにちは、私は[MASK]モデルです。")
[{'score': 0.21041248738765717,'sequence': 'こんにちは 、 私 は 、 モテルてす 。','token': 1482,'token_str': '、'},{'score': 0.12128563225269318,'sequence': 'こんにちは 、 私 は 元 モテルてす 。','token': 2051,'token_str': '元'},{'score': 0.033908627927303314,'sequence': 'こんにちは 、 私 は 初 モテルてす 。','token': 2178,'token_str': '初'},{'score': 0.029899440705776215,'sequence': 'こんにちは 、 私 は 女 モテルてす 。','token': 3014,'token_str': '女'},{'score': 0.021887250244617462,'sequence': 'こんにちは 、 私 は 男 モテルてす 。','token': 5846,'token_str': '男'}]
テキスト分類のための Fine Tuning の手順
以下、簡易的に 3 種類のラベル (positive: 2, neutral: 1, negative: 0) のデータを使って fine tuning を行います。
# 確認用のデータセットdf = pd.DataFrame([{"text": "私はこの映画をみることができて、とても嬉しい。", "label": 2},{"text": "今日の晩御飯は何だろう。", "label": 1},{"text": "猫に足を噛まれて痛い。", "label": 0}])
train_docs = df["text"].tolist()train_labels = df["label"].tolist()
モデルのダウンロード (キャッシュがない場合) と読み込み
同時にダウンロードされるトークナイザーを利用して、データセットの text の encoding を行います。
# Ref: https://huggingface.co/transformers/training.html#pytorchmodel_name = "cl-tohoku/bert-large-japanese"model = BertForSequenceClassification.from_pretrained(model_name, num_labels=3)tokenizer = BertTokenizer.from_pretrained(model_name)
encodings = tokenizer(train_docs, return_tensors='pt', padding=True, truncation=True, max_length=128)input_ids = encodings['input_ids']attention_mask = encodings['attention_mask']
# Fine-tuning in native PyTorch# > the AdamW() optimizer which implements gradient bias correction as well as weight decay.optimizer = AdamW(model.parameters(), lr=1e-5)labels = torch.tensor(train_labels).unsqueeze(0)outputs = model(input_ids, attention_mask=attention_mask, labels=labels)loss = outputs.lossloss.backward()optimizer.step()
Fine Tune したモデルで推論
学習に使ったデータを入力して推論してみます。
sentiment_analyzer = pipeline("sentiment-analysis", model=model, tokenizer=model_name)
sentiment_analyzer("これは、テストのための文章です")
[{'label': 'LABEL_0', 'score': 0.3931503891944885}]
_ = list(map(lambda x: print(f"{x}: {sentiment_analyzer(x)}"), train_docs))
私はこの映画をみることができて、とても嬉しい。: [{'label': 'LABEL_2', 'score': 0.3935401141643524}]今日の晩御飯は何だろう。: [{'label': 'LABEL_1', 'score': 0.5711930990219116}]猫に足を噛まれて痛い。: [{'label': 'LABEL_0', 'score': 0.5832840204238892}]
スコアは低いですが、学習に使ったデータセットに関して、正しいラベルが予測できていることを確認できました。
まとめ
簡単な文章とラベルを用意して fine tuning する方法を記載しました。
次の記事 では、より大きなデータセットを使って、より時間のかかる学習を試してみたいと思います。