BERT 日本語モデルの実験
概要
BERT (arxiv, GitHub) を理解するための第一歩として、訓練済み日本語モデルを fine-tune して文章のトピック分類の実験をしました。
この記事に含まれない内容:
- BERT の説明
この記事に含まれる内容:
- 訓練済み BERT 日本語モデルのまとめ
- 環境構築や実験にあたって私が遭遇した問題とその対処
- BERT が分類に失敗したサンプルの定性的な分析
訓練済みの BERT 日本語モデル
現時点で私の知る限り、日本語に適用できる訓練済み BERT モデルは以下の4つがあります。特に今回の実験では、
という理由で BERT with SentencePiece for Japanese text を選択しました。
BERT-Base, Multilingual
BERT の GitHub レポジトリで公式に提供されている多言語モデル。使っているトークナイザーが日本語に適しておらず、過剰に小さな(ほぼ 1 文字単位の)トークンに分割されてしまうことが報告されています*1。
BERT with SentencePiece for Japanese text
菊田遥平さんが提供しているモデル。前述のトークンの問題に対処するため SentencePiece を使用しています。
hottoSNS-BERT
ホットリンクの R&D 部が提供しているモデル。ここに挙げたモデルの中で唯一 Twitter データをコーパスに使っています。
- GitHub
- ブログ記事
- トークナイザー : SentencePiece
- コーパス : 日本語ツイートのコーパス(ホットリンク社内製、非公開)
BERT日本語Pretrainedモデル
京大の黒橋・河原研究室が提供しているモデル。当然ながら、トークナイザーには自製の JUMAN を採用しています。
TensorFlow + GPU 環境構築
私の研究室は GTX 1080 Ti を 2 枚積んだ GPU サーバーを所有しているのですが、極端に計算パワーを必要とする研究を私は今までしていなかったため、一度も使ったことがありません。今回は金をかけずにとりあえず BERT を試したかったこともあり、良い機会なのでこの GPU サーバーを使うことにしました。
しかし案の定と言うべきか、最初に環境を構築する段階で多数のエラーに見舞われかなり時間を費やしたので、その記録を残しておきます。
tensorflow-gpu インストール時のエラー対処
TensorFlow で GPU 計算をするためには tensorflow-gpu
パッケージが必要です((https://www.tensorflow.org/install/gpu)。これをインストールした後に Python で import tensorflow
を試みた時に以下のエラーが発生しました。
ImportError: libcublas.so.10.0: cannot open shared object file: No such file or directory
issue を見る限り、 TensorFlow と CUDA のバージョンが合致しない時にこのエラーが発生するようです。そこで、サーバーにインストールされていた CUDA のバージョンを確認すると
$ cat /usr/local/cuda/version.txt CUDA Version 9.2.148
TensorFlow 最新安定版の 1.13.1 では CUDA 10 しかサポートしていない*4ので、どちらかのバージョンを変更する必要があります。管理者権限無しで手っ取り早く対処するために TensorFlow の 1.12.0 をインストールしようとしたところで再びエラーに遭遇しました。
ERROR: Could not find a version that satisfies the requirement tensorflow-gpu==1.12.0 (from versions: 1.13.0rc1, 1.13.0rc2, 1.13.1, 2.0.0a0)
もちろんバージョン 1.12.0 は存在していますが、 Python 3.7 と互換性が無い*5ためにインストールできなかったようです。これには Python 3.6 の仮想環境を作成してから TensorFlow をインストールすることで対処しました。
$ conda create -n bert python=3.6 $ conda activate bert $ conda install -y tensorflow-gpu==1.12.0
最後に、 tensorflow-gpu
が正常にインストールされて GPU が使用可能であることを確認します。
$ python -c "import tensorflow as tf; tf.test.is_gpu_available()" 2019-05-28 15:18:53.502786: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 AVX512F FMA 2019-05-28 15:18:54.302067: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1432] Found device 0 with properties: name: GeForce GTX 1080 Ti major: 6 minor: 1 memoryClockRate(GHz): 1.582 pciBusID: 0000:17:00.0 totalMemory: 10.92GiB freeMemory: 10.77GiB 2019-05-28 15:18:54.377021: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1432] Found device 1 with properties: name: GeForce GTX 1080 Ti major: 6 minor: 1 memoryClockRate(GHz): 1.582 pciBusID: 0000:65:00.0 totalMemory: 10.91GiB freeMemory: 10.77GiB
GPU の状態監視
nvidia-smi コマンドを使うと、 GPU の使用率などを確認することができます。
特に --format=csv
オプションを指定すると結果が CSV 形式で出力されるので、スクリプトで読み込んで自動的に通知すると便利です。
私はこのレポジトリ に少し手を加えて Python 3 用に修正し、 GPU の状態を Slack の web hook に通知するようにしています。
メモリ解放
Jupyter Notebook 上で TensorFlow による GPU 計算が終わった後に状態を見ると、 GPU 使用率が 0% の一方で大量のメモリが占有されたままになっていました。ドキュメントを読む限り、これは特に異常なことではありません。メモリのフラグメンテーションを避けるために、 TensorFlow は プロセスが終了するまで GPU メモリを一切解放しない 仕様になっているようです。
Jupyter で GPU 計算が完了した後は忘れずにカーネルをシャットダウンしましょう。
実験
方法
finetune-to-livedoor-corpus.ipynb をほぼそのまま使用しました。
ただし、実験時に GPU メモリの空き容量が 7GB 程度しか無かったため、 run_classifier.py
の引数 train_batch_size
を 4 から 2 に下げて実行しました*6。
データ
livedoor ニュースコーパス (NHN Japan株式会社がクリエイティブ・コモンズライセンス「表示 – 改変禁止」のもと提供)
livedoor ニュースの 9 つのカテゴリごとに収集した記事のテキストデータです。全部で 7376 個の記事があり、各カテゴリごとの内訳は表のようになっています。
カテゴリ | 記事数 | 備考 |
---|---|---|
トピックニュース | 771 | 芸能ニュースなど |
Sports Watch | 901 | |
IT ライフハック | 871 | |
家電チャンネル | 865 | |
MOVIE ENTER | 871 | |
独女通信 | 871 | |
エスマックス | 871 | スマホ、モバイル、ガジェットなど |
livedoor HOMME | 512 | 男性向け、キャリア、デジタルなど |
Peachy | 843 | 女性向け、恋愛、ファッションなど |
結果
f1-score などの数値は、 finetune-to-livedoor-corpus.ipynb の先頭に記載されている結果と大差無いため割愛します。
BERT が「不正解」の予測をした全 41 件のサンプル (csv ファイル) を見てみると、もう少しおもしろいことがわかります。例えば以下の記事を読んで、 livedoor ニュースの 9 つのカテゴリのどれに該当すると思いますか?
手のひらに載る本格派 LUMIX G2のGはグレートだ今やマイクロ一眼はデジタルカメラの人気商品となり、各社とも続々とこの市場に参入を開始している。マイクロ一眼は、レトロなスタイルに加え、ミラーレスによる小型化でバックに入れて持ち歩けるデジタル一眼として年齢を問わずに使えるところが受けている。とはいえ、今人気のマイクロ一眼には、コンパクトデジカメやレンズ一体型デジカメに比べて高画質というメリットはあるが、デメリットもある。パナソニック LUMIX DMC-G2は、マイクロ一眼のデメリットを解消したカメラなのだ。 (後略)
実際のカテゴリは「livedoor HOMME」で、一方 BERT が予測したカテゴリは「IT ライフハック」でした。また、その次に予測確率 で「家電チャンネル」が続きます。もうお気づきかと思いますが、これら 3 つのカテゴリは排反なものではなく重複があってもおかしくありません。上述のサンプルであれば「livedoor HOMME」よりむしろ「家電チャンネル」か「IT ライフハック」の方が尤もらしいカテゴリに感じます。
classification の問題は、カテゴリが排反か否かによって"multi-class" と "multi-label" に分けられます。しかし今回の実験設定には以下のようなミスマッチがあり、それが原因で「正解より予測の方が妥当」という状況が発生しています。
- カテゴリは実際には multi-label であるべき
- 正解データは multi-class
- 今回用いた fine-tuning のコードは multi-class 用(softmax で確率を出力)
他の不正解サンプルについても「正解より予測の方が妥当」が大半を占めており、本当に予測ミスだと思われるものは 6 件 (csv ファイル)しかありません。 例として、以下の記事は実際には「livedoor HOMME」ですが、BERT はこれを「Peachy」と予測しました。
イケメン社長、野菜を売る——、若林輝男さんに聞く“農業ビジネスのカタチ”生産者と消費者が直接結びつく新たな市場として、農林水産省の補助事業として昨年9月に始まり、全国9都市で開催されるようになったマルシェジャポン。晴れ渡った3月の休日、大勢のお客さんで賑わう六本木の会場では、なんと“生姜(しょうが)のみ”を売る背が高くルックスのよい一人の男性を発見しました。土日は都内のマルシェジャポン会場で、平日は三輪自転車を走らせ都心の駅前を中心に、高知産の新鮮な生姜や青森産の大蒜(にんにく)を販売しているリーベル・アソシエイツ合同会社の代表=若林輝男さんです。 (後略)
結論
Google Colab 使った方が手っ取り早く実験できると思います。
*1:https://techlife.cookpad.com/entry/2018/12/04/093000
*2:https://github.com/google-research/bert/blob/master/multilingual.md#tokenization
*3:https://github.com/google-research/bert/blob/master/multilingual.md#data-source-and-sampling
*4:https://www.tensorflow.org/install/source#linux
*5:https://github.com/tensorflow/tensorflow/issues/23478
*6:https://github.com/google-research/bert#out-of-memory-issues