Hyppää sisältöön

Welcome to our weekly research support coffee hour on Zoom! Click here for more information.

Warning!

Puhti scratch disk is becoming very full (80+ % ) resulting in performance degradation. Everybody is advised to only keep actively processed data on scratch, all other data should be deleted, transferred to host institute or stored in Lumi-O. No new quota will be granted. Click here for a tool for examining your disk usage.

Monen GPU:n ja monen noodin koneoppiminen

Tässä oppaassa kerrotaan, miten voit hyödyntää useita GPU:ita ja useita noodeja koneoppimissovelluksissa CSC:n supertietokoneilla. Se on osa Koneoppimisopastamme.

Ensin selitämme yleiset periaatteet, kuten yhden ja usean noodin työt sekä mekanismit useiden prosessien käynnistämiseen. Sen jälkeen käsittelemme joitakin yleisiä ohjelmistokehikoita ja sitä, miten niitä käytetään CSC:n supertietokoneilla: PyTorch DDP, DeepSpeed sekä lyhyesti Horovod ja TensorFlow'n tf.distribute.Strategy.

Useita GPU:ita ja useita noodeja

Jokaisessa erillisessä GPU-noodissa (eli yksittäisessä klusterin tietokoneessa) on kiinteä määrä GPU:ita. Puhdissa, Mahdissa ja Roihussa on 4 GPU:ta per noodi, ja LUMIssa 8 GPU:ta per noodi. (Teknisesti LUMI-noodissa on 4 kaksisiruisen GPU:n korttia, mutta ohjelmiston näkökulmasta tämä näyttää samalta kuin 8 GPU:ta.) Koko supertietokoneessa voi olla kymmeniä tai jopa tuhansia GPU-noodeja. Katso lisätietoja kohdasta GPU-kiihdytetty koneoppiminen.

Jos tarvitset 1–4 GPU:ta (tai 1–8 LUMIssa), sinun tulee aina varata yhden noodin työ. Jos tarvitset enemmän kuin 4 GPU:ta (tai 8 LUMIssa), sinun täytyy varata usean noodin työ. Vaikka on teknisesti mahdollista varata esimerkiksi kaksi GPU:ta yhdestä noodista ja kaksi toisesta, tätä ei suositella muuten kuin testaustarkoituksiin, koska noodien välinen tiedonsiirto on aina hitaampaa kuin yhden noodin sisällä.

Varataksesi yhden noodin, jossa on N=1–4 GPU:ta Puhdissa tai Mahdissa tai 1–8 GPU:ta LUMIssa, tarvitset seuraavat valinnat (vaihda N todelliseen GPU-määrään):

#SBATCH --partition=gpu
#SBATCH --gres=gpu:v100:N
#SBATCH --partition=gpusmall 
#SBATCH --gres=gpu:a100:N

Huomaa: Mahdissa käytä gpusmall-osiota 1 tai 2 GPU:lle, gpumedium-osiota 3 tai 4 GPU:lle.

#SBATCH --partition=small-g
#SBATCH --gpus-per-node=N

Huomaa: LUMIssa voit käyttää standard-g-osiota, jos pyydät koko noodia (8 GPU:ta).

Usean noodin töissä varaat aina kokonaisia noodeja, joten käytössäsi on 4 GPU:n (tai LUMIssa 8 GPU:n) monikerta. Esimerkiksi kahdella noodilla Mahdissa käytössäsi on 2*4=8 GPU:ta.

#SBATCH --partition=gpu
#SBATCH --gres=gpu:v100:4
#SBATCH --nodes=2
#SBATCH --partition=gpumedium
#SBATCH --gres=gpu:a100:4
#SBATCH --nodes=2
#SBATCH --partition=standard-g
#SBATCH --gpus-per-node=8
#SBATCH --nodes=2

Huomaa, että --gres-valinta (tai LUMIssa --gpus-per-node) määrittää aina GPU:iden määrän per noodi, myös usean noodin tapauksessa. Jos siis varaamme 8 GPU:ta kahdelle noodille Puhdissa, se tarkoittaa 4 GPU:ta kummallakin noodilla eli --gres=gpu:v100:4.

