2
votes

TensorFlow 2.0: afficher la barre de progression dans une boucle d'entraînement personnalisée

J'entraîne un CNN pour une tâche de classification audio et j'utilise TensorFlow 2.0 RC avec une boucle d'entraînement personnalisée (comme expliqué dans ce guide sur leur site officiel). Je trouverais très pratique d'avoir une belle barre de progression, similaire au model.fit habituel de Keras.

Voici un aperçu de mon code de formation (j'utilise 4 GPU, avec une stratégie de distribution en miroir):

strategy = distribute.MirroredStrategy()

distr_train_dataset = strategy.experimental_distribute_dataset(train_dataset)

if valid_dataset:
    distr_valid_dataset = strategy.experimental_distribute_dataset(valid_dataset)

with strategy.scope():

    model = build_model() # build the model

    optimizer = # define optimizer
    train_loss = # define training loss
    train_metrics_1 = # AUC-ROC
    train_metrics_2 = # AUC-PR
    valid_metrics_1 = # AUC-ROC for validation
    valid_metrics_2 = # AUC-PR for validation

    # rescale loss
    def compute_loss(labels, predictions):
        per_example_loss = train_loss(labels, predictions)
        return per_example_loss/config.batch_size

    def train_step(batch):
        audio_batch, label_batch = batch
        with tf.GradientTape() as tape:
            logits = model(audio_batch)
            loss = compute_loss(label_batch, logits)
        variables = model.trainable_variables
        grads = tape.gradient(loss, variables)
        optimizer.apply_gradients(zip(grads, variables))

        train_metrics_1.update_state(label_batch, logits)
        train_metrics_2.update_state(label_batch, logits)
        train_mean_loss.update_state(loss)
        return loss

    def valid_step(batch):
        audio_batch, label_batch = batch
        logits = model(audio_batch, training=False)
        loss = compute_loss(label_batch, logits)

        val_metrics_1.update_state(label_batch, logits)
        val_metrics_2.update_state(label_batch, logits)
        val_loss.update_state(loss)
        return loss

    @tf.function 
    def distributed_train(batch):
        num_batches = 0
        for batch in distr_train_dataset:
            num_batches += 1
            strategy.experimental_run_v2(train_step, args=(batch, ))
            # print progress here
            tf.print('Step', num_batches, '; Loss', train_mean_loss.result(), '; ROC_AUC', train_metrics_1.result(), '; PR_AUC', train_metrics_2.result())
            gc.collect()

    @tf.function
    def distributed_valid(batch):
        for batch in distr_valid_dataset:
            strategy.experimental_run_v2(valid_step, args=(batch, ))
            gc.collect()

for epoch in range(epochs):
    distributed_train(distr_train_dataset)
    gc.collect()
    train_metrics_1.reset_states()
    train_metrics_2.reset_states()
    train_mean_loss.reset_states()

    if valid_dataset:
        distributed_valid(distr_valid_dataset)
        gc.collect()
        val_metrics_1.reset_states()
        val_metrics_2.reset_states()
        val_loss.reset_states()

Ici, train_dataset et valid_dataset sont deux tf.data.TFRecordDataset générés avec le pipeline d'entrée tf.data habituel.

TensorFlow fournit un très joli tf.keras.utils.Progbar (qui est en effet ce que vous voyez lorsque vous vous entraînez en utilisant model.fit ). J'ai jeté un œil à son code source , et il repose sur numpy, donc je ne peux pas l'utiliser à la place de l' tf.print() (qui est exécutée en mode graphique).

Comment puis-je implémenter une barre de progression similaire dans ma boucle d'entraînement personnalisée (avec ma fonction d'entraînement exécutée en mode graphique)?

Comment model.fit affiche-t-il une barre de progression en premier lieu?


0 commentaires

3 Réponses :


0
votes

Comment puis-je implémenter une barre de progression similaire dans ma boucle d'entraînement personnalisée (avec ma fonction d'entraînement exécutée en mode graphique)?

Pourquoi ne pas changer un peu la structure de votre code, afin d'encapsuler un seul appel strategy.experimental_run_v2 dans les fonctions tf.function -decorated et leur faire renvoyer les métriques que vous souhaitez afficher, puis les exécuter dans une boucle for non décorée et utiliser un tf.keras.utils.Progbar ?

