【问题标题】:Input 0 of layer "conv2d_5" is incompatible with the layer: expected min_ndim=4, found ndim=2. Full shape received: (None, 2)层“conv2d_5”的输入 0 与层不兼容:预期 min_ndim=4,发现 ndim=2。收到完整形状:(无,2)
【发布时间】:2022-12-10 02:13:13
【问题描述】:

我正在尝试在多变量时间序列上使用 CNN,而不是图像上最常见的用法。特征的数量在 90 到 120 之间,具体取决于我需要考虑和试验的特征。这是我的代码

scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)

X_train_s = X_train_s.reshape((X_train_s.shape[0], X_train_s.shape[1],1))
X_test_s = X_test_s.reshape((X_test_s.shape[0], X_test_s.shape[1],1))

batch_size = 1024
length = 120
n_features = X_train_s.shape[1]

generator = TimeseriesGenerator(X_train_s, pd.DataFrame.to_numpy(Y_train[['TARGET_KEEP_LONG', 
                                                                          'TARGET_KEEP_SHORT']]), 
                                                                 length=length, 
                                                                 batch_size=batch_size)

validation_generator = TimeseriesGenerator(X_test_s, pd.DataFrame.to_numpy(Y_test[['TARGET_KEEP_LONG', 'TARGET_KEEP_SHORT']]), length=length, batch_size=batch_size)


early_stop = EarlyStopping(monitor = 'val_accuracy', mode = 'max', verbose = 1, patience = 20)

CNN_model = Sequential()
   
model.add(
    Conv2D(
        filters=64,
        kernel_size=(1, 5),
        strides=1,
        activation="relu",
        padding="valid",
        input_shape=(length, n_features, 1),
        use_bias=True,
    )
)
model.add(MaxPooling2D(pool_size=(1, 2)))
model.add(
    Conv2D(
        filters=64,
        kernel_size=(1, 5),
        strides=1,
        activation="relu",
        padding="valid",
        use_bias=True,
    )
)
[... code continuation ...]

也就是说,我把特征作为一个维度,一定的行数作为另一个维度。但我得到这个错误

“ValueError:层“conv2d_5”的输入 0 与层不兼容:预期 min_ndim = 4,发现 ndim = 2。收到完整形状:(无,2)”

这被称为第一个 CNN 层。

