Skip to content

Recipes

Short setups for the places training jobs run. Each assumes pip install visin in the job's environment.

A SLURM cluster, with compute nodes that have no internet

Report offline from the compute node, and send from the login node, which usually shares your home directory.

#!/bin/bash
#SBATCH --gres=gpu:1
export VISIN_MODE=offline
export VISIN_DIR=$HOME/.visin            # on the filesystem the login node shares
python train.py

Then, from the login node, with visin login done once:

visin sync --list    # what is waiting
visin sync

Run visin sync while the job is still training and you get live-ish charts: reports written so far are sent, and later ones wait for the next sync. See Offline.

If compute nodes can reach Visin, drop VISIN_MODE and put visin check at the top of the script. It exits with status 1 when the job could not report, so a bad token fails in a second, not after a day of training:

visin check || exit 1
python train.py

A job that SLURM requeues

A requeued job keeps its SLURM_JOB_ID. Derive the run's UUID from it, and the restarted job continues the same run rather than starting a second:

export VISIN_TRAINING_UUID=$(python -c "import uuid, os; print(uuid.uuid5(uuid.NAMESPACE_DNS, 'road-seg-' + os.environ['SLURM_JOB_ID']))")
python train.py     # visin.init("unet baseline") resumes it if it exists

run.resumed says which happened. Epochs the restarted job logs again keep their first values, so resume from the epoch of your checkpoint and number the epochs the same way. See Resuming.

Training and testing as separate scripts

The training script creates the run. Later scripts, perhaps on other machines, add to it without touching its status:

# test.py
import visin

with visin.Run.attach(training_uuid, mark_status=False) as run:
    run.log_test_results(epoch, scores)

An orchestrator that registered the run first can export VISIN_TRAINING_UUID instead of passing the UUID. A script can also look a run up by name, with Api().find(name).

Docker and Compose

Pass the settings as environment variables, and keep the token out of the image:

services:
  train:
    image: my-training-image
    environment:
      VISIN_URL: https://vision-api.visin.eu
      VISIN_TOKEN: ${VISIN_TOKEN}
      VISIN_DIR: /spool
    volumes:
      - visin-spool:/spool
volumes:
  visin-spool:

Without the volume, reports that could not be sent die with the container. Alternatively mount a file and set VISIN_ENV_FILE=/run/secrets/visin.env, with the same NAME=value lines.

Continuous integration and tests

Leave VISIN_URL and VISIN_TOKEN unset: every call does nothing, so the same code runs in CI unchanged, and nobody needs a secret to run the tests. To check your own code's calls without a server, use visin.Run.disabled(). To make a failure to report an error in a test, pass strict=True:

with visin.init("test", strict=True) as run:
    run.log_epoch(1)  # raises: it needs results, where a normal run logs a warning

A notebook

Use a short, explicit setup, and the console log, since a notebook has no terminal to show warnings:

import visin

visin.enable_console_logging()
run = visin.init("exploration", project="road-seg", tags=["notebook"])
print(run.url)
...
run.finish()

A notebook that is closed without finish is finished when the kernel exits, so the run is not left "running" for ever.

Several GPUs

Every process runs the same script, and only rank zero reports (read from RANK, SLURM_PROCID, OMPI_COMM_WORLD_RANK or PMI_RANK). Log the metrics you have already reduced across ranks, since rank zero's own numbers are what Visin shows.