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

Waarden voorspellen met Deep Learning en Keras

Met Keras kunnen we een Deep Learning black box maken die toekomstige waarden kan voorspellen

28 januari 2022
post main image

Ik heb een dataset, veel rijen met N inputs en 1 output, en wil de output waarde voorspellen voor elke nieuwe combinatie van input waardes. Ik ben ook een data science noob, maar verhalen op het internet over Deep Learning suggereren dat we eenvoudig een soort black box kunnen maken met een aantal neuronen, nodes, erin, en dan de dataset gebruiken om de black box te trainen. Hierna kunnen we willekeurige inputs invoeren en onze black box geeft ons output waarden met een zekere foutmarge. Klinkt dat te mooi om waar te zijn? Is het echt zo eenvoudig?

Begin met KISS (Keep It Simple Stupid)

Als je op internet zoekt naar 'python data prediction' krijg je natuurlijk een hoop hits. Er zijn veel voorbeelden die ik leuk vind, maar de meeste zijn veel te complex voor een noob. Aandelenprijzen voorspellen met behulp van tijdreeksen, te complex. Huizenprijzen voorspellen, veel beter. Er is ook een wijn kwaliteit dataset. Ik hou van wijn. kan goed zijn, misschien een andere keer.

In dit bericht probeer ik een triviaal probleem op te lossen. Ik vervang de functie:

y = x0 + 2*x1

door:

  • een Lineair Regressie model, en,
  • een Deep Learning, in feite een neuraal netwerk, een zwarte doos

Een groot voordeel is dat ik de dataset zelf kan genereren. Dit betekent ook dat ik voorspellingen kan vergelijken met verwachte waarden.

Machine Leren: Regressie vs classificatie

Om het juiste algoritme te kiezen, is het belangrijk om eerst te begrijpen of de Machine Learning taak een regressie- of een classificatieprobleem is. Regressie en classificatie zijn beide types van Supervised Machine Learning-algoritmen. Supervised Machine Learning gebruikt het concept van het gebruik van datasets met bekende outputwaarden om voorspellingen te doen.

Regressie is een algoritme dat kan worden getraind met een dataset om outputs te voorspellen die numerieke waarden, getallen, zijn. Classification is een algoritme dat kan worden getraind met een dataset om uitgangen te voorspellen die labels, categorieën, meestal 0's en 1's zijn.

Regressie voorbeeld

We hebben een dataset bestaande uit rijen met 2 inputs en een 1 output, de outputwaarde is een getal dat 'elke' waarde kan hebben. Beschouw een dataset van woningen waarin de inputs het aantal personen zijn dat in het huis kan wonen, het aantal kamers, en de output de prijs.

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

Als we een dataset hebben die groot genoeg is, kunnen we een regressiealgoritme gebruiken om de prijs te voorspellen voor elke combinatie van personen en kamers. De output zal 22.500, 18.100 enz. zijn.

Classification voorbeeld

We hebben een dataset bestaande uit rijen met 3 inputs en een output van 1, de outputwaarde is een getal dat 0 of 1 is. Beschouw een dataset van woningen waarin de inputs het aantal personen zijn dat in het huis kan wonen, het aantal kamers, de prijs, en de output 0 of 1 is, afhankelijk van of het huis de voorkeur krijgt, geliefd is, bij mensen die op een website naar een huis zoeken.

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

Als we een dataset hebben die groot genoeg is, kunnen we een classificatie algoritme gebruiken om te voorspellen of een huis geliefd is voor elke combinatie van personen, kamers en prijs. De output zal 0 (niet geliefd), of 1 (geliefd) zijn.

Underfitting en overfitting

Onze dataset is opgesplitst in een training dataset en een test dataset. Aan de hand hiervan kunnen we bepalen hoe goed of slecht ons model of algoritme presteert.

Underfitting betekent dat het model niet in staat is geweest de relevante relaties tussen de gegevens te bepalen. Waarschijnlijk is het model te eenvoudig. Een voorbeeld is proberen niet-lineaire relaties weer te geven met een lineair model.

