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

