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

在Keras中基于model.predict结果优化电力需求预测RNN权重的咨询

基于自定义计数类指标优化Keras RNN多分位数回归模型权重

我最近在做电力需求的概率性预测项目,用Keras搭建了RNN模型,思路是先通过多分位数回归训练模型——让模型输出99个分位数结果,以此来覆盖预测值的概率分布范围。

训练完成后,我需要用一个自定义的计数类指标来评估模型效果,这个指标的计算逻辑大概是这样的:

def qcs(expected, observed):
    return ((observed - expected)**2 / expected)  # 完整逻辑这里只写了核心部分

但问题来了:这个qcs指标没办法直接用到模型的初始训练阶段(可能是因为它的计算依赖于预测后的期望值推导,或者不符合Keras训练时损失函数的可微分/凸性要求),现在我想基于这个指标来优化模型的权重,该怎么实现?

可行的解决方案思路

针对这个场景,我整理了两种实用的实现路径,你可以根据自己的需求选择:


1. 预训练+自定义训练循环微调

先通过标准的分位数损失完成模型预训练,得到一个具备基础多分位数预测能力的模型,然后用Keras的自定义训练循环,把qcs转化为可优化的损失目标来微调权重。这种方式的好处是不会破坏预训练模型的分位数预测能力,同时针对性优化qcs指标。

示例代码框架:

import tensorflow as tf
from tensorflow.keras import layers, models

# 第一步:搭建并预训练多分位数回归RNN模型
def build_rnn_quantile_model(timesteps, features, num_quantiles=99):
    inputs = layers.Input(shape=(timesteps, features))
    # 这里可以根据你的需求调整RNN结构,比如加Dropout、调整单元数
    x = layers.LSTM(64, return_sequences=True)(inputs)
    x = layers.Dropout(0.2)(x)
    x = layers.LSTM(32)(x)
    outputs = layers.Dense(num_quantiles)(x)  # 输出99个分位数
    model = models.Model(inputs, outputs)
    
    # 定义分位数损失函数
    def quantile_loss(q, y_true, y_pred):
        err = y_true - y_pred
        return tf.maximum(q * err, (q - 1) * err)
    
    # 组合所有分位数的损失(取均值)
    def combined_quantile_loss(y_true, y_pred):
        quantiles = tf.linspace(0.01, 0.99, num_quantiles)
        losses = [quantile_loss(q, y_true, y_pred[:, i]) for i, q in enumerate(quantiles)]
        return tf.reduce_mean(tf.stack(losses, axis=1))
    
    model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3), 
                  loss=combined_quantile_loss)
    return model

# 假设你已经准备好训练数据x_train, y_train(格式符合RNN输入要求)
model = build_rnn_quantile_model(timesteps=24, features=5)
model.fit(x_train, y_train, epochs=20, batch_size=32, validation_split=0.1)

# 第二步:自定义训练循环,基于qcs指标微调
def qcs_loss(expected, observed):
    # 解决数值稳定性问题:给expected加一个极小值避免除以0
    epsilon = 1e-6
    # 这里的expected需要从模型输出的99个分位数计算,比如取所有分位数的均值
    return tf.reduce_mean((observed - expected)**2 / (expected + epsilon))

# 定义微调用的优化器(用小学习率,避免破坏预训练效果)
fine_tune_optimizer = tf.keras.optimizers.Adam(learning_rate=1e-5)

# 自定义训练步骤(用tf.function加速)
@tf.function
def fine_tune_step(x_batch, y_batch):
    with tf.GradientTape() as tape:
        # 得到模型的分位数预测结果
        pred_quantiles = model(x_batch, training=True)
        # 从分位数计算期望值(这里的逻辑可以根据你的业务需求调整)
        expected_values = tf.reduce_mean(pred_quantiles, axis=1)
        # 计算qcs损失(我们要最小化这个损失)
        loss = qcs_loss(expected_values, y_batch)
    
    # 计算梯度并更新权重
    gradients = tape.gradient(loss, model.trainable_variables)
    fine_tune_optimizer.apply_gradients(zip(gradients, model.trainable_variables))
    return loss

# 开始微调(这里假设你用tf.data.Dataset加载数据)
fine_tune_epochs = 5
for epoch in range(fine_tune_epochs):
    print(f"Fine-tune Epoch {epoch+1}/{fine_tune_epochs}")
    total_loss = 0.0
    batch_count = 0
    for x_batch, y_batch in train_dataset:
        batch_loss = fine_tune_step(x_batch, y_batch)
        total_loss += batch_loss
        batch_count += 1
    avg_loss = total_loss / batch_count
    print(f"Average QCS Loss: {avg_loss:.4f}\n")

2. 组合损失函数:分位数损失+qcs损失加权

如果不想单独做微调,也可以把qcs作为辅助损失项,和原来的分位数损失加权结合,让模型在训练过程中同时优化两个目标。这种方式更适合在训练后期加入,或者全程用小权重让分位数损失主导。

示例代码:

def combined_loss(y_true, y_pred):
    # 原分位数损失
    quantiles = tf.linspace(0.01, 0.99, 99)
    quantile_losses = [tf.maximum(q*(y_true - y_pred[:, i]), (q-1)*(y_true - y_pred[:, i])) for i, q in enumerate(quantiles)]
    quantile_loss = tf.reduce_mean(tf.stack(quantile_losses, axis=1))
    
    # 计算qcs损失
    epsilon = 1e-6
    expected_values = tf.reduce_mean(y_pred, axis=1)
    qcs_loss_val = tf.reduce_mean((y_true - expected_values)**2 / (expected_values + epsilon))
    
    # 加权组合,alpha控制qcs损失的权重(建议设小一点,比如0.1)
    alpha = 0.1
    return quantile_loss + alpha * qcs_loss_val

# 用组合损失编译模型
model.compile(optimizer='adam', loss=combined_loss)
# 然后正常训练即可
model.fit(x_train, y_train, epochs=25, batch_size=32, validation_split=0.1)

关键注意事项

  • 期望值的计算逻辑:你需要明确qcs指标里的expected是怎么从99个分位数推导来的——是分位数的简单均值?还是基于分位数分布计算的期望?这会直接影响模型的优化方向,一定要和业务需求对齐。
  • 数值稳定性:当expected接近0时,除法会导致数值爆炸,所以一定要加一个极小的epsilon(比如1e-6)来避免这个问题。
  • 学习率调整:如果用微调的方式,一定要用远小于预训练的学习率,防止预训练好的分位数预测能力被破坏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:39:53