Hyppää sisältöön

Docs CSC now features an automatic Finnish translation. Click here for more information.

Warning!

Puhti and Mahti are being decommissioned in stages, and their storage areas will become fully unavailable from 15 October 2026. Clean up unnecessary files and move any data you need to keep by 31 August 2026. See the Roihu data migration guide for instructions on transferring your data to Roihu.

Puhti computing services have been decommissioned and no new jobs are accepted or executed on its compute nodes. Puhti login nodes and storage services are planned to remain available until 15 October 2026.

Monen GPU:n ja monen solmun koneoppiminen

Tässä oppaassa kerrotaan, miten useita GPU:ita ja useita solmuja voidaan hyödyntää koneoppimissovelluksissa CSC:n supertietokoneilla. Se on osa koneoppimisen opas.

Ensin selitämme yleiset periaatteet, kuten yhden ja usean solmun 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, PyTorch Lightning DDP:n kanssa, Accelerate, DeepSpeed ja TensorFlow'n tf.distribute.Strategy.

Useita GPU:ita ja useita solmuja

Jokaisessa erillisessä GPU-solmussa (eli yksittäisessä klusterin tietokoneessa) on kiinteä määrä GPU:ita. Puhdissa, Mahdissa ja Roihussa on 4 GPU:ta solmua kohden, ja LUMIssa 8 GPU:ta solmua kohden. (Teknisesti LUMI-solmussa 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-solmuja. Katso lisätietoja oppaasta GPU-kiihdytetty koneoppiminen.

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

Jos haluat varata yhden solmun, jossa on N=1–4 GPU:ta Puhdissa, Mahdissa tai Roihussa tai 1–8 GPU:ta LUMIssa, tarvitset seuraavat valinnat (vaihda N todelliseksi GPU-määräksi):

#SBATCH --partition=gpumedium
#SBATCH --gres=gpu:gh200: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 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 solmun (8 GPU:ta).

Usean solmun töissä varataan aina kokonaisia solmuja, joten käytössäsi on 4 GPU:n monikerta (tai 8 LUMIssa). Esimerkiksi kahdella solmulla Roihussa käytössäsi on 2*4=8 GPU:ta.

#SBATCH --partition=gpularge
#SBATCH --gres=gpu:gh200:4
#SBATCH --nodes=2

Huomaa, että pääsy Roihun gpularge-osioon edellyttää skaalautuvuustestien lähettämistä.

#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ä valinta --gres (tai LUMIssa --gpus-per-node) määrittää aina GPU:iden määrän solmua kohden, myös usean solmun tapauksessa. Jos siis varaamme 8 GPU:ta kahdelle solmulle Roihussa, se tarkoittaa 4 GPU:ta jokaisessa solmussa, eli --gres=gpu:gh200:4.

Muiden kuin GPU-resurssien allokointi

Muut resurssit (CPU-ytimet ja CPU-muisti) tulee varata sen mukaan, mikä osuus solmun GPU:ista on varattu. Esimerkiksi jos varaat 1 GPU:n neljästä, muut resurssit tulisi varata (enintään) 1/4 solmun 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 allokoitua automaattisesti.

Roihussa jokainen GH200-GPU on itse asiassa superpiiri, joka sisältää GPU:n, CPU:n ja CPU-muistin yhdessä tiiviisti integroidussa yksikössä. Roihussa saat automaattisesti koko GH200-superpiirin muistin (95 GiB HBM3-muistia + 122 GiB LPDDR5-muistia = 217 GiB). CPU-ytimiä voit varata enintään 72 ydintä (superpiirin koko ARM-CPU:n).

LUMIssa käytä enintään 7 CPU-ydintä ja 60 Gt muistia varattua GPU:ta kohden.

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

Katso yhden GPU:n töiden ajon opas Slurm-esimerkeillä, joissa on oikeat CPU- ja muistivaraukset.

GPU-käytön seuranta

Huomaa

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

Voit seurata, että ohjelmasi käyttää kaikkia varattuja GPU:ita samoilla mekanismeilla, jotka on kuvattu GPU-kiihdytetyn koneoppimisen 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ä Roihussa (yksi solmu):

Mon Aug 17 16:01:05 2026       
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 595.71.05              Driver Version: 595.71.05      CUDA Version: 13.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  NVIDIA GH200 120GB             On  |   00000019:01:00.0 Off |                    0 |
| N/A   55C    P0            424W /  680W |    4911MiB /  97871MiB |     81%      Default |
|                                         |                        |             Disabled |
+-----------------------------------------+------------------------+----------------------+
|   1  NVIDIA GH200 120GB             On  |   00000029:01:00.0 Off |                    0 |
| N/A   56C    P0            426W /  680W |    4911MiB /  97871MiB |     86%      Default |
|                                         |                        |             Disabled |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|    0   N/A  N/A         1499602      C   .../wrappers/2.10-te/bin/python3       4902MiB |
|    1   N/A  N/A         1499603      C   .../wrappers/2.10-te/bin/python3       4902MiB |
+-----------------------------------------------------------------------------------------+

Tässä meillä on kaksi CPU-prosessia, joista kumpikin käyttää yhtä GPU:ta noin 80 %: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 pieniä, 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). Tässä esimerkissä muistin käyttö on melko pieni, noin 5 %.

