没有为任何变量提供梯度 - 自定义损失函数

No gradients provided for any variables -Custom loss function

我正在尝试使用自定义损失函数训练网络,但出现错误:

ValueError: No gradients provided for any variable: ['conv2d/kernel:0', 'conv2d/bias:0', 'conv2d_1/kernel:0', 'conv2d_1/bias:0', 'conv2d_2/kernel:0', 'conv2d_2/bias:0', 'conv2d_3/kernel:0', 'conv2d_3/bias:0', 'conv2d_4/kernel:0', 'conv2d_4/bias:0', 'dense/kernel:0', 'dense/bias:0', 'dense_1/kernel:0', 'dense_1/bias:0'].

自定义损失函数为:

def cosine_sim_cal(self, vec1, vec2):
    vec1 = tf.convert_to_tensor([vec1])
    vec2 = tf.convert_to_tensor([vec2])
    cosine_loss = tf.keras.metrics.CosineSimilarity(axis=1)
    cosine_loss.update_state(vec1,vec2)
    return cosine_loss.result()

def triplets_loss(self, y_pred, m):
    eps = tf.keras.backend.epsilon()
    loss = 0.0
    for i in range(len(y_pred)):
        d_a_p = self.cosine_sim_cal(y_pred[i, 0, :], y_pred[i, 1, :])
        d_a_n = self.cosine_sim_cal(y_pred[i, 0, :], y_pred[i, 2, :])
        loss += tf.math.maximum((d_a_p - d_a_n + m), eps)
    return loss 

y_pred的形状是TensorShape([180, 3, 128]),m是一个浮点数。损失函数正在计算看起来像 tf.Tensor(37.054775, shape=(), dtype=float32)

的损失

我的训练循环是:

 model = self.model
 train_loss_list = []
 validation_loss_list = []
 train_triplet_gen_instance = Triplet_Generator(x_data=self.train_class_dict, batch=self.batch)
 val_triplet_gen_instance = Triplet_Generator(x_data=self.val_class_dict, batch=self.batch)  

 for epoch in range(self.epochs):
    total_train_loss = 0.0
    total_val_loss = 0.0
        
    for step in range(self.training_steps):
        x_train_batch = train_triplet_gen_instance.generate_batch()       
        with tf.GradientTape() as tape:
             train_logits = model(x_train_batch, training=True)
             train_loss_value = self.triplets_loss(train_logits, m)
             total_train_loss += train_loss_value
        grads = tape.gradient(train_loss_value, model.trainable_weights)
        optimizer.apply_gradients(zip(grads, model.trainable_weights))
        if step%20==0:
            print('Epoch: {}, Step: {}, training_loss:{}'.format(epoch, step, str(total_train_loss/step)))
        mean_training_loss = tf.divide(total_train_loss, self.training_steps)
        train_loss_list.append(mean_training_loss.numpy())

x_train_batch 是一个长度为 3 的元组。这个元组的每个元素的形状都是 (180, 200, 200, 3)

我无法找出代码中的错误。如果我将我的损失函数更改为基于距离的损失函数,代码就可以工作。

我在自定义损失函数中发现了问题。似乎 tf.keras.metrics.CosineSimilarity(axis=1) 不可微,因为没有计算梯度。为此,我尝试将函数重写为:

def triplets_loss(self, y_pred, m):
    eps = tf.keras.backend.epsilon()
    d_a_p = tf.convert_to_tensor(list(map(lambda x, y: tf.tensordot(x,y, axes=1)/(tf.norm(x)*tf.norm(y)), y_pred[:,0,:], y_pred[:,1,:])))
    d_a_n = tf.convert_to_tensor(list(map(lambda x, y: tf.tensordot(x,y, axes=1)/(tf.norm(x)*tf.norm(y)), y_pred[:,0,:], y_pred[:,2,:])))
    loss = tf.reduce_sum(tf.math.maximum((d_a_p - d_a_n + m), eps))
    return loss 

有了新的损失函数,我可以继续训练了。