Keras custom loss с одной из использованных функций и условием - PullRequest
0 голосов
/ 19 апреля 2019

Я пытаюсь сделать пользовательскую функцию для отклонения в Керасе. Отклонение рассчитывается как: 2 * (log (yTrue) - log (yPred))

Проблема здесь в том, что мои значения yTrue представляют собой число редких событий и поэтому часто равны 0, что приводит к ошибке -inf.

Вывод отклонения для моего конкретного случая (отклонение по Пуассону без масштабирования) дает решение этой проблемы:

  • Если yTrue = 0, то отклонение равно: 2 * D * yPred, где D - особенность моих данных.
  • Если yTrue! = 0, то отклонение равно: 2 * D * (yTrue * ln (yTrue) - yTrue * ln (yPred) - yTrue + yPred

Здесь я сталкиваюсь с двумя проблемами:

  • Мне нужно выбрать функцию в соответствии со значением yPred
  • Мне также нужно передать D в качестве аргумента функции потерь

Я сделал первую итерацию функции потерь перед выводом отклонения, добавив небольшие значения к yTrue, когда оно равно 0, чтобы предотвратить -Inf. проблемы, но это дает неправильные результаты для отклонения, поэтому я должен изменить его.

def DevianceBis(y_true, y_pred):
y_pred = KB.maximum(y_pred, 0.0 + KB.epsilon()) #make sure ypred is positive or ln(-x) = NAN
return (KB.sqrt(KB.square( 2 * KB.log(y_true + KB.epsilon()) - KB.log(y_pred))))

Я хотел бы знать, как передать значения D в функцию потерь и как использовать оператор if, чтобы выбрать правильное выражение для использования.

Заранее спасибо

РЕДАКТИРОВАТЬ:

Пробовал это, но возвращает NaN

    def custom_loss(data, y_pred):

        y_true = data[:, 0]
        d = data[:, 1:]
        # condition
        mask = keras.backend.equal(y_true, 0) #i.e. y_true != 0
        mask = KB.cast(mask, KB.floatx())
        # returns 0 when y_true =0, 1 otherwise
        #calculate loss using d...
        loss_value = mask * (2 * d * y_pred) + (1-mask) * 2 * d * (y_true * KB.log(y_true) - y_true * KB.log(y_pred) - y_true + y_pred)
        return loss_value


    def baseline_model():
        # create model
        #building model
        model = keras.Sequential()
        model.add(Dense(5, input_dim = 26, activation = "relu"))
        #model.add(Dense(10, activation = "relu"))
        model.add(Dense(1, activation = "exponential"))
        model.compile(loss=custom_loss, optimizer='RMSProp')
        return model

model = baseline_model()
model.fit(data2, np.append(y2, d, axis = 1), epochs=1, shuffle=True, verbose=1)

РЕДАКТИРОВАТЬ 2:

def custom_loss(data, y_pred):

    y_true = data[:, 0]
    d = data[:, 1:]
    # condition
    mask2 = keras.backend.not_equal(y_true, 0) #i.e. y_true != 0
    mask2 = KB.cast(mask2, KB.floatx())
    # returns 0 when y_true =0, 1 otherwise
    #calculate loss using d...
    loss_value = 2 * d * y_pred + mask2 * (2 * d * y_true * KB.log(y_true) + 2 * d * y_true * KB.log(y_pred) - 2 * d * y_true)
    return loss_value

EDIT 3, кажется, работает без журналов (хотя это не тот результат, который я ищу):

def custom_loss(data, y_pred):

    y_true = data[:, 0]
    d = data[:, 1]
    # condition
    mask2 = keras.backend.not_equal(y_true, 0) #i.e. y_true != 0
    mask2 = KB.cast(mask2, KB.floatx())
    # returns 0 when y_true =0, 1 otherwise
    #calculate loss using d...
    loss_value = 2 * d * y_pred #+ mask2 * (2 * d * y_true * KB.log(y_true) + 2 * d * y_true * KB.log(y_pred) - 2 * d * y_true)
    return loss_value


def baseline_model():
    # create model
    #building model
    model = keras.Sequential()
    model.add(Dense(5, input_dim = 26, activation = "relu"))
    #model.add(Dense(10, activation = "relu"))
    model.add(Dense(1, activation = "exponential"))
    model.compile(loss=custom_loss, optimizer='RMSProp')
    return model

model = baseline_model()
model.fit(data2, np.append(y2, d, axis = 1), epochs=1, shuffle=True, verbose=1)

Снова отредактируйте:

def custom_loss3(data, y_pred):

    y_true = data[:, 0]
    d = data[:, 1]
    # condition
    loss_value = KB.switch(KB.greater(y_true, 0), 2 * d * y_pred, 2 * d * (y_true * KB.log(y_true + KB.epsilon()) - y_true * KB.log(y_pred + KB.epsilon()) - y_true + y_pred))
    return loss_value

Ответы [ 2 ]

1 голос
/ 03 мая 2019

Итак, вот окончательный ответ ... спустя дни я наконец нашел, как это сделать.

def custom_loss3(data, y_pred):
        y_true = data[:, 0]
        d = data[:, 1]

        lnYTrue = KB.switch(KB.equal(y_true, 0), KB.zeros_like(y_true), KB.log(y_true))
        lnYPred = KB.switch(KB.equal(y_pred, 0), KB.zeros_like(y_pred), KB.log(y_pred))
        loss_value = 2 * d * (y_true * lnYTrue - y_true * lnYPred[:, 0] - y_true + y_pred[:, 0])
        return loss_value

Рассчитать журналы до фактической потери и дать K.zeros_like вместо него, если значение y_true равно 0. Также нужно взять только первый вектор y_pred, поскольку он вернет вектор NxN, а y_true вернет Nx1.

Также пришлось удалить значения d = 0 в данных (в любом случае они не очень полезны).

1 голос
/ 19 апреля 2019

Если D является функцией входного вектора, вы можете дополнить свою метку дополнительными D столбцами из ввода и записать собственный убыток. Вы можете передать дополнительную информацию прогноза w.r.t. ваш ввод в виде массива вроде этого

    def custom_loss(data, y_pred):

        y_true = data[:, 0]
        d = data[:, 1:]
        # condition
        mask = K.not_equal(y_true, 0) #i.e. y_true != 0
        # returns 0 when y_true =0, 1 otherwise
        #calculate loss using d...
        loss_value = mask*(2*d*y_pred) + mask*(2*d*(y_true*ln(y_true) - y_true*ln(y_pred) - y_true + y_pred)
        return loss_value


    def baseline_model():
        # create model
        i = Input(shape=(5,))
        x = Dense(5, kernel_initializer='glorot_uniform', activation='linear')(i)
        o = Dense(1, kernel_initializer='normal', activation='linear')(x)
        model = Model(i, o)
        model.compile(loss=custom_loss, optimizer=Adam(lr=0.0005))
        return model


    model.fit(X, np.append(Y_true, d, axis =1), batch_size = batch_size, epochs=90, shuffle=True, verbose=1)

EDIT:

Я добавил маску для условного оператора. Я не совсем уверен, будет ли это работать таким образом, или вам нужно привести его к целочисленным тензорам; потому что функция возвращает bool.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...