You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TensorFlow使用pearsonr作损失时首轮epoch损失大于1的原因

DNN使用皮尔逊相关系数作为损失首轮训练值大于1的问题排查

自定义损失实现与离线校验

目标是在深度网络中使用皮尔逊相关系数作为损失函数,参照scipy.stats.pearsonr逻辑实现的自定义损失如下,离线测试时计算结果与scipy官方接口输出几乎完全一致,函数逻辑验证正确:

def correlationLoss2(x, y):
    x = tf.convert_to_tensor(x)
    y = math_ops.cast(y, x.dtype)
    xmean = tf.reduce_mean(x)
    ymean = tf.reduce_mean(y)
    xsqsum = tf.reduce_sum( tf.math.squared_difference(x, xmean))
    ysqsum = tf.reduce_sum( tf.math.squared_difference(y, ymean))
    cov = tf.reduce_sum( (x - xmean) * (y - ymean))
    corr = cov / tf.sqrt(xsqsum * ysqsum)
    return - corr

x = data[:, 22]
y = data[:, -1]

print(- float(correlationLoss(x, y)))
print(stats.pearsonr(x, y)[0])

校验输出(x、y为项目自有数据集):

-0.017431042527298025
-0.017431042527298084

训练异常表现

损失函数接入网络训练后,最终训练效果符合预期,但首轮epoch输出的损失值大于1,不符合皮尔逊相关系数对应损失的[-1, 1]取值范围,评估指标采用1-corr,首轮及后续训练日志如下:

Epoch 1/50
196/196 [==============================] - 35s 172ms/step - loss: 1.0501 - correlationMetric: 0.8766 - val_loss: -0.0295 - val_correlationMetric: 0.9123
Epoch 2/50
196/196 [==============================] - 11s 55ms/step - loss: -0.1150 - correlationMetric: 0.8465 - val_loss: -0.0598 - val_correlationMetric: 0.9115
Epoch 3/50
196/196 [==============================] - 11s 56ms/step - loss: -0.1299 - correlationMetric: 0.8352 - val_loss: -0.0674 - val_correlationMetric: 0.9061
Epoch 4/50
196/196 [==============================] - 10s 53ms/step - loss: -0.1383 - correlationMetric: 0.8270 - val_loss: -0.0734 - val_correlationMetric: 0.9013

使用的网络结构代码:

def get_model():
    features_inputs = tf.keras.Input((Config.input_size, ), dtype=tf.float32)

    gn = tf.keras.layers.GaussianNoise(0.035)(features_inputs)
    feature_x = layers.Dense(256, activation='swish')(gn)
    feature_x = layers.Dropout(0.5)(feature_x)

    feature_x = layers.Dense(512, activation='swish', kernel_regularizer="l2")(feature_x)
    feature_x = layers.Dropout(0.44)(feature_x)
    feature_x = layers.Dense(128, activation='swish', kernel_regularizer="l2")(feature_x)
    feature_x = layers.Dropout(0.33)(feature_x)
    feature_x = layers.Dense(32, activation='swish', kernel_regularizer="l2")(feature_x)
    feature_x = layers.Dropout(0.3)(feature_x)
    output = layers.Dense(1)(feature_x)

    model = tf.keras.Model(inputs=[features_inputs], outputs=[output])
    model.compile(optimizer=tf.optimizers.Adam(0.001), loss=correlationLoss2,
                  metrics=[correlationMetric])

    return model

首轮损失大于1的根本原因

  • Keras训练过程中打印的loss是自定义皮尔逊损失 + 所有层正则化惩罚项的总和,不是单纯的皮尔逊损失值。网络中3层Dense加了L2正则,首轮模型权重为随机初始化值,权重数值整体偏大,L2正则计算的是权重平方和乘以正则系数,这部分惩罚值很容易超过1,直接将总loss抬到1以上。后续训练过程中权重被优化缩小,L2惩罚值降低,总loss就回到了皮尔逊损失对应的[-1,1]区间。
  • 训练阶段启用的GaussianNoise、Dropout层仅在训练时生效,会给前向传播过程加入随机扰动,也会让单批次计算的皮尔逊损失和离线全量计算结果有小幅偏差,但这部分影响远小于L2正则的贡献。
  • 验证方式很简单:临时去掉所有Dense层的kernel_regularizer="l2"参数再跑训练,首轮loss就会落在皮尔逊损失的正常取值区间;也可以单独打印训练步的原始损失和正则项数值,能直接看到首轮超出1的部分全部来自L2正则惩罚。

内容的提问来源于stack exchange,提问作者Mengeshall Wu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 19:24:31