• 日本語BERTfine-tuningをする
  • 手元でBERTの学習済みモデルをロードして文章をベクトル化して識別モデルを学習するところまではやってある
    • 72.1%だったのでこれをfine-tuningしてどこまで上がるか実験したい
  • これを読む
  • finetune-to-livedoor-corpus.ipynbを自分のGoogle Colab環境に複製
  • GCPにおいてからgcutil cpするように書かれているが、Google Driveをマウントすることにした
  • run_classifierのオプション:
    • --model_file=../model/wiki-ja.model \
    • --vocab_file=../model/wiki-ja.vocab \
    • これらはSentencePieceのモデルを指定してる
      • ipynbの手順通りだとあらかじめGCPからColabのFSにコピーされている
      • 僕はやってないので、Google Driveから読むことにする
      • こうなった
        • --model_file=/content/gdrive/My\ Drive/bert-wiki-ja/wiki-ja.model \
        • --vocab_file=/content/gdrive/My\ Drive/bert-wiki-ja/wiki-ja.vocab \
        • --init_checkpoint=/content/gdrive/My\ Drive/bert-wiki-ja/model.ckpt-1400000 \
      • Google ColabのFSのルートは/contentなの
        • 相対パス起因の失敗をするのは嫌なので絶対パスにした
      • 注: BERTモデルの読み込みと結果の書き出し先はGCPでなければならない
  • データの読み込みを行なっている場所
    • train_examples = processor.get_train_examples(FLAGS.data_dir)
      • processorはprocessor = processors[task_name]()しててコマンドライン引数で渡した--task_name=livedoorによってLivedoorProcessorが選択されている
      • LivedoorProcessorDataProcessorを継承して親クラスのクラスメソッド_read_tsvを呼んでいるが、これは単にファイルを開いてTSVとして読んで各行をリストに入れて返すだけ
      • その結果を元に LivedoorProcessor#_create_examplesの中でInputExampleオブジェクトを作ってリストに入れている
      • InputExampleは文章とラベルを持つ
  • モデルの作成
    • model_fn_builder(...)model_fnを作ってから、それをtf.contrib.tpu.TPUEstimatorで包んでestimatorと呼ぶ
      • 学習済みモデルはどこで読むか
      • model_fn_builder(...)create_modelを呼ぶ
      • これはオリジナルのBERTモデルを作ってからoutput_layer = model.get_pooled_output()する
      • get_pooled_outputを入力とするシンプルなロジスティック回帰を実装しているように見えるが、なんで自前で実装する必要があったのかよくわからない
      • 将来的にはいろいろカスタマイズしたいが、今回は「そういうものだ」と認めて進むことにするか
      • 今回の僕のケースではラベルが0/1なのがちょっと違う点
  • 実装
    • run_clussifier.pyをインポートしてLivedoorProcessor相当のものを自作して、mainを書き換えてそれを呼ぶようにしよう
    • title(unique id)から本文への対応づけがhonbun_data.jsonに入っているのでこれを使う
    • LivedoorProcessorはそれぞれのメソッド呼び出しに応じて異なるファイルを読んでいるが、僕のケースでは1つ
      • クラスの外でデータを作っておいてメソッドは参照を返すだけにする
    • ネガポジのペアはnegaposi.jsonに入ってるのでこれを使う
    • 将来的にはいろいろカスタマイズしたいが、今回は「そういうものだ」と認めて進むことにするか

      • これできないのではって気がしてきた
      • できなくはないが、2個の値のペアを受け取ってネガポジ判定するのをLRで実装するのは…
      • 組み合わせ素性がないので流石にダメでは…
      • まあ素朴な手段としてやっておくか
    • そもそも入力が2文であって、それぞれにpooled_outputが必要か?
      • BERTのtext_aとtext_bに入れれば良いか
    • オリジナルの_create_examplesではtokenization.convert_to_unicodeしてるけど、僕の場合0/1だからintで入れて大丈夫かな
  • 少し走って死んだ
    • TPUからGoogle ColabのローカルFSには書き込めない
    • “service-***@cloud-tpu.iam.gserviceaccount.com does not have storage.objects.list access to ***.appspot.com.”
      • ipynbの「TPUのチェック」と書かれたセルが、TPUに対してGCP Bucketのアクセス権を付与することまでやっている
      • うまくいかない場合はここが失敗しているので最初からやり直せば良い :
***** Eval results *****
eval_accuracy = 0.9525939
eval_loss = 0.40050572
global_step = 1047
loss = 0.39979258
CPU times: user 2.1 s, sys: 313 ms, total: 2.41 s
Wall time: 7min 54s

classification_report

             precision    recall  f1-score   support

           0       0.94      0.96      0.95      1118
           1       0.95      0.94      0.95      1117

    accuracy                           0.95      2235
   macro avg       0.95      0.95      0.95      2235
weighted avg       0.95      0.95      0.95      2235

confusion_matrix

[[1068   50]
 [  68 1049]]
  • ほんとなのかと眉に唾をつけたくなる

まとめ

  • 6705件のデータを使ったBERTのfine-tuningがTPUを使うと7分程度でできる
  • 72%→95%の精度
    • image
    • ただしBの処理結果をキャッシュできないという問題点がある
      • 計測してないけど処理にかかる時間が1〜2桁上がる懸念
      • 右の形を試したい
        • これは加算注意
      • 内積注意や次元削減注意を試したい