У меня есть сценарий, который выполняет передачу нейронного стиля в стиле Гэтиса. Он использует потерю стиля и полную потерю вариации. Я использую GradientTape () для вычисления градиентов. Убытки, которые я реализовал, похоже, работают нормально, но новая потеря, которую я добавил, не учитывается должным образом с помощью GradientTape (). Я использую TensorFlow с включенным нетерпеливым исполнением.
Я подозреваю, что это как-то связано с тем, как я вычисляю потери на основе входной переменной. Входными данными является 4D тензор (пакет, h, w, каналы). На самом базовом уровне входными данными является изображение с плавающей запятой, и для вычисления этой новой потери мне нужно преобразовать его в двоичное изображение, чтобы вычислить отношение цвета одного пикселя к другому. Я не хочу на самом деле идти и менять изображение таким образом на каждой итерации, поэтому я просто делаю копию тензора (в форме numpy) и работаю с ним, чтобы вычислить потерю. Я не понимаю ограничений GradientTape, но я считаю, что это «теряет поток» того, как входная переменная используется для получения потерь при преобразовании в массив numpy.
Могу ли я сделать копию тензора изображения и с его помощью выполнить операции преобразования в двоичную форму и вычисление потерь? Или я прошу тензорный поток сделать что-то, чего он просто не может?
Моя новая функция потерь:
def compute_loss(self, **kwargs):
loss = 0
image = self.model.deprocess_image(kwargs['image'].numpy())
binarized_image = self.image_decoder.binarize_image(image)
volume_fraction = self.compute_volume_fraction(binarized_image)
loss = np.abs(self.volume_fraction_target - volume_fraction)
return loss
Моя реализация с использованием GradientTape:
def compute_grads_and_losses(self, style_transfer_state):
"""
Computes gradients with respect to input image
"""
with tf.GradientTape() as tape:
loss = self.loss_evaluator.compute_total_loss(style_transfer_state)
total_loss = loss['total_loss']
return tape.gradient(total_loss, style_transfer_state['image']), loss
Пример, который, как мне кажется, может проиллюстрировать мое замешательство. Самое странное, что у моего кода нет проблем с запуском; похоже, что это совсем не сводит к минимуму новый срок убытков. Но этот пример даже не запустится из-за ошибки атрибута: AttributeError: 'numpy.float64' object has no attribute '_id'
.
Пример:
import tensorflow.contrib.eager as tfe
import tensorflow as tf
def compute_square_of_value(x):
a = turn_to_numpy(x['x'])
return a**2
def turn_to_numpy(arg):
return arg.numpy() #just return arg to eliminate the error
tf.enable_eager_execution()
x = tfe.Variable(3.0, dtype=tf.float32)
data_dict = {'x': x}
with tf.GradientTape() as tape:
tape.watch(x)
y = compute_square_of_value(data_dict)
dy_dx = tape.gradient(y, x) # Will compute to 6.0
print(dy_dx)
Редактировать:
Исходя из моего текущего понимания, возникает проблема, заключающаяся в том, что мое использование операции .numpy () - это то, что заставляет Gradient Tape терять отслеживание переменной, по которой вычисляется градиент. Моя первоначальная причина для этого заключается в том, что моя операция потери требует, чтобы я физически изменил значения тензора, и я не хочу фактически изменять значения, используемые для оптимизируемого тензора. Следовательно, для правильного вычисления потерь используется копия numpy (). Есть ли способ обойти это? Или я считаю, что мой расчет потерь невозможно реализовать из-за этого ограничения, заключающегося в необходимости выполнять практически необратимые операции с входным тензором?