Log a dictionary of metrics, media, or custom objects to a step with the W&B Python SDK. W&B collects the key-value pairs during each step and stores them in one unified dictionary each time you log data with wandb.log(). Data logged from your script is saved locally to your machine in a directory called wandb, then synced to the W&B cloud or your private server.
Key-value pairs are stored in one unified dictionary only if you pass the same value for each step. W&B writes all of the collected keys and values to memory if you log a different value for step.
Each call to wandb.log is a new step by default. W&B uses steps as the default x-axis when it creates charts and panels. You can optionally create and use a custom x-axis or capture a custom summary metric. For more information, see Customize log axes.
Use wandb.log() to log consecutive values for each step: 0, 1, 2, and so on. It is not possible to write to a specific history step. W&B only writes to the “current” and “next” step.
Automatically logged data
W&B automatically logs the following information during a W&B Experiment:
System metrics: CPU and GPU utilization, network, etc. These are shown in the System tab on the run page. For the GPU, these are fetched with nvidia-smi.
Command line: The stdout and stderr are picked up and show in the logs tab on the run page.
Git commit: Pick up the latest git commit and see it on the overview tab of the run page, as well as a diff.patch file if there are any uncommitted changes.
Dependencies: The requirements.txt file will be uploaded and shown on the files tab of the run page, along with any files you save to the wandb directory for the run.
What data is logged with specific W&B API calls?
With W&B, you can decide exactly what you want to log. The following lists some commonly logged objects:
Datasets: You have to specifically log images or other dataset samples for them to stream to W&B.
Plots: Use wandb.plot with wandb.log to track charts. See Log Plots for more information.
Tables: Use wandb.Table to log data to visualize and query with W&B. See Log Tables for more information.
PyTorch gradients: Add wandb.watch(model) to see gradients of the weights as histograms in the UI.
Configuration information: Log hyperparameters, a link to your dataset, or the name of the architecture you’re using as config parameters, passed in like this: wandb.init(config=your_config_dictionary). See the PyTorch Integrations page for more information.
Metrics: Use wandb.log to see metrics from your model. If you log metrics like accuracy and loss from inside your training loop, you’ll get live updating graphs in the UI.
Common workflows
Compare the best accuracy: To compare the best value of a metric across runs, set the summary value for that metric. By default, summary is set to the last value you logged for each key. This is useful in the table in the UI, where you can sort and filter runs based on their summary metrics, to help compare runs in a table or bar chart based on their best accuracy, instead of final accuracy. For example: wandb.run.summary["best_accuracy"] = best_accuracy
Multiple metrics on one chart: Log multiple metrics in the same call to wandb.log, like this: wandb.log({"acc'": 0.9, "loss": 0.1}) and they will both be available to plot against in the UI
Custom x-axis: Add a custom x-axis to the same log call to visualize your metrics against a different axis in the W&B dashboard. For example: wandb.log({'acc': 0.9, 'epoch': 3, 'batch': 117}). To set the default x-axis for a given metric use Run.define_metric()
Create and track plots from machine learning experiments.
Using the methods in wandb.plot, you can track charts with wandb.log, including charts that change over time during training. To learn more about our custom charting framework, check out this guide.
Basic charts
These simple charts make it easy to construct basic visualizations of metrics and results.
wandb.plot.line()
Log a custom line plot—a list of connected and ordered points on arbitrary axes.
data = [[x, y] for (x, y) in zip(x_values, y_values)]
table = wandb.Table(data=data, columns=["x", "y"])
wandb.log(
{
"my_custom_plot_id": wandb.plot.line(
table, "x", "y", title="Custom Y vs X Line Plot" )
}
)
You can use this to log curves on any two dimensions. If you’re plotting two lists of values against each other, the number of values in the lists must match exactly. For example, each point must have an x and a y.
Log a custom scatter plot—a list of points (x, y) on a pair of arbitrary axes x and y.
data = [[x, y] for (x, y) in zip(class_x_scores, class_y_scores)]
table = wandb.Table(data=data, columns=["class_x", "class_y"])
wandb.log({"my_custom_id": wandb.plot.scatter(table, "class_x", "class_y")})
You can use this to log scatter points on any two dimensions. If you’re plotting two lists of values against each other, the number of values in the lists must match exactly. For example, each point must have an x and a y.
Log a custom histogram—sort a list of values into bins by count/frequency of occurrence—natively in a few lines. Let’s say I have a list of prediction confidence scores (scores) and want to visualize their distribution:
data = [[s] for s in scores]
table = wandb.Table(data=data, columns=["scores"])
wandb.log({"my_histogram": wandb.plot.histogram(table, "scores", title="Histogram")})
You can use this to log arbitrary histograms. Note that data is a list of lists, intended to support a 2D array of rows and columns.
Note that the number of x and y points must match exactly. You can supply one list of x values to match multiple lists of y values, or a separate list of x values for each list of y values.
These preset charts have built-in wandb.plot methods that make it quick and easy to log charts directly from your script and see the exact information you’re looking for in the UI.
cm = wandb.plot.confusion_matrix(
y_true=ground_truth, preds=predictions, class_names=class_names
)
wandb.log({"conf_mat": cm})
You can log this wherever your code has access to:
a model’s predicted labels on a set of examples (preds) or the normalized probability scores (probs). The probabilities must have the shape (number of examples, number of classes). You can supply either probabilities or predictions but not both.
the corresponding ground truth labels for those examples (y_true)
a full list of the labels/class names as strings of class_names. Examples: class_names=["cat", "dog", "bird"] if index 0 is cat, 1 is dog, 2 is bird.
For full customization, tweak a built-in Custom Chart preset or create a new preset, then save the chart. Use the chart ID to log data to that custom preset directly from your script.
# Create a table with the columns to plottable = wandb.Table(data=data, columns=["step", "height"])
# Map from the table's columns to the chart's fieldsfields = {"x": "step", "value": "height"}
# Use the table to populate the new custom chart preset# To use your own saved chart preset, change the vega_spec_name# To edit the title, change the string_fieldsmy_custom_chart = wandb.plot_table(
vega_spec_name="carey/new_chart",
data_table=table,
fields=fields,
string_fields={"title": "Height Histogram"},
)
Just pass a matplotlib plot or figure object to wandb.log(). By default we’ll convert the plot into a Plotly plot. If you’d rather log the plot as an image, you can pass the plot into wandb.Image. We also accept Plotly charts directly.
If you’re getting an error “You attempted to log an empty plot” then you can store the figure separately from the plot with fig = plt.figure() and then log fig in your call to wandb.log.
Log custom HTML to W&B Tables
W&B supports logging interactive charts from Plotly and Bokeh as HTML and adding them to Tables.
Log Plotly figures to Tables as HTML
You can log interactive Plotly charts to wandb Tables by converting them to HTML.
import wandb
import plotly.express as px
# Initialize a new runrun = wandb.init(project="log-plotly-fig-tables", name="plotly_html")
# Create a tabletable = wandb.Table(columns=["plotly_figure"])
# Create path for Plotly figurepath_to_plotly_html ="./plotly_figure.html"# Example Plotly figurefig = px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16])
# Write Plotly figure to HTML# Set auto_play to False prevents animated Plotly charts# from playing in the table automaticallyfig.write_html(path_to_plotly_html, auto_play=False)
# Add Plotly figure as HTML file into Tabletable.add_data(wandb.Html(path_to_plotly_html))
# Log Tablerun.log({"test_table": table})
wandb.finish()
Log Bokeh figures to Tables as HTML
You can log interactive Bokeh charts to wandb Tables by converting them to HTML.
Use define_metric to set a custom x axis.Custom x-axes are useful in contexts where you need to log to different time steps in the past during training, asynchronously. For example, this can be useful in RL where you may track the per-episode reward and a per-step reward.
By default, all metrics are logged against the same x-axis, which is the W&B internal step. Sometimes, you might want to log to a previous step, or use a different x-axis.
Here’s an example of setting a custom x-axis metric, instead of the default step.
import wandb
wandb.init()
# define our custom x axis metricwandb.define_metric("custom_step")
# define which metrics will be plotted against itwandb.define_metric("validation_loss", step_metric="custom_step")
for i in range(10):
log_dict = {
"train_loss": 1/ (i +1),
"custom_step": i**2,
"validation_loss": 1/ (i +1),
}
wandb.log(log_dict)
The x-axis can be set using globs as well. Currently, only globs that have string prefixes are available. The following example will plot all logged metrics with the prefix "train/" to the x-axis "train/step":
import wandb
wandb.init()
# define our custom x axis metricwandb.define_metric("train/step")
# set all other train/ metrics to use this stepwandb.define_metric("train/*", step_metric="train/step")
for i in range(10):
log_dict = {
"train/step": 2**i, # exponential growth w/ internal W&B step"train/loss": 1/ (i +1), # x-axis is train/step"train/accuracy": 1- (1/ (1+ i)), # x-axis is train/step"val/loss": 1/ (1+ i), # x-axis is internal wandb step }
wandb.log(log_dict)
3 - Log distributed training experiments
Use W&B to log distributed training experiments with multiple GPUs.
In distributed training, models are trained using multiple GPUs in parallel. W&B supports two patterns to track distributed training experiments:
One process: Initialize W&B (wandb.init) and log experiments (wandb.log) from a single process. This is a common solution for logging distributed training experiments with the PyTorch Distributed Data Parallel (DDP) Class. In some cases, users funnel data over from other processes using a multiprocessing queue (or another communication primitive) to the main logging process.
Many processes: Initialize W&B (wandb.init) and log experiments (wandb.log) in every process. Each process is effectively a separate experiment. Use the group parameter when you initialize W&B (wandb.init(group='group-name')) to define a shared experiment and group the logged values together in the W&B App UI.
The proceeding examples demonstrate how to track metrics with W&B using PyTorch DDP on two GPUs on a single machine. PyTorch DDP (DistributedDataParallel intorch.nn) is a popular library for distributed training. The basic principles apply to any distributed training setup, but the details of implementation may differ.
Explore the code behind these examples in the W&B GitHub examples repository here. Specifically, see the log-dpp.py Python script for information on how to implement one process and many process methods.
Method 1: One process
In this method we track only a rank 0 process. To implement this method, initialize W&B (wandb.init), commence a W&B Run, and log metrics (wandb.log) within the rank 0 process. This method is simple and robust, however, this method does not log model metrics from other processes (for example, loss values or inputs from their batches). System metrics, such as usage and memory, are still logged for all GPUs since that information is available to all processes.
Use this method to only track metrics available from a single process. Typical examples include GPU/CPU utilization, behavior on a shared validation set, gradients and parameters, and loss values on representative data examples.
Within our sample Python script (log-ddp.py), we check to see if the rank is 0. To do so, we first launch multiple processes with torch.distributed.launch. Next, we check the rank with the --local_rank command line argument. If the rank is set to 0, we set up wandb logging conditionally in the train() function. Within our Python script, we use the following check:
if __name__ =="__main__":
# Get args args = parse_args()
if args.local_rank ==0: # only on main process# Initialize wandb run run = wandb.init(
entity=args.entity,
project=args.project,
)
# Train model with DDP train(args, run)
else:
train(args)
Explore the W&B App UI to view an example dashboard of metrics tracked from a single process. The dashboard displays system metrics such as temperature and utilization, that were tracked for both GPUs.
However, the loss values as a function epoch and batch size were only logged from a single GPU.
Method 2: Many processes
In this method, we track each process in the job, calling wandb.init() and wandb.log() from each process separately. We suggest you call wandb.finish() at the end of training, to mark that the run has completed so that all processes exit properly.
This method makes more information accessible for logging. However, note that multiple W&B Runs are reported in the W&B App UI. It might be difficult to keep track of W&B Runs across multiple experiments. To mitigate this, provide a value to the group parameter when you initialize W&B to keep track of which W&B Run belongs to a given experiment. For more information about how to keep track of training and evaluation W&B Runs in experiments, see Group Runs.
Use this method if you want to track metrics from individual processes. Typical examples include the data and predictions on each node (for debugging data distribution) and metrics on individual batches outside of the main node. This method is not necessary to get system metrics from all nodes nor to get summary statistics available on the main node.
The following Python code snippet demonstrates how to set the group parameter when you initialize W&B:
if __name__ =="__main__":
# Get args args = parse_args()
# Initialize run run = wandb.init(
entity=args.entity,
project=args.project,
group="DDP", # all runs for the experiment in one group )
# Train model with DDP train(args, run)
Explore the W&B App UI to view an example dashboard of metrics tracked from multiple processes. Note that there are two W&B Runs grouped together in the left sidebar. Click on a group to view the dedicated group page for the experiment. The dedicated group page displays metrics from each process separately.
The preceding image demonstrates the W&B App UI dashboard. On the sidebar we see two experiments. One labeled ’null’ and a second (bound by a yellow box) called ‘DPP’. If you expand the group (select the Group dropdown) you will see the W&B Runs that are associated to that experiment.
Use W&B Service to avoid common distributed training issues
There are two common issues you might encounter when using W&B and distributed training:
Hanging at the beginning of training - A wandb process can hang if the wandb multiprocessing interferes with the multiprocessing from distributed training.
Hanging at the end of training - A training job might hang if the wandb process does not know when it needs to exit. Call the wandb.finish() API at the end of your Python script to tell W&B that the Run finished. The wandb.finish() API will finish uploading data and will cause W&B to exit.
We recommend using the wandb service to improve the reliability of your distributed jobs. Both of the preceding training issues are commonly found in versions of the W&B SDK where wandb service is unavailable.
Enable W&B Service
Depending on your version of the W&B SDK, you might already have W&B Service enabled by default.
W&B SDK 0.13.0 and above
W&B Service is enabled by default for versions of the W&B SDK 0.13.0 and above.
W&B SDK 0.12.5 and above
Modify your Python script to enable W&B Service for W&B SDK version 0.12.5 and above. Use the wandb.require method and pass the string "service" within your main function:
if __name__ =="__main__":
main()
defmain():
wandb.require("service")
# rest-of-your-script-goes-here
For optimal experience we do recommend you upgrade to the latest version.
W&B SDK 0.12.4 and below
Set the WANDB_START_METHOD environment variable to "thread" to use multithreading instead if you use a W&B SDK version 0.12.4 and below.
Example use cases for multiprocessing
The following code snippets demonstrate common methods for advanced distributed use cases.
Spawn process
Use the wandb.setup()[line 8]method in your main function if you initiate a W&B Run in a spawned process:
import multiprocessing as mp
defdo_work(n):
run = wandb.init(config=dict(n=n))
run.log(dict(this=n * n))
defmain():
wandb.setup()
pool = mp.Pool(processes=4)
pool.map(do_work, range(4))
if __name__ =="__main__":
main()
Share a W&B Run
Pass a W&B Run object as an argument to share W&B Runs between processes:
defdo_work(run):
run.log(dict(this=1))
defmain():
run = wandb.init()
p = mp.Process(target=do_work, kwargs=dict(run=run))
p.start()
p.join()
if __name__ =="__main__":
main()
Note that we can not guarantee the logging order. Synchronization should be done by the author of the script.
4 - Log media and objects
Log rich media, from 3D point clouds and molecules to HTML and histograms
We support images, video, audio, and more. Log rich media to explore your results and visually compare your runs, models, and datasets. Read on for examples and how-to guides.
Looking for reference docs for our media types? You want this page.
In order to log media objects with the W&B SDK, you may need to install additional dependencies.
You can install these dependencies by running the following command:
pip install wandb[media]
Images
Log images to track inputs, outputs, filter weights, activations, and more.
Images can be logged directly from NumPy arrays, as PIL images, or from the filesystem.
Each time you log images from a step, we save them to show in the UI. Expand the image panel, and use the step slider to look at images from different steps. This makes it easy to compare how a model’s output changes during training.
It’s recommended to log fewer than 50 images per step to prevent logging from becoming a bottleneck during training and image loading from becoming a bottleneck when viewing results.
We assume the image is gray scale if the last dimension is 1, RGB if it’s 3, and RGBA if it’s 4. If the array contains floats, we convert them to integers between 0 and 255. If you want to normalize your images differently, you can specify the mode manually or just supply a PIL.Image, as described in the “Logging PIL Images” tab of this panel.
For full control over the conversion of arrays to images, construct the PIL.Image yourself and provide it directly.
images = [PIL.Image.fromarray(image) for image in image_array]
wandb.log({"examples": [wandb.Image(image) for image in images]})
For even more control, create images however you like, save them to disk, and provide a filepath.
im = PIL.fromarray(...)
rgb_im = im.convert("RGB")
rgb_im.save("myimage.jpg")
wandb.log({"example": wandb.Image("myimage.jpg")})
Image overlays
Log semantic segmentation masks and interact with them (altering opacity, viewing changes over time, and more) via the W&B UI.
To log an overlay, you’ll need to provide a dictionary with the following keys and values to the masks keyword argument of wandb.Image:
one of two keys representing the image mask:
"mask_data": a 2D NumPy array containing an integer class label for each pixel
"path": (string) a path to a saved image mask file
"class_labels": (optional) a dictionary mapping the integer class labels in the image mask to their readable class names
To log multiple masks, log a mask dictionary with multiple keys, as in the code snippet below.
To log a bounding box, you’ll need to provide a dictionary with the following keys and values to the boxes keyword argument of wandb.Image:
box_data: a list of dictionaries, one for each box. The box dictionary format is described below.
position: a dictionary representing the position and size of the box in one of two formats, as described below. Boxes need not all use the same format.
Option 1:{"minX", "maxX", "minY", "maxY"}. Provide a set of coordinates defining the upper and lower bounds of each box dimension.
Option 2:{"middle", "width", "height"}. Provide a set of coordinates specifying the middle coordinates as [x,y], and width and height as scalars.
class_id: an integer representing the class identity of the box. See class_labels key below.
scores: a dictionary of string labels and numeric values for scores. Can be used for filtering boxes in the UI.
domain: specify the units/format of the box coordinates. Set this to “pixel” if the box coordinates are expressed in pixel space, such as integers within the bounds of the image dimensions. By default, the domain is assumed to be a fraction/percentage of the image, expressed as a floating point number between 0 and 1.
box_caption: (optional) a string to be displayed as the label text on this box
class_labels: (optional) A dictionary mapping class_ids to strings. By default we will generate class labels class_0, class_1, etc.
Check out this example:
class_id_to_label = {
1: "car",
2: "road",
3: "building",
# ...}
img = wandb.Image(
image,
boxes={
"predictions": {
"box_data": [
{
# one box expressed in the default relative/fractional domain"position": {"minX": 0.1, "maxX": 0.2, "minY": 0.3, "maxY": 0.4},
"class_id": 2,
"box_caption": class_id_to_label[2],
"scores": {"acc": 0.1, "loss": 1.2},
# another box expressed in the pixel domain# (for illustration purposes only, all boxes are likely# to be in the same domain/format)"position": {"middle": [150, 20], "width": 68, "height": 112},
"domain": "pixel",
"class_id": 3,
"box_caption": "a building",
"scores": {"acc": 0.5, "loss": 0.7},
# ...# Log as many boxes an as needed }
],
"class_labels": class_id_to_label,
},
# Log each meaningful group of boxes with a unique key name"ground_truth": {
# ... },
},
)
wandb.log({"driving_scene": img})
Image overlays in Tables
To log Segmentation Masks in tables, you will need to provide a wandb.Image object for each row in the table.
If a sequence of numbers, such as a list, array, or tensor, is provided as the first argument, we will construct the histogram automatically by calling np.histogram. All arrays/tensors are flattened. You can use the optional num_bins keyword argument to override the default of 64 bins. The maximum number of bins supported is 512.
In the UI, histograms are plotted with the training step on the x-axis, the metric value on the y-axis, and the count represented by color, to ease comparison of histograms logged throughout training. See the “Histograms in Summary” tab of this panel for details on logging one-off histograms.
wandb.log({"gradients": wandb.Histogram(grads)})
If you want more control, call np.histogram and pass the returned tuple to the np_histogram keyword argument.
If histograms are in your summary they will appear on the Overview tab of the Run Page. If they are in your history, we plot a heatmap of bins over time on the Charts tab.
3D visualizations
Log 3D point clouds and Lidar scenes with bounding boxes. Pass in a NumPy array containing coordinates and colors for the points to render.
boxes is a NumPy array of python dictionaries with three attributes:
corners- a list of eight corners
label- a string representing the label to be rendered on the box (Optional)
color- rgb values representing the color of the box
score - a numeric value that will be displayed on the bounding box that can be used to filter the bounding boxes shown (for example, to only show bounding boxes where score > 0.75). (Optional)
type is a string representing the scene type to render. Currently the only supported value is lidar/beta
Now you can view videos in the media browser. Go to your project workspace, run workspace, or report and click Add visualization to add a rich media panel.
2D view of a molecule
You can log a 2D view of a molecule using the wandb.Image data type and rdkit:
If a numpy array is supplied we assume the dimensions are, in order: time, channels, width, height. By default we create a 4 fps gif image (ffmpeg and the moviepy python library are required when passing numpy objects). Supported formats are "gif", "mp4", "webm", and "ogg". If you pass a string to wandb.Video we assert the file exists and is a supported format before uploading to wandb. Passing a BytesIO object will create a temporary file with the specified format as the extension.
On the W&B Run and Project Pages, you will see your videos in the Media section.
Use wandb.Table to log text in tables to show up in the UI. By default, the column headers are ["Input", "Output", "Expected"]. To ensure optimal UI performance, the default maximum number of rows is set to 10,000. However, users can explicitly override the maximum with wandb.Table.MAX_ROWS = {DESIRED_MAX}.
Custom html can be logged at any key, and this exposes an HTML panel on the run page. By default we inject default styles, you can turn off default styles by passing inject=False.
The following guide describes how to log models to a W&B run and interact with them.
The following APIs are useful for tracking models as a part of your experiment tracking workflow. Use the APIs listed on this page to log models to a run, and to access metrics, tables, media, and other objects.
W&B suggests that you use W&B Artifacts if you want to:
Create and keep track of different versions of serialized data besides models, such as datasets, prompts, and more.
Explore lineage graphs of a model or any other objects tracked in W&B.
Interact with the model artifacts these methods created, such as updating properties (metadata, aliases, and descriptions)
For more information on W&B Artifacts and advanced versioning use cases, see the Artifacts documentation.
Log a model to a run
Use the log_model to log a model artifact that contains content within a directory you specify. The log_model method also marks the resulting model artifact as an output of the W&B run.
You can track a model’s dependencies and the model’s associations if you mark the model as the input or output of a W&B run. View the lineage of the model within the W&B App UI. See the Explore and traverse artifact graphs page within the Artifacts chapter for more information.
Provide the path where your model files are saved to the path parameter. The path can be a local file, directory, or reference URI to an external bucket such as s3://bucket/path.
Ensure to replace values enclosed in <> with your own.
import wandb
# Initialize a W&B runrun = wandb.init(project="<your-project>", entity="<your-entity>")
# Log the modelrun.log_model(path="<path-to-model>", name="<name>")
Optionally provide a name for the model artifact for the name parameter. If name is not specified, W&B will use the basename of the input path prepended with the run ID as the name.
Keep track of the name that you, or W&B assigns, to the model. You will need the name of the model to retrieve the model path with the use_model method.
See log_model in the API Reference guide for more information on possible parameters.
Example: Log a model to a run
import os
import wandb
from tensorflow import keras
from tensorflow.keras import layers
config = {"optimizer": "adam", "loss": "categorical_crossentropy"}
# Initialize a W&B runrun = wandb.init(entity="charlie", project="mnist-experiments", config=config)
# Hyperparametersloss = run.config["loss"]
optimizer = run.config["optimizer"]
metrics = ["accuracy"]
num_classes =10input_shape = (28, 28, 1)
# Training algorithmmodel = keras.Sequential(
[
layers.Input(shape=input_shape),
layers.Conv2D(32, kernel_size=(3, 3), activation="relu"),
layers.MaxPooling2D(pool_size=(2, 2)),
layers.Conv2D(64, kernel_size=(3, 3), activation="relu"),
layers.MaxPooling2D(pool_size=(2, 2)),
layers.Flatten(),
layers.Dropout(0.5),
layers.Dense(num_classes, activation="softmax"),
]
)
# Configure the model for trainingmodel.compile(loss=loss, optimizer=optimizer, metrics=metrics)
# Save modelmodel_filename ="model.h5"local_filepath ="./"full_path = os.path.join(local_filepath, model_filename)
model.save(filepath=full_path)
# Log the model to the W&B runrun.log_model(path=full_path, name="MNIST")
run.finish()
When the user called log_model, a model artifact named MNIST was created and the file model.h5 was added to the model artifact. Your terminal or notebook will print information of where to find information about the run the model was logged to.
View run different-surf-5 at: https://wandb.ai/charlie/mnist-experiments/runs/wlby6fuw
Synced 5 W&B file(s), 0 media file(s), 1 artifact file(s) and0 other file(s)
Find logs at: ./wandb/run-20231206_103511-wlby6fuw/logs
Download and use a logged model
Use the use_model function to access and download models files previously logged to a W&B run.
Provide the name of the model artifact where the model files you are want to retrieve are stored. The name you provide must match the name of an existing logged model artifact.
If you did not define name when originally logged the files with log_model, the default name assigned is the basename of the input path, prepended with the run ID.
Ensure to replace other the values enclosed in <> with your own:
import wandb
# Initialize a runrun = wandb.init(project="<your-project>", entity="<your-entity>")
# Access and download model. Returns path to downloaded artifactdownloaded_model_path = run.use_model(name="<your-model-name>")
The use_model function returns the path of downloaded model files. Keep track of this path if you want to link this model later. In the preceding code snippet, the returned path is stored in a variable called downloaded_model_path.
Example: Download and use a logged model
For example, in the proceeding code snippet a user called the use_model API. They specified the name of the model artifact they want to fetch and they also provided a version/alias. They then stored the path that is returned from the API to the downloaded_model_path variable.
import wandb
entity ="luka"project ="NLP_Experiments"alias ="latest"# semantic nickname or identifier for the model versionmodel_artifact_name ="fine-tuned-model"# Initialize a runrun = wandb.init(project=project, entity=entity)
# Access and download model. Returns path to downloaded artifactdownloaded_model_path = run.use_model(name =f"{model_artifact_name}:{alias}")
See use_model in the API Reference guide for more information on possible parameters and return type.
Log and link a model to the W&B Model Registry
The link_model method is currently only compatible with the legacy W&B Model Registry, which will soon be deprecated. To learn how to link a model artifact to the new edition of model registry, visit the Registry docs.
Use the link_model method to log model files to a W&B run and link it to the W&B Model Registry. If no registered model exists, W&B will create a new one for you with the name you provide for the registered_model_name parameter.
You can think of linking a model similar to ‘bookmarking’ or ‘publishing’ a model to a centralized team repository of models that others members of your team can view and consume.
Note that when you link a model, that model is not duplicated in the Model Registry. That model is also not moved out of the project and intro the registry. A linked model is a pointer to the original model in your project.
Use the Model Registry to organize your best models by task, manage model lifecycle, facilitate easy tracking and auditing throughout the ML lifecyle, and automate downstream actions with webhooks or jobs.
A Registered Model is a collection or folder of linked model versions in the Model Registry. Registered models typically represent candidate models for a single modeling use case or task.
The proceeding code snippet shows how to link a model with the link_model API. Ensure to replace other the values enclosed in <> with your own:
import wandb
run = wandb.init(entity="<your-entity>", project="<your-project>")
run.link_model(path="<path-to-model>", registered_model_name="<registered-model-name>")
run.finish()
See link_model in the API Reference guide for more information on optional parameters.
If the registered-model-name matches the name of a registered model that already exists within the Model Registry, the model will be linked to that registered model. If no such registered model exists, a new one will be created and the model will be the first one linked.
For example, suppose you have an existing registered model named “Fine-Tuned-Review-Autocompletion” in your Model Registry (see example here). And suppose that a few model versions are already linked to it: v0, v1, v2. If you call link_model with registered-model-name="Fine-Tuned-Review-Autocompletion", the new model will be linked to this existing registered model as v3. If no registered model with this name exists, a new one will be created and the new model will be linked as v0.
Example: Log and link a model to the W&B Model Registry
For example, the proceeding code snippet logs model files and links the model to a registered model name "Fine-Tuned-Review-Autocompletion".
To do this, a user calls the link_model API. When they call the API, they provide a local filepath that points the content of the model (path) and they provide a name for the registered model to link it to (registered_model_name).
Reminder: A registered model houses a collection of bookmarked model versions.
6 - Log summary metrics
In addition to values that change over time during training, it is often important to track a single value that summarizes a model or a preprocessing step. Log this information in a W&B Run’s summary dictionary. A Run’s summary dictionary can handle numpy arrays, PyTorch tensors or TensorFlow tensors. When a value is one of these types we persist the entire tensor in a binary file and store high level metrics in the summary object, such as min, mean, variance, percentiles, and more.
The last value logged with wandb.log is automatically set as the summary dictionary in a W&B Run. If a summary metric dictionary is modified, the previous value is lost.
The proceeding code snippet demonstrates how to provide a custom summary metric to W&B:
You can update the summary attribute of an existing W&B Run after training has completed. Use the W&B Public API to update the summary attribute:
api = wandb.Api()
run = api.run("username/project/run_id")
run.summary["tensor"] = np.random.random(1000)
run.summary.update()
Customize summary metrics
Custom metric summaries are useful to capture model performance at the best step, instead of the last step, of training in your wandb.summary. For example, you might want to capture the maximum accuracy or the minimum loss value, instead of the final value.
Summary metrics can be controlled using the summary argument in define_metric which accepts the following values: "min", "max", "mean" ,"best", "last" and "none". The "best" parameter can only be used in conjunction with the optional objective argument which accepts values "minimize" and "maximize". Here’s an example of capturing the lowest value of loss and the maximum value of accuracy in the summary, instead of the default summary behavior, which uses the final value from history.
import wandb
import random
random.seed(1)
wandb.init()
# define a metric we are interested in the minimum ofwandb.define_metric("loss", summary="min")
# define a metric we are interested in the maximum ofwandb.define_metric("acc", summary="max")
for i in range(10):
log_dict = {
"loss": random.uniform(0, 1/ (i +1)),
"acc": random.uniform(1/ (i +1), 1),
}
wandb.log(log_dict)
Here’s what the resulting min and max summary values look like, in pinned columns in the sidebar on the Project Page workspace:
To define a Table, specify the columns you want to see for each row of data. Each row might be a single item in your training dataset, a particular step or epoch during training, a prediction made by your model on a test item, an object generated by your model, etc. Each column has a fixed type: numeric, text, boolean, image, video, audio, etc. You do not need to specify the type in advance. Give each column a name, and make sure to only pass data of that type into that column index. For a more detailed example, see this report.
Use the wandb.Table constructor in one of two ways:
List of Rows: Log named columns and rows of data. For example the proceeding code snippet generates a table with two rows and three columns:
Pandas DataFrame: Log a DataFrame using wandb.Table(dataframe=my_df). Column names will be extracted from the DataFrame.
From an existing array or dataframe
# assume a model has returned predictions on four images# with the following fields available:# - the image id# - the image pixels, wrapped in a wandb.Image()# - the model's predicted label# - the ground truth labelmy_data = [
[0, wandb.Image("img_0.jpg"), 0, 0],
[1, wandb.Image("img_1.jpg"), 8, 0],
[2, wandb.Image("img_2.jpg"), 7, 1],
[3, wandb.Image("img_3.jpg"), 1, 1],
]
# create a wandb.Table() with corresponding columnscolumns = ["id", "image", "prediction", "truth"]
test_table = wandb.Table(data=my_data, columns=columns)
Add data
Tables are mutable. As your script executes you can add more data to your table, up to 200,000 rows. There are two ways to add data to a table:
Add a Row: table.add_data("3a", "3b", "3c"). Note that the new row is not represented as a list. If your row is in list format, use the star notation, * ,to expand the list to positional arguments: table.add_data(*my_row_list). The row must contain the same number of entries as there are columns in the table.
Add a Column: table.add_column(name="col_name", data=col_data). Note that the length of col_data must be equal to the table’s current number of rows. Here, col_data can be a list data, or a NumPy NDArray.
Adding data incrementally
This code sample shows how to create and populate a W&B table incrementally. You define the table with predefined columns, including confidence scores for all possible labels, and add data row by row during inference. You can also add data to tables incrementally when resuming runs.
# Define the columns for the table, including confidence scores for each labelcolumns = ["id", "image", "guess", "truth"]
for digit in range(10): # Add confidence score columns for each digit (0-9) columns.append(f"score_{digit}")
# Initialize the table with the defined columnstest_table = wandb.Table(columns=columns)
# Iterate through the test dataset and add data to the table row by row# Each row includes the image ID, image, predicted label, true label, and confidence scoresfor img_id, img in enumerate(mnist_test_data):
true_label = mnist_test_data_labels[img_id] # Ground truth label guess_label = my_model.predict(img) # Predicted label test_table.add_data(
img_id, wandb.Image(img), guess_label, true_label
) # Add row data to the table
Adding data to resumed runs
You can incrementally update a W&B table in resumed runs by loading an existing table from an artifact, retrieving the last row of data, and adding the updated metrics. Then, reinitialize the table for compatibility and log the updated version back to W&B.
# Load the existing table from the artifactbest_checkpt_table = wandb.use_artifact(table_tag).get(table_name)
# Get the last row of data from the table for resumingbest_iter, best_metric_max, best_metric_min = best_checkpt_table.data[-1]
# Update the best metrics as needed# Add the updated data to the tablebest_checkpt_table.add_data(best_iter, best_metric_max, best_metric_min)
# Reinitialize the table with its updated data to ensure compatibilitybest_checkpt_table = wandb.Table(
columns=["col1", "col2", "col3"], data=best_checkpt_table.data
)
# Log the updated table to Weights & Biaseswandb.log({table_name: best_checkpt_table})
Retrieve data
Once data is in a Table, access it by column or by row:
Row Iterator: Users can use the row iterator of Table such as for ndx, row in table.iterrows(): ... to efficiently iterate over the data’s rows.
Get a Column: Users can retrieve a column of data using table.get_column("col_name") . As a convenience, users can pass convert_to="numpy" to convert the column to a NumPy NDArray of primitives. This is useful if your column contains media types such as wandb.Image so that you can access the underlying data directly.
Save tables
After you generate a table of data in your script, for example a table of model predictions, save it to W&B to visualize the results live.
Log a table to a run
Use wandb.log() to save your table to the run, like so:
Each time a table is logged to the same key, a new version of the table is created and stored in the backend. This means you can log the same table across multiple training steps to see how model predictions improve over time, or compare tables across different runs, as long as they’re logged to the same key. You can log up to 200,000 rows.
To log more than 200,000 rows, you can override the limit with:
wandb.Table.MAX_ARTIFACT_ROWS = X
However, this would likely cause performance issues, such as slower queries, in the UI.
Access tables programmatically
In the backend, Tables are persisted as Artifacts. If you are interested in accessing a specific version, you can do so with the artifact API:
with wandb.init() as run:
my_table = run.use_artifact("run-<run-id>-<table-name>:<tag>").get("<table-name>")
For more information on Artifacts, see the Artifacts Chapter in the Developer Guide.
Visualize tables
Any table logged this way will show up in your Workspace on both the Run Page and the Project Page. For more information, see Visualize and Analyze Tables.
Artifact tables
Use artifact.add() to log tables to the Artifacts section of your run instead of the workspace. This could be useful if you have a dataset that you want to log once and then reference for future runs.
run = wandb.init(project="my_project")
# create a wandb Artifact for each meaningful steptest_predictions = wandb.Artifact("mnist_test_preds", type="predictions")
# [build up your predictions data as above]test_table = wandb.Table(data=data, columns=columns)
test_predictions.add(test_table, "my_test_key")
run.log_artifact(test_predictions)
You can join tables you have locally constructed or tables you have retrieved from other artifacts using wandb.JoinedTable(table_1, table_2, join_key).
Args
Description
table_1
(str, wandb.Table, ArtifactEntry) the path to a wandb.Table in an artifact, the table object, or ArtifactEntry
table_2
(str, wandb.Table, ArtifactEntry) the path to a wandb.Table in an artifact, the table object, or ArtifactEntry
join_key
(str, [str, str]) key or keys on which to perform the join
To join two Tables you have logged previously in an artifact context, fetch them from the artifact and join the result into a new Table.
For example, demonstrates how to read one Table of original songs called 'original_songs' and another Table of synthesized versions of the same songs called 'synth_songs'. The proceeding code example joins the two tables on "song_id", and uploads the resulting table as a new W&B Table:
import wandb
run = wandb.init(project="my_project")
# fetch original songs tableorig_songs = run.use_artifact("original_songs:latest")
orig_table = orig_songs.get("original_samples")
# fetch synthesized songs tablesynth_songs = run.use_artifact("synth_songs:latest")
synth_table = synth_songs.get("synth_samples")
# join tables on "song_id"join_table = wandb.JoinedTable(orig_table, synth_table, "song_id")
join_at = wandb.Artifact("synth_summary", "analysis")
# add table to artifact and log to W&Bjoin_at.add(join_table, "synth_explore")
run.log_artifact(join_at)
Read this tutorial for an example on how to combine two previously stored tables stored in different Artifact objects.
We suggest you utilize W&B Artifacts to make it easier to re-use the contents of the CSV file easier to use.
To get started, first import your CSV file. In the proceeding code snippet, replace the iris.csv filename with the name of your CSV filename:
import wandb
import pandas as pd
# Read our CSV into a new DataFramenew_iris_dataframe = pd.read_csv("iris.csv")
Convert the CSV file to a W&B Table to utilize W&B Dashboards.
# Convert the DataFrame into a W&B Tableiris_table = wandb.Table(dataframe=new_iris_dataframe)
Next, create a W&B Artifact and add the table to the Artifact:
# Add the table to an Artifact to increase the row# limit to 200000 and make it easier to reuseiris_table_artifact = wandb.Artifact("iris_artifact", type="dataset")
iris_table_artifact.add(iris_table, "iris_table")
# Log the raw csv file within an artifact to preserve our datairis_table_artifact.add_file("iris.csv")
For more information about W&B Artifacts, see the Artifacts chapter.
Lastly, start a new W&B Run to track and log to W&B with wandb.init:
# Start a W&B run to log datarun = wandb.init(project="tables-walkthrough")
# Log the table to visualize with a run...run.log({"iris": iris_table})
# and Log as an Artifact to increase the available row limit!run.log_artifact(iris_table_artifact)
The wandb.init() API spawns a new background process to log data to a Run, and it synchronizes data to wandb.ai (by default). View live visualizations on your W&B Workspace Dashboard. The following image demonstrates the output of the code snippet demonstration.
The full script with the preceding code snippets is found below:
import wandb
import pandas as pd
# Read our CSV into a new DataFramenew_iris_dataframe = pd.read_csv("iris.csv")
# Convert the DataFrame into a W&B Tableiris_table = wandb.Table(dataframe=new_iris_dataframe)
# Add the table to an Artifact to increase the row# limit to 200000 and make it easier to reuseiris_table_artifact = wandb.Artifact("iris_artifact", type="dataset")
iris_table_artifact.add(iris_table, "iris_table")
# log the raw csv file within an artifact to preserve our datairis_table_artifact.add_file("iris.csv")
# Start a W&B run to log datarun = wandb.init(project="tables-walkthrough")
# Log the table to visualize with a run...run.log({"iris": iris_table})
# and Log as an Artifact to increase the available row limit!run.log_artifact(iris_table_artifact)
# Finish the run (useful in notebooks)run.finish()
Import and log your CSV of Experiments
In some cases, you might have your experiment details in a CSV file. Common details found in such CSV files include:
Configurations needed for your experiment (with the added benefit of being able to utilize our Sweeps Hyperparameter Tuning).
Experiment
Model Name
Notes
Tags
Num Layers
Final Train Acc
Final Val Acc
Training Losses
Experiment 1
mnist-300-layers
Overfit way too much on training data
[latest]
300
0.99
0.90
[0.55, 0.45, 0.44, 0.42, 0.40, 0.39]
Experiment 2
mnist-250-layers
Current best model
[prod, best]
250
0.95
0.96
[0.55, 0.45, 0.44, 0.42, 0.40, 0.39]
Experiment 3
mnist-200-layers
Did worse than the baseline model. Need to debug
[debug]
200
0.76
0.70
[0.55, 0.45, 0.44, 0.42, 0.40, 0.39]
…
…
…
…
…
…
…
Experiment N
mnist-X-layers
NOTES
…
…
…
…
[…, …]
W&B can take CSV files of experiments and convert it into a W&B Experiment Run. The proceeding code snippets and code script demonstrates how to import and log your CSV file of experiments:
To get started, first read in your CSV file and convert it into a Pandas DataFrame. Replace "experiments.csv" with the name of your CSV file:
import wandb
import pandas as pd
FILENAME ="experiments.csv"loaded_experiment_df = pd.read_csv(FILENAME)
PROJECT_NAME ="Converted Experiments"EXPERIMENT_NAME_COL ="Experiment"NOTES_COL ="Notes"TAGS_COL ="Tags"CONFIG_COLS = ["Num Layers"]
SUMMARY_COLS = ["Final Train Acc", "Final Val Acc"]
METRIC_COLS = ["Training Losses"]
# Format Pandas DataFrame to make it easier to work withfor i, row in loaded_experiment_df.iterrows():
run_name = row[EXPERIMENT_NAME_COL]
notes = row[NOTES_COL]
tags = row[TAGS_COL]
config = {}
for config_col in CONFIG_COLS:
config[config_col] = row[config_col]
metrics = {}
for metric_col in METRIC_COLS:
metrics[metric_col] = row[metric_col]
summaries = {}
for summary_col in SUMMARY_COLS:
summaries[summary_col] = row[summary_col]
Next, start a new W&B Run to track and log to W&B with wandb.init():
run = wandb.init(
project=PROJECT_NAME, name=run_name, tags=tags, notes=notes, config=config
)
As an experiment runs, you might want to log every instance of your metrics so they are available to view, query, and analyze with W&B. Use the run.log() command to accomplish this:
run.log({key: val})
You can optionally log a final summary metric to define the outcome of the run. Use the W&B define_metric API to accomplish this. In this example case, we will add the summary metrics to our run with run.summary.update():