Прогнозирование временных рядов с использованием Google Temporal Fusion Transformer LSTM-версии RNN с прогнозированием PyTorch и Torch Lightning

В части 1 моего предыдущего блога объяснялось, как применять шаблон Неловко параллельно для ускорения прогнозирования, когда каждая модель обучается независимо, например, с традиционными алгоритмами прогнозирования ARIMA, Prophet и Neural Prophet. Данные, обучение и логические выводы движок Ray распределяет по локальным ядрам ноутбука. Концепция аналогична многопроцессорному пулу, за исключением того, что Ray может обрабатывать более сложные классы и функции. В отличие от многопроцессорной обработки, один и тот же код может выполняться параллельно в любом кластере в любом облаке.

В этом посте объясняется, как использовать Ray для ускорения прогнозирования глубокого обучения при обучении одной большой глобальной модели для прогнозирования множества целевых временных рядов. Зачем это делать? Что ж, часто вещи, которые компания хочет прогнозировать, связаны друг с другом, например, товары для спортивных болельщиков, стиральная и сушильная машины одной марки и цвета, товары в супермаркетах, которые часто покупаются вместе, и т. д. Затем каждый целевой временной ряд используется в качестве входных данных. к одной и той же модели, и каждый получает разные выходные данные.

Распараллеливание кода для распределенной среды выполнения глобальных моделей глубокого обучения требует распределенного параллелизма данных и параллелизма моделей. Это требует координации между распределенными вычислительными рабочими процессами для разделения данных, совместного использования градиентов между рабочими процессами, каждый со своим собственным сегментом данных, и объединения градиентов в единую глобальную модель. Ray управляет параллелизмом данных и моделей, сохраняя при этом простой API для разработчиков. Кроме того, Рэй может параллельно обучать модель глубокого обучения и делать выводы, распределяя ее по ядрам одного ноутбука или по вычислительным узлам в любом облаке.

Этот блог организован по следующим темам:

  • Введение в алгоритмы искусственного интеллекта глубокого обучения, используемые в прогнозировании
  • Использование Temporal Fusion Transformer от Google в прогнозировании Pytorch (использует PyTorch Lightning API)
  • Как ускорить обучение модели и вывод с помощью Ray
  • Как ускорить обучение моделей и логические выводы в любом облаке с помощью Anyscale

Введение Алгоритмы искусственного интеллекта глубокого обучения, используемые в прогнозировании

Рекуррентная нейронная сеть (RNN) – это тип нейронной сети, который часто используется для временных рядов, поскольку он последовательно обрабатывает данные. RNN состоит из последовательности ANN (искусственная нейронная сеть), обычно 1 ANN на временной шаг. Архитектура RNN допускает последовательный ввод и последовательный вывод. Каждый стандартный блок ИНС сам по себе представляет собой набор нейронов, разделенных на входной слой, скрытые слои и выходной слой, где каждый нейрон связан с другими нейронами, и каждое соединение имеет обучаемый вес. RNN были впервые использованы для перевода текста.

Ниже приведены некоторые связанные концептуальные термины.

LSTM (Long Short-Term Memory) – это тип рекуррентной архитектуры нейронной сети, предназначенный для преодоления проблемы исчезающего градиента (где в прошлом значения весов могли приближаться к нулевым). LSTM имеет 3 шлюза памяти, которые вместе позволяют сети запоминать и забывать.

GRN или закрытая остаточная сеть могут заменить базовый строительный блок ANN. В частности, он состоит из: 2 плотных слоев и 2 функций активации (экспоненциальный линейный блок ELU и линейный блок GLU). Это позволяет сети понять, какие входные преобразования являются простыми, какие требуют более сложного моделирования, а какие следует полностью пропустить.

Модель кодировщик-декодер — это тип RNN, в котором входная последовательность данных (данные для обучения) может иметь длину, отличную от выходной последовательности (проверочные или тестовые данные, иначе называемые горизонтом прогнозирования). Позиционные кодировки добавляются к входным вложениям, чтобы указать положение ввода относительно всей временной последовательности.

Механизм самообслуживания — это эволюция, разработанная для решения проблемы дальней зависимости LSTM (из-за ворот забвения LSTM важная информация может быть потеряна). Добавляя преобразователь, определенные входы могут привлечь больше «внимания», чем прямая связь через сеть RNN. На каждом временном шаге вычисляются обучаемые веса как функция Query (конкретного входного вектора относительно других входных данных), Key (вложений входных данных, которые также содержат этот запрос ) и значение V (выходной вектор, обычно вычисляемый скалярным произведением из полученных весов Q,K). Выходы передаются через сеть RNN. Поскольку все Q,K вычисляются из одного и того же входа, который, в свою очередь, применяется к одному и тому же входу, этот процесс называется «самовниманием».

