ERRANT is 何?
ERRor ANnotation Toolkit: ERRANTは文法誤り訂正 (Grammatical Error Correction: GEC) システムの出力文に対して、自動で編集箇所とエラータイプを付与し、評価スコアを計算することができるツールです。
2019年にGECの国際コンペであるBEA-2019 Shared Taskが開催されました。このコンペでは共通のデータセット・評価方法のもとで、参加チームが作成したGECシステムのスコアを競い合いました。このコンペの評価方法として用いられたのがERRANTです。
ERRANTのエラータイプの推定はルールベースで行なっており、Good, Acceptable, Badの3段階で人手評価を行ったところ、95%以上がGood, Acceptableであったと報告されています (Bryant et al. 2017)。
文法誤り訂正の評価方法
GECでは、編集箇所単位での適合率(Precision)、再現率(Recall)、および$F_{0.5}$が一般的な評価メトリクスとなっています。$F_{0.5}$は再現率を重視したF値のことです。
これらの値を計算するためには、GECシステムの訂正と、真の結果を以下のように分類した結果のカウントが必要になります。
真の結果が正 | 真の結果が負 | |
---|---|---|
GECシステムが訂正を行った | TP | FP |
GECシステムが訂正を行わなかった | FN | TN |
- TP: GECシステムが訂正を行い、それが真に正しい訂正だった場合の数
- FP: GECシステムが訂正を行い、それが真に正しい訂正ではなかった場合の数
- FN: 訂正すべき箇所に対して、GECシステムが訂正を行わなかった場合の数
- TN: 訂正が不要な箇所に対して、GECシステムが訂正を行わなかった場合の数
これらを使って以下の式で適合率、再現率、$F_{0.5}$を計算します。
\text{Precision} = \frac{\text{TP}}{\text{TP} + \text{FP}} \\
\text{Recall} = \frac{\text{TP}}{\text{TP} + \text{FN}} \\
F_{0.5} = (1+0.5^2) \cdot \frac{\text{Precision} \cdot \text{Recall}}{(0.5^2 \cdot \text{Precision}) + \text{Recall}}
サンプルデータ
今回はERRANTを試す用に、以下のような訂正を行うことを想定します。
※ [COLING2020のGECチュートリアルのスライド](https://github.com/grammatical/coling2020-tutorial/blob/master/slides/GEC_tutorial_2020.pdf)の5ページ目を拝借しました原文ファイル(orig.txt)、正解文ファイル(cor.txt)を用意します。
I think, that everybody deserve privacy, including famous people.
They can barelly breathing with all those photographers around them.
I don't know why people love spying famous people.
And magazines are full of those things.
I think that everybody deserves privacy, including famous people.
They can barely breath with all those photographers around them.
I don't know why people love spying on famous people.
And magazines are full of those things.
また、GECシステムの出力文ファイル(hyp.txt)も用意します。今回はGECシステムはないので一部を手動で編集しました。
I think that everybody deserve privacy, including famous people.
They can barely breathing with all those photographers around them.
I don't know why people love spying on famous people.
And the magazines are full of those things.
- 手動で編集した箇所
- 1文目の不要な「,」を削除 (TP)
- 2文目の「barelly」を「barely」に修正 (TP)
- 3文目の「spaying」を「spaying on」に修正 (TP)
- 4文目に不要な「the」を挿入 (FP)
- その他の間違いは修正しない (FN × 2)
ERRANTの使い方
まずERRANTをインストールします。
$ pip3 install -U pip setuptools wheel
$ pip3 install errant
$ python3 -m spacy download en
インストールすると、次の3つのコマンドを使用できるようになります。
- errant_parallel
- errant_m2
- errant_compare
以下の手順でコマンドを実行します
- ① errant_parallel コマンドで原文から正解文への編集箇所とエラータイプをM2フォーマットで出力する
- ② errant_parallel コマンドで原文から出力文への編集箇所とエラータイプをM2フォーマットで出力する
- ③ errant_compare コマンドで評価スコアを計算する
なお、errant_m2 コマンドは今回は使用しません。ERRANT以外の方法でM2ファイルが作成されている場合、それをERRANTの形式に統一するときにこのコマンドを使用します。
① errant_parallel コマンドで原文から正解文への編集箇所とエラータイプをM2フォーマットで出力する
最初に、次のコマンドを実行します。
$ errant_parallel -orig orig.txt -cor cor.txt -tok -out ref.m2
-
-org
には原文ファイルを指定します -
-cor
には正解文ファイルを指定します -
-out
には出力するファイルパスを指定します -
-tok
を指定するとspaCyを使って文をトークナイズしてくれます- 「think,」が「think ,」に分割されます
出力されるファイル(ref.m2)の中身は次のようになります。
S I think , that everybody deserve privacy , including famous people .
A 2 3|||U:PUNCT||||||REQUIRED|||-NONE-|||0
A 5 6|||R:VERB:SVA|||deserves|||REQUIRED|||-NONE-|||0
S They can barelly breathing with all those photographers around them .
A 2 3|||R:SPELL|||barely|||REQUIRED|||-NONE-|||0
A 3 4|||R:VERB|||breath|||REQUIRED|||-NONE-|||0
S I do n't know why people love spying famous people .
A 8 8|||M:PREP|||on|||REQUIRED|||-NONE-|||0
S And magazines are full of those things .
A -1 -1|||noop|||-NONE-|||REQUIRED|||-NONE-|||0
これは原文から正解文までにどのような編集を行ったかをM2フォーマットという形式で表しています。M2フォーマットのファイルをM2ファイルと呼びます。このコマンドではこのように2文間の編集アノテーションを自動で推定し、M2フォーマットで出力します。
M2フォーマット
M2フォーマットはCoNLL-2013 Shared Task以降、GECにおいて一般的なアノテーショファイルのフォーマットになっています。
S This are a sentence .
A 1 2|||R:VERB:SVA|||is|||-REQUIRED-|||NONE|||0
A 3 3|||M:ADJ|||good|||-REQUIRED-|||NONE|||0
A 1 2|||R:VERB:SVA|||is|||-REQUIRED-|||NONE|||1
A -1 -1|||noop|||-NONE-|||REQUIRED|||-NONE-|||2
- Sで始まる行は元の文を表す
- Aで始まる行は編集のアノテーションを表す
- アノテーション行は以下のようなフォマットに従う
A <開始トークン位置> <終了トークン位置>|||<エラータイプ>|||<正解トークン>|||<意味はないが形式上必要>|||<意味はないが形式上必要>|||<アノテーターID>
-
noop
は変更がないことを表す特別なラベル - もし何も編集がない場合、以下のようなnoopの1行だけ出力される
-
A -1 -1|||noop|||-NONE-|||REQUIRED|||-NONE-|||0
-
エラータイプ
例えば「M:ADJ」は「形容詞の不足」を表します。「operation:code」のように表されます。
operationにはM、R、Uの3種類があります。
- M: Missing (不足)
- R: Replacement (置換)
- U: Unnecessary (不要)
エラータイプのcodeは、論文に主な25種類が紹介されています (Bryant et al. 2017) 。
ERRANTはエラータイプをルールベースで分類しているので、以下の特徴があります。
- 特定のデータセットに依存しない
- 訓練データやアノテーションラベルデータなどが不要
- 機械学習と違い、分類のロジックが明確
② errant_parallel コマンドで原文から出力文への編集箇所とエラータイプをM2フォーマットで出力する
次に、errant_parallelコマンドの-cor
を出力文ファイルに入れ替えて実行します。
$ errant_parallel -orig orig.txt -cor hyp.txt -tok -out hyp.m2
出力されるM2ファイル(hyp.m2)の中身は次のようになります。
S I think , that everybody deserve privacy , including famous people .
A 2 3|||U:PUNCT||||||REQUIRED|||-NONE-|||0
S They can barelly breathing with all those photographers around them .
A 2 3|||R:SPELL|||barely|||REQUIRED|||-NONE-|||0
S I do n't know why people love spying famous people .
A 8 8|||M:PREP|||on|||REQUIRED|||-NONE-|||0
S And magazines are full of those things .
A 1 1|||M:DET|||the|||REQUIRED|||-NONE-|||0
これは原文から出力文までにどのような編集を行ったのかを表しています。
③ errant_compare コマンドで評価スコアを計算する
最後に、次のコマンドを実行することで、評価スコアが表示されます。
$ errant_compare -hyp hyp.m2 -ref ref.m2
=========== Span-Based Correction ============
TP FP FN Prec Rec F0.5
3 1 2 0.75 0.6 0.7143
==============================================
-
-hyp
には、2で作成した原文-出力文のM2ファイルを指定します -
-ref
には、1で作成した原文-正解文のM2ファイルを指定します
ERRANTは2つのM2ファイルからTP、FP、FNをカウントし、適合率、再現率、$F_{0.5}$を計算します。
-v
オプションを加えることで詳細を確認できます。
$ errant_compare -hyp hyp.m2 -ref ref.m2 -v
----------------------------------------
SENTENCE 0 - HYP 0 - REF 0
HYPOTHESIS EDITS : [(2, 3, '')]
REFERENCE EDITS : [(2, 3, ''), (5, 6, 'deserves')]
Local TP/FP/FN : 1 0 1
Local P/R/F0.5 : 1.0 0.5 0.8333
Global TP/FP/FN : 1 0 1
Global P/R/F0.5 : 1.0 0.5 0.8333
----------------------------------------
^^ HYP 0, REF 0 chosen for sentence 0
----------------------------------------
SENTENCE 1 - HYP 0 - REF 0
HYPOTHESIS EDITS : [(2, 3, 'barely')]
REFERENCE EDITS : [(2, 3, 'barely'), (3, 4, 'breath')]
Local TP/FP/FN : 1 0 1
Local P/R/F0.5 : 1.0 0.5 0.8333
Global TP/FP/FN : 2 0 2
Global P/R/F0.5 : 1.0 0.5 0.8333
----------------------------------------
^^ HYP 0, REF 0 chosen for sentence 1
----------------------------------------
SENTENCE 2 - HYP 0 - REF 0
HYPOTHESIS EDITS : [(8, 8, 'on')]
REFERENCE EDITS : [(8, 8, 'on')]
Local TP/FP/FN : 1 0 0
Local P/R/F0.5 : 1.0 1.0 1.0
Global TP/FP/FN : 3 0 2
Global P/R/F0.5 : 1.0 0.6 0.8824
----------------------------------------
^^ HYP 0, REF 0 chosen for sentence 2
----------------------------------------
SENTENCE 3 - HYP 0 - REF 0
HYPOTHESIS EDITS : [(1, 1, 'the')]
REFERENCE EDITS : []
Local TP/FP/FN : 0 1 0
Local P/R/F0.5 : 0.0 1.0 0.0
Global TP/FP/FN : 3 1 2
Global P/R/F0.5 : 0.75 0.6 0.7143
----------------------------------------
^^ HYP 0, REF 0 chosen for sentence 3
=========== Span-Based Correction ============
TP FP FN Prec Rec F0.5
3 1 2 0.75 0.6 0.7143
==============================================
-cat 1
オプションを加えることでoperation別にスコアを確認できます。
$ errant_compare -hyp hyp.m2 -ref ref.m2 -cat 1
===================== Span-Based Correction ======================
Category TP FP FN P R F0.5
M 1 1 0 0.5 1.0 0.5556
R 1 0 2 1.0 0.3333 0.7143
U 1 0 0 1.0 1.0 1.0
=========== Span-Based Correction ============
TP FP FN Prec Rec F0.5
3 1 2 0.75 0.6 0.7143
==============================================
-cat 2
オプションを加えることでエラータイプのcode別にスコアを確認できます。
$ errant_compare -hyp hyp.m2 -ref ref.m2 -cat 2
===================== Span-Based Correction ======================
Category TP FP FN P R F0.5
DET 0 1 0 0.0 1.0 0.0
PREP 1 0 0 1.0 1.0 1.0
PUNCT 1 0 0 1.0 1.0 1.0
SPELL 1 0 0 1.0 1.0 1.0
VERB 0 0 1 1.0 0.0 0.0
VERB:SVA 0 0 1 1.0 0.0 0.0
=========== Span-Based Correction ============
TP FP FN Prec Rec F0.5
3 1 2 0.75 0.6 0.7143
==============================================
-cat 3
オプションを加えることでoperation:code別にスコアを確認できます。
$ errant_compare -hyp hyp.m2 -ref ref.m2 -cat 3
===================== Span-Based Correction ======================
Category TP FP FN P R F0.5
M:DET 0 1 0 0.0 1.0 0.0
M:PREP 1 0 0 1.0 1.0 1.0
R:SPELL 1 0 0 1.0 1.0 1.0
R:VERB 0 0 1 1.0 0.0 0.0
R:VERB:SVA 0 0 1 1.0 0.0 0.0
U:PUNCT 1 0 0 1.0 1.0 1.0
=========== Span-Based Correction ============
TP FP FN Prec Rec F0.5
3 1 2 0.75 0.6 0.7143
==============================================
その他のオプションもあるので、helpをご覧ください。
$ errant_compare -h
日本語で使ったらどうなる?
ERRANTは英語向けのツールですが、日本語文を入力したらどうなるのか試します。次のようなサンプルデータを使用します。
※ [こちらの論文](https://www.anlp.jp/proceedings/annual_meeting/2020/pdf_dir/F2-3.pdf)から拝借しましただから、たばこの吸う人がたくさんいる。
人間の健康ようにたばこを吸わなくてください。
個人の権利はもし他人の権利を悪く影響したら、禁止られるべきです。
でも、人はその一人ばかりこの地球ですむのはない、
だから、たばこを吸う人がたくさんいる。
人間の健康のためにたばこを吸わないでください。
個人の権利はもし他人の権利に悪く影響したら、禁止されるべきです。
でも、人は一人だけでこの地球にすんでいるのではありません。
だから、たばこを吸う人がたくさんいる。
人間の健康のためにたばこを吸わないでください。
個人の権利はもし他人の権利に悪く影響したら、禁止されるべきです。
でも、人はその一人だけこの地球に住むことはない、
英語の場合はerrant_parallelのオプション-tok
でトークナイズできましたが、日本語には対応していないため事前に分かち書きしておきます。今回はmecab unidicで分かち書きします。
$ mecab -d path/to/unidic -Owakati orig.txt > orig.tok.txt
$ mecab -d path/to/unidic -Owakati cor.txt > cor.tok.txt
$ mecab -d path/to/unidic -Owakati hyp.txt > hyp.tok.txt
だ から 、 たばこ の 吸う 人 が たくさん いる 。
人間 の 健康 よう に たばこ を 吸わ なく て ください 。
個人 の 権利 は もし 他人 の 権利 を 悪く 影響 し たら 、 禁止 られる べき です 。
で も 、 人 は その 一人 ばかり この 地球 で すむ の は ない 、
だ から 、 たばこ を 吸う 人 が たくさん いる 。
人間 の 健康 の ため に たばこ を 吸わ ない で ください 。
個人 の 権利 は もし 他人 の 権利 に 悪く 影響 し たら 、 禁止 さ れる べき です 。
で も 、 人 は 一人 だけ で この 地球 に すん で いる の で は あり ませ ん 。
だ から 、 たばこ を 吸う 人 が たくさん いる 。
人間 の 健康 の ため に たばこ を 吸わ ない で ください 。
個人 の 権利 は もし 他人 の 権利 に 悪く 影響 し たら 、 禁止 さ れる べき です 。
で も 、 人 は その 一人 だけ この 地球 に 住む こと は ない 、
① errant_parallel コマンドで原文から正解文への編集箇所とエラータイプをM2フォーマットで出力する
$ errant_parallel -orig orig.tok.txt -cor cor.tok.txt -out ref.m2
S だ から 、 たばこ の 吸う 人 が たくさん いる 。
A 4 5|||R:NOUN|||を|||REQUIRED|||-NONE-|||0
S 人間 の 健康 よう に たばこ を 吸わ なく て ください 。
A 3 3|||M:NOUN|||の|||REQUIRED|||-NONE-|||0
A 3 4|||R:PREP|||ため|||REQUIRED|||-NONE-|||0
A 8 9|||R:SPELL|||ない|||REQUIRED|||-NONE-|||0
A 9 10|||R:DET|||で|||REQUIRED|||-NONE-|||0
S 個人 の 権利 は もし 他人 の 権利 を 悪く 影響 し たら 、 禁止 られる べき です 。
A 8 9|||R:NOUN|||に|||REQUIRED|||-NONE-|||0
A 15 15|||M:NOUN|||さ|||REQUIRED|||-NONE-|||0
A 15 16|||R:SPELL|||れる|||REQUIRED|||-NONE-|||0
S で も 、 人 は その 一人 ばかり この 地球 で すむ の は ない 、
A 5 6|||U:NOUN||||||REQUIRED|||-NONE-|||0
A 7 7|||M:ADV|||だけ|||REQUIRED|||-NONE-|||0
A 7 8|||R:NOUN|||で|||REQUIRED|||-NONE-|||0
A 10 10|||M:NOUN|||に すん|||REQUIRED|||-NONE-|||0
A 11 12|||R:NOUN|||いる|||REQUIRED|||-NONE-|||0
A 13 13|||M:NOUN|||で|||REQUIRED|||-NONE-|||0
A 14 16|||R:NOUN|||あり ませ ん|||REQUIRED|||-NONE-|||0
A 16 16|||M:PUNCT|||。|||REQUIRED|||-NONE-|||0
② errant_parallel コマンドで原文から出力文への編集箇所とエラータイプをM2フォーマットで出力する
$ errant_parallel -orig orig.tok.txt -cor hyp.tok.txt -out hyp.m2
S だ から 、 たばこ の 吸う 人 が たくさん いる 。
A 4 5|||R:NOUN|||を|||REQUIRED|||-NONE-|||0
S 人間 の 健康 よう に たばこ を 吸わ なく て ください 。
A 3 3|||M:NOUN|||の|||REQUIRED|||-NONE-|||0
A 3 4|||R:PREP|||ため|||REQUIRED|||-NONE-|||0
A 8 9|||R:SPELL|||ない|||REQUIRED|||-NONE-|||0
A 9 10|||R:DET|||で|||REQUIRED|||-NONE-|||0
S 個人 の 権利 は もし 他人 の 権利 を 悪く 影響 し たら 、 禁止 られる べき です 。
A 8 9|||R:NOUN|||に|||REQUIRED|||-NONE-|||0
A 15 15|||M:NOUN|||さ|||REQUIRED|||-NONE-|||0
A 15 16|||R:SPELL|||れる|||REQUIRED|||-NONE-|||0
S で も 、 人 は その 一人 ばかり この 地球 で すむ の は ない 、
A 7 8|||R:NOUN|||だけ|||REQUIRED|||-NONE-|||0
A 10 11|||R:NOUN|||に|||REQUIRED|||-NONE-|||0
A 11 12|||R:SPELL|||住む|||REQUIRED|||-NONE-|||0
A 12 13|||R:DET|||こと|||REQUIRED|||-NONE-|||0
③ errant_compare コマンドで評価スコアを計算する
$ errant_compare -hyp hyp.m2 -ref ref.m2 -v
----------------------------------------
SENTENCE 0 - HYP 0 - REF 0
HYPOTHESIS EDITS : [(4, 5, 'を')]
REFERENCE EDITS : [(4, 5, 'を')]
Local TP/FP/FN : 1 0 0
Local P/R/F0.5 : 1.0 1.0 1.0
Global TP/FP/FN : 1 0 0
Global P/R/F0.5 : 1.0 1.0 1.0
----------------------------------------
^^ HYP 0, REF 0 chosen for sentence 0
----------------------------------------
SENTENCE 1 - HYP 0 - REF 0
HYPOTHESIS EDITS : [(3, 3, 'の'), (3, 4, 'ため'), (8, 9, 'ない'), (9, 10, 'で')]
REFERENCE EDITS : [(3, 3, 'の'), (3, 4, 'ため'), (8, 9, 'ない'), (9, 10, 'で')]
Local TP/FP/FN : 4 0 0
Local P/R/F0.5 : 1.0 1.0 1.0
Global TP/FP/FN : 5 0 0
Global P/R/F0.5 : 1.0 1.0 1.0
----------------------------------------
^^ HYP 0, REF 0 chosen for sentence 1
----------------------------------------
SENTENCE 2 - HYP 0 - REF 0
HYPOTHESIS EDITS : [(8, 9, 'に'), (15, 15, 'さ'), (15, 16, 'れる')]
REFERENCE EDITS : [(8, 9, 'に'), (15, 15, 'さ'), (15, 16, 'れる')]
Local TP/FP/FN : 3 0 0
Local P/R/F0.5 : 1.0 1.0 1.0
Global TP/FP/FN : 8 0 0
Global P/R/F0.5 : 1.0 1.0 1.0
----------------------------------------
^^ HYP 0, REF 0 chosen for sentence 2
----------------------------------------
SENTENCE 3 - HYP 0 - REF 0
HYPOTHESIS EDITS : [(7, 8, 'だけ'), (10, 11, 'に'), (11, 12, '住む'), (12, 13, 'こと')]
REFERENCE EDITS : [(5, 6, ''), (7, 7, 'だけ'), (7, 8, 'で'), (10, 10, 'に すん'), (11, 12, 'いる'), (13, 13, 'で'), (14, 16, 'あり ませ ん'), (16, 16, '。')]
Local TP/FP/FN : 0 4 8
Local P/R/F0.5 : 0.0 0.0 0.0
Global TP/FP/FN : 8 4 8
Global P/R/F0.5 : 0.6667 0.5 0.625
----------------------------------------
^^ HYP 0, REF 0 chosen for sentence 3
=========== Span-Based Correction ============
TP FP FN Prec Rec F0.5
8 4 8 0.6667 0.5 0.625
==============================================
1~3文目は正しい訂正を行なっているため適合率、再現率ともに100%です。ですが4文目でFP、FNが多くカウントされているため、全体的なスコアが低くなっています。文節単位の訂正の場合、対象のトークン数が多くなるためスコアに与える影響が大きいということかと思います。
英語と違い、日本語ではエラータイプのルールベースが適用されないため、付与されるエラータイプは間違ったものになります。一方で編集箇所の検出やoperationの判別は日本語でも機能します。日本語でもエラータイプ別に精度を確認できるようになると嬉しいですね。
まとめ
長くなりましたが、文法誤り訂正の評価ツール ERRANT の使い方を紹介しました。テキストファイルがあれば、コマンドだけでM2ファイルに変換してくれて、評価スコアが計算でき、さらにエラータイプ別の精度まで確認できるのはとても便利だと思います!
ERRANTの詳細は公式GitHubをご覧ください。
https://github.com/chrisjbryant/errant