GPUtw Docs

Monitoring and Tracking

Watch GPU usage while a job runs, and record what each run actually did with Weights & Biases and Hugging Face.

Two different questions

“Is the GPU busy right now?” and “which run produced this checkpoint?” are answered by different tools, and mixing them up is why people end up with neither.

  • Resource monitoring: live utilization, VRAM, RAM, and disk. Answers whether the hardware you are paying for is actually working. Nothing to install.
  • Experiment tracking: loss curves, hyperparameters, and artifacts, kept after the instance is gone. That is what Weights & Biases is for.
  • Model and dataset management: pulling weights in and pushing results out, with the cache somewhere that survives the instance. That is Hugging Face plus /vault.

What the dashboard already shows

Every running instance reports live utilization on the Instances page — no agent, no setup. The same numbers are on the API, which is the honest source for how much of your rented allocation is in use:

GET/api/instances/{id}/resources
Info

This is also the figure to trust for disk. df inside the container reports the whole machine's filesystem, not the size your instance is held to — see Docker / Container Environment.

GPU usage from inside a notebook

A cell prefixed with ! runs a shell command, so the standard tools work unchanged. nvidia-smi is present on every GPU image:

Example
!nvidia-smi

For something readable while a job runs, nvitop gives a live view with per-process attribution — useful when you want to know whether it is your training loop or a forgotten notebook kernel holding the VRAM. Run it in a terminal tab rather than a cell, since it does not exit:

Example
!pip install -q nvitop
# then, in a Jupyter terminal:
nvitop

Inside the training loop, ask the framework instead — it reports what your process holds rather than what the driver sees:

Example
import torch

free, total = torch.cuda.mem_get_info()
print(f"in use: {(total - free) / 1e9:.1f} / {total / 1e9:.1f} GB")
print(f"peak this process: {torch.cuda.max_memory_allocated() / 1e9:.1f} GB")
Tip

A GPU sitting at low utilization while your job runs usually means it is waiting on data, not compute. Check dataloader workers and where the dataset lives before renting a bigger card — reading a dataset straight off /vault on every epoch is a common cause.

Weights & Biases

W&B records hyperparameters, metrics, and system stats for each run and keeps them on their servers, so the history outlives the instance. Log in once with a token from wandb.ai/authorize:

Example
%pip install -q wandb

import os, wandb
# WANDB_DIR is a ROOT — wandb creates its own wandb/ inside it, so runs
# land in /vault/wandb/. Default is ./wandb next to the script, which dies
# with the instance.
os.environ["WANDB_DIR"] = "/vault"
wandb.login()  # or set WANDB_API_KEY as an instance environment variable

Then wrap the run. Logging GPU memory alongside your loss is worth the one extra line — it is what tells you afterwards whether a batch size was actually safe:

Example
run = wandb.init(project="my-project", config={"lr": 3e-4, "batch_size": 32})

for epoch in range(epochs):
    loss = train_one_epoch()
    run.log({
        "loss": loss,
        "gpu_mem_gb": torch.cuda.max_memory_allocated() / 1e9,
    })

run.finish()  # flushes the last metrics — a killed kernel loses them
Tip

W&B needs outbound HTTPS, which instances have; you do not need to expose a port for it. If a run must survive a network problem, set WANDB_MODE=offline and upload later with wandb sync /vault/wandb/offline-run-*.

Hugging Face

The setting that matters most on GPUtw is where the cache lives. By default huggingface_hub caches under ~/.cache/huggingface, which is inside the container — so every new instance re-downloads the same weights. Point HF_HOME at /vault and you download once, ever:

Example
%pip install -q -U huggingface_hub

import os
os.environ["HF_HOME"] = "/vault/hf"                 # cache survives the instance
os.environ["HF_XET_HIGH_PERFORMANCE"] = "1"         # saturate the link on big pulls
os.environ.setdefault("HF_TOKEN", "")               # set at deploy time, not here
Info

Guides written before huggingface_hub v1.0 (October 2025) reach for hf_transfer and HF_HUB_ENABLE_HF_TRANSFER=1. That package was removed in v1.0 and the variable is now ignored — downloads go through the Xet backend, and HF_XET_HIGH_PERFORMANCE is its equivalent. Setting the old variable does not warn; it simply does nothing.

Warning

Set these before importing transformers, diffusers, or huggingface_hub. The cache path is read at import time, so a cell run afterwards silently has no effect — restart the kernel if you have already imported. The cleanest place for them is the Environment variables field when you deploy.

Pull a model, and push results back:

Example
from huggingface_hub import snapshot_download

path = snapshot_download("Qwen/Qwen2.5-7B-Instruct")

# after training
model.push_to_hub("my-org/my-model", private=True)
Warning

With HF_HOME on /vault, hf auth login writes your Hugging Face token in plaintext to /vault/hf/token — shared by every instance on the account, and downloadable by anything holding vault:read. Move the cache, not the credential: pass HF_TOKEN as an environment variable and skip login() entirely. If you have already run it, delete that file.

Tip

No instance running? The Vault page's Download from URL takes a Hugging Face reference and has the server fetch it straight into your vault — see Vault Storage.

Where to keep the cache

/vault is network storage. That is what makes it persistent and shared across your instances, and it is also why the first read of a large file is slower than local disk. The rule that follows:

  • Weights you load once: keep on /vault. Loading a checkpoint at startup is a one-time cost, and never re-downloading it is worth far more.
  • Data read every epoch: copy to /workspace first. Local disk, and the copy pays for itself within an epoch or two.
Warning

An HF_HOME on /vault counts against your vault quota, and model caches grow quietly. Clear old revisions with hf cache prune when the Vault page shows usage climbing.

Keep tokens out of notebooks

A WANDB_API_KEY or HF_TOKEN pasted into a cell is saved into the .ipynb file, and travels with it into /vault, into any repo you push, and into anything you share. Pass them as environment variables at deploy time instead — the Environment variables field on the deploy page, or env on the create API.

Know what that means: those values are kept with the instance record so the deploy form can prefill them next time, and they are not encrypted at rest. It is better than a notebook — nothing copies them onward — but it is not a secret manager. Use a scoped, short-lived token where the provider offers one (Hugging Face fine-grained tokens, a W&B service account) rather than an account-wide key.

Warning

Both tokens are account credentials for services outside GPUtw. Treat them like the GPUtw API key: scope them where the provider allows it, and rotate them if a notebook containing one was ever shared.