実践手話認識 - モデル開発編 補足: Word error rate について

This image is generated with ChatGPT-4 Omni, and edited by the author.
作成日:2024年09月12日(木) 00:00
最終更新日:2024年09月18日(水) 09:47
カテゴリ:手話言語処理
タグ:  実践手話認識 深層学習 時系列認識

時系列認識の評価によく用いられる,単語誤り率 (Word error rate) について簡単に説明します.

こんにちは.高山です.
今回の記事は,Encoder-Decoder を用いた時系列認識の処理 (以降では Encoder-Decoder 解説記事と記載します) の補足になります.

Encoder-Decoder 解説記事で,時系列認識の評価には単語誤り率 (WER: Word error rate) がよく使われると説明しました.
WER の説明を Encoder-Decoder 解説記事の中ですると少し浮いた内容になると思ったので,こちらで解説したいと思います.

更新履歴 (大きな変更のみ記載しています)

  • 2024/09/18: カテゴリを変更しました
  • 2024/09/17
    • タイトルとタグを更新しました
    • 系列認識 (Sequential recognition) は別の手法を連想させる可能性があるので,時系列認識 (temporal recognition) という用語を用いるようにしました

1. Word error rate とは?

WER は音声認識でよく使われる性能評価指標で,連続手話単語認識の評価でも用いられます.

WER の計算は次の式で行います.

\begin{eqnarray} WER & = & \frac{S + D + I}{N} \label{eqn:form1} \\ & = & \frac{S + D + I}{S + D + C} \label{eqn:form2} \end{eqnarray}

各変数の指す内容は下記のとおりです.

  • \(S\): ラベルの置き換え回数
  • \(D\): ラベルの削除回数
  • \(I\): ラベルの挿入回数
  • \(C\): 正解ラベル数
  • \(N\): 参照ラベルの長さ

式(\ref{eqn:form1})の分子はレーベンシュタイン距離 (Levenshtein distance) [Levenshtein'66],または編集距離 (Edit distance) と呼ばれます.
(原著はロシア語で流石に読めないので(^^;),英語版を参照として示しています)

編集距離は,あるラベル系列から別のラベル系列に変える際の,最小操作回数で定義されます.

つまり,WER は編集距離を参照ラベル (評価の場合は正解ラベル) の長さで正規化した値を示しています.

  • [Levenshtein'66]: V. I. Levenshtein, "Binary codes capable of correcting deletions, insertions, and reversals," Soviet Physics-Doklady, Vol.10, No.8, pp.707-710, available here, 1966.

2. WER によくある誤解

"Rate" という語が用いられているからかもしれませんが,WER は \([0, 1]\) の範囲の値になるとよく誤解されています.

入力ラベルが参照ラベルと完全に一致した場合,WER は \(0\) になります.
一方,最大値は \(1\) 以上の値を取り得ます (正確には入力ラベルと参照ラベルの長さの比で決まります) .

これは簡単に確かめられますので実験してみましょう.

まず,下記のコードで編集距離が使えるライブラリをインポートします.

1
from nltk.metrics.distance import edit_distance

編集距離が使えるライブラリはいくつかありますが,ここでは Colab に標準でインストールされている nltk という自然言語処理ライブラリを用います.

まず正解した場合の WER を次のコードで確認します.

1
2
3
4
5
ref_label = "abc"
len_ref = len(ref_label)

wer = edit_distance("abc", ref_label) / len_ref
print(f"WER of correct input:{wer}")
WER of correct input:0.0

結果は想定どおり \(0\) になりました.

次にいくつか間違いをした場合の WER を次のコードで確認します.

1
2
wer = edit_distance("a", ref_label) / len_ref
print(f"WER of 2 mistakes:{wer}")
WER of 2 mistakes:0.6666666666666666

3文字中 2文字間違っているので,\(0.66...\) となります.

では"ddddddd..." のように全く異なる文字列の場合はどうなるでしょうか?

1
2
3
4
failed_inputs = "ddddddddddddddd"
wer = edit_distance(failed_inputs, ref_label) / len_ref
print(f"WER of many mistakes:{wer}")
print(f"Maximum error:{len(failed_inputs)/len_ref}")
WER of many mistakes:5.0
Maximum error:5.0

結果から分かるように WER は \(5\) となり \(1\) 以上の値をとることが分かります.

実際は学習済みの認識器を評価するので実用上問題ありませんが,学習初期などに \(1\) 以上の値が出たとしても WER が間違っているわけではないので注意してください.

3. 余談: Normalized Edit distance について

余談ですが,WER が \(1\) 以上になることを嫌って,下記のような処理を組みたくなるかもしれません (昔の私のことです(^^;)).

1
wer = edit_distance(inputs_label, ref_label) / max(len(inputs_label), len(ref_label))

上の処理はしばしば Normalized edit distance (NED) と呼ばれるようです.
(同じ名前で違う計算手法もあるようなのでややこしいですが)

NED は確かに \([0, 1]\) の範囲に値が収まるのですが,性能評価に用いて良いかは少し疑問に思っています.

分母にモデルが出力したラベル系列長が入っているので,同じ入力データを用いた場合でも認識結果に応じて異なる正規化が施されることになります.

異なるスケールで正規化した値で大小を比べるのは難しいので,モデル間で WER を比較するのが困難になる気がしています.
(厳密には,そもそも評価指標の平均を比べるのではなくて,差の平均を比べるべきかもしれませんが)


今回は Word error rate について簡単に紹介しましたが,如何でしたでしょうか?
Levenshtein distance については過去にそれなりに時間をかけて調べたのですが,ほとんど忘れてしまってました (^^;).

評価指標を調べること自体は勉強になって面白いのですが,調べれば調べるほど "どれでも良いような,どれも駄目なような..." という状態になりがちです.
余裕が無いときは素直に先人の例に倣うのも一つの手です (体験談です(^^;)).

今回紹介した話が,これから深層学習を勉強してみようとお考えの方に何か参考になれば幸いです.