Вопрос или проблема
У меня проблема с моими пользовательскими функциями потерь и метрик. Моя цель – обучить модель CNN на изображениях с тангенсом угла ориентации объекта на моем изображении, и у меня есть столбец, который указывает, является ли тангенс положительным или отрицательным. В конце концов, у меня есть два выхода: один для тангенса (регрессия), а второй – для классификации. Теперь, когда я вызываю model.evaluate, я записываю регрессию как первую элемент, который должен появиться, но он не появляется первым. И я не уверен, что они как-то перепутаны, потому что не могу найти объяснение странным результатам, которые я получаю. Вот мой код:
# Пользовательские функции потерь и метрик
@keras.utils.register_keras_serializable(package="Custom")
def angular_loss(y_true, y_pred):
angles_true = tf.math.atan(y_true) * 180.0 / np.pi
angles_pred = tf.math.atan(y_pred) * 180.0 / np.pi
return tf.abs(angles_true - angles_pred)
@keras.utils.register_keras_serializable(package="Custom")
def rmse_degrees(y_true, y_pred):
a = tf.constant(np.pi)
angles_true = tf.math.atan(y_true) * 180.0 / a
angles_pred = tf.math.atan(y_pred) * 180.0 / a
b = tf.square(angles_true - angles_pred)
return tf.reduce_mean(b)
# Определяем модель
input_image = Input(shape=X_train_images.shape[1:], name="input_image")
x = layers.Conv2D(32, (3, 3), activation='relu')(input_image)
x = layers.MaxPooling2D((2, 2))(x)
x = layers.Dropout(0.3)(x)
x = layers.Conv2D(64, (3, 3), activation='relu')(x)
x = layers.MaxPooling2D((2, 2))(x)
x = layers.Dropout(0.3)(x)
x = layers.Flatten()(x)
x = layers.Dense(128, activation='relu')(x) # Промежуточный полносвязный слой
x = layers.Dropout(0.3)(x)
output_regression = layers.Dense(1, activation='linear', name="reg_output")(x)
output_classification = layers.Dense(1, activation='sigmoid', name="cls_output")(x)
model = keras.Model(inputs=input_image, outputs=[output_regression, output_classification])
model.summary()
model.save("modelfinal3.keras")
# Компилируем модель
model.compile(
optimizer = RMSprop(learning_rate=0.0001),
loss={
'reg_output': angular_loss,
'cls_output': 'binary_crossentropy'
},
metrics={
'reg_output': [rmse_degrees],
'cls_output': ['accuracy']
}
)
# Определяем обратный вызов ModelCheckpoint для сохранения лучшей модели
callbacks = [
keras.callbacks.ModelCheckpoint("modelfinal3.keras", monitor="reg_output_loss", save_best_only=True , mode="min"),
keras.callbacks.EarlyStopping(monitor="reg_output_loss" , patience = 8 ,mode="min" )
]
# Обучаем модель без валидационных данных
history = model.fit(
X_train_images,{'reg_output' : Y1_regression ,'cls_output' : Y2_classification} ,
epochs= 10 ,
batch_size= 64,
callbacks=callbacks
)
test_model =keras.models.load_model("modelfinal3.keras", custom_objects ={'angular_loss': angular_loss, 'rmse_degrees': rmse_degrees })
results = test_model.evaluate(X_test_images, {'reg_output' : Y1_regression_test ,'cls_output' : Y2_classification_test },return_dict=True )
print(results)
‘введите код здесьрезультаты
30/30 ━━━━━━━━━━━━━━━━━━━━ 51s 2s/step - cls_output_accuracy: 0.6618 - cls_output_loss: 9.0815 - loss: 14.4716 - reg_output_loss: 5.3914 - reg_output_rmse_degrees: 2806.2744
Эпоха 7/10
30/30 ━━━━━━━━━━━━━━━━━━━━ 53s 2s/step – cls_output_accuracy: 0.6401 – cls_output_loss: 8.9781 – loss: 14.7173 – reg_output_loss: 5.7363 – reg_output_rmse_degrees: 2787.8420
Эпоха 8/10
30/30 ━━━━━━━━━━━━━━━━━━━━ 51s 2s/step – cls_output_accuracy: 0.6524 – cls_output_loss: 9.0007 – loss: 14.5403 – reg_output_loss: 5.5401 – reg_output_rmse_degrees: 2789.3442
Эпоха 9/10
30/30 ━━━━━━━━━━━━━━━━━━━━ 51s 2s/step – cls_output_accuracy: 0.6674 – cls_output_loss: 9.4412 – loss: 14.7438 – reg_output_loss: 5.3030 – reg_output_rmse_degrees: 2844.9971
Эпоха 10/10
30/30 ━━━━━━━━━━━━━━━━━━━━ 52s 2s/step – cls_output_accuracy: 0.6610 – cls_output_loss: 9.3189 – loss: 14.7248 – reg_output_loss: 5.4059 – reg_output_rmse_degrees: 2828.9368
11/11 ━━━━━━━━━━━━━━━━━━━━ 2s 142ms/step – cls_output_accuracy: 1.0000 – cls_output_loss: 9.4424 – loss: 9.4928 – reg_output_loss: 1.1921e-07 – reg_output_rmse_degrees: 2435.0107
{‘cls_output_accuracy’: 1.0, ‘cls_output_loss’: 8.932900428771973, ‘loss’: 9.235373497009277, ‘reg_output_loss’: 1.1920930376163597e-07, ‘reg_output_rmse_degrees’: 2396.7568359375}
Процесс завершился с кодом выхода 0 ‘
Ответ или решение
Проблемы с метриками и функцией потерь при обучении модели CNN: Долгосрочные решения
В процессе разработки и обучения модели сверточной нейронной сети (CNN) для анализа изображений с использованием функции потерь и метрик может возникнуть множество проблем. Ваша ситуация, о которой вы рассказали, связана с обучением модели, которая предсказывает тангенс угла ориентации объектов на изображениях, а также предсказывает принадлежность к классу (положительный или отрицательный тангенс). Рассмотрим ключевые проблемы, касающиеся ваших пользовательских функций потерь и метрик.
1. Неправильный порядок метрик в выводе результата
Ваша основная проблема заключается в том, что при использовании model.evaluate()
регрессионная метрика (RMSE для углов) не отображается первой, хотя вы ожидаете именно этого. Это может быть связано с несколькими факторами:
- Порядок вывода метрик: Стандартный вывод в Keras отображает метрики в том порядке, в котором они были определены в функции
model.compile()
. Таким образом, для исправления порядка метрик попробуйте изменить порядок определения вmetrics
:
metrics={
'cls_output': ['accuracy'],
'reg_output': [rmse_degrees]
}
Теперь при оценке результаты будут выводиться в следующем порядке: сначала метрики классификации, затем метрики регрессии.
2. Неправильные функции потерь и их возможное влияние на обучение
Функция потерь angular_loss
в вашем коде определяется с использованием tf.math.atan()
, которая может привести к некорректным результатам, если значения y_true
и y_pred
выходят за пределы допустимых диапазонов. Проверьте диапазон ваших данных для предотвращения проблем с неустойчивыми значениями. Убедитесь, что значения тангенса находятся в допустимом диапазоне.
Также стоит реализовать более явно нормализованный подход, чтобы избежать крайних значений. В некоторых случаях может помочь использование других функций потерь, например, среднеквадратичной ошибки для регрессии.
3. Визуализация и анализ истории обучения
Согласно вашим выводам, классовая модель достигает высокой точности, в то время как регрессионная модель показывает крайне низкие значения потерь по окончании обучения. Чтобы легче понять динамику обучения, полезно визуализировать потери и метрики через графики. Это поможет вам определить, не возникает ли проблемы с переобучением или недообучением.
Используйте следующее:
import matplotlib.pyplot as plt
# Визуализация метрик
plt.plot(history.history['reg_output_rmse_degrees'], label='Регрессионный RMSE')
plt.plot(history.history['cls_output_accuracy'], label='Точность классификации')
plt.title('Метрики обучения')
plt.ylabel('Значение метрики')
plt.xlabel('Эпоха')
plt.legend()
plt.show()
Заключение
Для решения описанных вами проблем необходимо внимательно проверить порядок метрик в выводе, корректность определения функций потерь и наблюдать за динамикой обучения модели. Эти шаги помогут вам более точно настроить модель и, возможно, устранить выявленные недостатки. Обратите внимание на визуализацию данных, чтобы упростить процесс анализа и настройки. Удачи в ваших усилиях по разработке и обучению сверточной нейронной сети!