Muiden kuin GPU-resurssien varaaminen

Muut resurssit (CPU-ytimet ja CPU-muisti) tulee varata sen mukaan, kuinka suuri osuus noodin GPU:ista on varattu. Jos esimerkiksi varaat 1 GPU:n 4:stä, muut resurssit tulee varata (enintään) 1/4:aan noodin kokonaisresursseista.

Puhdissa tämä tarkoittaa 10 CPU-ydintä ja noin 95 Gt muistia (muistin osalta pyöristämme hieman alaspäin, koska yksiköt eivät ole aivan tarkkoja). Mahdissa enimmäismäärä on 32 CPU-ydintä, ja muisti pitäisi varautua automaattisesti.

LUMIssa käytä enintään 7 CPU-ydintä ja 60 Gt muistia per varattu GPU.

Huomaa, että GPU-muistin määrä on kiinteä GPU:iden lukumäärän mukaan; sitä ei voi varata enempää (tai vähempää).

GPU-käytön seuranta

Huomaa

Varmista, että koodisi todella osaa hyödyntää useita GPU:ita, sillä tämä vaatii yleensä joitakin muutoksia ohjelmaan. Pelkkä useamman GPU:n varaaminen ei riitä!

Voit seurata, että ohjelmasi käyttää kaikkia varattuja GPU:ita samoilla mekanismeilla, jotka on kuvattu GPU-kiihdytettyä koneoppimista käsittelevässä oppaassamme. Ainoa ero on, että nyt sinun pitäisi nähdä tilastoja useammasta kuin yhdestä GPU:sta.

Esimerkkituloste nvidia-smi:llä 2 GPU:n työstä Puhdissa (yksi noodi):

Tue Mar 17 13:36:42 2026       
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.288.01             Driver Version: 535.288.01   CUDA Version: 12.2     |
|-----------------------------------------+----------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |         Memory-Usage | GPU-Util  Compute M. |
|                                         |                      |               MIG M. |
|=========================================+======================+======================|
|   0  Tesla V100-SXM2-32GB           On  | 00000000:61:00.0 Off |                    0 |
| N/A   44C    P0             259W / 300W |   3973MiB / 32768MiB |     97%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+
|   1  Tesla V100-SXM2-32GB           On  | 00000000:62:00.0 Off |                    0 |
| N/A   43C    P0             257W / 300W |   3973MiB / 32768MiB |     98%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+

+---------------------------------------------------------------------------------------+
| Processes:                                                                            |
|  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
|        ID   ID                                                             Usage      |
|=======================================================================================|
|    0   N/A  N/A   2047858      C   ...oft/ai/wrap/pytorch-2.9/bin/python3     3968MiB |
|    1   N/A  N/A   2047859      C   ...oft/ai/wrap/pytorch-2.9/bin/python3     3968MiB |
+---------------------------------------------------------------------------------------+

Tässä meillä on kaksi CPU-prosessia, joista kumpikin käyttää yhtä GPU:ta lähes 100 %:n käyttöasteella (GPU-Util-sarake). Jos jommankumman GPU:n kohdalla näkyy sen sijaan 0 %, sitä ei käytetä lainkaan. Jos GPU:iden prosentit ovat melko matalia, se voi tarkoittaa, ettet tarvitse useita GPU:ita ainakaan laskentatehon vuoksi. Suurissa kielimalleissa niitä voidaan kuitenkin tarvita GPU-muistin vuoksi, joten tarkista myös GPU-muistin käyttö (Memory-Usage-sarake).

Useiden prosessien käynnistäminen

Tyypillinen lähestymistapa syväoppimisen monen GPU:n käsittelyssä on käynnistää yksi CPU-ohjausprosessi jokaista GPU:ta kohti. Näiden prosessien käynnistämisestä voi huolehtia joko syväoppimiskehikko itse (esimerkiksi PyTorchin torchrun) tai käyttämällä Slurmin MPI-toiminnallisuutta useiden MPI-tehtävien käynnistämiseen.

Saatavilla olevat kehikot

Monen GPU:n ja monen noodin koneoppimiseen on olemassa monia kehikoita. Jotkin kehikot ovat tiiviisti sidoksissa tiettyyn kehikkoon, kuten PyTorchin DistributedDataParallel (DDP), DeepSpeed tai TensorFlow'n tf.distribute.Strategy, kun taas toiset ovat yleisempiä, kuten Horovod.

Riippumatta siitä, minkä kehikon valitset, kiinnitä huomiota töiden käynnistämistapaan. Esimerkiksi Horovodin kanssa on tavallista käyttää MPI:tä, kun taas DeepSpeed voidaan määrittää käyttämään MPI:tä tai sen omaa rinnakkaista käynnistintä. Joissakin kehikoissa käynnistysmekanismi voi myös vaihdella sen mukaan, ajatko yhden vai usean noodin työtä.

Kaikkien kehikoiden tulisi käyttää NCCL:ää (NVIDIA) tai RCCL:ää (AMD) nopeaan GPU:iden väliseen tiedonsiirtoon, vaikka yhteyksien muodostamiseen käytettäisiinkin MPI:tä.

PyTorch DDP

PyTorch distributed, ja erityisesti DistributedDataParallel (DDP), tarjoaa hyvän tavan ajaa monen GPU:n ja monen noodin PyTorch-töitä.

Jotta DDP:n käyttö CSC:n supertietokoneilla olisi helpompaa, olemme luoneet joukon esimerkkejä siitä, miten yksinkertaisia DDP-töitä ajetaan klusterissa. Esimerkeissä käytämme rendezvous -mekanismia noodien välisen viestinnän muodostamiseen, emme MPI:tä.

Esimerkki Slurm-erätyöstä PyTorch DDP:n ajamiseen yhdellä täydellä noodilla:

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpu
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=40
#SBATCH --mem=320G
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:v100:4

module purge
module load pytorch

srun torchrun --standalone --nnodes=1 --nproc_per_node=4 myprog.py <options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpumedium
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=128
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:a100:4

module purge
module load pytorch

srun torchrun --standalone --nnodes=1 --nproc_per_node=4 myprog.py <options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small-g
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=56
#SBATCH --gpus-per-node=8
#SBATCH --mem=480G
#SBATCH --time=1:00:00

module purge
module use /appl/local/laifs/modules
module load lumi-aif-singularity-bindings

export SIF=/appl/local/laifs/containers/lumi-multitorch-latest.sif

srun singularity run $SIF \
  torchrun --standalone --nnodes=1 --nproc_per_node=$SLURM_GPUS_PER_NODE myprog.py <options>

Esimerkki PyTorch DDP:n ajamisesta kahdella täydellä noodilla:

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpu
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=40
#SBATCH --mem=320G
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:v100:4

export RDZV_HOST=$(hostname)
export RDZV_PORT=29400

module purge
module load pytorch

srun torchrun \
    --nnodes=$SLURM_JOB_NUM_NODES \
    --nproc_per_node=4 \
    --rdzv_id=$SLURM_JOB_ID \
    --rdzv_backend=c10d \
    --rdzv_endpoint="$RDZV_HOST:$RDZV_PORT" \
    myprog.py <options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpumedium
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=128
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:a100:4

export RDZV_HOST=$(hostname)
export RDZV_PORT=29400

module purge
module load pytorch

srun torchrun \
    --nnodes=$SLURM_JOB_NUM_NODES \
    --nproc_per_node=4 \
    --rdzv_id=$SLURM_JOB_ID \
    --rdzv_backend=c10d \
    --rdzv_endpoint="$RDZV_HOST:$RDZV_PORT" \
    myprog.py <options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small-g
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=56
#SBATCH --gpus-per-node=8
#SBATCH --mem=480G
#SBATCH --time=1:00:00

export RDZV_HOST=$(hostname)
export RDZV_PORT=29400

module purge
module use /appl/local/laifs/modules
module load lumi-aif-singularity-bindings

export SIF=/appl/local/laifs/containers/lumi-multitorch-latest.sif

