View a markdown version of this page

Memodifikasi Skrip PyTorch Pelatihan - Amazon SageMaker AI

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Memodifikasi Skrip PyTorch Pelatihan

Di bagian ini, Anda mempelajari cara memodifikasi skrip PyTorch pelatihan untuk mengonfigurasi pustaka paralelisme SageMaker model untuk partisi otomatis dan partisi manual.

catatan

Untuk menemukan PyTorch versi mana yang didukung oleh pustaka, lihatKerangka Kerja yang Didukung dan Wilayah AWS.

Tip

Untuk contoh buku catatan ujung ke ujung yang menunjukkan cara menggunakan skrip PyTorch pelatihan dengan pustaka paralelisme SageMaker model, lihat. Contoh perpustakaan paralelisme model Amazon SageMaker AI v1

Perhatikan bahwa partisi otomatis diaktifkan secara default. Kecuali ditentukan lain, skrip berikut menggunakan partisi otomatis.

Pemisahan otomatis dengan PyTorch

Perubahan skrip pelatihan berikut diperlukan untuk menjalankan skrip PyTorch pelatihan dengan pustaka SageMaker paralelisme model:

  1. Impor dan inisialisasi perpustakaan dengan smdistributed.modelparallel.torch.init().

  2. Bungkus model dengan smdistributed.modelparallel.torch.DistributedModel. Perhatikan bahwa setiap tensor yang dikembalikan dari forward metode nn.Module objek yang mendasarinya akan disiarkan melintasi perangkat model-paralel, menimbulkan overhead komunikasi, sehingga tensor apa pun yang tidak diperlukan di luar metode panggilan (seperti aktivasi perantara) tidak boleh dikembalikan.

    catatan

    Untuk pelatihan FP16, Anda perlu menggunakan pengelola konteks smdistributed.modelparallel.torch.model_creation () untuk membungkus model. Untuk informasi selengkapnya, lihat Pelatihan FP16 dengan Model Paralelisme.

  3. Bungkus pengoptimal dengan smdistributed.modelparallel.torch.DistributedOptimizer.

    catatan

    Untuk pelatihan FP16, Anda perlu mengatur penskalaan kerugian statis atau dinamis. Untuk informasi selengkapnya, lihat Pelatihan FP16 dengan Model Paralelisme.

  4. Gunakan DistributedModel objek yang dikembalikan alih-alih model pengguna.

  5. Letakkan logika maju dan mundur dalam fungsi langkah dan hiasi dengan smdistributed.modelparallel.torch.step.

  6. Batasi setiap proses ke perangkatnya sendiritorch.cuda.set_device(smp.local_rank()).

  7. Pindahkan tensor input ke GPU menggunakan .to() API sebelum smp.step panggilan (lihat contoh di bawah).

  8. Ganti torch.Tensor.backward dan torch.autograd.backward denganDistributedModel.backward.

  9. Lakukan pasca-pemrosesan pada output di seluruh mikrobatch menggunakan StepOutput metode seperti. reduce_mean

  10. Jika ada langkah evaluasi, letakkan logika maju di dalam fungsi yang smp.step dihias dan pasca-proses output menggunakan StepOutput API.

  11. Di drop_last=True aturDataLoader. Atau, lewati batch secara manual dalam loop pelatihan jika ukuran batch tidak dapat dibagi dengan jumlah mikrobatch.

Untuk mempelajari lebih lanjut tentang SageMaker API pustaka paralelisme model, lihat dokumentasi API.

