【问题标题】:Implementation of Adversarial Loss In Keras在 Keras 中实现对抗性损失
【发布时间】:2018-08-29 15:30:40
【问题描述】:

我正在尝试在 keras 中实现对抗性损失。 该模型由两个网络组成,一个自动编码器(目标模型)和一个鉴别器。这两个模型共享编码器。

我通过设置一个 keras 变量来创建自动编码器的对抗性损失

def get_adv_loss(d_loss):
    def loss(y_true, y_pred):
        return some_loss(y_true, y_pred) - d_loss
    return loss

discriminator_loss = K.variable()
L = get_adv_loss(discriminator_loss)
autoencoder.compile(..., loss=L)

在训练期间,我将train_on_batchdiscriminatorautoencoder 交错以更新discriminator_loss

d_loss = disciminator.train_on_batch(x, y_domain)
discriminator_loss.assign(d_loss)
a_loss, ... = self.segmenter.train_on_batch(x, y_target)

但是,我发现在编译模型时这些变量的值被冻结了。我试图在训练期间重新编译模型,但会引发错误

节点“IsVariableInitialized_13644”:未知输入节点 'training_12/Adam/变量'

我猜这意味着我不能在训练期间重新编译?关于如何在自动编码器中注入鉴别器损失的任何建议?

【问题讨论】:

    标签: python keras deep-learning generative-adversarial-network


    【解决方案1】:

    Keras 模型支持多个输出。因此,如果不应该训练判别器,只需将您的判别器包含到您的 keras 模型中并 freeze 判别器层。

    下一个问题是如何结合自动编码器损失和鉴别器损失。幸运的是 keras model.compile 支持损失权重。如果自动编码器是您的第一个输出,而鉴别器是您的第二个输出,您可以执行loss_weights=[1, -1] 之类的操作。所以更好的判别器对自动编码器来说更差。

    编辑:这是一个示例,如何实现对抗网络:

    # Build your architecture
    auto_encoder_input = Input((5,))
    auto_encoder_net = Dense(10)(auto_encoder_input)
    auto_encoder_output = Dense(5)(auto_encoder_net)
    
    discriminator_net = Dense(20)(auto_encoder_output)
    discriminator_output = Dense(5)(discriminator_net)
    
    # Define outputs of your model
    train_autoencoder_model = Model(auto_encoder_input, [auto_encoder_output, discriminator_output])
    train_discriminator_model = Model(auto_encoder_input, discriminator_output)
    
    # Compile the models (compile the first model and then change the trainable attribute for the second)
    for layer_index, layer in enumerate(train_autoencoder_model.layers):
        layer.trainable = layer_index < 3
    
    train_autoencoder_model.compile('Adam', loss=['mse', 'mse'], loss_weights=[1, -1])        
    
    for layer_index, layer in enumerate(train_discriminator_model.layers):
        layer.trainable = layer_index >= 3
    
    train_discriminator_model.compile('Adam', loss='mse')
    
    # A simple example how a training can look like
    for i in range(10):
        auto_input = np.random.sample((10,5))
        discrimi_output = np.random.sample((10,5))
        train_discriminator_model.fit(auto_input, discrimi_output, steps_per_epoch=5, epochs=1)
        train_autoencoder_model.fit(auto_input, [auto_input, discrimi_output], steps_per_epoch=1, epochs=1)  
    

    正如您所见,使用 keras 构建对抗模型并没有什么神奇之处。

    【讨论】:

    • 据我所知,当您有多个损失时,每个损失都会独立应用于每个输出。它与计算流回自动编码器的实际对抗性损失有什么不同吗?因为我希望自动编码器受到判别器丢失的影响,而不是判别器受到自动编码器的影响
    • 在我看来,这是一个更优雅的解决方案,更容易实现并且更喜欢 keras。此外,您的鉴别器从未冻结的自动编码器获取输出,因此自动编码器权重将通过 Loss_weights 因子进行更新。我不知道 keras 是先合并损失然后更新权重还是仅合并权重的更新。但结果应该是一样的。
    • 嗯,我完全同意,我想:它更优雅:-) 但我必须确保鉴别器不会收到自动编码器的损失。
    • 如果您正确冻结鉴别器的层,鉴别器将无法更新权重。在我过去的用例中,我使用了两个模型,它们在分层方面完全相同。但是在一个中我冻结了鉴别器,在另一个中我冻结了自动编码器。使用冻结层,特定部分无法学习任何东西。在训练判别器的情况下,模型不需要自动编码器的输出,所以你可以在这个模型中定义判别器输出。
    • 有效!编译和重新编译需要相当长的时间:-(
    【解决方案2】:

    除非你决定深入研究 keras 源代码,否则我认为你不能轻易做到这一点。在编写自己的对抗模块之前,您应该仔细检查现有作品。据我所知,keras-adversarial 仍然被很多人使用。当然,它只支持旧的 keras 版本,例如2.0.8。

    其他几件事:

    1. 冻结模型重量时要小心。如果你先编译一个模型,然后冻结一些权重,这些权重仍然是可训练的,因为在编译过程中会生成训练函数。所以你应该先冻结权重然后编译。
    2. keras-adversarial 以更优雅的方式完成这项工作。它没有创建两个模型,共享权重但以不同的方式冻结一些权重,而是创建了两个训练函数,每个玩家一个。

    【讨论】:

    • 确实在每次冻结/解冻后重新编译权重需要相当长的时间。我遇到了 keras-adversial,但我认为它不再开发。但我会看看他们是如何做到的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-08
    • 2018-05-21
    • 2017-08-20
    • 2019-04-05
    • 1970-01-01
    • 1970-01-01
    • 2020-01-27
    相关资源
    最近更新 更多