Пользовательская функция потерь, которая обновляется на каждом этапе с помощью градиентного спуска - PullRequest
2 голосов
/ 26 октября 2019

Из этой записи мы можем написать пользовательскую функцию потерь. Теперь предположим, что пользовательская функция потерь зависит от параметра a:

def customLoss(yTrue,yPred):
    return (K.log(yTrue) - K.log(yPred))**2+a*yPred

Как мы можем обновлять параметр a на каждом шаге с градиентным спуском, например, весами?:

a_new= a_old - alpha * (derivative of custom loss with respect to a)

PS реальная кастомная потеря отличается от вышеописанной. Пожалуйста, дайте мне общий ответ, который работает для любой произвольной пользовательской функции потерь, а не ответ на приведенный выше пример.

1 Ответ

1 голос
/ 31 октября 2019

Создайте пользовательский слой для хранения обучаемого параметра. Этот слой не будет возвращать входные данные в своем вызове, но у нас будут входные данные для соответствия с тем, как вы создаете слои.

class TrainableLossLayer(Layer):

    def __init__(self, a_initializer, **kwargs):
        super(TrainableLossLayer, self).__init__(**kwargs)
        self.a_initializer = keras.initializers.get(a_initializer)

    #method where weights are defined
    def build(self, input_shape):
        self.kernel = self.add_weight(name='kernel_a', 
                                  shape=(1,),
                                  initializer=self.a_initializer,
                                  trainable=True)
        self.built=True

    #method to define the layers operation (only return the weights)
    def call(self, inputs):
        return self.kernel

    #output shape
    def compute_output_shape(self, input_shape):
        return (1,)

Используйте слой в вашей модели, чтобы получить a с любыми входными данными(это не совместимо с последовательной моделью):

a = TrainableLossLayer(a_init, name="somename")(anyInput)

Теперь вы можете попытаться определить свою потерю некрасивым образом:

def customLoss(yTrue,yPred):
    return (K.log(yTrue) - K.log(yPred))**2+a*yPred

Если это работает, тоготово.


Вы также можете попробовать более сложную модель (если вы не хотите использовать a при проигрыше, прыгая по таким слоям, это может вызвать проблемы при сохранении / загрузке модели)

В этом случае вам потребуется, чтобы y_train входил в качестве входа вместо выхода:

y_true_inputs = Input(...)

Ваша функция потерь перейдет в слой Lambda, принимающий все параметры правильно:

def lambdaLoss(x):
    yTrue, yPred, alpha = x
    return (K.log(yTrue) - K.log(yPred))**2+alpha*yPred

loss = Lambda(lambdaLoss)(y_true_inputs, original_model_outputs, a)

Ваша модель выведет эту потерю:

model = Model([original_model_inputs, y_true_inputs], loss)

У вас будет функция фиктивной потери:

def dummyLoss(true, pred):
    return pred

model.compile(loss = dummyLoss, ...)

И вы будете тренироваться как:

model.fit([x_train, y_train], anything_maybe_None_or_np_zeros ,....)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...