基于股票收益的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
相关产品推荐
相关产品推荐

