我正在尝试使用以下两个损失函数来优化模型
def loss_1(pred, weights, logits):
weighted_sparse_ce = kls.SparseCategoricalCrossentropy(from_logits=True)
policy_loss = weighted_sparse_ce(pred, logits, sample_weight=advantages)
和
def loss_2(y_pred, y):
return kls.mean_squared_error(y_pred, y)
但是,因为TensorFlow 2期望损失函数的形式为
def fn(y_pred, y_true):
...
我正在为loss_1
使用一种变通办法,在将pred
和weights
打包成一个张量之前,在调用{{3}的过程中传递给loss_1
},然后将其解压缩到loss_1
中。这是不雅和令人讨厌的,因为pred
和weights
属于不同的数据类型,因此每次我呼叫model.fit
时,都需要进行附加的强制转换,打包,解压缩和取消转换。 / p>
此外,我知道sample_weight
的{{1}}参数,这有点像model.fit
的解决方案。如果不是因为我正在使用两个损失函数,而我只希望将fit
应用于其中一个函数,则这可能是一个可行的解决方案。而且,即使这是一个解决方案,也无法推广到其他类型的自定义损失函数。
简而言之,我的问题是:
创建任意数量的损失函数的最佳方法是什么 TensorFlow 2中的参数?
我尝试过的另一件事是传递this question,但这似乎也违反了TensorFlow对损失函数输入的期望。
答案 0 :(得分:2)
扩展乔恩的回答。如果您仍然想拥有 Keras 模型的好处,您可以扩展模型类并编写自己的自定义 train_step:
from tensorflow.python.keras.engine import data_adapter
# custom loss function that takes two outputs of the model
# as input parameters which would otherwise not be possible
def custom_loss(gt, x, y):
return tf.reduce_mean(x) + tf.reduce_mean(y)
class CustomModel(keras.Model):
def compile(self, optimizer, my_loss):
super().compile(optimizer)
self.my_loss = my_loss
def train_step(self, data):
data = data_adapter.expand_1d(data)
input_data, gt, sample_weight = data_adapter.unpack_x_y_sample_weight(data)
with tf.GradientTape() as tape:
y_pred = self(input_data, training=True)
loss_value = self.my_loss(gt, y_pred[0], y_pred[1])
grads = tape.gradient(loss_value, self.trainable_variables)
self.optimizer.apply_gradients(zip(grads, self.trainable_variables))
return {"loss_value": loss_value}
...
model = CustomModel(inputs=input_tensor0, outputs=[x, y])
model.compile(optimizer=tf.keras.optimizers.Adam(), my_loss=custom_loss)
答案 1 :(得分:1)
使用TF2中的custom training可以轻松解决此问题。您只需要在GradientTape
上下文中计算两分量损失函数,然后使用产生的梯度调用优化器即可。例如,您可以创建一个函数custom_loss
来计算给定每个参数的两个损耗:
def custom_loss(model, loss1_args, loss2_args):
# model: tf.model.Keras
# loss1_args: arguments to loss_1, as tuple.
# loss2_args: arguments to loss_2, as tuple.
with tf.GradientTape() as tape:
l1_value = loss_1(*loss1_args)
l2_value = loss_2(*loss2_args)
loss_value = [l1_value, l2_value]
return loss_value, tape.gradient(loss_value, model.trainable_variables)
# In training loop:
loss_values, grads = custom_loss(model, loss1_args, loss2_args)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
通过这种方式,每个损失函数都可以采用任意数量的渴望张量,无论它们是模型的输入还是输出。每个损失函数的参数集都不需要像本示例中所示那样相交。
答案 2 :(得分:0)
在tf 1.x中,我们具有tf.nn.weighted_cross_entropy_with_logits
函数,该函数可以通过为每个类添加额外的正权重来权衡查全率和查准率。在多标签分类中,它应该是(N,)张量或numpy数组。但是,在tf 2.0中,我还没有找到类似的损失函数,因此我编写了自己的损失函数,并带有额外的参数pos_w_arr
。
from tensorflow.keras.backend import epsilon
def pos_w_loss(pos_w_arr):
"""
Define positive weighted loss function
"""
def fn(y_true, y_pred):
_epsilon = tf.convert_to_tensor(epsilon(), dtype=y_pred.dtype.base_dtype)
_y_pred = tf.clip_by_value(y_pred, _epsilon, 1. - _epsilon)
cost = tf.multiply(tf.multiply(y_true, tf.math.log(
_y_pred)), pos_w_arr)+tf.multiply((1-y_true), tf.math.log(1-_y_pred))
return -tf.reduce_mean(cost)
return fn
不确定使用急切的张量或numpy数组作为输入时,这是什么意思。如果我错了,请纠正我。