srun singularity run $SIF torchrun \
    --nnodes=$SLURM_JOB_NUM_NODES \
    --nproc_per_node=$SLURM_GPUS_PER_NODE \
    --rdzv_id=$SLURM_JOB_ID \
    --rdzv_backend=c10d \
    --rdzv_endpoint="$RDZV_HOST:$RDZV_PORT" \
    myprog.py <options>

LUMI-esimerkeissä käytetään LUMI AI Factoryn PyTorch- asennusta.

Jos olet muuntamassa vanhaa PyTorch-skriptiä, sinun täytyy tehdä muutama vaihe:

  1. Alusta init_process_group()-kutsulla, esimerkiksi:

    import torch.distributed as dist
    
    dist.init_process_group(backend='nccl')
    
    local_rank = int(os.environ['LOCAL_RANK'])
    torch.cuda.set_device(local_rank)
    
  2. Kääri mallisi DistributedDataParallel-olioon:

    from torch.nn.parallel import DistributedDataParallel
    
    model = DistributedDataParallel(model, device_ids=[local_rank])
    
  3. Käytä DistributedSampler-luokkaa DataLoader-oliossasi:

    from torch.utils.data.distributed import DistributedSampler
    
    train_sampler = DistributedSampler(train_dataset)
    train_loader = DataLoader(dataset=train_dataset, sampler=train_sampler, ...)
    

Täysin toimiva esimerkki Puhdille löytyy pytorch-ddp-examples- repositoriostamme:

  • mnist_ddp.py näyttää Python-koodin yksinkertaisen CNN-mallin opettamiseen MNIST-datalla PyTorch DDP:tä käyttäen
  • run-ddp-gpu4.sh sisältää Slurm-skriptin opetuksen ajamiseen 4 GPU:lla yhdellä noodilla
  • run-ddp-gpu8.sh näyttää saman kahdelle täydelle noodille, yhteensä 8 GPU:lla

PyTorch Lightning DDP:n kanssa

PyTorch Lightning on suosittu korkeamman tason kehikko, joka on suunniteltu helpottamaan PyTorchin käyttöä. Monen GPU:n ja monen noodin töiden ajaminen Lightningilla on varsin helppoa. Jos haluat muuntaa olemassa olevan PyTorch-skriptisi Lightningille, ohjaamme sinut viralliseen PyTorch Lightningin dokumentaatioon.

Suosittelemme käyttämään DistributedDataParallelia (DDP) monen GPU:n ja monen noodin käyttöön. Sinun tarvitsee vain lisätä nämä valinnat Lightningin Traineriin:

trainer = pl.Trainer(devices=args.gpus,
                     num_nodes=args.nodes,
                     accelerator='gpu',
                     strategy='ddp',
                     ...)

Sinun täytyy antaa sopivat arvot devices-parametrille (GPU:iden määrä per noodi) ja num_nodes-parametrille. Suosittelemme antamaan nämä komentoriviargumentteina:

def main():
    parser = argparse.ArgumentParser()

    parser.add_argument('--gpus', default=1, type=int,
                        help='number of GPUs per node')
    parser.add_argument('--nodes', default=1, type=int,
                        help='number of nodes')
    # any other command line arguments here
    args = parser.parse_args()

PyTorch Lightningin Slurm-skripti yhdelle noodille käyttäen kaikkia GPU:ita:

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpu
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=4
#SBATCH --cpus-per-task=10
#SBATCH --mem=320G
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:v100:4

module purge
module load pytorch

srun python3 myprog.py --gpus=4 --nodes=1 <options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpumedium
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=4
#SBATCH --cpus-per-task=32
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:a100:4

module purge
module load pytorch

srun python3 myprog.py --gpus=4 --nodes=1 <options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small-g
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=8
#SBATCH --cpus-per-task=7
#SBATCH --gpus-per-node=8
#SBATCH --mem=480G
#SBATCH --time=1:00:00

module purge
module use /appl/local/laifs/modules
module load lumi-aif-singularity-bindings

export SIF=/appl/local/laifs/containers/lumi-multitorch-latest.sif

srun singularity run $SIF \
  python3 myprog.py --gpus=8 --nodes=1 <options>


PyTorch Lightningin Slurm-skripti kahdelle täydelle noodille käyttäen kaikkia GPU:ita:

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpu
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=4
#SBATCH --cpus-per-task=10
#SBATCH --mem=320G
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:v100:4