Useiden prosessien käynnistäminen

Tyypillinen lähestymistapa monen GPU:n syväoppimisessa on käynnistää yksi CPU-ohjausprosessi jokaista GPU:ta kohden. Näiden prosessien käynnistämisestä voi huolehtia joko syväoppimiskehikko itse (kuten 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 solmun koneoppimiseen on olemassa monia kehikoita, yleensä tiiviisti sidoksissa käyttämääsi syväoppimiskehikkoon. Tässä käsittelemme lähes yksinomaan PyTorchiin perustuvia ratkaisuja.

Riippumatta siitä, minkä kehikon valitset, kiinnitä huomiota töiden käynnistämistapaan. Joissakin tapauksissa, kuten PyTorch DDP:ssä, on erityinen käynnistin, joka käynnistää yksittäiset työt, kun taas toiset, kuten DeepSpeed, voivat käyttää tähän MPI:tä. Joissakin kehikoissa, kuten PyTorch Lightningissa, käynnistysmekanismi voi myös vaihdella sen mukaan, ajatko yhden vai usean solmun työtä.

Kaikkien kehikoiden tulisi käyttää NCCL:ää Puhdissa, Mahdissa ja Roihussa (NVIDIA) tai RCCL:ää (AMD) LUMIssa 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 solmun PyTorch-töitä.

Jotta DDP:n käyttö CSC:n supertietokoneilla olisi helpompaa, olemme luoneet esimerkkikokoelman yksinkertaisten DDP-töiden ajamisesta klusterissa. Näissä esimerkeissä käytämme rendezvous -mekanismia solmujen välisen viestinnän muodostamiseen, emme MPI:tä.

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

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpumedium
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=288
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:gh200:4

module purge
module load python-pytorch

srun torchrun --standalone --nnodes=1 --nproc_per_node=4 myprog.py <options>
#!/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ä solmulla:

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpularge
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=288
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:gh200:4

module purge
module load python-pytorch

export RDZV_HOST=$(hostname)
export RDZV_PORT=29400

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>

Huomaa, että pääsy Roihun gpularge-osioon edellyttää skaalautuvuustestien lähettämistä.

#!/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

export RDZV_HOST=$(hostname)
export RDZV_PORT=29400

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

module purge
module load pytorch

export RDZV_HOST=$(hostname)
export RDZV_PORT=29400

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

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

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

export RDZV_HOST=$(hostname)
export RDZV_PORT=29400

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 yhden GPU:n PyTorch-skriptiä, sinun täytyy tehdä muutama vaihe:

  1. Alusta init_process_group()-funktiolla, esimerkiksi:

    import torch.distributed as dist
    
    dist.init_process_group(backend='nccl')
    
  2. Käytä oikeaa GPU:ta paikallisen rankin mukaan

    device_id = int(os.environ['LOCAL_RANK'])
    

    esimerkiksi siirtäessäsi myöhemmin dataa GPU:lle:

    x = x.to(device_id)
    
  3. Kääri mallisi DistributedDataParallel-luokalla:

    from torch.nn.parallel import DistributedDataParallel
    
    model = DistributedDataParallel(model, device_ids=[device_id])
    
  4. Käytä DistributedSampler-luokkaa DataLoader-oliollasi:

    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 Roihulle löytyy pytorch-ddp-examples- repositorystamme:

  • mnist_ddp.py näyttää Python-koodin yksinkertaisen CNN-mallin opettamiseen MNIST-datalla käyttäen PyTorch DDP:tä
  • run-ddp-gpu4.sh sisältää Slurm-skriptin opetuksen ajamiseen 4 GPU:lla yhdellä solmulla
  • run-ddp-gpu8.sh näyttää saman kahdelle täydelle solmulle, 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 solmun töiden ajaminen Lightningilla on varsin helppoa. Jos haluat muuntaa olemassa olevan PyTorch-skriptisi Lightningille, ohjaamme sinut viralliseen PyTorch Lightning -dokumentaatioon.

Suosittelemme käyttämään DistributedDataParallelia (DDP) monen GPU:n ja monen solmun 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ä solmua kohden) ja num_nodes-parametrille. Suosittelemme antamaan nämä komentorivin argumentteina:

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 Lightning -Slurm-skripti yhdelle solmulle käyttäen kaikkia GPU:ita:

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpumedium
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=4
#SBATCH --cpus-per-task=72
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:gh200:4

