Tf 2.0:运行时错误:GradientTape.gradient只能在非持久性记录上调用一次。

25
tensorflow 2.0指南中的tf 2.0 DC Gan示例中,有两个梯度带。请参见以下内容。
@tf.function
def train_step(images):
    noise = tf.random.normal([BATCH_SIZE, noise_dim])

    with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
      generated_images = generator(noise, training=True)

      real_output = discriminator(images, training=True)
      fake_output = discriminator(generated_images, training=True)

      gen_loss = generator_loss(fake_output)
      disc_loss = discriminator_loss(real_output, fake_output)

    gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables)
    gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)

    generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables))
    discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))

正如您清楚地看到的,有两个渐变带。我想知道使用单个带有什么区别,并将其更改为以下内容

@tf.function
def train_step(images):
    noise = tf.random.normal([BATCH_SIZE, noise_dim])

    with tf.GradientTape() as tape:
      generated_images = generator(noise, training=True)

      real_output = discriminator(images, training=True)
      fake_output = discriminator(generated_images, training=True)

      gen_loss = generator_loss(fake_output)
      disc_loss = discriminator_loss(real_output, fake_output)

    gradients_of_generator = tape.gradient(gen_loss, generator.trainable_variables)
    gradients_of_discriminator = tape.gradient(disc_loss, discriminator.trainable_variables)

    generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables))
    discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))

这给我带来了以下错误:

RuntimeError: GradientTape.gradient can only be called once on non-persistent tapes.

我想知道为什么需要两个磁带。目前tf2.0 APIs的文档很少。有人能解释一下或者指导我正确的文档/教程吗?

2个回答

24

来自GradientTape文档

默认情况下,GradientTape持有的资源会在调用GradientTape.gradient()方法后立即释放。为了在同一计算中计算多个梯度,请创建一个持久的梯度磁带。这允许多次调用gradient()方法,因为当磁带对象被垃圾收集时,资源也会被释放。

可以使用with tf.GradientTape(persistent=True) as tape创建持久性梯度,应该使用del tape手动删除(感谢@zwep, @Crispy13)。


10
为了实际操作,你可以通过定义 tf.GradientTape(persistent=True) 来完成此操作。 - zwep
2
这应该被接受。顺便说一下,在使用 tape 后,执行 del tape - Crispy13

2
技术上的原因是gradient被调用了两次,在(非持久)记录中不允许这样做。
但在现实情况下,生成对抗网络的训练通常是通过交替优化生成器和鉴别器来完成的。每个优化都有自己的优化器,通常操作不同的变量,甚至最小化的损失也是不同的(在您的代码中为gen_lossdisc_loss)。
因此,你最终会得到两个梯度,因为训练GAN本质上是以交替方式优化两个不同(对抗性的)问题。"最初的回答"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接