首页 > 解决方案 > 我的印象是,当模型调用损失函数时,Y_TRUE 和 Y_PRED 的最后一个维度会被丢弃

问题描述

我正在使用 Keras 和 tensorflow 上的“yolo”方法构建用于对象分类和定位的深度学习模型。我对单个输入图像的输出是 52*52*10 矩阵。因此,当我运行 model.summary() 时,我得到以下输出维度:

...
...

leaky_103 (LeakyReLU)           (None, 52, 52, 128)  0           bnorm_103[0][0]                  
__________________________________________________________________________________________________
conv_104 (Conv2D)               (None, 52, 52, 256)  294912      leaky_103[0][0]                  
__________________________________________________________________________________________________
bnorm_104 (BatchNormalization)  (None, 52, 52, 256)  1024        conv_104[0][0]                   
__________________________________________________________________________________________________
leaky_104 (LeakyReLU)           (None, 52, 52, 256)  0           bnorm_104[0][0]                  
__________________________________________________________________________________________________
conv_105 (Conv2D)               (None, 52, 52, 10)   2570        leaky_104[0][0]                  
__________________________________________________________________________________________________
activation_2 (Activation)       (None, 52, 52, 10)   0           conv_105[0][0]                   
==================================================================================================
Total params: 55,642,218
Trainable params: 55,592,682
Non-trainable params: 49,536
______________________________________________________________

即输出为 [None, 52, 52, 10]

所以,因为我必须为我的输出创建一个自定义损失函数(因为我必须在切片上应用交叉熵并在[:,:,0:2]切片上应用另一个损失[:,:,2:6])。下面是损失函数的摘录

epsilon = 0.000001
def loss(y_true, y_pred):
    loss1 = K.mean(K.sum(K.categorical_crossentropy(y_true[:,:,:,0:2], y_pred[:,:,:,0:2]), 
                         axis = (1,2,3)), 
                   axis = 0)
    loss2 = K.mean(K.sum(-K.log(K.abs(tf.math.subtract(y_true[:,:,:,2:6],
                                                       y_pred[:,:,:,2:6])) 
                                + epsilon), 
                         axis = (1,2, 3)), 
                   axis = 0)
    return loss1+loss2

但是在运行时model.compile(),我收到以下错误:

ValueError: 3 维输入的无效缩减维数 3。对于 'loss_6/activation_2_loss/Sum_2' (op: 'Sum'),输入形状:[?,52,52], [3] 和计算的输入张量:input[1] = <1 2 3>。

我解释说,实际上,在调用损失函数时,损失是沿着最后一个维度逐层计算的,并减少了损失函数中的轴维度,“修改后的损失函数”是:

ε = 0.000001

def loss(y_true, y_pred):
    loss1 = K.mean(K.sum(K.categorical_crossentropy(y_true[:,:,:,0:2], y_pred[:,:,:,0:2]), 
                         axis = (1,2)), 
                   axis = 0)
    loss2 = K.mean(K.sum(-K.log(K.abs(tf.math.subtract(y_true[:,:,:,2:6],y_pred[:,:,:,2:6])) + epsilon), axis = (1,2)), axis = 0)
    return loss1+loss2

在此之后模型编译成功。谁能告诉我天气我对我的假设是对还是错。

标签: tensorflowkeras

解决方案


你是对的:categorical_crossentropy,将减少最后一个轴(维度 3)。您对 3 个班级有“一次”损失,而不是每个班级都有一次损失。

所以你输入(batch, 52, 52, 3)它会返回(batch, 52, 52)。因此,您sum只能在维度 1 和 2 上工作,没有维度 3。

你相应地更正了loss1


关于loss2,您忘记添加总和的维度。所以它将处于不同的数量级,因为在轴 0 中有一个,而在轴 0 中loss1有一个。meanloss2sum

你需要loss2像以前一样:

loss2 = K.mean(K.sum(-K.log(K.abs(tf.math.subtract(y_true[:,:,:,2:6],
                                                   y_pred[:,:,:,2:6])) 
                            + epsilon), 
                     axis = (1,2, 3)), 
               axis = 0)

我不是专门从事这项任务的,但也许你在那里仍然有不同的数量级,因为categorical_crossentropy在轴 3 上执行平均值,所以你loss2可能还需要这个平均值:

loss2 = K.mean(K.sum(-K.log(K.abs(y_true[:,:,:,2:6] - y_pred[:,:,:,2:6]) + epsilon),
                     axis=(1,2))) #let axis 3 to the mean. 

提示:mean在轴 0 上是可选的。Keras 稍后会为您完成。保持维度 0 不变的优点是以后可以使用样本权重。

提示2:tf.math.subtract(a, b)等于写作a-b


推荐阅读