module purge
module load python-pytorch

srun python3 myprog.py --gpus=4 --nodes=1 <options>
#!/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 Lightning -Slurm-skripti kahdelle täydelle solmulle käyttäen kaikkia GPU:ita:

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpularge
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=4
#SBATCH --cpus-per-task=72
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:gh200:4

module purge
module load python-pytorch

srun python3 myprog.py --gpus=4 --nodes=2 <options>

Huomaa, että pääsy Roihun gpularge-osioon edellyttää skaalautuvuustestien lähettämistä.

#!/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>

Täysin toimivia esimerkkejä PyTorch Lightningin käytöstä yhdellä tai kahdella täydellä solmulla löytyy pytorch-ddp-examples- repositorystamme.

Accelerate

Hugging Facen Accelerate on suosittu kehikko suurten kielimallien opettamiseen, ja se tekee kehittyneempien opetusalgoritmien, kuten FSDP:n, käytöstä hyvin 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 Accelerate-asetustiedosto.

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

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

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpumedium
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=288
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:gh200:4

module purge
module load python-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=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ä solmulla (8 GPU:ta).

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpularge
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=288
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:gh200:4

module purge
module load python-pytorch

NUM_PROCS=$(expr ${SLURM_NNODES} \* ${SLURM_GPUS_ON_NODE})
MAIN_PROCESS_IP=$(hostname -i)

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

srun bash -c "$RUN_CMD"

Huomaa, että pääsy Roihun gpularge-osioon edellyttää skaalautuvuustestien lähettämistä.

#!/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ä muuttuja $SLURM_NODEID on escapettu, jotta se arvioidaan vasta sillä varsinaisella solmulla, jossa sitä ajetaan. Normaalisti kaikki muuttujat arvioidaan ensimmäisellä solmulla, mutta $SLURM_NODEID:n pitäisi olla eri jokaisella solmulla, 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 esimerkiksi 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

Täysin toimivia esimerkkejä Acceleraten käytöstä yhdellä tai kahdella täydellä solmulla löytyy pytorch-ddp-examples- repositorystamme.

Lisää esimerkkejä LLM-hienosäädön tekemisestä Acceleratella löytyy llm-fine-tuning-examples- repositorysta.

DeepSpeed

DeepSpeed on PyTorchin optimointiohjelmisto- kokonaisuus, joka auttaa skaalaamaan sekä opetusta että päättelyä suurille syväoppimismalleille.

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

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpumedium
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=288
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:gh200:4

module purge
module load python-pytorch

srun deepspeed myprog.py \
    --deepspeed --deepspeed_config my_ds_config.json \
    <further options>
#!/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ä solmulla käyttäen MPI:tä erillisen tehtävän käynnistämiseen jokaiselle GPU:lle:

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpularge
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=4
#SBATCH --cpus-per-task=72
#SBATCH --time=1:00:00
#SBATCH --gres=gpu:gh200:4

module purge
module load python-pytorch

srun python3 myprog.py \
    --deepspeed --deepspeed_config my_ds_config.json \
    <further options>

Huomaa, että pääsy Roihun gpularge-osioon edellyttää skaalautuvuustestien lähettämistä.

#!/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 yhden GPU:n 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 opetusluuppia 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 -guide saadaksesi täydet tiedot. Erityisesti sinun täytyy myös luoda DeepSpeed- asetustiedosto.

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

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

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