Rumah > Peranti teknologi > AI > Latihan selari PyTorch Contoh kod lengkap DistributedDataParallel

Latihan selari PyTorch Contoh kod lengkap DistributedDataParallel

WBOY
Lepaskan: 2023-04-10 20:51:01
ke hadapan
1326 orang telah melayarinya

Masalah melatih rangkaian neural dalam yang besar (DNN) menggunakan set data yang besar merupakan cabaran utama dalam bidang pembelajaran mendalam. Apabila saiz DNN dan set data meningkat, begitu juga keperluan pengiraan dan memori untuk melatih model ini. Ini menjadikannya sukar atau bahkan mustahil untuk melatih model ini pada satu mesin dengan sumber pengkomputeran yang terhad. Beberapa cabaran utama melatih DNN besar menggunakan set data yang besar termasuk:

  • Masa latihan yang panjang: Proses latihan boleh mengambil masa berminggu-minggu atau bahkan berbulan-bulan untuk disiapkan, bergantung pada kerumitan model dan saiz set data tersebut.
  • Had memori: DNN yang besar mungkin memerlukan sejumlah besar memori untuk menyimpan semua parameter model, kecerunan dan pengaktifan perantaraan semasa latihan. Ini boleh menyebabkan ralat kehabisan memori dan mengehadkan saiz model yang boleh dilatih pada satu mesin.

Untuk menangani cabaran ini, pelbagai teknik telah dibangunkan untuk meningkatkan latihan DNN besar dengan set data yang besar, termasuk keselarian model, keselarian data dan keselarian hibrid, serta perkakasan, perisian dan Pengoptimuman algoritma.

Dalam artikel ini kami akan menunjukkan keselarian data dan keselarian model menggunakan PyTorch.

Latihan selari PyTorch Contoh kod lengkap DistributedDataParallel

Apa yang kami panggil selari secara amnya merujuk kepada melatih rangkaian saraf dalam (dnn) pada berbilang GPU atau berbilang mesin untuk mencapai Kurang masa latihan. Idea asas di sebalik keselarian data adalah untuk membahagikan data latihan kepada bahagian yang lebih kecil dan membiarkan setiap GPU atau mesin memproses sebahagian data yang berasingan. Keputusan untuk setiap nod kemudiannya digabungkan dan digunakan untuk mengemas kini parameter model. Dalam keselarian data, seni bina model adalah sama pada setiap nod, tetapi parameter model dipisahkan antara nod. Setiap nod melatih model setempatnya sendiri menggunakan ketulan data yang diperuntukkan, dan pada penghujung setiap lelaran latihan, parameter model disegerakkan merentas semua nod. Proses ini diulang sehingga model menumpu kepada hasil yang memuaskan.

Di bawah kami menggunakan set data ResNet50 dan CIFAR10 untuk contoh kod lengkap:

Dalam keselarian data, seni bina model kekal sama pada setiap nod, tetapi parameter model adalah berbeza antara nod. Pembahagian dilakukan, dan setiap nod melatih model setempatnya sendiri menggunakan ketulan data yang diperuntukkan.

Pustaka DistributedDataParallel PyTorch boleh berkomunikasi dan menyegerakkan kecerunan dan parameter model dengan cekap merentas nod untuk mencapai latihan teragih. Artikel ini memberikan contoh cara untuk melaksanakan keselarian data dengan PyTorch menggunakan set data ResNet50 dan CIFAR10, di mana kod dijalankan pada berbilang GPU atau mesin, dengan setiap mesin memproses subset data latihan. Proses latihan diselaraskan menggunakan perpustakaan DistributedDataParallel PyTorch.

Import perpustakaan yang diperlukan

import os
 from datetime import datetime
 from time import time
 import argparse
 import torchvision
 import torchvision.transforms as transforms
 import torch
 import torch.nn as nn
 import torch.distributed as dist
 from torch.nn.parallel import DistributedDataParallel
Salin selepas log masuk

Seterusnya, kami akan menyemak GPU.

import subprocess
 result = subprocess.run(['nvidia-smi'], stdout=subprocess.PIPE)
 print(result.stdout.decode())
Salin selepas log masuk

Oleh kerana kita perlu menjalankan berbilang pelayan, adalah tidak praktikal untuk melaksanakannya satu demi satu secara manual, jadi penjadual diperlukan. Di sini kami menggunakan fail SLURM untuk menjalankan kod (slurmpenjadual kerja sumber terbuka dan percuma untuk Linux dan kernel seperti Unix),

