Ошибка при проверке цели: ошибка измерений в модели CNN-LSTM для многомерного прогнозирования временных рядов.

Вопрос или проблема

Я создаю модель CNN-LSTM для прогнозирования многомерных временных рядов:

       model = Sequential()
       #model.build((10,7,1))
       model.add(Conv1D(filters=64,  kernel_size=2, activation='relu',input_shape=(10,7),strides=1))
       model.add(Conv1D(filters=128, kernel_size=2, activation='relu',strides=1))
       model.add(MaxPooling1D(pool_size=2))
       #model.add(Flatten())
       model.add(LSTM(200,return_sequences=True, activation='relu', recurrent_activation="sigmoid"))
       model.add(Dense(32, activation='sigmoid'))
       model.add(Dense(1))
       model.compile(optimizer="RMSprop", loss="mse",metrics=['accuracy'])
       model.summary()
       print('a new model has been created')

У меня на входе есть 7 признаков (“Временной ряд”) и один выход.

Я создал функцию (make_samples для выборки данных в виде скользящего окна размером 10, в коде называемого n_steps

def make_samples(self,file, n_steps):
    X, y = list(), list()
    data=pd.read_csv(file)
    for i in range(len(data)):
        # find the end of this pattern
        end_ix = i + n_steps
        # check if we are beyond the dataset
        if end_ix > len(data):
            break
        # gather input and output parts of the pattern
        seq_x = data[self.lista].values[i:end_ix]
        seq_y = data["Volume"].values[end_ix-1]
        X.append(seq_x)
        y.append(seq_y)

    return array(X).astype("float32"),array(y).astype("float32")

Когда я передаю эти данные в модель, я получаю следующую ошибку:

Error when checking target: expected dense_30 to have 3 dimensions, but got array with shape (659, 1))

Вопрос в том, почему возникает эта ошибка? И как ее исправить?

Вот сводка

_________________________________________________________________
Layer (type)                 Output Shape              Param    

conv1d_38 (Conv1D)           (None, 9, 64)             960       
_________________________________________________________________
conv1d_39 (Conv1D)           (None, 8, 128)            16512     
_________________________________________________________________
max_pooling1d_18 (MaxPooling (None, 4, 128)            0         
_________________________________________________________________
lstm_18 (LSTM)               (None, 4, 200)            263200    
_________________________________________________________________
dense_29 (Dense)             (None, 4, 32)             6432      
_________________________________________________________________
dense_30 (Dense)             (None, 4, 1)              33        

Заранее большое спасибо

Возможно, вы захотите попробовать использовать класс WindowGenerator из документации TensorFlow:

class WindowGenerator():
  def __init__(self, input_width, label_width, shift,
               train_df=train_df, val_df=val_df, test_df=test_df,
               label_columns=None):
    # Store the raw data.
    self.train_df = train_df
    self.val_df = val_df
    self.test_df = test_df

    # Work out the label column indices.
    self.label_columns = label_columns
    if label_columns is not None:
      self.label_columns_indices = {name: i for i, name in
                                    enumerate(label_columns)}
    self.column_indices = {name: i for i, name in
                           enumerate(train_df.columns)}

    # Work out the window parameters.
    self.input_width = input_width
    self.label_width = label_width
    self.shift = shift

    self.total_window_size = input_width + shift

    self.input_slice = slice(0, input_width)
    self.input_indices = np.arange(self.total_window_size)[self.input_slice]

    self.label_start = self.total_window_size - self.label_width
    self.labels_slice = slice(self.label_start, None)
    self.label_indices = np.arange(self.total_window_size)[self.labels_slice]

  def __repr__(self):
    return '\n'.join([
        f'Total window size: {self.total_window_size}',
        f'Input indices: {self.input_indices}',
        f'Label indices: {self.label_indices}',
        f'Label column name(s): {self.label_columns}'])
```

Ответ или решение

При разработке модели CNN-LSTM для прогнозирования многомерных временных рядов вы столкнулись с ошибкой "Error when checking target: expected dense_30 to have 3 dimensions, but got array with shape (659, 1))". Это связано с несоответствием размерностей выходных данных модели и целевых меток. Давайте разберем подробно, почему это происходит и как устранить эту ошибку.

Теория

При разворачивании временных рядов в кольцевое окно (sliding window) на вход вашей модели подается трехмерная структура данных, имеющая форму (samples, timesteps, features). Каждое измерение выполняет определённую роль:

  1. Samples (Примеры): Количество батчей, которые модель будет обрабатывать.
  2. Timesteps (Шаги по времени): Количество временных шагов (окно) для каждого примера.
  3. Features (Признаки): Количество факторов или временных рядов, которые анализируются.

В вашем случае входной слой Conv1D ожидает форму входного тензора (10, 7), что соответствует 10 шагам по времени и 7 признакам.

Когда мы создаем LSTM слой с return_sequences=True, он возвращает последовательность для каждого временного шага, сохраняя трехмерную форму данных через все выходы LSTM, Dense и другие слои. Если вы хотите, чтобы конечный выход вашего слоя Dense воздействовал только на последний временной шаг, то вам необходимо установить параметр return_sequences=False либо добавить пояснительный слой, который уменьшит размерность до двухмерной (samples, features).

Пример

Посмотрите на структуру вашей модели:

model = Sequential()
model.add(Conv1D(filters=64, kernel_size=2, activation='relu', input_shape=(10, 7), strides=1))
model.add(Conv1D(filters=128, kernel_size=2, activation='relu', strides=1))
model.add(MaxPooling1D(pool_size=2))
model.add(LSTM(200, return_sequences=False, activation='relu'))
model.add(Dense(32, activation='sigmoid'))
model.add(Dense(1))
model.compile(optimizer="RMSprop", loss="mse", metrics=['accuracy'])

Обратите внимание, мы изменили параметр return_sequences на False. Это позволяет избежать возврата полной последовательности и возвращает вместо этого трехмерный тензор, что в конечном итоге преобразует данные к двухмерной форме, необходимой для финальных слоев Dense.

Применение

Чтобы исправить проблему, выполните следующее:

  1. Измените параметр return_sequences в LSTM слое: Установите return_sequences=False, если вам необходимы только последние выходные данные временных шагов, а не полная последовательность.

  2. Преобразуйте выходные данные: Если по-прежнему необходима полная последовательность для последующих слоёв Dense, рассмотрите возможность использования Flatten, GlobalMaxPooling или GlobalAveragePooling слоев, чтобы преобразовать тензор в подходящую форму.

  3. Анализ окна временного ряда: Убедитесь, что полноценные выходные данные для данной задачи имеют нужное количество измерений на этапе окончательного прогнозирования. Если работаете с одномерным выходом, убедитесь, что форма данных соответствует (samples, 1).

  4. Проверка данных: Убедитесь, что подготовленные данные в make_samples соответствуют ожиданиям модели. Оба — и X, и y — должны быть согласованы по количеству выборок.

Эти темы будут гарантировать, что ваш подход к архитектурному дизайну CNN-LSTM модели останется оптимальным и избавит вас от типичных ошибок, связанных с размерностями. Обязательно протестируйте и верифицируйте изменения на небольших наборах данных прежде чем делать выводы на основе большой выборки. Такой подход позволит вам уделять внимание техническим деталям и подкрепить ваши инженерные решения доказанными практиками.

Оцените материал
Добавить комментарий

Капча загружается...