#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