自然言語処理モデルBERTの検証(1)-予測のお試し


はじめに

BERTを題材に自然言語処理(NLP)の検証スタートします。
BERTを上回るNLPモデルも最近は開発されているようです(XLNet、MT-DNN)。

BERT(自然言語処理モデル)の定義を、Wikipedia から引用:

Bidirectional Encoder Representations from Transformers(BERT)は、
Googleによって開発された、
自然言語処理(NLP)の事前学習用ためのTransformerベースの機械学習手法。

「Transformerベース」を深掘りしたい気持ちではありますが、とにかく試してみたい。

その前に、BERTに何ができる?

  • 提示された単語に対し、意味の近い別の単語を与える
  • 提示された文書の内容を基に、質問に答える
  • 異なる2つの表現について、同じことを言っているか判断
  • 文章から重要な部分を抜き出して要約
  • 別言語への翻訳(えー、すごい)

ですので、チャットボット、検索エンジンのレコメンデーション、スマートスピーカーなどに利用されているようです。

BERTの特徴

  • 文章の文脈を理解できる
  • 性能がよい(従来のNLPモデルCNNやRNNと比べ)
  • 学習用データの収集やラベリングコストが低い(これは大きいですね)
    • ラベルの付いていない既存の大量教師なしデータで事前学習ができる

早速試してみたい

学習済みBERTをさくっと試せるDockerイメージを名人が用意してくださっていました。
感謝感謝。

すぐに試せる日本語BERTのDocker Imageを作ってみた

BERTはTransformersを使用されたようです。

検証環境

CPU: Intel(R) Core(TM) 3.30GHz(4コア8スレッド)
メモリ: 16 GB
OS: Ubuntu 20.04 LTS

ちなみに、Ubuntuは、Windows 10で以下のように管理者権限で導入しました。

> wsl --install -d Ubuntu-20.04

事前準備

Dockerのインストール

sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
sudo apt update
apt-cache policy docker-ce
sudo apt install docker-ce
sudo service docker start
sudo service docker status
* Docker is running

dockerコマンドを実行するたびに sudoを入力しないようにする。
ユーザ名をdockerグループに追加。

sudo usermod -aG docker `id -un`
su - `id -un`

検証スタート

  • Dockerイメージをダウンロード(2GB以上あるので待たされます)
docker pull ishizakiyuko/japanese_bert_trial:1.0.1
  • Dockerコマンドを実行する
docker run -p 8888:8888 -d ishizakiyuko/japanese_bert_trial:1.0.1
xxx(コンテナID)

出力されるコンテナIDをコピーします。

  • logからjupyterへのアクセスURLを調べる
docker logs <コンテナID>

... ...
    Or copy and paste one of these URLs:
        http://327bef4aee86:8888/?token=xxx
     or http://127.0.0.1:8888/?token=xxx
  • ブラウザからjupyterにアクセスする
 http://127.0.0.1:8888/?token=xxx
  • Python3のnotebookを開く

BERTの検証

  • まず、BERTによる形態素解析

名人のサンプルコードで、textだけ書き換えました。

import os
import torch
from transformers import BertForMaskedLM, BertConfig, BertTokenizer
from pyknp import Juman

BASE_PATH = './Japanese_L-12_H-768_A-12_E-30_BPE_WWM_transformers'
BERT_CONFIG = 'config.json'
BERT_MODEL = 'pytorch_model.bin'
VOCAVULARY_LIST = 'vocab.txt'

jumanpp = Juman()

# 形態素解析
text = '世の中の美味しいものを全部食べてみたいな'
result = jumanpp.analysis(text)
tokenized_text =[mrph.midasi for mrph in result.mrph_list()]
print(tokenized_text)

すると、ちゃんと形態素解析できました!

['世の中', 'の', '美味しい', 'もの', 'を', '全部', '食べて', 'みたいな']
  • つぎ、'美味しい'をマスク
# Mask 
tokenized_text.insert(0, '[CLS]')
tokenized_text.append('[SEP]')

masked_index = 3 # Maskしたいtextのindex 
tokenized_text[masked_index] = '[MASK]'
print(tokenized_text)

結果、

['[CLS]', '世の中', 'の', '[MASK]', 'もの', 'を', '全部', '食べて', 'みたいな', '[SEP]']
  • BERTモデル作成し、トークナイズ
# Bert model
config = BertConfig.from_json_file(os.path.join(BASE_PATH, BERT_CONFIG))
model = BertForMaskedLM.from_pretrained(os.path.join(BASE_PATH, BERT_MODEL), config=config)
tokenizer = BertTokenizer(os.path.join(BASE_PATH, VOCAVULARY_LIST), do_lower_case=False, do_basic_tokenize=False)

# token化
indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)
tokens_tensor = torch.tensor([indexed_tokens])
print(tokens_tensor)

トークナイズの結果は

tensor([[    2, 21199,     5,     4,    60,    10,  7299, 13135, 24681,     3]])
  • '美味しい'に代わる単語を予測
# 予測
model.eval()

tokens_tensor = tokens_tensor.to('cpu')
model.to('cpu')

with torch.no_grad():
    outputs = model(tokens_tensor)
    predictions = outputs[0]

_, predicted_indexes = torch.topk(predictions[0, masked_index], k=5)
predicted_tokens = tokenizer.convert_ids_to_tokens(predicted_indexes.tolist())
print(predicted_tokens)

それっぽい予測できました。

['あらゆる', '大事な', '好きな', '悪い', 'いい']

おわりに

自然言語処理モデルBERTの概念を理解し、少し試してみました。
いろいろ面白いことができそうですので検証続けます。
お楽しみに。

[次回] 自然言語処理モデルBERTの検証(2)-MeCab+WordPiece