こいぬの散文的備忘録

散文的備忘録

BERTを動かしてみた

モチベーション

Kaggleに自然言語処理×感情分析っぽい問題を発見。そういえば、最近流行りのBERTを触ってみたいなぁ。
以上。

BERT

BERTはBidirectional Encoder Representations from Transformersの略称。訳すと、『トランスフォーマーを使った、両方向から符号化した表現』とかですかね。ちょっと意味わかんないね。最近、自然言語処理の界隈すごく流行ってる。google検索エンジンとか翻訳にも使われてる。
論文:https://arxiv.org/abs/1810.04805
参考: https://ainow.ai/2019/05/21/167211/

こんな認識
・Transformerベースの符号器
・教師なしで、文章データから知識獲得をする
・ものすごく表現力の高い分散表現を生成する
・転移学習に優れ、あらゆる分野に応用できる

動かしてみる

今回は、Hugging Faceさんの"Transformers "を拝借する。
github: https://github.com/huggingface/transformers
docs: https://huggingface.co/transformers/index.html

目的: BERTを動かす
実装: Pytorch + Transformers
実行環境: google Colaboratory

英語学習済みモデル

まずはTransformersをインストール

!pip install transformers
今回はPytorch+TransformersでBERTを動かすのに必要なライブラリをインポート。今回はBERTの英語学習済みモデルとトークナイザーを使ってみる。
import torch
from transformers import BertTokenizer,BertModel
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertModel.from_pretrained('bert-base-uncased')
"I love dogs."という文章の各単語を分散表現にしてみる。
text = 'I love dogs.'
input_ids = torch.tensor(tokenizer.encode(text,add_special_tokens=True)).unsqueeze(0)
outputs = model(input_ids)
outputs[0]
すると、(1,6,768)のテンソルが出力される。'I love dogs.'はトークナイザーで([CLS], I, love, dogs, ., [SEP])の6単語に分解されてる。出力結果は768次元の各単語の分散表現をテンソル型で格納してる模様。

日本語学習済みモデル

次に日本語学習済みモデルとトークナイザーを使って単語の穴埋め問題をしてみる。
まずはMeCabをインストール

!pip install mecab-python3
次に先ほどと違い、日本語学習済みモデルとトークナイザーを使ってみる。なお、今回は単語予測をしたいのでBertForMaskedLMってやつをインポート
import torch
from transformers import BertJapaneseTokenizer,BertForMaskedLM
tokenizer = BertJapaneseTokenizer.from_pretrained('bert-base-japanese-whole-word-masking')
model = BertForMaskedLM.from_pretrained('bert-base-japanese-whole-word-masking')
今回は"ジャコ・パストリアスは僕の敬愛する偉大なベーシストだ"という文章を"ジャコ・パストリアスは僕の敬愛するxxxなベーシストだ"と加工して、BERTに僕がジャコパスをどう思っているか予想させる。
text = 'ジャコ・パストリアスは私の敬愛する偉大なベーシストだ'
input_ids = torch.tensor(tokenizer.encode(text,add_special_tokens=True)).unsqueeze(0)
outputs = model(input_ids)

masked_index = 11
predictions = outputs[0][0,masked_index].topk(5)
for i,index_t in enumerate(predictions.indices):
  index = index_t.item()
  token = tokenizer.convert_ids_to_tokens([index])[0]
  print(str(i+1)+'位:',token)
予想結果はこんな感じ。
1位: 偉大
2位: 重要
3位: 優秀
4位: 強力
5位: 有名
見事、BERTは僕がジャコパスを"偉大"と思ってることを見抜いた。BERT君、君とはうまい酒が飲めそうだ。