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

解决时间序列Transformer股票预测中的张量形状不匹配错误

解决TimeSeries Transformer张量形状不匹配问题

问题描述

我正在训练TimeSeries Transformer模型,用前一日股价及其他参数预测股票价格变化,期间遇到一系列张量形状、维度相关错误,当前错误如下:

文件"\transformers\models\time_series_transformer\modeling_time_series_transformer.py",第1378行,forward方法中:transformer_inputs, loc, scale, static_feat = self.create_network_inputs(
文件"\transformers\models\time_series_transformer\modeling_time_series_transformer.py",第1303行,create_network_inputs方法中:抛出ValueError: input length 11 and time feature lengths 13 does not match

我的样本输入数据集包含10行、70个特征,搞不懂错误里的11和13是哪来的。之前还遇到过类似错误:

modeling_time_series_transformer.py",第1272行,create_network_inputs方法中:
(torch.cat((past_values, future_values), dim=1) - loc) / scale
RuntimeError: Sizes of tensors must match except in dimension 1. Expected size 2 but got size 1 for tensor number 1 in the list.

RuntimeError: Tensors must have same number of dimensions: got 3 and 2

代码

import pandas as pd
import numpy as np
from transformers import TimeSeriesTransformerModel, TimeSeriesTransformerConfig, Trainer, TrainingArguments, default_data_collator
from sklearn.preprocessing import MinMaxScaler, OneHotEncoder
from sklearn.metrics import mean_squared_error
import torch
from torch.utils.data import Dataset

# Load the CSV file
file_path = './spy-stock-price - Spy_Ind_Signal.csv'
data = pd.read_csv(file_path)

# Exclude specified columns
exclude_columns = ['20SMA', '50SMA', '200SMA', '20EMA', '10EMA', 'MACD', 'MACD_Signal', 'Average_Volume', 'Bollinger_High', 'Bollinger_Low', 'Bollinger_Middle', 'VWAP', 'AVWAP']
data = data.drop(columns=exclude_columns)

# Preprocess the data
data['Date'] = pd.to_datetime(data['Date'])
data = data.sort_values('Date')

# Encode categorical signals
data_transformed = data

# Drop the 'Date' column
data_transformed = data_transformed.drop(columns=['Date'])

# Normalize the dataset
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_data = scaler.fit_transform(data_transformed)

# Convert the data to a supervised learning problem
def create_dataset(data, look_back=1):
    X, Y = [], []
    for i in range(len(data) - look_back - 1):
        a = data[i:(i + look_back)]
        X.append(a)
        Y.append(data[i + look_back, -2:])  # Include the last two columns as targets
        if Y[-1] is None:
            print(f"NoneType found at index {i + look_back}")
    return np.array(X), np.array(Y)

look_back = 10  # Adjusted look_back to 10
X, y = create_dataset(scaled_data, look_back)

# Split into train and test sets
train_size = int(len(X) * 0.67)
X_train, X_test = X[0:train_size], X[train_size:]
y_train, y_test = y[0:train_size], y[train_size:]


# Reshape input to be [samples, time steps, features]
X_train = np.reshape(X_train, (X_train.shape[0], X_train.shape[1], data_transformed.shape[1]))
X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], data_transformed.shape[1]))

# Create observed mask for the transformer model
def create_observed_mask(data):
    mask = np.ones_like(data, dtype=np.float32)
    return mask

train_observed_mask = create_observed_mask(X_train)
test_observed_mask = create_observed_mask(X_test)

# Convert data to PyTorch tensors
X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.float32)
y_test = torch.tensor(y_test, dtype=torch.float32)
train_observed_mask = torch.tensor(train_observed_mask, dtype=torch.float32)
test_observed_mask = torch.tensor(test_observed_mask, dtype=torch.float32)

# Create a custom dataset class
class TimeSeriesDataset(Dataset):
    def __init__(self, X, y, observed_mask):
        self.X = X
        self.y = y
        self.observed_mask = observed_mask

    def __len__(self):
        return len(self.X)

    def __getitem__(self, idx):
        time_dim = self.X.shape[1]
        feature_dim = self.X.shape[2]

        future_values = self.y[idx].unsqueeze(0).repeat(time_dim, feature_dim // 2)
        static_categorical_features = torch.tensor([]).unsqueeze(0).repeat(time_dim, feature_dim)
        static_real_features = torch.zeros((time_dim, feature_dim))
        static_feat = torch.zeros((time_dim, feature_dim, 1))

        sample = {
            'past_values': self.X[idx],
            'past_time_features': torch.zeros((time_dim, feature_dim)),  # Add this line
            'past_observed_mask': self.observed_mask[idx],
            'future_values': future_values,
            'future_time_features': future_values,
        }

        return sample

train_dataset = TimeSeriesDataset(X_train, y_train, train_observed_mask)
test_dataset = TimeSeriesDataset(X_test, y_test, test_observed_mask)

# Model configuration
config = TimeSeriesTransformerConfig(
    prediction_length=1,
    context_length=look_back,
    lags_seq=[1, 2, 3],
    input_size=data_transformed.shape[1],
    output_size=2,  # Predicting both price_change and bull_bear_signal
    num_time_features=data_transformed.shape[1],  # Match the input size
    num_static_categorical_features=0,
    num_static_real_features=0,
    cardinality=[],
    embedding_dimension=[]
)

model = TimeSeriesTransformerModel(config)

# Training configuration
training_args = TrainingArguments(
    output_dir="./results",
    eval_strategy="epoch",
    learning_rate=1e-4,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=16,
    num_train_epochs=10,
    weight_decay=0.01,
    logging_dir="./logs",
)

# Training
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=test_dataset,
    data_collator=default_data_collator,
)

