Polyaxon provides several methods for tracking metrics, metadata, summaries, and graphs in your jobs.

Overview

For each run, Polyaxon creates an artifacts folder with a predefined structure to organize your events:

  • metrics
  • charts
  • text
  • HTML

Some events create save related assets to these events and are saved under a separate folder called assets.

Logging single results and outputs

To log single results that do not need to be visualized, do not change over time, or only should be recorded at the end of a job you should use:

from polyaxon import tracking

tracking.log_outputs(foo="bar", scalar=0.1, key="val")

Logging step-wise events

To log texts, HTML, scalars, metrics that change overtime or need to be recorded in a step-wise manner, or if you need to visualize the event in the dashboard you should use:

Tracking changing metrics

from polyaxon import tracking

def get_loss(step):
    result = 10 / (step + 1)
    noise = (random.random() - 0.5) * 0.5 * result
    return result + noise

def get_accuracy(loss):
    return (100 - loss) / 100.0

for i in range(1, 5):
    loss = get_loss(i)
    accuracy = get_accuracy(loss)
    tracking.log_metrics(loss=loss, accuracy=accuracy, step=i)

Tracking a changing text value over time or step-wise

from polyaxon import tracking

for i in range(1, 5):
    tracking.log_text(name="text-event", value="value at step {}".format(i), step=i)

Tracking a changing HTML value over time or step-wise

from polyaxon import tracking

def get_html(step):
    return (
        '<span><a href="https://link.com">This is a link {step} </a>'
        '<b>Some more html at step {step}</b></span>'.format(step=step)
    )

for i in range(1, 5):
    tracking.log_html(name="text-event", html=get_html(i), step=i)

Tracking a changing audio over time or step-wise

import numpy as np

from polyaxon import tracking

def get_audio(step):
    sample_rate = 44100 + step
    freqs = 440
    dummy_audio = np.arange(sample_rate * 2, dtype=np.float32)
    return np.cos(dummy_audio * (2.0 * freqs * np.pi / sample_rate))

for i in range(1, 5):
    tracking.log_audio(data=get_audio(i), name='audio-ex', step=i)

Tracking a changing distribution over time or step-wise

from polyaxon import tracking

def get_dist(step):
    x = np.random.random(1000)
    return x + step


def get_np_hist(step):
    values, counts = np.histogram(np.random.randint(255, size=(1000,)))
    return {"values": values, "counts": counts, "step": step}

for i in range(1, 5):
    tracking.log_histogram('distribution', get_dist(i), 'auto', step=i)
    tracking.log_np_histogram('np-hist', **get_np_hist(i))
  • Tracking a changing curves and charts over time or step-wise
import random

import altair as alt
import matplotlib.pyplot as plt
import numpy as np
import plotly.express as px
from bokeh.plotting import figure
from vega_datasets import data

from polyaxon import tracking


def plot_scatter(step):
    x = np.random.randn(step)
    y = np.random.randn(step)

    left, width = 0.1, 0.65
    bottom, height = 0.1, 0.65
    spacing = 0.005

    rect_scatter = [left, bottom, width, height]
    rect_histx = [left, bottom + height + spacing, width, 0.2]
    rect_histy = [left + width + spacing, bottom, 0.2, height]

    figure = plt.figure(figsize=(8, 8))

    ax_scatter = plt.axes(rect_scatter)
    ax_scatter.tick_params(direction='in', top=True, right=True)
    ax_histx = plt.axes(rect_histx)
    ax_histx.tick_params(direction='in', labelbottom=False)
    ax_histy = plt.axes(rect_histy)
    ax_histy.tick_params(direction='in', labelleft=False)
    ax_scatter.scatter(x, y)

    binwidth = 0.25
    lim = np.ceil(np.abs([x, y]).max() / binwidth) * binwidth
    ax_scatter.set_xlim((-lim, lim))
    ax_scatter.set_ylim((-lim, lim))

    bins = np.arange(-lim, lim + binwidth, binwidth)
    ax_histx.hist(x, bins=bins)
    ax_histy.hist(y, bins=bins, orientation='horizontal')

    ax_histx.set_xlim(ax_scatter.get_xlim())
    ax_histy.set_ylim(ax_scatter.get_ylim())
    tracking.log_mpl_plotly_chart(name='scatter', figure=figure, step=step)


def plot_mpl_figure(step):
    np.random.seed(step)
    data = np.random.randn(2, 100)

    figure, axs = plt.subplots(2, 2, figsize=(5, 5))
    axs[0, 0].hist(data[0])
    axs[1, 0].scatter(data[0], data[1])
    axs[0, 1].plot(data[0], data[1])
    axs[1, 1].hist2d(data[0], data[1])

    tracking.log_mpl_image(figure, 'mpl_image', step=step)


