Passer au contenu principal
Nous prenons en charge les images, la vidéo, l’audio et bien plus encore. Journalisez des médias enrichis pour explorer vos résultats et comparer visuellement vos runs, vos modèles et vos jeux de données. Poursuivez votre lecture pour découvrir des exemples et des guides pratiques.
Pour en savoir plus, consultez la référence des types de données.

Prérequis

Pour journaliser des objets multimédias avec le SDK W&B, vous devrez peut-être installer des dépendances supplémentaires. Vous pouvez installer ces dépendances en exécutant la commande suivante :
pip install wandb[media]

Images

Journalisez des images pour suivre les entrées, les sorties, les poids des filtres, les activations, et plus encore.
Entrées et sorties d'autoencodeur
Les images peuvent être journalisées directement à partir de tableaux NumPy, comme images PIL, ou depuis le système de fichiers. Chaque fois que vous journalisez des images à une étape donnée, elles sont disponibles dans l’interface utilisateur. Développez le panneau d’image, puis utilisez le curseur d’étape pour afficher les images de différentes étapes. Cela permet de comparer facilement l’évolution de la sortie d’un modèle pendant l’entraînement. Cliquez sur un panneau multimédia pour afficher une image en mode plein écran ; vous pouvez alors zoomer et vous déplacer dans l’image, y compris à l’aide des raccourcis clavier. Pour comparer des images ou des vidéos de différents runs, étapes ou indices dans une même vue, utilisez Compare mode dans un panneau multimédia.
Nous vous recommandons de journaliser moins de 50 images par étape afin d’éviter que la journalisation ne devienne un goulot d’étranglement pendant l’entraînement et que le chargement des images ne ralentisse la consultation des résultats.
Fournissez directement les tableaux lors de la création manuelle d’images, par exemple avec make_grid de torchvision.Les tableaux sont convertis en PNG à l’aide de Pillow.
import wandb

with wandb.init(project="image-log-example") as run:

    images = wandb.Image(image_array, caption="Top: Output, Bottom: Input")

    run.log({"examples": images})
Nous supposons que l’image est en niveaux de gris si la dernière dimension vaut 1, en RGB si elle vaut 3, et en RGBA si elle vaut 4. Si le tableau contient des nombres à virgule flottante, nous les convertissons en entiers entre 0 et 255. Si vous souhaitez normaliser vos images autrement, vous pouvez spécifier manuellement le mode ou simplement fournir une PIL.Image, comme décrit dans l’onglet « Journaliser des images PIL » de ce panneau.

Superpositions d’images

Consignez des masques de segmentation sémantique et interagissez avec eux (en modifiant l’opacité, en visualisant les changements au fil du temps, etc.) via l’interface W&B.
Visualisation interactive des masques
Pour consigner une superposition, fournissez un dictionnaire avec les clés et valeurs suivantes au paramètre nommé masks de wandb.Image :
  • l’une des deux clés représentant le masque de l’image :
    • "mask_data": un tableau NumPy 2D contenant une étiquette de classe entière pour chaque pixel
    • "path": (string) le chemin vers un fichier de masque d’image enregistré
  • "class_labels": (facultatif) un dictionnaire associant les étiquettes de classe entières du masque de l’image à des noms de classe lisibles
Pour consigner plusieurs masques, consignez un dictionnaire de masques avec plusieurs clés, comme dans l’extrait de code ci-dessous.Voir un exemple interactifExemple de code
mask_data = np.array([[1, 2, 2, ..., 2, 2, 1], ...])

class_labels = {1: "tree", 2: "car", 3: "road"}

mask_img = wandb.Image(
    image,
    masks={
        "predictions": {"mask_data": mask_data, "class_labels": class_labels},
        "ground_truth": {
            # ...
        },
        # ...
    },
)
Les masques de segmentation associés à une clé sont définis à chaque étape (à chaque appel à run.log()).
  • Si différentes étapes fournissent des valeurs différentes pour une même clé de masque, seule la valeur la plus récente de cette clé est appliquée à l’image.
  • Si différentes étapes fournissent des clés de masque différentes, toutes les valeurs de chaque clé sont affichées, mais seules celles définies dans l’étape actuellement affichée sont appliquées à l’image. Activer ou désactiver la visibilité des masques non définis dans cette étape ne modifie pas l’image.

Superpositions d’images dans Tables

Masques de segmentation interactifs dans Tables
Pour journaliser des masques de segmentation dans Tables, vous devez fournir un objet wandb.Image pour chaque ligne du tableau.Un exemple est fourni dans l’extrait de code ci-dessous :
table = wandb.Table(columns=["ID", "Image"])

