不能将梯度组合用于多输出 keras 模型的多个损失函数

Can't use combination of gradiants for multiple losses functions of a multi-output keras model

我正在使用 CNN 和 EHR 数据集在 Keras 中进行时间序列预测。目标是预测给患者什么分子以及下一次患者就诊的时间。我必须基于 this paper 实现双 objective 梯度下降。实现的算法在这里(第7页结束,第8页开始):

我选的是这一款:

以长度为3的时间序列为输入(对应客户连续3次访问) 和 2 个输出:

两个输出都使用 SparseCategoricalCorssentropy 损失函数。

当我开始执行第一个操作时:gs - gl我有这个错误:

我的渐变中的一些值是 None,我不知道为什么。我的优化器定义如下:optimizer=tf.Keras.optimizers.Adam(learning_rate=1e-3 编译我的模型时。

此外,当我尝试对梯度进行一些操作以查看其工作原理时,我遇到了另一个问题:只考虑了一个输入,这将在以后造成问题,因为我必须分别考虑每个损失函数:

使用此代码,我得到以下输出消息:WARNING:tensorflow:Gradients do not exist for variables ['outputWaitTime/kernel:0', 'outputWaitTime/bias:0'] when minimizing the loss.

EPOCHS = 1

for epoch in range(EPOCHS):
    with tf.GradientTape() as ATCTape, tf.GradientTape() as WTTape:
        predictions = model(xTrain,training=False)
        ATCLoss = loss(yTrain[:,:,0],predictions[ATC_CODE])
        WTLoss = loss(yTrain[:,:,1],predictions[WAIT_TIME])

    ATCGrads = ATCTape.gradient(ATCLoss, model.trainable_variables)
    WTGrads  = WTTape.gradient(WTLoss,model.trainable_variables)
    grads = ATCGrads + WTGrads

    model.optimizer.apply_gradients(zip(grads, model.trainable_variables))

有了这段代码就可以了,但是两个损失合并为一个,而我需要分别考虑两个损失

EPOCHS = 1

for epoch in range(EPOCHS):
    with tf.GradientTape() as tape:
        predictions = model(xTrain,training=False)
        ATCLoss = loss(yTrain[:,:,0],predictions[ATC_CODE])
        WTLoss = loss(yTrain[:,:,1],predictions[WAIT_TIME])
        lossValue = ATCLoss + WTLoss

    grads = tape.gradient(lossValue, model.trainable_variables)

    model.optimizer.apply_gradients(zip(grads, model.trainable_variables))

我需要帮助来理解为什么我有所有这些问题。

包含所有代码的笔记本在这里:https://colab.research.google.com/drive/1b6UorAAEddNKFQCxaK1Wsuj09U645KhU?usp=sharing

实施从 Model Creation

部分开始

你在ATCGradsWTGrads中得到None的原因是因为两个梯度对应的损失是wrt不同的输出outputATCoutputWaitTime,如果 输出值不用于计算损失然后将没有输出的梯度 wrt 因此你得到该输出层的 None 梯度。这也是你得到 WARNING:tensorflow:Gradients do not exist for variables ['outputWaitTime/kernel:0', 'outputWaitTime/bias:0'] when minimizing the loss 的原因,因为你没有每次损失的梯度。如果将损失合并为一个,则两个输出都用于计算损失,因此没有 WARNING.

所以如果你想做一个列表元素明智的减法,你可以在减法之前先将 None 转换为 0.,你不能使用 tf.math.subtract(gs, gl) 因为它需要所有输入的形状必须匹配,所以:

import tensorflow as tf

gs = [tf.constant([1., 2.]), tf.constant(3.), None]
gl = [tf.constant([3., 4.]), None, tf.constant(4.)]

to_zero = lambda i : 0. if i is None else i
gs = list(map(to_zero, gs))
gl = list(map(to_zero, gl))
sub = [s_i - l_i for s_i, l_i in zip(gs, gl)]
print(sub)

输出:

[<tf.Tensor: shape=(2,), dtype=float32, numpy=array([-2., -2.], dtype=float32)>, 
<tf.Tensor: shape=(), dtype=float32, numpy=3.0>, 
<tf.Tensor: shape=(), dtype=float32, numpy=-4.0>]

还要注意 tape.gradient() 将 return 张量列表或嵌套结构(或 IndexedSlices,或 None),源中的每个元素一个。返回的结构与sources的结构相同;在 python 中添加两个列表 [1, 2] + [3, 4] 不会像在 numpy 数组中那样给你 [4, 6],相反它会合并两个列表并给你 [1, 2, 3, 4].