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

归一化目标值后神经网络始终输出相同预测值的问题排查

问题分析与解决方案

你的核心问题是目标变量归一化后模型输出固定值,主要由两个关键原因导致:数据泄露和目标分布极端不平衡,以下是具体分析和修复步骤:

1. 致命错误:归一化过程存在数据泄露

你当前的代码先对整个数据集的目标值做归一化,再拆分训练/测试集,这会导致测试集的归一化用到了训练集以外的信息(包括极端值),属于严重的数据泄露,直接破坏模型泛化能力。

修复代码:

把归一化步骤放到训练测试拆分之后,仅用训练集拟合scaler:

def create_and_train_model_opti2(dff, target_column):
    df = dff.copy()
    
    y = df[target_column].values.reshape(-1, 1)
    X = df.drop([target_column], axis=1)
    
    # 归一化特征
    scaler_X = MinMaxScaler(feature_range=(0, 1))
    X_scaled = scaler_X.fit_transform(X)
    
    # 先拆分训练测试集
    X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)
    
    # 仅用训练集的目标值拟合scaler_y
    scaler_y = MinMaxScaler(feature_range=(0, 1))
    y_train_scaled = scaler_y.fit_transform(y_train)
    y_test_scaled = scaler_y.transform(y_test)
    
    # 模型构建不变
    model = Sequential([
        Dense(128, activation='relu', input_shape=(X_train.shape[1],), kernel_regularizer=l2(0.001)),
        Dropout(0.2),
        Dense(128, activation='relu', kernel_regularizer=l2(0.001)),
        Dropout(0.2),
        Dense(1)
    ])
    model.compile(optimizer=Adam(learning_rate=0.001), loss='mean_squared_error')
    
    # 用归一化后的训练目标训练
    history = model.fit(X_train, y_train_scaled, epochs=60, batch_size=64, validation_split=0.2)
    
    return model, history, y_train_scaled, y_test_scaled, X_train, X_test, scaler_y

2. 目标分布极端不平衡

从你的预测输出看,目标值存在极大离群点(比如2579.44),同时大量样本是0,MinMaxScaler会把这个极端值映射到1,其余绝大多数样本映射到接近0的区间。模型为了最小化MSE,会倾向于输出所有样本的平均归一化值,反归一化后就变成固定的353.5。

解决方法:

  • 改用鲁棒归一化器:用RobustScaler替代MinMaxScaler,它基于中位数和四分位数,对离群点的鲁棒性更强:
    from sklearn.preprocessing import RobustScaler
    scaler_y = RobustScaler()
    
  • 处理极端值:统计目标列的分位数,截断或删除极端值(比如保留99分位数以内的数据):
    q99 = df[target_column].quantile(0.99)
    df = df[df[target_column] <= q99]
    
  • 对数变换:对目标值做对数变换缩小极端值影响,再归一化:
    y = np.log1p(df[target_column].values.reshape(-1, 1))  # log1p避免0值问题
    
  • 加权损失函数:给少数大目标样本赋予更高权重,强迫模型关注这些样本:
    # 计算权重:用目标值的相对大小作为权重
    weights = y_train.flatten() / y_train.flatten().max()
    history = model.fit(X_train, y_train_scaled, sample_weight=weights, epochs=60, batch_size=64, validation_split=0.2)
    

3. 调整训练策略

  • 增加训练轮数+早停:当前60轮可能不足以让模型学到有效特征,增加到100-200轮,同时加入早停防止过拟合:
    from tensorflow.keras.callbacks import EarlyStopping
    early_stop = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True)
    history = model.fit(X_train, y_train_scaled, epochs=200, batch_size=64, validation_split=0.2, callbacks=[early_stop])
    
  • 调整学习率:归一化后目标值范围缩小,可尝试降低学习率到0.0001,或用学习率调度器动态调整:
    from tensorflow.keras.callbacks import ReduceLROnPlateau
    lr_scheduler = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=5)
    history = model.fit(X_train, y_train_scaled, epochs=200, batch_size=64, validation_split=0.2, callbacks=[early_stop, lr_scheduler])
    

内容的提问来源于stack exchange,提问作者William Dekeyser

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 23:49:52