56
46

More than 1 year has passed since last update.

【Keras入門(4)】Kerasの評価関数(Metrics)

Last updated at Posted at 2019-06-13

入門者に向けてKerasの評価関数について解説します。
適合率(Precision)や再現率(Recall)を評価関数として追加したときに、理解に時間をかけたので記録しておきます。
TensorBoardも含めてGoogle Colaboratoryを使っているのでローカルでの環境準備すらしていません。Google Colaboratoryについては「Google Colaboratory概要と使用手順(TensorFlowもGPUも使える)」の記事を参照ください。

以下のシリーズ記事です。

使ったPythonライブラリ

Google Colaboratoryでインストール済の以下のライブラリとバージョンを使っています。KerasはTensorFlowに統合されているものを使っているので、ピュアなKerasは使っていません。Pythonは3.6です。

  • tensorflow: 1.13.1
  • Numpy: 1.16.3

Kerasでの評価関数(Metrics)の基本的な使い方

compile関数で評価関数(Metrics)を指定します。"acc"または"accuracy"を選ぶと、損失関数や出力テンソルの情報から自動で"categorical_accuracy"などを判断してくれるようです。

model.compile(loss="binary_crossentropy", optimizer="sgd", metrics=['acc'])

概要は評価関数の公式文書に書いてあります。TensorFlow1.13以降を使えば、適合率(Precision)や再現率(Recall)なども指定できます(以下のコード参照)。あまりよく調べていないのですが純正Kerasだと使えなそうな気がします。使用可能なMetricsはAPI文書を参照ください。
※2021/09/16 リンク先変更しました。こちらの方がわかりやすい。

from tensorflow.keras.metrics import Precision, Recall
model.compile(loss="binary_crossentropy", optimizer="sgd", metrics=[Precision(), Recall()])

Kerasでのカスタム評価関数(Metrics)の定義の仕方

Tensorの扱い方に慣れていないので、作り方を理解するのに時間がかかりました。公式ガイドを見ても情報が少なくてよくわからない。metrics.pyなどを見てつくりながら確認しました。

(y_true, y_pred) を引数とし,各データ点に対してスカラを返す関数を評価関数として利用できます:
y_true: 正解ラベル.Theano/TensorFlow テンソル
y_pred: 予測.y_trueと同じ形状のTheano/TensorFlow テンソル

カスタム評価関数

カスタム関数の基本とTP定義

今回はOne-Hot-Encodingでない二値分類だとします。
その場合、関数の引数y_true(正解ラベル)は0または1、y_pred(予測値)は0から1までの連続変数です。仮にバッチサイズが4で、TP・TN・FP・FNの全パターンの場合は以下のように引数が渡されます。

TP TN FP FN
y_true 1 0 0 1
y_pred 0.8 0.2 0.8 0.2

例えばTP(True Positive)のMetricsは以下のように定義します。

import tensorflow.keras.backend as K

def tp(y_true, y_pred):
    return K.sum(K.round(y_true * y_pred)) * batches

混合行列で"K.round(y_true * y_pred)"の部分を表現すると下記のようになり、TP部分の1が"K.sum"でカウントされます("K.round"は四捨五入)。

実際は正
(Positive)
y_true=1
実際は負
(Negative)
y_true=0
予測が正
(Positive)
y_pred=0.8
TP
$1 \times 0.8 \fallingdotseq 1$
FP
$0 \times 0.8 \fallingdotseq 0$
予測が負
(Negative)
y_pred=0.2
FN
$1 \times 0.2 \fallingdotseq 0$
TN
$0 \times 0.2 \fallingdotseq 0$

計算式の末尾の"* batches"の部分は、1エポック内でバッチをまわす回数です。Kerasはバッチ間のMetricsが平均により算出されます。そのため、平均化したくない場合にはバッチ回数で乗算が必要です(二度手間)。

例えば、30件のデータに対してバッチサイズを10にして1エポックで3回バッチ実行をします。

model.fit(data, labels, epochs=300, batch_size=10)

その場合、乗算をしないと以下のように計算され、最終的にエポック内でのMetrics出力値は20となります。

