Et ne manquez pas notre aide-mémoire Keras , qui présente les six étapes à suivre pour construire des réseaux de neurones en Python, avec des exemples de code !
Introduction aux réseaux de neurones artificiels
Avant d’aller plus loin avec Keras et son usage pour débuter le deep learning en Python, il est utile de rappeler quelques notions sur les réseaux de neurones. Comme évoqué brièvement, ils s’inspirent de la biologie : le terme « réseau neuronal » s’applique aussi aux neurones biologiques. Le cerveau humain en est un exemple, composé d’un grand nombre de neurones.
Comme vous le savez, le cerveau réalise des calculs très complexes ; c’est de là que vient l’inspiration des réseaux de neurones artificiels. Le réseau, dans son ensemble, est un puissant outil de modélisation.
Perceptrons
Le réseau neuronal le plus simple est le « perceptron » qui, dans sa forme élémentaire, se compose d’un seul neurone. À l’image du neurone biologique, doté de dendrites et d’un axone, le neurone artificiel adopte une structure arborescente simple avec des nœuds d’entrée et un nœud de sortie unique, relié à chaque entrée. Voici une comparaison visuelle des deux :
Comme vous le voyez, un neurone artificiel comporte six éléments. De gauche à droite :
Nœuds d’entrée . Chaque nœud d’entrée est associé à une valeur numérique, pouvant être n’importe quel nombre réel (positif, négatif, entier ou décimal).
Connexions . Chaque connexion issue d’un nœud d’entrée possède un poids, également un nombre réel.
Ensuite, les valeurs des nœuds d’entrée et les poids des connexions sont combinés : ils alimentent une somme pondérée : \(y = f(\sum_{i=1}^{D} w_i*x_i)\) , autrement dit \(y = f(w_1*x_1 + w_2*x_2 + ... w_D*x_D)\) .
Le résultat sert d’entrée à une fonction de transfert ou d’activation . Dans le cas le plus simple (mais trivial), la fonction de transfert est l’identité, \(f(x)=x\) ou \(y=x\) . Ici, \(x\) correspond à la somme pondérée des entrées. Toutefois, comme un neurone biologique ne s’active que si un certain seuil est dépassé, le neurone artificiel « déclenche » aussi seulement si la somme des entrées franchit un seuil, par exemple 0. Ce comportement n’apparaît pas avec une fonction identité ! L’approche la plus intuitive consiste à définir un système comme suit :
\(f(x) = 0\) si \(x<0\) \(f(x) = 0{,}5\) si \(x=0\) \(f(x) = 1\) si \(x>0\)
L’inconvénient : la sortie n’est pas lisse, c’est une fonction discontinue. Pour faciliter le traitement mathématique, on utilise souvent une variante continue, la sigmoïde. Un exemple bien connu est la fonction logistique, qui produit un résultat beaucoup plus lisse.
On obtient alors le nœud de sortie , lié à la fonction (par exemple, la sigmoïde) appliquée à la somme pondérée des entrées. La sigmoïde est une fonction mathématique en forme de « S » ; vous en lirez plus loin.
Enfin, le perceptron peut inclure un paramètre supplémentaire, le biais , assimilable au poids d’un nœud d’entrée additionnel fixé à 1. Le biais est crucial car il décale la fonction d’activation vers la gauche ou la droite, ce qui peut conditionner la réussite de l’apprentissage.
Conséquence logique : les perceptrons ne traitent que des données numériques. Toute donnée nominale doit donc être convertie au préalable.
Comme les perceptrons fonctionnent avec des seuils, le passage à la classification est naturel : tout score au-dessus d’un seuil indique l’appartenance à une classe, et en dessous à l’autre. La droite où la sortie égale le seuil forme alors la frontière entre les deux classes.
Perceptrons multicouches
Un réseau de perceptrons forme un perceptron multicouche, et c’est ce que vous allez implémenter en Python avec Keras ! On parle aussi de « réseau neuronal à propagation avant ». Comme vous l’imaginez, c’est plus complexe qu’un simple perceptron : plusieurs neurones sont organisés en couches. Le nombre de couches est souvent limité à deux ou trois, mais en théorie, il n’y a pas de limite.
Les couches se comportent comme leurs homologues biologiques : la sortie d’une couche devient l’entrée de la suivante.
On distingue une couche d’entrée, une ou plusieurs couches cachées et une couche de sortie. Les perceptrons multicouches sont souvent entièrement connectés : chaque neurone d’une couche est relié à chacun de la couche suivante. Ce n’est pas une obligation, mais c’est fréquent.
Alors que le perceptron ne permettait que des séparations linéaires, le perceptron multicouche lève cette limite et peut modéliser des frontières de décision plus complexes.
Prédire le type de vin en Python avec Keras
Pour ce tutoriel, vous utiliserez le jeu de données « wine quality » disponible dans le jeu de données wine quality de l’UCI Machine Learning Repository. Idéalement, on applique le deep learning sur de grands jeux de données, mais pour l’exercice, nous utiliserons un jeu plus petit afin de vous familiariser avec la bibliothèque et le fonctionnement des réseaux de neurones.
Vous connaissez peut-être déjà ce jeu de données, très populaire pour s’initier à la résolution de problèmes de machine learning. Ici, il vous servira à démarrer avec le deep learning en Python et Keras.
C’est parti !
Comprendre les données
Avant de charger les données, testez vos connaissances œnologiques (liées au dataset, bien sûr). La plupart savent qu’il existe deux types de vin très répandus : rouge et blanc.
(Il y en a bien d’autres, mais pour simplifier – et au vu de mes connaissances limitées en vin – restons-en là. Mes excuses aux véritables connaisseurs parmi vous :)).
Savoir cela est un début, mais pour analyser ces données, il vous faut un peu plus.
Commencez par consulter le dossier de description pour voir quelles variables sont incluses. C’est généralement la première étape pour comprendre un jeu de données. Rendez-vous sur cette page pour lire la description, ou poursuivez ici pour un aperçu.
Les données comprennent deux jeux liés aux variantes rouges et blanches du « Vinho Verde » portugais. Comme indiqué, seules des variables physicochimiques et sensorielles sont incluses. Le fichier de description liste 12 variables ; si, comme moi, vous n’êtes pas expert·e en chimie, voici un bref descriptif :
Acidité fixe : les acides sont des éléments majeurs du vin et contribuent fortement à son goût. On distingue l’acidité volatile et l’acidité non volatile (ou fixe). Parmi les acides fixes des vins : tartrique, malique, citrique, succinique. Exprimé en g(\(acide\ tartrique\) )/\(dm^3\) .
Acidité volatile : il s’agit du processus par lequel le vin tourne au vinaigre. Aux États‑Unis, la limite légale d’acidité volatile est de 1,2 g/L pour les vins rouges et 1,1 g/L pour les blancs. Ici en g(\(acide\ acétique\) )/\(dm^3\) .
Acide citrique : l’un des acides fixes présents dans les vins. Exprimé en g/\(dm^3\) .
Sucre résiduel : sucre restant après, ou suite à l’arrêt de, la fermentation. Exprimé en g/\(dm^3\) dans les données red et white.
Chlorures : peuvent contribuer à la salinité du vin. Exprimé en g(\(chlorure\ de\ sodium\) )/\(dm^3\) .
Soufre libre (SO2 libre) : la partie du dioxyde de soufre ajoutée au vin et restée active (non liée). Le vigneron cherche à maximiser la part libre. Exprimé en mg/\(dm^3\) .
Soufre total : somme des formes liée et libre de SO2. Exprimé en mg/\(dm^3\) . Limites légales : dans l’UE, 160 mg/L pour les rouges, ~210 mg/L pour blancs et rosés ; 400 mg/L pour les moelleux. Aux États‑Unis : 350 mg/L ; en Australie : 250 mg/L.
Densité : indicateur de la conversion sucre → alcool. Exprimé en g/\(cm^3\) .
pH : mesure d’acidité ou de basicité. pH < 7 = acide ; pH > 7 = basique. L’eau pure a un pH de 7. La plupart des vins ont un pH entre 2,9 et 3,9, donc acides.
Sulfates : fréquemment utilisés en vinification et considérés nécessaires. Ici en g(\(sulfate\ de\ potassium\) )/\(dm^3\) .
Alcool : le pourcentage d’alcool, variable selon les vins. Exprimé en % vol.
Qualité : des experts notent la qualité de 0 (très mauvais) à 10 (excellent). La note finale est la médiane d’au moins trois évaluations.
Voilà pour les bases nécessaires pour démarrer. Si vous êtes un véritable amateur ou une véritable amatrice de vin, vous savez sans doute tout cela – et plus encore !
Passons à la récupération des données.
Charger les données
Cela se fait facilement avec la bibliothèque de manipulation de données Pandas. Respectez la convention d’import et importez le package sous l’alias pd.
Utilisez ensuite read_csv() pour lire les fichiers CSV. Précisez sep pour indiquer que le séparateur est un point‑virgule, et non une virgule.
Essayez dans le bloc DataCamp Light ci‑dessous :
# Import pandas
import pandas as pd
# Read in white wine data
white = ___________("http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv", sep=';')
# Read in red wine data
red = ___________("http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv", sep=';')
Parfait ! Simple comme bonjour, non ?
Vous l’avez sans doute déjà fait mille fois, mais c’est une étape essentielle. Vous êtes maintenant prêt·e à explorer, manipuler et modéliser vos données.
Exploration des données
Avec les données en main, découvrez‑en plus sur ces vins ! Première étape : un rapide coup d’œil aux deux DataFrames :
# Print info on white wine
_____(white.____())
# Print info on red wine
_____(red.____())
Vérifiez maintenant que l’import s’est bien passé : les variables promises par la description UCI sont‑elles présentes ? Au‑delà de leur nombre, contrôlez la qualité de l’import : types corrects ? Lignes complètes ? Valeurs nulles à traiter lors du nettoyage ?
Vous pouvez aussi aller au‑delà de info() :
# First rows of `red`
red.____()
# Last rows of `white`
white.____()
# Take a sample of 5 rows of `red`
red.______(5)
# Describe `white`
white.________()
# Double check for null values in `red`
pd.isnull(red)
Rappel express des fonctions pandas : head(), tail() et sample() offrent un aperçu rapide sans effort.
describe() fournit des statistiques descriptives utiles pour évaluer la qualité des données. Certaines variables présentent des écarts importants entre min et max ; vous les traiterez plus loin, mais gardez‑le en tête.
Enfin, vous avez vérifié l’absence de valeurs nulles dans red avec isnull(), pratique si un doute subsiste après info().
Astuce : vérifiez aussi la présence de valeurs nulles dans les données du vin blanc via l’IPython shell du bloc ci‑dessus.
Après ce contrôle d’import, allons un cran plus loin.
Visualiser les données
Une approche consiste à observer la distribution de certaines variables et tracer des nuages de points pour détecter des corrélations potentielles. Pour un projet, vous pourriez aller beaucoup plus loin.
Alcool
Une variable intéressante au premier regard : alcohol. Elle attire souvent l’attention lorsqu’on parcourt un dataset sur le vin. Vous pouvez visualiser les distributions avec n’importe quelle bibliothèque, mais nous utiliserons ici matplotlib pour aller vite :
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 2)
ax[0].hist(red.alcohol, 10, facecolor='red', alpha=0.5, label="Red wine")
ax[1].hist(white.alcohol, 10, facecolor='white', ec="black", lw=0.5, alpha=0.5, label="White wine")
fig.subplots_adjust(left=0, right=1, bottom=0, top=0.5, hspace=0.05, wspace=1)
ax[0].set_ylim([0, 1000])
ax[0].set_xlabel("Alcohol in % Vol")
ax[0].set_ylabel("Frequency")
ax[1].set_xlabel("Alcohol in % Vol")
ax[1].set_ylabel("Frequency")
#ax[0].legend(loc='best')
#ax[1].legend(loc='best')
fig.suptitle("Distribution of Alcohol in % Vol")
plt.show()
Comme le montre le graphique ci‑dessous, les niveaux d’alcool des vins rouges et blancs sont globalement similaires : autour de 9 % d’alcool, avec de nombreuses observations à 10 % ou 11 %.
Vous pouvez le vérifier avec histogram() de numpy pour calculer l’histogramme des données white et red :
import numpy as np
print(np.histogram(red.alcohol, bins=[7,8,9,10,11,12,13,14,15]))
print(np.histogram(white.alcohol, bins=[7,8,9,10,11,12,13,14,15]))
Si les tutoriels matplotlib vous intéressent, consultez le tutoriel Matplotlib pour débutants et le tutoriel Viewing 3D Volumetric Data , qui montre comment utiliser l’API d’événements de Matplotlib.
Sulfates
Je m’intéresse ensuite au lien entre sulfates et qualité. Les sulfites peuvent donner mal à la tête ; cela influence‑t‑il la qualité perçue ? On entend souvent que les femmes évitent le vin pour cette raison. Cela affecte‑t‑il les notes des vins rouges ?
Regardons.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 2, figsize=(8, 4))
ax[0].scatter(red['quality'], red["sulphates"], color="red")
ax[1].scatter(white['quality'], white['sulphates'], color="white", edgecolors="black", lw=0.5)
ax[0].set_title("Red Wine")
ax[1].set_title("White Wine")
ax[0].set_xlabel("Quality")
ax[1].set_xlabel("Quality")
ax[0].set_ylabel("Sulphates")
ax[1].set_ylabel("Sulphates")
ax[0].set_xlim([0,10])
ax[1].set_xlim([0,10])
ax[0].set_ylim([0,2.5])
ax[1].set_ylim([0,2.5])
fig.subplots_adjust(wspace=0.5)
fig.suptitle("Wine Quality by Amount of Sulphates")
plt.show()
Comme on le voit ci‑dessous, le vin rouge semble contenir davantage de sulfates que le blanc, qui en a rarement au‑delà de 1 g/\(dm^3\) . Pour le blanc, seules quelques observations dépassent légèrement 1 g/\(dm^3\) , alors que c’est plus fréquent pour les rouges. Cela pourrait expliquer l’idée reçue selon laquelle le rouge donne mal à la tête. Mais qu’en est‑il de la qualité ?
On observe du vin blanc avec peu de sulfates et une note de 9, mais il est difficile d’aller plus loin dans l’interprétation à ce stade.
N’oubliez pas que la différence de volumes d’observations peut aussi influer sur les graphiques et leur lecture.
Acidité
Au‑delà des sulfates, l’acidité est un attribut clé pour obtenir de grands vins. Les meilleurs équilibrent acidité, tanins, alcool et sucrosité. D’après la littérature, entre 0,2 et 0,4 g/L, l’acidité volatile n’affecte pas la qualité ; au‑delà, elle donne une sensation vineuse piquante. Une acidité volatile extrême révèle un vin gravement défectueux.
Mettons les données à l’épreuve avec un nuage de points alcool vs acidité volatile, coloré par la quality :
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(570)
redlabels = np.unique(red['quality'])
whitelabels = np.unique(white['quality'])
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 2, figsize=(8, 4))
redcolors = np.random.rand(6,4)
whitecolors = np.append(redcolors, np.random.rand(1,4), axis=0)
for i in range(len(redcolors)):
redy = red['alcohol'][red.quality == redlabels[i]]
redx = red['volatile acidity'][red.quality == redlabels[i]]
ax[0].scatter(redx, redy, c=redcolors[i])
for i in range(len(whitecolors)):
whitey = white['alcohol'][white.quality == whitelabels[i]]
whitex = white['volatile acidity'][white.quality == whitelabels[i]]
ax[1].scatter(whitex, whitey, c=whitecolors[i])
ax[0].set_title("Red Wine")
ax[1].set_title("White Wine")
ax[0].set_xlim([0,1.7])
ax[1].set_xlim([0,1.7])
ax[0].set_ylim([5,15.5])
ax[1].set_ylim([5,15.5])
ax[0].set_xlabel("Volatile Acidity")
ax[0].set_ylabel("Alcohol")
ax[1].set_xlabel("Volatile Acidity")
ax[1].set_ylabel("Alcohol")
#ax[0].legend(redlabels, loc='best', bbox_to_anchor=(1.3, 1))
ax[1].legend(whitelabels, loc='best', bbox_to_anchor=(1.3, 1))
#fig.suptitle("Alcohol - Volatile Acidity")
fig.subplots_adjust(top=0.85, wspace=0.7)
plt.show()
Notez que les couleurs sont choisies aléatoirement via numpy.random. Vous pouvez fournir votre propre liste à redcolors et whitecolors (assurez‑vous qu’elles correspondent – sauf 1, car le blanc a une valeur de quality unique de plus – sinon les légendes ne correspondront pas).
Consultez le graphique complet ici :
On constate que les niveaux mentionnés plus haut se vérifient surtout pour le blanc : la plupart des vins notés 8 ont une acidité volatile de 0,5 ou moins. Difficile toutefois de conclure sur l’impact direct sur la qualité, les points étant très denses d’un côté du graphique.
Ceci n’est qu’une exploration rapide. Pour aller plus loin, consultez nos ressources d’exploration de données : les tutoriels Python Exploratory Data Analysis et Python Data Profiling .
Conclusion de l’EDA
Beaucoup d’informations à digérer ; voici un récapitulatif utile pour la suite :
Certaines variables présentent des valeurs très éloignées ; vous traiterez cela ensuite.
Bonne nouvelle : pas de valeurs nulles.
La plupart des vins ont environ 9 % d’alcool.
Le vin rouge semble contenir plus de sulfates que le blanc, qui en compte rarement au‑delà de 1 g/\(dm^3\) .
La plupart des vins ont une acidité volatile ≤ 0,5. Pas de lien direct évident avec la qualité pour l’instant.
Jusqu’ici, vous avez examiné rouge et blanc séparément. Les deux diffèrent sur certaines variables et se ressemblent sur d’autres. Pensez‑vous qu’on puisse classer automatiquement une entrée en rouge ou blanc à partir de ses variables ?
Une seule façon de le savoir : prétraitez et modélisez !
Prétraiter les données
Maintenant que vous avez exploré vos données, mettez à profit ces enseignements ! Prétraitez pour pouvoir construire votre réseau de neurones.
# Add `type` column to `red` with value 1
___['type'] = 1
# Add `type` column to `white` with value 0
_____['type'] = 0
# Append `white` to `red`
wines = red.______(white, ignore_index=True)
Ici, vous mettez ignore_index à True pour ne pas conserver les index de white lors de l’assemblage avec red : les étiquettes d’index doivent continuer celles de red, sans doublons dus à la concaténation.
Intermède : matrice de corrélation
Maintenant que vous avez le jeu complet, faites une exploration rapide. Vous avez déjà quelques idées issues des jeux séparés ; consolidons‑les.
Comme les graphiques peuvent être difficiles à interpréter, tracez une matrice de corrélation pour identifier rapidement les variables corrélées :
import seaborn as sns
corr = wines.corr()
sns.heatmap(corr,
xticklabels=corr.columns.values,
yticklabels=corr.columns.values)
sns.plt.show()
Comme attendu, certaines variables corrèlent, par exemple density et residual sugar. volatile acidity et type sont plus liées que ce qu’on entrevoyait séparément, et il était prévisible que free sulfur dioxide et total sulfur dioxide corrèlent.
Très instructif !
Ensembles d’entraînement et de test
On parle de données déséquilibrées quand les classes ne sont pas représentées équitablement. La majorité des datasets de classification ne sont pas parfaitement équilibrés, et une petite différence n’est pas critique. Il faut cependant s’assurer que les deux classes (rouge et blanc) soient présentes dans l’entraînement, et en quantités comparables pour ne pas favoriser une classe dans les prédictions.
Ici, il existe un déséquilibre, mais nous allons poursuivre ainsi pour l’instant. Si le modèle sous‑performe, vous pourrez recourir à l’undersampling ou à l’oversampling.
Pour l’heure, importez train_test_split depuis sklearn.model_selection et affectez les données et étiquettes cibles aux variables X et y. Il faut aplatir le tableau d’étiquettes cibles pour utiliser correctement train_test_split(). À vous de jouer :
# Import `train_test_split` from `sklearn.model_celection`
from sklearn.model_selection import train_test_split
# Specify the data
X=wines.ix[:,0:11]
# Specify the target labels and flatten the array
y=np.ravel(wines.type)
# Split the data up in train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
Vous êtes en bonne voie pour construire votre premier réseau de neurones, mais il reste un point : souvenez‑vous de ce qu’a révélé le descriptif des jeux white et red…
En effet, certaines valeurs étaient très éloignées. Il est pertinent de standardiser.
Standardiser les données
La standardisation permet de gérer ces écarts. Scikit‑learn propose une solution simple et rapide : importez StandardScaler depuis sklearn.preprocessing et mettez à l’échelle vos ensembles d’entraînement et de test !
from sklearn. preprocessing import StandardScaler
scaler = StandardScaler( ) . fit( X_train)
X_train = scaler. transform( X_train)
X_test = scaler. transform( X_test) Propulsé par
Vos données étant prétraitées, passons au cœur du sujet : construire un réseau de neurones pour classifier les vins.
Modéliser les données
Avant de modéliser, revenez à la question : peut‑on prédire si un vin est rouge ou blanc à partir de ses propriétés chimiques (acidité volatile, sulfates, etc.) ?
Comme vous n’avez que deux classes (blanc et rouge), il s’agit d’une classification binaire. « Binaire » signifie 0 ou 1, non ou oui. Les réseaux ne manipulant que des données numériques, vous avez déjà encodé rouge = 1 et blanc = 0.
Un perceptron multicouche fonctionne bien sur ce type de problème. Comme vu au début, il est souvent entièrement connecté. Vous allez donc construire une pile simple de couches denses. Pour la fonction d’activation, utilisez l’une des plus courantes pour vous familiariser avec Keras : la fonction ReLU.
Pour démarrer rapidement, utilisez le modèle Séquentiel de Keras : une pile linéaire de couches. Créez le modèle en passant une liste de couches au constructeur, initialisée avec model = Sequential().
Souvenez‑vous de la structure : une couche d’entrée, des couches cachées, une couche de sortie. Votre première couche doit connaître la forme de l’entrée. D’où la présence des arguments input_shape, input_dim, input_length ou batch_size dans la documentation.
Ici, vous utiliserez une couche Dense (entièrement connectée), qui implémente : output = activation(dot(input, kernel) + bias). Sans activation, Dense ne ferait qu’un produit scalaire suivi d’une addition.
Dans la première couche, l’argument activation vaut relu. input_shape est défini : le modèle attend des tableaux de forme (12,) (soit (*, 12)). La première couche a 12 unités (units), soit la dimension de l’espace de sortie : le modèle renverra des tableaux de forme (*, 12). Pas d’inquiétude si cela n’est pas encore clair.
Les units représentent en fait le kernel de la formule (matrice des poids de toutes les entrées). Notez que l’exemple ci‑dessous n’inclut pas de biais (use_bias non spécifié).
La couche intermédiaire utilise aussi relu. Sa sortie a la forme (*,8).
Le réseau se termine par une couche Dense de taille 1. La couche finale utilise une sigmoïde pour produire une probabilité entre 0 et 1 : la probabilité que l’échantillon soit de classe « 1 », donc un vin rouge.
# Import `Sequential` from `keras.models`
from keras.models import Sequential
# Import `Dense` from `keras.layers`
from keras.layers import Dense
# Initialize the constructor
model = Sequential()
# Add an input layer
model.add(Dense(12, activation='relu', input_shape=(11,)))
# Add one hidden layer
model.add(Dense(8, activation='relu'))
# Add an output layer
model.add(Dense(1, activation='sigmoid'))
Deux décisions architecturales clés : le nombre de couches et le nombre d’unités cachées par couche.
Ici, vous avez choisi 12 unités cachées pour la première couche : vous réglez la liberté d’expression du réseau. Davantage d’unités permettent d’apprendre des représentations plus complexes, au risque d’un coût plus élevé et d’un surapprentissage.
Le surapprentissage (overfitting) survient quand le modèle est trop complexe : il capte le bruit aléatoire plutôt que la relation sous‑jacente. Autrement dit, il modélise trop bien les données d’entraînement.
Si vous avez peu de données d’entraînement, privilégiez un petit réseau (souvent une seule couche cachée, comme ici).
Pour obtenir des informations sur le modèle, utilisez l’attribut output_shape ou la fonction summary(), entre autres. Essayez ces appels :
# Model output shape
model.___________
# Model summary
model.__________
# Model config
model.get_config()
# List all weight tensors
model.get_weights()
Compiler et ajuster
Il est temps de compiler et d’ajuster votre modèle : utilisez compile() puis fit().
model. compile ( loss= 'binary_crossentropy' ,
optimizer= 'adam' ,
metrics= [ 'accuracy' ] )
model. fit( X_train, y_train, epochs= 20 , batch_size= 1 , verbose= 1 ) Propulsé par
Lors de la compilation, vous configurez l’optimiseur adam et la fonction de perte binary_crossentropy. Vous suivez en plus la précision via ['accuracy'].
optimizer et loss sont requis pour compiler. Parmi les algorithmes d’optimisation populaires : descente de gradient stochastique (SGD), Adam et RMSprop. Selon l’algorithme, vous réglerez des paramètres comme le taux d’apprentissage ou le momentum. Le choix de la perte dépend de la tâche : en régression, on utilise souvent l’erreur quadratique moyenne (MSE). Ici, pour la classification binaire rouge/blanc, vous utilisez binary_crossentropy. Pour la classification multiclasse, utilisez categorical_crossentropy.
Entraînez ensuite le modèle 20 époques (itérations sur l’ensemble X_train/y_train) par lots d’un échantillon. Avec verbose=1, vous affichez une barre de progression.
En d’autres termes, vous entraînez le modèle pendant un nombre d’époques donné (un passage complet sur l’entraînement), avec une taille de lot définissant combien d’échantillons sont propagés à la fois, ce qui optimise l’efficacité mémoire.
Prédire
Mettez votre modèle à l’épreuve ! Prédisez les étiquettes de l’ensemble de test avec predict(). Le résultat est stocké dans y_pred :
y_pred = model. predict( X_test) Propulsé par
Avant l’évaluation formelle, jetez un œil à la concordance entre y_pred et y_test :
y_pred[ : 5 ] Propulsé par
array( [ [ 0 ] ,
[ 1 ] ,
[ 0 ] ,
[ 0 ] ,
[ 0 ] ] , dtype= int32) Propulsé par
y_test[ : 5 ] Propulsé par
array( [ 0 , 1 , 0 , 0 , 0 ] ) Propulsé par
Ces valeurs semblent cohérentes. Passons aux chiffres.
Évaluer le modèle
Maintenant que vous avez construit et utilisé votre modèle pour prédire sur des données inédites, évaluez ses performances. Vous pouvez comparer visuellement aux étiquettes réelles (y_test) ou utiliser des métriques. Ici, nous utiliserons evaluate(). Passez les données et, si besoin, verbose=1 pour plus de logs.
score = model. evaluate( X_test, y_test, verbose= 1 )
print ( score) Propulsé par
[ 0.025217213829228164 , 0.99487179487179489 ] Propulsé par
La liste renvoie la perte et la précision. Les scores semblent excellents, mais souvenez‑vous : les données étaient déséquilibrées (davantage de vins blancs). La précision peut refléter la distribution de classes si le modèle « joue la majorité ».
Avant de rééquilibrer, testez d’autres métriques. Appuyez‑vous sur scikit‑learn (sklearn) comme précédemment pour créer les ensembles d’entraînement/test.
Nous allons calculer quelques métriques classiques :
Matrice de confusion : répartition des prédictions, montrant les bonnes et les erreurs par type. Idéalement, des valeurs uniquement sur la diagonale.
Précision (precision) : mesure de l’exactitude du classifieur. Plus elle est élevée, plus les prédictions positives sont correctes.
Rappel (recall) : mesure de l’exhaustivité. Plus il est élevé, plus de cas positifs sont couverts.
F1‑score : moyenne harmonique de la précision et du rappel.
Kappa de Cohen : précision normalisée tenant compte du déséquilibre des classes.
from sklearn. metrics import confusion_matrix, precision_score, recall_score, f1_score, cohen_kappa_score
confusion_matrix( y_test, y_pred) Propulsé par
array( [ [ 1585 , 3 ] ,
[ 8 , 549 ] ] ) Propulsé par
precision_score( y_test, y_pred) Propulsé par
0.994565217391 Propulsé par
recall_score( y_test, y_pred) Propulsé par
0.98563734290843807 Propulsé par
f1_score( y_test, y_pred) Propulsé par
0.99008115419296661 Propulsé par
cohen_kappa_score( y_test, y_pred) Propulsé par
0.98662321692498967 Propulsé par
Excellents résultats ! Vous avez construit un modèle très précis malgré davantage d’observations de vins blancs.
Bravo !
Aller plus loin avec des expériences
Vous avez réussi votre premier modèle ; allons plus loin. Testez les pistes suivantes et observez leur impact. Comme évoqué, vos deux leviers principaux sont le nombre de couches et le nombre d’unités cachées :
Vous avez utilisé 1 couche cachée. Essayez 2 ou 3.
Augmentez ou réduisez le nombre d’unités cachées par couche.
Prenez la colonne quality comme cible et le reste (y compris type encodée) comme données. Vous obtenez une classification multiclasse !
Testez aussi d’autres fonctions d’activation : au lieu de relu, essayez tanh et comparez.
Prédire la qualité des vins
Votre modèle de classification a très bien performé pour une première itération !
Mais vous pouvez aller au‑delà d’un perceptron multicouche. Pourquoi ne pas créer un réseau de neurones pour prédire la qualité du vin ?
Ici, nous supposons que quality est une variable continue : la tâche devient une régression ordinale. On prédit une variable ordinale, où l’ordre relatif des valeurs de quality est significatif. L’échelle 0–10 (« très mauvais » à « excellent ») en est un exemple.
Vous pourriez aussi traiter ce problème en classification, avec des classes fixes par note.
Dans tous les cas, cette mise en place signifie que vos étiquettes cibles seront la colonne quality dans vos DataFrames red et white. Cela nécessite un prétraitement additionnel.
Prétraiter les données
Puisque quality devient la cible, isolez les étiquettes de qualité du reste. Placez wines.quality dans y et le reste des données (sans quality) dans X.
Vous pourriez à nouveau découper en train/test, mais ici nous utiliserons une validation croisée en k volets : on partage en K partitions (souvent 4 ou 5), on instancie des modèles identiques, on les entraîne chacun sur une partition et on évalue sur les autres. Le score de validation est la moyenne des K scores.
Vous verrez comment faire juste après. Pour l’instant, standardisez vos données avec StandardScaler, comme précédemment.
# Isolate target labels
y = wines.________
# Isolate data
X = wines.drop('quality', axis=_)
N’oubliez pas de remettre à l’échelle : certaines variables de red, white (et donc wines) diffèrent beaucoup.
Essayez dans le bloc ci‑dessous. Les bibliothèques nécessaires sont chargées !
# Scale the data with `StandardScaler`
X = ________________.fit_transform(X)
Vous revoilà au même point : prêt·e à modéliser.
Définir l’architecture du réseau
Après prétraitement, construisez à nouveau un perceptron multicouche. Même pour une régression, l’architecture peut rester proche : deux couches Dense.
N’oubliez pas : la première est la couche d’entrée. Vous passerez la dimension des données via input_dim.
# Import `Sequential` from `keras.models`
from keras.models import Sequential
# Import `Dense` from `keras.layers`
from keras.layers import Dense
# Initialize the model
model = Sequential()
# Add input layer
model.add(Dense(64, input_dim=12, activation='relu'))
# Add output layer
model.add(Dense(1))
Rappel : la première couche définit l’entrée. Vous passez 12 comme dimension (n’oubliez pas la colonne Type ajoutée en première partie). Vous utilisez encore relu, sans biais, avec 64 unités cachées.
Votre réseau se termine par une seule unité Dense(1), sans activation. C’est l’architecture typique d’une régression scalaire (prédire une valeur continue).
Compiler le modèle, ajuster les données
Avec le modèle prêt, compilez‑le et ajustez‑le. Mais attendez : n’avions‑nous pas parlé de validation en k volets ? Exact.
import numpy as np
from sklearn. model_selection import StratifiedKFold
seed = 7
np. random. seed( seed)
kfold = StratifiedKFold( n_splits= 5 , shuffle= True , random_state= seed)
for train, test in kfold. split( X, Y) :
model = Sequential( )
model. add( Dense( 64 , input_dim= 12 , activation= 'relu' ) )
model. add( Dense( 1 ) )
model. compile ( optimizer= 'rmsprop' , loss= 'mse' , metrics= [ 'mae' ] )
model. fit( X[ train] , Y[ train] , epochs= 10 , verbose= 1 ) Propulsé par
Utilisez compile() pour compiler, puis fit() pour entraîner. Définissez au minimum optimizer et loss. Ici, vous pouvez utiliser rsmprop (un des plus populaires) et mse pour la perte, typique des problèmes de régression.
Le paramètre metrics définit la mesure d’évaluation : en régression, on utilise souvent l’erreur absolue moyenne (MAE). Vous en verrez plus au prochain paragraphe.
Passez les données et étiquettes d’entraînement à fit(), définissez le nombre d’époques, la taille de lot, et éventuellement verbose=1 pour suivre la progression.
Évaluer le modèle
Comme précédemment, évaluez votre modèle. En plus de y_pred = model.predict(X[test]), utilisez des métriques de sklearn comme dans la première partie.
Servez‑vous de l’erreur quadratique moyenne (MSE) et de l’erreur absolue moyenne (MAE). La première (aussi appelée « mean squared deviation », MSD) mesure la moyenne des carrés des erreurs ; plus elle est proche de zéro, mieux c’est. La seconde (MAE) quantifie l’écart moyen absolu entre prédictions et valeurs réelles.
Ajoutez ces lignes au code ci‑dessus (attention à l’indentation) :
mse_value, mae_value = model. evaluate( X[ test] , Y[ test] , verbose= 0 )
print ( mse_value)
0.522478731072
print ( mae_value)
0.561965950103 Propulsé par
Outre MSE et MAE, vous pouvez également utiliser le score R2 (coefficient de détermination). Le meilleur score est 1, mais il peut être négatif.
from sklearn. metrics import r2_score
r2_score( Y[ test] , y_pred)
0.3125092543 Propulsé par
À première vue, ces chiffres ne sont pas fameux. L’avantage : vous pouvez maintenant expérimenter pour améliorer les résultats.
C’est l’objet de la dernière section.
Affiner le modèle
L’affinage est une étape clé, car tous les problèmes ne sont pas aussi directs que dans la première partie. Comme évoqué, vous ajusterez surtout le nombre de couches et d’unités cachées.
Au début, c’est un vrai parcours d’essais et d’erreurs.
Ajouter des couches
Que se passe‑t‑il si vous ajoutez une couche ? Par exemple :
model = Sequential( )
model. add( Dense( 64 , input_dim= 12 , activation= 'relu' ) )
model. add( Dense( 64 , activation= 'relu' ) )
model. add( Dense( 1 ) ) Propulsé par
Unités cachées
Essayez aussi d’augmenter le nombre d’unités cachées et observez l’impact sur l’évaluation :
model = Sequential( )
model. add( Dense( 128 , input_dim= 12 , activation= 'relu' ) )
model. add( Dense( 1 ) ) Propulsé par
Rappel : comme vous n’avez pas un volume de données énorme, le risque de surapprentissage augmente avec la taille du réseau. Préférez un petit réseau.
Autres essais : paramètres d’optimisation
Au‑delà des couches et des unités, jouez aussi sur les paramètres de l’algorithme d’optimisation passé à compile(). Jusqu’ici, vous avez passé une chaîne comme rmsprop à l’argument optimizer.
Mais vous pouvez faire autrement !
Par exemple, importez RMSprop depuis keras.models et ajustez le taux d’apprentissage lr. Vous pouvez aussi modifier d’autres paramètres par défaut de RMSprop() (non recommandé). Plus d’infos ici .
from keras. optimizers import RMSprop
rmsprop = RMSprop( lr= 0.0001 )
model. compile ( optimizer= rmsprop, loss= 'mse' , metrics= [ 'mae' ] ) Propulsé par
Expérimentez aussi d’autres optimisateurs, comme la descente de gradient stochastique (SGD). Observez‑vous un effet ?
from keras. optimizers import SGD, RMSprop
sgd= SGD( lr= 0.1 )
model. compile ( optimizer= sgd, loss= 'mse' , metrics= [ 'mae' ] ) Propulsé par
Allez plus loin !
Ce tutoriel n’est qu’un point de départ pour votre parcours en deep learning avec Python et Keras. Il reste beaucoup à explorer : pourquoi ne pas suivre le cours Deep Learning in Python de DataCamp ? En attendant, parcourez la documentation Keras si ce n’est déjà fait : vous y trouverez des exemples, des informations détaillées sur les fonctions, les arguments, d’autres couches, etc. Une ressource incontournable pour apprendre à utiliser les réseaux de neurones en Python ! Si vous préférez un livre expliquant les fondamentaux du deep learning (avec Keras) et ses applications pratiques, lisez sans hésiter l’ouvrage de François Chollet Deep Learning in Python .
Vous connaissez sans doute déjà le machine learning, branche de l’informatique qui étudie la conception d’algorithmes capables d’apprendre. Aujourd’hui, vous allez vous concentrer sur le deep learning, sous-domaine du machine learning qui regroupe des algorithmes inspirés de la structure et du fonctionnement du cerveau. Ces algorithmes sont généralement appelés réseaux de neurones artificiels (ANN). Le deep learning est l’un des domaines phares de la data science, avec des cas d’usage qui affichent des résultats étonnants en robotique, en reconnaissance d’images et en intelligence artificielle (IA).
Parmi les bibliothèques Python les plus puissantes et faciles à utiliser pour développer et évaluer des modèles de deep learning, on trouve Keras ; elle s’appuie sur les bibliothèques de calcul numérique performantes Theano et TensorFlow. L’avantage : démarrer avec les réseaux de neurones devient simple et agréable.
Le tutoriel Keras du jour, pensé pour les débutants, vous présentera les bases du deep learning en Python :