web-dev-qa-db-ja.com

Tf 2.0:RuntimeError:GradientTape.gradientは、非永続的なテープで1回だけ呼び出すことができます

Tf 2.0 DC Gan example in tensorflow 2.0 guide では、2つの勾配テープがあります。以下を参照してください。

@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))

2つのグラデーションテープがあることがはっきりとわかります。単一のテープメイクを使用してどのような違いがあるのだろうと思っていて、次のように変更しました

@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.

なぜ2本のテープが必要なのか知りたいのですが。現在のところ、tf2.0 APIに関するドキュメントは不十分です。誰かが私に正しいドキュメント/チュートリアルを説明したり教えたりできますか?

10
Himaprasoon

GradientTapeの-​​ documentation から:

デフォルトでは、GradientTape.gradient()メソッドが呼び出されるとすぐに、GradientTapeによって保持されているリソースが解放されます。同じ計算で複数の勾配を計算するには、永続的な勾配テープを作成します。これにより、tapeオブジェクトがガベージコレクションされるときにリソースが解放されるため、gradient()メソッドを複数回呼び出すことができます。

5
Sparky05

技術的な理由は、gradientが2回呼び出されるためです(これは(非永続的)テープでは許可されていません)。

ただし、現在のケースでは、根本的な理由は、一般的にGANSのトレーニングがジェネレーターとディスクリミネーターの最適化を交互に行うことによって行われることです。各最適化には独自のオプティマイザーがあり、通常はさまざまな変数で動作し、現在では最小化された損失でさえも異なります(gen_lossおよびdisc_loss(コード内)。

つまり、GANのトレーニングは基本的に2つの異なる(敵対的な)問題を交互に最適化しているため、2つの勾配になってしまいます。

0
P-Gn