【はじめての BERT 】GoogleColaboratory上に BERT の環境構築

私の研究で BERT を使うことになったので BERT の使い方の備忘録を記事にしました。環境構築～テスト実行を載せています。これから初めて BERT を触ろうとしている方の参考になれば幸いです。

## 環境構築の前に
日本語の自然言語処理をするために BERT を使うのですが、自然言語処理で欠かせない形態素解析には JUMAN++ というものを使います。これは京大で開発された形態素解析器なのですが、MeCabよりも優れているという情報があったので今回は BERT と JUMAN++ をインストールします。

そして、今回もGoogleColaboratoryで開発を進めることを前提に話を進めていきます。

## JUMAN++ のインストール
今回参照するサイトはこちらです

https://www.mojirca.com/2019/08/colab-jumanpp.html

まず、環境構築のためだけのファイル（例「BERT・JUMAN++インストール.ipynb」）を作成します。

そのファイルの最初のコードブロックを以下のようにします。

~~~python
# JUMAN++インストール
!wget https://github.com/ku-nlp/jumanpp/releases/download/v2.0.0-rc2/jumanpp-2.0.0-rc2.tar.xz
!tar xfv jumanpp-2.0.0-rc2.tar.xz  
%cd jumanpp-2.0.0-rc2
!mkdir bld
%cd bld
!cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local
!make install -j2

# インストールしたものを自分のGoogleドライブにコピー
!mkdir juman_bu
!mkdir juman_bu/bin
!mkdir juman_bu/libexec
!cp -rf /usr/local/bin/jumanpp ./juman_bu/bin/
!cp -rf /usr/local/libexec/jumanpp ./juman_bu/libexec/ 

# 使うとき（実行ファイルの初めの部分にこれをコピペ）
# !mkdir /usr/local/libexec
# !cp -rf ./juman_bu/bin/jumanpp /usr/local/bin/
# !cp -rf ./juman_bu/libexec/jumanpp /usr/local/libexec/
# !chmod 755 /usr/local/bin/jumanpp
# !chmod 755 /usr/local/libexec/jumanpp/jumandic.config
# !chmod 755 /usr/local/libexec/jumanpp/jumandic.jppmdl

# 動作確認（コマンド）
!echo "おはようございます" | jumanpp

# 動作確認（pyknpから）
!pip install pyknp
from pyknp import Juman
jumanpp = Juman()
result = jumanpp.analysis("おはようございます")
for mrph in result.mrph_list():
    print(mrph.midasi, mrph.yomi, mrph.genkei, mrph.hinsi)
~~~

これを実行すればJUMAN++がインストールされて、動作確認までできます。

ちなみに動作確認の結果はこんな感じでした。↓

~~~
mkdir: cannot create directory ‘/usr/local/libexec’: File exists
おはよう おはよう おはよう 感動詞 12 * 0 * 0 * 0 "代表表記:おはよう/おはよう"
ございます ございます ございます 接尾辞 14 動詞性接尾辞 7 動詞性接尾辞ます型 31 基本形 2 "代表表記:御座います/ございます"
EOS
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/
Requirement already satisfied: pyknp in /usr/local/lib/python3.7/dist-packages (0.6.1)
Requirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from pyknp) (1.15.0)
おはよう おはよう おはよう 感動詞
ございます ございます ございます 接尾辞
~~~

細かい解説は参照元のサイトにありますが、簡単に説明します。

本来GoogleColaboratoryでJUMAN++を使おうと思ったら数分かかるこのインストールを、実行ファイルを作成する度にしないといけないのですが、一旦自分のGoogleドライブにJUMAN++を保存して次回からはドライブからコピーしてくることでインストール作業を省くという、単純ですが画期的な手法です。

「次回からコピーしてくる」というのは上記コードの「# 使うとき（実行ファイルの初めの部分にこれをコピペ）」でコメントアウトしている部分のコードでできますが、その方法もこの後「 BERT を実行」で説明します。

## BERT （日本語Pretrainedモデル）のダウンロード

ここからは次のサイトを参照します

https://toukei-lab.com/bert#JUMAN

先ほどのファイルの続きに以下の二つのコードブロックを追加していきます。

~~~python
# Googleドライブと接続
from google.colab import drive 

drive.mount('/content/drive')
~~~
~~~python
!mkdir -p /content/drive/'My Drive'/bert/japanese

cd /content/drive/'My Drive'/bert/japanese

import urllib.request

