【问题标题】:GradientTape losing track of variableGradientTape 丢失变量的轨迹
【发布时间】:2019-07-26 19:01:38
【问题描述】:

我有一个执行类似 Gatys 的神经风格迁移的脚本。它使用样式损失和总变化损失。我正在使用 GradientTape() 来计算我的渐变。我实施的损失似乎工作正常,但我添加的一个新损失没有被 GradientTape() 正确解释。我正在使用启用了 Eager Execution 的 TensorFlow。

我怀疑这与我如何根据输入变量计算损失有关。输入是一个 4D 张量(batch, h, w, channels)。在最基本的层面上,输入是一个浮点图像,为了计算这个新的损失,我需要将它转换为一个二值图像来计算一个像素颜色与另一个像素颜色的比率。我不想在每次迭代期间都去改变图像,所以我只是制作张量的副本(以 numpy 形式)并对其进行操作以计算损失。我不明白 GradientTape 的局限性,但我相信输入变量在转换为 numpy 数组时如何用于获取损失的“线程丢失”。

我可以复制图像张量并使用它执行二值化操作和损失计算吗?还是我要求 tensorflow 做一些它不能做的事情?

我的新损失函数:

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() 操作导致梯度磁带无法跟踪计算梯度的变量。我这样做的最初原因是因为我的损失操作需要我在物理上更改张量的值,并且我不想实际更改用于正在优化的张量的值。因此,使用 numpy() 副本来处理以正确计算损失。有没有办法解决?还是因为必须对输入张量执行基本不可逆操作的限制,我是否应该认为我的损失计算无法实现?

【问题讨论】:

    标签: python-3.x tensorflow tensorflow2.0


    【解决方案1】:

    这里的第一个问题是 GradientTape 只跟踪对 tf.Tensor 对象的操作。当您调用 tensor.numpy() 时,在那里执行的操作落在磁带之外。

    第二个问题是,您的第一个示例从未在您想要区分的图像上调用 tape.watche。

    【讨论】:

    • 谢谢@Alexandre。如果我使用的是 Eager Execution 模式,我还需要使用“watch”吗?我的优化似乎在不使用它的情况下工作得很好(当然这个新的损失除外)。
    • 好的,你已经切入了我的问题的核心。对于这种特殊的损失,张量是一个图像(batch,H,W,C)。为了计算损失,我需要获取图像中像素的浮点值并将它们映射到最接近的值(例如 [0,0,0] 和 [255,255,255]),这样每个像素都是一个价值或其他。然后我计算比率,这就是返回的“体积分数”损失。我不想真正弄乱正在优化的原始图像,因此我只以 numpy 数组的形式复制一份。你可以制作张量副本吗?
    • TF 张量是不可变的,所以你不能乱用它,也不需要复制。但是,如果您坚持制作一个,则始终可以使用 tf.identity。但是,在我看来,您的损失是可微的(因为图像像素值的微小变化对输入没有任何影响)
    • 我明白了。这让我很困惑,因为为了评估体积分数损失,我需要拍摄代表生成图像的张量的快照,并对像素进行图像处理以调整它们,以便可以计算损失计算。输入图像的变化会影响损失,因为像素 A/像素 B 的体积分数会发生变化(或者至少我是这么认为的)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-13
    • 1970-01-01
    相关资源
    最近更新 更多