angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

Прогнозирование значений с помощью Deep Learning и Keras

С помощью Keras мы можем создать "черный ящик" Deep Learning , который сможет предсказывать будущие значения

28 января 2022
post main image

У меня есть набор данных, много строк с N входами и 1 выходом, и я хочу предсказать значение выхода для любой новой комбинации входных значений. Я также новичок в науке о данных, но истории в интернете о Deep Learning говорят о том, что мы можем легко создать своего рода черный ящик с некоторыми нейронами, узлами, в нем, а затем использовать набор данных для обучения черного ящика. После этого мы можем подавать любые входные данные, и наш "черный ящик" выдает нам выходные значения с некоторой погрешностью. Звучит слишком хорошо, чтобы быть правдой? Действительно ли это так просто?

Начните с KISS (Keep It Simple Stupid).

Когда вы ищете в интернете "предсказание данных в Python", вы, конечно, получаете много результатов. Есть много примеров, которые мне нравятся, но большинство из них слишком сложны для новичка. Предсказать цены на акции, используя временные ряды, слишком сложно. Прогнозирование цен на жилье - гораздо лучше. Есть также набор данных о качестве вина. Я люблю вино. Может быть хорошим, может быть в другой раз.

В этом посте я пытаюсь решить тривиальную проблему. Я заменяю функцию:

y = x0 + 2*x1

на:

  • модель линейной регрессии, и,
  • Deep Learning, фактически нейронной сетью, черным ящиком.

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

Machine Learning: регрессия против классификации

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

Регрессия - это алгоритм, который может быть обучен с набором данных для прогнозирования выходных данных, которые являются числовыми значениями, числами. Classification - это алгоритм, который может быть обучен на наборе данных для прогнозирования выходов, которые представляют собой метки, категории, обычно 0 и 1.

Пример регрессии

У нас есть набор данных, состоящий из строк с 2 входами и 1 выходом, выходное значение - это число, которое может иметь "любое" значение. Рассмотрим набор данных о жилье, где входными данными являются количество человек, которые могут проживать в доме, количество комнат, а выходным - цена.

 persons | rooms | price
---------+-------+--------
  5      |  4    | 20.000
  3      |  2    | 24.000

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

Пример Classification

У нас есть набор данных, состоящий из строк с 3 входами и 1 выходом, выходное значение - это число, равное 0 или 1. Рассмотрим набор данных о жилье, где входными данными являются количество человек, которые могут жить в доме, количество комнат, цена, а выходным значением является 0 или 1 в зависимости от того, нравится ли этот дом людям, ищущим дом на сайте.

 persons | rooms | price   | liked
---------+-------+---------+--------
  5      |  4    | 20.000  | 0
  3      |  2    | 24.000  | 1

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

Недооптимизация и переоптимизация

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

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

Недоподгонка:

  • Плохо работает с обучающими данными
  • Плохо работает с тестовыми данными

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

Переподгонка:

  • Хорошо работает с обучающими данными
  • Плохо работает с тестовыми данными

Оба случая могут иметь место, когда в нашем наборе данных недостаточно данных.

Линейная регрессия

Я предлагаю вам ознакомиться с примерами в замечательном учебнике 'Linear Regression in Python', см. ссылки ниже. Ниже я показываю свою версию с двумя входами, обучающими и тестовыми данными, и прогнозированием значения. Поскольку мы моделируем с помощью линейной регрессии, неудивительно, что коэффициент детерминации равен 1.0, и что нам нужно очень небольшое количество обучающих данных.

# Linear regression: y = x0 + 2*x1
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

# generate dataset
X_items = []
y_items = []
for x0 in range(0, 3):
    for x1 in range(3, 5):
        y = x0 + 2*x1
        X_items.append([x0, x1])
        y_items.append(y)

X = np.array(X_items).reshape((-1, 2))
y = np.array(y_items)
print('X = {}'.format(X))
print('y = {}'.format(y))

# split dataset in training and test data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)
print('X_train = {}'.format(X_train))
print('y_train = {}'.format(y_train))
print('X_test = {}'.format(X_test))
print('y_test = {}'.format(y_test))

# create model
model = LinearRegression()

# mess up a training value
#X_train[0][0] += 2

# calculate optimal values of weights b0 and b1
model.fit(X_train, y_train)

# show results, mess up test data
print('model result:')
print('- intercept (b0) = {}'.format(model.intercept_))
print('- slope (b1) = {}'.format(model.coef_))
print('- coefficient of determination for training data = {}'.
    format(model.score(X_train, y_train)))
print('- coefficient of determination for test data = {}'.
    format(model.score(X_test, y_test)))

x = np.array([8, 9]).reshape((-1, 2))
y_pred = model.predict(x)
print('predicted response for x = {}: {}'.format(x, y_pred))

Сценарий выдает следующий результат:

