Реализация причинно-следственной связи CNN в Керасе для многомерного прогнозирования временных рядов - PullRequest
2 голосов
/ 24 июня 2019

Этот вопрос является продолжением моего предыдущего вопроса: Многофункциональная причинная реализация CNN - Keras , однако, есть много вещей, которые неясны для меня, так как я думаю, что это требует нового вопроса.Данная модель была построена в соответствии с принятым ответом в посте, упомянутом выше.

Я пытаюсь применить модель Causal CNN к многомерным данным временных рядов из 10 последовательностей с 5 функциями.

lookback, features = 10, 5
  • Какими должны быть установлены фильтры и ядро?

    • Каково влияние фильтров и ядра на сеть?
    • Являются ли они просто произвольным числом - то есть числом нейронов в слое ANN?
    • Или они будут влиять на то, как сеть интерпретирует временные шаги?
  • Какое расширение должно быть установлено?

    • Это просто произвольное число или это lookback модели?
filters = 32
kernel = 5
dilations = 5
dilation_rates = [2 ** i for i in range(dilations)]

model = Sequential()
model.add(InputLayer(input_shape=(lookback, features)))
model.add(Reshape(target_shape=(features, lookback, 1), input_shape=(lookback, features)))

В соответствии с ранее упомянутым ответом, вход должен быть изменен в соответствии со следующей логикой:

  • После Reshape 5 функций вводатеперь рассматривается как временной слой для слоя TimeDistributed
  • Когда Conv1D применяется к каждому входному объекту, он думает, что форма слоя (10, 1)

  • со значением по умолчанию «channel_last", поэтому ...

  • 10 временных шагов - это временное измерение
  • 1 - это "канал", новое местоположение для карт характеристик
# Add causal layers
for dilation_rate in dilation_rates:
    model.add(TimeDistributed(Conv1D(filters=filters,
                              kernel_size=kernel,
                              padding='causal',
                              dilation_rate=dilation_rate,
                              activation='elu')))

Согласнона упомянутый ответ, модель должна быть изменена, в соответствии со следующей логикой:

  • Сложите карты объектов друг на друге, чтобы каждый шаг по времени мог смотреть на все функции, созданные ранее - (10 разшаги, 5 элементов * 32 фильтра)

Далее, причинные слои теперь применяются к 5 входным элементам зависимым образом.

  • Почему они изначально применялись независимо?
  • Почему они теперь применяются зависимо?
model.add(Reshape(target_shape=(lookback, features * filters)))

next_dilations = 3
dilation_rates = [2 ** i for i in range(next_dilations)]
for dilation_rate in dilation_rates:
    model.add(Conv1D(filters=filters,
                     kernel_size=kernel,
                     padding='causal',
                     dilation_rate=dilation_rate,
                     activation='elu'))
    model.add(MaxPool1D())

model.add(Flatten())
model.add(Dense(units=1, activation='linear'))

model.summary()

РЕЗЮМЕ

  • Что должны фильтрыи ядро ​​будет установлено?
    • Будут ли они влиять на то, как сеть интерпретируетe временные шаги?
  • Какие значения расширения должны быть установлены для представления обратного просмотра 10?

  • Почему причинные слои изначально наносятся независимо?

  • Почему они наносятся зависимо после изменения формы?
    • Почемуне применять их с самого начала?

==========================================================================

ПОЛНЫЙ КОД

lookback, features = 10, 5

filters = 32
kernel = 5
dilations = 5
dilation_rates = [2 ** i for i in range(dilations)]

model = Sequential()
model.add(InputLayer(input_shape=(lookback, features)))
model.add(Reshape(target_shape=(features, lookback, 1), input_shape=(lookback, features)))

# Add causal layers
for dilation_rate in dilation_rates:
    model.add(TimeDistributed(Conv1D(filters=filters,
                              kernel_size=kernel,
                              padding='causal',
                              dilation_rate=dilation_rate,
                              activation='elu')))


model.add(Reshape(target_shape=(lookback, features * filters)))

next_dilations = 3
dilation_rates = [2 ** i for i in range(next_dilations)]
for dilation_rate in dilation_rates:
    model.add(Conv1D(filters=filters,
                     kernel_size=kernel,
                     padding='causal',
                     dilation_rate=dilation_rate,
                     activation='elu'))
    model.add(MaxPool1D())

model.add(Flatten())
model.add(Dense(units=1, activation='linear'))

model.summary()

======================================================================================

РЕДАКТИРОВАТЬ:

Даниэль, спасибо за ваш ответ.

Вопрос:

Если вы можете «точно» объяснить, как вы структурируете свои данные, каковаисходные данные и то, как вы преобразуете их в форму ввода, если у вас есть независимые последовательности, если вы создаете скользящие окна и т. д. Можно достичь лучшего понимания этого процесса.

Ответ:

Надеюсь, я правильно понял ваш вопрос.

Каждая функция представляет собой массив последовательностей данных временных рядов.Они независимы, как, например, они не являются изображениями, однако они несколько коррелируют друг с другом.

