Как создать собственную функцию потерь в Keras, которая оценивает прогноз после каждой эпохи? - PullRequest
1 голос
/ 25 октября 2019

Я работаю над нейронной сетью в Керасе, которая переводит английские предложения на пользовательский язык. Для этого я хотел бы создать пользовательскую функцию потерь, которая принимает прогноз для каждого предложения и оценивает, соответствует ли он правилам грамматики пользовательского языка и, если нет, добавляет значение к стандартной функции потерь.

Как я могу оценить тензор после каждой эпохи, но не во время компиляции?

Ниже приведена моя пользовательская функция потерь. Поскольку во время компиляции модели еще нет пакета, y_pred имеет форму (None, x, y) и не может быть оценен, чтобы получить прогноз. Моя идея, чтобы обойти это, заключалась в том, чтобы назначить стандартную функцию потерь во время компиляции и, когда прибывают партии, рассчитать пользовательские потери. К сожалению, пользовательские потери не достигаются.

def custom_loss(tokenizer, punishment_rate):

    def compile_loss(y_true, y_pred):
        shape = K.int_shape(y_pred)
        #standard loss function
        loss = K.sparse_categorical_crossentropy(y_true, y_pred)

        if shape[0] is not None:
            #THIS is never reached and that's the problem
            prediction = logits_to_text(K.eval(y_pred), tokenizer)

            #test if prediction complies to grammar rules
            compileable = compiles(prediction) ^ 1

            compile_error = compileable * punishment_rate
            loss =  K.sparse_categorical_crossentropy(y_true, y_pred, axis=-1) * (1 + compile_error)

        return loss

    return compile_loss

Есть ли обходной путь для оценки тензора, только когда он был заполнен партией? Или, в качестве альтернативы, изменить функцию потерь после компиляции модели с помощью обратного вызова без необходимости перекомпиляции модели?

1 Ответ

0 голосов
/ 25 октября 2019

В соответствии с источником keras , вы можете использовать Оболочку функции потери , чтобы создать класс пользовательской функции потери и затем беспрепятственно передать его в вашу модель.

Какпример:

#Import the wrapper
from keras.losses import LossFunctionWrapper

#Create your class extending the wrapper
class MyLossFunction(LossFunctionWrapper):

#Implement the constructor - here you can give extended arguments to it.
   def __init__(self, 
                 tokenizer, 
                 punishment_rate,
                 reduction=losses_utils.Reduction.SUM_OVER_BATCH_SIZE,
                 name='my_custom_text_function'):
        super(MyLossFunction, self).__init__(
            my_function, 
            name=name,
            reduction=reduction,
            tokenizer = tokenizer, 
            punishment_rate= punishment_rate)

#Now you have to define your function "my_function":
#Please, notice that ALL loss functions that follow keras model needs two arguments: 
#y_true (correct result) and y_pred (the result obtained in the network).
def my_function(y_true, y_pred, tokenizer, punishment_rate):
   shape = K.int_shape(y_pred)
   if shape[0] is not None:
       prediction = logits_to_text(K.eval(y_pred), tokenizer)

       #test if prediction complies to grammar rules
       compileable = compiles(prediction) ^ 1

       compile_error = compileable * punishment_rate
       return K.sparse_categorical_crossentropy(y_true, y_pred, axis=-1) * (1 + compile_error)
   return K.sparse_categorical_crossentropy(y_true, y_pred)

Вы можете создать его экземпляр и использовать в своем компиляторе:

custom_loss= MyLossFunction(tokenizer = ..., punishment_rate = ...)
classifier.compile(optimizer=optimizer, 
                      loss=custom_loss, 
                      metrics= ['binary_accuracy'])
...