import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchnet.dataset import SplitDataset from torchvision import datasets import smdistributed.modelparallel.torch as smp class GroupedNet(nn.Module): def __init__(self): super(GroupedNet, self).__init__() # define layers def forward(self, x): # define forward pass and return model outputs # smdistributed: Define smp.step. Return any tensors needed outside. @smp.step def train_step(model, data, target): output = model(data) loss = F.nll_loss(output, target, reduction="mean") model.backward(loss) return output, loss def train(model, device, train_loader, optimizer): model.train() for batch_idx, (data, target) in enumerate(train_loader): # smdistributed: Move input tensors to the GPU ID used by the current process, # based on the set_device call. data, target = data.to(device), target.to(device) optimizer.zero_grad() # Return value, loss_mb is a StepOutput object _, loss_mb = train_step(model, data, target) # smdistributed: Average the loss across microbatches. loss = loss_mb.reduce_mean() optimizer.step() # smdistributed: initialize the backend smp.init() # smdistributed: Set the device to the GPU ID used by the current process. # Input tensors should be transferred to this device. torch.cuda.set_device(smp.local_rank()) device = torch.device("cuda") # smdistributed: Download only on a single process per instance. # When this is not present, the file is corrupted by multiple processes trying # to download and extract at the same time dataset = datasets.MNIST("../data", train=True, download=False) # smdistributed: Shard the dataset based on data-parallel ranks if smp.dp_size() > 1: partitions_dict = {f"{i}": 1 / smp.dp_size() for i in range(smp.dp_size())} dataset = SplitDataset(dataset, partitions=partitions_dict) dataset.select(f"{smp.dp_rank()}") # smdistributed: Set drop_last=True to ensure that batch size is always divisible # by the number of microbatches train_loader = torch.utils.data.DataLoader(dataset, batch_size=64, drop_last=True) model = GroupedNet() optimizer = optim.Adadelta(model.parameters(), lr=4.0) # smdistributed: Use the DistributedModel container to provide the model # to be partitioned across different ranks. For the rest of the script, # the returned DistributedModel object should be used in place of # the model provided for DistributedModel class instantiation. model = smp.DistributedModel(model) optimizer = smp.DistributedOptimizer(optimizer) train(model, device, train_loader, optimizer)

Pemisahan manual dengan PyTorch

Gunakan smp.partition pengelola konteks untuk menempatkan modul di perangkat tertentu. Modul apa pun yang tidak ditempatkan dalam smp.partition konteks apa pun ditempatkan didefault_partition. Ke default_partition butuhan yang harus disediakan jika auto_partition diatur keFalse. Modul yang dibuat dalam smp.partition konteks tertentu ditempatkan pada partisi yang sesuai.

Untuk mempelajari lebih lanjut tentang SageMaker API pustaka paralelisme model, lihat dokumentasi API.

import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchnet.dataset import SplitDataset from torchvision import datasets import smdistributed.modelparallel.torch as smp class GroupedNet(nn.Module): def __init__(self): super(GroupedNet, self).__init__() with smp.partition(0): # define child modules on device 0 with smp.partition(1): # define child modules on device 1 def forward(self, x): # define forward pass and return model outputs # smdistributed: Define smp.step. Return any tensors needed outside. @smp.step def train_step(model, data, target): output = model(data) loss = F.nll_loss(output, target, reduction="mean") model.backward(loss) return output, loss def train(model, device, train_loader, optimizer): model.train() for batch_idx, (data, target) in enumerate(train_loader): # smdistributed: Move input tensors to the GPU ID used by the current process, # based on the set_device call. data, target = data.to(device), target.to(device) optimizer.zero_grad() # Return value, loss_mb is a StepOutput object _, loss_mb = train_step(model, data, target) # smdistributed: Average the loss across microbatches. loss = loss_mb.reduce_mean() optimizer.step() # smdistributed: initialize the backend smp.init() # smdistributed: Set the device to the GPU ID used by the current process. # Input tensors should be transferred to this device. torch.cuda.set_device(smp.local_rank()) device = torch.device("cuda") # smdistributed: Download only on a single process per instance. # When this is not present, the file is corrupted by multiple processes trying # to download and extract at the same time dataset = datasets.MNIST("../data", train=True, download=False) # smdistributed: Shard the dataset based on data-parallel ranks if smp.dp_size() > 1: partitions_dict = {f"{i}": 1 / smp.dp_size() for i in range(smp.dp_size())} dataset = SplitDataset(dataset, partitions=partitions_dict) dataset.select(f"{smp.dp_rank()}") # smdistributed: Set drop_last=True to ensure that batch size is always divisible # by the number of microbatches train_loader = torch.utils.data.DataLoader(dataset, batch_size=64, drop_last=True) model = GroupedNet() optimizer = optim.Adadelta(model.parameters(), lr=4.0) # smdistributed: Use the DistributedModel container to provide the model # to be partitioned across different ranks. For the rest of the script, # the returned DistributedModel object should be used in place of # the model provided for DistributedModel class instantiation. model = smp.DistributedModel(model) optimizer = smp.DistributedOptimizer(optimizer) train(model, device, train_loader, optimizer)

