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

损失值低但模型预测失效?分子势能预测技术求助

训练损失低但测试预测失效:分子势能预测模型问题排查与改进方案

问题背景

在物理领域应用机器学习预测分子势能,该势能可表示为64×64的二维数组,已将其值缩放至0-1范围。目标是用Keras构建神经网络,输入为一维物理量数组,输出为上述分子势能。训练阶段模型表现看似良好(MAPE低于5%),但测试阶段(训练集与测试集输入分布一致)出现严重预测失效。

现象展示

  • 缩放后的势能样本:
    缩放后的分子势能样本
  • 测试集预测结果对比:左图为模型预测势能,中图为真实值,右图为局部MAPE分布
    测试集预测/真实/MAPE对比
  • 训练损失曲线:
    训练损失曲线

训练阶段得到的最低损失:

120/120 [==============================] - 3s 29ms/step - loss: 0.0534 - mape: 1.2858

现有尝试与代码

已尝试多种损失函数(MAE、1-SSIM等),并调整模型层结构,但均无改善。

自定义损失函数

def LOSS(y_true, y_pred):

    LOSS1 = K.abs(y_pred - y_true)
    LOSS1 = K.batch_flatten(LOSS1)
    LOSS1 = tf.reduce_mean(LOSS1, axis=-1)

    LOSS2 = 1 - tf.image.ssim(tf.reshape(y_true, [-1,  NyMax, NxMax, 1]),
                              tf.reshape(y_pred, [-1,  NyMax, NxMax, 1]), 1)

    return tf.math.add(3*LOSS1, 7*LOSS2)

模型结构

def create_model(in_dim,x_dim,y_dim):
    H,W = int(y_dim/2), int(x_dim/2)

    inputs = tf.keras.Input(shape=(in_dim,))  
    
    x = tf.keras.layers.Dense(64, activation='tanh')(inputs)
    x = tf.keras.layers.Dense(H*W, activation='tanh')(x)
    x = tf.keras.layers.Dropout(0.2)(x)

    x = tf.keras.layers.Reshape((H,W,1))(x)
    x = tf.keras.layers.Conv2DTranspose(4, kernel_size=(1,1), strides=(1,1), activation='selu', padding='same',
                                        kernel_regularizer=regularizers.L1(1e-4), bias_regularizer=regularizers.L1(1e-4))(x)
    x = tf.keras.layers.Dropout(0.2)(x)  
    x = tf.keras.layers.Conv2DTranspose(4, kernel_size=(4,4), strides=(2,2), activation='selu', padding='same',
                                        kernel_regularizer=regularizers.L1(1e-4), bias_regularizer=regularizers.L1(1e-4))(x)
    x = tf.keras.layers.Dropout(0.2)(x) 
    x = tf.keras.layers.Conv2D(1, kernel_size=(5,5), activation='relu', padding='same',
                               kernel_regularizer=regularizers.L1(1e-4), bias_regularizer=regularizers.L1(1e-4))(x)

    outputs = tf.keras.layers.Reshape((y_dim,x_dim))(x)

    model = tf.keras.Model(inputs=inputs, outputs=outputs) 
    return model

输入数据处理

poly = PolynomialFeatures(POLY_DEGREE) # POLY_DEGREE = 4
scaler = StandardScaler()
pca = PCA(PCA_COMPONENTS) # PCA_COMPONENTS = 64

X = poly.fit_transform(X)
X = scaler.fit_transform(X)
X = pca.fit_transform(X)