module purge
module load pytorch

srun python3 myprog.py --gpus=4 --nodes=2 <options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpumedium
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=4
#SBATCH --cpus-per-task=32
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:a100:4

module purge
module load pytorch

srun python3 myprog.py --gpus=4 --nodes=2 <options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small-g
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=8
#SBATCH --cpus-per-task=7
#SBATCH --gpus-per-node=8
#SBATCH --mem=480G
#SBATCH --time=1:00:00

module purge
module use /appl/local/laifs/modules
module load lumi-aif-singularity-bindings

export SIF=/appl/local/laifs/containers/lumi-multitorch-latest.sif

srun singularity run $SIF \
  python3 myprog.py --gpus=8 --nodes=2 <options>

Accelerate

Hugging Facen Accelerate on suosittu kehikko suurten kielimallien opettamiseen, ja se tekee edistyneempien opetusalgoritmien, kuten FSDP:n, käytöstä erittäin helppoa. Työn käynnistäminen Acceleratella on samanlaista kuin PyTorch DDP:llä, paitsi että meidän täytyy käyttää Acceleraten käynnistintä ja lisäksi antaa Acceleraten asetustiedosto.

Toimiva esimerkki LLM-hienosäädöstä löytyy tästä GitHub- repositoriosta (tarkista tiedostot, joiden nimi päättyy -accelerate.sh). Katso myös oppaamme LLM:ien käytöstä supertietokoneilla.

Esimerkki Acceleraten käytöstä yhden noodin kaikilla GPU:illa:

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpu
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=40
#SBATCH --mem=320G
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:v100:4

module purge
module load pytorch

srun accelerate launch \
 --config_file=accelerate_config.yaml \
 --num_processes=4 \
 --num_machines=1 \
 --machine_rank=0 \
 myprog.py <options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpumedium
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=128
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:a100:4

module purge
module load pytorch

srun accelerate launch \
 --config_file=accelerate_config.yaml \
 --num_processes=4 \
 --num_machines=1 \
 --machine_rank=0 \
 myprog.py <options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small-g
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=56
#SBATCH --mem=480G
#SBATCH --time=1:00:00
#SBATCH --gpus-per-node=8

module purge
module use /appl/local/laifs/modules
module load lumi-aif-singularity-bindings

export SIF=/appl/local/laifs/containers/lumi-multitorch-latest.sif

srun singularity run $SIF accelerate launch \
 --config_file=accelerate_config.yaml \
 --num_processes=8 \
 --num_machines=1 \
 --machine_rank=0 \
 myprog.py <options>

Esimerkki Acceleraten ajamisesta kahdella täydellä noodilla (8 GPU:ta).

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpu
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=40
#SBATCH --mem=320G
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:v100:4

module purge
module load pytorch

GPUS_PER_NODE=4
NUM_PROCESSES=$(expr $SLURM_NNODES \* $GPUS_PER_NODE)
MAIN_PROCESS_IP=$(hostname -i)

RUN_CMD="accelerate launch \
                    --config_file=accelerate_config.yaml \
                    --num_processes=$NUM_PROCESSES \
                    --num_machines=$SLURM_NNODES \
                    --machine_rank=\$SLURM_NODEID \
                    --main_process_ip=$MAIN_PROCESS_IP \
                    myprog.py <options>"

srun bash -c "$RUN_CMD"
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpumedium
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=128
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:a100:4

module purge
module load pytorch

GPUS_PER_NODE=4
NUM_PROCESSES=$(expr $SLURM_NNODES \* $GPUS_PER_NODE)
MAIN_PROCESS_IP=$(hostname -i)

RUN_CMD="accelerate launch \
                    --config_file=accelerate_config.yaml \
                    --num_processes=$NUM_PROCESSES \
                    --num_machines=$SLURM_NNODES \
                    --machine_rank=\$SLURM_NODEID \
                    --main_process_ip=$MAIN_PROCESS_IP \
                    myprog.py <options>"