Pertimbangan-pertimbangan

Saat Anda mengonfigurasi skrip PyTorch pelatihan menggunakan SageMaker pustaka paralelisme model, Anda harus mengetahui hal berikut:

  • Jika Anda menggunakan teknik pengoptimalan yang bergantung pada norma gradien global, misalnya norma gradien dari seluruh model, seperti beberapa varian pengoptimal LAMB atau kliping gradien global, Anda perlu mengumpulkan semua norma di seluruh partisi model untuk kebenaran. Anda dapat menggunakan tipe data dasar komunikasi perpustakaan untuk melakukan ini.

  • Semua torch.Tensor argumen untuk metode maju nn.Modules dalam model Anda harus digunakan dalam perhitungan output modul. Dengan kata lain, perpustakaan tidak mendukung kasus di mana ada torch.Tensor argumen ke modul di mana output modul tidak bergantung.

  • Argumen untuk smp.DistributedModel.backward() panggilan harus bergantung pada semua output model. Dengan kata lain, tidak mungkin ada output dari smp.DistributedModel.forward panggilan yang tidak digunakan dalam perhitungan tensor yang dimasukkan ke dalam panggilan. smp.DistributedModel.backward

  • Jika ada torch.cuda.synchronize() panggilan dalam kode Anda, Anda mungkin perlu menelepon torch.cuda.set_device(smp.local_rank()) segera sebelum panggilan sinkronisasi. Jika tidak, konteks CUDA yang tidak perlu mungkin dibuat di perangkat 0, yang akan menghabiskan memori secara tidak perlu.

  • Karena perpustakaan ditempatkan nn.Modules pada perangkat yang berbeda, modul dalam model tidak boleh bergantung pada keadaan global apa pun yang dimodifikasi di dalamnyasmp.step. Setiap keadaan yang tetap tetap selama pelatihan, atau yang dimodifikasi smp.step di luar dengan cara yang terlihat oleh semua proses, diperbolehkan.

  • Anda tidak perlu memindahkan model ke GPU (misalnya, menggunakanmodel.to(device)) saat menggunakan perpustakaan. Jika Anda mencoba memindahkan model ke GPU sebelum model dipartisi (sebelum smp.step panggilan pertama), panggilan pindah diabaikan. Pustaka secara otomatis memindahkan bagian model yang ditetapkan ke peringkat ke GPU-nya. Setelah pelatihan dengan pustaka dimulai, jangan pindahkan model ke CPU dan gunakan, karena tidak akan memiliki parameter yang benar untuk modul yang tidak ditetapkan ke partisi yang dipegang oleh proses. Jika Anda ingin melatih ulang model atau menggunakannya untuk inferensi tanpa pustaka setelah dilatih menggunakan pustaka paralelisme model, cara yang disarankan adalah menyimpan model lengkap menggunakan API checkpointing kami dan memuatnya kembali ke Modul biasa. PyTorch

  • Jika Anda memiliki daftar modul sedemikian rupa sehingga output dari satu umpan ke yang lain, mengganti daftar itu dengan nn.Sequential dapat meningkatkan kinerja secara signifikan.

  • Pembaruan berat (optimizer.step()) perlu terjadi di luar smp.step karena saat itulah seluruh pass mundur selesai dan gradien siap. Saat menggunakan model hybrid dengan paralelisme model dan data, pada titik ini, gra AllReduce dien juga dijamin selesai.

  • Saat menggunakan perpustakaan dalam kombinasi dengan paralelisme data, pastikan bahwa jumlah batch pada semua peringkat paralel data sama sehingga AllReduce tidak hang menunggu peringkat yang tidak berpartisipasi dalam langkah tersebut.

  • Jika Anda meluncurkan pekerjaan pelatihan menggunakan jenis instans ml.p4d (seperti ml.p4d.24xlarge), Anda harus menyetel variabel pemuat data. num_workers=0 Misalnya, Anda dapat mendefinisikan DataLoader sebagai berikut:

    dataloader = torch.utils.data.DataLoader( data, batch_size=batch_size, num_workers=0, pin_memory=True, drop_last=True, shuffle=shuffle, )
  • Input smp.step harus berupa input model yang dihasilkan olehDataLoader. Ini karena smp.step secara internal membagi tensor input di sepanjang dimensi batch dan menyalurkannya. Ini berarti bahwa mener DataLoader uskan dirinya ke smp.step fungsi untuk menghasilkan input model di dalamnya tidak berfungsi.

    Misalnya, jika Anda mendefinisikan a DataLoader sebagai berikut:

    train_loader = torch.utils.data.DataLoader(dataset, batch_size=64, drop_last=True)

    Anda harus mengakses input model yang dihasilkan oleh train_loader dan meneruskannya ke fungsi yang smp.step didekorasi. Jangan train_loader langsung masuk ke smp.step fungsi.

    def train(model, device, train_loader, optimizer): model.train() for batch_idx, (data, target) in enumerate(train_loader): ... _, loss_mb = train_step(model, data, target) ... @smp.step def train_step(model, data, target): ... return output, loss
  • Tensor input smp.step harus dipindahkan ke perangkat saat ini menggunakan .to() API, yang harus dilakukan setelah torch.cuda.set_device(local_rank()) panggilan.

    Misalnya, Anda dapat mendefinisikan train fungsi sebagai berikut. Fungsi ini menambah data dan target ke perangkat saat ini menggunakan .to() API sebelum menggunakan tensor input tersebut untuk dipanggiltrain_step.

    def train(model, device, train_loader, optimizer): model.train() for batch_idx, (data, target) in enumerate(train_loader): # smdistributed: Move input tensors to the GPU ID used by the current process, # based on the set_device call. data, target = data.to(device), target.to(device) optimizer.zero_grad() # Return value, loss_mb is a StepOutput object _, loss_mb = train_step(model, data, target) # smdistributed: Average the loss across microbatches. loss = loss_mb.reduce_mean() optimizer.step()

    Tensor input ke fungsi yang smp.set dihias ini telah dipindahkan ke perangkat saat ini dalam train fungsi di atas. Model tidak perlu dipindahkan ke perangkat saat ini. Pustaka secara otomatis memindahkan bagian model yang ditetapkan ke peringkat ke GPU-nya.

    @smp.step def train_step(model, data, target): output = model(data) loss = F.nll_loss(output, target, reduction="mean") model.backward(loss) return output, loss