Comment model.fit affiche-t-il une barre de progression en premier lieu?

Dans la version 2, model.fit affiche une barre de progression via l'utilisation d'un objet TrainingContext , qui encapsule une Progbar ainsi que d'autres rappels spécifiés, qui sont dotés de on_epoch_end , on_batch_begin , etc. qui traitent les journaux. Pour être honnête, je ne sais pas trop comment implémenter des mécanismes similaires dans une boucle d'entraînement personnalisée, mais cela pourrait valoir la peine d'enquêter sur celui par défaut, dont la source est ici .


0 commentaires

4
votes

La barre de progression de la boucle d'entraînement personnalisée peut être générée à l'aide du code suivant:

from tensorflow.keras.utils import Progbar
import time 
import numpy as np

metrics_names = ['acc','pr'] 

num_epochs = 5
num_training_samples = 100
batch_size = 10

for i in range(num_epochs):
    print("\nepoch {}/{}".format(i+1,num_epochs))

    pb_i = Progbar(num_training_samples, stateful_metrics=metrics_names)

    for j in range(num_training_samples//batch_size):

        time.sleep(0.3)

        values=[('acc',np.random.random(1)), ('pr',np.random.random(1))]

        pb_i.add(batch_size, values=values)

Production :

époque 1/5

100/100 [===============================] - 3s 30ms / pas - acc: 0,2169 - pr: 0,9011

époque 2/5

100/100 [===============================] - 3s 30ms / pas - acc: 0.7815 - pr: 0.4900

époque 3/5

100/100 [===============================] - 3s 30ms / pas - acc: 0.8003 - pr: 0.9292

époque 4/5

100/100 [================================] - 3s 30ms / pas - acc: 0.8280 - pr: 0.9113

époque 5/5

100/100 [===============================] - 3s 30ms / pas - acc: 0.8497 - pr: 0.1929


1 commentaires

Merci pour cet exemple.



2
votes

La réponse de @Shubham Malaviya est parfaite.

Je veux juste l'étendre davantage lors de l'interaction avec tf.data.Dataset . Ce code est également basé sur cette réponse .

epoch 1/2 60000/60000 [==============================] - 1s 22us/step
- train_loss: 0.7019 - val_loss: 0.0658

epoch 2/2 60000/60000 [==============================] - 1s 21us/step
- train_loss: 0.5561 - val_loss: 0.0324

Production:

import tensorflow as tf
import numpy as np
import time 

# From https://www.tensorflow.org/guide/data#reading_input_data
(images_train, labels_train), (images_test, labels_test) = tf.keras.datasets.fashion_mnist.load_data()

images_train = images_train/255
images_test = images_test/255

dataset_train = tf.data.Dataset.from_tensor_slices((images_train, labels_train))
dataset_test = tf.data.Dataset.from_tensor_slices((images_test, labels_test))

# From @Shubham Malaviya https://stackoverflow.com/a/60094207/8682939
metrics_names = ['train_loss','val_loss'] 
num_epochs = 2
num_training_samples = images_train.shape[0]
batch_size = 10

# Loop on each epoch
for epoch in range(num_epochs):

  print("\nepoch {}/{}".format(epoch+1,num_epochs))

  progBar = tf.keras.utils.Progbar(num_training_samples, stateful_metrics=metrics_names)

  # Loop on each batch of train dataset
  for idX, (batch_x, batch_y) in enumerate(dataset_train.batch(batch_size)): 

    # Train the model
    train_loss = np.random.random(1)

    values=[('train_loss',train_loss)]

    progBar.update(idX*batch_size, values=values) 


  # Loop on each batch of test dataset for validation
  for batch_x, batch_y in dataset_test.batch(batch_size):

    # Foward image through the network
    # -----
    # Calc the loss
    val_loss = np.random.random(1)


  # Update progBar with val_loss
  values=[('train_loss',train_loss),('val_loss',val_loss)]

  progBar.update(num_training_samples, values=values, finalize=True)


0 commentaires