for id, img, label in zip(ids, images, labels):
    mask_img = wandb.Image(
        img,
        masks={
            "prediction": {"mask_data": label, "class_labels": class_labels}
            # ...
        },
    )

    table.add_data(id, mask_img)

with wandb.init(project="my_project") as run:
    run.log({"Table": table})

Histogrammes

Si une séquence de nombres, comme une liste, un tableau ou un tenseur, est fournie comme premier argument, nous créons automatiquement l’histogramme en appelant np.histogram. Tous les tableaux/tenseurs sont aplatis. Vous pouvez utiliser l’argument mot-clé facultatif num_bins pour remplacer la valeur par défaut de 64 bins. Le nombre maximal de bins pris en charge est de 512.Dans l’interface utilisateur, les histogrammes sont tracés avec l’étape d’entraînement sur l’axe des x, la valeur de la métrique sur l’axe des y, et le nombre représenté par la couleur, afin de faciliter la comparaison des histogrammes enregistrés tout au long de l’entraînement. Voir l’onglet « Histogrammes dans le summary » de ce panneau pour plus de détails sur la journalisation d’histogrammes ponctuels.
run.log({"gradients": wandb.Histogram(grads)})
Gradients du discriminateur GAN
Si des histogrammes figurent dans votre summary, ils apparaîtront dans l’onglet Vue d’ensemble de la page du run. S’ils figurent dans votre historique, nous affichons une carte thermique des bins au fil du temps dans l’onglet Charts.

Visualisations 3D

Journalisez des nuages de points 3D et des scènes LiDAR avec des boîtes englobantes. Passez un tableau NumPy contenant les coordonnées et les couleurs des points pour le rendu.
point_cloud = np.array([[0, 0, 0, COLOR]])

run.log({"point_cloud": wandb.Object3D(point_cloud)})
L’UI de W&B tronque les données au-delà de 300 000 points.

Formats de tableaux NumPy

Trois formats différents de tableaux NumPy sont pris en charge pour permettre des schémas de couleurs flexibles.
  • [[x, y, z], ...] nx3
  • [[x, y, z, c], ...] nx4 | c est une catégorie dans l’intervalle [1, 14] (utile pour la segmentation)
  • [[x, y, z, r, g, b], ...] nx6 | r,g,b sont des valeurs dans l’intervalle [0,255] pour les canaux de couleur rouge, vert et bleu.

Objet Python

Avec ce schéma, vous pouvez définir un objet Python et le transmettre à la méthode from_point_cloud.
  • points est un tableau NumPy contenant les coordonnées et les couleurs des points à afficher, en utilisant les mêmes formats que ceux du rendu simple de nuage de points présenté ci-dessus.
  • boxes est un tableau NumPy de dictionnaires Python avec les attributs suivants :
    • corners- une liste de huit sommets
    • label- une chaîne représentant l’étiquette à afficher sur la boîte (facultatif)
    • color- des valeurs RGB représentant la couleur de la boîte
    • score - une valeur numérique affichée sur la boîte englobante, qui peut être utilisée pour filtrer les boîtes englobantes affichées (par exemple, pour afficher uniquement les boîtes englobantes où score > 0.75). (facultatif)
  • type est une chaîne représentant le type de scène à afficher. Actuellement, la seule valeur prise en charge est lidar/beta
point_list = [
    [
        2566.571924017235, # x
        746.7817289698219, # y
        -15.269245470863748,# z
        76.5, # red
        127.5, # green
        89.46617199365393 # blue
    ],
    [ 2566.592983606823, 746.6791987335685, -15.275803826279521, 76.5, 127.5, 89.45471117247024 ],
    [ 2566.616361739416, 746.4903185513501, -15.28628929674075, 76.5, 127.5, 89.41336375503832 ],
    [ 2561.706014951675, 744.5349468458361, -14.877496818222781, 76.5, 127.5, 82.21868245418283 ],
    [ 2561.5281847916694, 744.2546118233013, -14.867862032341005, 76.5, 127.5, 81.87824684536432 ],
    [ 2561.3693562897465, 744.1804761656741, -14.854129178142523, 76.5, 127.5, 81.64137897587152 ],
    [ 2561.6093071504515, 744.0287526628543, -14.882135189841177, 76.5, 127.5, 81.89871499537098 ],
    # ... et ainsi de suite
]

run.log({"my_first_point_cloud": wandb.Object3D.from_point_cloud(
     points = point_list,
     boxes = [{
         "corners": [
                [ 2601.2765123137915, 767.5669506323393, -17.816764802288663 ],
                [ 2599.7259021588347, 769.0082337923552, -17.816764802288663 ],
                [ 2599.7259021588347, 769.0082337923552, -19.66876480228866 ],
                [ 2601.2765123137915, 767.5669506323393, -19.66876480228866 ],
                [ 2604.8684867834395, 771.4313904894723, -17.816764802288663 ],
                [ 2603.3178766284827, 772.8726736494882, -17.816764802288663 ],
                [ 2603.3178766284827, 772.8726736494882, -19.66876480228866 ],
                [ 2604.8684867834395, 771.4313904894723, -19.66876480228866 ]
        ],
         "color": [0, 0, 255], # couleur RVB de la boîte englobante
         "label": "car", # chaîne affichée sur la boîte englobante
         "score": 0.6 # valeur numérique affichée sur la boîte englobante
     }],
     vectors = [
        {"start": [0, 0, 0], "end": [0.1, 0.2, 0.5], "color": [255, 0, 0]}, # la couleur est facultative
     ],
     point_cloud_type = "lidar/beta",
)})
Lorsque vous visualisez un nuage de points, vous pouvez, tout en maintenant la touche Ctrl enfoncée, utiliser la souris pour vous déplacer dans l’espace.

Fichiers de nuages de points

Vous pouvez utiliser la méthode from_file pour charger un fichier JSON contenant des données de nuages de points.
run.log({"my_cloud_from_file": wandb.Object3D.from_file(
     "./my_point_cloud.pts.json"
)})
Un exemple du format des données de nuage de points est présenté ci-dessous.
{
    "boxes": [
        {
            "color": [
                0,
                255,
                0
            ],
            "score": 0.35,
            "label": "My label",
            "corners": [
                [
                    2589.695869075582,
                    760.7400443552185,
                    -18.044831294622487
                ],
                [
                    2590.719039645323,
                    762.3871153874499,
                    -18.044831294622487
                ],
                [
                    2590.719039645323,
                    762.3871153874499,
                    -19.54083129462249
                ],
                [
                    2589.695869075582,
                    760.7400443552185,
                    -19.54083129462249
                ],
                [
                    2594.9666662674313,
                    757.4657929961453,
                    -18.044831294622487
                ],
                [
                    2595.9898368371723,
                    759.1128640283766,
                    -18.044831294622487
                ],
                [
                    2595.9898368371723,
                    759.1128640283766,
                    -19.54083129462249
                ],
                [
                    2594.9666662674313,
                    757.4657929961453,
                    -19.54083129462249
                ]
            ]
        }
    ],
    "points": [
        [
            2566.571924017235,
            746.7817289698219,
            -15.269245470863748,
            76.5,
            127.5,
            89.46617199365393
        ],
        [
            2566.592983606823,
            746.6791987335685,
            -15.275803826279521,
            76.5,
            127.5,
            89.45471117247024
        ],
        [
            2566.616361739416,
            746.4903185513501,
            -15.28628929674075,
            76.5,
            127.5,
            89.41336375503832
        ]
    ],
    "type": "lidar/beta"
}

Tableaux NumPy

À l’aide des mêmes formats de tableaux définis ci-dessus, vous pouvez utiliser directement des tableaux numpy avec la méthode from_numpy pour définir un nuage de points.
run.log({"my_cloud_from_numpy_xyz": wandb.Object3D.from_numpy(
     np.array(  
        [
            [0.4, 1, 1.3], # x, y, z
            [1, 1, 1], 
            [1.2, 1, 1.2]
        ]
    )
)})
run.log({"my_cloud_from_numpy_cat": wandb.Object3D.from_numpy(
     np.array(  
        [
            [0.4, 1, 1.3, 1], # x, y, z, category 
            [1, 1, 1, 1], 
            [1.2, 1, 1.2, 12], 
            [1.2, 1, 1.3, 12], 
            [1.2, 1, 1.4, 12], 
            [1.2, 1, 1.5, 12], 
            [1.2, 1, 1.6, 11], 
            [1.2, 1, 1.7, 11], 
        ]
    )
)})
run.log({"my_cloud_from_numpy_rgb": wandb.Object3D.from_numpy(
     np.array(  
        [
            [0.4, 1, 1.3, 255, 0, 0], # x, y, z, r, g, b 
            [1, 1, 1, 0, 255, 0], 
            [1.2, 1, 1.3, 0, 255, 255],
            [1.2, 1, 1.4, 0, 255, 255],
            [1.2, 1, 1.5, 0, 0, 255],
            [1.2, 1, 1.1, 0, 0, 255],
            [1.2, 1, 0.9, 0, 0, 255],
        ]
    )
)})
run.log({"protein": wandb.Molecule("6lu7.pdb")})
Journalisez des données moléculaires dans l’un des 10 types de fichiers suivants :pdb, pqr, mmcif, mcif, cif, sdf, sd, gro, mol2 ou mmtf. W&B prend également en charge la journalisation de données moléculaires à partir de chaînes SMILES, de fichiers mol de rdkit et d’objets rdkit.Chem.rdchem.Mol.
resveratrol = rdkit.Chem.MolFromSmiles("Oc1ccc(cc1)C=Cc1cc(O)cc(c1)O")

