Рубрики
Без рубрики

Глубокое обучение в Keras – Построение модели глубокого обучения

В этом уроке мы будем строить модель глубокого обучения с использованием Python с Keras. Мы будем компилировать, прогнозировать и оценивать модель, чтобы интерпретировать ее производительность.

Автор оригинала: Ammar Alyousfi.

Вступление

Глубокое обучение-одно из самых интересных и перспективных направлений искусственного интеллекта (ИИ) и машинного обучения в настоящее время. Благодаря огромным достижениям в области технологий и алгоритмов в последние годы глубокое обучение открыло дверь в новую эру приложений искусственного интеллекта.

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

Python стал основным языком машинного обучения, и многие из самых популярных и мощных библиотек глубокого обучения и фреймворков , таких как TensorFlow , Keras и PyTorch , построены на Python.

В этой серии мы будем использовать Keras для выполнения Исследовательского анализа данных (EDA), предварительной обработки данных и , наконец, построения модели глубокого обучения и ее оценки.

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

Определение модели

Нейронная сеть глубокого обучения-это просто нейронная сеть со многими скрытыми слоями.

Определение модели может быть разбито на несколько характеристик:

  • Количество слоев
  • Типы этих слоев
  • Количество единиц (нейронов) в каждом слое
  • Функции активации каждого слоя
  • Размер входного и выходного сигнала

Слои Глубокого обучения

Существует много типов слоев для моделей глубокого обучения. Сверточные и объединяющие слои используются в CNN, которые классифицируют изображения или обнаруживают объекты, в то время как рекуррентные слои используются в RNN, которые распространены в обработке естественного языка и распознавании речи.

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

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

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

Функции Активации

Существует также множество типов функций активации, которые могут быть применены к слоям. Каждый из них связывает вход и вес нейрона по-разному и заставляет сеть вести себя по-разному.

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

Входные и выходные слои

В дополнение к скрытым слоям модели имеют входной слой и выходной слой:

архитектура нейронной сети глубокого обучения

Количество нейронов во входном слое совпадает с количеством объектов в наших данных. Мы хотим научить сеть реагировать на эти особенности. У нас есть 67 функций в фреймах данных train_df и test_df – таким образом, наш входной слой будет иметь 67 нейронов. Они станут точкой входа в наши данные.

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

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

Определение кода модели

Мы будем использовать несколько импорта для кода вперед:

import matplotlib.pyplot as plt
from matplotlib import ticker
import numpy as np
import pandas as pd
import seaborn as sns

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

Имея в виду эти импортные данные и параметры, давайте определим модель с помощью Keras:

model = keras.Sequential([
    layers.Dense(64, activation='relu', input_shape=[train_df.shape[1]]),
    layers.Dropout(0.3, seed=2),
    layers.Dense(64, activation='swish'),
    layers.Dense(64, activation='relu'),
    layers.Dense(64, activation='swish'),
    layers.Dense(64, activation='relu'),
    layers.Dense(64, activation='swish'),
    layers.Dense(1)
])

Здесь мы использовали Keras’ Sequential() для создания экземпляра модели. Он берет группу последовательных слоев и складывает их вместе в единую модель. В конструктор Sequential() мы передаем список, содержащий слои, которые мы хотим использовать в нашей модели.

В этой модели мы сделали несколько Плотных слоев и один Выпадающий слой. Мы сделали input_shape равным количеству объектов в наших данных. Мы определяем это на первом слое как вход этого слоя.

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

Мы быстро сократили 30% входных данных, чтобы избежать переобучения. Значение seed равно 2, поэтому мы получаем более воспроизводимые результаты. Если бы мы просто совершенно случайно отбросили их, каждая модель была бы другой.

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

Компиляция модели

После определения нашей модели следующим шагом является ее компиляция. Компиляция модели Keras означает настройку ее для обучения.

Чтобы скомпилировать модель, нам нужно выбрать:

  • Функция потерь -Чем меньше ошибка, тем ближе модель к цели. Различные проблемы требуют различных функций потерь для отслеживания прогресса. Вот список поддерживаемых функций потерь.
  • Оптимизатор – Оптимизирующий алгоритм, который помогает нам достичь лучших результатов для функции потерь.
  • Метрики – Метрики, используемые для оценки модели. Например, если у нас есть Среднеквадратичная ошибка функция потерь, было бы разумно использовать Среднюю абсолютную ошибку в качестве метрики, используемой для оценки.

