bert-as-service 日本語テキストのベクトル化サーバー構築
感情分析、テキスト分類など、多くのNLPアプリケーションで必要な処理として「テキストのエンコード/埋め込み」があります。
とある案件で約100万件/日のメールのテキスト分類タスクがあり、「テキストのエンコード/埋め込み」=「メール本文の固定長ベクトル化」をするため手法調査とサービス運用を視野にいれた環境構築をためしました。
おおよそ求めているのはこの辺りを満たすもの☟
・公開されている学習済みモデルを利用できる。
将来の運用にてモデルのfine-tuningは想定。初期ではモデルをゼロからトレーニングすることはしません。
・メール本文というそれなりに長い文章&複数文で構成されるテキストに対応する。
単語レベルの埋め込み表現でなく、文章コンテキストを表現します。
・実際の運用にはベクトル化後に分類タスクが控えており、ベクトル化自体高速な処理で終えたい。
幾つか調査した中で、2018年末に登場し様々な言語処理タスクで様々なSOTAを更新したNLPモデルBERTをエンコーダーとしてサービス化できる「bert-as-service 」の構築をしてみます。
bert-as-service 構築準備
「bert-as-service 」ではBERTをセンテンスエンコーダーとして使用してサービスとしてホストします。
以下のような機能を持っています。
・事前トレーニング済みの12/24レイヤーのBERTモデルを利用して構築される。(独自の学習済みモデルでも運用可能です。
・少量のコードでテキストを固定長のベクトルとして取得が可能。
・低遅延、高速処理に最適化されている。Tesla M40 24GBで900文/秒。
・複数のクライアント、複数GPUでスケールの拡張ができる。
インストール
(今回の環境)
OS Ubuntu 18.04
GPU GeForce GTX 1070
Python 3.6
Tensorflow 1.14.0
pipで簡単にインストールできます。
$ pip install -U bert-serving-server bert-serving-client
公開されている学習済みモデルを配置
次に学習済みモデルを適当な位置に保存しておきましょう。
今回はGoogleが公開しているモデルをダウンロードし、zipファイルを models ディレクトリにダウンロード&解凍をします。
Google AIがリリースした事前トレーニング済みBERTモデルのリスト:
BERT-Large, Uncased (Whole Word Masking)
: 24-layer, 1024-hidden, 16-heads, 340M parametersBERT-Large, Cased (Whole Word Masking)
: 24-layer, 1024-hidden, 16-heads, 340M parametersBERT-Base, Uncased
: 12-layer, 768-hidden, 12-heads, 110M parametersBERT-Large, Uncased
: 24-layer, 1024-hidden, 16-heads, 340M parametersBERT-Base, Cased
: 12-layer, 768-hidden, 12-heads , 110M parametersBERT-Large, Cased
: 24-layer, 1024-hidden, 16-heads, 340M parametersBERT-Base, Multilingual Cased (New, recommended)
: 104 languages, 12-layer, 768-hidden, 12-heads, 110M parametersBERT-Base, Multilingual Uncased (Orig, not recommended)
(Not recommended, useMultilingual Cased
instead): 102 languages, 12-layer, 768-hidden, 12-heads, 110M parametersBERT-Base, Chinese
: Chinese Simplified and Traditional, 12-layer, 768-hidden, 12-heads, 110M parameters
今回は多言語対応版モデルの BERT-Base, Multilingual Cased (New, recommended)
を利用します。
$ mkdir ./models
$ cd ./models
$ wget https://storage.googleapis.com/bert_models/2018_11_23/multi_cased_L-12_H-768_A-12.zip
$ unzip multi_cased_L-12_H-768_A-12.zip
./models/multi_cased_L-12_H-768_A-12/ 以下に学習済みBERTモデルデータが展開されます。
bert_config.json
bert_model.ckpt.data-00000-of-00001
bert_model.ckpt.index
bert_model.ckpt.meta
vocab.txt
追記)
Google公開以外のモデルとして「京都大学 大学院情報学研究科 知能情報学専攻 知能メディア講座 言語メディア分野 工学部電気電子工学科)黒川・川原研究室」で公開されている「BERT日本語Pretrainedモデル(tensorflow版)」での動作を確認しました。
サービスを起動
以下コマンドにて起動させます。 -model_dir オプションで学習済みモデルの位置ディレクトリを指定します。
$ bert-serving-start -model_dir ./models/multi_cased_L-12_H-768_A-12/
デフォルトではGPU処理仕様で起動し、なければCPUバージョンの起動がされます。
オプションのひとつとして -num_worker=[NUMBER_OF_WORKER] にて同時処理ワーカーの数を指定可能です。-num_worker=4 なら最大4つのワーカーを同時に処理できます。
その他オプションは bert-serving-start –help や公式にて確認しましょう。
#起動中のログいろいろ usage: /usr/local/bin/bert-serving-start -model_dir ./model/multi_cased_L-12_H-768_A-12/ ARG VALUE __________________________________________________ ckpt_name = bert_model.ckpt config_name = bert_config.json cors = * cpu = False device_map = [] do_lower_case = True fixed_embed_length = False fp16 = False gpu_memory_fraction = 0.5 graph_tmp_dir = None http_max_connect = 10 http_port = None mask_cls_sep = False max_batch_size = 256 max_seq_len = 25 model_dir = ./model/multi_cased_L-12_H-768_A-12/ no_special_token = False num_worker = 1 pooling_layer = [-2] pooling_strategy = REDUCE_MEAN port = 5555 port_out = 5556 prefetch_size = 10 priority_batch_size = 16 show_tokens_to_client = False tuned_model_dir = None verbose = False xla = False : #ログいろいろ : I1112 11:48:57.032177 140565767853824 __init__.py:164] all set, ready to serve request!
これでベクトル化の準備は完了です。
日本語テキストのベクトルの抽出
Pythonで記述するとこのような感じです。
from bert_serving.client import BertClient bc = BertClient() text_list = [ 'お世話になります。', 'はじめまして、' , '株式会社バートアズサービスの伊藤花子と申します。' ] bc.encode(text_list) # output 768次元にencodeされたベクトル # [[-1.9442471 0.5215177 0.5582967 ... 0.05251018 -0.5523748 -0.0039347 ] # [-0.2243494 0.6562447 0.0960088 ... 1.7321543 0.23941146 -0.0011313] # [-1.2245594 0.39260447 0.26600635 ... 1.6061543 0.23941146 -0.08075813]]
テキストをリスト形式で渡し、それぞれテキストへの768次元にencodeされたベクトルが得られました。
これらをもとにして、文書分類やテキスト類似度の検索、ランキング学習等の別タスクへの特徴量として利用しましょう。
処理速度の計測
ここでは参考値として社内検証環境で速度計測を行いました。
CPUとGPUそれぞれの環境で、10,000件のテキストを入力としてベクトル化処理を複数回まわしてその平均値を比較。
CPUではCPUコア数=4から 起動時のオプション -num_worker=4 としました。
spec | 処理時間 [sec] | 時間当たり処理 [text/sec] | |
CPU | Intel(R) Core(TM) i3-9100F CPU @ 3.60GH | 166.5179022 | 60.05360305 |
GPU | GeForce GTX 1070 | 12.46233234 | 802.4180165 |
CPU処理でもそれなりに速いので、実際の運用では「新規データの追加時などの適宜処理ではworker数の多いCPU」、「日毎などのバッチ処理で良いケースなら都度GPUインスタンス起動」と目的ごとにサーバー複数台で運用でしたほうがコスト的に良さそうな感じです。
まとめ
「bert-as-service」を構築し、自然言語処理の学習済みBERTモデルからテキストのベクトル化を簡単なステップで行えました。
一からの学習には多くの時間が必要なケースが多くモデルの肥大化も進むNLP分野において、公開されているPretrainedモデルや便利な運用環境など先人の肩に上手に乗りながらサービスへ導入検討をしていきたいですね。