【问题标题】:Training discriminator and generator at the same time(Tensorflow)同时训练判别器和生成器(Tensorflow)
【发布时间】:2019-05-10 16:54:31
【问题描述】:

通常在使用 TensorFlow 的 GAN 代码中,我们有以下形式:

 _, D_loss_curr, _ = sess.run(
            [D_solver, D_loss, clip_D],
            feed_dict={X: X_mb, z: sample_z(mb_size, z_dim)}
        )

 _, G_loss_curr = sess.run(
        [G_solver, G_loss],
        feed_dict={z: sample_z(mb_size, z_dim)}
    )

这可以看作是先训练判别器(D),然后训练生成器(G)。但是,如果我们执行以下操作会怎样:

 _, D_loss_curr, _ ,_, G_loss_curr= sess.run(
                [D_solver, D_loss, clip_D,G_solver, G_loss],
                feed_dict={X: X_mb, z: sample_z(mb_size, z_dim)}
            )

现在是否意味着 D 和 G 正在并行训练?还是和以前相比,G 现在已经“过时”了 D?

【问题讨论】:

    标签: tensorflow machine-learning neural-network generative-adversarial-network


    【解决方案1】:

    将列表[D_solver, D_loss, clip_D, G_solver, G_loss] 传递给函数sess.run() 时,鉴别器D 和生成器G 不会并行训练。该列表的所有操作都将被执行,但函数Session.run() 不能保证这些操作的任何执行顺序。可能会发生 G 在 D 之前执行,反之亦然。

    Session.run() 的这种行为在前几期 tensorflow 中讨论过:#13133#10860

    编辑:为改写的问题添加答案

    如果您调用sess.run 两次,如您的示例所示,您将首先训练判别器 D,然后训练生成器 G。 如果您只调用一次sess.run,并且列表fetches 中对D 和G 的所有操作,该列表中的所有操作都将按某种顺序执行。但不能保证它将是哪个顺序。在每次调用时,可以先训练 D,然后训练 G,或者可以先训练 G,然后训练 D。 函数Session.run() 遵循执行顺序,不会并行运行操作,即图操作不会同时执行。此执行顺序不一定是您在fetches=[D_solver, D_loss, clip_D, G_solver, G_loss] 中传递的顺序。

    例如,考虑第二种情况,我们在一次调用sess.run() 中传递所有操作。在您的第一次训练迭代中,可能会首先执行G_loss,然后执行G_solver,然后执行D_solver,等等。在第二次迭代中,我们实际上可能会首先执行D_loss,然后D_solver,然后是G_solver,等等

    sess.run 在每次迭代中执行的执行顺序示例(没有clip_D): 迭代 1:G_loss、G_solver、D_solver、D_loss
    迭代 2:D_loss、D_solver、G_solver、G_loss
    迭代 3:G_solver、G_loss、D_loss、D_solver
    迭代4:G_solver、G_loss、D_loss、D_solver ...

    使用这种方法,您的训练将不会有规律可循。例如,在第一次迭代中,我们在训练 D 之前训练 G。在第二次迭代中,我们在 G 中没有任何最近更新的情况下训练 D,即,在第 1 次和第 2 次迭代中对 D 的训练之间没有训练 G。

    另一方面,在考虑顺序训练 D 和 G 的第一个场景时,我们保证在每次训练迭代中,在 G 之前训练 D,并且在训练 G 之前计算 D 的指标, G 的指标是在 D 的训练之后计算出来的。

    【讨论】:

    • 或许更好的措辞问题:如果我调用 sess.run 两次,一次更新 D(D_solver, D_loss),一次更新 G(G_solver, G_loss),这与调用 sess 有何不同. 使用 D 和 G 在相同条件下运行一次(D_solver、D_loss、G_solver、G_loss)。我的理解是,调用 sess.run 两次将导致 D 和 G 的顺序执行,并且仅使用所有参数调用它一次将导致 D 和 G 的同时执行(即 D 的权重将与 G 的同时更新,而在顺序中,D 的权重将首先更新,G 的随后更新)。
    • 我编辑了改写问题的答案。希望对您有所帮助。
    • 谢谢@K。波格丹。我仍然有点困惑,这就是我想要做的。我想计算 D 和 G 的损失,然后同时反向传播两者的梯度。也就是说,我不希望 G 在计算损失时使用更新后的 D。在计算 D 和 G 的损失后,我可以通过依次放置 D_loss.backward()、D_solver.step()、G_loss.backward()、G_solver.step() 在 pytorch 中轻松做到这一点。这就是为什么我认为我可以做到就像我提到的那样,在 TF 中。任何帮助将不胜感激。
    • 我认为您可以查看Distributed Tensorflow。但是,为什么需要同时反向传播 G 和 D 的梯度呢?
    • @k-bogdan 这与我正在进行的一个项目有关,主要是为了确保 D 和 G 的训练方式确保 G 的梯度不基于更新的 D,或者换句话说,D 在计算 G 的损失之前没有得到更新的梯度。只是想知道,用 tf.group() 将损失函数分组是否有效?
    猜你喜欢
    • 1970-01-01
    • 2018-07-23
    • 2022-01-22
    • 2018-06-06
    • 1970-01-01
    • 2020-06-26
    • 1970-01-01
    • 2020-08-11
    • 2020-10-04
    相关资源
    最近更新 更多