Сделать пользовательскую функцию потери в керасе
Привет я пытался сделать пользовательские функции потерь в кератах для dice_error_coefficient. Он имеет свои реализации в тензорной доске, и я попытался использовать ту же функцию в кератах с тензорным потоком, но он продолжает возвращать NoneType, когда я использовал model.train_on_batch или model.fit где, поскольку он дает правильные значения при использовании в метриках в модели. Может кто-нибудь помочь мне с тем, что мне делать? Я попробовал следующие библиотеки, такие как Keras-FCN от ahundt, где он использовал пользовательские функции потери, но, похоже, ничего из этого не работает. Целью и выводом в коде являются y_true и y_pred соответственно, как используется в файле lost.py в keras.
def dice_hard_coe(target, output, threshold=0.5, axis=[1,2], smooth=1e-5):
"""References
-----------
- `Wiki-Dice <https://en.wikipedia.org/wiki/Sørensen–Dice_coefficient>`_
"""
output = tf.cast(output > threshold, dtype=tf.float32)
target = tf.cast(target > threshold, dtype=tf.float32)
inse = tf.reduce_sum(tf.multiply(output, target), axis=axis)
l = tf.reduce_sum(output, axis=axis)
r = tf.reduce_sum(target, axis=axis)
hard_dice = (2. * inse + smooth) / (l + r + smooth)
hard_dice = tf.reduce_mean(hard_dice)
return hard_dice
3 ответа
Есть два шага в реализации параметризованной пользовательской функции потерь в Keras. Во-первых, написание метода для коэффициента / метрики. Во-вторых, написание функции-обертки для форматирования вещей так, как это нужно Керасу.
На самом деле немного чище использовать бэкэнд Keras вместо tenorflow для простых пользовательских функций потерь, таких как DICE. Вот пример коэффициента, реализованного таким образом:
import keras.backend as K def dice_coef(y_true, y_pred, smooth, thresh): y_pred = y_pred > thresh y_true_f = K.flatten(y_true) y_pred_f = K.flatten(y_pred) intersection = K.sum(y_true_f * y_pred_f) return (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)
Теперь для сложной части. Функции потери Keras должны принимать только (y_true, y_pred) в качестве параметров. Поэтому нам нужна отдельная функция, которая возвращает другую функцию.
def dice_loss(smooth, thresh): def dice(y_true, y_pred) return -dice_coef(y_true, y_pred, smooth, thresh) return dice
Наконец, вы можете использовать его следующим образом в компиляции Keras.
# build model
model = my_model()
# get the loss function
model_dice = dice_loss(smooth=1e-5, thresh=0.5)
# compile model
model.compile(loss=model_dice)
Согласно документации , вы можете использовать пользовательскую функцию потерь следующим образом:
Любой callable с подписью
loss_fn(y_true, y_pred)
который возвращает массив потерь (одну из выборок во входном пакете), можно передать в compile() как потерю. Обратите внимание, что взвешивание выборки автоматически поддерживается для любых таких потерь.
В качестве простого примера:
def my_loss_fn(y_true, y_pred):
squared_difference = tf.square(y_true - y_pred)
return tf.reduce_mean(squared_difference, axis=-1) # Note the `axis=-1`
model.compile(optimizer='adam', loss=my_loss_fn)
Полный пример:
import tensorflow as tf
import numpy as np
def my_loss_fn(y_true, y_pred):
squared_difference = tf.square(y_true - y_pred)
return tf.reduce_mean(squared_difference, axis=-1) # Note the `axis=-1`
model = tf.keras.Sequential([
tf.keras.layers.Dense(8, activation='relu'),
tf.keras.layers.Dense(16, activation='relu'),
tf.keras.layers.Dense(1)])
model.compile(optimizer='adam', loss=my_loss_fn)
x = np.random.rand(1000)
y = x**2
history = model.fit(x, y, epochs=10)
Кроме того, вы можете расширить существующую функцию потерь, наследуя от нее. Например, маскировкаBinaryCrossEntropy
:
class MaskedBinaryCrossentropy(tf.keras.losses.BinaryCrossentropy):
def call(self, y_true, y_pred):
mask = y_true != -1
y_true = y_true[mask]
y_pred = y_pred[mask]
return super().call(y_true, y_pred)
Хорошей отправной точкой являетсяcustom log
руководство: https://www.tensorflow.org/guide/keras/train_and_evaluate#custom_losses