Простое краткое введение в регрессию/классификацию данных временных рядов и преобразователи, а также реализацию в PyTorch.

Я работаю над проектом, в котором используются модели-трансформеры для диагностики нейродегенеративных заболеваний. Идея состоит в том, что если вы можете собрать данные о передвижении пациента, вы сможете проанализировать эти данные и определить, болен ли пациент и насколько он болен. Это пример регрессии и классификации временных рядов, и модели преобразователя, которые много раз использовались в задачах НЛП, очень хорошо подходят для этой задачи [1].

В этой статье я представлю простое введение в данные временных рядов, модели трансформаторов и их адаптацию к поставленной задаче, а также приведу очень краткое тематическое исследование.

Как обычно, я буду предоставлять реализацию, и мой код доступен на моем GitHub.

Что такое данные временного ряда?

Очевидный вопрос с простым ответом. Данные временных рядов — это просто ряд точек данных, проиндексированных во временном порядке. Простой пример: измерение температуры за окном каждую минуту в течение дня. В итоге вы получите 24x60 = 1440 измерений температуры во временном порядке. Если подумать, многие данные, которые мы собираем в мире, представляют собой данные временных рядов — подумайте о финансовых данных (курсах акций), данных о погоде или любых данных датчиков в носимых устройствах, которые можно носить.

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

Что мы можем делать с данными временных рядов?

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

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

Классификация является следующей наиболее распространенной: при заданном наборе индексированных по времени точек данных задача состоит в том, чтобы сказать, к какой (заранее определенной) категории относятся данные. Представьте, что мы собрали данные о ходьбе людей, собак и кошек (например, с помощью акселерометра на Apple Watch). Мы хотим иметь возможность определить, какие из них создали данные, когда мы делаем классификацию.

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

В прошлом использование алгоритмов машинного обучения для этих задач оказалось довольно сложной задачей. Оказывается, традиционные методы машинного обучения плохо моделируют дальнодействующие зависимости (поэтому модель будет просто смотреть на данные, которые находятся близко друг к другу при прогнозировании, а не на данные, которые далеко друг от друга) по разным причинам, изложенным в этой замечательной статье. ». Здесь на помощь приходит трансформатор, представленный в 2017 году [2].

Что такое трансформатор?

Обратите внимание, что в следующем обсуждении я могу ссылаться на использование предложений в качестве входных данных для моделей. Преобразователи изначально были созданы для задач обработки языка, и иногда их легче объяснить, используя примеры из языка, а не данные временных рядов. Предложение можно рассматривать как часть данных временного ряда — порядок слов имеет значение.

Я постараюсь объяснить это очень просто, но для тех, кто хочет подробного ознакомления, на Medium есть несколько замечательных статей, таких как эта.

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

Для математического введения в само-внимание, пожалуйста, смотрите здесь. Ниже простая интуиция, стоящая за тем, что он делает.

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

Быстрая коричневая лиса перепрыгивает через ленивую собаку.

Если бы я переводил это на французский, я бы хотел убедиться, что знаю слова, обозначающие лиса и собака по-французски. Я также хотел бы иметь возможность правильно их расположить (т. е. лиса перепрыгивает через собаку, а не наоборот). Возможно, я бы уделял меньше внимания слову the, так как оно не является подлежащим или дополнением предложения. Внимание пытается сделать именно это — оно пытается посмотреть на ввод и увидеть, какие биты ввода более важны для текущей задачи.

Представьте, что у нас есть одно и то же предложение, но задача состоит в том, чтобы выделить цвета из предложения. Внимание будет больше приковано к слову коричневый и меньше к другим словам в предложении.

В примере на гифке выше мы переводим с французского на английский. Если скрытое состояние более выделено, это означает, что внимание придает ему больший вес. Вы увидите, что при создании английского I внимание уделяется только французскому Je. Однако для английского языка a внимание уделяется как suis, так и étudiant . Это связано с тем, что в английском языке нам нужно знать, что идет после связки, чтобы знать, использовать ли a или an в нашем переводе. Если бы последним словом было pomme, перевод был бы таким: Я яблоко. Вот почему внимание полезно — оно позволяет модели понять, что важно для текущей задачи.

Преобразователи для данных временных рядов

Теперь у нас есть своего рода интуиция, стоящая за механизмом внимания. Давайте разберемся, что такое трансформер.

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

В преобразователе энкодер выполняет самообслуживание, как описано выше (чтобы более или менее взвешивать различные части входных данных), а затем пропускает их через уровень прямой связи — хорошее введение см. здесь. Декодер делает наоборот.

В исходном преобразователе, предложенном в [2], авторы фактически заставили кодировщик запускаться 6 раз (т. е. выходной сигнал передавался в другой идентичный кодировщик, который, в свою очередь, имел уровни самообслуживания и прямой связи еще 5 раз), и тому подобное. для декодера.