def main():
 
 # get distributed configuration from Slurm environment
 
 parser = argparse.ArgumentParser()
 parser.add_argument('-b', '--batch-size', default=128, type =int,
 help='batch size. it will be divided in mini-batch for each worker')
 parser.add_argument('-e','--epochs', default=2, type=int, metavar='N',
 help='number of total epochs to run')
 parser.add_argument('-c','--checkpoint', default=None, type=str,
 help='path to checkpoint to load')
 args = parser.parse_args()
 
 rank = int(os.environ['SLURM_PROCID'])
 local_rank = int(os.environ['SLURM_LOCALID'])
 size = int(os.environ['SLURM_NTASKS'])
 master_addr = os.environ["SLURM_SRUN_COMM_HOST"]
 port = "29500"
 node_id = os.environ['SLURM_NODEID']
 ddp_arg = [rank, local_rank, size, master_addr, port, node_id]
 train(args, ddp_arg)
Salin selepas log masuk

Kemudian, kami menggunakan perpustakaan DistributedDataParallel untuk melaksanakan latihan yang diedarkan.

def train(args, ddp_arg):
 
 rank, local_rank, size, MASTER_ADDR, port, NODE_ID = ddp_arg
 
 # display info
 if rank == 0:
 #print(">>> Training on ", len(hostnames), " nodes and ", size, " processes, master node is ", MASTER_ADDR)
 print(">>> Training on ", size, " GPUs, master node is ", MASTER_ADDR)
 #print("- Process {} corresponds to GPU {} of node {}".format(rank, local_rank, NODE_ID))
 
 print("- Process {} corresponds to GPU {} of node {}".format(rank, local_rank, NODE_ID))
 
 
 # configure distribution method: define address and port of the master node and initialise communication backend (NCCL)
 #dist.init_process_group(backend='nccl', init_method='env://', world_size=size, rank=rank)
 dist.init_process_group(
 backend='nccl',
 init_method='tcp://{}:{}'.format(MASTER_ADDR, port),
 world_size=size,
 rank=rank
)
 
 # distribute model
 torch.cuda.set_device(local_rank)
 gpu = torch.device("cuda")
 #model = ResNet18(classes=10).to(gpu)
 model = torchvision.models.resnet50(pretrained=False).to(gpu)
 ddp_model = DistributedDataParallel(model, device_ids=[local_rank])
 if args.checkpoint is not None:
 map_location = {'cuda:%d' % 0: 'cuda:%d' % local_rank}
 ddp_model.load_state_dict(torch.load(args.checkpoint, map_location=map_location))
 
 # distribute batch size (mini-batch)
 batch_size = args.batch_size
 batch_size_per_gpu = batch_size // size
 
 # define loss function (criterion) and optimizer
 criterion = nn.CrossEntropyLoss()
 optimizer = torch.optim.SGD(ddp_model.parameters(), 1e-4)
 
 
 transform_train = transforms.Compose([
 transforms.RandomCrop(32, padding=4),
 transforms.RandomHorizontalFlip(),
 transforms.ToTensor(),
 transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),
])
 
 # load data with distributed sampler
 #train_dataset = torchvision.datasets.CIFAR10(root='./data',
 # train=True,
 # transform=transform_train,
 # download=False)
 
 # load data with distributed sampler
 train_dataset = torchvision.datasets.CIFAR10(root='./data',
train=True,
transform=transform_train,
download=False)
 
 train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset,
 num_replicas=size,
 rank=rank)
 
 train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
batch_size=batch_size_per_gpu,
shuffle=False,
num_workers=0,
pin_memory=True,
sampler=train_sampler)
 
 # training (timers and display handled by process 0)
 if rank == 0: start = datetime.now()
 total_step = len(train_loader)
 
 for epoch in range(args.epochs):
 if rank == 0: start_dataload = time()
 
 for i, (images, labels) in enumerate(train_loader):
 
 # distribution of images and labels to all GPUs
 images = images.to(gpu, non_blocking=True)
 labels = labels.to(gpu, non_blocking=True)
 
 if rank == 0: stop_dataload = time()
 
 if rank == 0: start_training = time()
 
 # forward pass
 outputs = ddp_model(images)
 loss = criterion(outputs, labels)
 
 # backward and optimize
 optimizer.zero_grad()
 loss.backward()
 optimizer.step()
 
 if rank == 0: stop_training = time()
 if (i + 1) % 10 == 0 and rank == 0:
 print('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}, Time data load: {:.3f}ms, Time training: {:.3f}ms'.format(epoch + 1, args.epochs,
 i + 1, total_step, loss.item(), (stop_dataload - start_dataload)*1000,
(stop_training - start_training)*1000))
 if rank == 0: start_dataload = time()
 
 #Save checkpoint at every end of epoch
 if rank == 0:
 torch.save(ddp_model.state_dict(), './checkpoint/{}GPU_{}epoch.checkpoint'.format(size, epoch+1))
 
 if rank == 0:
 print(">>> Training complete in: " + str(datetime.now() - start))
 
 
 if __name__ == '__main__':
 
 main()
