Partant du principe qu’il vaut mieux s’adresser à Dieu au’à ses Saints, après avoir étudié The Boston Housing Price dataset avec (JM) Jojo Moolayil, présentons ici la version de F. Chollet (FC), l’auteur de Keras. Si le code de JM est très intéressant d’un point de vue pédagogique, il ne l’est pas en termes d’efficacité et d’efficience.

Le code est ici. C’est celui du livre de F. Chollet : Deep Learning with Python.

Pour une description des données, voir Kaggle ici, ou ici.

Le but de l’exercice est de prédire le prix moyen d’une maison à Boston, dans les années 70. Nous sommes dans un cas typique de régression.

Lecture des données

from keras.datasets import boston_housing (train_data, train_targets), (test_data, test_targets) = boston_housing.load_data()
Code language: JavaScript (javascript)
train_data.shape
Code language: CSS (css)
(404, 13)
test_data.shape
Code language: CSS (css)
(102, 13)
train_targets[0:5]
Code language: CSS (css)
array([15.2, 42.3, 50. , 21.1, 17.7])
Code language: CSS (css)

Normalisation

Si les données sont toutes de type float, elles ne sont pas toutes dans le même intervalle. C »est pourquoi il est préférable de les normaliser. Notez que la moyenne et l’écart-type sont calculés sur les données d’apprentissage et utilisées sur celles-ci ainsi que sur les données de test.

# Normalizing the data mean = train_data.mean(axis=0) train_data -= mean std = train_data.std(axis=0) train_data /= std test_data -= mean test_data /= std
Code language: PHP (php)

Autre façon de normaliser (plus simple à mon avis)

from sklearn import preprocessing n_train_data = preprocessing.scale(train_data) n_train_data
Code language: JavaScript (javascript)

Si on veut ensuite utiliser, le scaler calculé avec sckit-learn pour les données de test, c’est tout à fait possible. Voir ici.

scaler = preprocessing.StandardScaler().fit(train_data) scaler.transform(test_data)

Construction du réseau

Les différentes couches

Le modèle proposé par FC est différent de celui de JM puisque au lieu de 13/6/1 on a 64/64/1.

Par contre tous deux utilisent un ReLU.

Concernant l’optimizer, FC choisit rmsprop alors que JM préfère Adam.

La fonction de coût choisie par FC et JM est MSE, ce qui est presque systématique dans le cas d’une régression.

La métrique de FC est MAE (mean_absolute_error) et celle de JM MAPE (mean_absolute_percentage_error).

Pour rappel, la compétition Kaggle existe RMSE. Avec Keras, il est permis d’utiliser n’importe quelle fonction de coût comme métrique mais RMSE n’est pas implémenté. Il faut créer sa propre fonction.

La définition de RMSE est :

RMSE(y) = \sqrt{\sum_{i=1}^n (y_i - \hat{y}_i)^2}
def root_mean_squared_error(y_true, y_pred): return K.sqrt(K.mean(K.square(y_pred - y_true)))
Code language: CSS (css)

Pour rappel, la métrique n’est pas utilisée pour les calculs du modèle.


# Building your network from keras import models from keras import layers def build_model(): model = models.Sequential() model.add(layers.Dense(64, activation='relu',input_shape=(train_data.shape[1],))) model.add(layers.Dense(64, activation='relu')) model.add(layers.Dense(1)) model.compile(optimizer='rmsprop', loss='mse', metrics=['mae']) return model
Code language: PHP (php)

K-fold

FC utilise cette technique pour tester différents paramètres car il n’y a pas beaucoup de données dans le dataset.

Il faut tester ici différentes valeurs pour num_epochs mais aussi différentes couches (nombre de neurones et nombre de couches)

# K-fold validation import numpy as np k=4 num_val_samples = len(train_data) // k num_epochs = 100 all_scores = [] for i in range(k): print('processing fold #', i) val_data = train_data[i * num_val_samples: (i + 1) * num_val_samples] val_targets = train_targets[i * num_val_samples: (i + 1) * num_val_samples] partial_train_data = np.concatenate( [train_data[:i * num_val_samples], train_data[(i + 1) * num_val_samples:]], axis=0) partial_train_targets = np.concatenate([train_targets[:i * num_val_samples], train_targets[(i + 1) * num_val_samples:]], axis=0) model = build_model() model.fit(partial_train_data, partial_train_targets, epochs=num_epochs, batch_size=1, verbose=0) val_mse, val_mae = model.evaluate(val_data, val_targets, verbose=0) all_scores.append(val_mae)
Code language: PHP (php)

evaluate :

Returns the loss value & metrics values for the model in test mode.

https://keras.io/models/model/#evaluate
processing fold # 0 processing fold # 1 processing fold # 2 processing fold # 3
Code language: PHP (php)
all_scores
[2.095678972725821, 2.220593815982932, 2.859968412040484, 2.4053568893139907]
Code language: JSON / JSON with Comments (json)
np.mean(all_scores)
Code language: CSS (css)
2.395399522515807
Code language: CSS (css)
# Saving the validation logs at each fold num_epochs = 500 all_mae_histories = [] for i in range(k): print('processing fold #', i) val_data = train_data[i * num_val_samples: (i + 1) * num_val_samples] val_targets = train_targets[i * num_val_samples: (i + 1) * num_val_samples] partial_train_data = np.concatenate([train_data[:i * num_val_samples],train_data[(i + 1) * num_val_samples:]], axis=0) partial_train_targets = np.concatenate([train_targets[:i * num_val_samples],train_targets[(i + 1) * num_val_samples:]],axis=0) model = build_model() history = model.fit(partial_train_data, partial_train_targets, validation_data=(val_data, val_targets), epochs=num_epochs, batch_size=1, verbose=0) mae_history = history.history['val_mean_absolute_error'] all_mae_histories.append(mae_history)
Code language: PHP (php)
processing fold # 0 processing fold # 1 processing fold # 2 processing fold # 3
Code language: PHP (php)
# Building the history of successive mean K-fold validation scores average_mae_history = [np.mean([x[i] for x in all_mae_histories]) for i in range(num_epochs)]
Code language: PHP (php)

affichage des données

# Plotting validation scores import matplotlib.pyplot as plt plt.plot(range(1, len(average_mae_history) + 1), average_mae_history) plt.xlabel('Epochs') plt.ylabel('Validation MAE') plt.show()
Code language: PHP (php)
# Plotting validation scores, excluding the first 10 data points def smooth_curve(points, factor=0.9): smoothed_points = [] for point in points: if smoothed_points: previous = smoothed_points[-1] smoothed_points.append(previous * factor + point * (1 - factor)) else: smoothed_points.append(point) return smoothed_points smooth_mae_history = smooth_curve(average_mae_history[10:]) plt.plot(range(1, len(smooth_mae_history) + 1), smooth_mae_history) plt.xlabel('Epochs') plt.ylabel('Validation MAE') plt.show()
Code language: PHP (php)

Version finale du réseau

# Training the final model model = build_model() model.fit(train_data, train_targets,epochs=80, batch_size=16, verbose=0) test_mse_score, test_mae_score = model.evaluate(test_data, test_targets)
Code language: PHP (php)
102/102 [==============================] - 0s 1ms/step
test_mae_score
2.675027146058924
Code language: CSS (css)

J’ai modifié la métrique afin de comparer les résultats avec la compétition Kaggle.

# On remplace la métrique par RMSE import keras.backend as Kdef root_mean_squared_error(y_true, y_pred): return K.sqrt(K.mean(K.square(y_pred - y_true)))
Code language: CSS (css)

def build_model_rmse():
model = models.Sequential()
model.add(layers.Dense(64, activation=’relu’,input_shape=(train_data.shape[1],)))
model.add(layers.Dense(64, activation=’relu’))
model.add(layers.Dense(1))
model.compile(optimizer=’rmsprop’, loss=’mse’, metrics=[root_mean_squared_error])
return model

# Training the final model model_rmse = build_model_rmse() model_rmse.fit(train_data, train_targets,epochs=80, batch_size=16, verbose=0) # Returns the loss value & metrics values for the model in test mode. test_mse_score, test_rmse_score = model_rmse.evaluate(test_data, test_targets)
Code language: PHP (php)
102/102 [==============================] - 0s 516us/step
test_rmse_score
5.667209728091371
Code language: CSS (css)

Avec un tel résultat on est 69ème dans la compétition, ce qui n’est pas terrible.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *