Tf 2.0 : RuntimeError: GradientTape.gradient 只能在非持久性磁带上调用一次

Posted

技术标签:

【中文标题】Tf 2.0 : RuntimeError: GradientTape.gradient 只能在非持久性磁带上调用一次【英文标题】:Tf 2.0 : RuntimeError: GradientTape.gradient can only be called once on non-persistent tapes 【发布时间】:2019-09-28 01:40:41 【问题描述】:

在tensorflow 2.0 guide 的 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 API 的文档很少。任何人都可以解释或指出正确的文档/教程吗?

【问题讨论】:

【参考方案1】:

来自GradientTape的documentation:

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

可以使用with tf.GradientTape(persistent=True) as tape 创建持久渐变,并且可以/应该使用del tape 手动删除(此@zwep、@Crispy13 的功劳)。

【讨论】:

出于实用目的,您可以通过定义tf.GradientTape(persistent=True)来做到这一点 这应该被接受。对了,用tape后,做del tape【参考方案2】:

技术原因是gradient 被调用了两次,这在(非持久性)磁带上是不允许的。

然而,在目前的情况下,根本原因是 GANS 的训练通常是通过交替优化生成器和判别器来完成的。每个优化都有自己的优化器,通常对不同的变量进行操作,现在即使是最小化的损失也不同(代码中的gen_lossdisc_loss)。

所以你最终会得到两个梯度,因为训练 GAN 本质上是以交替的方式优化两个不同的(对抗性)问题。

【讨论】:

以上是关于Tf 2.0 : RuntimeError: GradientTape.gradient 只能在非持久性磁带上调用一次的主要内容,如果未能解决你的问题,请参考以下文章

RuntimeError: `set_session` 在使用 TensorFlow 2.0 时不可用

TF 2.0 打印张量值

如何在 Tensorflow-2.0 中绘制 tf.keras 模型?

建议在 tensorflow 2.0 中调试 `tf.data.Dataset` 操作

TensorFlow 2.0 语法变更

在TF 2.0中使用tf.keras,如何定义依赖于学习阶段的自定义层?