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

Transformer模型在多元时间序列数据上拟合不佳的技术咨询

多元时间序列多对一分类Transformer模型问题解答

用户问题背景

我已构建LSTM、带Self-Attention的LSTM两种模型,目前正在开发首个Transformer模型,用于多元时间序列的多对一分类任务。
数据为小时级变化数据,包含8个特征(小时、月份、温度、湿度、风速、太阳辐射浓度等),目标是预测建筑能耗值。输入形状为X.shape = (8783, 168, 8)(8783个时间序列,每个序列含168条小时数据,每条数据8个特征);输出形状为Y.shape = (8783,1)(每个序列对应1个建筑能耗值)。

参考Keras官方示例构建模型,将输出转换为类别,n_classes = len(np.unique(Y_train)) = 156,输入输出形状为Input shape (X_train) = (8783, 168, 8) Output shape (Y_train) = (8783,1) n_classes = 156,在softmax激活层设置输出为n_classes,但模型拟合效果很差。

附上模型代码:

def build_transformer_model(input_shape, head_size, num_heads, ff_dim, num_transformer_blocks,
                            mlp_units, dropout=0, mlp_dropout=0):

    inputs = keras.Input(shape=input_shape)
    x = inputs
    for _ in range(num_transformer_blocks):

        # Normalization and Attention
        x = layers.LayerNormalization(epsilon=1e-6)(x)
        x = layers.MultiHeadAttention(
            key_dim=head_size, num_heads=num_heads, dropout=dropout
        )(x, x)
        x = layers.Dropout(dropout)(x)
        res = x + inputs

        # Feed Forward Part
        x = layers.LayerNormalization(epsilon=1e-6)(res)
        x = layers.Conv1D(filters=ff_dim, kernel_size=1, activation="relu")(x)
        x = layers.Dropout(dropout)(x)
        x = layers.Conv1D(filters=inputs.shape[-1], kernel_size=1)(x)
        x = x + res

    x = layers.GlobalAveragePooling1D(data_format="channels_first")(x)
    for dim in mlp_units:
        x = layers.Dense(dim, activation="relu")(x)
        x = layers.Dropout(mlp_dropout)(x)
    x = layers.Dense(n_classes, activation="softmax")(x)
    return keras.Model(inputs, x)


model_tr = build_transformer_model(input_shape=(X_train.shape[1], X_train.shape[2]), head_size=256,
                                   num_heads=4, ff_dim=4, num_transformer_blocks=4, mlp_units=[128], mlp_dropout=0.4, dropout=0.2)
model_tr.compile(loss="sparse_categorical_crossentropy",
    optimizer=keras.optimizers.Adam(learning_rate=0.0001),
    metrics=["sparse_categorical_accuracy"],
)
plot_model(model_tr, to_file='model_plot.png', show_shapes=True, show_layer_names=True)
model_tr.summary()
m_tr_history = model_tr.fit(x=X_train, y=Y_train, validation_split=0.15, batch_size=64, epochs=100, verbose = 1)
model_tr.save('halka_transformer.h5')

咨询问题:
I) 模型架构是否存在问题?代码中是否有需要调整的部分以适配我的任务?
II) Transformer能否处理我这类8特征输入、1特征输出的多元问题,还是仅适用于单变量问题?


问题解答

I) 模型架构问题与调整建议

1. 残差连接逻辑错误

原代码中Transformer块的残差连接直接叠加原始输入inputs,会破坏特征的递进学习:

res = x + inputs  # 错误:应该叠加当前块的输入,而非原始输入

正确的残差连接应保存每个块的初始输入作为基准:

def build_transformer_model(input_shape, head_size, num_heads, ff_dim, num_transformer_blocks,
                            mlp_units, dropout=0, mlp_dropout=0):
    inputs = keras.Input(shape=input_shape)
    x = inputs
    for _ in range(num_transformer_blocks):
        # 保存当前块的输入作为残差基准
        residual = x
        
        # Normalization and Attention
        x = layers.LayerNormalization(epsilon=1e-6)(x)
        x = layers.MultiHeadAttention(
            key_dim=head_size, num_heads=num_heads, dropout=dropout
        )(x, x)
        x = layers.Dropout(dropout)(x)
        x = x + residual  # 注意力输出 + 块输入
        
        # Feed Forward Part
        residual = x  # 更新残差基准为注意力后的输出
        x = layers.LayerNormalization(epsilon=1e-6)(x)
        x = layers.Conv1D(filters=ff_dim, kernel_size=1, activation="relu")(x)
        x = layers.Dropout(dropout)(x)
        x = layers.Conv1D(filters=inputs.shape[-1], kernel_size=1)(x)
        x = x + residual  # 前馈输出 + 注意力后的输出
    
    x = layers.GlobalAveragePooling1D()(x)
    for dim in mlp_units:
        x = layers.Dense(dim, activation="relu")(x)
        x = layers.Dropout(mlp_dropout)(x)
    x = layers.Dense(n_classes, activation="softmax")(x)
    return keras.Model(inputs, x)

2. 池化层参数错误

GlobalAveragePooling1D设置data_format="channels_first"不符合你的输入结构:你的输入是(时间步, 特征数),默认channels_last才是正确维度,修改后才能正确对时间步做池化。

3. 超参数适配问题

  • head_size与特征维度不匹配:输入特征维度为8,head_size=256过大,建议调整为8/16等与特征维度适配的值,同时保证head_size * num_heads与特征维度兼容(比如head_size=4, num_heads=2)。
  • ff_dim过小:ff_dim=4无法充分提取特征,建议调整为32或64。
  • 分类任务合理性验证:156个类别属于多分类,若能耗值是连续数值,转为分类会损失信息,建议优先尝试回归任务(用MSE损失+Dense(1, activation='linear'))。

4. 输入特征归一化

时间序列特征数值范围差异大,必须先做标准化/归一化:

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
# 展平时间步做归一化,再恢复原形状
X_train_scaled = scaler.fit_transform(X_train.reshape(-1, X_train.shape[-1])).reshape(X_train.shape)
X_val_scaled = scaler.transform(X_val.reshape(-1, X_val.shape[-1])).reshape(X_val.shape)

II) Transformer对多元输入的支持

Transformer完全可以处理8特征输入的多元时间序列任务:

  • 输入的8个特征会作为每个时间步的特征向量,自注意力机制会同时捕捉不同时间步的所有特征关联,学习特征间的依赖关系。
  • 单变量时间序列只是多元的特例(特征维度=1),Transformer在多元任务中表现更具优势,能并行处理所有时间步的特征交互,高效捕捉长距离依赖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 07:45:19