pro1
y_true
是一维数组,代表了真实的目标值(例如股票收盘价),长度为 100,表示有 100 个样本的真实值。y_pred
是二维数组,形状为 (100, 1)
,这意味着模型对这 100 个样本进行了预测,每个样本的预测结果是一个单独的值(在二维数组中表示为一列)。
这种形状不匹配是导致之前计算 beta_t
出现问题的关键所在。在计算 Tradaboost_error
函数中的 E = np.max(np.abs(y_true - y_pred))
时,由于广播机制,y_pred
会被扩展为 (100, 100)
,从而导致计算出的 E
也是 (100, 100)
,最终使得 e
和 beta_t
的形状也不正确。
你可以按照之前建议的,在计算 E
时指定正确的轴,将其修改为 E = np.max(np.abs(y_true - y_pred), axis=0)
(或者根据实际需求选择合适的轴,确保计算结果的形状符合后续计算的预期),然后检查整个代码流程中其他涉及到这些变量计算和使用的部分,确保它们都能正确处理修改后的形状
现在的问题在于 np.power(beta_t, np.abs(y_historical - weak_learner.predict(X_historical)))
这一步。虽然 E
的形状正确了,但 np.abs(y_historical - weak_learner.predict(X_historical))
的形状仍然是 (100, 100)
,这是因为在计算这个差值的绝对值时,y_historical
(形状为 (100,)
)和 weak_learner.predict(X_historical)
(形状为 (100, 1)
)之间的广播规则导致了结果的形状扩展。
要解决这个问题,你需要确保在计算 np.abs(y_historical - weak_learner.predict(X_historical))
时,两个数组的形状能够正确匹配。一种方法是将 y_historical
扩展为二维数组,使其形状与 weak_learner.predict(X_historical)
兼容,
但是Tradaboost_error
函数返回的是e而不是E啊,e是(100,100)
pro2
pro3
new_bi_lstm = Bidirectional(LSTM(units=50))
创建了一个新的双向长短期记忆(Bi - LSTM)层,其中units=50
表示该层内部神经元的数量为 50。Bi - LSTM 层能够同时处理正向和反向的时间序列信息,从而更好地捕捉序列中的长期依赖关系。new_bi_lstm.build((None, dataset.shape[1], 1))
这一步是构建新的 Bi - LSTM 层,指定了输入数据的形状。None
表示样本数量可以是任意的(在实际训练中会根据数据集的大小确定),dataset.shape[1]
表示输入数据的时间步长(即每个样本包含的特征数量,例如股票价格数据中的开盘价、最高价、最低价等特征的数量),1
表示每个时间步的数据是一维的(例如单个股票价格数值)shared_layer = Dense(1, activation='linear')
创建了一个全连接层(Dense 层),输出维度为 1,这意味着该层将对输入数据进行线性变换,最终输出一个预测值(例如预测股票的收盘价)。activation='linear'
表示使用线性激活函数,不进行非线性变换,适用于回归任务(如预测股票价格)。shared_layer.build((None, 100))
构建共享层,指定输入维度为 100。这里的 100 是假设两个 Bi - LSTM 层的输出进行拼接后的维度(每个 Bi - LSTM 层输出维度为 50,拼接后为 100),表示该层将接收来自两个 Bi - LSTM 层的综合信息作为输入。
U = np.ones((100, 1)) / 50
和W = np.ones((100, 1)) / 50
定义了两个权重矩阵U
和W
,用于调整两个 Bi - LSTM 层输出在共享层中的权重。它们的形状为(100, 1)
,表示将 100 维的输入特征映射到 1 维的输出(预测值)。初始化时,使用全 1 矩阵并除以 50,这是一种简单的初始化方式,实际应用中可能需要根据具体情况选择更合适的初始化方法,如随机初始化等。weak_learner.layers[-1].set_weights([U, W])
将定义好的权重矩阵设置为弱学习器模型最后一层(即共享层)的权重。
- Bi - LSTM 层输入形状:
(None, dataset.shape[1], 1)
,其中None
表示样本数量可变,dataset.shape[1]
是输入数据的时间步长(特征数量),1
表示每个时间步的数据是一维的。 - Bi - LSTM 层输出形状:如果假设 Bi - LSTM 层内部单元数量为 50(如代码中设置的
units=50
),并且考虑双向结构,其输出形状为(None, 50)
。这是因为对于每个时间步,Bi - LSTM 会生成一个 50 维的向量来表示该时间步的隐藏状态,最后将所有时间步的隐藏状态进行某种方式的聚合(如取最后一个时间步的隐藏状态或进行平均等,具体取决于模型的实现细节),得到一个形状为(None, 50)
的输出。 - 共享层输入形状:根据代码中的假设,两个 Bi - LSTM 层输出拼接后为 100 维,所以共享层的输入形状为
(None, 100)
。 - 共享层输出形状:共享层的输出形状为
(None, 1)
,因为它的任务是对输入数据进行线性变换,最终输出一个预测值(例如预测股票收盘价)
那这个是哪层的格式不统一?
但是按论文,不应该是弱学习器固有一个model.add(Dense(1)),然后FL——Share的时候,是让新旧弱学习器的输出先经过U,W计算得到一个输出后,再经过一个Dense(1)吗??这里先让新旧模型的权重都为0.5,修改代码以匹配论文
pro4
这个错误是因为在获取 new_bi_lstm
(新添加的双向 LSTM 层)的输出时,这个层还没有被调用,所以没有定义输出。
在 Keras 中,层的输出在模型运行(例如通过 fit
、predict
等方法)或者手动调用层时才会被确定。在你的代码中,只是定义和构建了 new_bi_lstm
层,但没有将数据传入这个层来触发计算,因此尝试获取其输出就会导致错误。
为了解决这个问题,你可以在获取输出之前,手动调用这个层,将一些虚拟的数据传入,这样就能定义其输出了
什么意思?没懂问题出在哪
在代码里,你定义了 new_bi_lstm
这个 Bidirectional(LSTM(units=50))
层,也就是双向长短期记忆层,但是仅仅定义和构建它(通过 new_bi_lstm.build((None, dataset.shape[1], 1))
这一步只是设置了它能接受的输入形状等信息)是不够的。
神经网络层的输出张量(也就是 output
)并不是在定义的时候就自动生成和确定下来的,它需要在实际运行过程中,有输入数据流过这个层,经过层内的计算逻辑(比如 LSTM
单元里的各种运算、对输入数据的处理等),才能得到相应的输出。
就好比你造了一台复杂的机器(对应这个 new_bi_lstm
层),虽然机器组装好了(定义和构建好了),但如果不启动它,不给它原材料(输入数据)让它运转起来,你是没办法知道它最终加工出来的成品(输出)是什么样子的。
在你的代码中,当执行到 new_bi_lstm_output = new_bi_lstm.output
这一行时,由于之前没有让数据流过 new_bi_lstm
层,Keras 框架就不知道这个层的输出具体是什么,所以会报错提示 The layer bidirectional_55 has never been called and thus has no defined output
,意思就是这个 new_bi_lstm
(这里显示为 bidirectional_55
,是 Keras 自动给这个层起的一个标识名称)层从来没有被调用过,也就没有定义好的输出
为了解决这个问题,我们需要人为地 “启动” 这个层,让它先处理一些数据,这样就能确定它的输出了。
pro5
这个错误提示表明你正在试图将一个 KerasTensor
(它是在构建 Keras 模型时使用的一种符号化的占位符,代表了特定的形状和数据类型)作为输入传递给一个普通的 TensorFlow 函数(在这里就是 tf.matmul
),但这是不被允许的操作
weighted_output = tf.matmul(combined_output, U) + tf.matmul(combined_output, W)
pro6
old_output shape: (None, 100) new_bi_lstm_output shape: (None, 100) combined_output shape: (None, 200)
为什么单个模型的output shape是100??前一层不都是50的Bidirectional(LSTM(units=50))吗??
对于 build_weak_learner
函数中模型结构的分析
在 build_weak_learner
函数构建的模型里,有两层 Bidirectional(LSTM(units=50))
结构,具体如下:
-
第一层
Bidirectional(LSTM(units=50, return_sequences=True))
:- 这一层
LSTM
单元数量设置为50
,意味着每个时间步的隐藏状态维度是50
。同时,由于设置了return_sequences=True
,它会在每个时间步都输出隐藏状态,所以输出形状为(None, 时间步长, 50)
(None
表示样本数量可变)。
- 这一层
-
第二层
Bidirectional(LSTM(units=50))
:- 它接收第一层的输出作为输入,这一层没有设置
return_sequences=True
,默认只在最后一个时间步输出隐藏状态。对于双向LSTM
,它从正向和反向分别处理序列数据后,会将正向和反向最后一个时间步的隐藏状态进行拼接(如果LSTM
单元数量为50
,正向最后一个时间步输出50
维向量,反向同理,拼接后就是100
维向量),所以这一层的输出形状为(None, 100)
,也就是对于每个样本,最终输出一个100
维的向量。
- 它接收第一层的输出作为输入,这一层没有设置
pro7

这个 KeyError
错误提示表明在调用 new_model.fit(X, y, epochs=50, batch_size=32, verbose=0)
时,模型在执行前向传播(也就是 Functional.call()
这个过程中)出现了问题,导致无法正确获取输出张量,进而引发了 KeyError
。
以下是一些可能导致这个问题的原因及对应的解决思路:
1. 输入数据维度问题
从错误信息中看到输入数据 X
的形状是 (None, 4, 1)
,很有可能是这个输入数据的维度与模型期望的输入维度不匹配。
在你的代码中,虽然有 X = X.reshape(X.shape[0], X.shape[1], 1)
这一步对数据进行了重塑,但还是要确认一下:
- 时间步长维度:模型构建时(比如
LSTM
层的input_shape
相关设置)所期望的时间步长维度是否确实是4
。如果模型期望的是其他时间步长数值,那需要调整输入数据X
的形状,使其时间步长维度符合模型要求。 - 特征维度:这里最后一维是
1
,表示每个时间步的特征维度为 1,同样要检查模型中各层对输入特征维度的要求是否与之相符,比如是否存在某个层期望每个时间步有多个特征,而不是单个特征,若不匹配需要对数据进行相应的预处理(例如增加或调整特征维度)
这个错误提示表明在尝试访问 new_model
中 InputLayer
(输入层)的 input_shape
属性时,发现该对象没有这个属性,所以出现了 AttributeError
。
在 Keras 中,较新版本里获取输入层的形状信息的方式有所变化,对于 InputLayer
,应该使用 layer.shape
来获取其形状信息,而不是 input_shape
。
None
出现在张量形状的第一个位置,它表示这个维度的大小是可变的,可以根据实际传入的数据批量大小(batch size)动态调整。例如,在训练模型时,你可能一次传入 16 个样本、32 个样本等不同数量的样本进行批量训练,这个 None
就代表了每次传入样本的数量是可以变化的,由具体的训练设置(如调用 fit
方法时指定的 batch_size
参数等)来决定。
2. 4
维度
这里的 4
表示时间步长(time steps)或者序列长度(sequence length),意味着输入的数据具有一定的时间序列特性,且每个样本包含 4 个时间步的数据。比如,如果你处理的是股票价格数据,可能每个样本就是连续 4 个时间点(如 4 个交易日)的开盘价、收盘价等相关数据组成的序列;要是处理文本数据,可能就是一个长度为 4 的单词序列等情况,具体取决于你的应用场景和数据本身的特点。
3. 1
维度
最后的 1
表示每个时间步对应的特征维度(feature dimension),也就是在每个时间步上只有 1 个特征值。例如对于股票价格数据来说,可能就是在每个时间步只有一个具体的价格数值(如果只考虑单一价格指标的话);要是有多个特征(比如同时考虑开盘价、收盘价、成交量等),那这个数值就会相应变大,特征维度会根据实际包含的特征数量进行调整,比如变成 (None, 4, 3)
表示每个时间步有 3 个特征。