使用 tf.GradientTape 的自定义 GAN 训练循​​环返回 [None] 作为生成器的梯度,而它适用于鉴别器

时间:2021-07-25 13:37:54

标签: python tensorflow deep-learning generative-adversarial-network gradienttape

我正在尝试训练 GAN。不知何故,生成器的梯度返回 None ,即使它返回鉴别器的梯度。当优化器将梯度应用于权重时,这会导致 ValueError: No gradients provided for any variable: ['carrier_freq:0'].(在这种情况下只是一个权重,应该是一个单一的梯度)。我似乎找不到原因,因为计算应该几乎相同。

这是生成器梯度返回 [None] 的训练步骤的代码。

generator = make_generator()
discriminator = make_discriminator()

g_loss_fn = keras.losses.BinaryCrossentropy(from_logits=True)
g_optimizer = keras.optimizers.Adam(learning_rate=0.04)
d_loss_fn = keras.losses.BinaryCrossentropy(from_logits=True)
d_optimizer = keras.optimizers.Adam(learning_rate=0.03)

def train_step(train_set):
    # modulate or don't modulate sample
    for batch in train_set:
        # get a random DEMAND noise sample to mix with speech
        noise_indices = tf.random.uniform([batch_size], minval=0, maxval=len(demand_dataset), dtype=tf.int32)
        
        # labels of 0 representing legit samples
        legit_labels = tf.zeros(batch_size, dtype=tf.uint8)
        # labels of 1 representing adversarial samples
        adversarial_labels = tf.ones(batch_size, dtype=tf.uint8)
        # concat legit and adversarial labels
        concat_labels = tf.concat((legit_labels, adversarial_labels), axis=0)
        
        # calculate gradients
        with tf.GradientTape(persistent=True) as tape:
            legit_predictions = discriminator(legit_path(batch, noise_indices))
            adversarial_predictions = discriminator(adversarial_path(batch, noise_indices))
            # concat legit and adversarial predictions to match double batch of concat_labels
            d_predictions = tf.concat((legit_predictions, adversarial_predictions), axis=0)
            d_loss = d_loss_fn(concat_labels, d_predictions)
            g_loss = g_loss_fn(legit_labels, adversarial_predictions)
            print('Discriminator loss: ' + str(d_loss))
            print('Generator loss: ' + str(g_loss))
        d_grads = tape.gradient(d_loss, discriminator.trainable_weights)
        g_grads = tape.gradient(g_loss, generator.trainable_weights)
        print(g_grads)
        d_optimizer.apply_gradients(zip(d_grads, discriminator.trainable_weights))
        g_optimizer.apply_gradients(zip(g_grads, generator.trainable_weights))
        
        discriminator_loss(d_loss)
        generator_loss(g_loss)
    return d_loss, g_loss

这里有一些关于那里发生的事情的信息:
鉴别器的目标是区分合法样本和对抗样本。鉴别器接收双倍的批次。一旦批处理以合法数据的方式进行预处理,并再次以产生对抗性数据的方式进行预处理,即数据通过生成器并在那里进行修改。
生成器现在只有一个权重,由包裹在 lambda 层中的加法和乘法运算组成。
损失计算为标签和数据之间的 BinaryCrossentropy。鉴别器接收代表每个样本是否被修改的真实标签。生成器损失的计算方式类似,但它只考虑被修改的样本和代表合法样本的标签。所以它基本上衡量了有多少对抗样本被鉴别器分类为合法。

现在解决问题:
当它们返回一个值时,两种损失计算似乎都有效。梯度的计算也适用于鉴别器。但是生成器的梯度返回 [None]。它应该与鉴别器梯度的计算非常相似,因为不同之处在于损失计算仅使用用于鉴别器损失的数据子集。另一件事是,生成器只有一个权重,并且由执行乘法和加法的 lambda 层组成,而判别器是一个密集网络并且有多个权重。

有人知道问题的根源是什么吗?

1 个答案:

答案 0 :(得分:0)

我找到了问题和解决方案。无法从问题中提供的代码中解决问题,但我仍然想写下针对具有相同问题和背景情况的不太可能发生的事件的解决方案。

问题:生成器权重是 tf.keras.layers.Lambda() 层的一部分。 此类权重或变量将不会被跟踪以进行梯度计算。更多信息请访问:https://programming.vip/docs/day-6-tensorflow2-model-subclassing-api.html .
解决方案:编写自定义层,继承上面链接的基础层类。