Classification d’iris – #3

Ce tutoriel de classification d’iris, à l’aide de TensorFlow 2.x est le suivant du … #1 et du #2 au cours duquel nous avons étudié la création du dataset et du modèle. Tout ce qui est écrit en #1 et #2 est donc supposé être connu.

On poursuit avec la boucle d’apprentissage.

Le problèmeRéférencesCodeGist

Le problème

Classer des iris, en 3 catégories (Iris setosa, Iris virginica et Iris versicolor), à partir des dimensions (largeur et longueur) des sépales et pétales est un problème classique du Machine Learning. Puisqu’on peut le traiter facilement avec les outils de la statistique, pourquoi ne pas essayer de le faire, de façon plus compliquée avec un réseau de neurones ! Tout cela, bien sûr, dans un but pédagogique.

Références

Code

Le notebook Jupyter, en Python, dans l’environnement GCP est disponible ici.

Gist

Boucle d’apprentissage

Intéressons-nous uniquement à ce qui est fondamental dans la boucle. Le reste ne sert qu’à l’enregistrement et à l’affichage des résultats.

## Note: Rerunning this cell uses the same model variables

# Keep results for plotting
train_loss_results = []
train_accuracy_results = []

num_epochs = 201

for epoch in range(num_epochs):
  epoch_loss_avg = tf.keras.metrics.Mean()
  epoch_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()

  # Training loop - using batches of 32
  for x, y in train_dataset:
    # Optimize the model
    loss_value, grads = grad(model, x, y)
    optimizer.apply_gradients(zip(grads, model.trainable_variables))

    # Track progress
    epoch_loss_avg.update_state(loss_value)  # Add current batch loss
    # Compare predicted label to actual label
    # training=True is needed only if there are layers with different
    # behavior during training versus inference (e.g. Dropout).
    epoch_accuracy.update_state(y, model(x, training=True))

  # End epoch
  train_loss_results.append(epoch_loss_avg.result())
  train_accuracy_results.append(epoch_accuracy.result())

  if epoch % 50 == 0:
    print("Epoch {:03d}: Loss: {:.3f}, Accuracy: {:.3%}".format(epoch,
                                                                epoch_loss_avg.result(),
                                                                epoch_accuracy.result()))

La boucle externe itère sur le nombre d’epochs, c’est le nombre de fois que l’on va parcourir l’ensemble du jeu de données

La boucle interne itère sur le dataset. Pour chaque élément, on calcule la sortie du réseau, la perte (forward du réseau), le gradient et on met à jour les poids.

Si on utilise fit, c’est beaucoup plus simple, tout se fait automatiquement.

Visualisation des résultats

Pour afficher l’évolution de la perte et de l’accuracy dans le temps, selon les epochs :

fig, axes = plt.subplots(2, sharex=True, figsize=(12, 8))
fig.suptitle('Training Metrics')

axes[0].set_ylabel("Loss", fontsize=14)
axes[0].plot(train_loss_results)

axes[1].set_ylabel("Accuracy", fontsize=14)
axes[1].set_xlabel("Epoch", fontsize=14)
axes[1].plot(train_accuracy_results)
plt.show()

Les courbes obtenues sont celles-ci :

On peut aussi choisir d’utiliser l’outil TensorBoard pour mémoriser et afficher les résultats.

Avec TensorBoard

Ce n’est pas dans le code d’origine, il a été ajouté par nous en s’inspirant de Get started with TensorBoard.

# Load the TensorBoard notebook extension
%load_ext tensorboard
# Clear any logs from previous runs
!rm -rf ./logs/ 
import datetime
current_time = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
train_log_dir = 'logs/gradient_tape/' + current_time + '/train'
test_log_dir = 'logs/gradient_tape/' + current_time + '/test'
train_summary_writer = tf.summary.create_file_writer(train_log_dir)
test_summary_writer = tf.summary.create_file_writer(test_log_dir)
# Define our metrics
train_loss = tf.keras.metrics.Mean('train_loss', dtype=tf.float32)
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy('train_accuracy')
test_loss = tf.keras.metrics.Mean('test_loss', dtype=tf.float32)
test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy('test_accuracy')
## Note: Rerunning this cell uses the same model variables

# Keep results for plotting
train_loss_results = []
train_accuracy_results = []

num_epochs = 201

for epoch in range(num_epochs):

  # Training loop - using batches of 32
  for x, y in train_dataset:
    # Optimize the model
    loss_value, grads = grad(model, x, y)
    optimizer.apply_gradients(zip(grads, model.trainable_variables))

    # Track progress
    train_loss.update_state(loss_value)  # Add current batch loss
    # Compare predicted label to actual label
    # training=True is needed only if there are layers with different
    # behavior during training versus inference (e.g. Dropout).
    train_accuracy.update_state(y, model(x, training=True))

  # End epoch
  train_loss_results.append(train_loss.result())
  train_accuracy_results.append(train_accuracy.result())

  with train_summary_writer.as_default():
    tf.summary.scalar('loss', train_loss.result(), step=epoch)
    tf.summary.scalar('accuracy', train_accuracy.result(), step=epoch)

  if epoch % 50 == 0:
    print("Epoch {:03d}: Loss: {:.3f}, Accuracy: {:.3%}".format(epoch,
                                                                train_loss.result(),
                                                                train_accuracy.result()))
%tensorboard --logdir logs/gradient_tape