Многоголовое внимание использует несколько преобразований Q,K на каждом временном шаге. Чистое само-внимание использует все исторические данные на каждом временном шаге. Например, если h = 4 головки внимания, входные данные разбиваются на 4 фрагмента, затем к каждому фрагменту применяется собственное внимание с использованием матриц Q, K для получения 4 различных векторов V-оценки. Это означает, что один вход проецируется на 4 разных «подпространства представления», а те передаются через сеть RNN. В результате внимание к себе становится более тонким. С точки зрения распределенных вычислений это идеально, поскольку каждый фрагмент h из многоголового внимания может выполняться асинхронно на отдельном процессоре или рабочем потоке.

Бэктестинг. Данные обучения и проверки разбиты на пакеты скользящих окон (каждый пакет представляет собой предыдущий пакет, сдвинутый на 1 значение в будущем). Этот метод называется «бэк-тестирование», поскольку вы не можете взять случайную выборку 80/20 для обучения/тестирования, как обычно. Последовательный порядок данных должен быть сохранен. Временные ряды обычно берут окно данных размером context_length для обучения, а затем другое окно размера Prediction_length для проверки.

Пример использования реализации Google Temporal Fusion Transformer в Pytorch Forecasting

Набор данных, используемый в этом руководстве, представляет собой исторические объемы поездок Желтого такси Нью-Йорка за 8 месяцев.

Наш объект кодирования данных будет генератором для многократного сворачивания последовательных данных с использованием метода тестирования на исторических данных. Чтобы позаботиться об исключении тренда, мы будем использовать групповой нормализатор PyTorch Forecasting или пакетную норму для каждого элемента item_id. Каждый пакет разделен на 63-часовые входные данные для обучения и 168-часовые или 1-недельные цели прогнозирования. То есть данные обучаются/достоверны с использованием длины окна 63/168, чтобы сохранить последовательный порядок данных неповрежденным.

Проект сети будет представлять собой LSTM-версию RNN со строительными блоками GRN, кодировщиком-декодером и многоголовым вниманием. Мы будем использовать реализацию PyTorch Forecasting Temporal Fusion Transformer от Google. PyTorch Forecasting — это набор удобных API для PyTorch Lightning. PyTorch Lightning, в свою очередь, представляет собой набор удобных API поверх PyTorch. Это похоже на то, как Keras представляет собой набор удобных API-интерфейсов поверх TensorFlow.

Код демо на github.

Пример того, как ускорить обучение модели и вывод с помощью Ray

Ray — это библиотека с открытым исходным кодом, разработанная в RISELab из Калифорнийского университета в Беркли, который также разработал Apache Spark. Ray упрощает распараллеливание и распространение кода Python. Затем код может выполняться на ядрах любого типа: а) на ядрах вашего ноутбука, б) на кластере в AWS, GCP или любом обычном облаке.

В оставшейся части поста предполагается, что у вас уже определена модель PyTorch Lightning либо с помощью ванильного PyTorch Lightning, либо с помощью прогнозирования PyTorch. Части кода, которые необходимо изменить, чтобы заставить его работать на Ray, выделены ниже жирным шрифтом.

Шаг 1. Установите и импортируйте Ray, Ray Plugin для PyTorch Lightning и Anyscale. Убедитесь, что ваша версия PyTorch Lightning – 1.4.

# Install these libraries in your conda environment  
conda install pytorch  
pip install pytorch_lightning==1.4   #required version for ray  
pip install git+https://github.com/jdb78/pytorch-forecasting@maintenance/pip-install  #used at time of writing this blog, check for updates  
pip install ray  
pip install anyscale  
pip install ray_lightning
# Import these libraries in your .py or .ipynb code     
import torch   
import pytorch_lightning as pl    
import pytorch_forecasting as ptf   
import ray  
from ray_lightning import RayPlugin
# PyTorch visualization uses Tensorboard
import tensorflow as tf #Tensorflow
import tensorboard as tb  #Tensorboard
#compatibility for PyTorch
tf.io.gfile = tb.compat.tensorflow_stub.io.gfile

Шаг 2. Инициализируйте Ray для количества ядер вашего ноутбука (это поведение по умолчанию). У меня было 8 ядер.

# initialize ray, detects and uses all available CPU by default
ray.init()

Шаг 3. Инициализируйте подключаемый модуль Ray Lightning, также для количества ядер на вашем ноутбуке.

# initialize the Ray Lightning plugin
plugin = \      
   RayPlugin(           
      num_workers=8,  #fixed num CPU        
      num_cpus_per_worker=1,           
      use_gpu=False,  #True or False    
      find_unused_parameters=False, #skip warnings    
   )

Шаг 4.Преобразуйте данные в тензоры PyTorch и определите загрузчики данных прогнозирования PyTorch, как обычно. API-интерфейс PyTorch Forecasting data loaders удобно автоматически сворачивает тензоры в окна обучения/тестирования.

Затем измените PyTorch Lightning Trainer, чтобы использовать подключаемый модуль Ray. Добавьте параметр plugins=[ray_plugin] ниже.

Примечание. Демонстрационные данные находятся в том же репозитории github, что и код. Данные уже объединены в почасовые поездки на такси по местам в Нью-Йорке.

# read data into pandas dataframe
filename = "data/clean_taxi_hourly.parquet"
df = pd.read_parquet(filename)
# keep only certain columns
df = df[["time_idx", "pulocationid", "day_hour",
         "trip_quantity", "mean_item_loc_weekday",
         "binned_max_item"]].copy()
# convert data to PyTorch tensors and PyTorch Forecasting loaders 
# PyTorch Forecasting folds tensors into backtest windows
train_dataset, train_loader, val_loader = \
     convert_pandas_pytorch_timeseriesdata(df)
# define the pytorch lightning trainer
trainer = pl.Trainer(      
     max_epochs=EPOCHS,      
     gpus=NUM_GPU,      
     gradient_clip_val=0.1,        
     limit_train_batches=30,       
     callbacks=[lr_logger, 
                early_stop_callback],      
     # how often to log, default=50      
     logger=logger,      
     # To go back to regular python - just comment out below      
     # Plugin allows Ray engine to distribute objects     
     plugins=[ray_plugin] 
     )

Наконец, определите модель PyTorch Lightning (или Forecasting), как обычно. И подходит к модели, как обычно.

# define a pytorch forecasting model
model = ptf.models.TemporalFusionTransformer.from_dataset(   
             train_dataset,      
             learning_rate=LR,      
             hidden_size=HIDDEN_SIZE,      
             attention_head_size=ATTENTION_HEAD_SIZE,      
             dropout=DROPOUT,    
             hidden_continuous_size=HIDDEN_CONTINUOUS_SIZE,   
             loss=ptf.metrics.QuantileLoss(),      
             log_interval=10,      
             reduce_on_plateau_patience=4, 
             )
# fit the model on training data
trainer.fit(
     model,      
     train_dataloaders=train_loader,         
     val_dataloaders=val_loader, 
)
# get best model from the trainer
best_model_path = trainer.checkpoint_callback.best_model_path
best_model = \
ptf.models.TemporalFusionTransformer.load_from_checkpoint(
     best_model_path
)

Вот и все! Теперь ваша модель PyTorch Lightning будет работать распределенно. За кулисами API-интерфейсы подключаемого модуля Ray Lightning вместе с Ray автоматически распределяют как данные, так и модели. Входные данные автоматически полностью сегментируются, сегменты данных и обучающие функции помещаются в каждый параллельный рабочий процесс, градиенты распределяются между рабочими процессами, создается одна глобальная модель, и результирующая модель возвращается в соответствии с запрошенным типом (тип модели PyTorch Lightning или PyTorch Forecasting).

Ранее я пытался обучить эту модель на своем ноутбуке, но прервал выполнение через несколько часов, так как первая эпоха еще не закончилась. После распространения кода с Рэем тот же код запускается примерно через 1 час.

Эти небольшие изменения позволили обучить очень точную глобальную модель прогнозирования глубокого обучения примерно за 1 час на довольно небольшом вычислительном ресурсе (моем ноутбуке).

Еще одно преимущество Ray заключается в том, что теперь код выполняется параллельно на моем ноутбуке, и я могу запускать ОДИНАКОВЫЙ код в любом облаке, используя Anyscale, что я покажу далее.

Как ускорить обучение моделей и логические выводы в любом облаке с помощью Anyscale

