Before you start#
- You have a ZIH login and you joined the course project
p_lv_llmsecrets. - You are on the university network or the VPN.
- You have a terminal: Terminal on macOS and Linux, PowerShell or Windows Terminal on Windows. All of them know
ssh.
Not sure what a login node or a workspace is? Read Meet the machines first.
Marie and Martin. Martin installs PyTorch by hand on the login node. Marie runs the setup script with bash and nothing is switched on afterwards. See what happened
The four steps#
-
Log in
Pick a GPU cluster. Alpha has A100 GPUs, Capella has H100 GPUs. Both work for everything in this lab.
on your computershell ssh <zih-login>@login1.alpha.hpc.tu-dresden.de # GPU cluster, 8 A100 per node ssh <zih-login>@login1.capella.hpc.tu-dresden.de # GPU cluster, 4 H100 per node ssh <zih-login>@login1.barnard.hpc.tu-dresden.de # CPU clusterThe first time,
sshasks if you trust the machine. Compare what it shows with the key fingerprints in the Compendium and answeryes. Then type your ZIH password. Nothing appears while you type, that is normal.Optional: log in without typing the password every time
Create a key pair on your own computer and copy the public half to the cluster. Give the key a passphrase when you are asked.
on your computer (macOS, Linux)shell ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 ssh-copy-id -i ~/.ssh/id_ed25519.pub <zih-login>@login1.alpha.hpc.tu-dresden.deWindows has no
ssh-copy-id. Copy the file over and add it by hand:on Windows, in PowerShellshell ssh-keygen -t ed25519 scp $env:USERPROFILE\.ssh\id_ed25519.pub <zih-login>@login1.alpha.hpc.tu-dresden.de: ssh <zih-login>@login1.alpha.hpc.tu-dresden.dethen, on the login nodeshell mkdir -p ~/.ssh && cat id_ed25519.pub >> ~/.ssh/authorized_keys && rm id_ed25519.pubMore about keys and ssh settings is in the Compendium.
-
Get the lab kit
You are now on a login node. Clone the repository into your home folder. It is small.
on the login nodeshell git clone https://github.com/himanshubeniwal/behind-llms-lab.git cd behind-llms-lab/hpc_lab -
Build the Python environment
Installing PyTorch is real work, so it does not belong on the login node. Ask Slurm for a small interactive job, run the setup script there, and give the machine back.
Two lines every job needs on Alpha.
--nodes=1, because ZIH wants the number of nodes in every job. And--gres=gpu:1, because Alpha only accepts jobs that ask for a GPU, even an installation that does not use one. Without them you getQOSMinGRESor a reminder about-N. On Barnard, leave out--gres.on the login nodeshell srun --account=p_lv_llmsecrets --nodes=1 --gres=gpu:1 \ --ntasks=1 --cpus-per-task=4 --mem-per-cpu=2G \ --time=00:45:00 --pty bash -l # a small interactive job cd ~/behind-llms-lab/hpc_lab source 00_setup/setup_env.sh # workspace, venv, training text exit # give the machine backThe first run takes 5 to 10 minutes. At the end you should see something like this:
what the setup script prints workspace : /data/horse/ws/<zih-login>-llm-lab creating the venv /data/horse/ws/<zih-login>-llm-lab/venv-llm (only the first time, this takes a few minutes) python : /data/horse/ws/<zih-login>-llm-lab/venv-llm/bin/python (Python 3.12.3) downloaded tiny Shakespeare to /data/horse/ws/<zih-login>-llm-lab/data/input.txt environment readyUse
source, notbash. Only then does the environment stay switched on in your shell. From now on the same line takes a second, and the job scripts run it themselves. -
Check that it works
Send the first job of the lab. Its work runs on the CPU and takes a few seconds once it starts. It still asks for a GPU, because Alpha takes nothing else.
on the login nodeshell cd ~/behind-llms-lab/hpc_lab/01_hello mkdir -p logs && sbatch hello.sbatch squeue --me # PD means waiting, R means running cat logs/hello-hpc-*.out # when the job is gone from the queueIf the log shows the name of a compute node and an estimate of pi, you are ready for the HPC lab.
The setup script#
00_setup/setup_env.sh does five things, and it is safe to run as often as you like:
- It creates the workspace
llm-lab, or reuses it. This is the big, fast storage for the environment, the data and the models. - It loads a Python module of the cluster.
- It creates a virtual environment with PyTorch and transformers inside the workspace, or switches it on if it is already there.
- It points the pip, Hugging Face and temporary caches into the workspace, away from the small home folder.
- It downloads the tiny Shakespeare text that exercise 4 trains on.
It also sets $WS_DIR, the path of your workspace. The job scripts use it for data and results.
setup_env.sh
#!/bin/bash
# Behind the Secrets of LLMs, HPC lab
# 00_setup/setup_env.sh: sets up your Python environment once, and switches it on later.
#
# The first time it installs packages, which takes 5 to 10 minutes. Do that inside
# a small interactive job, not on the login node:
#
# srun --account=p_lv_llmsecrets --ntasks=1 --cpus-per-task=4 --mem-per-cpu=2G \
# --time=00:45:00 --pty bash -l
# source 00_setup/setup_env.sh
#
# After that, in every new shell and in every batch job, it only takes a second:
#
# source 00_setup/setup_env.sh
#
# Use "source", not "bash", so that the venv stays active in your shell.
#
# What it does:
# 1. creates (or reuses) a workspace, which is big and fast storage for venv, data and models
# 2. loads a Python module
# 3. creates (or reuses) a venv with PyTorch and transformers inside the workspace
# 4. points the pip, Hugging Face and tmp caches into the workspace instead of $HOME
# 5. downloads the tiny Shakespeare text for exercise 4
# ---- settings you may change ------------------------------------------------
WS_NAME="${WS_NAME:-llm-lab}" # workspace name
WS_FS="${WS_FS:-horse}" # file system, horse works on all clusters
WS_DAYS="${WS_DAYS:-30}" # lifetime in days, extend it later with ws_extend
VENV_NAME="${VENV_NAME:-venv-llm}"
# Python module. If it does not exist on your cluster, look with: module spider Python
PY_MODULES="release/24.10 GCCcore/13.3.0 Python/3.12.3"
# PyTorch built for CUDA 12.x runs with the drivers on Alpha (A100) and Capella (H100).
# A plain "pip install torch" may pick a CUDA 13 build that needs a newer driver.
# If nvidia-smi shows CUDA 13.0 or newer you can use .../whl/cu130 instead.
TORCH_INDEX="https://download.pytorch.org/whl/cu128"
# -----------------------------------------------------------------------------
# 1) workspace. If this shell (or the shell that submitted the job) already has it, reuse it.
if [ -z "$WS_DIR" ] || [ ! -d "$WS_DIR" ]; then
# ws_allocate prints the path. For a workspace that already exists it just reuses it.
WS_DIR="$(ws_allocate -F "$WS_FS" "$WS_NAME" "$WS_DAYS" 2>/dev/null)"
fi
if [ -z "$WS_DIR" ] || [ ! -d "$WS_DIR" ]; then
echo "Could not create the workspace '$WS_NAME' on '$WS_FS'. Check with: ws_list -l" >&2
return 1 2>/dev/null || exit 1
fi
export WS_DIR
echo "workspace : $WS_DIR"
# 2) modules
module purge > /dev/null 2>&1
if ! module load $PY_MODULES; then
echo "'module load $PY_MODULES' did not work. Run 'module spider Python' and change PY_MODULES." >&2
return 1 2>/dev/null || exit 1
fi
# 3) caches go into the workspace, because the $HOME quota is small
export PIP_CACHE_DIR="$WS_DIR/.cache/pip"
export HF_HOME="$WS_DIR/.cache/huggingface"
export TMPDIR="$WS_DIR/tmp"
mkdir -p "$PIP_CACHE_DIR" "$HF_HOME" "$TMPDIR" "$WS_DIR/data" "$WS_DIR/runs"
# 4) venv
if [ ! -f "$WS_DIR/$VENV_NAME/bin/activate" ]; then
echo "creating the venv $WS_DIR/$VENV_NAME (only the first time, this takes a few minutes)"
python -m venv "$WS_DIR/$VENV_NAME"
source "$WS_DIR/$VENV_NAME/bin/activate"
pip install --quiet --upgrade pip
pip install --quiet torch --index-url "$TORCH_INDEX"
pip install --quiet numpy matplotlib tqdm transformers accelerate ipykernel
# the same environment as a kernel in JupyterHub
python -m ipykernel install --user --name "$VENV_NAME" --display-name "LLM Lab ($VENV_NAME)"
else
source "$WS_DIR/$VENV_NAME/bin/activate"
fi
echo "python : $(which python) ($(python --version 2>&1))"
# 5) the training text for exercise 4
if [ ! -s "$WS_DIR/data/input.txt" ]; then
curl -sSL -o "$WS_DIR/data/input.txt" \
https://raw.githubusercontent.com/karpathy/char-rnn/master/data/tinyshakespeare/input.txt \
&& echo "downloaded tiny Shakespeare to $WS_DIR/data/input.txt"
fi
echo "environment ready"Settings you may change
| Setting | Default | What it is |
|---|---|---|
WS_NAME | llm-lab | The name of the workspace. |
WS_FS | horse | The file system. horse works on all clusters. |
WS_DAYS | 30 | The lifetime in days. Extend it later with ws_extend. |
VENV_NAME | venv-llm | The name of the virtual environment. |
PY_MODULES | release/24.10 GCCcore/13.3.0 Python/3.12.3 | The Python module. Module versions change about twice a year. If loading fails, run module spider Python and put the new names here. |
TORCH_INDEX | https://download.pytorch.org/whl/cu128 | Which PyTorch build to install. This one fits the GPU drivers on Alpha and Capella. |
Prefer conda?#
The venv above is what the lab uses and what ZIH recommends. If you are used to conda, the folder 00_setup/conda builds a similar environment with conda instead: PyTorch, transformers, pandas and evaluate, in a workspace of its own called llm-conda. It does not touch the lab venv, and the exercises keep using the venv.
Anaconda has a licence. Anaconda's terms now cover universities of TU Dresden's size, and TU Dresden has no central licence. So the script installs only from conda-forge. If in doubt, use the venv.
cd ~/behind-llms-lab/hpc_lab/00_setup/conda
mkdir -p logs && sbatch create_env.sbatch # once, about 10 to 15 minutes
cat logs/create-env-*.out # the last line should say OK | CUDA: True
sbatch job.sbatch # runs check_env.py in the environment
cat logs/conda-job-*.out # ends with ALL GOODThree things work differently from conda on your laptop:
- No
conda init. ZIH asks you not to use it. Load the module and sourceconda.shinstead, in every shell and in every job, asjob.sbatchdoes. - The environment lives in a workspace, given with
--prefix, not in~/.conda. Workspaces expire: check withws_listand extend withws_extend -F horse llm-conda 30. pipneedsPIP_REQUIRE_VIRTUALENV=falseinside a conda environment, because pip on ZIH systems refuses to run outside a venv.
srun --account=p_lv_llmsecrets --nodes=1 --ntasks=1 --cpus-per-task=4 --mem-per-cpu=2G --gres=gpu:1 --time=00:30:00 --pty bash -l
module load Anaconda3 && source $EBROOTANACONDA3/etc/profile.d/conda.sh
conda activate $(ws_find -F horse llm-conda)/env
PIP_REQUIRE_VIRTUALENV=false pip install --no-cache-dir datasets # or whatever you need
exitcreate_env.sbatch
#!/bin/bash
# The conda route, an alternative to setup_env.sh for people who prefer conda.
# Builds a conda environment with PyTorch, transformers, pandas and evaluate in its
# own workspace. Run it once, from this folder, on an Alpha login node:
#
# cd ~/behind-llms-lab/hpc_lab/00_setup/conda
# mkdir -p logs && sbatch create_env.sbatch
# cat logs/create-env-<jobid>.out # the last line should say OK
#
# Running it again builds the environment from scratch.
#
# ZIH recommends the venv from setup_env.sh. Anaconda's licence now covers universities
# of TU Dresden's size and TU Dresden has no central licence, so this script installs
# only from conda-forge. If in doubt, use the venv.
#
#SBATCH --job-name=create-env
#SBATCH --account=p_lv_llmsecrets
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=6
#SBATCH --gres=gpu:1 # Alpha takes only GPU jobs, and the last line tests CUDA
#SBATCH --mem=32G
#SBATCH --time=01:00:00
#SBATCH --output=logs/%x-%j.out
#SBATCH --error=logs/%x-%j.err
WS_NAME=llm-conda
module purge
module load Anaconda3 # if this fails: module spider Anaconda3
source $EBROOTANACONDA3/etc/profile.d/conda.sh # ZIH asks for this instead of "conda init"
# The environment lives in its own workspace, not in the small $HOME
ws_allocate -F horse $WS_NAME 30 > /dev/null
ENV=$(ws_find -F horse $WS_NAME)/env
conda create -y --prefix $ENV --override-channels -c conda-forge python=3.11 pip
conda activate $ENV
# pip on ZIH systems refuses to run outside a venv, and a conda env does not count as one
export PIP_REQUIRE_VIRTUALENV=false
# PyTorch for CUDA 12.x fits the drivers on Alpha and Capella (see setup_env.sh)
pip install --no-cache-dir torch --index-url https://download.pytorch.org/whl/cu128
pip install --no-cache-dir transformers pandas evaluate
python -c "import torch, transformers, pandas, evaluate; print('OK | CUDA:', torch.cuda.is_available())"job.sbatch
#!/bin/bash
# The conda route: a job that runs a Python script inside the conda environment.
# Run create_env.sbatch once first. Then, from this folder:
#
# mkdir -p logs && sbatch job.sbatch
# cat logs/conda-job-<jobid>.out # ends with ALL GOOD
#
# For your own code, copy this file and change the last line.
#
#SBATCH --job-name=conda-job
#SBATCH --account=p_lv_llmsecrets
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=6
#SBATCH --gres=gpu:1
#SBATCH --mem=32G
#SBATCH --time=00:30:00
#SBATCH --output=logs/%x-%j.out
#SBATCH --error=logs/%x-%j.err
WS_NAME=llm-conda
module purge
module load Anaconda3
source $EBROOTANACONDA3/etc/profile.d/conda.sh
conda activate $(ws_find -F horse $WS_NAME)/env
export HF_HOME=$(ws_find -F horse $WS_NAME)/hf-cache # downloaded models go to the workspace, not $HOME
export SRUN_CPUS_PER_TASK=$SLURM_CPUS_PER_TASK
srun python -u check_env.pycheck_env.py
"""The conda route: check that the environment works on a GPU node.
Run it with job.sbatch. It tests the GPU, transformers, pandas and evaluate,
and ends with ALL GOOD. The first run downloads a small model (about 250 MB).
"""
import time
import evaluate
import pandas as pd
import torch
import transformers
from transformers import pipeline
# 1. Versions
print(f"torch {torch.__version__} | transformers {transformers.__version__} | "
f"pandas {pd.__version__} | evaluate {evaluate.__version__}")
# 2. GPU
assert torch.cuda.is_available(), "No GPU visible. Is '#SBATCH --gres=gpu:1' in the job script?"
print("GPU:", torch.cuda.get_device_name(0))
x = torch.randn(4096, 4096, device="cuda")
x @ x # warm-up
torch.cuda.synchronize()
t = time.time()
x @ x
torch.cuda.synchronize()
print(f"4096x4096 matmul: {(time.time() - t) * 1000:.1f} ms")
# 3. transformers: a small sentiment model on the GPU
clf = pipeline(
"sentiment-analysis",
model="distilbert/distilbert-base-uncased-finetuned-sst-2-english",
device=0,
)
texts = [
"The cluster finally runs my jobs.",
"Waiting in the queue all day is awful.",
"This environment setup was painless.",
"The error messages were confusing.",
]
labels = [1, 0, 1, 0] # 1 = positive, 0 = negative
preds = clf(texts)
# 4. pandas
df = pd.DataFrame({
"text": texts,
"pred": [p["label"] for p in preds],
"score": [round(p["score"], 3) for p in preds],
})
print(df.to_string(index=False))
# 5. evaluate
accuracy = evaluate.load("accuracy")
pred_ids = [1 if p["label"] == "POSITIVE" else 0 for p in preds]
print("accuracy:", accuracy.compute(predictions=pred_ids, references=labels)["accuracy"])
print("ALL GOOD")Where to run the notebooks#
the easy way
Google Colab
Nothing to install. Use the buttons on the Notebooks page. For notebooks 5 and 6, choose a T4 GPU under Runtime > Change runtime type.
on the cluster
JupyterHub
Open jupyterhub.hpc.tu-dresden.de from the university network, start a server, and pick the kernel LLM Lab (venv-llm). The setup script installed it for you.
offline
Your laptop
Clone the repository, then pip install torch transformers matplotlib jupyter in a virtual environment. The notebooks pick small settings when there is no GPU.
Your own experiments#
The lab kit is meant to be taken apart. Once the seven exercises work, the same pieces run your own code.
- Code goes into your home folder, everything big goes into the workspace. After
source 00_setup/setup_env.shthe workspace is$WS_DIR. The lab uses$WS_DIR/datafor data and$WS_DIR/runsfor results. - Need another package? Start an interactive job as in step 3, switch the environment on and install it. It lands in the environment in your workspace and every later job has it.
- Write a job script. Copy the one from the exercise that is closest to what you want and change the last line, or use the generator below.
- Send it and watch it.
sbatch,squeue --me,tail -f logs/…. The cheat sheet has the rest.
srun --account=p_lv_llmsecrets --nodes=1 --ntasks=1 --cpus-per-task=4 --mem-per-cpu=2G --gres=gpu:1 --time=00:30:00 --pty bash -l
source ~/behind-llms-lab/hpc_lab/00_setup/setup_env.sh
pip install datasets # or whatever you need
exitHabits worth copying from the lab scripts
- Create
logs/before you submit. If the folder for the log file is missing, the job ends at once and leaves no trace. - Print with
flush=Trueor runpython -u. Otherwise the log stays empty until the buffer is full. - Save a checkpoint when Slurm says stop. Slurm sends SIGTERM when you cancel a job or when the time is over.
train_tinygpt.pycatches it and saves, and--signal=TERM@60makes the signal come 60 seconds early. - Ask for what you need, not more. A job that asks for less time and fewer GPUs starts sooner.
- Download models on the login node first. Then set
HF_HUB_OFFLINE=1in the job, as exercise 6 does, so the job uses the copy in your workspace. - Sweeps are job arrays. One script, one line
--array=0-3, and$SLURM_ARRAY_TASK_IDpicks the setting. See exercise 5.
A separate workspace for another project
The setup script takes its settings from the environment. To keep a project apart from the lab, give it its own workspace. Jobs you send from the same shell use it too.
unset WS_DIR # forget the lab workspace in this shell
export WS_NAME=my-project
source ~/behind-llms-lab/hpc_lab/00_setup/setup_env.shThe course project is for the course. Jobs with --account=p_lv_llmsecrets are booked on the course. For your thesis or your own research, ask your supervisor which HPC project to use and put its name there.