Вопрос или проблема
Для создания пользовательской функции потерь, которая обращается к значениям в подмножестве (соответствующем граням сетки)
Мне нужно вычислить ошибку на основе значения в каждой вершине граней.
В переменной corr
у меня есть список граней для сетки (30k граней), где 3 целых значения представляют грань с соответствующими номерами вершин.
Что я сделал в функции пользовательских потерь:
def customLoss(y_true, y_pred):
global corr
rms2 = 0.
for i in range(len(corr)):
rms2 += (abs(y_true[corr[i][0]] - y_pred[corr[i][0]]) + abs(y_true[corr[i][1]] - y_pred[corr[i][1]]) + abs(y_true[corr[i][2]] - y_pred[corr[i][2]])) /3
print(i, rms2)
return rms2
Идея заключается в том, чтобы проверить для каждой грани, равны ли три значения относительно.
Проблема в том, что это занимает много времени для вычислений.
Есть ли способ ускорить процесс?
Например, я пытаюсь получить доступ к y_true
и y_pred
с помощью индексации numpy
corr = np.array(corr)
print(corr.shape) = (29984, 3)
Но если я пытаюсь получить доступ в функции customloss
y_true[corr]
это вызывает ошибку
ValueError: Shape must be rank 1 but is rank 3 for '{{node customLoss/strided_slice}} = StridedSlice[Index=DT_INT32, T=DT_FLOAT, begin_mask=0, ellipsis_mask=0, end_mask=0, new_axis_mask=0, shrink_axis_mask=1](IteratorGetNext:1, customLoss/strided_slice/stack_1, customLoss/strided_slice/stack_3, customLoss/strided_slice/stack_4)' with input shapes: [?,15003], [1,29984,3], [1,29984,3], [1].
Ответ или решение
Для реализации пользовательской функции потерь в Keras, которая учитывает соседние значения вершин, можно оптимизировать ваш код, чтобы уменьшить время вычисления. Основная идея заключается в том, чтобы использовать индексацию NumPy для извлечения нужных элементов вместо циклических операций. Далее представлен оптимизированный вариант вашей функции потерь.
Оптимизированная функция потерь
import numpy as np
import tensorflow as tf
# Предположим, что corr уже определен как numpy массив
# corr = np.array(...) # (29984, 3)
# На вход функции можно передавать corr
def customLoss(corr, y_true, y_pred):
# Извлекаем предсказанные и истинные значения вершин в один шаг
y_true_faces = tf.gather(y_true, corr)
y_pred_faces = tf.gather(y_pred, corr)
# Вычисляем среднюю абсолютную ошибку для координат вершин в одном шаге
# Используем tf.reduce_mean, чтобы избавиться от лишних операций
rms = tf.reduce_mean(tf.abs(y_true_faces - y_pred_faces), axis=1)
# Возвращаем среднее значение для всех граней
return tf.reduce_mean(rms)
# Пример использования:
# model.compile(loss=lambda y_true, y_pred: customLoss(corr, y_true, y_pred), optimizer='adam')
Объяснение оптимизаций
-
Использование
tf.gather
:
Вместо того, чтобы перебирать каждую грань в цикле, мы используемtf.gather
для извлечения всех необходимых значений одновременно. Это позволяет значительно сократить время выполнения, так как операции с тензорами в TensorFlow оптимизированы для работы с большими массивами. -
Уменьшение средних значений:
Мы предварительно вычисляем среднюю абсолютную ошибку для каждой грани с помощью функцииtf.reduce_mean
. После этого возвращаем среднее значение по всем граням, что является требуемым значением вашей функции потерь.
Как использовать функцию потерь
При компиляции вашей модели, вместо обычной функции потерь вы можете передать свою пользовательскую функцию, используя конструкцию lambda
для инкапсуляции corr
:
model.compile(loss=lambda y_true, y_pred: customLoss(corr, y_true, y_pred), optimizer='adam')
Заключение
Данная реализация не только решает вашу задачу по расчету ошибочной функции с учетом соседних вершин, но и значительно ускоряет вычисления. Использование возможностей TensorFlow и NumPy для работы с векторизованными операциями позволяет эффективно это реализовать.