srun bash -c "$RUN_CMD"
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small-g
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=56
#SBATCH --gpus-per-node=8
#SBATCH --mem=480G
#SBATCH --time=1:00:00

module purge
module use /appl/local/laifs/modules
module load lumi-aif-singularity-bindings

export SIF=/appl/local/laifs/containers/lumi-multitorch-latest.sif

NUM_PROCESSES=$(expr $SLURM_NNODES \* $SLURM_GPUS_PER_NODE)
MAIN_PROCESS_IP=$(hostname -i)

RUN_CMD="accelerate launch \
                    --config_file=accelerate_config.yaml \
                    --num_processes=$NUM_PROCESSES \
                    --num_machines=$SLURM_NNODES \
                    --machine_rank=\$SLURM_NODEID \
                    --main_process_ip=$MAIN_PROCESS_IP \
                    myprog.py <options>"

srun singularity run $SIF bash -c "$RUN_CMD"

Huomaa hieman kömpelö tapa määritellä komento niin, että $SLURM_NODEID-muuttuja on escapettu, jotta se evaluoidaan vasta sillä varsinaisella noodilla, jossa sitä ajetaan. Normaalisti kaikki muuttujat evaluoidaan ensimmäisellä noodilla, mutta $SLURM_NODEID:n pitäisi olla eri jokaisella noodilla, jotta hajautettu asetus toimii oikein.

Molemmat esimerkit käyttävät tätä accelerate_config.yaml-tiedostoa:

compute_environment: LOCAL_MACHINE
debug: false
distributed_type: MULTI_GPU
downcast_bf16: 'no'
gpu_ids: all
main_training_function: main
main_process_port: 29500
mixed_precision: bf16
num_processes: 1
rdzv_backend: static
same_network: true
tpu_env: []
tpu_use_cluster: false
tpu_use_sudo: false
use_cpu: false

Jos haluat käyttää FSDP:tä, käytä yksinkertaisesti tämän kaltaista Accelerate-asetusta:

compute_environment: LOCAL_MACHINE
debug: false
distributed_type: FSDP
downcast_bf16: 'no'
fsdp_config:
  fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP
  fsdp_backward_prefetch_policy: BACKWARD_PRE
  fsdp_forward_prefetch: false
  fsdp_cpu_ram_efficient_loading: true
  fsdp_offload_params: false
  fsdp_sharding_strategy: FULL_SHARD
  fsdp_state_dict_type: SHARDED_STATE_DICT
  fsdp_sync_module_states: true
  fsdp_use_orig_params: true
gpu_ids: all
main_training_function: main
main_process_port: 29500
mixed_precision: bf16
num_processes: 1
rdzv_backend: static
same_network: true
tpu_env: []
tpu_use_cluster: false
tpu_use_sudo: false
use_cpu: false

Katso lisää esimerkkejä GitHub-repositoriostamme.

DeepSpeed

DeepSpeed on PyTorchille tarkoitettu optimointiohjelmistopaketti, joka auttaa skaalaamaan sekä opetusta että päättelyä suurille syväoppimismalleille.

Esimerkki DeepSpeedin ajamisesta yhdellä täydellä noodilla käyttäen deepspeed-käynnistintä:

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpu
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=40
#SBATCH --mem=320G
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:v100:4

module purge
module load pytorch

srun apptainer_wrapper exec deepspeed myprog.py \
    --deepspeed --deepspeed_config my_ds_config.json \
    <further options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpumedium
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=128
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:a100:4

module purge
module load pytorch

srun apptainer_wrapper exec deepspeed myprog.py \
    --deepspeed --deepspeed_config my_ds_config.json \
    <further options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small-g
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=56
#SBATCH --gpus-per-node=8
#SBATCH --mem=480G
#SBATCH --time=1:00:00

module purge
module use /appl/local/laifs/modules
module load lumi-aif-singularity-bindings

export SIF=/appl/local/laifs/containers/lumi-multitorch-latest.sif

srun singularity run $SIF \
  deepspeed myprog.py \
    --deepspeed --deepspeed_config my_ds_config.json \
    <further options>


