Изучение набора данных НАСА по ТРДД

LSTM для профилактического обслуживания турбовентиляторных двигателей

Объяснение генерации последовательности, заполнения и настройки гиперпараметров для FD004

‹отказ от ответственности Я стремлюсь продемонстрировать влияние различных методов и вариантов, сделанных во время разработки модели. Эти эффекты часто демонстрируются с помощью набора тестов, что считается (очень) плохой практикой, но помогает в образовательных целях. ›

В последнем посте мы разработали MLP с запаздывающими переменными для FD002, набора данных, в котором двигатели работают в шести различных рабочих условиях. Сегодня мы подведем итоги этой серии и разработаем LSTM для набора данных FD004, в котором двигатели могут вырабатывать два разных отказа в дополнение к работе в нескольких рабочих условиях. Это самая большая проблема в наборе данных НАСА по ТРДД, но мы можем использовать множество строительных блоков из прошлого раза. Давайте начнем!

Загрузка данных

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

Затем мы загрузим данные и проверим первые несколько строк.

Хорошо смотритесь. Как обычно, мы вычисляем оставшийся полезный срок службы (RUL) обучающей выборки.

Как и в предыдущем посте, эти двигатели работают в нескольких режимах. Создание графиков не принесет нам пользы без предварительной обработки. Итак, давайте создадим базовую модель, прежде чем продолжить наш анализ.

Базовая модель

Для базовой модели мы обучим линейную регрессию на доступных датчиках и настройках двигателя. Мы установим верхний предел вычисляемого RUL равным 125, так как он лучше отражает то, что мы знаем о RUL [1] двигателей.

# returns
# train set RMSE:21.437942286411495, R2:0.7220738975061722
# test set RMSE:34.59373591137396, R2:0.5974472412018376

В нашей базовой модели RMSE тренировки составляет 21,43, а тестовая RMSE - 34,59, что будет лучшим показателем. Давайте перейдем к построению графиков, чтобы выбрать наши особенности.

Сюжет

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

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

Как и в прошлый раз, датчики 1, 5, 16 и 19 выглядят одинаково, но не очень полезны.

Сенсоры 2, 3, 4, 11 и 17 показывают аналогичную тенденцию к росту и должны быть включены для дальнейшей разработки модели.

Датчики 6, 10 и 16 не выявляют особых тенденций, мы их опустим.

Сенсоры 7, 12, 15, 20 и 21 ясно показывают различие между двумя развивающимися неисправностями.

Сенсоры 8, 9, 13, 14 показывают аналогичные модели, но с добавлением условия неисправности эти сигналы могут принести больше вреда, чем пользы для характеристик модели. Поскольку сигналы не очень хорошо различают неисправности. Испытание модели с этими датчиками и без них должно показать, должны ли быть включены эти функции.

Датчик 18, похоже, не хранит никакой информации после стандартизации на основе условий. Пора начинать подготовку к нашему LSTM.

LSTM

Объяснение того, как работает LSTM, выходит за рамки этого сообщения, вы можете найти отличные ресурсы в Интернете, если хотите прочитать эту технику [2]. Я сосредоточусь в основном на том, как применять алгоритм. Я выбрал LSTM в основном из-за его способности работать с последовательностями, что является полезным способом упорядочивания данных при работе с таймсериями. Я объясню, как создавать последовательности ниже.

Подготовка данных

Мы можем повторно использовать некоторые функции из прошлого раза, такие как экспоненциальное сглаживание и разделение на проверку.

Экспоненциальное сглаживание - это простой, но мощный алгоритм сглаживания. См. Упрощенную формулу ниже [3].

~Xt = a*Xt + (1 - a)*~Xt-1

Где ~ Xt - отфильтрованное значение Xt, а α - сила фильтра. Альфа может принимать значение от 0 до 1. Когда альфа = 0,8, отфильтрованная точка данных будет состоять из 80% значения в Xt и 20% (уже отфильтрованного) значения в Xt-1. Значения альфа, близкие к 0, приводят к более заметному эффекту сглаживания.

Для проверки модели важно, чтобы записи одного двигателя не разделялись между обучающими и проверочными наборами. LSTM может быть в состоянии правильно прогнозировать проверку, установленную путем интерполяции, что дает ложное представление об ошибке прогнозирования. Когда в модель подаются действительно невидимые данные, она будет работать намного хуже, поскольку она больше не сможет предсказать RUL путем интерполяции. Train_val_group_split разделяет данные таким образом, что все записи одного движка назначаются либо обучающему, либо проверочному набору.