Имея это в виду, давайте скомпилируем модель:

optimizer = tf.keras.optimizers.RMSprop(learning_rate=0.001)

model.compile(loss=tf.keras.losses.MeanSquaredError(),
              optimizer=optimizer,
              metrics=['mae'])

Здесь мы создали оптимизатор RMSProp со скоростью обучения 0.001 . Не стесняйтесь экспериментировать с другими оптимизаторами, такими как Adam optimizer.

Примечание: Вы можете либо объявить оптимизатор и использовать этот объект, либо передать его строковое представление в методе compile () .

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

Обучение модели

После компиляции модели мы можем обучить ее с помощью нашего набора данных train_df . Это делается путем подгонки его с помощью функции fit() :

history = model.fit(
    train_df, train_labels,
    epochs=70, validation_split=0.2
)

Здесь мы передали обучающие данные ( train_df ) и метки поездов ( train_labels ).

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

Наконец, мы передаем обучающие данные, которые используются для проверки. В частности, мы сказали ему использовать 0.2 (20%) обучающих данных для проверки полученных результатов. Не путайте это с набором данных test_df , который мы будем использовать для его оценки.

Эти 20% будут использоваться не для обучения, а скорее для проверки, чтобы убедиться, что он прогрессирует.

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

Закончив, мы можем посмотреть, как это делается в каждую эпоху:

Epoch 65/70
59/59 [==============================] - 0s 2ms/step - loss: 983458944.0000 - mae: 19101.9668 - val_loss: 672429632.0000 - val_mae: 18233.3066
Epoch 66/70
59/59 [==============================] - 0s 2ms/step - loss: 925556032.0000 - mae: 18587.1133 - val_loss: 589675840.0000 - val_mae: 16720.8945
Epoch 67/70
59/59 [==============================] - 0s 2ms/step - loss: 1052588800.0000 - mae: 18792.9805 - val_loss: 608930944.0000 - val_mae: 16897.8262
Epoch 68/70
59/59 [==============================] - 0s 2ms/step - loss: 849525312.0000 - mae: 18392.6055 - val_loss: 613655296.0000 - val_mae: 16914.1777
Epoch 69/70
59/59 [==============================] - 0s 2ms/step - loss: 826159680.0000 - mae: 18177.8945 - val_loss: 588994816.0000 - val_mae: 16520.2832
Epoch 70/70
59/59 [==============================] - 0s 2ms/step - loss: 920209344.0000 - mae: 18098.7070 - val_loss: 571053952.0000 - val_mae: 16419.8359

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

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

model_history = pd.DataFrame(history.history)
model_history['epoch'] = history.epoch

fig, ax = plt.subplots(figsize=(14,8))
num_epochs = model_history.shape[0]
ax.plot(np.arange(0, num_epochs), model_history["mae"], 
        label="Training MAE", lw=3, color='#f4b400')
ax.plot(np.arange(0, num_epochs), model_history["val_mae"], 
        label="Validation MAE", lw=3, color='#0f9d58')
ax.legend()
plt.tight_layout()
plt.show()
функция mae и потерь с течением времени и обучения

Мы можем ясно видеть, как значения mae и потерь со временем снижаются. Это именно то, что мы хотим – модель стала более точной с предсказаниями с течением времени.

Составление прогнозов с помощью модели

Теперь, когда наша модель обучена, давайте воспользуемся ею, чтобы сделать некоторые прогнозы. Мы берем элемент из тестовых данных (в test_df ):

test_unit = test_df.iloc[[0]]

Этот элемент, хранящийся в test_unit , имеет следующие значения, обрезанные только на 7 записей для краткости:

Фасад участка Площадь Участка Общее Качество Общее Состояние Год Постройки Итого Bsmt SF 1-й Флр СФ
14 0.0157117 -0.446066 1.36581 -0.50805 0.465714 1.01855 0.91085