def log_bokeh(step):
    factors = ["a", "b", "c", "d", "e", "f", "g", "h"]
    x = [50, 40, 65, 10, 25, 37, 80, 60]

    dot = figure(title="Categorical Dot Plot", tools="", toolbar_location=None,
                 y_range=factors, x_range=[0, 100])

    dot.segment(0, factors, x, factors, line_width=2, line_color="green", )
    dot.circle(x, factors, size=15, fill_color="orange", line_color="green", line_width=3, )

    factors = ["foo 123", "bar:0.2", "baz-10"]
    x = ["foo 123", "foo 123", "foo 123", "bar:0.2", "bar:0.2", "bar:0.2", "baz-10", "baz-10",
         "baz-10"]
    y = ["foo 123", "bar:0.2", "baz-10", "foo 123", "bar:0.2", "baz-10", "foo 123", "bar:0.2",
         "baz-10"]
    colors = [
        "#0B486B", "#79BD9A", "#CFF09E",
        "#79BD9A", "#0B486B", "#79BD9A",
        "#CFF09E", "#79BD9A", "#0B486B"
    ]

    hm = figure(title="Categorical Heatmap", tools="hover", toolbar_location=None,
                x_range=factors, y_range=factors)

    hm.rect(x, y, color=colors, width=1, height=1)

    tracking.log_bokeh_chart(name='confusion-bokeh', figure=hm, step=step)


def log_altair(step):
    source = data.cars()

    brush = alt.selection(type='interval')

    points = alt.Chart(source).mark_point().encode(
        x='Horsepower:Q',
        y='Miles_per_Gallon:Q',
        color=alt.condition(brush, 'Origin:N', alt.value('lightgray'))
    ).add_selection(
        brush
    )

    bars = alt.Chart(source).mark_bar().encode(
        y='Origin:N',
        color='Origin:N',
        x='count(Origin):Q'
    ).transform_filter(
        brush
    )

    chart = points & bars

    tracking.log_altair_chart(name='altair_chart', figure=chart, step=step)


def log_curves(step):
    # ROC curve
    x = [
        0.0,
        0.0,
        0.0,
        0.0196078431372549,
        0.0196078431372549,
        0.0784313725490196,
        0.0784313725490196,
        0.09803921568627451,
        0.09803921568627451,
        0.11764705882352941,
        0.11764705882352941,
        0.13725490196078433,
        0.13725490196078433,
        0.1568627450980392,
        0.1568627450980392,
        0.17647058823529413,
        0.17647058823529413,
        0.3137254901960784,
        0.3137254901960784,
        0.3333333333333333,
        0.3333333333333333,
        0.35294117647058826,
        0.35294117647058826,
        0.4117647058823529,
        0.4117647058823529,
        0.45098039215686275,
        0.45098039215686275,
        0.47058823529411764,
        0.47058823529411764,
        0.5098039215686274,
        0.5098039215686274,
        0.5686274509803921,
        0.5686274509803921,
        1.0
    ]
    y = [
        0.0,
        0.041666666666666664,
        0.125,
        0.125,
        0.25,
        0.25,
        0.2916666666666667,
        0.2916666666666667,
        0.3333333333333333,
        0.3333333333333333,
        0.4166666666666667,
        0.4166666666666667,
        0.5,
        0.5,
        0.5416666666666666,
        0.5416666666666666,
        0.5833333333333334,
        0.5833333333333334,
        0.7083333333333334,
        0.7083333333333334,
        0.75,
        0.75,
        0.7916666666666666,
        0.7916666666666666,
        0.8333333333333334,
        0.8333333333333334,
        0.875,
        0.875,
        0.9166666666666666,
        0.9166666666666666,
        0.9583333333333334,
        0.9583333333333334,
        1.0,
        1.0
    ]
    tracking.log_roc_auc_curve(name='roc-curve-man', fpr=x, tpr=y, auc=0.742149, step=step)

    x = [0.66666667, 0.5, 1., 1.]
    y = [1., 0.5, 0.5, 0.]
    tracking.log_pr_curve(name='pr-curve-man', precision=x, recall=y, average_precision=0.742149,
                          step=step)

    # Random curve
    tracking.log_curve(
        name='random-curve-man', x=np.random.randn(10 * step), y=np.random.randn(10 * step), step=step
    )



def get_sin_plot(step):
    x = np.linspace(0, step * np.pi, 400)
    y = np.sin(x ** 2)

    f, ax = plt.subplots()
    ax.plot(x, y)
    ax.set_title('Simple plot')
    tracking.log_mpl_plotly_chart(name='sin', figure=f, step=step)


def log_confusion(step):
    z = np.array([[0.1, 0.3, 0.5, 0.2],
     [1.0, 0.8, 0.6, 0.1],
     [0.1, 0.3, 0.6, 0.9],
     [0.6, 0.4, 0.2, 0.2]]) * step

    x = ['healthy', 'multiple diseases', 'rust', 'scab']
    y = ['healthy', 'multiple diseases', 'rust', 'scab']
    tracking.log_confusion_matrix("confusion_test", x, y, z.tolist(), step=step)


def log_plotly(step):
    df = px.data.tips()

    fig = px.density_heatmap(df, x="total_bill", y="tip", facet_row="sex", facet_col="smoker")
    tracking.log_plotly_chart(name="2d-hist", figure=fig, step=step)


for i in range(1, 5):
    plot_scatter(i)
    get_sin_plot(i)
    plot_mpl_figure(i)
    log_bokeh(i)
    log_altair(i)
    log_curves(i)
    log_plotly(i)
    log_confusion(i)