Keras中变长序列的Softmax层应用问题求助
你的核心问题在于Softmax的作用维度不对:当前你在每个时间步单独应用Softmax(不管是直接用Dense(1, activation='softmax')还是TimeDistributed包装的版本),但每个时间步只有1个输出值,Softmax计算后结果还是1,根本无法让整个序列的概率总和为1。
要实现「每个样本的[1,a,1]概率向量总和为1」的目标,需要把Softmax作用于整个序列维度(axis=1),而不是每个时间步的特征维度。下面是具体的修改方案:
修改后的模型代码
import tensorflow as tf model = tf.keras.models.Sequential() # 保持前两层LSTM不变,确保return_sequences=True保留序列维度 model.add(tf.keras.layers.LSTM(32, return_sequences=True, batch_input_shape=(1, None, len(features)))) model.add(tf.keras.layers.LSTM(8, return_sequences=True)) # 先输出未激活的数值,不要在这里加softmax model.add(tf.keras.layers.Dense(1)) # 添加Lambda层,对序列维度(axis=1)应用Softmax model.add(tf.keras.layers.Lambda(lambda x: tf.nn.softmax(x, axis=1))) print(model.summary(90)) # 注意:如果目标是概率分布,categorical_crossentropy可能比MSE更适合 model.compile(loss='mean_squared_error', optimizer='adam')
关键细节解释
Softmax的作用维度:
你的输入序列形状是(1, a, len(features)),经过LSTM后输出是(1, a, 8),再经过Dense(1)后变成(1, a, 1)。此时axis=1对应序列的长度维度(也就是每个样本的a个时间步),对这个维度做Softmax,就能让整个序列的所有概率值之和为1。为什么不用TimeDistributed?
当LSTM设置return_sequences=True时,后续的Dense层会自动对每个时间步单独应用(等价于TimeDistributed(Dense(...))),所以这里不需要额外包装,而且包装后也解决不了Softmax维度的问题。损失函数的可选优化:
如果你的目标是严格的概率分布(总和为1),使用categorical_crossentropy损失通常比mean_squared_error更适合,因为它是专门针对概率分布拟合设计的。不过需要确保你的目标张量batch_y的形状和模型输出一致((1, a, 1))。
验证输出
你可以在训练前用一个测试输入验证输出的总和是否为1:
# 生成一个测试输入,比如长度为5的序列 test_input = tf.random.normal((1, 5, len(features))) test_output = model(test_input) # 计算整个序列的概率和 print(tf.reduce_sum(test_output).numpy()) # 应该接近1.0
内容的提问来源于stack exchange,提问作者deepAgrawal

