Осмысление больших данных

TensorFlow 2: как использовать AutoEncoder для интерполяции

Краткое руководство по использованию TensorFlow 2 с AutoEncoder для интерполяции и устранения шумов

Автоэнкодер

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

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

Обратной стороной использования Autoencoder для интерполяции является то, что сжатые данные представляют собой черный ящик - мы не знаем структуру данных в сжатой версии. Предположим, у нас есть набор данных с 10 параметрами, и мы обучаем автоэнкодер по этим данным. Кодировщик не пропускает некоторые параметры для лучшего представления, но объединяет параметры для создания сжатой версии, но с меньшим количеством параметров (снижает количество параметров, скажем, до 5 из 10). Автоэнкодер состоит из двух частей: кодировщика и декодера. Кодер сжимает входные данные, а декодер делает противоположное, чтобы создать несжатую версию данных для создания восстановленного входного сигнала, максимально приближенного к исходному.

Методы интерполяции

Интерполяция - это процесс угадывания значения функции между двумя точками данных. Например, вам даны x = [1, 3, 5, 7, 9] и y = [230.02, 321.01, 305.00, 245.75, 345.62] и на основе заданных данных вы хотите узнать значение y при x = 4. В литературе доступно множество методов интерполяции - некоторые из них основаны на моделях, а некоторые - без моделей, то есть на основе данных. Наиболее распространенный способ достижения интерполяции - подгонка данных. Например, вы используете линейный регрессионный анализ, чтобы подогнать линейную модель к заданным данным.

В линейной регрессии с учетом объясняющей / предиктивной переменной X и переменной ответа Y данные подбираются по формуле Y = β0 + β1X, где β0 и β1 определяются с помощью аппроксимации методом наименьших квадратов. Как следует из названия, линейная регрессия является линейной, т. Е. Соответствует прямой, даже если связь между предиктором и переменной ответа может быть нелинейной.

Однако наиболее общий вид интерполяции - это подгонка полиномами. Учитывая k точек выборки, легко подобрать полином степени k. Учитывая набор данных {xi, yi}, полиномиальная аппроксимация получается путем определения полиномиальных коэффициентов ai функции

путем решения обращения матрицы из следующего выражения:

Когда у нас есть коэффициенты ai, мы можем найти значение функции f для любого x.

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

Однако суть этой статьи не в подгонке полиномов, а в интерполяции. Подгонка полиномов происходит просто для облегчения интерполяции. Однако существует проблема с методами подбора полиномов - будь то параметрический или непараметрический, они ведут себя так, как их учат. Это означает, что если данные чистые, подгонка будет чистой и плавной, но если данные зашумлены, подгонка будет шумной. Эта проблема чаще встречается в данных датчика, например, в данных о частоте пульса, данных о расстоянии от LiDAR, данных о скорости CAN Bus от вашего автомобиля, данных GPS и т. Д.



Кроме того, из-за шума с ними труднее справиться, особенно если ваш алгоритм требует выполнения двойной или второй производной для таких данных. Как правило, эти данные датчиков представляют собой данные временного ряда, то есть они собираются с течением времени, поэтому переменная отклика может быть некоторой физической величиной, такой как скорость, расстояние до объектов от LiDAR, установленного на крыше беспилотного автомобиля, частота сердечных сокращений. , а предикторная переменная - время. При работе с такими данными может быть несколько целей: я хочу, чтобы данные были интерполированы до некоторой отметки времени, по которой мой датчик не мог записать какой-либо ответ, но поскольку датчики работают в реальном времени и из-за лежащих в основе физика, эти данные остаются зашумленными, мне также нужна надежная интерполяция, на которую не влияет шум сенсора. Кроме того, мое требование может также включать производные от таких временных рядов данных. Производные имеют тенденцию усиливать шум, присутствующий в данных базового временного ряда. Что, если есть способ, с помощью которого я могу получить базовое представление данных, одновременно отбрасывая шум? Автоэнкодер приходит на помощь, чтобы достичь моей цели в таком случае.

Автоэнкодер как интерполятор

Чтобы продемонстрировать цель шумоподавления + интерполяции с использованием автоэнкодера, я использую пример данных о расстоянии, собранных с транспортного средства моей лабораторией, где переменная ответа - это расстояние до транспортного средства впереди моего транспортного средства, а предиктор - время. Я сделал небольшой набор данных доступным в моем репозитории GitHub в рамках демонстрации, которую вы можете использовать. Однако он действительно маленький и не служит никакой цели, кроме руководства, описанного в этой статье.



Ладно, пора писать код.

Примечание. Прежде чем использовать данные, я должен указать, что время (предсказатель) и сообщение (ответ) должны быть перемасштабированы. В моем случае исходное время начинается с 1594247088.289515 (в формате POSIX в секундах) и заканчивается на 1594247110.290019. Я нормализовал свою временную стоимость с помощью формулы (time - start_time)/(end_time - start_time). Точно так же переменная ответа была нормализована с помощью (message - message_min)/(message_max -message_min). Образцы данных, представленные в моем GitHub, уже нормализованы, и вы можете повторно использовать их прямо из коробки.

