すぐに試せる日本語BERTのDocker Imageを作ってみた
はじめに
学習済みBERTを試しに触ってみたいんだけど、日本語使えるBERTの環境整えるの面倒!っていう人向けに、お試しでBERTを使える Docker Image 作ってみました。
BERT はTransformers(旧pytorch-transformers、旧pytorch-pretrained-bert) を使用。
黒橋・河原研究室のWEBサイトに掲載されている、日本語pretrainedモデルのWhole Word Masking版を使ってます。
Transformers — transformers 2.2.0 documentation
BERT日本語Pretrainedモデル - KUROHASHI-KAWAHARA LAB
Docker Image
ここに置いてあります。
https://hub.docker.com/r/ishizakiyuko/japanese_bert_trial
(多分、重いです...。全然「すぐに試せる」じゃないかも。)
ファイル一式をGitHubにもあげてます。
https://github.com/yuko-i/japanese_bert_trial_dockerfile
----- 追記 -----
Imageがかなり大きいです。
GitHubからDockerfile一式をcloneしてbuildするのをお勧めします!!
言い訳
1. JUMAN++のv2がcmakeでコケるので、v1にしてます_:(´ཀ`」 ∠):_
2. CMDが想定通りに動かないのでdocker runのオプションで対応で _:(´ཀ`」 ∠):_
tag 1.0.1から、CMDを使って動きます。runオプションつけなくても大丈夫です。
3. Docker弱者なので、中身が諸々変かもです _:(´ཀ`」 ∠):_
起動
1. pull する
docker pull ishizakiyuko/japanese_bert_trial:1.0.1
3. run する
docker run -p 8888:8888 -itd
tag 1.0.1 からは sh 指定なしでjupyter動きます
docker run -p 8888:8888 -d ishizakiyuko/japanese_bert_trial:1.0.1
4. log から token 調べる
docker logs <conteiner id>
5. ブラウザからjupyter にアクセスする(http://localhost:8888)
6. 4.で調べた token を入れてログイン
7. コードを書いて BERT を試してみる
コード例
おなじみのMask予測を動かしてみます。
日本語対応はこちらを参考にしました。
pytorch-transformersを触ってみる② - 機械学習・自然言語処理の勉強メモ
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 = 6 # Maskしたいtextのindex tokenized_text[masked_index] = '[MASK]' print(tokenized_text)
>> ['[CLS]', 'どんなに', '勉強', 'して', 'も', '全然', '[MASK]', 'が', '良く', 'なら', 'ない', '[SEP]']
# 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, 1, 6547, 19, 23, 1, 4, 11, 4161, 371, 46, 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)
>> ['成績', '頭', '気持ち', '方', '態度']
それらしいのが、出力されました。
Multi lingualも試してみる
Multi lingual が存在し、日本語も含まれる 104 の言語対応している学習済みモデルが使えます。
Multi-lingual models — transformers 2.2.0 documentation
黒橋・河原研究室版の方が良いはずですが、一応、どんなものか試してみたいと思います。
上記のコードのtokenizerとmodelの部分を変更。
tokenizer = BertTokenizer.from_pretrained("bert-base-multilingual-cased") model = BertForMaskedLM.from_pretrained('bert-base-multilingual-cased')
形態素解析の結果も違っているので、masked_indexを9にしました。
# 形態素解析 tokenized_text = tokenizer.tokenize(text) print(tokenized_text)
>> ['ど', '##んな', '##に', '勉', '強', 'しても', '全', '然', '頭', 'が', '良', 'く', '##な', '##らない']
masked_index = 9 tokenized_text[masked_index] = '[MASK]' print(tokenized_text)
>> ['[CLS]', 'ど', '##んな', '##に', '勉', '強', 'しても', '全', '然', '[MASK]', 'が', '良', 'く', '##な', '##らない', '[SEP]']
あとは同じで、
>> ['愛', '心', '気', '方', '日']
と出てきました。
やっぱり、黒橋・河原研究室版の方が良いですね!
文章埋め込み
BertModelから文章埋め込みベクトルを取得したいと思います。
config, juman++は上と同じ
from transformers import BertModel text = '今日は朝から犬の鳴き声がうるさい' result = jumanpp.analysis(text) tokenized_text =[mrph.midasi for mrph in result.mrph_list()] print(tokenized_text)
>> ['今日', 'は', '朝', 'から', '犬', 'の', '鳴き声', 'が', 'うるさい']
# token化 bert_tokenizer = BertTokenizer(os.path.join(BASE_PATH, VOCAVULARY_LIST), do_lower_case=False, do_basic_tokenize=False) bert_tokens = bert_tokenizer.tokenize(" ".join(tokenized_text)) ids = bert_tokenizer.convert_tokens_to_ids(["[CLS]"] + bert_tokens[:126] + ["[SEP]"]) tokens_tensor = torch.tensor(ids).reshape(1, -1) print(tokens_tensor)
>> tensor( [ [ 2, 2281, 9, 599, 27, 2099, 5, 21245, 11, 4274, 8823, 3 ] ] )
# embedding config = BertConfig.from_json_file(os.path.join(BASE_PATH, BERT_CONFIG)) model = BertModel.from_pretrained(os.path.join(BASE_PATH, BERT_MODEL), config=config) model.eval() with torch.no_grad(): all_encoder_layers, _ = model(tokens_tensor) embedding = all_encoder_layers.numpy()[0][-1] primt(embedding)
>> [ 6.78906918e-01 2.64199853e-01 4.61503953e-01 -3.25612813e-01 ..... -2.42455140e-01 -1.16255842e-02]
最終レイヤーを取る形にしました。
おわり
日本語BERTのImageって既にあるかも?と思いましたが、勉強なので何番煎じでも良いと思い書きました╭( ・ㅂ・)و ̑̑
Dockerfile、ここ直した方がいいよ!みたいなのがあったらコメントいただけたら嬉しいです!
Kaggle Days Tokyo のオフラインコンペがNLP疑惑もあり、Google QUEST Q&A Labeling コンペも面白いという噂ですし、 NLP 機運?
おわり2
こちらのブログ記事、上記の黒橋・河原研究室WEBサイトの「公開モデルを試していただいたサイト」欄に掲載してくださいました!!
ご関係者の方には感謝です!!٩(ˊᗜˋ*)و