Ce guide fournit des recommandations pour intégrer W&B à votre script d’entraînement Python ou à votre notebook afin d’optimiser la recherche d’hyperparamètres.
Script d’entraînement original
Supposons que vous disposiez d’un script Python qui entraîne un modèle (voir ci-dessous). Votre objectif est de trouver les hyperparamètres qui maximisent la précision de validation (val_acc).
Dans votre script Python, vous définissez deux fonctions : train_one_epoch et evaluate_one_epoch. La fonction train_one_epoch simule l’entraînement pendant une époque et renvoie la précision et la perte d’entraînement. La fonction evaluate_one_epoch simule l’évaluation du modèle sur le jeu de données de validation et renvoie la précision et la perte de validation.
Vous définissez un dictionnaire de configuration (config) qui contient des valeurs d’hyperparamètres telles que le taux d’apprentissage (lr), la taille du lot (batch_size) et le nombre d’époques (epochs). Les valeurs du dictionnaire de configuration contrôlent le processus d’entraînement.
Ensuite, vous définissez une fonction appelée main qui reproduit une boucle d’entraînement classique. Pour chaque époque, la précision et la perte sont calculées sur les jeux de données d’entraînement et de validation.
Ce code est un script d’entraînement factice. Il n’entraîne pas de modèle, mais simule le processus d’entraînement en générant des valeurs aléatoires de précision et de perte. L’objectif de ce code est de montrer comment intégrer W&B à votre script d’entraînement.
import random
import numpy as np
def train_one_epoch(epoch, lr, batch_size):
acc = 0.25 + ((epoch / 30) + (random.random() / 10))
loss = 0.2 + (1 - ((epoch - 1) / 10 + random.random() / 5))
return acc, loss
def evaluate_one_epoch(epoch):
acc = 0.1 + ((epoch / 20) + (random.random() / 10))
loss = 0.25 + (1 - ((epoch - 1) / 10 + random.random() / 6))
return acc, loss
# variable de configuration avec les valeurs des hyperparamètres
config = {"lr": 0.0001, "batch_size": 16, "epochs": 5}
def main():
lr = config["lr"]
batch_size = config["batch_size"]
epochs = config["epochs"]
for epoch in np.arange(1, epochs):
train_acc, train_loss = train_one_epoch(epoch, lr, batch_size)
val_acc, val_loss = evaluate_one_epoch(epoch)
print("epoch: ", epoch)
print("training accuracy:", train_acc, "training loss:", train_loss)
print("validation accuracy:", val_acc, "validation loss:", val_loss)
if __name__ == "__main__":
main()
Dans la section suivante, vous allez ajouter W&B à votre script Python afin de suivre les hyperparamètres et les métriques pendant l’entraînement. Vous allez utiliser W&B pour trouver les meilleurs hyperparamètres afin de maximiser la précision de validation (val_acc).
Ajoutez W&B à votre script d’entraînement
Mettez à jour votre script d’entraînement pour y intégrer W&B. La manière d’intégrer W&B à votre script Python ou notebook dépend de la façon dont vous gérez les Sweeps.
Pour utiliser le W&B Python SDK afin de démarrer, d’arrêter et de gérer les Sweeps, suivez les instructions de l’onglet Python script or notebook. Pour utiliser le W&B CLI à la place, suivez les instructions de l’onglet CLI.
Créez un fichier de configuration YAML avec la configuration de votre balayage. Le
fichier de configuration contient les hyperparamètres que vous souhaitez que le balayage explore. Dans
l’exemple suivant, les hyperparamètres de taille de lot (batch_size), d’époques (epochs) et de
taux d’apprentissage (lr) varient à chaque balayage.# config.yaml
program: train.py
method: random
name: sweep
metric:
goal: maximize
name: val_acc
parameters:
batch_size:
values: [16, 32, 64]
lr:
min: 0.0001
max: 0.1
epochs:
values: [5, 10, 15]
Pour en savoir plus sur la création d’une configuration de balayage W&B, voir Définir la configuration de balayage.Vous devez fournir le nom de votre script Python pour la clé program
dans votre fichier YAML.Ensuite, ajoutez les éléments suivants à l’exemple de code :
- Importez le SDK Python de W&B (
wandb) et PyYAML (yaml). PyYAML sert à lire notre fichier de configuration YAML.
- Lisez le fichier de configuration.
- Utilisez
wandb.init() pour démarrer un processus en arrière-plan afin de synchroniser et journaliser les données en tant que W&B Run. Transmettez l’objet de configuration au paramètre config.
- Définissez les valeurs des hyperparamètres à partir de
wandb.Run.config au lieu d’utiliser des valeurs codées en dur.
- Journalisez la métrique que vous souhaitez optimiser avec
wandb.Run.log(). Vous devez journaliser la métrique définie dans votre configuration. Dans le dictionnaire de configuration (sweep_configuration dans cet exemple), vous définissez le balayage pour maximiser la valeur val_acc.
import wandb
import yaml
import random
import numpy as np
def train_one_epoch(epoch, lr, batch_size):
acc = 0.25 + ((epoch / 30) + (random.random() / 10))
loss = 0.2 + (1 - ((epoch - 1) / 10 + random.random() / 5))
return acc, loss
def evaluate_one_epoch(epoch):
acc = 0.1 + ((epoch / 20) + (random.random() / 10))
loss = 0.25 + (1 - ((epoch - 1) / 10 + random.random() / 6))
return acc, loss
def main():
# Configurez vos hyperparamètres par défaut
with open("./config.yaml") as file:
config = yaml.load(file, Loader=yaml.FullLoader)
with wandb.init(config=config) as run:
for epoch in np.arange(1, run.config['epochs']):
train_acc, train_loss = train_one_epoch(epoch, run.config['lr'], run.config['batch_size'])
val_acc, val_loss = evaluate_one_epoch(epoch)
run.log(
{
"epoch": epoch,
"train_acc": train_acc,
"train_loss": train_loss,
"val_acc": val_acc,
"val_loss": val_loss,
}
)
# Appeler la fonction principale.
main()
Dans votre CLI, définissez le nombre maximal de runs que l’agent de
balayage doit essayer. C’est facultatif. Dans cet exemple, nous fixons ce
nombre maximal à 5.Ensuite, initialisez le balayage avec la commande wandb sweep. Indiquez le nom du fichier YAML. Vous pouvez aussi indiquer le nom du projet avec l’option de projet (--project) :wandb sweep --project sweep-demo-cli config.yaml
Cela renvoie un ID de balayage. Pour en savoir plus sur l’initialisation des balayages, voir
Initialiser les balayages.Copiez l’ID de balayage et remplacez sweepID dans l’extrait de code suivant pour démarrer
le job de balayage avec la commande wandb agent :wandb agent --count $NUM your-entity/sweep-demo-cli/sweepID
Pour plus d’informations, voir Lancer des jobs de balayage. Suivez ces étapes pour ajouter W&B à votre script Python :
- Créez un objet de type dictionnaire dans lequel les paires clé-valeur définissent une configuration de balayage. La configuration de balayage définit les hyperparamètres que vous souhaitez voir W&B explorer pour vous, ainsi que la métrique à optimiser. En reprenant l’exemple précédent, la taille de lot (
batch_size), les époques (epochs) et le taux d’apprentissage (lr) sont les hyperparamètres à faire varier à chaque balayage. Vous voulez maximiser l’accuracy du score de validation ; vous définissez donc "goal": "maximize" ainsi que le nom de la variable à optimiser, dans ce cas val_acc ("name": "val_acc").
- Passez le dictionnaire de configuration du balayage à
wandb.sweep(). Cela initialise le balayage et renvoie l’ID du balayage (sweep_id). Pour plus d’informations, voir Initialiser les balayages.
- Au début de votre script, importez le SDK Python W&B (
wandb).
- Dans votre fonction
main, utilisez wandb.init() pour démarrer un processus en arrière-plan qui synchronise et journalise les données en tant que W&B Run. Passez le nom du projet en paramètre de la méthode wandb.init(). Si vous ne passez pas de nom de projet, W&B utilise le nom de projet par défaut.
- Récupérez les valeurs des hyperparamètres dans l’objet
wandb.Run.config. Cela vous permet d’utiliser les valeurs des hyperparamètres définies dans le dictionnaire de configuration du balayage, au lieu de valeurs codées en dur.
- Journalisez dans W&B la métrique que vous optimisez à l’aide de
wandb.Run.log(). Vous devez journaliser la métrique définie dans votre configuration. Par exemple, si vous définissez val_acc comme métrique à optimiser, vous devez journaliser val_acc. Si vous ne journalisez pas la métrique, W&B ne sait pas quoi optimiser. Dans le dictionnaire de configuration (sweep_configuration dans cet exemple), vous définissez le balayage pour maximiser la valeur val_acc.
- Lancez le balayage avec
wandb.agent(). Fournissez l’ID du balayage et le nom de la fonction à exécuter (function=main), puis fixez à quatre le nombre maximal de runs à essayer (count=4).
En combinant tout cela, votre script devrait ressembler à ce qui suit :import wandb # Importer le W&B Python SDK
import numpy as np
import random
import argparse
def train_one_epoch(epoch, lr, batch_size):
acc = 0.25 + ((epoch / 30) + (random.random() / 10))
loss = 0.2 + (1 - ((epoch - 1) / 10 + random.random() / 5))
return acc, loss
def evaluate_one_epoch(epoch):
acc = 0.1 + ((epoch / 20) + (random.random() / 10))
loss = 0.25 + (1 - ((epoch - 1) / 10 + random.random() / 6))
return acc, loss
def main(args=None):
# Lorsqu'il est appelé par l'agent de balayage, args vaut None,
# on utilise donc le projet issu de la configuration du balayage
project = args.project if args else None
with wandb.init(project=project) as run:
# Récupère les valeurs des hyperparamètres depuis l'objet `wandb.Run.config`
lr = run.config["lr"]
batch_size = run.config["batch_size"]
epochs = run.config["epochs"]
# Exécute la boucle d'entraînement et enregistre les valeurs de performances dans W&B
for epoch in np.arange(1, epochs):
train_acc, train_loss = train_one_epoch(epoch, lr, batch_size)
val_acc, val_loss = evaluate_one_epoch(epoch)
run.log(
{
"epoch": epoch,
"train_acc": train_acc,
"train_loss": train_loss,
"val_acc": val_acc, # Métrique optimisée
"val_loss": val_loss,
}
)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--project", type=str, default="sweep-example", help="nom du projet W&B")
args = parser.parse_args()
# Définir un dictionnaire de configuration de balayage
sweep_configuration = {
"method": "random",
"name": "sweep",
# Métrique à optimiser
# Par exemple, pour maximiser la précision de validation,
# définissez "goal": "maximize" et le nom de la variable
# à optimiser, dans ce cas "val_acc"
"metric": {
"goal": "maximize",
"name": "val_acc"
},
"parameters": {
"batch_size": {"values": [16, 32, 64]},
"epochs": {"values": [5, 10, 15]},
"lr": {"max": 0.1, "min": 0.0001},
},
}
# Initialiser le balayage en passant le dictionnaire de configuration
sweep_id = wandb.sweep(sweep=sweep_configuration, project=args.project)
# Démarrer le job de balayage
wandb.agent(sweep_id, function=main, count=4)
Journalisation des métriques dans W&B lors d’un balayageVous devez journaliser la métrique que vous définissez et que vous optimisez, à la fois dans votre configuration de balayage et avec wandb.Run.log(). Par exemple, si vous définissez val_acc comme métrique à optimiser dans votre configuration de balayage, vous devez également journaliser val_acc dans W&B. Si vous ne journalisez pas cette métrique, W&B ne saura pas quoi optimiser.with wandb.init() as run:
val_loss, val_acc = train()
run.log(
{
"val_loss": val_loss,
"val_acc": val_acc
}
)
L’exemple suivant montre une journalisation incorrecte de la métrique dans W&B. La métrique optimisée dans la configuration de balayage est val_acc, mais le code journalise val_acc dans un dictionnaire imbriqué sous la clé validation. Vous devez journaliser la métrique directement, et non dans un dictionnaire imbriqué.with wandb.init() as run:
val_loss, val_acc = train()
run.log(
{
"validation": {
"val_loss": val_loss,
"val_acc": val_acc
}
}
)