Underfitting:

  • Werkt slecht met trainingsgegevens
  • Werkt slecht met testgegevens

Overfitting betekent dat het model ook relaties tussen gegevens en willekeurige fluctuaties heeft bepaald. Waarschijnlijk is het model te complex, leert het te goed.

Overfitting:

  • Werkt goed met trainingsgegevens
  • Werkt slecht met testgegevens

Beide gevallen kunnen zich ook voordoen als er niet genoeg gegevens in onze dataset zitten.

Lineaire regressie

Ik stel voor dat je de voorbeelden doorleest in de geweldige tutorial 'Linear Regression in Python', zie de links hieronder. Hieronder toon ik mijn versie met twee inputs, training en test data en het voorspellen van een waarde. Omdat we modelleren met Lineaire Regressie is het niet verwonderlijk dat de determinatiecoëfficiënt 1,0 is, en dat we slechts een zeer kleine hoeveelheid trainingsdata nodig hebben.

# 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))

Het script geeft de volgende uitvoer:

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.]

Om een beetje problemen te creëren heb ik een trainingswaarde veranderd, zie hierboven. Dit geeft het resultaat:

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]

Door meer trainingsdata toe te voegen krijgen we een betere fit.

Diep leren met Keras

Dit zou meer de black box benadering moeten zijn. Ik voeg gewoon wat neuronen en lagen toe en dat zou het moeten zijn. Maar is dat echt zo? Hier gebruik ik Keras omdat het erg populair blijkt te zijn. Het volgende voorbeeld was erg behulpzaam: 'Keras 101: A simple (and interpretable) Neural Network model for House Pricing regression', zie links hieronder. Het plotten van zowel het verlies als de gemiddelde fout was erg zinvol.

We zullen de volgende stappen uitvoeren:

  • Laad de gegevens
  • Definieer het model
  • Compileer het model
  • Het model trainen (fitten)
  • Het model evalueren
  • Voorspellingen doen

Laad de gegevens Hier genereren we de gegevens zelf, zie ook hierboven.

Definieer het model De eerste Dense laag heeft de input_shape parameter set nodig. Ik ben begonnen met 100 neuronen in de eerste laag, 50 in de tweede laag, 25 in de derde. Waarom? Ik heb geen idee, heb me er nog niet in verdiept.

Compileer het model Hier valt niet veel over te zeggen.

Train (fit) het model We gebruiken de validation_split parameter, zonder deze kunnen we niet plotten. Wanneer validation_split is opgegeven wordt een deel van de trainingsdata gebruikt voor validatie. De data die gebruikt wordt voor validatie tijdens fit kan veranderen, het is waarschijnlijk beter om vaste data te gebruiken anders krijgen we elke keer een andere fit.

Evalueer het model We gebruiken hier de testgegevens.

Voorspellingen Gebruik gewoon model.predict().

Natuurlijk hebben we hier meer trainingsdata nodig. Maar ook niet echt veel meer. Ik heb ook code toegevoegd om het model op te slaan en te laden. Hieronder staat de code die ik gemaakt heb.

# 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)

Het script geeft de volgende output, exclusief de input data:

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

Verbetering van Deep Learning prestaties

Tijdens het schrijven van deze post veranderde ik het aantal neuronen, dichte lagen, de validation_split parameter. Het resulteerde allemaal in enkele veranderingen, soms goed, soms slecht. De grootste verbetering is zonder twijfel het toevoegen van meer trainingsdata, maar hoeveel is genoeg?

Samenvatting

Het belangrijkste dat ik heb geleerd is dat Deep Learning een grote dataset vereist, hoe groter hoe beter. Hou ik van de zwarte doos? Ja, en tot nu toe heb ik er niet echt in gekeken. Ik kan dit nu gebruiken als een begin voor enkele echte wereld projecten. Er zijn ook dingen als het normaliseren van de inputs, het toevoegen van gewichten aan de inputs. Nog veel meer te lezen ...

Links / credits

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

Laat een reactie achter

Reageer anoniem of log in om commentaar te geven.

Opmerkingen

Laat een antwoord achter

Antwoord anoniem of log in om te antwoorden.