Leçon: Workflow pour le deep learning orienté pour Tensorflow¶

Les différentes étapes¶

  1. Charger les données
  2. Pré-traiter les données
  3. Construire une architecture ou importer un modèle pré-entrainé (nombre de couche, de neurones par couche, type de cellules, architecture du réseau)
  4. Définir les hyper-paramètre relatifs à chaque couche (fonction d'activation)
  5. Définir les hyper-paramètres relatifs à l'apprentissage (optimiseur, fonction de perte)
  6. Définir la métrique d'évaluation
  7. Entrainer le réseau
  8. Monitorer et gérer le sur-apprentissage (courbes d'apprentissange, early stopping, couche de régularisation, early stopping, batch normalisation)
  9. Sauvegarder le réseau
In [ ]:
import tensorflow as tf
from tensorflow import keras

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

Charger les données¶

A partir de data set externes¶

On peut utiliser la librairie pandas pour charger des données tabulaires, par exemple:

In [ ]:
# chargement du dataset AutoMPG de puis le site ce l'UCI
url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data'
column_names = ['MPG', 'Cylinders', 'Displacement', 'Horsepower', 'Weight',
                'Acceleration', 'Model Year', 'Origin']

raw_dataset = pd.read_csv(url, names=column_names,
                          na_values='?', comment='\t',
                          sep=' ', skipinitialspace=True)
X = raw_dataset.drop(columns='MPG')
y = raw_dataset['MPG']

Créer des pipelines de données (module tf.data.Dataset)¶

  • Une source de données qui construit un data set à partir de données en mémoire : utiliser tf.data.DataSet.from_tensors() ou tf.data.Dataset.from_tensor_slices()
  • Une transformation de données qui construit un esemble de données à partir d'objets de tf.data.Dataset: par exemple pour appliquer des transformations par élément avec DataSet.map() ou des transformations multi-éléments comme la création de batches avec Dataset.batch
In [ ]:
X_tensor = tf.data.Dataset.from_tensors(X)
y_tensor = tf.data.Dataset.from_tensors(y)

X_tensor
In [ ]:
list(X_tensor.as_numpy_iterator())

Pré-traitements des données¶

En utilisant les pipelines de Tensorflow¶

Dans Tensroflow, l'API de keras permet d'appliquer des pré-traitements aux données en mémoire en utilisant des couches de pré-traitements de différents types:

  • pour le pré-traitement de données numériques continues (normalisation, discretisation)
  • le pré-traitement de données catégorielles (enocding, ...)
  • le pré-traitement de données textuelles (vectorisation)
  • le pré-traitement d'images (crop, resizing, rescaling)
  • l'augmentation de données d'images (crop, rotations, translations, ...)

Exemple d'implémentation d'une couche de normalisation:¶

Définition et application de la couche de normalisation:

In [ ]:
normalizer = tf.keras.layers.Normalization(axis=-1)
normalizer.adapt(X_tensor)

Exemple d'implémentation d'une couche de vectorisation de données textuelles:¶

In [ ]:
from tensorflow.keras import layers
data = [
    "ξεῖν᾽, ἦ τοι μὲν ὄνειροι ἀμήχανοι ἀκριτόμυθοι",
    "γίγνοντ᾽, οὐδέ τι πάντα τελείεται ἀνθρώποισι.",
    "δοιαὶ γάρ τε πύλαι ἀμενηνῶν εἰσὶν ὀνείρων:",
    "αἱ μὲν γὰρ κεράεσσι τετεύχαται, αἱ δ᾽ ἐλέφαντι:",
    "τῶν οἳ μέν κ᾽ ἔλθωσι διὰ πριστοῦ ἐλέφαντος,",
]
layer = layers.TextVectorization()
layer.adapt(data)
vectorized_text = layer(data)
print(vectorized_text)

Pour un exemple complet de pre-traitement, voir ce notebook

Construction du réseau de neurone¶

Architecture du modèle¶

Choix du type de réseau¶

Avec les progrès de la recherche en IA ces dernières années, de nombreux modèles ont vu le jour et de nouvelles architectures appraissent.

On peut cependant classer quelques types caractéristiques d'architecture, qu'il faudra choisir en fonction de vôtre tâche:

Le perceptron multi-couche (MLP) ou réseau dense¶

Il est généralement utilisé dans les tâches standard de classification ou de régression.

Du fait de sa propriété d'universalité, il est parfois utilisé dans certaines tâches pour approximer une fonction, par exemple la fonction d'évaluation dans les jeux à somme constante.

Les réseaux convolutifs ou Convolutionnal Neural Network (CNN)¶

Ils sont principalement utilisé dans le traitement de vision par ordinateur (images 2D et 3D), mais les CNN à 1 dimensions sont parfois également utilisés pour apprendre des motifs particuliers dans les séquences (langage, série temporelle)

No description has been provided for this image

Les réseaux récurrents ou Recurrent Neural Network (RNN)¶

Ils sont principalement utilisé dans le traitement de séquences (langage, séries, temporelles, ...). Ils ont connu plusieurs variations avec les modèles intégrant des capacité de mémoire, comme les LSTM (Long Short Term Memory) et GRU (Gated Recurrent Unit)

No description has been provided for this image

Les auto-encodeurs¶

Il s'agit d'un des rares modèles en deep learning pouvant être utilisé pour des tâches non supervisée: on utilise généralement en récupérant ses couches cachées sous forme de variables latentes, par exemple pour des tâches de segmentation de données ou pour débiaiser des données

No description has been provided for this image

Les GAN(s)¶

Il s'agit de modèles génératifs, inventés en 2014, et qui sont devenus depuis particulièrement populaires, en particulier pour la génération d'images et de sons

No description has been provided for this image

Les Transformers¶

Il s'agit d'une catégorie de très gros modèles, appartenant à la classe des réseaux attentionnels.

Ce type de réseaux utilise des mécaniques d'attention pour combattre les phénomènes de perte d'information en conservant en mémoire des états précédants du réseaux.

Inventés en 2017, ils sont principalement utilisé par apprentissage par transfert dans différentes tâches de traitement du langage, comme la génération de texte, la réponse au question, le résumé, la traduction, ...

Ils sont à la base de la plupart des Large Langage Models (LLM) dont le fameux GPT

No description has been provided for this image

...

Choix des couches : type et nombre de couches, neurones par couches¶

Il s'agit des principaux hyper-paramètres ayant un impact généralement le plus important sur les performances, il conditionne la complexité de votre réseau.

En fonction de la tâche à traiter, 3 scenarii sont possibles:

  • utiliser un réseau déja pré-entrainé (apprentissage par transfert) sans le ré-entraîner: vous ne changer pas son architecture
  • utiliser un réseau pré-entrainé et ré-entrainer certaines couches spécifiquement (fine tuning): vous pouvez décidez de changer certaines couches du réseau à ré-entrainer
  • créer complètement l'architecture de votre réseau

Intuition¶

  • nombre de neurone par couche : nombre de "motifs" différents capturé dans les données
  • nombre de couches : "niveau de granularité" dans les motifs crées par votre réseau

Code avec l'API Sequential de keras¶

Cette API est pensée pour refléter une manière simple de penser le réseau comme un empilement de couches (où chaque couche à exactement un tenseur d'entrée et un tenseur de sortie):

In [ ]:
 model = tf.keras.Sequential([
  # couche 1
  # couche 2
  # ...   
  ])
In [ ]:
model = tf.keras.Sequential()
model.add(...) # on passe en argument un objet layer
model.add(...)
...

Si votre réseau possède une topologie particulière (plusieurs entrée ou sorties, connexions entre couches, ...) vous devrez utiliser l'API fonctionnelle de Keras, plus souple

Afficher l'architecure et les paramètres du réseau¶

In [ ]:
model.summary()

Fonction d'activation¶

Permet d'introduire une non-linéarité dans le traitement des données, permettant au réseau d'approximer n'importe qu'elle fonction (propriété d'universalité des réseaux de neurones)

Vous pouvez choisir parmi celles disponibles dans l'API de keras ou sinon implémenter votre propre fonction d'activation.

La communauté des chercheurs et utilisateurs recommandent l'utilisation par défaut de relu car elle est rapide à calculer

Exemple avec un réseau dense (MLP):¶

In [ ]:
 model = tf.keras.Sequential([
    keras.layers.Dense(64, activation='relu'),
    keras.layers.Dense(64, activation='relu'),
    keras.layers.Dense(10)
  ])

Optimiseur & learning rate¶

Il s'agit de l'algorithme utilisé pour trouver les meilleurs paramètres, ceux qui minimisent l'erreur mesurée par la fonction de perte

En deep learning on utilise quasi exclusivement des variantes de l'algorithme de descente de gradient stochastique calculée par mini-batches que vous pouvez choisir parmi ceux disponibles dans l'API de keras

La communauté des chercheurs et utilisateurs recommande l'utilisation par défaut de Adam car il combine plusieurs propriétés avantageuses:

  • intégre un learning rate adaptatif : il varie en fonction de l'historique passé des gradients
  • intégre les moments: ajoute de l'inertie au calcul du gradient (en gardant en mémoire les valeurs précédantes du gradient), ce qui peut aider le gradient à ressortir d'un minimum local
  • intégre la capacité à sélectionner les features ayant été le moins mise à jour à l'itération précédante (comme AdaGrad)
  • il est rapide à calculer (par rapport à AdaGrad)
  • il fonctionne bien avec des réseaux de grande taille

No description has been provided for this image

Pour les réseaux récurrents, on utilise plus souvent historiquementRMSprop

Pour les embeding, Adamax donne généralement de meilleurs résultats que Adam

Exemple avec l'optimiseur Adam :¶

In [ ]:
model.compile(optimizer = tf.keras.optimizers.adam())

Fonction de perte (loss) : $L(\theta_1,\theta_2, \cdots \theta_i)$¶

La fonction de perte mesure l'erreur faite par l'optimiseur au moment de l'apprentissage.

Mathématiquement, elle doit être une fonction continue et différenciable pour chaque $\theta_i$. En pratique, on peut se la représenter comme un vallée dont la topgraphie est "lisse" mais complexe

En fonction de la tâche à résoudre (classification, régréssion, ...), vous pouvez choisir parmi celles disponibles dans l'API de keras ou sinon implémenter la votre.

Par exemple, pour la classification on utilise souvent la binary cross entropy ou log loss, car elle renvoie des valeurs qui varient de manière plus "lisse": $$ Log Loss = -\frac{1}{n}\sum_{i=0}^{n}y_ilog(\hat y_i) + (1 - y_i)log(1 - \hat y_i) $$

Utilisation dans keras :¶

In [ ]:
# si vous choisissez parmi la liste proposées
model.compile(loss = "binary_crossentropy")


# ou en utlisant l'objet dédié (plus flexible)
loss = keras.losses.BinaryCrossentropy(...)
model.compile(loss = loss)

# si vous choisissez de coder votre propre loss
def custom_mse(y_true, y_pred):
    squared_diff = tf.square(y_true - y_pred)
    return tf.reduce_mean(squared_diff)

model.compile(loss=custom_mse)

Métrique d'évaluation¶

Elle mesure la performance de votre modèle à résoudre la tâche, c'est à dire une fois l'apprentissage effectué (en général, elle est différente de la fonction de perte). Il est donc important de bien la choisir en fonction des caractéristiques de la tâche !

Vous pouvez choisir parmi celles disponibles dans l'API de keras ou sinon implémenter la votre.

Exemple avec la métrique RMSE¶

On définit la métrique a utiliser avant l'apprentissage:

In [ ]:
model.compile(metrics=[tf.keras.metrics.RootMeanSquaredError()])

On évalue la performance du modèle entrainé sur le jeu de test:

In [ ]:
loss, accuracy = model.evaluate(X_test,y_test)

Batch size (mini-batch gradient descent)¶

Dans la descente de gradient stochastique et ses dérivées, le gradient se calcule de manière privilégiée en utilisant un petit paquet de b données, les batches:

  • entraînement plus rapide car parallélisable
  • permet d'utiliser des learning rate plus important
  • facilite la convergence de la descente de gradient

Il faut trouver un compromis entre des batches de petite taille (rapide à calculer mais mauvaise estimation du gradient) et gros batches (lent à calculer mais bonne estimation du gradient):
la recherche recommande généralement une valeur maximale de 32, en pratique on utilise souvent batch_size=16 ou batch_size=32 ou des tailles plus grandes lorsque l'on a un petit dataset

Nombre d'epochs¶

Il s'agit du nombre d'itérations au cours desquelles le réseau a fait une passe d'optimisation des paramètres avec toutes les données du data set Une epoch est divisée en autant d'itérations de mise à jour des paramètres qu'il y a de batches :

$(\theta_0^0, \theta_1^0, ...,\theta_n^0) \rightarrow (\theta_0^1, \theta_1^1, ..., \theta_n^1)$ sur le batch $b_0=(X_1, X_2, ..., X_{10})$

$\theta_0^1, \theta_1^1, ...,\theta_n^1) \rightarrow (\theta_0^2, \theta_1^2, ..., \theta_n^2)$ sur le batch $b_1=(X_{10}, X_{11}, ..., X_{20})$

...

Il faut trouver un compromis entre laisser le réseau s'entrainer sur peu d'epochs, avec le risque qu'il sous apprenne, et beaucoup d'epoches, avec le risque qu'il sur apprenne

Conseil¶

Dans une première itération, il vaut mieux spécifier un nombre d'epochs important pour vérifier si votre réseau est capable de sur-apprendre, vous pourrez diminuer ensuite ce nombre d'epochs pour atteindre un meilleurs compromis

Prévention du sur-apprentissage (overfitting)¶

Couper son dataset en train/validation/test¶

  • jeu d'apprentissage : sert pour l'entrainement du modèle
  • jeu de validation : sert à valider les performances de votre modèle (pour estimer l'overfitting, comparer des modèles, ...)
  • jeu de test : sert a évaluer la capacité de votre modèle à généraliser en simulant de nouvelles données

Faire une validation croisée de type K-fold sur le jeu d'apprentissage¶

Comme en machine learning classique, c'est une approche plus complète pour segmenter le jeu d'apprentissage, mais elle peut être particulièrement longue à calculer en deep learning !

Entraînement¶

Ressources de calcul¶

Avant de lancer votre entrainement, il est conseillé d'avoir configuré vos ressources de calcul (locales ou cloud) pour utiliser des ressouces permettant de paralléliser l'entraînement, au contraire du CPU faiblement parallélisable. Pour raccourcir le temps de calcul, il est conseillé d'utiliser :

  • les GPU (Graphical Processing Unit) : les processeurs de la carte graphique, faiblement cadencés, mais nombreux et parallélisables
  • les TPU (Tensor Processing Unit): processeurs développés par Google pour faire uniquement du calcul de tenseur, utilisables pour le deep learning

Code dans tensorflow :¶

Après avoir défini l'architecture du réseau, on spécifie ses hyper-paramètres d'apprentissage:

In [ ]:
model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              optimizer = tf.keras.optimizers.adam(learning_rate=base_learning_rate/10),
              metrics=[tf.keras.metrics.RootMeanSquaredError()])

Puis on entraine le réseau avec la méthode .fit , en spécifiant un pourcentage de données pour la validation :

In [ ]:
history = model.fit(X_train, y_train,
          validation_split=0.3,
          batch_size=16,
          epochs=100)

ou explicitement des données de validation (utile par exemple pour faire une cross-validation) :

In [ ]:
history = model.fit(X_train, y_train,
          validation_data=(X_val, y_val), 
          batch_size=16,
          epochs=100)

Réglages des hyper paramètres¶

Définition¶

De même que dans le Machine Learning classique, les hyperparamètres sont des variables qui régissent le processus de formation d'un modèle : ils sont constants tout au long du processus d'apprentissage et ne sont pas appris.

On en distingue deux types :

  • ceux liés au modèles : ils influencent l'architecture du modèle que vous allez sélectionner

par ex: le nombre de couches, le nombre de neurones par couche, ...

  • ceux liés à l'algorithmie : ils influencent la vitesse et la qualité de l'algorithme d'apprentissage

par ex: le taux d'apprentissage de la descente de gradient stochastique, le nombre de batch, ...

Différents variantes d'algorithmes¶

Dans tensorflow vous allez utiliser le module Keras Tuner pour assurer le réglage des hyper paramètres suivant des méthodes différentes :

  • RandomSearch: tire au hasard les paramètres à tester (suivant une loi de probabilité)
  • Hyperband: sélectionne les paramètres en les mettant en compétition à la manière d'un tournoi
  • BayesianOptimization: utilise les statistiques bayesienne pour l'optimisation
  • Sklearn : utilise une recherche exhaustive (GridSearch)

Conseil : Hyperband peut être un bon choix pour réduire le temps de calcul de la recherche

Application dans tensorflow¶

Vous définisez un hypermodèle ainsi qu'un espace de recherche :

  • soit en créant une fonction dédiée
  • soit en créant une sous classe de Keras Tuner

Exemple d'une chaine de traitement avec la méthode hyperband¶

On définit une fonction pour créer notre hypermodèle et son espace de recherche :

In [ ]:
def model_builder(hp):
  model = keras.Sequential()
  model.add(keras.layers.Flatten(input_shape=(28, 28)))

  # Tune the number of units in the first Dense layer
  # Choose an optimal value between 32-512
  hp_units = hp.Int('units', min_value=32, max_value=512, step=32)
  model.add(keras.layers.Dense(units=hp_units, activation='relu'))
  model.add(keras.layers.Dense(10))

  # Tune the learning rate for the optimizer
  # Choose an optimal value from 0.01, 0.001, or 0.0001
  hp_learning_rate = hp.Choice('learning_rate', values=[1e-2, 1e-3, 1e-4])

  return model

Puis on instancie le tuner, en choisissant une stratégie (ici la méthode hyperband):

In [ ]:
tuner = kt.Hyperband(model_builder,
                     objective='val_accuracy',
                     max_epochs=10,
                     factor=3, #paramètre spécifique à la méthode hyperband
                     directory='my_dir',
                     project_name='intro_to_kt')

Enfin on lance le calcul de la recherche des hyperparamètres :

In [ ]:
tuner.search(img_train, label_train, epochs=50, validation_split=0.2, callbacks=[stop_early])

Une fois le calcul terminé, on accède aux hyperparamètres sélectionnés:

In [ ]:
# Get the optimal hyperparameters
best_hps=tuner.get_best_hyperparameters(num_trials=1)[0]

best_hps.get('units') #pour le nombre de neurone
best_hps.get('learning_rate') #pour le learning rate
...

On peut ensuite entrainer le modèle ainsi sélectionné :

In [ ]:
# entrainement du modèle sélectionné avec les meilleurs hp
model = tuner.hypermodel.build(best_hps)
history = model.fit(img_train, label_train, epochs=50, validation_split=0.2)

# résultats des epochs calculées
val_acc_per_epoch = history.history['val_accuracy']
best_epoch = val_acc_per_epoch.index(max(val_acc_per_epoch)) + 1

Pour aller plus loin¶

Pour un tutoriel complet voir le tutoriel de tensorflow et pour plus de details la page de documentation dédiées de keras

En particulier, pour les applications liées à la vision par ordinateur, keras propose des hypermodèles spécialisés, comme HyperResNet ou HyperXception utilisable pour les modèles pré-entrainés correspondant

Apprentissage par transfert et fine-tuning¶

Dans certaines tâches, comme celles de vision par ordinateur, il est courant d'utiliser des réseaux de neurones pré-entrainés, souvent sur de très gros dataset et avec des architectures à l'état de l'art.

On peut alors bénéficier de l'apprentissage de ces réseaux pré-entrainés pour les adapater à notre tâche:

  • sans les ré-entrainer : pour bénéficier de leur capacité d'extraction automatisée de features
  • en ne ré-entraînant que quelques couches spécifiques : on peut ré-entraine certaines couches (souvent les plus externes) sur un dataset spécifique à notre tâche, en conservant l'apprentissage effectué dans les autres couches (les valeurs des paramètres y sont figées)

Implémentation dans tensorflow¶

On peut facilement charger un modèle pré-entrainé depuis tensorflow, par exemple MobileNetV2 pour l'extraction de features:

In [ ]:
from tf.keras.applications import MobileNetV2
base_model = MobileNetV2(include_top=False, # on ne charge pas les couche finales
                         weights='imagenet')

ou pour le fine-tuning :

In [ ]:
# couche  à partir de laquelle on ré-entraine les couches
fine_tune_at = 100

# on gèle les couches avant 
for layer in base_model.layers[:fine_tune_at]:
  layer.trainable = False

Ensuite on spécifie les hyper-paramètres d'apprentissage :

In [ ]:
model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              optimizer = tf.keras.optimizers.adam(),
              metrics=['accuracy'])

Et on ré-entraine une partie des couches du modèle pré-entrainé, à partir de la dernière epoch:

In [ ]:
fine_tune_epochs = 10
total_epochs =  initial_epochs + fine_tune_epochs

history_fine = model.fit(train_dataset,
                         epochs=total_epochs,
                         initial_epoch=history.epoch[-1],
                         validation_data=validation_dataset)

Gestion du compromis biais/variance¶

Détection de l'overfitting: les courbes d'apprentissage¶

On peut définir une fonction pour tracer les courbes d'apprentissage en fonction du nombre d'epochs :

In [ ]:
def plot_loss(history):
  plt.plot(history.history['loss'], label='loss')
  plt.plot(history.history['val_loss'], label='val_loss')
  plt.ylim([0, 10])
  plt.xlabel('Epoch')
  plt.ylabel('Error')
  plt.legend()
  plt.grid(True)

Exemple de courbes d'apprentissage:

No description has been provided for this image

Encore mieux : utiliser Tensorboard pour le monitoring¶

Tensorboard est un tableau de bord interactif qui vous permet de mesurer plusieurs métriques pour le monitoring au travers de vos itérations :

Il se définit comme un callback :

In [ ]:
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir= ...)

et est appelé au moment du fit

In [ ]:
history = model.fit(X_train, y_train,
          validation_split=0.3,
          batch_size=16,
          epochs=100,
          callbaks = [tensorboard_callback])

No description has been provided for this image

Réduction de l'overfitting¶

Early stopping¶

Plutôt que de spécifier un nombre d'epoch fixe, il est possible de fixer un critère automatique d'arrêt qui sera vérifié à la fin de chaque epoch (par un callback)
Suivant ce critère, l'apprentissage sera stoppé a une epoch donnée si elle a empirée par rapport aux k epochs précédentes

In [ ]:
from tensorflow.keras.callbacks import EarlyStopping

es = EarlyStopping()
history = model.fit(X_train, y_train,
          validation_split=0.3,
          batch_size=16,
          epochs=1000, # on peut spécifier un grand nombre d'epoch pour être sur qu'elle ne soient pas une limite
          callbacks = [es])

On peut fixer une patience, spécifiant le nombre d'epoch a attendre si il n'y a pas d'amélioration de l'entraînement :

In [ ]:
es = EarlyStopping(patience=20)

Il est aussi courant de conserver les valeurs des paramètres à partir de l'epoch ayant enregistré les meilleurs valeurs des paramètres (avant le délai de patience)

In [ ]:
es = EarlyStopping(patience=20, restore_best_weights=True)

model.fit(X_train, y_train, 
          batch_size=16, 
          epochs=1000, 
          validation_split=0.3,
          callbacks=[es])

Les couches de régularisation¶

Comme dans le machine learning classique, on peut introduire des procédures de régularisation pour contraindre l'apprentissage des paramètres à trouver des valeurs moins grandes

Les méthodes les plus classiques de régularisation utilisent les normes L1 et L2:

$$ L2~Loss = Loss + \alpha \sum_{i}\theta_i^2$$$$ L1~Loss = Loss + \alpha \sum_{i}|\theta_i|$$

Dans Tensorflow, la régularisation est pensée pour être employée couche par couche, et s'appliquer sur :

  • les poids des neurones : kernel_regularizer
  • les biais des neurones : biais_regularizer
  • la sortie de la fonction d'activation : activity_regularizer

Exemple d'implémentation :¶

In [ ]:
# from tensorflow.keras import regularizers, Sequential, layers

reg_l1 = regularizers.L1(0.03)
reg_l2 = regularizers.L2(0.01)
reg_l1_l2 = regularizers.l1_l2(l1=0.001, l2=0.001)

model = Sequential()

# régularisation sur le poids des neurones
model.add(layers.Dense(100, activation='relu', kernel_regularizer=reg_l1))

# régularisation sur le biais des neurones
model.add(layers.Dense(100, activation='relu', bias_regularizer=reg_l2))

# régularsisation sur la sortie de la fonction d'activation
model.add(layers.Dense(100, activation='relu', activity_regularizer=reg_l1_l2))

Le dropout¶

Il s'agit d'un type de régularisation spécifique au deep learning, dans lequel on vient "éteindre" aléatoirement la sortie de neurones dans le réseau, au moment de l'apprentissage. Pratiquement cela à pour effet de :

  • empêcher les neurones d'adapter leur paramètres en fonction d'observations d'entrée spécifiques
  • forcer le réseau à utiliser moins de paramètres pendant son apprentissage (principe de parcimonie)

Implémentation¶

Ici encore, l'implémentation de tensorflow se fait sous forme de couches virtuelles et on peut appliquer le dropout à n'importe qu'elle couche:

In [ ]:
# dropout avec 20% de neurones éteint dans cette couche
model.add(layers.Dense(100, activation='relu'))
model.add(layers.Dropout(rate=0.2))

La batch normalisation¶

Elle consiste à normaliser la sortie d'une couche, calculée avec les données de chaque batch et joue un rôle similaire à la régularisation

In [ ]:
model.add(BatchNormalization())

Elle joue un rôle similaire à la régularisation

Sauvegarder le modèle¶

Afin de faire facilement plusieurs itérations de votre chaîne de traitement, il est recommandé de sauvegarder, pour chaque itération vos modèles entrainés :

Le plus simple : Via keras.model¶

Pour sauvegrader un modèle entrainé :

model.save(filepath)

Pour le charger : `` tf.keras.models.load_model()


De manière plus complète :¶

Le format SavedModel qui enregistre le modèle de manière indépendante au code source qui la crée (cela peut être utile pour gérer son déploiement)

Récapitulatif d'un réseau basique (pseudo code)¶

Définir le réseau¶

In [ ]:
# transforme le data set X_train, y_train en tenseur
X_train = tf.data.Dataset.from_tensors(X_train)
y_train = tf.data.Dataset.from_tensors(y_train)

# si vous avez des couches de pre-traitement
normalizer = tf.keras.layers.Normalization(axis=-1)
normalizer.adapt(tensor_dataset)
X_train = normalized(X_train)
y_train = normalized(y_train)

# construit le modèle (ici avec des couches denses)
model = Sequential()
model.add(layers.Dense(100, activation=..., kernel_regularizer=...))
model.add(layers.Dense(100, activation=..., bias_regularizer=...))
model.add(layers.Dense(100, activation=..., bias_regularizer=...))
...

# [Optionnel] applique des couches spécifiques (Normalisation, Drop out, Batch Normalisation)
model.add(layers.Dropout(rate=0.2))
model.add(BatchNormalization())
# régularisation sur le poids des neurones
reg_l1 = regularizers.L1(0.03)

model.add(layers.Dense(100, activation='relu', kernel_regularizer=reg_l1))

# régularisation sur le biais des neurones
reg_l2 = regularizers.L2(0.01)
model.add(layers.Dense(100, activation='relu', bias_regularizer=reg_l2))

# régularsisation sur la sortie de la fonction d'activation
reg_l1_l2 = regularizers.l1_l2(l1=0.001, l2=0.001)
model.add(layers.Dense(100, activation='relu', activity_regularizer=reg_l1_l2))

# afficher les paramètres du modèle
model.summary()

# spécifie loss, optimizer et métrique d'évaluation
model.compile(loss=...,
              optimizer= ...,
              metrics=[...])

Entrainer, évaluer et sauvegarder le réseau¶

In [ ]:
# définition des callbacks early stopping & Tensorboard
es = EarlyStopping(min_delta=...,patience=...)
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir= ...)

history = model.fit(X_train,y_train,
          validation_split=...,
          batch_size=16,
          epochs=..., 
          callbacks = [es, tensorboard_callback, ...])

# affiche tensorboard (dans un notebook)
%tensorboard --logdir votre_path/fit


# évaluer les performances du modèle
loss, accuracy = model.evaluate(X_test,y_test)

# sauvegarder le modele
model.save(filepath, ...)

Sources¶

  • La jungle des différents types de réseaux de neurones profonds, par The Asimov Institute
  • Les sections tutorials et guide de tensorflow