Затем, чтобы быстрее обучать или делать логические выводы, вы, вероятно, захотите запустить тот же код в облаке на более крупных экземплярах или в более крупном кластере. Чтобы использовать точно такой же код Ray в облаке (AWS, GCP, …), вам необходимо использовать либо кластер Ray с открытым исходным кодом, либо Anyscale, что упрощает настройку любого облака.

С Anyscale у вас есть выбор: а) выполнять установку pip и клонирование github в конфигурации кластера или б) выполнять их во время выполнения. Дополнительные сведения см. в разделе кластер или среды выполнения. Сначала используется конфигурация кластера, затем конфигурация среды выполнения, если она указана, переопределяет конфигурацию кластера.

Шаги для запуска кода Ray в любом облаке с помощью Anyscale:

Шаг 1. Зарегистрируйтесь в Anyscale и настройте учетную запись.

Шаг 2. Создайте конфигурацию кластера. Я сделал это для удобства, так как у меня было несколько нетипичных новых библиотек ML для установки с зависимостями. Откройте в браузере Консоль Anyscale и в левом меню Configurations нажмите кнопку Create new environment. См. изображение консоли Anyscale ниже.

  1. Cluster environment name. Дайте вашей конфигурации среды любое имя.
  2. Выберите версию Python.
  3. Выберите базовый образ докера. Я выбрал anyscale/ray-ml:1.9.0-python38-gpu.
  4. В разделе Pip packages см. рисунок ниже для установки пакетов и порядка их установки.
  5. Под Post build commands см. рисунок ниже, если вы хотите установить этот демонстрационный код и данные автоматически.
  6. Нажмите кнопку Create.

Запишите свой cluster-config-name:version_number. На скриншоте ниже у меня christy-forecast-pytorch:13. Это понадобится вам для следующего шага.

Шаг 3. Инициализируйте Ray, указав имя облачного кластера и конфигурацию кластера.

import anyscale 
# initialize ray on Anyscale to run on any cloud 
# name your cluster on the fly 
# set cluster_env parameter = your preconfigured cluster config name
ray.init(      
     anyscale://my-cool-cluster, #give your cluster any name   
     cluster_env=christy-forecast-pytorch:13, 
)

Шаг 4. Инициализируйте подключаемый модуль Ray Lightning с параметром num_workers=N, где N › число процессоров на головном узле вашего облачного кластера. Если вы укажете любое число ‹= N, Anyscale не будет масштабироваться. При любом числе › N автомасштабирование Anyscale будет запускаться автоматически, вплоть до предела, настроенного в вашей учетной записи. Установите GPU, если у вас есть доступ к GPU.

plugin = \
     RayPlugin(
          num_workers=10,              
          num_cpus_per_worker=1,              
          use_gpu=True,                  
     )

Теперь запустите свой код Python (или блокнот) как обычно. Он будет автоматически работать параллельно в любом облаке! Во время работы вашего приложения вы можете отслеживать использование облачного кластера в консоли Anyscale в разделе Clusters.

Заключение

В этом блоге показано, как легко включить параллелизм данных и моделей для моделей PyTorch Lightning, используемых для прогнозирования временных рядов. Требовались лишь минимальные изменения кода. После модификации для Ray один и тот же код может работать параллельно на вашем ноутбуке или параллельно в любом облаке через Anyscale.

Полный код демо на github.

Спасибо Яну Бейтнеру, автору PyTorch Forecasting, за то, что он принял мои запросы на слияние и создал отладочный релиз, используемый в этой демонстрации.

Ресурсы

  1. Страницы документа Ray: https://docs.ray.io/en/latest/using-ray.html
  2. Плагин Ray для PyTorch Lightning: https://github.com/ray-project/ray_lightning
  3. Прогнозирование PyTorch: https://pytorch-forecasting.readthedocs.io/en/stable/
  4. Страницы документации Anyscale: https://docs.anyscale.com/get-started
  5. Документ об алгоритме Temporal Fusion Transformer: https://arxiv.org/pdf/1912.09363.pdf
  6. Справочная информация о RNN, используемом в прогнозировании: https://assets.amazon.science/0b/93/4117a5014af5a5dd487d7ffd74ab/deep-state-space-models-for-time-series-forecasting.pdf
  7. Справочная информация об алгоритмах прогнозирования временных рядов: https://towardsdatascience.com/the-best-deep-learning-models-for-time-series-forecasting-690767bc63f0
  8. Справочная информация о параллелизме данных и моделей: https://arxiv.org/abs/1404.5997

Первоначально опубликовано на https://www.anyscale.com.