Именно поэтому я пытаюсь использовать Wavenet, который очень хорош для предсказания одного массива временных рядовОднако моя проблема требует, чтобы я использовал несколько функций.

1 Ответ

3 голосов
/ 27 июня 2019

Комментарии о данном ответе

Вопросы:

  • Почему причинные слои изначально наносятся независимо?
  • Почему они применяются зависимо после изменения формы?
    • Почему бы не применять их с самого начала?

Этот ответ довольно странный. Я не эксперт, но я не вижу необходимости сохранять независимые функции со слоем TimeDistributed. Но я также не могу сказать, дает ли это лучший результат или нет. Сначала я бы сказал, что это просто ненужно. Но это может принести дополнительный интеллект, учитывая, что он может видеть отношения, которые включают в себя отдаленные шаги между двумя функциями вместо того, чтобы просто смотреть на «одинаковые шаги». (Это должно быть проверено)

Тем не менее, в этом подходе есть ошибка .

Изменения формы, предназначенные для обмена задним числом и размерами элементов, не соответствуют ожидаемым. Автору ответа явно хочется поменять оси (сохраняет интерпретацию того, что является особенностью, что есть просмотр), что отличается от изменить (смешивает все, и данные теряют смысл)

Для правильного подхода потребуется замена оси, например model.add(Permute((2,1))) вместо изменения формы.

Итак, я не знаю этих ответов, но, кажется, ничто не создает такой потребности. Одно несомненно: вам наверняка понадобится зависимая часть. Модель не приблизится к интеллекту вашей исходной модели, если она не учитывает отношения между функциями. (Если вам не повезло, что ваши данные полностью независимы)

Теперь объясним связь между LSTM и Conv1D

LSTM можно напрямую сравнить с Conv1D, и используемые формы абсолютно одинаковы, и они означают практически то же самое, если вы используете channels_last.

Тем не менее, форма (samples, input_length, features_or_channels) является правильной формой для LSTM и Conv1D. На самом деле, функции и каналы в этом случае абсолютно одинаковы. Что меняется, так это то, как работает каждый слой относительно длины ввода и расчетов.

Концепция фильтров и ядер

Ядро - это весь тензор внутри слоя конвона, который будет умножен на входные значения для получения результатов. Ядро включает его пространственный размер (kernel_size) и число filters (выходные функции). А также фильтры автоматического ввода.

Ядров нет, но есть kernel_size. Размер ядра - это количество шагов в длине, которые будут объединены для каждого шага вывода. (Этот учебник отлично подходит для непонятных двумерных сверток относительно того, что он делает и каков размер ядра - просто представьте вместо этого 1D-изображения - этот учебник не показывает количество «фильтров», хотя, как 1 -фильтр анимации)

Число filters напрямую связано с числом features, это одно и то же.

Какие фильтры и ядро ​​должны быть установлены?

Итак, если ваш слой LSTM использует units=256, что означает, что он выведет 256 объектов, вы должны использовать filters=256, что означает, что ваша свертка выведет 256 каналов / объектов.

Это не правило, хотя , вы можете обнаружить, что использование большего или меньшего количества фильтров может привести к лучшим результатам, поскольку слои в конце концов делают разные вещи. Нет необходимости иметь все слои с одинаковым количеством фильтров! Здесь вы должны пойти с настройкой параметров. Проверьте, какие цифры лучше всего подходят для вашей цели и данных.

Теперь размер ядра не сравнится с LSTM. Это новая вещь, добавленная в модель.

Число 3 - очень распространенный выбор. Это означает, что свертка потребует три временных шага, чтобы произвести один временной шаг. Затем сдвиньте один шаг, чтобы выполнить другую группу из трех шагов, чтобы произвести следующий шаг и так далее.

дилатация

Расширения означают, сколько промежутков между шагами будет иметь фильтр свертки.

  • Свертка dilation_rate=1 предпринимает kernel_size последовательных шагов, чтобы произвести один шаг.
  • Свертка с dilation_rate = 2 требует, например, шагов 0, 2 и 4 для получения шага. Затем выполняются шаги 1,3,5 для создания следующего шага и так далее.

Какое расширение должно быть установлено для представления обратного хода 10?

range = 1 + (kernel_size - 1) * dilation_rate

Итак, с размером ядра = 3:

  • Dilation = 0 (dilation_rate = 1): размер ядра будет составлять 3 шага
  • Дилатация = 1 (dilation_rate = 2): размер ядра будет в диапазоне 5 шагов
  • Дилатация = 2 (dilation_rate = 4): размер ядра будет составлять 9 шагов
  • Dilation = 3 (dilation_rate = 8): размер ядра будет составлять 17 шагов

Мой вопрос к тебе

Если вы можете «точно» объяснить, как вы структурируете свои данные, каковы исходные данные и как вы преобразуете их в форму ввода, если у вас есть независимые последовательности, если вы создаете скользящие окна и т. Д. Лучшее понимание этого процесса может быть достигнуто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...