【问题讨论】:

    标签: python conv-neural-network


    【解决方案1】:

    数据加载

    我制作了一个简单的课程,演示了这样做的合理方法。请注意,我对 TensorFlow 不是很熟悉,主要使用 PyTorch,因此代码可能没有优化。

    如果不能为此使用自定义生成器,您可能最擅长定义自定义生成器。阅读 cmets 后,我注意到您不想提前计算所有值;这样做是因为我们只将基础数据保留在self.data 中,并基于此创建新的张量。

    import tensorflow as tf
    import numpy as np
    v = np.array([[12055., 11430., 10966., 12055., 11430., 10966.], 
                  [11430., 10966., 10725., 11430., 10966., 10725.],
                  [10966., 10725., 10672.,10966., 10725., 10672.]])
    q = tf.constant(v)
    class MyData():
    
        def __init__(self, data, windows_size):
            self.data = data
            self.windows_size = windows_size
            self._dataset = tf.data.Dataset.from_generator(self._generator,
                            output_types=tf.float32,
                            output_shapes=(self.windows_size, self.data.shape[1]))
    
        def _generator(self):
            for i in range(self.data.shape[0] - self.windows_size + 1):
                yield self.data[i:i+self.windows_size]
        
        def __len__(self):
            return self.data.shape[0] - self.windows_size + 1
    
        def get_dataset(self):
            return self._dataset
    # Example usage:
    test = MyData(q, 2)
    it = iter(test.get_dataset())
    
    for data in it:
        print(data.shape)
    

    这会生成第一维具有 windows_size 的张量。该代码与 [N, DATA] -> [W, DATA] 配合使用,其中 N 代表时间序列,W 代表缩小的窗口大小;我添加了上一个链接中的部分示例代码。

    模型设计

    可以为模型设计做出多个设计决策。

    首先,您可以将其视为嵌入问题(Embedding layer)。然后你可以reshape它与你的 2D 卷积一起使用。

    第二种方法是直接将数据重塑为类似于二维图像的东西。请注意,如果不同示例之间的序列长度发生变化,则第二种方法将很糟糕。您不能在不修改网络的情况下对训练进行批处理(根据大小添加额外的层来处理图像并不相对简单)。

    最后,已经存在使用 features of time series data 执行此类操作的教程,如下所示:

    def basic_conv2D(n_filters=10, fsize=5, window_size=5, n_features=2):
     new_model = keras.Sequential()
     new_model.add(tf.keras.layers.Conv2D(n_filters, (1,fsize), padding=”same”, activation=”relu”, input_shape=(window_size, n_features, 1)))
     new_model.add(tf.keras.layers.Flatten())
     new_model.add(tf.keras.layers.Dense(1000, activation=’relu’))
     new_model.add(tf.keras.layers.Dense(100))
     new_model.add(tf.keras.layers.Dense(1))
     new_model.compile(optimizer=”adam”, loss=”mean_squared_error”) 
     return new_model
    m2 = basic_conv2D(n_filters=24, fsize=2, window_size=window_size, n_features=data_train_wide.shape[2])
    m2.summary()
    

    【讨论】:

    • 谢谢回复:这是数据准备的麻烦,不是模型定义的麻烦。我已经读过那篇文章,但据我了解,它建议“手动”创建和保存 (N-1) 的滑动窗口加上 RAM 中的当前行,对于大型数据集可能会导致过载问题。出于这个原因,我考虑使用 TimeseriesGenerator,它应该在每次请求时创建新的 N 组(在我的示例中 N = 120)过去的广告当前行。这种方法是错误的吗?或者它是正确的,但我没有正确应用它?在你的第一个提案中,滑动窗口“尺寸”在哪里准备?
    • @fede72bari 好问题;我们可以想到 2 个滑动窗口。一个是我们让嵌入层看到多少(从时间序列序列)。另一件需要考虑的事情是卷积的大小有多少会捕获我们序列的嵌入式表示中的依赖性。现在,如果你为 Embedding 输入 120 并对嵌入进行卷积,你不能保证考虑了哪些嵌入特征。
    • @fede72bari 建议你阅读这样的内容:pinecone.io/learn/time-series-vectors
    • 我认为嵌入不是使过去 N 行的滑动组具有所有特征作为列的正确方法。您在回答中提到的最后一篇文章提出了将其创建为新数据框或系列的代码,但代价是 RAM 使用量激增。我的尝试是改用 TimeseriesGenerator 来避免内存问题。我需要有关我的 TimeseriesGenerator 解决方案的答案。我需要为 2D CNN 提供 1 个通道、M 列(与原始数据集相同)、120 行(最后一行是当前行)X 数据集长度。
    • @fede72bari 我已经编辑了答案,包括如何动态生成时间序列。我对 TimeseriesGenerator 不太熟悉,但确实创建了一个类作为示例。 StopIteratonException 如果您在 for 循环之外使用它,则需要它。
    【解决方案2】:

    经过几天的尝试并希望发帖提供一些间接的见解,我发现了问题所在,我可以分享解决方案

    • 使用时间序列而非图像的 2DCNN 模型
    • 避免使用 TimeseriesGenerator 准备数据集的内存问题

    正如预期的那样,问题在于准备具有正确形状的数据集。我代码中的主要错误是这个

    X_train_s = X_train_s.reshape((X_train_s.shape[0], X_train_s.shape[1],1))
    X_test_s = X_test_s.reshape((X_test_s.shape[0], X_test_s.shape[1],1))
    

    应该用这个替换(我也更改了系列的名称,但只是为了保持原来的不变)

    X_train_s_CNN = X_train_s.reshape(*X_train_s.shape, 1)
    X_test_s_CNN = X_test_s.reshape(*X_test_s.shape, 1)
    

    这是完整的工作代码

    from tensorflow.keras.layers import Conv1D, MaxPooling1D, Dense, Flatten, Conv2D, MaxPooling2D
    from tensorflow.keras.layers import BatchNormalization
    
    scaler = StandardScaler()
    X_train_s = scaler.fit_transform(X_train)
    X_test_s = scaler.transform(X_test)
    
    X_train_s_CNN = X_train_s.reshape(*X_train_s.shape, 1)
    X_test_s_CNN = X_test_s.reshape(*X_test_s.shape, 1)
    
    
    batch_size = 64
    length = 300
    n_features = X_train_s.shape[1]
    
    generator = TimeseriesGenerator(X_train_s_CNN, pd.DataFrame.to_numpy(Y_train[['TARGET_KEEP_LONG', 
                                                                              'TARGET_KEEP_SHORT']]), 
                                                                        length=length, 
                                                                        batch_size=batch_size)
    
    validation_generator = TimeseriesGenerator(X_test_s, pd.DataFrame.to_numpy(Y_test[['TARGET_KEEP_LONG', 
                                                                                       'TARGET_KEEP_SHORT']]), 
                                                                               length=length, 
                                                                               batch_size=batch_size)
    
    
    early_stop = EarlyStopping(monitor = 'val_accuracy', mode = 'max', verbose = 1, patience = 10)
    
    CNN_model = Sequential()
    
    
    CNN_model.add(
        Conv2D(
            filters=64,
            kernel_size=(2,2),
            strides=1,
            activation="relu",
            padding="same",
            input_shape=(length, n_features, 1),
            use_bias=True,
        )
    )
    CNN_model.add(BatchNormalization())
    CNN_model.add(MaxPooling2D(pool_size=(2, 2)))
    #CNN_model.add(Dropout(0.2))
    
    CNN_model.add(
        Conv2D(
            filters=128,
            kernel_size=(2,2),
            strides=1,
            activation="relu",
            padding="same"
        )
    )
    CNN_model.add(BatchNormalization())
    CNN_model.add(MaxPooling2D(pool_size=(2, 2)))
    #CNN_model.add(Dropout(0.3))
    
    # CNN_model.add(
    #    Conv2D(
    #        filters=256,
    #        kernel_size=(2,2),
    #        strides=1,
    #        activation="relu",
    #        padding="same"
    #    )
    # )
    # CNN_model.add(
    #    Conv2D(
    #        filters=256,
    #        kernel_size=(2,2),
    #        strides=1,
    #        activation="relu",
    #        padding="same"
    #    )
    # )
    # CNN_model.add(BatchNormalization())
    # CNN_model.add(MaxPooling2D(pool_size=(2, 2)))
    # CNN_model.add(Dropout(0.3))
    
    
    CNN_model.add(Flatten())
    # CNN_model.add(Dense(units=4096, activation="relu", ))
    # CNN_model.add(BatchNormalization())
    # #CNN_model.add(Dropout(0.5))
    # CNN_model.add(Dense(units=128, activation="relu", ))
    # CNN_model.add(BatchNormalization())
    # # CNN_model.add(Dropout(0.5))
    CNN_model.add(Dense(units=2, activation="softmax", ))
    
    
    CNN_model.compile(
        optimizer="adam", loss="categorical_crossentropy", metrics=["accuracy"]
    )
    
    
    
    CNN_model.fit(
        generator, steps_per_epoch=1, 
        validation_data=validation_generator,
        epochs=200,
    )
    

    在备注部分中,我测试过的变体。遗憾的是,在这种特定情况下,结果在准确性和 val_accuracy 方面非常不稳定。最令人不安的是具有真正不稳定行为的准确性。不清楚为什么。

    【讨论】:

      猜你喜欢
      • 2020-12-24
      • 1970-01-01
      • 2021-06-17
      • 1970-01-01
      • 2021-09-04
      • 2021-09-23
      • 1970-01-01
      • 2021-08-10
      • 2021-01-24
      相关资源
      最近更新 更多