はじめに
いつも参考にさせていただいているDevelopers.IOさんのサイトに掲載されている記事BERTの日本語事前学習済みモデルでテキスト埋め込みをやってみるを見ると、いつものように試したくなるのが人情というもの。そして、色々とつまづいた点もあり、ちょっと修正しなければならなかったり、環境を揃えなければいけない点もありました。これらをできるだけ簡単に揃えて試すところまでできたので紹介します。
ベースイメージ
やっぱりお手軽に試すには、サイズは小さい方が正義ということで、alpineベースにしようとしたけれど、そもそもtensorflowが対応していなかった(←)。ということで、tensorflowと親和性が良いUbuntuベースにpython環境があるものを利用する方針。
ただ、python公式を探しても基本debianベースのイメージしかなかったため、3.7.5-slim-busterを参考にubuntuベースのイメージを用意して利用することとした。サイズ的にはまぁまぁな感じです。
0bara/python 3.7.5-ubuntu18.04 167MB
python 3.7.5-slim-buster 178MB
juman++ & tensorflow
ただ、ベースイメージを小さくしても、結局形態素解析(とその辞書)やtensorflow動作環境を入れると大きくなってしまいます。
# docker/Dockerfile
FROM 0bara/python:3.7.5-ubuntu18.04
MAINTAINER t.obara
RUN apt update -y && apt upgrade -y && \
apt install -y --no-install-recommends \
build-essential cmake git curl
WORKDIR /opt
COPY requirements.txt /opt
COPY bin /opt/bin
RUN curl -L https://github.com/ku-nlp/jumanpp/releases/download/v2.0.0-rc3/jumanpp-2.0.0-rc3.tar.xz -o /tmp/j.txz \
&& cd /tmp && tar xJfv j.txz \
&& cd jumanpp-2.0.0-rc3 \
&& mkdir build && cd build \
&& cmake .. -DCMAKE_BUILD_TYPE=Release \
&& make install \
&& cd /opt \
&& git clone https://github.com/0bara/bert.git \
&& pip install -r requirements.txt \
&& rm -rf /tmp/* \
&& apt autoremove -y build-essential cmake git curl \
&& apt -y clean \
&& rm -rf /var/cache/* \
&& rm -rf /var/lib/apt/lists/*
CMD ["/bin/bash"]
これでサイズが1.5G近く
bert_env latest 1.51GB
ちなみに、元のBERTコードは、TensorFlow1.11.0で確認したとのことで、新しいTensorFlowだとエラーやワーニングが出てきます。既にdeprecatedなメソッドなどがエラー、もうすぐでdeprecatedだよというワーニングがある。基本的にはimport tensorflow as tf
を、import tensorflow.compat.v1 as tf
とするとかなりの軽減される。ワーニングも全て解消したいとは思ったのだけれど、それなりにあるLayerをEager modeに変換するのは厄介なので、その部分のワーニングは放置したけど、それなりに動くようにしたコードを置いたので、Docker Image内で取り込むようにしている。修正するのであれば、「Migrate your TensorFlow 1 code to TensorFlow 2」とか、「Writing custom layers and models with Keras」を読むのが良さそうです。
あ、肝心な事を忘れていましたが、Juman++を利用して日本語をトークン化する部分も同時に追加しています。この部分は元のページに詳しく記述されているので、ここでは特に触れない。
事前学習モデル
さらに事前学習モデルがあるともっと大きくなるのですが、このモデル自体は色々と出てくるでしょうし、ここに入れてより簡単にするか手間を増やすか考えたのですが、複数のモデルを同時に利用することもないだろうということから、利用したいモデルを選んで(自分でダウンロードして)利用していただく方法とした。(比較したい人は同梱の方が楽でしょうけど。)
一応、ダウンロードして動く事を確認したのは以下3つのモデルです。
1、2は同じサイトで、それぞれtensorflow用のzipファイルをダウンロードし、所定の場所に配置してください。3については「ダウンロードリンク」が示されているので、そこを辿り、GoogleDriveにあるtensorflow版に個々のファイルがあるので、それぞれダウンロードして所定の場所においてください。所定の場所については、以降に記載する手順の中にあります。
環境構築準備
それほど難しい作業ではないけれど、手軽と言いつつ、それなりに面倒かもしれない。
以下に手順を示す。
# 作成したファイルのダウンロード
$ git clone https://github.com/0bara/bert_env.git
$ cd bert_env
# Dockerイメージの作成
$ docker-compose build
# extract_features.pyを実行する際に入力するテキストをinput.txtを配置する場所としてworkディレクトリを用意する。ここには実行結果(output.jsonlと、output.tsv)が出力される。binディレクトリに入力例のテキストを配置しているので、binをworkにシンボリックリンクしている。自分で入力テキストを用意するのであれば、workディレクトリを作成するだけで良い。
$ ln -s docker/bin work
$ cd work
$ ln -s input_ex1.txt input.txt
$ cd ..
# モデルデータを用意する
$ mkdir model
# このディレクトリにダウンロードしたファイルを配置する
$ curl http://nlp.ist.i.kyoto-u.ac.jp/nl-resource/JapaneseBertPretrainedModel/Japanese_L-12_H-768_A-12_E-30_BPE.zip -o model/Japanese_L-12_H-768_A-12_E-30_BPE.zip
$ cd model
$ unzip Japanese_L-12_H-768_A-12_E-30_BPE.zip
$ cd ..
上記の作業により、以下のようなファイル構成となっていれば良い。
$ tree
.
├── README.md
├── docker
│ ├── Dockerfile
│ ├── bin
│ │ ├── btest.sh
│ │ ├── conv_tsv.py
│ │ ├── elmo.env
│ │ ├── input.txt -> input_ex1.txt
│ │ ├── input_ex1.txt
│ │ ├── input_ex2.txt
│ │ ├── norm.env
│ │ ├── output.jsonl
│ │ ├── output.tsv
│ │ └── wwm.env
│ ├── jumanpp-2.0.0-rc3.tar.xz
│ └── requirements.txt
├── docker-compose.yml
├── model
│ ├── Japanese_L-12_H-768_A-12_E-30_BPE
│ │ ├── README.txt
│ │ ├── bert_config.json
│ │ ├── bert_model.ckpt.data-00000-of-00001
│ │ ├── bert_model.ckpt.index
│ │ ├── bert_model.ckpt.meta
│ │ └── vocab.txt
│ └── Japanese_L-12_H-768_A-12_E-30_BPE.zip
└── work -> docker/bin
実行してみる
$ docker-compose up
これを行うと、workディレクトリにoutput.jsonlとoutput.tsvが出力される。
可視化
これも元のページと同じなので軽く
Embedding Projectorを利用して可視化できるようにしています。利用するのは、入力で利用したinput.txtと出力されたoutput.tsvです。
- 上記Embedding Projectorを開く
- 左側ペインにあるLoadボタンを押すとダイヤログが開く
- 上部[Step 1: Load a TSV file of vectors]に対してoutput.tsvを指定
- 下部[Step 2 (optional): Load a TSV file of metadata]にinput.txtを指定
ダイヤログ以外をクリックすると結果が表示される
別のモデルを利用する場合
Whole Word Masking model
tensorflow版のJapanese_L-12_H-768_A-12_E-30_BPE_WWM.zip をダウンロードし、modelディレクトリに置いてunzipする
以下のような配置になれば良いかと。
├── model
│ ├── Japanese_L-12_H-768_A-12_E-30_BPE_WWM
そして、以下のコマンドで実行する
$ docker-compose run bert /bin/sh bin/btest.sh bin/wwm.env
ちなみに、bin/wwm.envファイルは環境変数を設定しているファイルで、各モデルがあるディレクトリに応じて変更すれば良いが、上記の配置にしておけば、そのまま修正する必要はない。
これは次のモデルでも同様である。
日本語ビジネスニュース記事(300万記事)
modelディレクトリ直下にELMoディレクトリを作成し、ダウンロードリンクからダウンロードした各ファイルを配置する。
├── ELMo
│ ├── bert_config.json
│ ├── output_model.ckpt.data-00000-of-00001
│ ├── output_model.ckpt.index
│ ├── output_model.ckpt.meta
│ └── vocab.txt
そして、以下のコマンドで実行する
$ docker-compose run bert /bin/sh bin/btest.sh bin/elmo.env
参考ページ
- https://dev.classmethod.jp/machine-learning/bert-text-embedding/
- http://nlp.ist.i.kyoto-u.ac.jp/index.php?BERT%E6%97%A5%E6%9C%AC%E8%AA%9EPretrained%E3%83%A2%E3%83%87%E3%83%AB
- https://qiita.com/mkt3/items/3c1278339ff1bcc0187f
最後に
本当はGPUを利用した場合も試したかったのだけれど、すぐ使えるモノがなかったのと、AWSで試そうかと調べたんだけど、そこまでの元気がありませんでした。。
また、「機械学習ツールを掘り下げる」のAdventCalendarに参加している割に、機械学習という単語がタイトルにもタグも入れないという記事ですが、生暖かい感じで流し読みいただけたら幸いです。