Вопрос или проблема
У меня есть модель, и я реализовал пользовательскую функцию потерь что-то вроде:
def custom_loss(labels, predictions):
global diff
# фактический код использует декоратор, поэтому глобальных переменных нет
diff = labels - predictions
return tf.square(diff)
model.compile(loss=custom_loss, optimizer=opt.RMSprop())
...
model.train_on_batch(input, labels)
#
Как получить diff после того, как я запустил train_on_batch, не вызывая повторного выполнения predict за кулисами (ненужное замедление) и не испортив trainable/batchnorm и т.д. (возможные проблемы)?
Я хочу избежать создания ручного цикла train_op в чистом tensorflow и т.д., отслеживая фазу обучения и прочее. Это мой единственный выбор?
Я использую модуль keras версии tensorflow 1.14
Я решил эту проблему (открыл управление зависимостями и запомнил переменные). В основном, я создаю операцию присваивания diff переменной и с помощью control_dependencies forcing tf выполнять эту операцию каждый раз, когда вычисляется op, таким образом, когда я получаю эту переменную, она не вызывает перерасчет графа.
diff_var = tf.Variable()
def custom_loss(labels, predictions):
diff = labels - predictions
diff_var_op = diff_var.assign(diff)
with tf.control_dependencies([diff_var_op]):
return tf.square(diff)
тестовый код
import tensorflow as tf
sess = tf.Session()
var1 = tf.Variable(1, dtype=tf.float32)
var2 = tf.Variable(2, dtype=tf.float32)
counter = tf.Variable(1, dtype=tf.float32)
var2_op = tf.square(var2)*counter
diff_var = tf.Variable(10, dtype=tf.float32, trainable=False)
diff = var2_op - var1
diff_var_op = diff_var.assign(diff)
with tf.control_dependencies([diff_var_op]):
op = tf.square(diff)
sess.run(tf.global_variables_initializer())
print('diff var:', sess.run(diff_var)) #10
print('counter:', sess.run(counter)) #1
print('op:', sess.run(op)) #9
print('diff var:', sess.run(diff_var)) #3
print('-')
counter_op = tf.assign_add(counter, 1)
print('counter:', sess.run(counter)) #1
print('diff var:', sess.run(diff_var)) #3 # все еще то же самое
print('var2:', sess.run(var2_op)) #4
print('-')
sess.run(counter_op)
print('после counter_op')
print('counter:', sess.run(counter)) #2
print('var2:', sess.run(var2_op)) #8
# все еще то же самое, хотя var2 изменился из-за counter_op
print('diff var:', sess.run(diff_var)) #3
print('op:', sess.run(op)) #49 # выполняем полный op
print('-')
print('после op')
print('diff var:', sess.run(diff_var)) #7
# переменная изменилась, никаких операций не было
Ответ или решение
Чтобы получить значение тензора diff
в функции потерь при использовании train_on_batch
в Keras, при этом избегая повторного вычисления, можно воспользоваться механизмами управления зависимостями TensorFlow и переменными для хранения промежуточных значений.
Подход к реализации
При создании пользовательской функции потерь, которая требует доступ к промежуточным вычислениям, стоит учитывать, что невнимательное обращение с графом вычислений может привести к повторным вычислениям, что ухудшит производительность. Использование глобальных переменных не рекомендуется, так как это может привести к нежелательной сложности, особенно при работе с многопоточным выполнением кода.
Одним из эффективных способов решения данной задачи является использование переменных для хранения результатов и контроля их обновления с помощью зависимостей TensorFlow.
Шаги реализации
-
Создание переменной для хранения
diff
: Определите переменную TensorFlow, которая будет хранить значениеdiff
, используяtrainable=False
, чтобы избежать его обучения. -
Использование
assign
для обновления переменной: В функции потерь создайте операцию, которая будет обновлять значениеdiff
и поместите её в блокеcontrol_dependencies
. Это гарантирует, что при вычислении потерь значениеdiff
обновится без повторного вызоваpredictions
. -
Возврат значения потерь: Возвратите квадрат разности (или любое другое значение по вашему выбору) после обновления переменной.
Пример реализации
Вот пример, как можно эффективно реализовать вашу функцию потерь:
import tensorflow as tf
# Создаем переменную вне функции потерь для хранения разности
diff_var = tf.Variable(0, dtype=tf.float32, trainable=False)
# Определяем пользовательскую функцию потерь
def custom_loss(labels, predictions):
# Вычисляем разность
diff = labels - predictions
# Обновляем переменную с помощью assign, не забывая указать зависимости
diff_var_op = diff_var.assign(diff)
with tf.control_dependencies([diff_var_op]):
# Возвращаем квадрат разности в качестве потерь
return tf.square(diff)
# Компиляция модели с пользовательской функцией потерь
model.compile(loss=custom_loss, optimizer=tf.keras.optimizers.RMSprop())
# Обучение модели на пакетах данных
model.train_on_batch(input, labels)
# Теперь diff_var будет содержать последнее значение разности
current_diff = diff_var.numpy() # Получаем значение разности
print("Текущая разность:", current_diff)
Вывод
Данный подход позволяет избежать множественного вычисления predictions
, что приводит к увеличению производительности и снижению нагрузки на граф вычислений. Использование управления зависимостями и переменных – это чистое и эффективное решение, которое не требует вручную отслеживать состояние графа или превращаться в сложные циклы обучения. Таким образом, можно сохранить простоту и чистоту кода, придерживаясь стандартных практик Keras и TensorFlow.
Этот метод обеспечивает надежность и удобство, что особенно важно при построении комплексных моделей в области глубокого обучения, где производительность и управление ресурсами играют ключевую роль.