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

基于股票收益的LSTM自定义损失函数报错求助

解决LSTM自定义指标维度不匹配的ValueError问题

报错核心原因

  • 自定义指标ret中,全局变量train_close.diff()的维度为[998],而y_pred是模型输出的one-hot编码,维度为[batch_size, 2],两者无法直接相乘。
  • train_close是原始训练数据的收盘价,未和序列创建后的训练样本对齐,导致长度不匹配。
  • 自定义指标中使用numpy数组运算,未适配TensorFlow的张量批量处理逻辑。

解决方案步骤

1. 调整数据预处理,对齐收益与训练样本

修改序列创建函数,同步提取对应样本的收益值,确保收益数据长度和训练样本数一致:

# 修改sequences_creation函数,增加收益提取逻辑
def sequences_creation(data_x, data_y, returns, timesteps):
    data_x_seq, data_y_seq, data_symbol_seq, returns_seq = [], [], [], []
    for i in range(data_x.shape[0] - (timesteps-1)):
        data_x_seq.append(data_x.iloc[i:i+timesteps].values)
        data_y_seq.append(data_y.loc[i + (timesteps-1), 'trgt'])
        data_symbol_seq.append(data_y.loc[i + (timesteps-1), 'Date'])
        # 提取对应序列最后一天的收益值
        returns_seq.append(returns.iloc[i + (timesteps-1)])
    data_x_seq = np.array(data_x_seq)
    data_y_seq = np.array(data_y_seq).reshape(-1,1)
    data_symbol_seq = np.array(data_symbol_seq).reshape(-1,1)
    returns_seq = np.array(returns_seq).reshape(-1,1)
    print(f'Data dimensions: {data_x_seq.shape}, {data_y_seq.shape}, {returns_seq.shape}')
    return data_x_seq, data_y_seq, pd.DataFrame(data_symbol_seq), returns_seq

2. 重写自定义指标,适配张量运算

将收益数据作为模型输入传递,把one-hot编码转换为类别标签后再计算收益差值:

import keras.backend as K

def return_metric(y_true, y_pred, returns):
    # 将one-hot编码转为0/1类别标签
    y_true_label = K.argmax(y_true, axis=-1)
    y_pred_label = K.argmax(y_pred, axis=-1)
    # 计算策略收益与实际收益的差值绝对值均值
    algo_return = returns * K.cast(y_pred_label, K.floatx())
    logic_return = returns * K.cast(y_true_label, K.floatx())
    return K.mean(K.abs(algo_return - logic_return))

3. 改用函数式API构建模型,支持多输入

将序列数据和收益数据作为双输入,确保指标能获取对应批次的收益值:

from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, LSTM, Dense

# 定义序列输入层
seq_input = Input(shape=(timesteps, train_x.shape[2]))
# LSTM特征提取层
x = LSTM(32, return_sequences=True)(seq_input)
x = LSTM(62, return_sequences=True)(x)
x = LSTM(120)(x)
# 定义收益输入层(仅用于指标计算,不参与模型训练)
return_input = Input(shape=(1,))
# 输出层
output = Dense(train_y.shape[1], activation='softmax')(x)
# 创建模型
model = Model(inputs=[seq_input, return_input], outputs=output)
# 编译模型,绑定自定义指标
model.compile(
    loss='categorical_crossentropy',
    optimizer='Adam',
    metrics=[lambda y_true, y_pred: return_metric(y_true, y_pred, return_input)]
)

4. 调整训练数据与模型拟合逻辑

# 准备训练集收益数据,对齐序列样本长度
train_returns = train_close.diff().dropna()
train_returns = train_returns.iloc[timesteps-1:]  # 跳过前timesteps-1个无对应序列的收益
# 准备测试集收益数据
test_close = test_x.Close.copy()
test_returns = test_close.diff().dropna()
test_returns = test_returns.iloc[timesteps-1:]

# 创建序列时传入收益数据
train_x, train_y, _, train_returns_seq = sequences_creation(train_x, train_y, train_returns, timesteps=timesteps)
test_x, test_y, test_symbol, test_returns_seq = sequences_creation(test_x, test_y, test_returns, timesteps=timesteps)

# 转换为one-hot编码
train_y = to_categorical(train_y, num_classes=2)
test_y = to_categorical(test_y, num_classes=2)

# 拟合模型,传入双输入
model.fit(
    [train_x, train_returns_seq], 
    train_y, 
    epochs=100, 
    batch_size=32, 
    verbose=2,
    validation_split=0.2,
    class_weight=class_weight,
    use_multiprocessing=True,
    workers=6
)

关键修改说明

  • 移除全局变量依赖,通过模型输入传递收益数据,确保批次维度完全匹配。
  • 将one-hot编码转换为类别标签后再与收益相乘,解决维度不兼容问题。
  • 严格对齐收益数据与序列样本的长度,避免因长度不一致导致的维度错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 12:36:17