Aracılığıyla paylaş


Çoklu GPU ve çok düğümlü iş yükü

Sunucusuz GPU Python API'sini kullanarak dağıtılmış iş yükünü tek bir düğümde veya birden çok düğümde birden çok GPU arasında başlatabilirsiniz. API, GPU sağlama, ortam kurulumu ve iş yükü dağıtımı ayrıntılarını soyutlayan basit, birleşik bir arabirim sağlar. En az kod değişikliğiyle tek GPU eğitiminden aynı not defterinden uzak GPU'lar arasında dağıtılmış yürütmeye sorunsuz bir şekilde geçiş yapabilirsiniz.

Hızlı başlangıç

Dağıtılmış eğitim için sunucusuz GPU API'si Databricks not defterleri için sunucusuz GPU işlem ortamlarına önceden yüklenmiştir. GPU ortamı 4 ve üzerini öneririz. Dağıtılmış eğitimde kullanmak için, eğitim işlevinizi dağıtmak üzere distributed dekoratörünü içe aktarın ve kullanın.

Aşağıdaki kod parçacığı temel kullanımını @distributedgösterir:

# Import the distributed decorator
from serverless_gpu import distributed

# Decorate your training function with @distributed and specify the number of GPUs, the GPU type,
# and whether or not the GPUs are remote
@distributed(gpus=8, gpu_type='A10', remote=True)
def run_train():
    ...

Aşağıda, bir not defterinden 8 A10 GPU düğümünde çok katmanlı bir algı (MLP) modelini eğiten tam bir örnek verilmiştir:

  1. Modelinizi ayarlayın ve yardımcı program işlevlerini tanımlayın.

    
    # Define the model
    import os
    import torch
    import torch.distributed as dist
    import torch.nn as nn
    
    def setup():
        dist.init_process_group("nccl")
        torch.cuda.set_device(int(os.environ["LOCAL_RANK"]))
    
    def cleanup():
        dist.destroy_process_group()
    
    class SimpleMLP(nn.Module):
        def __init__(self, input_dim=10, hidden_dim=64, output_dim=1):
            super().__init__()
            self.net = nn.Sequential(
                nn.Linear(input_dim, hidden_dim),
                nn.ReLU(),
                nn.Dropout(0.2),
                nn.Linear(hidden_dim, hidden_dim),
                nn.ReLU(),
                nn.Dropout(0.2),
                nn.Linear(hidden_dim, output_dim)
            )
    
        def forward(self, x):
            return self.net(x)
    
  2. serverless_gpu kitaplığını ve dağıtılmış modülü içeri aktarın.

    import serverless_gpu
    from serverless_gpu import distributed
    
  3. Model eğitim kodunu bir fonksiyon içerisine alın ve bu fonksiyona @distributed dekoratörü ekleyin.

    @distributed(gpus=8, gpu_type='A10', remote=True)
    def run_train(num_epochs: int, batch_size: int) -> None:
        import mlflow
        import torch.optim as optim
        from torch.nn.parallel import DistributedDataParallel as DDP
        from torch.utils.data import DataLoader, DistributedSampler, TensorDataset
    
        # 1. Set up multi node environment
        setup()
        device = torch.device(f"cuda:{int(os.environ['LOCAL_RANK'])}")
    
        # 2. Apply the Torch distributed data parallel (DDP) library for data-parellel training.
        model = SimpleMLP().to(device)
        model = DDP(model, device_ids=[device])
    
        # 3. Create and load dataset.
        x = torch.randn(5000, 10)
        y = torch.randn(5000, 1)
    
        dataset = TensorDataset(x, y)
        sampler = DistributedSampler(dataset)
        dataloader = DataLoader(dataset, sampler=sampler, batch_size=batch_size)
    
        # 4. Define the training loop.
        optimizer = optim.Adam(model.parameters(), lr=0.001)
        loss_fn = nn.MSELoss()
    
        for epoch in range(num_epochs):
            sampler.set_epoch(epoch)
            model.train()
            total_loss = 0.0
            for step, (xb, yb) in enumerate(dataloader):
                xb, yb = xb.to(device), yb.to(device)
                optimizer.zero_grad()
                loss = loss_fn(model(xb), yb)
                # Log loss to MLflow metric
                mlflow.log_metric("loss", loss.item(), step=step)
    
                loss.backward()
                optimizer.step()
                total_loss += loss.item() * xb.size(0)
    
            mlflow.log_metric("total_loss", total_loss)
            print(f"Total loss for epoch {epoch}: {total_loss}")
    
        cleanup()
    
  4. Kullanıcı tanımlı bağımsız değişkenlerle dağıtılmış işlevi çağırarak dağıtılmış eğitimi gerçekleştirin.

    run_train.distributed(num_epochs=3, batch_size=1)
    
  5. Çalıştırıldığında, not defteri hücresinin çıktısında bir MLflow çalıştırma bağlantısı oluşturulur. Çalıştırma sonuçlarını görmek için MLflow çalıştırma bağlantısına tıklayın veya Deneme panelinde bulun.

    Not defteri hücresindeki çıkış

Dağıtılmış yürütme ayrıntıları

