はじめに
無敵級ビリーバー3周年👑👑👑 nikkieです。
「お休みの日にしかできないことを」と追求した結果、最近のお休みは開発合宿感があります。
今回は気になっていた技術、BERT-CRFを触りました。
目次
ずっと引っかかっていたBERT-CRF
BERT-CRFという技術は固有表現認識でなかなかよいと聞いていました1。
ただずっと「具体的にどう実装すればいいの?」というところがよく分かりませんでした。
2018年に登場した機械学習モデルBERT2。
Transformer3というアーキテクチャを使って組み上げられたこのモデルは、1つのモデルで複数の自然言語処理タスクが解けるということで注目を集めていきます4(一つの時代を築きましたね)。
自然言語処理のタスクの1つ、固有表現認識5。
これを深層学習モデルで解く場合、CRFを合わせるとよいことが分かっています。
BERT登場以前はLSTMが性能がよいモデルとして知られていましたが、LSTMもCRFと組み合わせると性能が上がります。
BERTの場合も同様で、BERT-CRFとして知られます。
性能がよい手法なら実装できるようになりたいと思い、参考実装を調べたこともあったのですが、私にとってはなかなか壁は高かった感じでした。
情報を求めに行くもピンポイントで見つからなかったり、見つけられても必要な知識が多く要求されて手を動かしきれなかったり...
『大規模言語モデル入門』6章「固有表現認識」
発売されたばかりの『大規模言語モデル入門』。
6章が固有表現認識。
買って詳細目次を見て驚いたのですが、BERTのファインチューニングで固有表現認識タスクを解いた後で(エラー分析をはさんで)BERT-CRFで精度改善までするんですよ!
「この6章を読めば知りたかったことが知られるかも!」とBERT-CRFを触るべく手を動かしました。
ソースコードは公開されています。
ローカルに開発環境を用意しなくてもGoogle Colabで動かせます。
BERT-CRFクイックツアーの感想
写経したノートブックはこちらです(訓練まで)。
一応テストセットに対する評価結果まで出せていて
{'precision': 0.8833580980683506, 'recall': 0.891972993248312, 'f1_score': 0.8876446435237028}
(5エポック訓練したものを評価しました。ベストかは見ていないです)
公開ノートブックに載っている性能です。
https://huggingface.co/llm-book/bert-base-japanese-v3-crf-ner-wikipedia-dataset
{'precision': 0.8944610778443114, 'recall': 0.8964741185296324, 'f1_score': 0.8954664668415137}
同じコードを繰り返し書きたくなかったので、6.2で作ったoutput_tokens_and_labels
をリファクタリングして再利用しました。
Colabではなくローカル環境にスクリプトとして写経してdoctestを書きながら進めました。
モデルに入力するTensorとそれをモデルの中で扱うところが(テストコードが書けず)自信がなかったのですが、訓練できているみたいだからヨシ!
1日で訓練〜評価のすべて理解するのは時間が足りなかった面もあり、評価については「コピペしたのでなんかよくわかんないけど動いた」が半分くらい残っています。
書籍への感想
- 固有表現認識の理論の説明が非常に丁寧
- 例:固有表現のタイプにはどんなものがあるか。数例(MUC、IREX、拡張固有表現階層)紹介
- 参考文献のリンクがめちゃめちゃ充実している
- これを1冊目で読みたかった感(教科書感がある)
- そのうえでBERT-CRF(かつてのSOTA)まで連れて行ってくれる
- 入門と言っているけど、題材はめちゃめちゃ本格的!
- Hugging Face Hubにデータセットやモデルが公開されている!
- https://huggingface.co/llm-book
- 扱いが揃う=覚えることが減る。非常にありがたい(入門しやすそう)
- データセットはhuggingface/datasetsで共通で取り回せる
- モデルやトークナイザはtransformersでfrom_pretrainedする
- 書籍の外に出ても同じ扱い方ができる(覚え直し不要!)
- 知らなかったライブラリをめっちゃ知られた
- spacy-alignments・pytorch-crf
- 現状メンテされていないように見えるライブラリもあるのは気になっている
- 関連:知っていたライブラリもサンプルコードを見て、使い方に学びがあった(クイックツアー感)
- モデルの選択〜性能評価は、書籍の流れでいいのかな?
- ストックマークさんのデータセットを使っていて、train / validation / testがある
- 5エポック訓練。5つのcheckpoint(モデル)をvalidationデータを使って選択。選んだモデルをtestデータに対して汎化性能の評価
- あれ、validationデータを使って訓練しているぞ?
- trainデータとvalidationデータ両方をtrainerに渡している
- 訓練でvalidationデータをevalに使ったうえで、checkpointのモデルのうちvalidationデータへの評価指標で選択するのは、汎化性能最大のモデルの選択と言える?言えない?
- evalのスコアで早期終了していないから大丈夫?
- 私は厳密にやるのを好むので、trainを2つに分割して、validationはtrainerには一切渡しません6
サンプルコードへの感想
- 型ヒント書いてある、めっちゃありがたい!👏
- 型ヒントには伸びしろありますね
- 思うに、人向けだけの型ヒント(型を表すコメントに近い)
- mypy(型チェッカ)は実行していないんじゃないかな。mypy流していたらエラーで落ちます
- 組み込み関数の
any
を型ヒントに使ってはいけません- 見つけちゃったんだ
dict[str, any]
- 関数であって型じゃないですから!!
- mypy曰く「error: Function "builtins.any" is not valid as a type [valid-type]」
- 👉typing.Anyを使いましょう
- https://docs.python.org/ja/3/library/typing.html#typing.Any
- 見つけちゃったんだ
dict[str, Any]
という型ヒントに直した上で- 『ロバストPython』を引くと、これは異種コレクションの辞書です7
- 👉
TypedDict
がおすすめ! - https://docs.python.org/ja/3/library/typing.html#typing.TypedDict
- データサイエンスのコードでよく見かける、複数の返り値の関数
- 書きたい気持ちめちゃ分かるんですが、複数返り値あると関数がまず大きいですし、再利用もしづらくなるんですよね
- 今回は手元で容赦なくリファクタリングしました(単一責務にしていく練習)
- 例えば
output_tokens_and_labels
という(tokens, labels)
を返す関数はtokensを返す関数とlabelsを返す関数にバラします- スコープ小さくなって私としてはスッキリ。doctestも書きやすい
終わりに
『大規模言語モデル入門』のおかげで、ずっと気になっていたBERT-CRFを訓練できました。
なるほど、こんな感じになるのか〜
- 理論面を詳しく、transformersなどのライブラリは最小限で押さえて、BERT-CRFまで実装できました
- 書籍内のPythonの型ヒントの書き方は伸び代あり。誤った型ヒントもあるので、型ヒントはどこか別で学ぶのをオススメします
- 型ヒントについて意味分からないけど写経するというのは、間違えて身に着けてしまうリスクが高いので、私はオススメしません
BERT-CRFについてはストックマークさんの本でも取り上げられていたのですが、
『大規模言語モデル入門』がタイミングやとっつきやすさがあって、今の自分にピタッとハマった感覚です。
BERT-CRFを学ぶための題材が実は他にも手元にあった(積読していた)と認識したので、活用して理解度を上げていくぞ!