Функция потерь Хаверсина: Градиенты не предоставлены для любых переменных?

Вопрос или проблема

Я пытаюсь реализовать пользовательскую функцию потерь, потерю Хаверсина, которая вычисляет расстояние между двумя точками на сфере. Координаты классов сохраняются в 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:

  1. Получение предсказанных и истинных индексов классов:
    Вы используете tf.argmax для получения индекса класса с наивысшей вероятностью, и сразу потом преобразуете истинные классы в tf.int32.

  2. Извлечение координат классов:
    С помощью tf.gather получаете координаты из DataFrame на основе индексов. Примечание: здесь может быть проблема с тем, что tf.gather работает с тензорами, а не с NumPy массивами, которые возвращает DataFrame.

  3. Калькуляция расстояния Хаверсина:
    Использование функции haversine_distance для получения значений расстояний.

Причины проблемы

Наиболее вероятная причина проблемы с отсутствием градиентов заключается в использовании функций, которые не имеют градиентов. Рассмотрим несколько проблем:

  1. Использование Pandas DataFrame:
    Функция tf.gather ожидает тензоры TensorFlow, но если вы используете clusters_df['Center_Latitude'].values, он вернет NumPy массив, а это приведет к тому, что TensorFlow не сможет отслеживать эти операции для обратного распространения ошибки.

  2. Приведение типов и tf.cast:
    Ваша логика casting внутри haversine_distance может привести к проблемам, если в TensorFlow не удается отслеживать операции преобразования.

Рекомендации по исправлению

Чтобы исправить вашу функцию потерь и убедиться, что градиенты рассчитываются корректно, выполните следующие шаги:

  1. Преобразование данных в тензоры 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)
  2. Избегайте использования tf.print для отладки:
    Вместо tf.print используйте механизмы логирования или стандартный вывод для отладки, но помните, что они могут повлиять на градиенты. Если используете их, убедитесь, что они не нарушают граф вычислений TensorFlow.

  3. Проверьте использование функций и операций:
    Убедитесь, что все используемые вами функции поддерживают автоматическое дифференцирование, например, функции TensorFlow, а не обычные Python функции.

Заключение

С помощью вышеописанных изменений вы сможете устранить проблему с отсутствием градиентов в вашей функции потерь Хаверсина. Убедитесь, что вы всегда используете тензоры TensorFlow для выполнения операций с данными, что позволит TensorFlow корректно отслеживать все операции и обеспечит адекватное вычисление градиентов.

Оцените материал
Добавить комментарий

Капча загружается...