在 Keras 中实现对抗性损失
Implementation of Adversarial Loss In Keras
我正在尝试在 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)
并且在训练期间我交错 discriminator
和 autoencoder
的 train_on_batch
来更新 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)
但是,我发现这些变量的值在编译模型时被冻结了。我试图在训练期间重新编译模型,但这引发了错误
Node 'IsVariableInitialized_13644': Unknown input node
'training_12/Adam/Variable'
我猜这意味着我无法在训练期间重新编译?关于如何在自动编码器中注入鉴别器损失的任何建议?
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源代码,否则我认为你不能轻易做到这一点。在编写自己的对抗模块之前,您应该仔细检查现有作品。据我所知,keras-adversarial 仍然被很多人使用。当然,它只支持旧的keras版本,例如2.0.8。
其他几件事:
- 冻结模型权重时要小心。如果你先编译一个模型,然后冻结一些权重,这些权重仍然是可训练的,因为在编译过程中生成了train函数。所以你应该先冻结权重然后编译。
keras-adversarial
以更优雅的方式完成这项工作。它不是制作两个模型,共享权重而是以不同的方式冻结一些权重,而是创建两个训练函数,每个玩家一个。
我正在尝试在 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)
并且在训练期间我交错 discriminator
和 autoencoder
的 train_on_batch
来更新 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)
但是,我发现这些变量的值在编译模型时被冻结了。我试图在训练期间重新编译模型,但这引发了错误
Node 'IsVariableInitialized_13644': Unknown input node 'training_12/Adam/Variable'
我猜这意味着我无法在训练期间重新编译?关于如何在自动编码器中注入鉴别器损失的任何建议?
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源代码,否则我认为你不能轻易做到这一点。在编写自己的对抗模块之前,您应该仔细检查现有作品。据我所知,keras-adversarial 仍然被很多人使用。当然,它只支持旧的keras版本,例如2.0.8。
其他几件事:
- 冻结模型权重时要小心。如果你先编译一个模型,然后冻结一些权重,这些权重仍然是可训练的,因为在编译过程中生成了train函数。所以你应该先冻结权重然后编译。
keras-adversarial
以更优雅的方式完成这项工作。它不是制作两个模型,共享权重而是以不同的方式冻结一些权重,而是创建两个训练函数,每个玩家一个。