不能将梯度组合用于多输出 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 个输出:
- atc代码(要预测的分子的代码)
- 等待下次访问的时间(按月份分类:>=4 为 0、1、2、3、4)
两个输出都使用 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
部分开始
你在ATCGrads
和WTGrads
中得到None
的原因是因为两个梯度对应的损失是wrt不同的输出outputATC
和outputWaitTime
,如果
输出值不用于计算损失然后将没有输出的梯度 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]
.
我正在使用 CNN 和 EHR 数据集在 Keras 中进行时间序列预测。目标是预测给患者什么分子以及下一次患者就诊的时间。我必须基于 this paper 实现双 objective 梯度下降。实现的算法在这里(第7页结束,第8页开始):
我选的是这一款:
以长度为3的时间序列为输入(对应客户连续3次访问) 和 2 个输出:
- atc代码(要预测的分子的代码)
- 等待下次访问的时间(按月份分类:>=4 为 0、1、2、3、4)
两个输出都使用 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
你在ATCGrads
和WTGrads
中得到None
的原因是因为两个梯度对应的损失是wrt不同的输出outputATC
和outputWaitTime
,如果
输出值不用于计算损失然后将没有输出的梯度 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]
.