Python中如何用Keras Sequential构建多特征多类别输入输出的LSTM?
嘿,我来帮你搞定这个用Keras Sequential构建多特征多类别输入输出LSTM的问题!首先得明确:你的输入是三个分类特征(A/B/C)组成的时序数据,输出也是对应时序的这三个特征对吧?那咱们一步步来:
第一步:先把分类特征处理好(重中之重!)
你的三个特征都是分类类型,直接喂原始数字给LSTM绝对不行——模型会把它们当成连续数值,完全理解错你的类别含义。所以得先做编码:
- FeatureA(100种取值):用独热编码,转成100维的向量;如果你的原始值是1-100,记得先减1把索引拉到0-99(独热编码默认从0开始)。
- FeatureB(0/1开关):可以直接用独热编码转成2维向量,或者保留0/1也能行,但统一编码更规范。
- FeatureC(5种取值):同样转成5维独热向量,注意索引对齐。
给你个代码示例,假设你的时序数据是(样本数, 时间步长, 3)的格式:
import numpy as np from tensorflow.keras.utils import to_categorical # 模拟你的时序数据,shape=(2个样本, 3个时间步, 3个特征) raw_data = np.array([ [[40,1,5], [58,1,2], [57,1,5]], [[40,0,1], [32,1,3], [67,0,2]] ]) # 分别编码每个特征 feature_a = to_categorical(raw_data[..., 0] - 1, num_classes=100) # 处理100类 feature_b = to_categorical(raw_data[..., 1], num_classes=2) # 处理2类 feature_c = to_categorical(raw_data[..., 2] - 1, num_classes=5) # 处理5类 # 把编码后的特征拼起来,得到LSTM的输入数据 X = np.concatenate([feature_a, feature_b, feature_c], axis=-1) # 现在X的形状是 (2, 3, 107) —— 107=100+2+5
第二步:处理输出目标
因为你要预测这三个特征,所以目标数据也要做和输入一样的编码。这里假设你要做序列预测(即每个时间步都输出下一个时间步的A/B/C),所以把原始数据移位作为目标:
# 目标是每个样本去掉第一个时间步的特征,对应输入的前n-1个时间步 y_a = to_categorical(raw_data[..., 0][:, 1:] - 1, num_classes=100) y_b = to_categorical(raw_data[..., 1][:, 1:], num_classes=2) y_c = to_categorical(raw_data[..., 2][:, 1:] - 1, num_classes=5)
第三步:用Sequential构建模型(两种方案)
这里要说明:Sequential是线性层堆叠,天生适合单输出场景,但咱们也能搞定多输出;如果想更灵活,函数式API会更顺手,我都给你列出来:
方案1:纯Sequential实现(拼接输出)
把三个输出的独热向量拼成一个107维的大向量,模型最后输出这个大向量,训练时用分类交叉熵损失:
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, TimeDistributed # 先把三个目标拼起来 y_combined = np.concatenate([y_a, y_b, y_c], axis=-1) # 构建Sequential模型 model = Sequential() # 输入层:指定输入形状为(时间步长, 特征数),return_sequences=True表示输出每个时间步的结果 model.add(LSTM(64, return_sequences=True, input_shape=(X.shape[1], X.shape[2]))) model.add(LSTM(32, return_sequences=True)) # 可以加多层LSTM提升能力 # 最后一层输出107维,用softmax激活(多分类必备) model.add(TimeDistributed(Dense(107, activation='softmax'))) # 编译模型 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) # 开始训练:输入取前n-1个时间步,对应目标的n-1个时间步 model.fit(X[:, :-1, :], y_combined, epochs=20, batch_size=32)
方案2:函数式API(更推荐,多输出更清晰)
虽然你问的是Sequential,但实际多输出场景下,函数式API能让每个输出头独立设置损失和指标,逻辑更清楚,这里也给你参考:
from tensorflow.keras.models import Model from tensorflow.keras.layers import Input, LSTM, Dense, TimeDistributed # 定义输入层 inputs = Input(shape=(X.shape[1], X.shape[2])) # LSTM层共享参数 x = LSTM(64, return_sequences=True)(inputs) x = LSTM(32, return_sequences=True)(x) # 三个独立的输出头,分别对应三个特征的分类 output_a = TimeDistributed(Dense(100, activation='softmax'), name='output_a')(x) output_b = TimeDistributed(Dense(2, activation='softmax'), name='output_b')(x) output_c = TimeDistributed(Dense(5, activation='softmax'), name='output_c')(x) # 构建模型 model = Model(inputs=inputs, outputs=[output_a, output_b, output_c]) # 编译时给每个输出单独指定损失和指标 model.compile( optimizer='adam', loss={ 'output_a': 'categorical_crossentropy', 'output_b': 'categorical_crossentropy', 'output_c': 'categorical_crossentropy' }, metrics={ 'output_a': 'accuracy', 'output_b': 'accuracy', 'output_c': 'accuracy' } ) # 训练时传入三个独立的目标 model.fit(X[:, :-1, :], [y_a, y_b, y_c], epochs=20, batch_size=32)
几个关键提醒
- 时序形状别搞错:LSTM的输入必须是
(样本数, 时间步长, 特征数),千万别喂二维数据! - return_sequences的设置:如果是序列预测(每个时间步都输出),一定要设为
True;如果只预测最后一个时间步的结果,就设为False。 - 编码要对齐:输入和目标的编码规则必须完全一致,比如FeatureA的原始值40,输入和目标都要转成索引39的独热向量,不然模型白学。
内容的提问来源于stack exchange,提问作者Dev Ermenegildo
相关产品推荐
相关产品推荐