Это значения единицы объекта и мы будем использовать модель для прогнозирования его цены продажи:

test_pred = model.predict(test_unit).squeeze()

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

Примечание: predict() возвращает массив NumPy , поэтому мы использовали squeeze () , который является функцией NumPy, чтобы “сжать” этот массив и получить из него значение предсказания в виде числа, а не массива.

Теперь давайте получим фактическую цену единицы измерения из test_labels :

test_lbl = test_labels.iloc[0]

А теперь давайте сравним прогнозируемую цену и фактическую:

print("Model prediction = {:.2f}".format(test_pred))
print("Actual value = {:.2f}".format(test_lbl))
Model prediction = 225694.92
Actual value = 212000.00

Таким образом, фактическая цена продажи этой единицы составляет $212 000 , а наша модель предсказала, что она составит *$225 694*. Это довольно близко, хотя модель превысила цену ~на 5%.

Давайте попробуем другой блок из test_df :

test_unit = test_df.iloc[[100]]

И мы повторим тот же процесс, чтобы сравнить цены:

test_pred = model.predict(test_unit).squeeze()
test_lbl = test_labels.iloc[100]
print("Model prediction = {:.2f}".format(test_pred))
print("Actual value = {:.2f}".format(test_lbl))
Model prediction = 330350.47
Actual value = 340000.00

Таким образом, для этой единицы фактическая цена составляет $340 000 , а прогнозируемая цена – *$330 350*. Опять же, не совсем точно, но это ошибка всего лишь ~3%. Это очень точно.

Оценка модели

Это заключительный этап в нашем путешествии по построению модели глубокого обучения Keras. На этом этапе мы будем использовать модель для генерации прогнозов по всем единицам наших тестовых данных ( test_df ), а затем вычислить среднюю абсолютную ошибку этих прогнозов, сравнивая их с фактическими истинными значениями ( test_labels ).

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

Мы выбрали MADE в качестве нашей метрики, потому что ее можно легко интерпретировать. Значение MAE представляет собой среднее значение ошибки модели: $$ \begin{equation*} \text{ME}(y, \hat{y}) = \frac{1}{n}}^{n} \left| y_i – \hat{y}_i \right|. \end{уравнение*} $$

Для вашего удобства функция evaluate() позаботится об этом за нас:

loss, mae = model.evaluate(test_df, test_labels, verbose=0)

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

Давайте запустим код и посмотрим, как он работает:

print('MAE = {:.2f}'.format(mae))
MAE = 17239.13

Средняя абсолютная ошибка равна 17239.13 . То есть для всех единиц модель в среднем предсказывала $17 239 выше или ниже фактической цены.

Интерпретация характеристик модели

Насколько хорош этот результат? Если мы оглянемся назад на КОНЕЦ , который мы прошли по цене продажи , мы увидим, что средняя цена продажи для единиц в наших исходных данных составляет $180,796 . Тем не менее, МЭЙ из 17,239 это довольно хорошо.

Чтобы интерпретировать эти результаты по-другому, давайте построим прогнозы относительно фактических цен:

test_predictions_ = model.predict(test_df).flatten()
test_labels_ = test_labels.to_numpy().flatten()
fig, ax = plt.subplots(figsize=(14,8))
plt.scatter(test_labels_, test_predictions_, alpha=0.6, 
            color='#ff7043', lw=1, ec='black')
lims = [0, max(test_predictions_.max(), test_labels_.max())]
plt.plot(lims, lims, lw=1, color='#00acc1')
plt.tight_layout()
plt.show()
фактические и прогнозируемые значения

Если бы наша модель была на 100% точна с 0 СДЕЛАННЫМИ точками, все точки появлялись бы точно на диагональной голубой линии. Однако ни одна модель не является точной на 100%, и мы видим, что большинство точек находятся близко к диагональной линии, что означает, что прогнозы близки к фактическим значениям.

Есть несколько выбросов, некоторые из которых сильно отклонены . Это резко повышает среднюю МЭ нашей модели. На самом деле для большинства из этих точек MAE намного меньше, чем 17,239 .

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

Вывод

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

Хотя мы и не были точны на 100%, нам удалось получить очень приличные результаты с небольшим количеством выбросов.