Sunucusuz GPU API'si birkaç temel bileşenden oluşur:

  • İşlem yöneticisi: Kaynak ayırma ve yönetimi işler
  • Çalışma zamanı ortamı: Python ortamlarını ve bağımlılıklarını yönetir
  • Başlatıcı: İş yürütme ve izlemeyi düzenler

Dağıtılmış modda çalışırken:

  • İşlev serileştirilir ve belirtilen sayıda GPU'ya dağıtılır
  • Her GPU işlevin bir kopyasını aynı parametrelerle çalıştırır
  • Ortam tüm düğümler arasında senkronize edilir
  • Sonuçlar tüm GPU'lardan toplanır ve döndürülür

olarak ayarlanırsa remoteTrue, iş yükü uzak GPU'lara dağıtılır. remote False olarak ayarlanırsa, iş yükü geçerli deftere bağlı tek bir GPU düğümünde çalışır. Düğümde birden çok GPU yongası varsa bunların tümü kullanılır.

API Dağıtılmış Veri Paralel (DDP), Tam Parçalı Veri Paralel (FSDP), DeepSpeed ve Ray gibi popüler paralel eğitim kitaplıklarını destekler.

Not defteri örneklerindeki çeşitli kitaplıkları kullanarak daha gerçek dağıtılmış eğitim senaryoları bulabilirsiniz.

Ray ile başlat

Sunucusuz GPU API, üzerinde katmanlanmış @ray_launch ile @distributed dekoratörü kullanılarak Ray framework'ü ile dağıtılmış eğitimi başlatmayı da destekler. Her ray_launch görev önce Işın baş çalışanına karar vermek ve IP'leri toplamak için meşale dağıtılmış bir randevuyu önyükler. Sıfırıncı derece ray start --head başlar (ölçümler etkinse dışa aktarılarak), RAY_ADDRESS ayarlanır ve süslenmiş işlevinizi Ray sürücüsü olarak çalıştırır. Diğer düğümler ray start --address üzerinden bağlanır ve sürücü bir tamamlama işaretçisi yazana kadar bekler.

Ek yapılandırma ayrıntıları:

  • Her düğümde Ray sistem ölçüm toplamayı etkinleştirmek için RayMetricsMonitorremote=True ile kullanın.
  • Standart Ray API'lerini kullanarak dekore edilmiş işlevinizin içinde Ray çalışma zamanı seçeneklerini (aktörler, veri kümeleri, yerleştirme grupları ve zamanlama) tanımlayın.
  • Dekoratör bağımsız değişkenlerinde veya not defteri ortamında, işlevin dışında GPU sayısı ve türü, uzak mod ve yerel mod, zaman uyumsuz davranış ve Databricks havuzu ortam değişkenleri gibi küme genelindeki denetimleri yönetin.

Aşağıdaki örnekte nasıl kullanılacağı @ray_launchgösterilmektedir:

from serverless_gpu.ray import ray_launch
@ray_launch(gpus=16, remote=True, gpu_type='A10')
def foo():
    import os
    import ray
    print(ray.state.available_resources_per_node())
    return 1
foo.distributed()

Eksiksiz bir örnek için, birden çok A10 GPU'da Resnet18 sinir ağını eğitmek için Ray'i başlatan bu not defterine göz atın.

LlM'lerde dağıtılmış toplu çıkarım çalıştırmak üzere yapay zeka iş yükleri için ölçeklenebilir bir veri işleme kitaplığı olan Ray Data'yı çağırmak için de bu API'yi kullanabilirsiniz. Bkz. vllm ve sglang örnekleri.

FAQs

Veri yükleme kodu nereye yerleştirilmelidir?

Dağıtılmış eğitim için Sunucusuz GPU API'sini kullanırken veri yükleme kodunu @distributed dekoratörün içine taşıyın. Veri kümesi boyutu, turşunun izin verdiği boyut üst sınırını aşabilir, bu nedenle aşağıda gösterildiği gibi veri kümesinin dekoratör içinde oluşturulması önerilir:

from serverless_gpu import distributed

# this may cause pickle error
dataset = get_dataset(file_path)
@distributed(gpus=8, remote=True)
def run_train():
  # good practice
  dataset = get_dataset(file_path)
  ....

Ayrılmış GPU havuzlarını kullanabilir miyim?

Çalışma alanınızda ayrılmış GPU havuzu varsa (lütfen yöneticinize danışın) ve bunu dekoratörde remote belirtirseniz True@distributed, iş yükü varsayılan olarak ayrılmış GPU havuzunda başlatılır. İsteğe bağlı GPU havuzunu kullanmak istiyorsanız, aşağıda gösterildiği gibi dağıtılmış işlevi çağırmadan önce ortam değişkenini DATABRICKS_USE_RESERVED_GPU_POOLFalse olarak ayarlayın:

import os
os.environ['DATABRICKS_USE_RESERVED_GPU_POOL'] = 'False'
@distributed(gpus=8, remote=True)
def run_train():
    ...

Daha fazla bilgi edinin

API başvurusu için Sunucusuz GPU Python API belgelerine bakın.