Далее мы обсудим создание последовательностей, используемых моделями LSTM.

Последовательности

В идеале вы бы использовали что-то вроде TimeseriesGenerator из tensorflow для создания своих последовательностей, но есть несколько причин, по которым я предпочитаю использовать собственный код.

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

Во-вторых, таймсерии обычно используют временные точки X для прогнозирования Yt + 1, тогда как я хочу прогнозировать Yt. Прогнозирование Yt вместо Yt + 1 позволяет добиться двух вещей:

(I) Прежде всего, это соответствует всем предыдущим схемам данных, которые мы использовали в этой короткой серии, и

(II) это позволяет нам передать в алгоритм крошечный бит больше данных. Если вы, естественно, использовали предпоследнюю запись для предсказания последней цели, теперь мы можем использовать последнюю запись для предсказания последней цели (см. Рисунок 1 ниже). Хотя для каждого движка требуется всего 1 дополнительная запись, это может иметь значение для очень небольших подмножеств. Например, некоторые движки в тестовой выборке состоят всего из пары записей.

Я был вдохновлен кодом на странице github Microsoft Azure для создания последовательностей [4], но внес некоторые значительные изменения. Код был обновлен для реализации генерации последовательности справа (см. Рисунок 1) и включения дополнительных последовательностей тестового набора (которые я объясню ниже).

Пример фрейма данных с рисунка 1 используется для демонстрации эффектов кода, генерирующего последовательность.

Функция gen_train_data была разработана для получения фрейма данных, содержащего записи одного движка. При создании последовательностей длиной = 4 он может возвращать 2 массива (или последовательности). Один от индекса 0 до индекса 3 включительно, а другой от индекса 1 до индекса 4 включительно. Значения возвращаемых последовательностей должны упростить их проверку на примере фрейма данных (рисунок 1) и понимание того, что происходит. .

Затем мы напишем функцию-оболочку для генерации этих последовательностей для нескольких движков.

Мы сделаем то же самое для ярлыков, чтобы они могли предсказать.

Обратите внимание, что возвращаются 3-е и 4-е значения индекса, соответствующие приведенным выше последовательностям. Опять же, оболочка может генерировать метки для нескольких движков.

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

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

В примере фрейма данных есть 5 строк на движок, в приведенном выше коде мы хотим создать последовательность length = 6. Как и в примере с заполнением, доступные строки возвращаются в виде последовательности с фиктивными значениями с префиксом или дополнениями, чтобы получить желаемую длину последовательности.
Обратите внимание: я поместил значение маски как float, чтобы оно соответствовало другим значениям во фрейме данных.

Теперь у нас есть все строительные блоки для обучения первого LSTM.

Модельное обучение

Сначала мы объединяем все этапы предварительной обработки, чтобы подготовить данные для моделирования.

Исходная модель определяется одним слоем LSTM. Маскирующий слой позволяет нам передавать дополненные фиктивные значения без их интерпретации моделью. Далее мы скомпилируем модель и сохраним ее веса.

Модель перекомпилируется, и ее веса перезагружаются перед обучением для обеспечения воспроизводимости [5].

Обратите внимание, что время обучения примерно в 5 раз выше по сравнению с прошлым MLP. На этом этапе я обычно начинаю изучать облачные вычисления (особенно для настройки гиперпараметров ниже), но в этой серии мы сохраним все на обычном ноутбуке.

Глядя на поезд и потерю валидации, вроде все в порядке. Давайте оценим производительность модели.

# returns:
# train set RMSE:16.55081558227539, R2:0.8388066627963793
# test set RMSE:29.043230109223934, R2:0.7162618665206494

С RMSE 29,043 текущий LSTM уже на 16,04% лучше базовой модели.

Перед настройкой гиперпараметров необходимо проверить еще две вещи;
- (I) производительность модели без датчиков 8, 9, 13 и 14 и
- (II) поведение потери проверки при запуске большего количества эпох.

Чтобы протестировать производительность модели без датчиков 8, 9, 13 и 14, мы должны обновить нашу переменную unknown_sensors.

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

# returns:
# train set RMSE:17.098350524902344, R2:0.8279650412665183
# test set RMSE:29.36311002353286, R2:0.709977307051393

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

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

# returns:
# train set RMSE:15.545417785644531, R2:0.857795579414809
# test set RMSE:29.32099593032191, R2:0.7108086415870063

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

Настройка гиперпараметров

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

Параметры для настройки:
- альфа, сила фильтра
- длина_последовательности
- эпохи
- количество слоев
- узлов на слой
- выпадение
- оптимизатор (я предпочитаю не настраивать этот параметр)
- скорость обучения (я предпочитаю не настраивать этот параметр)
- функция активации
- размер партии
- включенные датчики