Адаптация преобразователя для классификации/регрессии

Декодер необходим в случае машинного перевода, потому что мы ожидаем, что на выходе будет последовательность слов, а не просто одно число. В случае данных временных рядов это было бы похоже на прогнозирование, где выход представляет собой ряд точек данных. Смотрите здесь и здесь для примеров этого.

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

Адаптация преобразователя для многомерных данных

Отлично — теперь у нас есть модель на основе преобразователя, которая может принимать ряд индексированных по времени точек данных и выводить классификацию или регрессию. До сих пор мы рассматривали одномерные временные ряды. Это означает, что для каждого момента времени у нас есть только одно измерение (например, температура). К сожалению, большинство данных не так просто — даже данные с одного акселерометра на самом деле имеют три точки для каждого временного шага (по одной для каждой оси, x, y и z). В моем случае — при использовании трансформаторов для диагностики заболеваний по данным датчика движения — у меня 17 датчиков вокруг тела (всего 17x3=51 точка данных на временной шаг).

Подойдет ли наш преобразователь для этих данных? Ну… вроде. Он не сломается и все равно будет давать какие-то внятные выводы, но мы можем сделать его лучше. Используя эту формулировку внимания, внимание будет относиться ко всем точкам данных на одном временном шаге одинаково и взвешивать их одинаково. Хотя это нормально, это означает, что наша модель будет моделировать только изменения во времени, а не в пространстве.

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

То, что мы на самом деле хотим, изображено справа на изображении выше. В то время как слева каждой переменной на данном временном шаге уделяется одинаковое количество внимания, справа у нас есть внимание, которое может варьироваться как в пространственном, так и во временном измерениях.

Самый простой способ добиться этого описан в [3] — мы линеаризуем наши входные данные. Это означает, что вместо того, чтобы на каждом временном шаге иметь вектор для описания наших данных (одно значение для каждой переменной), мы просто повторяем индекс времени несколько раз, чтобы охватить наши данные. Например, если у нас есть T временных шагов и N переменных, наши входные данные изначально будут иметь форму TxN. В этой модифицированной версии вместо этого у нас будет ввод NT x 1.

Примечание о сложности: вычислительная сложность преобразователя зависит от ширины вектора (первоначально T, теперь NT) как O (T²). Переход от вектора ширины T к NT теперь даст нам вычислительную сложность O(N²T²). В моем случае с 51 измерением это будет означать сложность в 2600 раз больше, чем в исходном случае. Это далеко от идеала, и в статье [3] обсуждаются различные способы смягчения этого (один для другого поста!).

Тестовый пример — распознавание человеческой деятельности (HAR)

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

В исследовании в общей сложности 24 участника разного пола, возраста, веса и роста выполняли 6 действий в 15 испытаниях в одних и тех же условиях и условиях: ходьба вниз по лестнице, ходьба вверх по лестнице, ходьба, бег трусцой, сидя и стоя. Задача такова: по 2,5-секундному фрагменту данных, снятому с акселерометра iPhone 6s, можем ли мы определить, какое из этих действий выполняется?

Таким образом, набор данных представляет собой временной ряд с 12 измерениями (по 3 измерения для каждого положения, гравитации, ускорения пользователя и скорости вращения). В исходной статье с использованием различных (нетрансформаторных) методов наиболее эффективные модели смогли получить точность ~ 92%. Когда я попробовал это с ванильным трансформатором выше, тренируясь менее 10 минут и не выполняя настройку гиперпараметров, я смог получить точность 90%.

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

Приложение: реализация в PyTorch

Как обычно, моя реализация доступна на моем GitHub. Пожалуйста, убедитесь, что вы загружаете данные здесь. В моей реализации есть класс Transformer, а также Trainer и DataHandler для удобства обучения в PyTorch. Трансформатор был взят и адаптирован из этого большого репозитория (и бумажного!).

Рекомендации

[1] Вэнь, К., Чжоу, Т., Чжан, К., Чен, В., Ма, З., Ян, Дж. и Сунь, Л., 2022. Преобразователи во временных рядах: обзор. препринт arXiv arXiv:2202.07125.

[2] Васвани, А., Шазир, Н., Пармар, Н., Ушкорейт, Дж., Джонс, Л., Гомес, А.Н., Кайзер, Л. и Полосухин И., 2017. Внимание — это все, что вам нужно. Достижения в области нейронных систем обработки информации, 30.

[3] Григсби Дж., Ван З. и Ци Ю., 2021. Преобразователи дальнего действия для динамического пространственно-временного прогнозирования. препринт arXiv arXiv:2109.12218.

[4] Малекзаде М., Клегг Р. Г., Кавалларо А. и Хаддади Х., 2019 г., апрель. Анонимизация данных мобильных датчиков. В Материалы международной конференции по проектированию и внедрению Интернета вещей (стр. 49–58).