X = [[0 3]
 [0 4]
 [1 3]
 [1 4]
 [2 3]
 [2 4]]
y = [ 6  8  7  9  8 10]
X_train = [[2 3]
 [0 3]
 [1 4]
 [2 4]]
y_train = [ 8  6  9 10]
X_test = [[1 3]
 [0 4]]
y_test = [7 8]
model result:
- intercept (b0) = -3.552713678800501e-15
- slope (b1) = [1. 2.]
- coefficient of determination for training data = 1.0
- coefficient of determination for test data = 1.0
predicted response for x = [[8 9]]: [26.]

Чтобы создать небольшую проблему, я изменил обучающее значение, см. выше. Это дает результат:

model result:
- intercept (b0) = -2.3529411764705817
- slope (b1) = [0.52941176 2.76470588]
- coefficient of determination for training data = 0.9865546218487395
- coefficient of determination for test data = -0.5570934256055304
predicted response for x = [[8 9]]: [26.76470588]

Добавив больше обучающих данных, мы получаем лучшее соответствие.

Deep Learning с Keras

Это больше похоже на подход "черного ящика". Я просто добавляю несколько нейронов и слоев, и все. Но так ли это на самом деле? Здесь я использую Keras, потому что он кажется очень популярным. Следующий пример был очень полезен: 'Keras 101: A simple (and interpretable) Neural Network model for House Pricing regression', см. ссылки ниже. Построение графиков как потерь, так и средней ошибки имеет большой смысл.

Мы выполним следующие шаги:

  • Загрузить данные
  • Определить модель
  • Компиляция модели
  • Обучение (подгонка) модели
  • Оценить модель
  • Сделать прогнозы

Загрузка данных Здесь мы сами генерируем данные, см. также выше.

Определение модели Для первого плотного слоя необходим набор параметров input_shape . Я начал со 100 нейронов в первом слое, 50 во втором, 25 в третьем. Почему? Понятия не имею, еще не разбирался.

Скомпилируйте модель Не так много нужно сказать об этом.

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

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

Прогнозы Просто используйте model.predict().

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

# Keras deep learning: y = x0 + 2*x1
from keras.models import Sequential, load_model
from keras.layers import Dense
import numpy as np
from plotly.subplots import make_subplots
import plotly.graph_objects as go
from sklearn.model_selection import train_test_split

use_saved_model = False
#use_saved_model = True

# create dataset
def fx(x0, x1):
    return x0 + 2*x1

X_items = []
y_items = []
for x0 in range(0, 18, 3):
    for x1 in range(2, 27, 3):
        y = fx(x0, x1)
        X_items.append([x0, x1])
        y_items.append(y)

X = np.array(X_items).reshape((-1, 2))
y = np.array(y_items)
print('X = {}'.format(X))
print('y = {}'.format(y))
X_data_shape = X.shape
print('X_data_shape = {}'.format(X_data_shape))

class DLM:
    
    def __init__(
        self,
        model_name='default_model',
    ):
        self.model_name = model_name
        self.dense_input_shape=(2, )
        self.dense_neurons = [100, 50, 25]
        self.fit_params = {
            'epochs': 100, 
            'validation_split': 0.1, 
            'verbose': 0,
        }

    def data_split_train_test(
        self,
        X,
        y,
    ):
        self.X_train, self.X_test, self.y_train, self.y_test = train_test_split(X, y, test_size=0.3, random_state=1)
        print('self.X_train = {}'.format(self.X_train))
        print('self.X_test = {}'.format(self.X_test))
        print('self.y_train = {}'.format(self.y_train))
        print('self.y_test = {}'.format(self.y_test))

        print('training data row count = {}'.format(len(self.y_train)))
        print('test data row count = {}'.format(len(self.y_test)))

        X_train_data_shape = self.X_train.shape
        print('X_train_data_shape = {}'.format(X_train_data_shape))

    def get_model(
        self,
    ):
        self.model = Sequential()
        self.model.add(Dense(self.dense_neurons[0], input_shape=self.dense_input_shape, activation='relu', name='dense_input'))
        for i, n in enumerate(self.dense_neurons[1:]):
            self.model.add(Dense(n, activation='relu', name='dense_hidden_' + str(i)))
        self.model.add(Dense(1, activation='linear', name='dense_output'))
        self.model.compile(optimizer='adam', loss='mse', metrics=['mean_absolute_error'])
        self.model_summary()
        return self.model

    def model_summary(
        self,
    ):
        self.model.summary()

    def train(
        self, 
        model,
        plot=False,
    ):
        history = model.fit(self.X_train, self.y_train, **self.fit_params)

        if plot:

            fig = go.Figure()
            fig.add_trace(go.Scattergl(y=history.history['loss'], name='Train'))
            fig.add_trace(go.Scattergl(y=history.history['val_loss'], name='Valid'))
            fig.update_layout(height=500, width=700, xaxis_title='Epoch', yaxis_title='Loss')
            fig.show()

            fig = go.Figure()
            fig.add_trace(go.Scattergl(y=history.history['mean_absolute_error'], name='Train'))
            fig.add_trace(go.Scattergl(y=history.history['val_mean_absolute_error'], name='Valid'))
            fig.update_layout(height=500, width=700, xaxis_title='Epoch', yaxis_title='Mean Absolute Error')
            fig.show() 

        return history

    def evaluate(
        self, 
        model,
    ):
        mse_nn, mae_nn = model.evaluate(self.X_test, self.y_test)
        print('Mean squared error on test data: ', mse_nn)
        print('Mean absolute error on test data: ', mae_nn)
        return mse_nn, mae_nn

    def predict(
        self,
        model,
        x0,
        x1,
        fx=None,
    ):
        x = np.array([[x0, x1]]).reshape((-1, 2))
        predictions = model.predict(x)
        expected = ''
        if fx is not None:
            expected = ', expected = {}'.format(fx(x0, x1))
        print('for x = {}, predictions = {}{}'.format(x, predictions, expected))
        return predictions

    def save_model(
        self,
        model,
    ):
        model.save(self.model_name)

    def load_saved_model(
        self,
    ):
        self.model = load_model(self.model_name)
        return self.model