Salin selepas log masuk

Kod membahagikan data dan model kepada berbilang GPU dan mengemas kini model dengan cara yang diedarkan. Berikut ialah beberapa penjelasan kod:

train(args, ddp_arg) mempunyai dua parameter, args dan ddp_arg, dengan args ialah parameter baris arahan yang dihantar kepada skrip dan ddp_arg mengandungi parameter berkaitan latihan teragih.

kedudukan, peringkat_tempatan, saiz, MASTER_ADDR, port, NODE_ID = ddp_arg: Buka pek parameter berkaitan latihan yang diedarkan dalam ddp_arg.

Jika kedudukan ialah 0, cetak bilangan GPU yang sedang digunakan dan maklumat alamat IP nod induk.

dist.init_process_group(backend='nccl', init_method='tcp://{}:{}'.format(MASTER_ADDR, port), world_size=size, rank=rank): Gunakan bahagian belakang NCCL Initialize kumpulan proses yang diedarkan.

torch.cuda.set_device(local_rank): Pilih GPU yang ditentukan untuk proses ini.

model = torchvision.models. ResNet50 (pretrained=False).to(gpu): Muatkan model ResNet50 daripada model torchvision dan alihkannya ke gpu yang ditentukan.

ddp_model = DistributedDataParallel(model, device_ids=[local_rank]): Balut model dalam modul DistributedDataParallel, yang bermaksud bahawa kita boleh melakukan latihan teragih

Muatkan data CIFAR-10 Kumpul dan gunakan data transformasi pembesaran.

train_sampler=torch.utils.data.distributed.DistributedSampler(train_dataset,num_replicas=size,rank=rank): Buat objek DistributedSampler untuk memisahkan set data kepada berbilang GPU.

train_loader =torch.utils.data.DataLoader(dataset=train_dataset,batch_size=batch_size_per_gpu,shuffle=False,num_workers=0,pin_memory=True,sampler=train_sampler): Buat objek DataLoa akan dimuatkan dalam kelompok Dalam model, ini konsisten dengan langkah latihan biasa kami, kecuali pensampelan data teragih DistributedSampler ditambah.

Latih model untuk bilangan zaman yang ditentukan dan kemas kini pemberat menggunakan optimizer.step() dalam cara yang diedarkan.

pangkat0 menyimpan pusat pemeriksaan pada penghujung setiap pusingan.

pangkat0 menunjukkan kehilangan dan masa latihan setiap 10 kelompok.

Pada akhir latihan, jumlah masa yang dihabiskan untuk mencetak model latihan juga berada dalam kedudukan0.

Ujian kod

telah dilatih pada 1 nod dengan 1/2/3/4 GPU, 2 nod dengan 6/8 GPU dan setiap nod dengan 3/4 GPU Ujian Resnet50 dihidupkan Cifar10 ditunjukkan dalam rajah di bawah Saiz kelompok setiap ujian tetap sama. Masa yang diambil untuk menyelesaikan setiap ujian direkodkan dalam beberapa saat. Apabila bilangan GPU yang digunakan meningkat, masa yang diperlukan untuk menyelesaikan ujian berkurangan. Apabila menggunakan 8 GPU, ia mengambil masa 320 saat untuk diselesaikan, yang merupakan masa terpantas yang direkodkan. Ini sudah pasti, tetapi kita dapat melihat bahawa kelajuan latihan tidak meningkat secara linear dengan peningkatan bilangan GPU Ini mungkin kerana Resnet50 adalah model yang agak kecil dan tidak memerlukan latihan selari.

Latihan selari PyTorch Contoh kod lengkap DistributedDataParallel

Menggunakan keselarian data pada berbilang GPU boleh mengurangkan dengan ketara masa yang diperlukan untuk melatih rangkaian saraf dalam (DNN) pada set data tertentu. Apabila bilangan GPU meningkat, masa yang diperlukan untuk menyelesaikan proses latihan berkurangan, menunjukkan bahawa DNN boleh dilatih dengan lebih cekap secara selari.

Pendekatan ini amat berguna apabila berurusan dengan set data yang besar atau seni bina DNN yang kompleks. Dengan memanfaatkan berbilang GPU, proses latihan boleh dipercepatkan, membolehkan lelaran dan percubaan model yang lebih pantas. Walau bagaimanapun, perlu diingatkan bahawa peningkatan prestasi yang dicapai melalui Data Parallelism mungkin dihadkan oleh faktor seperti overhed komunikasi dan had memori GPU, dan memerlukan penalaan berhati-hati untuk mendapatkan hasil yang terbaik.

Atas ialah kandungan terperinci Latihan selari PyTorch Contoh kod lengkap DistributedDataParallel. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:51cto.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan