Le livre Learn Keras for Deep Neural Networks de Jojo Moolayil, publié chez Apress est un livre de 182 pages qui se veut une introduction au Deep Learning (apprentissage profond) en s’appuyant sur la librairie Keras.

Chapitre 1 : An introduction do Deep Learning and Keras

Le chapitre #1 : An introduction do Deep Learning and Keras satisfera les débutants dans le Deep Learning (DL). Une présentation générale des frameworks est présentée et un premier exemple très simple en Python décrit ce qu’est un logiciel développé avec Keras. Dommage qu’il n’y ait pas le code quelque part sur le Web.

Pour exécuter ce premier exemple, si vous le faites sur votre PC/Mac, alors il est préférable d’utiliser Anaconda, dans un environnement où vous avez installé TensorFlow et Keras. Sinon, utilisez GCP, et mon code disponible sur Github.

Cet exemple n’est pas commenté dans le détail dans ce chapitre. Il a juste vocation à montrer les grandes ligne d’un code Keras.

Chapitre 2 : Keras in action

L’installation de l’environnement est tout d’abord décrite. Personnellement, je pense préférable d’utiliser Anaconda ou GCP et d’installer les packages supplémentaires à partir d’Anaconda.

Ce qui est bien dans ce chapitre, c’est l’explication de ce que sont la fonction d’activation, la fonction sigmoïde, ReLU.

Par ailleurs, la description des couches de neurones est très claire (core layer, dense layer). Idem pour le dropout, la fonction de coût, les optimizers et les métriques.

Ce chapitre permet de comprendre facilement quels sont les points importants dans un réseau de neurones.

Le code décrit au § Model training est ici. Ce code n’est pa très intéressant car il s’appuie sur des données aléatoires. Il est préférable de travailler sur des données réelles, ce qui est fait en fin de ce chapitre avec le Boston House Prices dataset et qui est décrit ci-dessous.

Boston House Prices

Les données de cet exercice ont servi à une compétition Kaggle et sont disponibles sur leur site, tout comme sur celui de Keras.

La description des données est la suivante :

The Boston data frame has 506 rows and 14 columns.
This data frame contains the following columns:
crim
per capita crime rate by town.
zn
proportion of residential land zoned for lots over 25,000 sq.ft.
indus
proportion of non-retail business acres per town.
chas
Charles River dummy variable (= 1 if tract bounds river; 0 otherwise).
nox
nitrogen oxides concentration (parts per 10 million).
rm
average number of rooms per dwelling.
age
proportion of owner-occupied units built prior to 1940.
dis
weighted mean of distances to five Boston employment centres.
rad
index of accessibility to radial highways.
tax
full-value property-tax rate per \$10,000.
ptratio
pupil-teacher ratio by town.
black
1000(Bk – 0.63)^2 where Bk is the proportion of blacks by town.
lstat
lower status of the population (percent).
medv
median value of owner-occupied homes in \$1000s.

https://www.kaggle.com/c/boston-housing/overview

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

Il est utile de consulter la compétition sur Kaggle, d’autant plus qu’elle est terminée depuis longtemps et qu’on connait les performances obtenues par les concurrents.

Dans le cas présent,

The medv variable is the target variable.

medv: median value of owner-occupied homes in \$1000s.

https://www.kaggle.com/c/boston-housing/overview

La méthode d’évaluation est RMSE.

RMSE(y) = \sqrt{\sum_{i=1}^n (y_i - \hat{y}_i)^2}

Avec Pandas

Pour faciliter la compréhension des données, je montre aussi comment lire les données avec Pandas et les présenter avec matplotlib et seaborn.

IdCRIMZNINDUSCHASNOXRMAGEDISRADTAXPTRATIOBLSTATtarget
00.0063218.02.310.00.5386.57565.24.09001.0296.015.3396.904.9824.0
10.027310.07.070.00.4696.42178.94.96712.0242.017.8396.909.1421.6
20.027290.07.070.00.4697.18561.14.96712.0242.017.8392.834.0334.7
30.032370.02.180.00.4586.99845.86.06223.0222.018.7394.632.9433.4
40.069050.02.180.00.4587.14754.26.06223.0222.018.7396.905.3336.2

Il y a 506 enregistrements dans le fichier.

Je vous recommande d’exécuter df.describe() qui vous donnera une bonne image de vos données. medv est renommée target dans le tableau.

et ensuite pd.isnull(df).sum() pour savoir s’il y a des données manquantes (ce qui n’est pas le cas ici).

Les corrélations entre les variables sont les suivantes :

Conversion avec Pandas

Pour obtenir des DataFrames, une autre solution est de convertir les données Numpy. Par exemple :

Training set, test set

Lorsque les données sont lues avec Keras, elles sont scindées automatiquement entre un Training Set et un Test set.

Le testing set a une taille (approximative) de 25% du training set ou dit autrement (approximativement) 20% du dataset. C’est d’ailleurs ce qu’on lit dans le code de Keras (test_split=0.2)

Si vous ne connaissez pas la différence entre Training Set, Validation Set et Test Set, rendez-vous ici.

Training Dataset: The sample of data used to fit the model.

Validation Dataset: The sample of data used to provide an unbiased evaluation of a model fit on the training dataset while tuning model hyperparameters. 

Test Dataset: The sample of data used to provide an unbiased evaluation of a final model fit on the training dataset.

https://towardsdatascience.com/train-validation-and-test-sets-72cb40cba9e7

y_train

y_train correspond à la valeur médiane des maisons occupées (en milliers de dollars).

Les prix sont entre 10K$ et 50K$ mais c’était les années 70 !

Imports

Le modèle utilisé ici est le modèle séquentiel de Keras, un modèle relativement simple à comprendre.

Données de validation

Des données de validation sont créées (pour rappel, nous avons déjà des données de test)

Cette manière de faire est assez étonnante car Keras permet de définir un validation_split, un float qui indique le pourcentage utilisé pour les données de validation.

Architecture

Le modèle est séquentiel. On décrit successivement les différentes couches du réseau.

Première couche

Pour la première couche, il est impératif d’indiquer la shape (les dimensions input_dim=13) car elle ne peut pas être déduite contrairement aux autres couches suivantes pour qui c’est possible dans un modèle séquentiel.

The model needs to know what input shape it should expect. For this reason, the first layer in a Sequential model (and only the first, because following layers can do automatic shape inference) needs to receive information about its input shape. There are several possible ways to do this:
Pass an input_shape argument to the first layer. This is a shape tuple (a tuple of integers or None entries, where None indicates that any positive integer may be expected). In input_shape, the batch dimension is not included.
Some 2D layers, such as Dense, support the specification of their input shape via the argument input_dim, and some 3D temporal layers support the arguments input_dim and input_length.

https://keras.io/getting-started/sequential-model-guide/

Pourquoi avoir précisé kernel_initializer=’normal’ ? je ne sais pas, l’auteur ne l’explique pas. Je doute que ça ait une quelconque utilité ici.

La fonction d’activation est ReLu. C’est la fonction la plus commune aujourd’hui mais ce n’est pas la fonction d’activation par défaut, il est donc nécessaire de le préciser.

Deuxième couche

Rien de particulier. Pourquoi passe t-on de 13 à 6 couches et pas à 5 ou 4 ou … il n’y a pas de règles.

Toutefois, étant donné le faible nombre de données, il est préférable de limiter le nombre de couches. Ce qu’en dit F. Chollet (le créateur de Keras) :

Because so few samples are available, you’ll use a very small network with two hidden layers, each with 64 units. In general, the less training data you have, the worse overfit- ting will be, and using a small network is one way to mitigate overfitting.

Deep Learning with Python

Lui utilise, pour le même exemple : 2 couches de 64 neurones suivies d’un output à 1.

Dernière couche

Il n’y a pas d’autre option que de terminer avec un nombre. Nous sommes dans le cas d’une régression. Notez qu’il n’y a pas de fonction d’activation. Une fonction d’activation nous contraindrait sur les valeurs que peut prendre le nombre.

Compilation du modèle

La fonction de perte est MSE, c’est celle qu’on utilise typiquement dans un problème de régression. L’auteur a choisi Adam pour optimizer. Par défaut, on utilise sgd. Quelle est l’influence de ce choix ? Difficile à dire.

Ma métrique est MAPE. Cette métrique n’a été choisie ici que pour sa vertu pédagogique. Elle donne un pourcentage sur l’erreur.

Apprentissage

Le nombre d’epochs est très faible (3), par contre le batch_size me semble élevé. Les données de validation ont été discutées précédemment.

Les résultats ne sont pas très bons (et c’est un euphémisme )

67% sur l’erreur !

Sur les données de Test

évidemment le résultat n’est pas meilleur !

En augmentant le nombre d’epochs

Il y a du progrès : 23%

Sur les données de Test

On est à 29%

Il y a de la place pour s’améliorer ! mais l’explication est claire.

F. Chollet recommande d’utiliser un K-fold pour la validation et de normaliser les données.

Chapitre 3 – Deep Neural Networks for Supervised Learning : Regression

Cette fois, le dataset est le Rossmann Store sales dataset

You are provided with historical sales data for 1,115 Rossmann stores. The task is to forecast the « Sales » column for the test set. Note that some stores in the dataset were temporarily closed for refurbishment.

https://www.kaggle.com/c/rossmann-store-sales/data

Il s’agit encore une fois d’une régression : prévoir les ventes (le CA) pour un magasin, pour un jour donné.

L’auteur nous présente les frameworks SCR et SCQ que je ne connaissais pas et que je vois ici utilisé pour la première fois dans le Machine Learning. Je ne suis pas sûr que ce soit très utile.

Etude des données

train

Le problème avec le dataset Rossman, c’est qu’il n’est pas pris en compte par Keras (ni sckit-kearn, ni Tensorflow, …). Il faut copier les données sur son disque/serveur. C’est ce que j’ai fait.

Remplacez : « /Users/… » par votre lien.

IdStoreDayOfWeekDateSalesCustomersOpenPromoStateHolidaySchoolHoliday
01531/07/1552635551101
12531/07/1560646251101
23531/07/1583148211101
34531/07/151399514981101
45531/07/1548225591101

Le fichier a une taille conséquente, 1 017 209 lignes, et 9 colonnes.

Les champ sont les suivants :

Most of the fields are self-explanatory. The following are descriptions for those that aren’t.
Id – an Id that represents a (Store, Date) duple within the test set
Store – a unique Id for each store
Sales – the turnover for any given day (this is what you are predicting)
Customers – the number of customers on a given day
Open – an indicator for whether the store was open: 0 = closed, 1 = open
StateHoliday – indicates a state holiday. Normally all stores, with few exceptions, are closed on state holidays. Note that all schools are closed on public holidays and weekends. a = public holiday, b = Easter holiday, c = Christmas, 0 = None
SchoolHoliday – indicates if the (Store, Date) was affected by the closure of public schools
StoreType – differentiates between 4 different store models: a, b, c, d
Assortment – describes an assortment level: a = basic, b = extra, c = extended
CompetitionDistance – distance in meters to the nearest competitor store
CompetitionOpenSince[Month/Year] – gives the approximate year and month of the time the nearest competitor was opened
Promo – indicates whether a store is running a promo on that day
Promo2 – Promo2 is a continuing and consecutive promotion for some stores: 0 = store is not participating, 1 = store is participating
Promo2Since[Year/Week] – describes the year and calendar week when the store started participating in Promo2
PromoInterval – describes the consecutive intervals Promo2 is started, naming the months the promotion is started anew. E.g. « Feb,May,Aug,Nov » means each round starts in February, May, August, November of any given year for that store

https://www.kaggle.com/c/rossmann-store-sales/data

store

Ce fichier décrit les magasins.

IdStoreStoreTypeAssortmentCompetitionDistanceCompetitionOpenSinceMonthCompetitionOpenSinceYearPromo2Promo2SinceWeekPromo2SinceYearPromoInterval
01ca1270.09.02008.00NaNNaNNaN
12aa570.011.02007.0113.02010.0Jan,Apr,Jul,Oct
23aa14130.012.02006.0114.02011.0Jan,Apr,Jul,Oct
34cc620.09.02009.00NaNNaNNaN
45aa29910.04.02015.00NaNNaNNaN

merge

Il nous faut travailler sur un seul ensemble de données. Nous allons fusionner les 2 fichiers précédents en un seul, grâce aux possibilités offertes par Pandas.

Il y a 1115 magasins, ce qu’on savait déjà avec le nombre de lignes de store. Il y a 942 jours pour lesquels on a a des données, et le chiffre d’affaires moyen journalier pour un magasin est de 5773,82 $.

types

Les données sont de types variés. Nous devons mettre un peu d’ordre dans tout ça.

Nettoyage des données

Dates

Comme souvent, lorsqu’il y a des dates, il faut les réarranger pour leur donner du sens. En effet, il est plus important de savoir qu’on a affaire à un WE qu’au 12/03/2019. Si vous utilisez fastai il y a des routines spécialisées pour cela. Ici ce n’est pas le cas.

Ce que nous voyons déjà, c’est que certains enregistrements ne sont pas datés.

Je n’insiste pas sur ces conversions qui peuvent être faites automatiquement avec certains outils. Notez que l’auteur pense nécessaire de calculer la saison.

Histogrammes

Histogramme des ventes

Autres histogrammes

Valeurs absentes

Comment traiter les valeurs absentes. Là aussi, fastai propose une solution technique. Ici il faut le faire soi-même. L’auteur a choisi de remplacer les valeurs absentes pas le mode (plutôt que la moyenne). Pourquoi pas !

Valeurs qualitatives

L’auteur continue son analyse des données de façon similaire.

Data engineering

Les catégories (pour lesquelles c’est possible) sont transformées en One Hot Encoding.

Il faut aussi modifier StateHoliday qui est de type Objet.

On remplace les a, b, c par 1 et le reste par 0

Apprentissage /Test / Validation

Les données sont scindées en jeu d’apprentissage, de validation et de test. Il y a une petite erreur dans le code du livre. Au lieu de

il faut :

Modèle

La métrique est MAE (mean absolute error)

Premier DNN

Le modèle est très classique et fortement inspiré de l’exemple précédent.

Mes résultats sont un peu différents mais somme toute assez voisins de ceux du livre.

Et sur le test dataset :

ça colle aussi !

Amélioration du modèle

Au lieu de mean_absolute_error pour la fonction de coût, utilisons mean_squared_error et augmentons le nombre de couches cachées.

Les résultats sont meilleurs mais à mon avis pas de façon très significative.

Par la suite, l’auteur essaie différentes options.

Le dernier test se fait avec un réseau plus profond et plus d’epochs.

Je ne constate pas les performances décrites dans le livre. J’y reviendrai.

Les chapitres suivants seront présentés dans un prochain article.

(mon code et ici)

Laisser un commentaire

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