Keras训练时自定义SIM metric值与离线计算不符求助
你遇到的训练时metric与离线计算结果差异巨大的问题,根源在于自定义SIM函数的两个关键维度处理错误,导致训练时的计算逻辑完全偏离了预期的样本级SIM定义:
1. 核心错误点
错误1:全局归一化而非样本级归一化
你的代码中K.sum(y_true)会对整个batch的所有元素求和,而非每个样本单独求和。这意味着所有样本的真实值和预测值被统一缩放至全局总和为1,完全违背了“每个样本单独归一化”的SIM计算逻辑。
比如,假设batch有32个样本,每个样本的真实值总和是1(比如one-hot向量),那么全局总和是32,每个样本的真实值元素会被除以32,导致归一化后的值被严重缩小。
错误2:全局求和而非样本级求和后取平均
K.sum(K.minimum(n_y_true, n_y_pred))没有指定求和轴,会对整个batch的所有元素的最小值求和,再对这个标量取均值(结果就是总和本身)。这导致训练时的metric输出是整个batch的全局交集总和,而非每个样本SIM值的平均值。
2. 训练与离线计算差异的原因
训练时,你的函数计算的是全局归一化后的batch级交集总和,这个值会随着batch大小变化,且由于全局缩放的影响,数值会明显偏高;而离线计算时,你大概率是对每个样本单独处理(比如遍历数据集计算单个样本的SIM再取平均),这时候每个样本是单独归一化的,得到的是符合预期的样本级SIM平均值,因此数值远低于训练时的结果。
3. 修复后的SIM实现
以下是修正后的代码,确保每个样本单独归一化,并计算样本级SIM的平均值:
import tensorflow.keras.backend as K def SIM(y_true, y_pred): # 对每个样本的最后一维(类别/特征维度)求和,keepdims保证广播时维度匹配 sum_y_true = K.sum(y_true, axis=-1, keepdims=True) sum_y_pred = K.sum(y_pred, axis=-1, keepdims=True) # 每个样本单独归一化到总和为1(添加epsilon避免除零) n_y_true = y_true / (sum_y_true + K.epsilon()) n_y_pred = y_pred / (sum_y_pred + K.epsilon()) # 计算每个样本的SIM值:对特征维度取min后求和 sample_sim = K.sum(K.minimum(n_y_true, n_y_pred), axis=-1) # 返回batch内所有样本SIM值的平均值 return K.mean(sample_sim)
4. 验证说明
修正后,训练时的metric会计算每个样本的SIM值再取平均,和你离线加载权重后逐个样本计算SIM再平均的结果完全一致。你之前的测试代码(张量与NumPy结果一致)应该是用单个样本测试的,此时K.sum(y_true)等价于样本级求和,所以逻辑暂时正确,但批量训练时就暴露了维度错误。
内容的提问来源于stack exchange,提问作者azteks