Определим возможные значения параметров.

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

Затем мы определим функции для подготовки наших данных и создания модели.

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

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

Я запускал случайный поиск сетки несколько раз с разными вариациями (например, с ранней остановкой и разными диапазонами параметров). Последнее задание по настройке было остановлено после 55 итераций, так как мой ноутбук замедлился до ползания, однако лучший результат, казалось, был довольно стабильным, с потерей проверки немного выше 200 MSE. Посмотрим на результат.

Как видите, итерации без датчиков 8, 9, 13 и 14 не попали в пятерку лучших, что убедительно свидетельствует о том, что лучше оставить эти датчики включенными. Давайте переобучим нашу модель с использованием наиболее эффективных гиперпараметров и проверим результат.

Результат

# returns:
# train set RMSE:12.35975170135498, R2:0.9112171726749143
# test set RMSE:25.35340838205415, R2:0.7837776516770107

Итоговое среднеквадратичное значение теста составляет 25,353, что на 26,71% больше по сравнению с нашей базовой моделью. По сравнению с литературой (см. Обзоры в [3] и [8]), результаты кажутся такими же, как у современных подходов 2017/2018 гг. Что, на мой взгляд, довольно удобно, учитывая, что решение не слишком сложное. Выполнение большего количества итераций, а также настройка оптимизатора и скорости обучения, вероятно, могли бы продвинуть это немного дальше.

Размышления и подведение итогов

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

Я надеюсь, что эта серия статей дала вам хорошее представление о (некоторых) методах профилактического обслуживания. Описание, примеры и объяснения определенно помогли бы мне в начале. Если вы хотите еще больше усовершенствоваться, я бы посоветовал прочитать несколько статей о более сложных архитектурах предварительной обработки и нейронных сетей, а также изменить меру ошибки с RMSE на ту, которая штрафует за поздние прогнозы (см. [3] для примера другого погрешность меры). Еще один интересный подход - рассчитать / спрогнозировать индекс здоровья активов [8–10]. Идея состоит в том, чтобы иметь единый абстрактный KPI, информирующий об общем состоянии оборудования. Вы могли бы разбить его дальше, указав вклад каждого датчика в общую оценку.

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

Вы можете найти полный код на моей странице на github здесь. Я хотел бы поблагодарить Майкла Гроббе за то, что он провел со мной многочисленные обсуждения и просмотрел все мои статьи. Кроме того, я хотел бы поблагодарить вас за чтение и, как всегда, если у вас есть какие-либо вопросы или замечания, пожалуйста, оставьте их в комментариях ниже!

Ссылки
[1] Ф.О. Хаймс, Рекуррентные нейронные сети для оценки оставшегося срока полезного использования, Международная конференция по прогнозированию и управлению здоровьем, 2008 г., Денвер, Колорадо, 2008 г., стр. 1–6, doi: 10.1109 / PHM.2008.4711422.
[2] http://colah.github.io/posts/2015-08-Understanding-LSTMs/
[3] Дуарте Паша, Г., Paixão de Medeiros, I., & Yoneyama, T. (2019). Методы прогнозирования на основе нейронных сетей, инвариантных к рабочему состоянию, применяемые на турбовентиляторных авиационных двигателях. Ежегодная конференция общества PHM, 11 (1). Https://doi.org/10.36001/phmconf.2019.v11i1.786
[4] https://github.com/Azure/lstms_for_predictive_mainasted
[5] Учебник по разработке воспроизводимые нейронные сети в Jupyter Notebook
[6] Чжэн, Алиса. Оценка моделей машинного обучения. O'Reilly Media, Inc., 2015
[7] Дж. Ли, Х. Ли и Д. Хе, Направленная ациклическая графическая сеть в сочетании с CNN и LSTM для прогнозирования оставшегося полезного срока службы, в IEEE Доступ, т. 7, стр 75464-75475, 2019, DOI:.. 10,1109 / ACCESS.2019.2919566
[8] https://www.researchgate.net/profile/Jianjun_Shi/publication/260662503_A_Data-Level_Fusion_Model_for_Developing_Composite_Health_Indices_for_Degradation_Modeling_and_Prognostic_Analysis/links/553e47d80cf20184050e16ea. pdf
[9] http://www.pubmanitoba.ca/v1/exhibits/mh_gra_2015/coalition-10-3.pdf
[10] https: //www.wapa. gov / About / the-source / Documents / AMtoolkitTSSymposium0818.pdf