BERTの学習済みモデルを利用して日本語文章の尤度を測る

# 概要
BERTの本家には文章の尤度を測るサンプルがなかった。
尤度を測れるまでの作業メモ

* 本家 [GitHub google-research/bert](https://github.com/google-research/bert)
* 言語モデル拡張 [GitHub xu-song/bert-as-language-model](https://github.com/xu-song/bert-as-language-model)
* 日本語モデル [BERT with SentencePiece を日本語 Wikipedia で学習してモデルを公開しました](https://yoheikikuta.github.io/bert-japanese/)
* 日本語モデルコード [GitHub yoheikikuta/bert-japanese](https://github.com/yoheikikuta/bert-japanese)

# 謝辞
google-researchチーム、xu-songさん、yoheikikutaさんに感謝いたします。

# フォークしたソース
[GitHub KTaskn/bert-as-language-model](https://github.com/KTaskn/bert-as-language-model)

# 手順
1. [言語モデル拡張](https://github.com/xu-song/bert-as-language-model)をgit cloneする
1. [日本語モデルコード](https://github.com/yoheikikuta/bert-japanese)からtokenization_sentencepiece.pyをダウンロードする
1. クローンしたディレクトリにmodelsディレクトリを作成する
1. [日本語モデル](https://yoheikikuta.github.io/bert-japanese/)から "内容" => "google drive"から日本語モデルをダウンロードしmodelsディレクトリに保存する
1. run_lm_predict.pyのコードを修正する
1. 日本語モデルのconfig.iniを参考にからbert_config.jsonを作成する


``` bash.
$ git clone https://github.com/xu-song/bert-as-language-model.git
$ mkdir models
$ wget --no-check-certificate https://raw.githubusercontent.com/yoheikikuta/bert-japanese/master/src/tokenization_sentencepiece.py
# modelsにモデルをダウンロード
# bert_configを作成する
$ export BERT_BASE_DIR=models
$ export INPUT_FILE=data/lm/test.ja.tsv
$ python run_lm_predict.py \
  --input_file=$INPUT_FILE \
  --vocab_file=$BERT_BASE_DIR/wiki-ja.vocab \
  --bert_config_file=$BERT_BASE_DIR/bert_config.json \
  --init_checkpoint=$BERT_BASE_DIR/model.ckpt-1400000 \
  --max_seq_length=128 \
  --output_dir=/tmp/lm_output/ \
  --jp_tokenizer=True
```

``` run_lm_predict.py
# 21行目〜
import os
import json
import modeling
import tokenization
# 追加
import tokenization_sentencepiece as tokenization_jp

import numpy as np
import tensorflow as tf

# ~~

# 93行目〜
flags.DEFINE_integer(
    "num_tpu_cores", 8,
    "Only used if `use_tpu` is True. Total number of TPU cores to use.")

# 追加
flags.DEFINE_bool("jp_tokenizer", False, "Use JP Tokenizer")

class InputExample(object):
  def __init__(self, unique_id, text):
    self.unique_id = unique_id
    self.text = text

# 310行目〜
# 変更
if FLAGS.jp_tokenizer:
  tokenizer = tokenization_jp.FullTokenizer(
      model_file="./models/jp_model/wiki-ja.model",
      vocab_file="./models/jp_model/wiki-ja.vocab",
      do_lower_case=True)
else:
  tokenizer = tokenization.FullTokenizer(
    vocab_file=FLAGS.vocab_file, do_lower_case=FLAGS.do_lower_case)

```

``` bert_config.json
{
    "attention_probs_dropout_prob" : 0.1,
    "hidden_act" : "gelu",
    "hidden_dropout_prob" : 0.1,
    "hidden_size" : 768,
    "initializer_range" : 0.02,
    "intermediate_size" : 3072,
    "max_position_embeddings" : 512,
    "num_attention_heads" : 12,
    "num_hidden_layers" : 12,
    "type_vocab_size" : 2,
    "vocab_size" : 32000
}
```

# 実行結果

``` data/lm/test.ja.tsv
私は本を読む
私は日本を読む
本の国土は広い
日本の国土は広い

```

``` /tmp/lm_output/test_results.json 
[
  {
    "tokens": [
      {
        "token": "▁", 
        "prob": 0.9849837422370911
      }, 
      {
        "token": "私は", 
        "prob": 0.01772877760231495
      }, 
      {
        "token": "本", 
        "prob": 0.38430821895599365
      }, 
      {
        "token": "を読む", 
        "prob": 0.14501915872097015
      }
    ], 
    "ppl": 5.6616988500880625
  }, 
  {
    "tokens": [
      {
        "token": "▁", 
        "prob": 0.9833461046218872
      }, 
      {
        "token": "私は", 
        "prob": 0.019558683037757874
      }, 
      {
        "token": "日本", 
        "prob": 0.00026242720196023583
      }, 
      {
        "token": "を読む", 
        "prob": 0.0007271786453202367
      }
    ], 
    "ppl": 128.47718205285057
  }, 
  {
    "tokens": [
      {
        "token": "▁", 
        "prob": 0.011469533666968346
      }, 
      {
        "token": "本の", 
        "prob": 2.954236833829782e-06
      }, 
      {
        "token": "国土", 
        "prob": 5.874089401913807e-05
      }, 
      {
        "token": "は", 
        "prob": 0.514896810054779
      }, 
      {
        "token": "広い", 
        "prob": 3.2568786991760135e-05
      }
    ], 
    "ppl": 1973.8280517535734
  }, 
  {
    "tokens": [
      {
        "token": "▁日本の", 
        "prob": 0.001967047341167927
      }, 
      {
        "token": "国土", 
        "prob": 0.07699552178382874
      }, 
      {
        "token": "は", 
        "prob": 0.11561550199985504
      }, 
      {
        "token": "広い", 
        "prob": 2.0818872144445777e-05
      }
    ], 
    "ppl": 228.85563777870746
  }
]
```

``` summary.
* 私は本を読む => 5.6616988500880625
* 私は日本を読む => 128.47718205285057
* 本の国土は広い => 1973.8280517535734
* 日本の国土は広い => 228.85563777870746
```

うまくいったかな？

以上