【问题标题】:Keras custom loss function that uses hidden layer outputs as part of the objectiveKeras 自定义损失函数,使用隐藏层输出作为目标的一部分
【发布时间】:2019-01-27 04:53:44
【问题描述】:

我正在尝试在 Keras 中实现一个自动编码器,它不仅可以最大限度地减少重建误差,而且它的构造特征还应该最大化我定义的度量。我真的不知道如何做到这一点。

这是我目前所拥有的sn-p:

corrupt_data = self._corrupt(self.data, 0.1)

# define encoder-decoder network structure
# create input layer
input_layer = Input(shape=(corrupt_data.shape[1], ))
encoded = Dense(self.encoding_dim, activation = "relu")(input_layer)
decoded = Dense(self.data.shape[1], activation="sigmoid")(encoded)

# create autoencoder
dae = Model(input_layer, decoded)

# define custom multitask loss with wlm measure
def multitask_loss(y_true, y_pred):
    # extract learned features from hidden layer
    learned_fea = Model(input_layer, encoded).predict(self.data)
    # additional measure I want to optimize from an external function
    wlm_measure = wlm.measure(learned_fea, self.labels)
    cross_entropy = losses.binary_crossentropy(y_true, y_pred)
    return wlm_measure + cross_entropy

# create optimizer
dae.compile(optimizer=self.optimizer, loss=multitask_loss)

dae.fit(corrupt_data, self.data, 
                epochs=self.epochs, batch_size=20, shuffle=True, 
                callbacks=[tensorboard])

# separately create an encoder model
encoder = Model(input_layer, encoded)

目前这不能正常工作......当我查看训练历史时,模型似乎忽略了额外的措施,只根据交叉熵损失进行训练。此外,如果我将损失函数更改为仅考虑 wlm 度量,则会收到错误“numpy.float64”对象没有属性“get_shape”(我不知道将 wlm 函数的返回类型更改为张量是否会有所帮助)。

我认为有几个地方可能出错了。我不知道我是否在自定义损失函数中正确提取了隐藏层的输出。另外我不知道我的 wlm.measure 函数是否正确输出——它应该输出 numpy.float32 还是 float32 类型的一维张量。

基本上传统的损失函数只关心输出层的预测标签和真实标签。就我而言,我还需要考虑隐藏层的输出(激活),这在 Keras 中实现起来并不那么简单。

感谢您的帮助!

【问题讨论】:

标签: python tensorflow keras autoencoder


【解决方案1】:

您不想在自定义损失函数中定义 learned_fea Model。相反,您可以预先定义一个具有两个输出的单一模型:解码器的输出(重建)和 endoder 的输出(特征表示):

multi_output_model = Model(inputs=input_layer, outputs=[decoded, encoded])

现在您可以编写一个仅适用于编码器输出的自定义损失函数:

def custom_loss(y_true, y_pred):
    return wlm.measure(y_pred, y_true)

在编译模型时,您传递一个损失函数列表(或者如果您命名您的张量,则传递一个字典):

model.compile(loss=['binary_crossentropy', custom_loss], optimizer=...)

并通过传递输出列表来拟合模型:

model.fit(X=X, y=[data_to_be_reconstructed,labels_for_wlm_measure])

【讨论】:

  • 感谢您的回答!在那种情况下,模型是否拟合了两次,每次都有不同的损失?最终模型是共享相同的编码层还是训练了两个不同的编码层?这看起来像正在创建两个单独的模型,但我可能错了......此外,如果两个目标共享编码层,我如何指定我想要支持的目标?假设我更关心优化 wlm_measure 而不是优化重构误差,我该怎么做?
  • 不,只创建一个模型并针对您提供的损失函数列表的平均值进行优化。所以只有一个“共享”编码层。如果你想强调一个损失函数而不是另一个,model.compile() 有一个参数 loss_weights 可以让你做到这一点。详情请查看the docs
  • 我觉得这很有意义!那么现在当我调用预测时,我的模型会产生两个输出吗?一个输出是重构的特征(输出层的输出),另一个输出是学习到的特征(编码器层的输出)?
  • 是的,model.predict() 将返回一个预测列表,正如您提到的那样。
  • 太棒了!这解决了问题,非常感谢!最后一个问题:如果我要制作一个多输出模型,那么我需要将 wlm_measure 作为一个单独的损失。 wlm_measure 需要所有样本的学习特征(维度是编码维度)和标签数组(维度是原始数据集的维度,即样本数)来计算它。这与 y_true, y_pred 格式并不真正匹配。换句话说,我需要访问所有样本的学习特征才能计算损失。有没有办法做到这一点?
猜你喜欢
  • 2019-01-01
  • 2017-05-30
  • 2019-01-11
  • 2018-06-28
  • 2018-07-22
  • 1970-01-01
  • 1970-01-01
  • 2020-11-14
  • 1970-01-01
相关资源
最近更新 更多