run.log(
    {
        "resveratrol": wandb.Molecule.from_rdkit(resveratrol),
        "green fluorescent protein": wandb.Molecule.from_rdkit("2b3p.mol"),
        "acetaminophen": wandb.Molecule.from_smiles("CC(=O)Nc1ccc(O)cc1"),
    }
)
Une fois votre run terminé, vous pourrez interagir avec les visualisations 3D de vos molécules dans l’interface. Voir un exemple en direct avec AlphaFold
Structure moléculaire

Image PNG

wandb.Image convertit par défaut les tableaux numpy ou les instances de PILImage en fichiers PNG.
run.log({"example": wandb.Image(...)})
# Ou plusieurs images
run.log({"example": [wandb.Image(...) for img in images]})

Vidéo

Les vidéos sont enregistrées avec le type de données wandb.Video :
run.log({"example": wandb.Video("myvideo.mp4")})
Vous pouvez maintenant visualiser des vidéos dans l’explorateur de médias. Accédez à l’espace de travail de votre projet, à l’espace de travail du run ou à votre rapport, puis cliquez sur Ajouter une visualisation pour ajouter un panneau de médias enrichis.

Vue 2D d’une molécule

Vous pouvez journaliser une vue 2D d’une molécule à l’aide du type de données wandb.Image et de rdkit :
molecule = rdkit.Chem.MolFromSmiles("CC(=O)O")
rdkit.Chem.AllChem.Compute2DCoords(molecule)
rdkit.Chem.AllChem.GenerateDepictionMatching2DStructure(molecule, molecule)
pil_image = rdkit.Chem.Draw.MolToImage(molecule, size=(300, 300))

run.log({"acetic_acid": wandb.Image(pil_image)})

Autres médias

W&B prend également en charge l’enregistrement de divers autres types de médias.

Audio

run.log({"whale songs": wandb.Audio(np_array, caption="OooOoo", sample_rate=32)})
Un maximum de 100 clips audio peuvent être enregistrés par étape. Pour plus d’informations sur l’utilisation, voir audio-file.

Vidéo

run.log({"video": wandb.Video(numpy_array_or_path_to_video, fps=4, format="gif")})
Si un tableau numpy est fourni, nous supposons que les dimensions sont, dans l’ordre : temps, canaux, largeur, hauteur. Par défaut, nous créons une image GIF à 4 fps (ffmpeg et la bibliothèque Python moviepy sont requis lors du passage d’objets numpy). Les formats pris en charge sont "gif", "mp4", "webm" et "ogg". Si vous passez une chaîne à wandb.Video, nous vérifions que le fichier existe et qu’il est dans un format pris en charge avant de le téléverser sur wandb. Le passage d’un objet BytesIO crée un fichier temporaire avec le format spécifié comme extension. Sur les pages W&B Run et projet, vous verrez vos vidéos dans la section Média. Pour plus d’informations sur l’utilisation, voir video-file.

Texte

Utilisez wandb.Table pour journaliser du texte dans des tableaux afin de l’afficher dans l’UI. Par défaut, les en-têtes de colonne sont ["Input", "Output", "Expected"]. Pour des performances optimales de l’UI, le nombre maximal de lignes par défaut est fixé à 10 000. Cependant, vous pouvez explicitement redéfinir ce maximum avec wandb.Table.MAX_ROWS = {DESIRED_MAX}.
with wandb.init(project="my_project") as run:
    columns = ["Text", "Predicted Sentiment", "True Sentiment"]
    # Méthode 1
    data = [["I love my phone", "1", "1"], ["My phone sucks", "0", "-1"]]
    table = wandb.Table(data=data, columns=columns)
    run.log({"examples": table})

    # Méthode 2
    table = wandb.Table(columns=columns)
    table.add_data("I love my phone", "1", "1")
    table.add_data("My phone sucks", "0", "-1")
    run.log({"examples": table})
Vous pouvez également passer un objet DataFrame pandas.
table = wandb.Table(dataframe=my_dataframe)
Pour plus d’informations sur l’utilisation, voir string.

HTML

run.log({"custom_file": wandb.Html(open("some.html"))})
run.log({"custom_string": wandb.Html('<a href="https://mysite">Link</a>')})
Journalisez du HTML personnalisé avec n’importe quelle clé afin d’afficher un panneau HTML sur la page du run. Par défaut, nous injectons les styles par défaut ; vous pouvez désactiver cette injection en passant inject=False.
run.log({"custom_file": wandb.Html(open("some.html"), inject=False)})
Pour en savoir plus sur l’utilisation, voir html-file.