Fitur kerangka kerja yang tidak didukung

Fitur- PyTorch fitur berikut tidak didukung oleh pustaka paral SageMaker elisme model:

  • Jika Anda menggunakan paralelisme data dengan PyTorch DDP asli, modul pem torch.nn.parallel.DistributedDataParallel bungkus tidak didukung oleh pustaka. Perpustakaan secara internal mengelola integrasi dengan PyTorch DDP, termasuk siaran parameter dan gradien AllReduce. Saat menggunakan perpustakaan, buffer modul hanya disiarkan sekali pada awal pelatihan. Jika model Anda memiliki buffer modul yang perlu disinkronkan di seluruh grup paralel data pada setiap langkah, Anda dapat melakukannya melalui torch.distributed API, menggunakan grup proses yang dapat diperoleh melaluismp.get_dp_process_group().

  • Untuk pelatihan presisi campuran, apex.amp modul tidak didukung. Cara yang disarankan untuk menggunakan perpustakaan dengan presisi campuran otomatis adalah dengan menggunakantorch.cuda.amp, dengan pengecualian menggunakan alih- smp.amp.GradScaler alih implementasi dalam obor.

  • torch.jit.ScriptModulesatau ScriptFunctions tidak didukung oleh smp.DistributedModel

  • apex:FusedLayerNorm,FusedAdam,FusedLAMB, dan FusedNovoGrad dari apex tidak didukung. Anda dapat menggunakan implementasi pustaka ini melalui smp.optimizers dan smp.nn API sebagai gantinya.