Реализация пользовательской функции потерь в Tensorflow приводит к «Ошибке значения: «выходы» должны быть определены перед циклом».

#python #tensorflow #keras #nlp #loss-function

Вопрос:

Я работаю над своим первым проектом машинного обучения на Python — использую TensorFlow, чтобы попытаться составить слова по слогам с помощью набора данных Moby Hyphenator II.

Я рассматриваю это как проблему классификации с несколькими метками, в которой слова и их слоги кодируются в следующем формате:

 T e n - s o r - f l o w
0 0 1   0 0 1   0 0 0 0
 

Читая это руководство в качестве отправной точки, я увидел, что автор использовал пользовательскую функцию — они усредняли взвешенную двоичную перекрестную энтропию с среднеквадратичной ошибкой в PyTorch как таковой:

 def bce_rmse(pred, target, pos_weight = 1.3, epsilon = 1e-12):
    # Weighted binary cross entropy
    loss_pos = target * torch.log(pred   epsilon)
    loss_neg = (1 - target) * torch.log(1 - pred   epsilon)
    bce = torch.mean(torch.neg(pos_weight * loss_pos   loss_neg))

    # Root mean squared error
    mse = (torch.sum(pred, dim = 0) - torch.sum(target, dim = 0)) ** 2
    rmse = torch.mean(torch.sqrt(mse   epsilon))

    return (bce   rmse) / 2
 

Я попытался реализовать это в TensorFlow следующим образом:

 def weighted_bce_mse(y_true, y_prediction):
    # Binary crossentropy with weighting
    epsilon = 1e-12
    positive_weight = 4.108897148948174
    loss_positive = y_true * tf.math.log(y_prediction   epsilon)
    loss_negative = (1 - y_true) * tf.math.log(1 - y_prediction   epsilon)
    bce_loss = np.mean(tf.math.negative(positive_weight * loss_positive   loss_negative))
    
    # Mean squared error
    mse = tf.keras.losses.MeanSquaredError()
    mse_loss = mse(y_true, y_prediction)

    averaged_bce_mse = (bce_loss   mse_loss) / 2
    return averaged_bce_mse
 

При этом я получаю ошибку ValueError: 'outputs' must be defined before the loop. , и я не уверен, почему, поскольку я определяю эту функцию перед сборкой и компиляцией своей модели.

Я использую функциональный API Keras, и мои этапы компиляции и подгонки:

 model.compile(optimizer="adam", loss=weighted_bce_mse, metrics=["accuracy"], steps_per_execution=64)
history = model.fit(padded_inputs, padded_outputs, validation_data=(validation_inputs, validation_outputs), epochs=10, verbose=2)
 

Комментарии:

1. Где это outputs определено?

2. @kkgarg Я использую функциональный API Keras, как указано, выходные данные определяются следующим образом: model = tf.keras.models.Model(inputs=inputs, outputs=x) Я уверен, что проблема не в построении модели, поскольку она отлично работает с любой другой функцией потерь, которую я использовал раньше (двоичная перекрестная энтропия или среднеквадратичная ошибка)-ошибка возникает только с этой пользовательской функцией потерь. Интересно, что модель также работает, когда я беру среднее значение двоичной перекрестной энтропии и среднеквадратичную ошибку без взвешивания, поэтому я считаю, что именно взвешивание вызывает проблему.

3. Похоже, с новой функцией потерь проблем нет. Можете ли вы вставить стек ошибок и полный код?

4. @kkgarg Да! Вот стек ошибок и соответствующий код .

5. Спасибо! Я совсем новичок в том, чтобы задавать вопросы о переполнении стека, поэтому я не знал, что это лучшая практика, но буду придерживаться этого в будущем.

Ответ №1:

Как упоминалось ранее, показанная ошибка не имеет ничего общего с функцией пользовательских потерь. В коде, который вы показали, было множество других ошибок, таких как неправильный импорт tf.keras.layers . После исправления этих ошибок ознакомьтесь с приведенным ниже кодом и протестируйте приведенные ниже версии (работает нормально).:

 tensorflow 2.4.1
numpy 1.19.5
python 3.9.6
 
 import tensorflow as tf

# Custom loss function - mean of binary crossentropy and mean squared error
def mean_weighted_bce_mse(y_true, y_prediction):
    # Binary crossentropy with weighting
    epsilon = 1e-12
    positive_weight = 4.108897148948174
    loss_positive = y_true * tf.math.log(y_prediction   epsilon)
    loss_negative = (1 - y_true) * tf.math.log(1 - y_prediction   epsilon)
    bce_loss = np.mean(tf.math.negative(positive_weight * loss_positive   loss_negative))
    
    # Mean squared error
    mse = tf.keras.losses.MeanSquaredError()
    mse_loss = mse(y_true, y_prediction)
 
    averaged_bce_mse = (bce_loss   mse_loss) / 2
    return tf.math.reduce_mean(averaged_bce_mse, axis=-1)
 
 