kyoto_u_bert_url = "http://nlp.ist.i.kyoto-u.ac.jp/nl-resource/JapaneseBertPretrainedModel/Japanese_L-12_H-768_A-12_E-30_BPE.zip"
urllib.request.urlretrieve(kyoto_u_bert_url, "Japanese_L-12_H-768_A-12_E-30_BPE.zip")

!unzip Japanese_L-12_H-768_A-12_E-30_BPE.zip
~~~

これらを実行してエラーが起きなかったら成功です。

これで環境構築は終了です！

次は実際に BERT で自然言語処理をテスト実行します。

## BERT を実行

引き続き先ほどのサイトを見ながら進めていきます。

**新たに実行ファイルを作成して**最初のコードブロックに以下のコードを書きます。

~~~python
!mkdir /usr/local/libexec
!cp -rf /content/drive/'My Drive'/bert/japanese/juman_bu/bin/jumanpp /usr/local/bin/
!cp -rf /content/drive/'My Drive'/bert/japanese/juman_bu/libexec/jumanpp /usr/local/libexec/
!chmod 755 /usr/local/bin/jumanpp
!chmod 755 /usr/local/libexec/jumanpp/jumandic.config
!chmod 755 /usr/local/libexec/jumanpp/jumandic.jppmdl
~~~

このコードは先ほどJUMAN++をインストールしたときにコメントアウトしていたコードです。インストールして保存していたJUMAN++を引っ張り出します。ここで使うんですねー。

続けて以下のコードブロックを追加してください。

~~~python
# Googleドライブに接続
from google.colab import drive 

drive.mount('/content/drive')
~~~
~~~python
# ライブラリをpipインストール
!pip install transformers
!pip install pyknp

# Python上のインポート
import torch
from transformers import BertTokenizer, BertForMaskedLM, BertConfig
import numpy as np
from pyknp import Juman
jumanpp = Juman()

# 必要なパラメータやモデル、BERTが扱いやすい形に加工するための変換処理などを先ほどダウンロードした日本語Pretrainedモデルから取得
config = BertConfig.from_json_file('/content/drive/My Drive/bert/japanese/Japanese_L-12_H-768_A-12_E-30_BPE/bert_config.json')

model = BertForMaskedLM.from_pretrained('/content/drive/My Drive/bert/japanese/Japanese_L-12_H-768_A-12_E-30_BPE/pytorch_model.bin', config=config)
bert_tokenizer = BertTokenizer('/content/drive/My Drive/bert/japanese/Japanese_L-12_H-768_A-12_E-30_BPE/vocab.txt',
 do_lower_case=False, do_basic_tokenize=False)
~~~

ここまでは準備で、ここから処理をしていきます。

コードとその結果を示していきます。

~~~python
# JUMAN++によって品詞分解

text = "KankyouKouchikuは＊を発信するサイトです"
result = jumanpp.analysis(text)
tokenized_text = [mrph.midasi for mrph in result.mrph_list()]
print(tokenized_text)
~~~
    ['KankyouKouchiku', 'は', '＊', 'を', '発信', 'する', 'サイト', 'です']
~~~python
# 文章の区切れやマスクする部分をBERTに明示的に知らせるために、SEPやMASKを挿入

tokenized_text.insert(0, '[CLS]')
tokenized_text.append('[SEP]')
masked_index = 3
tokenized_text[masked_index] = '[MASK]'
print(tokenized_text)
~~~
    ['[CLS]', 'KankyouKouchiku', 'は', '[MASK]', 'を', '発信', 'する', 'サイト', 'です', '[SEP]']
~~~python
# 得られたテキストをBERT用に変換

tokens = bert_tokenizer.convert_tokens_to_ids(tokenized_text)
tokens_tensor = torch.tensor([tokens])
~~~
~~~python
# マスクされた部分をBERTで予測

model.eval()
with torch.no_grad():
  outputs = model(tokens_tensor)
  predictions = outputs[0]
_,predicted_indexes = torch.topk(predictions[0, masked_index], k=20)
predicted_tokens = bert_tokenizer.convert_ids_to_tokens(predicted_indexes.tolist())
print(predicted_tokens)
~~~

ここまで実行して、以下のような結果になれば成功です！

    ['情報', 'ニュース', 'インターネット', 'コンテンツ', 'ブログ', '音楽', '文化', '魅力', '[UNK]', '動画', 'メッセージ', 'トレンド', '日本', 'それ', '話題', '広告', 'サービス', 'メール', '写真', '技術']