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

TensorFlow Probability时间序列预测输出恒同问题求助

时间序列分布预测问题:TFP+LSTM输出时间步参数完全一致

问题背景

尝试用TensorFlow Probability(TFP)结合LSTM构建时间序列未来分布预测模型,替代现有GARCH方案,目标是捕捉标准差自回归行为和价格均值回归特性。模型设计为输出1344步预测,对应1344个Student-T分布,但无论输入如何变化,所有时间步的分布参数完全相同,无法实现预期效果。

模型核心代码

def negative_log_likelihood(y, distr):
    return -distr.log_prob(y)

def student_dist(params):
    stuT = tfd.StudentT(loc=params[:,0:OUT_STEPS], 
                                        scale=1e-3 + tf.math.softplus(0.05 * params[:,OUT_STEPS:2 * OUT_STEPS]), 
                                        df =1e-3 + tf.math.softplus(0.05 * params[:,2 * OUT_STEPS:3 * OUT_STEPS]))                                            
    return stuT

nn1 = tf.keras.layers.Input(batch_input_shape=(128, 1374, 9))
nn2 = tf.keras.layers.LSTM(64, return_sequences=True)(nn1)
nn3 = tf.keras.layers.LSTM(32, return_sequences=True)(nn2)
nn4 = tf.keras.layers.Dropout(0.1)(nn3)
nn5 = tf.keras.layers.LSTM(16, return_sequences=True)(nn4)
nn6 = tf.keras.layers.Dropout(0.1)(nn5)
nn7 = tf.keras.layers.Flatten()(nn6)
nn8 = tf.keras.layers.Dense(OUT_STEPS*num_features, activation='relu')(nn7)
nn9 = tf.keras.layers.Dense(OUT_STEPS*num_features, kernel_initializer=tf.initializers.RandomNormal(stddev=0.5))(nn8)
nn10 = tf.keras.layers.Reshape([OUT_STEPS * num_features])(nn9)
nn11= tfp.layers.DistributionLambda(student_dist)(nn10)

multi_lstm_model = tf.keras.models.Model(nn1, nn11)

early_stopping = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=5, mode='min', 
                                                restore_best_weights=True, min_delta= 10e-5)

model.compile(loss=negative_log_likelihood, optimizer=tf.keras.optimizers.Adam())

history = model.fit(genData(candles_1m, train_start, val_start, 14*24*4, 128), validation_data=genData(candles_1m, val_start, test_start, 14*24*4, 128),                      
                      steps_per_epoch=train_step_per_epoch, validation_steps=val_step_per_epoch, 
                      epochs=200, callbacks=[early_stopping])

异常现象

提取DistributionLambda层输入参数后,所有样本的各时间步参数完全一致:

new_model = tf.keras.Model(inputs=multi_lstm_model.input, outputs=multi_lstm_model.layers[-1].input)
prediction = pd.DataFrame(new_model.predict(genData(candles_1m, train_start, val_start, 14*24*4, 128), steps=5))
prediction.iloc[:, OUT_STEPS:3*OUT_STEPS] = tf.math.softplus(prediction.iloc[:, OUT_STEPS:3*OUT_STEPS] * 0.05).numpy()
prediction

# 输出示例(所有行/时间步参数完全相同)
array([[-0.4935108 , -0.29652068,  0.7733726 , ...,  2.814322  ,
         2.9786308 ,  2.915939  ],
       [-0.4935108 , -0.29652068,  0.7733726 , ...,  2.814322  ,
         2.9786308 ,  2.915939  ],
       ...])

已尝试的无效方案

  • 将Student-T分布包裹在Independent分布中
  • 自定义负对数似然函数,手动计算Student-T的对数概率
  • 确认输入数据的特征和目标值随时间步正常变化

排查建议

  1. 重构模型为序列到序列架构
    当前Flatten层将LSTM的序列输出直接展平,再用Dense层生成所有时间步的参数,这种设计容易让模型忽略时间步差异。建议:
    • 去掉Flatten层,将最后一层LSTM设为return_sequences=False获取最终隐藏状态
    • 用RepeatVector(OUT_STEPS)将隐藏状态映射到输出时间步长度
    • 最后通过TimeDistributed(Dense(3))为每个时间步独立生成loc/scale/df三个参数
  2. 调整参数变换的梯度效率
    当前用0.05 * params缩小输入后再做softplus,可能导致梯度过小难以更新:
    • 增大缩放系数至0.5~1.0,或直接在Dense层为scale/df对应的输出单元使用softplus激活
  3. 验证损失计算的维度匹配
    确认负对数似然函数的输出维度与目标数据(batch_size, OUT_STEPS)完全匹配,确保每个时间步的损失都能被正确反向传播
  4. 添加时间步区分特征
    在输入特征中加入归一化的时间步序号,帮助模型明确区分不同预测时间点,强制学习时间步间的差异
  5. 简化模型调试
    暂时减少LSTM层数、单元数和Dropout,用更小的输出步长(如24步)测试,排查是否因模型复杂度或梯度消失导致参数无法更新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 10:57:22