Обзор
Это последняя статья из серии об использовании машинного обучения для прогнозирования средней температуры.В качестве последней статьи я буду использовать платформу машинного обучения Google с открытым исходным кодом tensorflow для построения регрессора нейронной сети. Для введения, установки и знакомства с tensorflow, пожалуйста, погуглите сами, и я не буду описывать это здесь.
В этой статье я в основном объясняю следующие моменты:
- Понимание теории искусственных нейронных сетей
- высокоуровневый API tensorflow: Оценщики
- Построение модели DNN для предсказания погоды
Базовая теория искусственной нейронной сети
В предыдущей статье в основном объяснялось, как построить модель линейной регрессии (которая является самым простым алгоритмом машинного обучения) для прогнозирования среднесуточной температуры в Линкольне, штат Небраска. Модели линейной регрессии очень эффективны и могут использоваться для числовых (например, классификация) и предсказания (например, предсказание погоды). Алгоритм линейной регрессии также относительно ограничен, он требует линейной зависимости между данными. Существует бесчисленное множество алгоритмов интеллектуального анализа данных и машинного обучения для работы со сценариями нелинейных отношений. Наиболее популярным в последние годы является нейросетевой алгоритм, который может справиться со многими задачами в области машинного обучения. Алгоритмы нейронных сетей способны использовать как линейные, так и нелинейные алгоритмы обучения. Нейронные сети вдохновлены биологическими нейронами в мозге, которые работают в сложных взаимодействующих сетях для передачи, сбора и изучения информации на основе истории информации, которая была собрана. Интересующие нас вычислительные нейронные сети аналогичны нейронам головного мозга тем, что представляют собой наборы нейронов (узлов), которые получают входные сигналы (цифровые величины), обрабатывают ввод и отправляют обработанные сигналы другим нижестоящим агентам. Интернет. Обработка сигналов как цифровых величин с помощью нейронных сетей — очень мощная функция, которая не ограничивается линейными отношениями. В этой серии я сосредоточился на конкретном типе машинного обучения, называемом обучением с учителем, что означает, что результаты обучающих данных известны, а выходные данные, соответствующие будущим входным данным, прогнозируются на основе ранее известных входных и выходных данных. . . . Кроме того, тип прогнозирования — это истинное значение значения, что означает, что мы используем алгоритм прогнозирования регрессии. Графически нейронная сеть, аналогичная описанной в этой статье, представлена на рисунке:Нейронная сеть, описанная выше, содержит входной слой в крайнем левом углу, x1 и x2 на рисунке, эти две функции являются входными значениями нейронной сети. Эти две функции передаются в нейронную сеть для обработки и передачи через два слоя нейронов, называемых скрытыми слоями. Это описание показывает два скрытых слоя, каждый из которых содержит три нейрона (узла). Затем этот сигнал покидает нейронную сеть и агрегируется в выходном слое как единый числовой предиктор. Позвольте мне воспользоваться моментом, чтобы объяснить значение стрелок, которые представляют обработку передачи данных между слоями с одного узла на другой. Каждая стрелка представляет собой математическое преобразование числового значения, начиная с нижней части стрелки и умножая на вес, характерный для этого пути. Таким образом, каждый узел в слое получит значение. Затем просуммируйте все значения, которые сходятся в узлах. Это линейная работа нейронной сети, о которой я упоминал ранее. После суммирования в каждом узле к сумме применяется специальная нелинейная функция, которая изображена как Fn(...) на изображении выше. Эта специальная функция введения нелинейных функций в нейронную сеть называется функцией активации. Эта нелинейность, вызванная функцией активации, придает многослойной нейронной сети ее мощь. Если бы в процесс не была добавлена нелинейность, все слои были бы эффективно объединены алгебраически в одну постоянную операцию, состоящую из умножения входных данных на некоторое значение плоского коэффициента (т. е. линейная модель). Ну, это все хорошо, но как это перевести на алгоритм обучения? Таким образом, наиболее простым ответом является оценка текущего прогноза, выходных данных модели «y», до фактического ожидаемого значения (целевого значения) и выполнение ряда корректировок весов для повышения общей точности прогноза. В мире регрессионных алгоритмов машинного обучения точность оценивается с помощью функции стоимости (т. е. «потери» или «цели») (т. е. суммы квадратов ошибок (SSE)). Обратите внимание, что я обобщаю это утверждение на весь континуум машинного обучения, а не только на нейронные сети. В предыдущей статье работу выполнил алгоритм обычных наименьших квадратов, который нашел комбинацию коэффициентов, минимизирующую сумму квадратов ошибок (т.е. метод наименьших квадратов). Наш регрессор нейронной сети сделает то же самое. Он перебирает обучающие данные для извлечения значений признаков, вычисляет функцию стоимости (используя SSE) и корректирует веса таким образом, чтобы минимизировать функцию стоимости. Процесс итеративного проталкивания функций через алгоритм и оценки того, как корректируются веса в соответствии с функцией стоимости. Алгоритмы оптимизации модели очень важны для построения надежных нейронных сетей. Например, он проходит через сетевую архитектуру (то есть ширину и глубину), а затем оценивается в соответствии с функцией стоимости, корректируя веса. Когда функция оптимизатора определяет, что корректировка веса не приведет к изменению вычислительной стоимости функции стоимости, говорят, что модель «обучается».
TensorFlow Estimator API
tensorflow состоит из нескольких частей, наиболее часто используемой из которых является Core API, который предоставляет пользователям набор низкоуровневых API для определения и обучения любого алгоритма машинного обучения, использующего символьные операции. Это также основная функция TensorFlow.Хотя Core API может обрабатывать большинство сценариев приложений, я уделяю больше внимания API Estimator. Команда TensorFlow разработала Estimator API, чтобы сделать библиотеку более доступной для обычных разработчиков. Этот API предоставляет модели обучения, модели оценки и интерфейсы прогнозирования для неизвестных данных, аналогичные библиотеке Sci-Kit, что достигается за счет реализации общего интерфейса для различных алгоритмов. Кроме того, в высокоуровневый API встроено множество лучших практик машинного обучения, абстракций и масштабируемости. Все эти преимущества машинного обучения позволяют использовать набор инструментов, реализованных в базовом классе Estimator, а также несколько предварительно упакованных типов моделей, которые снижают порог входа для использования TensorFlow, поэтому его можно применять к повседневным задачам. Абстрагируясь от таких проблем, как написание обучающих циклов или обработка сеансов, разработчики могут сосредоточиться на более важных вещах, таких как быстрое тестирование нескольких моделей и архитектур моделей, чтобы найти ту, которая лучше всего соответствует их потребностям. В этом посте я опишу, как использовать регрессор DNN, один из очень мощных инструментов для оценки глубоких нейронных сетей.
Создание DNNRegressor для предсказания погоды
Сначала мы импортируем некоторые библиотеки, которые нам нужно использовать.
import pandas as pd
import numpy as np
import tensorflow as tf
from sklearn.metrics import
explained_variance_score, \
mean_absolute_error, \
median_absolute_error
from sklearn.model_selection import train_test_split
Давайте обработаем данные, я выложил все данные на Github, и вы можете проверить клон.
# read in the csv data into a pandas data frame and set the date as the index
df = pd.read_csv('end-part2_df.csv').set_index('date')
# execute the describe() function and transpose the output so that it doesn't overflow the width of the screen
df.describe().T
# execute the info() function
df.info()
<class 'pandas.core.frame.DataFrame'>
Index: 997 entries, 2015-01-04 to 2017-09-27
Data columns (total 39 columns):
meantempm 997 non-null int64
maxtempm 997 non-null int64
mintempm 997 non-null int64
meantempm_1 997 non-null float64
meantempm_2 997 non-null float64
meantempm_3 997 non-null float64
meandewptm_1 997 non-null float64
meandewptm_2 997 non-null float64
meandewptm_3 997 non-null float64
meanpressurem_1 997 non-null float64
meanpressurem_2 997 non-null float64
meanpressurem_3 997 non-null float64
maxhumidity_1 997 non-null float64
maxhumidity_2 997 non-null float64
maxhumidity_3 997 non-null float64
minhumidity_1 997 non-null float64
minhumidity_2 997 non-null float64
minhumidity_3 997 non-null float64
maxtempm_1 997 non-null float64
maxtempm_2 997 non-null float64
maxtempm_3 997 non-null float64
mintempm_1 997 non-null float64
mintempm_2 997 non-null float64
mintempm_3 997 non-null float64
maxdewptm_1 997 non-null float64
maxdewptm_2 997 non-null float64
maxdewptm_3 997 non-null float64
mindewptm_1 997 non-null float64
mindewptm_2 997 non-null float64
mindewptm_3 997 non-null float64
maxpressurem_1 997 non-null float64
maxpressurem_2 997 non-null float64
maxpressurem_3 997 non-null float64
minpressurem_1 997 non-null float64
minpressurem_2 997 non-null float64
minpressurem_3 997 non-null float64
precipm_1 997 non-null float64
precipm_2 997 non-null float64
precipm_3 997 non-null float64
dtypes: float64(36), int64(3)
memory usage: 311.6+ KB
Обратите внимание, что мы только что записали 1000 записей метеорологических данных, и все функции имеют числовой характер. Кроме того, благодаря нашей тяжелой работе в первом посте все записи завершены, потому что в них не пропущено ни одного значения (нет ненулевых значений). Теперь я уберу столбцы "mintempm" и "maxtempm", так как они бесполезны для предсказания средней температуры. Мы пытаемся предсказать будущее, поэтому у нас явно нет данных о будущем. Я также отделю функции (X) от цели (y).
# First drop the maxtempm and mintempm from the dataframe
df = df.drop(['mintempm', 'maxtempm'], axis=1)
# X will be a pandas dataframe of all columns except meantempm
X = df[[col for col in df.columns if col != 'meantempm']]
# y will be a pandas series of the meantempm
y = df['meantempm']
Как и во всех приложениях машинного обучения с учителем, я разделю свой набор данных на обучающие и тестовые наборы. Однако, чтобы лучше объяснить итеративный процесс обучения этой нейронной сети, я буду использовать дополнительный набор данных, который назову «проверочный набор». Для обучающего набора я буду использовать 80% данных, а для тестового и проверочного наборов каждый из них будет составлять по 10% оставшихся данных. Чтобы разделить эти данные, я снова воспользуюсь функцией train_test_split() из библиотеки Scikit Learn.
# split data into training set and a temporary set using sklearn.model_selection.traing_test_split
X_train, X_tmp, y_train, y_tmp = train_test_split(X, y, test_size=0.2, random_state=23)
# take the remaining 20% of data in X_tmp, y_tmp and split them evenly
X_test, X_val, y_test, y_val = train_test_split(X_tmp, y_tmp, test_size=0.5, random_state=23)
X_train.shape, X_test.shape, X_val.shape
print("Training instances {}, Training features {}".format(X_train.shape[0], X_train.shape[1]))
print("Validation instances {}, Validation features {}".format(X_val.shape[0], X_val.shape[1]))
print("Testing instances {}, Testing features {}".format(X_test.shape[0], X_test.shape[1]))
Training instances 797, Training features 36
Validation instances 100, Validation features 36
Testing instances 100, Testing features 36
Первым шагом при построении модели нейронной сети является создание экземпляра класса tf.estimator.DNNRegressor(). Конструктор класса имеет несколько параметров, но я сосредоточусь на следующих параметрах:
- feature_columns: Структура в виде списка, содержащая имена и определения типов данных функций, которые должны быть введены в модель.
- hidden_units: структура в виде списка, содержащая определения ширины и глубины числа нейронной сети.
- оптимизатор: Экземпляр подкласса tf.Optimizer, который оптимизирует веса модели во время обучения, его значение по умолчанию — оптимизатор AdaGrad.
- активация_fn: функция активации, используемая для внесения нелинейности в сеть на каждом уровне; по умолчанию используется ReLU.
- model_dir: каталог для создания, содержащий метаданные модели и другие сохранения контрольных точек. Я начну с определения списка столбцов числовых функций. Для этого я использую функцию tf.feature_column.numeric_column() для возврата экземпляра FeatureColumn.
feature_cols = [tf.feature_column.numeric_column(col) for col in X.columns]
Теперь, используя столбец определенных функций, я могу создать экземпляр класса DNNRegressor и сохранить его в переменной регрессии. Я указал, что мне нужна нейронная сеть с двумя слоями в глубину, где оба слоя имеют ширину 50 узлов. Я также указал, что хочу, чтобы данные моей модели хранились в каталоге с именем tf_wx_model.
regressor = tf.estimator.DNNRegressor(feature_columns=feature_cols,
hidden_units=[50, 50],
model_dir='tf_wx_model')
INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_tf_random_seed': 1, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_model_dir': 'tf_wx_model', '_log_step_count_steps': 100, '_keep_checkpoint_every_n_hours': 10000, '_save_summary_steps': 100, '_keep_checkpoint_max': 5, '_session_config': None}
Следующее, что я хочу сделать, это определить повторно используемую функцию, обычно называемую «функция ввода», которую я вызову wx_input_fn(). Эта функция будет использоваться для ввода данных в мою нейронную сеть на этапах обучения и тестирования. Существует множество различных способов построения входных функций, но я опишу, как определить и использовать один из них на основе tf.estimator.inputs.pandas_input_fn(), поскольку мои данные находятся в структуре данных pandas.
def wx_input_fn(X, y=None, num_epochs=None, shuffle=True, batch_size=400):
return tf.estimator.inputs.pandas_input_fn(x=X,
y=y,
num_epochs=num_epochs,
shuffle=shuffle,
batch_size=batch_size)
Обратите внимание, что эта функция wx_input_fn() принимает один обязательный параметр и четыре необязательных параметра, которые затем передаются функции ввода TensorFlow специально для возвращаемых данных панд. Это очень мощная функция TensorFlow API. Параметры функции определяются следующим образом:
- X: ввод для подачи в один из трех методов интерфейса DNNRegressor (обучение, оценка и прогнозирование).
- y: целевое значение X, это необязательно и не будет предоставлено вызову прогнозирования.
- num_epochs: необязательный параметр. Новая эпоха наступает, когда алгоритм выполняется один раз для всего набора данных.
- shuffle: необязательный параметр, указывающий, следует ли случайным образом выбирать пакет (подмножество) набора данных при каждом выполнении алгоритма.
- batch_size: количество выборок для включения при каждом выполнении алгоритма.
Определив нашу входную функцию, мы теперь можем обучить нашу нейронную сеть на обучающем наборе данных. Читатели, знакомые с высокоуровневым API TensorFlow, могут заметить, что способ, которым я обучаю свои модели, немного нетрадиционный. По крайней мере, с точки зрения текущих руководств на веб-сайте TensorFlow и других в Интернете. Как правило, вы увидите что-то вроде следующего.
regressor.train(input_fn=input_fn(training_data, num_epochs=None, shuffle=True), steps=some_large_number)
.....
lots of log info
....
Затем автор покажет функцию Assessment() напрямую, с небольшим намеком на то, что она делает или почему существует эта строка кода.
regressor.evaluate(input_fn=input_fn(eval_data, num_epochs=1, shuffle=False), steps=1)
.....
less log info
....
После этого, предполагая, что все обученные модели совершенны, они сразу переходят к выполнению функции прогнозирования().
predictions = regressor.predict(input_fn=input_fn(pred_data, num_epochs=1, shuffle=False), steps=1)
Я надеюсь, что смогу дать разумное объяснение того, как обучать и оценивать эту нейронную сеть, чтобы свести к минимуму риск подгонки или переподгонки этой модели к обучающим данным. Итак, без дальнейших задержек, позвольте мне определить простой цикл обучения, который тренируется на обучающих данных и периодически оценивает данные оценки.
evaluations = []
STEPS = 400
for i in range(100):
regressor.train(input_fn=wx_input_fn(X_train, y=y_train), steps=STEPS)
evaluations.append(regressor.evaluate(input_fn=wx_input_fn(X_val,
y_val,
num_epochs=1,
shuffle=False)))
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Saving checkpoints for 1 into tf_wx_model/model.ckpt.
INFO:tensorflow:step = 1, loss = 1.11335e+07
INFO:tensorflow:global_step/sec: 75.7886
INFO:tensorflow:step = 101, loss = 36981.3 (1.321 sec)
INFO:tensorflow:global_step/sec: 85.0322
... A WHOLE LOT OF LOG OUTPUT ...
INFO:tensorflow:step = 39901, loss = 5205.02 (1.233 sec)
INFO:tensorflow:Saving checkpoints for 40000 into tf_wx_model/model.ckpt.
INFO:tensorflow:Loss for final step: 4557.79.
INFO:tensorflow:Starting evaluation at 2017-12-05-13:48:43
INFO:tensorflow:Restoring parameters from tf_wx_model/model.ckpt-40000
INFO:tensorflow:Evaluation [1/1]
INFO:tensorflow:Finished evaluation at 2017-12-05-13:48:43
INFO:tensorflow:Saving dict for global step 40000: average_loss = 10.2416, global_step = 40000, loss = 1024.16
INFO:tensorflow:Starting evaluation at 2017-12-05-13:48:43
INFO:tensorflow:Restoring parameters from tf_wx_model/model.ckpt-40000
INFO:tensorflow:Finished evaluation at 2017-12-05-13:48:43
INFO:tensorflow:Saving dict for global step 40000: average_loss = 10.2416, global_step = 40000, loss = 1024.16
Приведенный выше цикл повторяется 100 раз. В теле цикла я вызываю метод train() объекта регрессора и передаю его моему повторно используемому wx_input_fn(), который, в свою очередь, передает набор функций обучения и цель. Я намеренно сделал параметр по умолчанию num_epochs равным None, по сути говоря: «Мне все равно, сколько раз вы проходите тренировочный набор, просто продолжайте тренировать алгоритм для каждого по умолчанию batch_size 400» (примерно половина тренировочного набора). Я также установил для параметра перемешивания значение по умолчанию True, чтобы случайным образом выбирать данные во время обучения, чтобы избежать какой-либо взаимосвязи порядка в данных. Последний параметр метода train () — это шаги, которые я установил на 400, что означает, что обучающий набор будет группироваться 400 раз за цикл. Это дало мне хорошее время, чтобы объяснить, что означает эпоха в более конкретных числах. Напомним, что эпоха наступает, когда все записи обучающей выборки обучаются через нейронную сеть один раз. Таким образом, если у нас есть около 800 (797, если быть точным) записей в нашем обучающем наборе, и мы выбираем 400 на пакет, мы делаем один раз каждые два пакета. Итак, если мы переберем весь обучающий набор на 100 итераций по 400 шагов, каждый с размером пакета 400 (полтора раза на пакет), мы получим:
(100 x 400 / 2) = 20,000 epochs
Теперь вам может быть интересно, почему я выполняю метод и оцениваю() для каждой итерации цикла и фиксирую его вывод в списке. Сначала позвольте мне объяснить, что происходит каждый раз, когда запускается метод train(). Он случайным образом выбирает набор обучающих записей и проталкивает их по сети, пока не будет сделан прогноз, и вычисляет функцию потерь для каждой записи. Затем веса корректируются в соответствии с логикой оптимизатора на основе рассчитанных потерь, что помогает уменьшить общие потери для следующей итерации. Как правило, эти значения потерь со временем постепенно уменьшаются, если скорость обучения достаточно мала. Однако после определенного количества таких итераций обучения на веса начинает влиять не только общий тренд данных, но и наследование нереалистичного шума во всех реальных данных. В этот момент на сеть чрезмерно влияют характеристики обучающих данных, и она становится неспособной обобщать свои прогнозы относительно данных о населении. Это связано с неадекватностью многих других руководств по высокоуровневому API TensorFlow, о которых я упоминал ранее. Важно периодически прерывать это во время обучения и оценивать, как модель обобщает набор данных для оценки или проверки. Взглянув на вывод оценки первой итерации цикла, давайте на минутку взглянем на результат, возвращаемый функцией Evaluate().
evaluations[0]
{'average_loss': 31.116383, 'global_step': 400, 'loss': 3111.6382}
Как видите, он выводит средние потери (среднеквадратическую ошибку) и общие потери (сумму квадратов ошибок) для шагов обучения, то есть для шага 400. В хорошо обученных сетях обычно наблюдается тенденция, при которой потери при обучении и оценке снижаются более или менее параллельно. Однако в перенастроенной модели в определенный момент времени проверочный обучающий набор больше не будет видеть, что выходные данные его метода Assessment () уменьшаются в точке, где фактически начинает появляться переоснащение. Здесь вы хотите остановить дальнейшее обучение модели, желательно до того, как произойдет изменение. Теперь, когда у нас есть набор оценок для каждой итерации, давайте нанесем их на график в зависимости от шагов обучения, чтобы убедиться, что мы не переобучаем нашу модель. Для этого я буду использовать простую точечную диаграмму из модуля pyplot matplotlib.
import matplotlib.pyplot as plt
%matplotlib inline
# manually set the parameters of the figure to and appropriate size
plt.rcParams['figure.figsize'] = [14, 10]
loss_values = [ev['loss'] for ev in evaluations]
training_steps = [ev['global_step'] for ev in evaluations]
plt.scatter(x=training_steps, y=loss_values)
plt.xlabel('Training steps (Epochs = steps / 2)')
plt.ylabel('Loss (SSE)')
plt.show()
Из приведенного выше графика видно, что после всех этих итераций я не переусердствовал с моделью, поскольку потеря оценки никогда не показывала существенного изменения в сторону добавления ценности. Теперь я могу смело приступить к прогнозированию на основе оставшегося набора тестовых данных и оценить, насколько хорошо модель предсказывает среднюю температуру погоды. Подобно двум другим методам регрессии, которые я продемонстрировал, для метода predict() требуется input_fn, я буду использовать повторно используемый wx_input_fn(), чтобы передать input_fn, дать ему тестовый набор данных, указать num_epochs как None и перемешать как False. , поэтому он будет по очереди передавать все данные для тестирования. Затем я выполняю итеративное форматирование диктов, возвращаемых методом Predict(), чтобы у меня был пустой массив прогнозов. Затем я использую методы sklearn объясните_вариантность_оценки (), среднее_абсолютное_ошибка () и медиана_абсолютная_ошибка (), чтобы предсказать массив, чтобы измерить, как предсказания относятся к известной цели y_test.
pred = regressor.predict(input_fn=wx_input_fn(X_test,
num_epochs=1,
shuffle=False))
predictions = np.array([p['predictions'][0] for p in pred])
print("The Explained Variance: %.2f" % explained_variance_score(
y_test, predictions))
print("The Mean Absolute Error: %.2f degrees Celcius" % mean_absolute_error(
y_test, predictions))
print("The Median Absolute Error: %.2f degrees Celcius" % median_absolute_error(
y_test, predictions))
INFO:tensorflow:Restoring parameters from tf_wx_model/model.ckpt-40000
The Explained Variance: 0.88
The Mean Absolute Error: 3.11 degrees Celcius
The Median Absolute Error: 2.51 degrees Celcius
Я использовал ту же метрику, что и метод линейной регрессии, связанный с предыдущей статьей, чтобы мы могли не только оценить эту модель, но и сравнить их. Как видите, обе модели работают примерно одинаково, но более простая модель линейной регрессии немного лучше. Однако вы можете оптимизировать модель машинного обучения, изменив такие параметры, как скорость обучения, ширина и глубина.
Суммировать
В этой статье показано, как использовать высокоуровневый подкласс оценщика API TensorFlow DNNRegressor. Кроме того, я описываю теорию нейронных сетей, способы их обучения и важность осознания опасности переобучения моделей в процессе. Чтобы продемонстрировать этот процесс построения нейронной сети, я построил модель, способную предсказывать среднюю температуру на следующий день на основе числовых признаков, собранных в первой статье этой серии. Цель написания этих статей не в том, чтобы построить очень хорошую модель для предсказания погоды, а в том, чтобы:
- Продемонстрируйте общий процесс проведения анализа (машинное обучение, наука о данных и т. д.) проекта, начиная со сбора данных, обработки данных, исследовательского анализа данных, выбора модели, построения модели и оценки модели.
- Демонстрирует, как использовать две популярные библиотеки Python, StatsModels и Scikit Learn, для выбора значимых функций, которые не нарушают ключевые предположения методов линейной регрессии.
- Продемонстрируйте, как использовать высокоуровневый API TensorFlow, и получите наглядное представление о том, что происходит под всеми этими уровнями абстракции.
- Обсудите вопросы, связанные с переоснащением моделей.
- Объясните экспериментирование с несколькими типами моделей, чтобы наилучшим образом решить проблему.
Статьи по Теме
Использование машинного обучения для прогнозирования погоды, часть II Использование машинного обучения для прогнозирования погоды, часть 1 Английский оригинал