12.16some pro about py model

发布于:2025-03-14 ⋅ 阅读:(16) ⋅ 点赞:(0)

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 中,层的输出在模型运行(例如通过 fitpredict 等方法)或者手动调用层时才会被确定。在你的代码中,只是定义和构建了 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)) 结构,具体如下:

  1. 第一层 Bidirectional(LSTM(units=50, return_sequences=True))

    • 这一层 LSTM 单元数量设置为 50,意味着每个时间步的隐藏状态维度是 50。同时,由于设置了 return_sequences=True,它会在每个时间步都输出隐藏状态,所以输出形状为 (None, 时间步长, 50)None 表示样本数量可变)。
  2. 第二层 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 个特征。