Вопрос или проблема
Я пытаюсь реализовать пользовательскую функцию потерь, потерю Хаверсина, которая вычисляет расстояние между двумя точками на сфере. Координаты классов сохраняются в csv-файле, поэтому мне нужно преобразовать истинный и предсказанный индексы в имена классов (‘cluster’), чтобы извлечь соответствующие координаты из csv. (Csv-файл содержит только кластер (целое число) и пару координат, Center_Longitude и Center_Latitude как float32). Я думаю, что извлечение координат, а также вычисление Хаверсина работают (смотрите вывод ниже). Но в итоге я не знаю, почему получаю эту ошибку: ValueError: No gradients provided for any variable.
Мой вывод – это слой softmax, поэтому я использую argmax, чтобы получить предсказание с наивысшей вероятностью. Я думаю, это может вызывать проблемы, но я все еще не уверен, как это решить. Почему я не получаю градиентов? Как я мог бы изменить свой код, чтобы он работал правильно?
def haversine_loss(y_true, y_pred):
pred_index = tf.argmax(y_pred, axis=-1)
true_index = tf.cast(y_true, tf.int32)
tf.print("Предсказанные индексы:", pred_index)
tf.print("Истинные индексы:", true_index)
pred_class_names = tf.gather(class_names, pred_index)
true_class_names = tf.gather(class_names, true_index)
tf.print("Предсказанные имена классов:", pred_class_names)
tf.print("Истинные имена классов:", true_class_names)
pred_lat_lon = tf.stack([
tf.gather(clusters_df['Center_Latitude'].values, pred_index),
tf.gather(clusters_df['Center_Longitude'].values, pred_index)
], axis=-1)
true_lat_lon = tf.stack([
tf.gather(clusters_df['Center_Latitude'].values, true_index),
tf.gather(clusters_df['Center_Longitude'].values, true_index)
], axis=-1)
tf.print("Предсказанные широта/долгота:", pred_lat_lon)
tf.print("Истинная широта/долгота:", true_lat_lon)
lat1, lon1 = pred_lat_lon[:, 0], pred_lat_lon[:, 1]
lat2, lon2 = true_lat_lon[:, 0], true_lat_lon[:, 1]
distance = haversine_distance(lat1, lon1, lat2, lon2)
tf.print("Вычисленные расстояния:", distance)
return tf.reduce_mean(distance)
def haversine_distance(lat1, lon1, lat2, lon2):
lat1 = tf.cast(lat1, tf.float32) * (tf.constant(m.pi, dtype=tf.float32) / 180.0)
lon1 = tf.cast(lon1, tf.float32) * (tf.constant(m.pi, dtype=tf.float32) / 180.0)
lat2 = tf.cast(lat2, tf.float32) * (tf.constant(m.pi, dtype=tf.float32) / 180.0)
lon2 = tf.cast(lon2, tf.float32) * (tf.constant(m.pi, dtype=tf.float32) / 180.0)
dlon = lon2 - lon1
dlat = lat2 - lat1
a = tf.sin(dlat / 2)**2 + tf.cos(lat1) * tf.cos(lat2) * tf.sin(dlon / 2)**2
c = 2 * tf.asin(tf.sqrt(a))
R = 6371.0
return R * c
Эпоха 1/25
Предсказанные индексы: [1124]
Истинные индексы: [604]
Предсказанные имена классов: ["8983"]
Истинные имена классов: ["8463"]
Предсказанная широта/долгота: [[51.227374672500062 7.2118920326250366]]
Истинная широта/долгота: [[49.075162783850026 9.48693443665003]]
Вычисленные расстояния: [289.012787]
Traceback (most recent call last):
File "mypath.py", line 171, in <module>
model.fit(
File "mypath.py\pythonProject\.venv\Lib\site-packages\keras\src\utils\traceback_utils.py", line 122, in error_handler
raise e.with_traceback(filtered_tb) from None
File "mypath.py\pythonProject\.venv\Lib\site-packages\keras\src\optimizers\base_optimizer.py", line 662, in _filter_empty_gradients
raise ValueError("No gradients provided for any variable.")
ValueError: No gradients provided for any variable.
Процесс завершён с кодом выхода 1
Ответ или решение
Введение в проблему
Ошибка ValueError: No gradients provided for any variable
возникает в вашем коде при работе с пользовательской функцией потерь, основанной на расстоянии Хаверсина. Эта ошибка возникает, когда TensorFlow не может вычислить градиенты для переменных модели. Основная причина этого может заключаться в том, что вы используете функции, не поддерживающие автоматическое дифференцирование.
В данной статье мы подробно рассмотрим, как работает ваша функция потерь, и предложим пути исправления проблемы.
Функция потерь Haversine
Вот основные стадии вашей функции haversine_loss
:
-
Получение предсказанных и истинных индексов классов:
Вы используетеtf.argmax
для получения индекса класса с наивысшей вероятностью, и сразу потом преобразуете истинные классы вtf.int32
. -
Извлечение координат классов:
С помощьюtf.gather
получаете координаты из DataFrame на основе индексов. Примечание: здесь может быть проблема с тем, чтоtf.gather
работает с тензорами, а не с NumPy массивами, которые возвращает DataFrame. -
Калькуляция расстояния Хаверсина:
Использование функцииhaversine_distance
для получения значений расстояний.
Причины проблемы
Наиболее вероятная причина проблемы с отсутствием градиентов заключается в использовании функций, которые не имеют градиентов. Рассмотрим несколько проблем:
-
Использование Pandas DataFrame:
Функцияtf.gather
ожидает тензоры TensorFlow, но если вы используетеclusters_df['Center_Latitude'].values
, он вернет NumPy массив, а это приведет к тому, что TensorFlow не сможет отслеживать эти операции для обратного распространения ошибки. -
Приведение типов и
tf.cast
:
Ваша логика casting внутриhaversine_distance
может привести к проблемам, если в TensorFlow не удается отслеживать операции преобразования.
Рекомендации по исправлению
Чтобы исправить вашу функцию потерь и убедиться, что градиенты рассчитываются корректно, выполните следующие шаги:
-
Преобразование данных в тензоры TensorFlow:
Замените доступ к данным из DataFrame на создание тензоров с помощью TensorFlow. Например:pred_lat_lon = tf.stack([ tf.gather(tf.convert_to_tensor(clusters_df['Center_Latitude'].values), pred_index), tf.gather(tf.convert_to_tensor(clusters_df['Center_Longitude'].values), pred_index) ], axis=-1) true_lat_lon = tf.stack([ tf.gather(tf.convert_to_tensor(clusters_df['Center_Latitude'].values), true_index), tf.gather(tf.convert_to_tensor(clusters_df['Center_Longitude'].values), true_index) ], axis=-1)
-
Избегайте использования
tf.print
для отладки:
Вместоtf.print
используйте механизмы логирования или стандартный вывод для отладки, но помните, что они могут повлиять на градиенты. Если используете их, убедитесь, что они не нарушают граф вычислений TensorFlow. -
Проверьте использование функций и операций:
Убедитесь, что все используемые вами функции поддерживают автоматическое дифференцирование, например, функции TensorFlow, а не обычные Python функции.
Заключение
С помощью вышеописанных изменений вы сможете устранить проблему с отсутствием градиентов в вашей функции потерь Хаверсина. Убедитесь, что вы всегда используете тензоры TensorFlow для выполнения операций с данными, что позволит TensorFlow корректно отслеживать все операции и обеспечит адекватное вычисление градиентов.