Machine Learning tutorial
This page is a beginner's manual concerning how to port a machine learning job to a Compute Canada cluster.
Step 1: Archiving a data set
The filesystems on Compute Canada clusters are designed for a small number of extremely large files. Make sure that the data set which you need for your training is an archive format like tar, which you can then transfer to your job's compute node when the job starts. If you do not respect these rules, you risk causing enormous numbers of I/O operations on the shared filesystem, leading to performance issues on the cluster for all of its users. If you want to learn more about how to handle collections of large number of files, we recommend that you spend some time reading Handling_large_collections_of_files this page.
Assuming that the files which you need are in the directory mydataset:
$ tar cf mydataset.tar mydataset/*
The above command does not compress the data. If you believe that this is appropriate, you can use tar czf.
Étape 2: Préparation de l'environnement virtuel
Nous vous recommandons d'essayer votre tâche dans une tâche interactive avant de la soumettre avec un script (section suivante). Vous pourrez ainsi diagnostiquer plus rapidement les problèmes. Voici un exemple de la commande pour soumettre une tâche interactive:
$ salloc --account=def-someuser --gres=gpu:1 --cpus-per-task=6 --mem=32000M --time=1:00
Une fois dans la tâche:
- Créez et activez un environnement virtuel dans $SLURM_TMPDIR (cette variable pointe vers un dossier local, c'est-à-dire sur le nœud de calcul). N'utilisez pas Anaconda. Par exemple:
$ virtualenv --no-download $SLURM_TMPDIR/env
- Installez les paquets dont vous avez besoin. Pour TensorFlow, installez le paquet tensorflow_gpu; il s'agit d'une version optimisée pour nos systèmes.
- Tentez d'exécuter votre programme
- Installez les paquets manquants s'il y a lieu
- Créez un fichier requirements.txt afin de pouvoir recréer l'environnement virtuel:
(env) $ pip freeze > ~/requirements.txt
Maintenant est un bon moment pour vérifier que votre tâche lit et écrit le plus possible sur le nœud de calcul ($SLURM_TMPDIR), et le moins possible sur les systèmes de fichiers partagés (home, scratch, project).
Étape 3: Préparation du script de soumission
Vous devez soumettre vos tâches à l'aide de scripts sbatch, afin qu'elles puissent être entièrement automatisées. Les tâches interactives servent uniquement à préparer et à déboguer des tâches.
Éléments importants d'un script sbatch
- Compte sur lequel les ressources seront "facturées"
- Ressources demandées:
- Nombre de CPU, suggestion: 6
- Nombre de GPU, suggestion: 1 (Utilisez un (1) seul GPU, à moins d'être certain que votre programme en utilise plusieurs. Par défaut, TensorFlow et PyTorch utilisent un seul GPU.)
- Quantité de mémoire, suggestion: 32000M
- Durée (Maximum Béluga: 7 jours, Graham et Cedar: 28 jours)
- Commandes bash:
- Préparation de l'environnement (modules, virtualenv)
- Transfert des données vers le noeud de calcul
- Lancement de l'exécutable
Exemple de script
#!/bin/bash
#SBATCH --gres=gpu:1 # Request GPU "generic resources"
#SBATCH --cpus-per-task=6 # Cores proportional to GPUs: 6 on Cedar, 16 on Graham.
#SBATCH --mem=32000M # Memory proportional to GPUs: 32000 Cedar, 64000 Graham.
#SBATCH --time=0-03:00 # DD-HH:MM:SS
#SBATCH --output=%N-%j.out
module load python/3.6 cuda cudnn
SOURCEDIR=~/ml-test
# Prepare virtualenv
virtualenv --no-download $SLURM_TMPDIR/env
source $SLURM_TMPDIR/env/bin/activate
pip install --no-index -r $SOURCEDIR/requirements.txt
# Prepare data
mkdir $SLURM_TMPDIR/data
tar xf ~/projects/def-xxxx/data.tar $SLURM_TMPDIR/data
# Start training
python $SOURCEDIR/train.py $SLURM_TMPDIR/data
Morcellement d'une longue tâche
Nous vous recommandons de morceler vos tâches en blocs de 24 heures. Demander des tâches plus courtes améliore votre priorité. En créant une chaîne de tâches, il est possible de dépasser la limite de 7 jours sur Béluga.
- Modifiez votre script de soumission (ou votre programme) afin que votre tâche puisse être interrompue et continuée. Votre programme doit pouvoir accéder au checkpoint le plus récent. (Voir l'exemple de script ci-dessous.)
- Vérifiez combien d'epochs (ou d'itérations) peuvent être effectuées à l'intérieur de 24 heures.
- Calculez combien de blocs de 24 heures vous aurez besoin: n_blocs = n_epochs_total / n_epochs_par_24h
- Utilisez l'argument --array 1-<n_blocs>%1 pour demander une chaine de n_blocs tâches.
Le script de soumission ressemblera à ceci:
#!/bin/bash
#SBATCH --array=1-10%1 # 10 is the number of jobs in the chain
#SBATCH ...
module load python/3.6 cuda cudnn
# Prepare virtualenv
...
# Prepare data
...
# Get most recent checkpoint (this example is for PyTorch *.pth checkpoint files)
export CHECKPOINTS=~/scratch/checkpoints/ml-test
LAST_CHECKPOINT=$(find . -maxdepth 1 -name "$CHECKPOINTS/*.pth" -print0 | xargs -r -0 ls -1 -t | head -1)
# Start training
if [ -n "$LAST_CHECKPOINT" ]; then
# $LAST_CHECKPOINT is null; start from scratch
python $SOURCEDIR/train.py --write-checkpoints-to $CHECKPOINTS ...
else
python $SOURCEDIR/train.py --load-checkpoint $CHECKPOINTS/$LAST_CHECKPOINT --write-checkpoints-to $CHECKPOINTS ...
fi