问题原因分析

  1. 输入预处理数据泄露:当前代码对整个数据集(含测试集)执行fit_transform,导致测试集信息提前融入预处理过程,训练时模型看似拟合良好,但测试时无法泛化到真实未知数据。这是最可能的核心原因。
  2. 损失函数与任务需求不匹配:自定义损失是3MAE +7(1-SSIM),MAE是全局平均误差,SSIM关注整体结构相似性,二者均对局部极值区域(分子势能的物理关键区域)的大误差不敏感。训练时的全局MAPE掩盖了局部的严重误差,导致模型未学到关键结构。
  3. 模型结构局限性:
    • 从一维输入先映射到32×32再上采样到64×64,中间的Dense层可能丢失输入与势能局部区域的关联,转置卷积的上采样难以恢复精细结构。
    • 过多的Dropout层(共3层)可能导致训练时模型无法充分学习关键特征,测试时因失活关闭出现性能骤降。
    • 最后一层使用ReLU激活,虽能保证输出非负,但无法约束输出在0-1范围内,可能导致局部预测值超出合理区间。
  4. 评估指标的误导:仅依赖全局MAPE评估,未关注局部关键区域的误差,无法及时发现模型在物理重要区域的失效。

改进方案

1. 修复输入预处理的数据泄露

将预处理步骤的fit仅在训练集上执行,用同一实例转换测试集,避免数据泄露:

# 先拆分训练集与测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 多项式特征转换
poly = PolynomialFeatures(POLY_DEGREE)
X_train_poly = poly.fit_transform(X_train)
X_test_poly = poly.transform(X_test)

# 标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train_poly)
X_test_scaled = scaler.transform(X_test_poly)

# PCA降维
pca = PCA(PCA_COMPONENTS)
X_train = pca.fit_transform(X_train_scaled)
X_test = pca.transform(X_test_scaled)

2. 优化损失函数,强化关键区域约束

针对分子势能的极值区域(物理关键区域)增加损失权重,同时用多尺度SSIM关注精细结构:

def LOSS(y_true, y_pred):
    # 对势能极值区域(>0.8或<0.2)赋予10倍权重
    weights = tf.where(tf.logical_or(y_true > 0.8, y_true < 0.2), 10.0, 1.0)
    weighted_mae = K.mean(weights * K.abs(y_pred - y_true), axis=[1,2])
    
    # 多尺度SSIM更关注不同层级的结构细节
    ssim_loss = 1 - tf.image.ssim_multiscale(tf.reshape(y_true, [-1, 64, 64, 1]),
                                             tf.reshape(y_pred, [-1, 64, 64, 1]), 1.0)
    
    # 调整权重比例,平衡局部误差与结构相似性
    return 0.4 * weighted_mae + 0.6 * ssim_loss

3. 调整模型结构

  • 减少Dropout层数量,降低失活率,避免过度抑制特征学习;
  • 最后一层改用Sigmoid激活,约束输出在0-1范围内;
  • 增加全连接层维度,直接输出全尺寸向量后用卷积层细化特征:
def create_model(in_dim,x_dim,y_dim):
    inputs = tf.keras.Input(shape=(in_dim,))  
    
    # 加深全连接层,用GELU激活提升表达能力
    x = tf.keras.layers.Dense(256, activation='gelu')(inputs)
    x = tf.keras.layers.Dense(512, activation='gelu')(x)
    # 直接输出全尺寸势能向量,用Sigmoid约束范围
    x = tf.keras.layers.Dense(x_dim*y_dim, activation='sigmoid')(x)
    x = tf.keras.layers.Reshape((y_dim,x_dim,1))(x)
    
    # 用卷积层细化特征,捕捉局部结构
    x = tf.keras.layers.Conv2D(8, kernel_size=(3,3), activation='gelu', padding='same')(x)
    x = tf.keras.layers.Conv2D(4, kernel_size=(3,3), activation='gelu', padding='same')(x)
    # 最终输出用Sigmoid确保在0-1区间
    outputs = tf.keras.layers.Conv2D(1, kernel_size=(3,3), activation='sigmoid', padding='same')(x)
    outputs = tf.keras.layers.Reshape((y_dim,x_dim))(outputs)
    
    model = tf.keras.Model(inputs=inputs, outputs=outputs) 
    return model

4. 完善评估指标

除全局MAPE外,增加以下评估指标:

  • 局部极值区域的MAPE(统计y_true>0.8或y_true<0.2区域的误差);
  • 峰值误差(PE):计算预测值与真实值的最大绝对误差;
  • SSIM得分:直接评估结构相似性。

内容的提问来源于stack exchange,提问作者Hoàng Trọng Đại Dương

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 22:40:24