Esimerkki DeepSpeedin ajamisesta kahdella täydellä noodilla käyttäen MPI:tä erillisen tehtävän käynnistämiseen jokaiselle GPU:lle:

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpu
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=4
#SBATCH --cpus-per-task=10
#SBATCH --mem=320G
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:v100:4

module purge
module load pytorch

srun python3 myprog.py \
    --deepspeed --deepspeed_config my_ds_config.json \
    <further options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpumedium
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=4
#SBATCH --cpus-per-task=32
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:a100:4

module purge
module load pytorch

srun python3 myprog.py \
    --deepspeed --deepspeed_config my_ds_config.json \
    <further options>
#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small-g
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=8
#SBATCH --cpus-per-task=7
#SBATCH --gpus-per-node=8
#SBATCH --mem=480G
#SBATCH --time=1:00:00

module purge
module use /appl/local/laifs/modules
module load lumi-aif-singularity-bindings

export SIF=/appl/local/laifs/containers/lumi-multitorch-latest.sif

srun singularity run $SIF python3 myprog.py \
    --deepspeed --deepspeed_config my_ds_config.json \
    <further options>

Jos olet muuntamassa vanhaa PyTorch-skriptiä, sinun täytyy tehdä muutama vaihe:

  1. Varmista, että se käsittelee DeepSpeedin komentoriviargumentit, esimerkiksi:

    import argparse
    
    parser = argparse.ArgumentParser()
    # handle any own command line arguments here
    parser = deepspeed.add_config_arguments(parser)
    
    args = parser.parse_args()
    
  2. Alusta hajautettu ympäristö, esimerkiksi:

    import deepspeed
    
    deepspeed.init_distributed()
    
  3. Alusta DeepSpeed-moottori:

    model = # defined in normal way
    train_dataset = # defined normally
    
    model_engine, optimizer, train_loader, __ = deepspeed.initialize(
        args=args, model=model, model_parameters=model.parameters(),
        training_data=train_dataset)
    
  4. Muokkaa opetuslenkkiä käyttämään DeepSpeed-moottoria:

    for batch in train_loader:
        data = batch[0].to(model_engine.local_rank)
        labels = batch[1].to(model_engine.local_rank)
    
        outputs = model_engine(data)
        loss = criterion(outputs, labels)
    
        model_engine.backward(loss)
        model_engine.step()
    

Katso DeepSpeedin Getting started -opas täydet tiedot. Erityisesti sinun täytyy myös luoda DeepSpeedin asetustiedosto.

Täysin toimiva esimerkki löytyy pytorch-ddp-examples- repositoriostamme:

  • mnist_deepspeed.py näyttää Python-koodin yksinkertaisen CNN-mallin opettamiseen MNIST-datalla PyTorch DeepSpeediä käyttäen
  • run-deepspeed-gpu4.sh sisältää Slurm-skriptin opetuksen ajamiseen 4 GPU:lla yhdellä noodilla
  • run-deepspeed-gpu8.sh näyttää saman kahdelle täydelle noodille, yhteensä 8 GPU:lla
  • ds_config.json näyttää tässä esimerkissä käytetyn DeepSpeed-asetustiedoston

Horovod

Horovod on yleiskäyttöinen kirjasto, joka tukee muun muassa PyTorchia ja TensorFlow'ta. Horovodin kanssa sinun tulee käyttää MPI:tä töiden käynnistämiseen. Horovodia voidaan käyttää sekä yhden että usean noodin töissä.

CSC:n supertietokoneilla Horovodia tuetaan vain joidenkin tiettyjen TensorFlow'n ja PyTorchin versioiden kanssa. Tarkista lisätiedot sovellussivuilta. Ottaaksesi Horovodin käyttöön lataa vain sopiva moduuli ja muokkaa ohjelmaasi Horovodin dokumentaation ohjeiden mukaan, esimerkiksi:

TensorFlow'n tf.distribute.Strategy

TensorFlow'lla on myös omat sisäänrakennetut mekanisminsa hajautettuun opetukseen tf.distribute.Strategy- API:ssa.

Suomenkielinen tekoälykäännös

Sisällössä voi esiintyä virheellistä tietoa tekoälykäännöksestä johtuen.

Klikkaa tästä antaaksesi palautetta