inputs = tf.keras.Input(shape=(15,))
x = tf.keras.layers.Embedding(64, 64, mask_zero=True)(inputs)
 
x = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(128, return_sequences=True))(x)
x = tf.keras.layers.Dropout(0.2)(x)
x = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(128, return_sequences=True))(x)
x = tf.keras.layers.Dropout(0.2)(x)
x = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(128, return_sequences=True))(x)
x = tf.keras.layers.Dropout(0.3)(x)
 
 
x = tf.keras.layers.Conv1D(64, kernel_size=1)(x)
x = tf.keras.layers.Dropout(0.2)(x)
x = tf.keras.layers.Conv1D(64, kernel_size=1)(x)
x = tf.keras.layers.Dropout(0.2)(x)
x = tf.keras.layers.GlobalMaxPool1D()(x)
x = tf.keras.layers.Dropout(0.5)(x)
 
x = tf.keras.layers.Dense(32, activation="relu")(x)
x = tf.keras.layers.Dense(15, activation="sigmoid")(x)
 
 
model = tf.keras.models.Model(inputs=inputs, outputs=x)
model.compile(optimizer="adam", loss=mean_weighted_bce_mse, metrics=["accuracy"], steps_per_execution=64)
 
# history = model.fit(padded_inputs,
#                     padded_outputs,
#                     validation_data=(validation_inputs, validation_outputs),
#                     epochs=20,
#                     batch_size=8)
 

Комментарии:

1. Я думаю , что допустил ошибку при создании pastebin, так что последняя строка функции потерь должна быть просто return averaged_bce_mse , повлияет ли это на решение?

2. Однако ничего подобного ошибке, о которой вы упоминали ранее, я не рассматривал саму функцию потерь глубоко. Сработало ли вышеупомянутое решение?

3. К сожалению, я все еще получаю ту же ошибку ValueError: 'outputs' must be defined before the loop. ; Я получил этот стек ошибок .

Ответ №2:

В приведенной ниже строке кода:

 model.compile(optimizer="adam", loss=mean_weighted_bce_mse, metrics=["accuracy"], steps_per_execution=64)
history = model.fit(padded_inputs,
                padded_outputs,
                validation_data=(validation_inputs, validation_outputs),
                epochs=20,
                batch_size=8)
 

какова длина ваших входных данных?
steps_per_execution должен быть . len(input_data)/Batch_size
Снимите steps_per_execution и проверьте еще раз.

Комментарии:

1. Удаление steps_per_execution приводит к другой ошибке при вызове model.fit ; новая ошибка TypeError: Input 'y' of 'Mul' Op has type float32 that does not match type int32 of argument 'x'. , которая, я думаю, означает, что ошибка действительно связана с пользовательской функцией потери, которую я написал.

2. все в порядке steps_per_execution=len(input_data)/Batch_size ?… В трассировке стека ошибок, которую вы опубликовали, первая точка, в которой возникает ошибка batch_size=8 , правильна?….

3. steps_per_execution 64 для ускорения времени выполнения, поскольку это означает, что 64 пакета передаются за один tf.function вызов вместо только 1 — это не зависит от длины входных данных и размера пакета, я думаю, вы имеете в steps_per_epoch виду ? Я также опубликовал свое решение этого вопроса, проблема в том, что я использовал np.mean вместо tf.math.reduce_mean и не приводил y_prediction и y_true к типу tf.float32 данных .

4. Отлично!… вы исправили это…Я сталкивался с этим раньше и это происходило из-за steps_per_execution того, что я спрашивал вас об этом

Ответ №3:

Я обнаружил, что ошибка возникла из-за операций, которые я использовал в пользовательской функции потерь:

 bce_loss = np.mean(tf.math.negative(positive_weight * loss_positive   loss_negative))
 

В этой строке используется np.mean то, что вызывало ошибку — замена этого на tf.math.reduce_mean наряду с приведением y_true и y_prediction для tf.float32 tf.cast решения проблемы:

 # Custom loss function - mean of binary crossentropy and mean squared error
def mean_weighted_bce_mse(y_true, y_prediction):
    y_true = tf.cast(y_true, tf.float32)
    y_prediction = tf.cast(y_prediction, tf.float32)

    # Binary crossentropy with weighting
    epsilon = 1e-12
    positive_weight = 4.108897148948174
    loss_positive = y_true * tf.math.log(y_prediction   epsilon)
    loss_negative = (1 - y_true) * tf.math.log(1 - y_prediction   epsilon)
    bce_loss = tf.math.reduce_mean(tf.math.negative(positive_weight * loss_positive   loss_negative))
    
    # Mean squared error
    mse = tf.keras.losses.MeanSquaredError()
    mse_loss = mse(y_true, y_prediction)

    averaged_bce_mse = (bce_loss   mse_loss) / 2
    return averaged_bce_mse