# create & save or used saved
dlm = DLM()
if use_saved_model:
    model = dlm.load_saved_model()    
else:
    dlm.data_split_train_test(X, y)
    model = dlm.get_model()
    dlm.train(model, plot=True)
    dlm.evaluate(model)
    dlm.save_model(model)

# predict
dlm.predict(model, 4, 17, fx=fx)
dlm.predict(model, 23, 79, fx=fx)
dlm.predict(model, 40, 33, fx=fx)

Сценарий дает следующий результат, исключая входные данные:

training data row count = 37
test data row count = 17
X_train_data_shape = (37, 2)
2022-01-28 16:00:30.598860: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcuda.so.1'; dlerror: libcuda.so.1: cannot open shared object file: No such file or directory
2022-01-28 16:00:30.598886: W tensorflow/stream_executor/cuda/cuda_driver.cc:269] failed call to cuInit: UNKNOWN ERROR (303)
2022-01-28 16:00:30.598911: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:156] kernel driver does not appear to be running on this host (myra): /proc/driver/nvidia/version does not exist
2022-01-28 16:00:30.599110: I tensorflow/core/platform/cpu_feature_guard.cc:151] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_input (Dense)         (None, 100)               300       
                                                                 
 dense_hidden_0 (Dense)      (None, 50)                5050      
                                                                 
 dense_hidden_1 (Dense)      (None, 25)                1275      
                                                                 
 dense_output (Dense)        (None, 1)                 26        
                                                                 
=================================================================
Total params: 6,651
Trainable params: 6,651
Non-trainable params: 0
_________________________________________________________________
1/1 [==============================] - 0s 25ms/step - loss: 0.1018 - mean_absolute_error: 0.2752
Mean squared error on test data:  0.10178931057453156
Mean absolute error on test data:  0.27519676089286804
2022-01-28 16:00:33.549267: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
for x = [[ 4 17]], predictions = [[38.0433]], expected = 38
for x = [[23 79]], predictions = [[177.94098]], expected = 181
for x = [[40 33]], predictions = [[103.54724]], expected = 106

Улучшение производительности Deep Learning

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

Резюме

Самое важное, что я узнал, это то, что Deep Learning требует большого набора данных, чем больше, тем лучше. Нравится ли мне "черный ящик"? Да, и до сих пор я не заглядывал внутрь. Теперь я могу использовать это как начало для некоторых проектов в реальном мире. Есть также такие вещи, как нормализация входных данных, добавление весов к входным данным. Многое еще предстоит прочитать...

Ссылки / кредиты

How to find the value for Keras input_shape/input_dim?
https://www.machinecurve.com/index.php/2020/04/05/how-to-find-the-value-for-keras-input_shape-input_dim

Keras 101: A simple (and interpretable) Neural Network model for House Pricing regression
https://towardsdatascience.com/keras-101-a-simple-and-interpretable-neural-network-model-for-house-pricing-regression-31b1a77f05ae

Keras examples
https://keras.io/examples

Linear Regression in Python
https://realpython.com/linear-regression-in-python

Predictive Analysis in Python
https://medium.com/my-data-camp-journey/predictive-analysis-in-python-97ca5b64e97f

Regression Tutorial with the Keras Deep Learning Library in Python
https://machinelearningmastery.com/regression-tutorial-keras-deep-learning-library-python

Оставить комментарий

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

Комментарии

Оставьте ответ

Ответьте анонимно или войдите в систему, чтобы ответить.