Такие методы нелегко реализовать, но есть хитрость. Определите потери следующим образом:
import keras.backend as K
def regression_nll_loss(sigma_sq, epsilon = 1e-6):
def nll_loss(y_true, y_pred):
return 0.5 * K.mean(K.log(sigma_sq + epsilon) + K.square(y_true - y_pred) / (sigma_sq + epsilon))
return nll_loss
Затем определите модель с двумя выходными данными, один для среднего значения, а другой для дисперсии:
from keras.models import Model
from keras.layers import Dense, Input
inp = Input(shape=(1,))
x = Dense(32, activation="relu")(inp)
x = Dense(32, activation="relu")(x)
mean = Dense(1, activation="linear")(x)
var = Dense(1, activation="softplus")(x)
train_model = Model(inp, mean)
pred_model = Model(inp, [mean, var])
train_model.compile(loss=regression_nll_loss(var), optimizer="adam")
train_model.fit(x, y, ...)
mean, var = pred_model.predict(some_input)
Хитрость заключается в явном прохождении тензорадля дисперсии к потере, поэтому требуется только два входа, а контроль выполняется только для среднего значения. Затем вам нужно определить две модели, которые имеют общие веса, одну для обучения, а другую для тестирования / вывода. Эта последняя модель возвращает среднее значение и дисперсию.
Не забудьте использовать активацию softplus для дисперсии, чтобы сохранить ее положительной. Я реализовал эту потерю для использования с Deep Ensembles , вы можете найти пример здесь .