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

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

