Как использовать метрики TensorFlow в Керасе
Кажется, уже есть несколько тем / проблем по этому вопросу, но мне не кажется, что это было решено:
Как я могу использовать метрическую функцию тензорного потока в моделях keras?
https://github.com/fchollet/keras/issues/6050
https://github.com/fchollet/keras/issues/3230
Люди, кажется, либо сталкиваются с проблемами, связанными с инициализацией переменной, либо с метрикой 0.
Мне нужно рассчитать различные показатели сегментации и я хотел бы включить tf.metric.mean_iou в мою модель Keras. Это лучшее, что мне удалось придумать:
def mean_iou(y_true, y_pred):
score, up_opt = tf.metrics.mean_iou(y_true, y_pred, NUM_CLASSES)
K.get_session().run(tf.local_variables_initializer())
return score
model.compile(optimizer=adam, loss='categorical_crossentropy', metrics=[mean_iou])
Этот код не выдает никаких ошибок, но mean_iou всегда возвращает 0. Я считаю, что это потому, что up_opt не оценивается. Я видел, что до TF 1.3 люди предлагали использовать что-то вроде control_flow_ops.with_dependencies([up_opt], Score) для достижения этой цели. Это больше не представляется возможным в TF 1.3.
Таким образом, как я могу оценить метрики TF 1.3 в Keras 2.0.6? Это кажется довольно важной особенностью.
2 ответа
Вы все еще можете использоватьcontrol_dependencies
def mean_iou(y_true, y_pred):
score, up_opt = tf.metrics.mean_iou(y_true, y_pred, NUM_CLASSES)
K.get_session().run(tf.local_variables_initializer())
with tf.control_dependencies([up_opt]):
score = tf.identity(score)
return score
Вы можете использовать следующий декоратор для переноса tf.metrics в keras.metrics:
def as_keras_metric(method):
import functools
from keras import backend as K
import tensorflow as tf
@functools.wraps(method)
def wrapper(self, args, **kwargs):
""" Wrapper for turning tensorflow metrics into keras metrics """
value, update_op = method(self, args, **kwargs)
K.get_session().run(tf.local_variables_initializer())
with tf.control_dependencies([update_op]):
value = tf.identity(value)
return value
return wrapper
Основное использование:
auc_roc = as_keras_metric(tf.metrics.auc)
recall = as_keras_metric(tf.metrics.recall)
...
Скомпилируйте модель keras:
model.compile(..., metrics=[auc_roc])
Функция украшения:
Помните о несоответствии с аргументами (например, порядок y_pred
, y_true
). Украсьте свой выход из этого:
@as_keras_metric
def auc_roc(y_true, y_pred):
return tf.contrib.metrics.streaming_auc(y_pred, y_true)
Вы также можете использовать декоратор для установки параметров по умолчанию (например, для mean_iou
):
@as_keras_metric
def mean_iou(y_true, y_pred, num_classes=2):
return tf.metrics.mean_iou(y_true, y_pred, num_classes)
Для метрик, которые возвращают несколько значений, я ожидаю, что среднее значение берется во время каждой оценки эпохи. Например, использование двух пороговых значений в precision_at_thresholds
возвращает два значения, но, насколько я вижу, Keras сообщает среднее значение во время тренировки.
@as_keras_metric
def precision_at_thresholds(y_true, y_pred, thresholds=[0.25, 0.50]):
return tf.metrics.precision_at_thresholds(y_true, y_pred, thresholds)
Предостережения:
Помните, как прокомментировал fchollet, что это взлом. Это может привести к нежелательным результатам, поскольку Keras не поддерживает метрики тензорного потока.
Было 2 ключа, чтобы заставить это работать на меня. Первый использовал
sess = tf.Session()
sess.run(tf.local_variables_initializer())
Инициализировать переменные TF после использования функций TF (и компиляции), но перед выполнением model.fit()
, Вы получили это в своем первоначальном примере, но большинство других примеров показывают tf.global_variables_initializer()
, который не работал для меня.
Еще одна вещь, которую я обнаружил, - это объект op_update, который возвращается как вторая часть кортежа из многих метрик TF. Это то, что мы хотим. Другая часть кажется равной 0, когда метрики TF используются с Keras. Таким образом, ваш показатель IOU должен выглядеть следующим образом:
def mean_iou(y_true, y_pred):
return tf.metrics.mean_iou(y_true, y_pred, NUM_CLASSES)[1]
from keras import backend as K
K.get_session().run(tf.local_variables_initializer())
model.fit(...)