概要
BERT日本語Pretrainedモデル(京大 黒橋・河原研)を利用して、日本語文章に含まれるトークン(単語)の尤度を出力します。
「BERTの学習済みモデルを利用して日本語文章の尤度を測る」を参考に、こちらの記事ではSentencePieceによるモデルを利用されていたところを、上記の京大のモデル(Juman++)に対応させた形です。
コード
- https://github.com/ohchun/bert-as-language-model
- fork: https://github.com/xu-song/bert-as-language-model
環境
- Ubuntu 16.04.4 LTS
- Python 3.6.0
- tensorflow==1.14.0
- pyknp==0.4.1
- Juman++ Version: 2.0.0-rc2
参考サイト
利用手順
- Juman++のインストール
- Pythonモジュールのインストール
- 上記コードを clone
- modelsディレクトリを作成
- BERT日本語Pretrainedモデルのダウンロード
- 解凍後、モデルファイル群が入ったディレクトリを models に配置
- 以下のコマンドを実行
export BERT_BASE_DIR=models/Japanese_L-12_H-768_A-12_E-30_BPE
python run_lm_predict.py \
--input_file=./data/lm/test.ja.tsv \
--vocab_file=$BERT_BASE_DIR/vocab.txt \
--bert_config_file=$BERT_BASE_DIR/bert_config.json \
--init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \
--do_lower_case False \
--max_seq_length=128 \
--output_dir=./data/lm/output/ \
--jp_tokenizer=True
実行結果
入力内容
誤変換を含む文章を用意し、尤度が低くなるか確認してみます。
cat ./data/lm/test.ja.tsv
機械学習で処理する
機会学習で処理する
世間では人工知能が流行している
世間では人口知能が流行している
結果
誤変換に該当する単語およびその周辺単語の尤度が低くなりました。
なお、先頭と最後の単語も尤度が低くなりがちです。
この理由は、先頭と最後には様々な単語が現れる可能性があり、bi-directional とはいえ確率がばらけてしまうためと考えています。
# prob: probability
# ppl: perplexity
[
{
"tokens": [
{
"token": "機械",
"prob": 0.7197790145874023
},
{
"token": "学習",
"prob": 0.0011436253553256392
},
{
"token": "で",
"prob": 0.4158846437931061
},
{
"token": "処理",
"prob": 0.00014628272037953138
},
{
"token": "する",
"prob": 0.00011202425957890227
}
],
"ppl": 177.91305425305157
},
{
"tokens": [
{
"token": "機会",
"prob": 4.273203558113892e-06 # low probability
},
{
"token": "学習",
"prob": 0.00048818811774253845
},
{
"token": "で",
"prob": 0.14289069175720215
},
{
"token": "処理",
"prob": 0.0002504551666788757
},
{
"token": "する",
"prob": 8.453470945823938e-05
}
],
"ppl": 2754.0894828429246
},
{
"tokens": [
{
"token": "世間",
"prob": 0.00029105637804605067
},
{
"token": "で",
"prob": 0.8351001739501953
},
{
"token": "は",
"prob": 0.9587864875793457
},
{
"token": "人工",
"prob": 0.986724317073822
},
{
"token": "知能",
"prob": 0.5667852759361267
},
{
"token": "が",
"prob": 0.9329909086227417
},
{
"token": "流行",
"prob": 0.1348113864660263
},
{
"token": "して",
"prob": 0.9265641570091248
},
{
"token": "いる",
"prob": 1.2146945664426312e-05
}
],
"ppl": 12.065788660694167
},
{
"tokens": [
{
"token": "世間",
"prob": 0.00021123532496858388
},
{
"token": "で",
"prob": 0.8677905201911926
},
{
"token": "は",
"prob": 0.949567437171936
},
{
"token": "人口",
"prob": 1.7458520233049057e-05 # low probability
},
{
"token": "知能",
"prob": 3.086066135438159e-05 # low probability
},
{
"token": "が",
"prob": 0.914918839931488
},
{
"token": "流行",
"prob": 0.051112908869981766
},
{
"token": "して",
"prob": 0.927436888217926
},
{
"token": "いる",
"prob": 1.0879161891352851e-05
}
],
"ppl": 141.40153489831755
}
]
コードの修正内容
ほぼ、参考サイト様の通りです。
- Juman++ でトークン化できるように、tokenization.py に JumanPPTokenizer クラスを追加
- BERTの日本語事前学習済みモデルでテキスト埋め込みをやってみる を参考にしました。
- 日本語トークナイズ処理のオン/オフを切り替えられるように、run_lm_predict.py に jp_tokenizer オプションを追加
- BERTの学習済みモデルを利用して日本語文章の尤度を測る を参考にしました。
- 日本語トークナイズを行わない場合(=オリジナルのトークナイズを行う場合)は、別途、BERTモデルを用意しておきます。
- 出力ファイル名が固定だったため、入力ファイル名_result.json となるように変更しました。
所感
- 思いのほか簡単に導入でき、結果が期待通りで良かったです。
- 結果が分かりやすいので、色々と活用できそうです。
- 各トークン位置の候補語も出せそうな気がするので、覗いていきたいところです。