trainer.train()

# Evaluation
predictions, labels, _ = trainer.predict(test_dataset)

# Inverse transform the predictions and labels
predictions = scaler.inverse_transform(predictions)
labels = scaler.inverse_transform(y_test.numpy())

# Separate the predictions and labels for price_change and bull_bear_signal
predictions_price_change = predictions[:, 0]
predictions_bull_bear_signal = predictions[:, 1]
labels_price_change = labels[:, 0]
labels_bull_bear_signal = labels[:, 1]

# Calculate the Mean Squared Error for price_change
mse_price_change = mean_squared_error(labels_price_change, predictions_price_change)
print(f"Mean Squared Error for Price Change: {mse_price_change}")

# For bull_bear_signal, we can use accuracy as the metric
accuracy_bull_bear_signal = np.mean(predictions_bull_bear_signal.round() == labels_bull_bear_signal.round())
print(f"Accuracy for Bull Bear Signal: {accuracy_bull_bear_signal}")

已采取的步骤

  • 升级transformers库到4.42版本
  • 在HuggingFace和Stack Overflow搜索解决方案,能解决当前错误但会出现同类变体错误
  • 修复过多个同类错误,确保past_values、past_time_features、future_values等张量形状一致

问题根源与修复方案

1. 错误数值解析

错误里的input length=11是上下文长度+预测长度(10+1=11),time feature lengths=13是模型自动计算的上下文长度+预测长度+lags序列长度(10+1+2=13),核心问题是你的时间特征张量形状完全不符合模型要求。

2. 数据集类核心修正

你的TimeSeriesDataset对future_values、past_time_features的处理完全错误,修改后的类如下:

class TimeSeriesDataset(Dataset):
    def __init__(self, X, y, observed_mask):
        self.X = X
        self.y = y
        self.observed_mask = observed_mask
        self.num_time_features = 1  # 用序列位置作为时间特征,无真实时间特征时设为1

    def __len__(self):
        return len(self.X)

    def __getitem__(self, idx):
        # past_values形状: [context_length, input_size] = [10,70]
        past_values = self.X[idx]
        context_length = past_values.shape[0]
        
        # future_values形状: [prediction_length, output_size] = [1,2]
        future_values = self.y[idx].unsqueeze(0)
        
        # 生成时间特征:用序列位置编码作为简单时间特征
        past_time_features = torch.arange(context_length).unsqueeze(1).float()  # [10,1]
        future_time_features = torch.arange(context_length, context_length + 1).unsqueeze(1).float()  # [1,1]
        
        # 观察掩码形状与对应值保持一致
        past_observed_mask = self.observed_mask[idx]
        future_observed_mask = torch.ones_like(future_values)  # 训练时标签已知,设为1

        sample = {
            'past_values': past_values,
            'past_time_features': past_time_features,
            'past_observed_mask': past_observed_mask,
            'future_values': future_values,
            'future_time_features': future_time_features,
            'future_observed_mask': future_observed_mask
        }

        return sample

3. 模型配置修正

num_time_features需与数据集里的时间特征数一致,不能等于输入特征数:

config = TimeSeriesTransformerConfig(
    prediction_length=1,
    context_length=look_back,
    lags_seq=[1, 2, 3],
    input_size=data_transformed.shape[1],  # 70,正确
    output_size=2,  # 正确,预测2个特征
    num_time_features=1,  # 修正为时间特征数
    num_static_categorical_features=0,
    num_static_real_features=0,
    cardinality=[],
    embedding_dimension=[]
)

4. 预测后处理修正

模型输出形状为[batch_size, prediction_length, output_size],需压缩维度后再逆变换:

# Evaluation
predictions, labels, _ = trainer.predict(test_dataset)
predictions = predictions.squeeze(1)  # 从[batch_size,1,2]转为[batch_size,2]

# 构造完整特征矩阵进行逆变换(scaler基于全特征训练)
def inverse_transform_predictions(preds, scaler, total_features):
    dummy = np.zeros((preds.shape[0], total_features))
    dummy[:, -2:] = preds
    return scaler.inverse_transform(dummy)[:, -2:]

predictions = inverse_transform_predictions(predictions, scaler, data_transformed.shape[1])
labels = inverse_transform_predictions(y_test.numpy(), scaler, data_transformed.shape[1])

5. 其他细节检查

  • 确认create_dataset中目标列data[i + look_back, -2:]确实是你要预测的特征
  • 观察掩码past_observed_mask无缺失值时用全1是正确的

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 05:19:50