Обучение

import glob
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
df = pd.read_csv("../data/lead_dist_sample.csv")
time = df['Time']
message = df['Message']
import tensorflow as tf
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(units = 1, activation = 'linear', input_shape=[1]))
model.add(tf.keras.layers.Dense(units = 128, activation = 'relu'))
model.add(tf.keras.layers.Dense(units = 64, activation = 'relu'))
model.add(tf.keras.layers.Dense(units = 32, activation = 'relu'))
model.add(tf.keras.layers.Dense(units = 64, activation = 'relu'))
model.add(tf.keras.layers.Dense(units = 128, activation = 'relu'))
model.add(tf.keras.layers.Dense(units = 1, activation = 'linear'))
model.compile(loss='mse', optimizer="adam")
model.summary()
# Training
model.fit( time, message, epochs=1000, verbose=True)

Как видите, я не выполнял никакой регуляризации, поскольку я намеренно хочу выполнить переобучение, чтобы в полной мере использовать основную природу данных. Пришло время сделать прогноз. Вы увидите, что я масштабировал временную ось до исходных значений, прежде чем делать прогнозы. В этом примере у меня былиtime_original[0] = 1594247088.289515, time_original[-1] = 1594247110.290019, msg_min = 33, msg_max = 112

newtimepoints_scaled = np.linspace(time[0] - (time[1] - time[0]),time[-1], 10000)
y_predicted_scaled = model.predict(newtimepoints_scaled)
newtimepoints = newtimepoints_scaled*(time_original[-1] - time_original[0]) + time_original[0]
y_predicted = y_predicted_scaled*(msg_max - msg_min) + msg_min

Обратите внимание, что я создаю более плотные временные точки в переменной newtimepoints_scaled, которая позволяет мне интерполировать данные в невидимые временные точки. Наконец, вот кривая:

# Display the result
import matplotlib.pylab as pylab
params = {'legend.fontsize': 'x-large',
          'figure.figsize': (15, 5),
         'axes.labelsize': 'x-large',
         'axes.titlesize':'x-large',
         'xtick.labelsize':'x-large',
         'ytick.labelsize':'x-large'}
pylab.rcParams.update(params)
plt.scatter(time*(1594247110.290019 - 1594247088.289515) + 1594247088.289515, message*(112 - 33) + 33, label='Original Data')
plt.scatter(newtimepoints, y_predicted, c = 'red', s = 1, label = 'Interpolated Data')
plt.xlabel('Time')
plt.ylabel('Message')
plt.legend()
plt.show()

Заключительные замечания

Хотя я тренировался всего 1000 эпох, ваше обучение может быть не таким коротким, если у вас большие данные. Самым большим преимуществом этого метода является получение производных, так как из следующего графика ясно, что производная, выполняемая на исходных данных, плохая - может даже не представлять истинную производную!

df_interpolation = pd.DataFrame()
df_interpolation['Time'] = newtimepoints
df_interpolation['Message'] = y_predicted
df_interpolation['diff'] = df_interpolation['Message'].diff()/df_interpolation['Time'].diff()
df_original = pd.DataFrame()
df_original['Time'] = time*(1594247110.290019 - 1594247088.289515) + 1594247088.289515
df_original['Message']  = message*(112 - 33) + 33
df_original['diff'] = df_original['Message'].diff()/df_original['Time'].diff()
# Display the result
import matplotlib.pylab as pylab
params = {'legend.fontsize': 'x-large',
          'figure.figsize': (15, 5),
         'axes.labelsize': 'x-large',
         'axes.titlesize':'x-large',
         'xtick.labelsize':'x-large',
         'ytick.labelsize':'x-large'}
pylab.rcParams.update(params)
plt.scatter(df_original['Time'], df_original['diff'], label='Derivative on Original Data')
plt.scatter(df_interpolation['Time'], df_interpolation['diff'], s= 10, c = 'red', label='Derivative on Interpolated Data')
plt.xlabel('Time')
plt.ylabel('Message')
plt.legend()
plt.show()

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

Блокнот для воспроизведения этого руководства можно найти на моем GitHub по адресу

Https://github.com/rahulbhadani/medium.com/blob/master/01_02_2021/AutoEncoder_Interpolation_TF2.ipynb.

Расширенная версия статьи размещена на ArXiv.org.

Если эта статья принесет вам пользу, пожалуйста, используйте следующие цитаты, чтобы ссылаться на мою работу:

Rahul Bhadani. Autoencoder for interpolation. arXiv preprint arXiv:2101.00853, 2021.

or

@article{bhadani2021autoencoder,
    title={AutoEncoder for Interpolation},
    author={Rahul Bhadani},
    year={2021},
    eprint={2101.00853},
    archivePrefix={arXiv},
    primaryClass={stat.ML},
  journal={arXiv preprint arXiv:2101.00853},
}

Если вам понравилась эта статья, вы захотите узнать больше о том, как использовать TensorFlow 2. Ознакомьтесь с некоторыми из моих других статей о TensorFlow 2: