Вопрос или проблема
Я пытаюсь реализовать модель бинарной классификации с использованием tensorflow keras и столкнулся с проблемой, которую не могу понять.
Моя модель должна классифицировать изображения домов на два класса: “старый/антикварный” и “новый/современный”. Я использовал трансферное обучение с предобученной моделью VGG16 и уже достиг некоторых успехов, но хотел бы немного оптимизировать её. Вот схема модели
model_cropped = keras.Sequential([
layers.InputLayer(input_shape=(224, 224, 3)),
augmentation,
pre_model,
layers.Flatten(),
layers.Dense(256, activation='relu'),
layers.Dropout(0.2),
layers.Dense(128, activation='relu'),
layers.Dropout(0.2),
layers.Dense(64, activation='relu'),
layers.Dropout(0.2),
layers.Dense(1, activation='sigmoid')
])
optimizer = keras.optimizers.Nadam(learning_rate=1e-6, use_ema = True)
model_cropped.compile(
optimizer = optimizer,
loss=keras.losses.BinaryCrossentropy(),
metrics=[keras.BinaryCrossentropy()]
)
Я уже использовал несколько метрик и хотел попробовать метрику BinaryCrossentropy, так как, согласно документации, она подходит для задач бинарной классификации. Однако, хотя использование бинарной кросс-энтропии в качестве функции потерь вместе с другими метриками (такими как BinaryAccuracy) работает хорошо, использование бинарной кросс-энтропии в качестве метрики вызывает ошибку
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[201], line 4
1 epochs = 600
2 print("Fitting the end-to-end model")
----> 4 history_cropped = model_cropped.fit(
5 X_train, y_train,
6 epochs=epochs,
7 validation_data=(X_test, y_test),
8 batch_size=64
9 )
File ~/lib/python3.10/site-packages/keras/src/utils/traceback_utils.py:122, in filter_traceback.<locals>.error_handler(*args, **kwargs)
119 filtered_tb = _process_traceback_frames(e.__traceback__)
120 # Чтобы получить полный трассировочный журнал, вызовите:
121 # `keras.config.disable_traceback_filtering()`
--> 122 raise e.with_traceback(filtered_tb) from None
123 finally:
124 del filtered_tb
File ~/lib/python3.10/site-packages/keras/src/backend/tensorflow/nn.py:737, in binary_crossentropy(target, output, from_logits)
734 output = tf.convert_to_tensor(output)
736 if len(target.shape) != len(output.shape):
--> 737 raise ValueError(
738 "Arguments `target` and `output` must have the same rank "
739 "(ndim). Received: "
740 f"target.shape={target.shape}, output.shape={output.shape}"
741 )
742 for e1, e2 in zip(target.shape, output.shape):
743 if e1 is not None and e2 is not None and e1 != e2:
ValueError: Аргументы `target` и `output` должны иметь одинаковую ранг (ndim). Получено: target.shape=(None,), output.shape=(None, 1)
Очевидно, что ранг выходного узла равен (None, 1), но бинарная кросс-энтропия ожидает (None,). Можете кто-нибудь объяснить мне, что я не понимаю здесь или что я делаю не так? Я думал, что, поскольку бинарная кросс-энтропия работает как функция потерь, она также должна работать как метрика.
Большое спасибо
Как я упоминал в своем комментарии к оригинальному вопросу, проблема, кажется, заключается в том, что у вас несоответствие в размерах. Чтобы решить это, вы можете преобразовать ваши целевые метки (y_train
и y_test
) так, чтобы они имели форму (None, 1)
вместо (None,). Вы можете сделать это, добавив дополнительное измерение с помощью np.expand_dims
(или аналогичной функции в TF). Если вы предпочитаете не изменять свои целевые данные, вы можете адаптировать выходной слой, чтобы он выдавал форму (None,)
, сделав его одномерным.
Ответ или решение
Для реализации модели бинарной классификации с использованием библиотеки Keras и функции потерь BinaryCrossentropy существует несколько ключевых моментов, чтобы избежать ошибок и оптимизировать результат.
Проблема
Вы столкнулись с ошибкой, связанной с несовпадением размерностей в выходных данных вашей модели. Ваша модель генерирует выходные данные в форме (None, 1)
, в то время как метрика BinaryCrossentropy ожидает данные в форме (None,)
— т.е. одномерные массивы (вектор меток). Это несоответствие приводит к следующей ошибке:
ValueError: Arguments `target` and `output` must have the same rank (ndim). Received: target.shape=(None,), output.shape=(None, 1)
Решение
Для исправления этой токсичной несостыковки можно применить одно из предложенных ниже решений:
-
Изменение формы меток:
Используйтеnp.expand_dims()
для изменения формы ваших метокy_train
иy_test
на(None, 1)
. Пример кода для изменения формы меток:import numpy as np y_train = np.expand_dims(y_train, axis=-1) # теперь y_train имеет shape (N, 1) y_test = np.expand_dims(y_test, axis=-1) # теперь y_test имеет shape (M, 1)
-
Адаптация выходного слоя модели:
Это решение предполагает, что вы измените выходной слой вашей модели, чтобы он выдавал одномерный выход. Это можно сделать, изменив последний слой с:layers.Dense(1, activation='sigmoid')
на
layers.Dense(1, activation='sigmoid', use_bias=False)
или добавив
Flatten()
перед выходным слоем, чтобы результат стал одномерным.
Реализация модели
Ваш окончательный код для компиляции модели будет выглядеть следующим образом:
model_cropped.compile(
optimizer=optimizer,
loss=keras.losses.BinaryCrossentropy(),
metrics=[keras.metrics.BinaryAccuracy()] # Используйте более подходящую метрику для оценки
)
Замечания
-
Использование метрик: BinaryCrossentropy как метрика не является стандартной практикой. Она используется в первую очередь как функция потерь. Вместо этого рекомендуем использовать такие метрики, как
BinaryAccuracy
, чтобы оценить производительность модели. -
Настройки оптимизатора: Убедитесь, что рассматриваемая скорость обучения и настройки оптимизатора в большинстве случаев влияют на стабильность и качество обучения модели. Бывает полезно проводить поиск по гиперпараметрам, чтобы найти наилучшие значения.
-
Аугментация данных: Если данные недостаточно разнообразны, попробуйте использовать дополнительные методы аугментации изображений, чтобы избежать переобучения и улучшить обобщающую способность модели.
Следуя данным рекомендациям, вы сможете избежать ошибок и оптимизировать вашу модель для задачи бинарной классификации.