関数出力値
バッチ1回目 10
バッチ2回目 20
バッチ3回目 30
出力Metrics (10+20+30)/3 = 20

TPのような絶対値を出力したいMetricsでは、平均化したくないので乗算をして以下のように計算をします。

TP関数出力値
バッチ1回目 $10 \times 3 = 30$
バッチ2回目 $20 \times 3 = 60$
バッチ3回目 $30 \times 3 = 90$
出力Metrics $ (30+60+90) / 3 = 60$
$ 10+20+30 = 60$

TN定義

TN(True Negative)の場合は以下の計算式で算出します。

def tn(y_true, y_pred):
    return K.sum(K.cast(K.equal(K.round(y_true + y_pred), 0), K.floatx())) * batches

混合行列で"K.round(y_true + y_pred)"の部分を表現すると下記のようになり、TNは0と計算させます。

実際は正
(Positive)
y_true=1
実際は負
(Negative)
y_true=0
予測が正
(Positive)
y_pred=0.8
TP
$1 + 0.8 \fallingdotseq 2$
FP
$0 + 0.8\fallingdotseq 1$
予測が負
(Negative)
y_pred=0.2
FN
$1 + 0.2 \fallingdotseq 1$
TN
$0 + 0.2 \fallingdotseq 0$

そのあとに以下の流れでTNをカウントします。
1. "K.equal"で0をTrueに変換
2. "K.cast"でTrueを1に変換
3. "K.sum"で1を合算

FP定義

FP(False Positive)の場合は以下の計算式で算出します。

def fp(y_true, y_pred):
    return K.sum(K.cast(K.equal(K.round(y_pred) - y_true, 1), K.floatx())) * batches

混合行列で"K.round(y_pred) - y_true"の部分を表現すると下記のようになり、FPは1と計算させます。

実際は正
(Positive)
y_true=1
実際は負
(Negative)
y_true=0
予測が正
(Positive)
y_pred=0.8
TP
$1 - 1 = 0$
FP
$1 - 0 = 1$
予測が負
(Negative)
y_pred=0.2
FN
$0 - 1 = -1$
TN
$0 - 0 = 0$

そのあとに以下の流れでFPをカウントします。
1. "K.equal"で1をTrueに変換
2. "K.cast"でTrueを1に変換
3. "K.sum"で1を合算

FN定義

FN(False Negative)の場合は以下の計算式で算出します。

def fn(y_true, y_pred):
    return K.sum(K.cast(K.equal(y_true - K.round(y_pred), 1), K.floatx())) * batches

混合行列で"y_true - K.round(y_pred)"の部分を表現すると下記のようになり、FNは1と計算させます。

実際は正
(Positive)
y_true=1
実際は負
(Negative)
y_true=0
予測が正
(Positive)
y_pred=0.8
TP
$1 - 1 = 0$
FP
$0 - 1 = -1$
予測が負
(Negative)
y_pred=0.2
FN
$1 - 0 = 1$
TN
$0 - 0 = 0$

そのあとに以下の流れでFNをカウントします。
1. "K.equal"で1をTrueに変換
2. "K.cast"でTrueを1に変換
3. "K.sum"で1を合算

適合率(Precision)と再現率(Recall)

TP、FP、FNが算出できれば適合率(Precision)と再現率(Recall)は簡単です。TPなどの値から計算すればいいだからです。

def custom_precision(y_true, y_pred):
    return tp(y_true, y_pred) / (tp(y_true, y_pred) + fp(y_true, y_pred))

def custom_recall(y_true, y_pred):
    return tp(y_true, y_pred) / (tp(y_true, y_pred) + fn(y_true, y_pred))

F1スコアを出したい場合には、簡単にできないので注意してください。
Kerasで評価関数にF1スコアを使う方法参照。

Pythonプログラム

プログラム全体はGitHubにあります。
適合率(Precision)や再現率(Recall)を追加するだけなら、TensorFlow1.13以上のバージョンでは、ここで書いてあるような面倒なことは不要です。
TensorBoardに出力すれば、以下のようにMetricsを見ることができます。
※出力方法は記事「【Keras入門(3)】TensorBoardで見える化」参照

04.MetricsTensorBoard.JPG

56
46
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
56
46