深度學習模型的訓練往往需要耗費大量時間,尤其在處理大規模資料集和複雜模型時。利用多 GPU 進行分散式訓練是提升訓練效率的有效方法。PyTorch 提供了 DistributedDataParallel(DDP)策略,讓開發者可以輕鬆地在多 GPU 環境下進行模型訓練。DDP 策略的核心概念是將資料分散到不同的 GPU 上進行平行處理,並在每個訓練步驟後同步梯度,確保模型引數的一致性。此方法能有效縮短訓練時間,並允許訓練更大規模的模型。在實作過程中,需要設定分散式訓練環境,並修改訓練程式碼以支援 DDP。此外,還需注意處理多 GPU 環境下的重複輸出問題,例如只讓 rank 為 0 的程式輸出測試結果。

使用PyTorch進行多GPU訓練

在深度學習中,模型的訓練時間往往是一個巨大的挑戰。為了加速訓練過程,我們可以使用多GPU訓練,也就是分散式訓練。本文將介紹PyTorch中的DistributedDataParallel(DDP)策略,幫助讀者瞭解如何利用多GPU來加速模型訓練。

為什麼需要分散式訓練?

即使在單一GPU或機器上訓練模型是可行的,但這個過程可能非常耗時。透過將訓練過程分散到多台機器(每台機器可能有多個GPU),可以顯著減少訓練時間。這在模型開發的實驗階段尤為重要,因為在這個階段,可能需要進行多次訓練迭代來微調模型引數和架構。

PyTorch的DistributedDataParallel(DDP)策略

DDP透過將輸入資料分割到可用的裝置上,並同時處理這些資料子集來實作平行化。這是如何工作的呢?PyTorch在每個GPU上啟動一個獨立的程式,每個程式接收並保留模型的副本;這些副本在訓練過程中會被同步。

DDP的工作流程

  1. 模型初始化:首先,在CPU上初始化模型。
  2. 模型複製:然後,將模型的副本複製到每個GPU上。
  3. 資料分割:接著,將輸入資料分割成不同的小批次(minibatch),並將這些小批次分配給每個GPU上的模型副本。
  4. 前向傳遞和反向傳遞:每個GPU上的模型副本獨立進行前向傳遞和反向傳遞,計算輸出和梯度。
  5. 梯度同步:最後,將每個GPU上的梯度進行同步和平均,用於更新模型引數。

使用DDP的優點

使用DDP的主要優點是,它可以顯著提高處理資料集的速度。與單一GPU相比,使用兩個GPU理論上可以將訓練時間縮短一半。使用八個GPU,則可以將訓練時間縮短到八分之一。

實作DDP

要實作DDP,需要對原有的訓練程式碼進行一些修改。首先,需要匯入一些額外的模組和函式,例如torch.multiprocessingDistributedSamplerDistributedDataParallel等。

import torch.multiprocessing as mp
from torch.utils.data.distributed import DistributedSampler
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.distributed import init_process_group, destroy_process_group

設定DDP

def ddp_setup(rank, world_size):
    os.environ["MASTER_ADDR"] = "localhost"
    os.environ["MASTER_PORT"] = "12355"
    init_process_group(backend="nccl", rank=rank, world_size=world_size)

訓練模型

def train(model, dataloader, optimizer, loss_fn, device):
    model.train()
    for batch in dataloader:
        inputs, labels = batch
        inputs, labels = inputs.to(device), labels.to(device)
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = loss_fn(outputs, labels)
        loss.backward()
        optimizer.step()

注意事項

  1. DDP不支援互動式Python環境:DDP需要在獨立的Python指令碼中執行,而不是在Jupyter Notebook中。
  2. 多GPU支援:需要確保硬體支援多GPU訓練。
內容解密:
  1. 分散式訓練的重要性:分散式訓練可以顯著減少模型訓練時間,特別是在實驗階段。
  2. DDP的工作原理:DDP透過將資料分割到多個GPU上,並同步梯度來實作平行化。
  3. 實作DDP的步驟:需要匯入必要的模組,設定DDP環境,並修改訓練程式碼以支援DDP。
  4. 使用DDP的優點:可以顯著提高資料處理速度,減少訓練時間。
  5. 注意事項:需要在獨立的Python指令碼中執行,且需要硬體支援多GPU訓練。

使用GPU最佳化訓練效能:分散式資料平行處理(DDP)實作解析

在前述章節中,我們探討瞭如何使用單一GPU進行模型訓練。然而,隨著模型複雜度和資料量的增加,單一GPU的訓練速度可能成為瓶頸。本文將介紹如何利用PyTorch的分散式資料平行(Distributed Data Parallel, DDP)技術,結合多GPU進行模型訓練,以顯著提升訓練效率。

程式碼解析

首先,我們來看實作DDP的核心程式碼:

import os
import torch
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.utils.data import DataLoader, DistributedSampler

# 設定分散式訓練環境
def ddp_setup(rank, world_size):
    os.environ["MASTER_PORT"] = "12345"
    dist.init_process_group(
        backend="nccl",
        rank=rank,
        world_size=world_size
    )
    torch.cuda.set_device(rank)

# 準備資料集
def prepare_dataset():
    # 插入資料集準備程式碼
    train_loader = DataLoader(
        dataset=train_ds,
        batch_size=2,
        shuffle=False,
        pin_memory=True,
        drop_last=True,
        sampler=DistributedSampler(train_ds)
    )
    return train_loader, test_loader

# 主要訓練函式
def main(rank, world_size, num_epochs):
    ddp_setup(rank, world_size)
    train_loader, test_loader = prepare_dataset()
    model = NeuralNetwork(num_inputs=2, num_outputs=2)
    model.to(rank)
    optimizer = torch.optim.SGD(model.parameters(), lr=0.5)
    model = DDP(model, device_ids=[rank])
    
    for epoch in range(num_epochs):
        for features, labels in train_loader:
            features, labels = features.to(rank), labels.to(rank)
            # 插入模型預測和反向傳播程式碼
            print(f"[GPU{rank}] Epoch: {epoch+1:03d}/{num_epochs:03d}"
                  f" | Batchsize {labels.shape[0]:03d}"
                  f" | Train/Val Loss: {loss:.2f}")
    
    model.eval()
    train_acc = compute_accuracy(model, train_loader, device=rank)
    print(f"[GPU{rank}] Training accuracy", train_acc)
    test_acc = compute_accuracy(model, test_loader, device=rank)
    print(f"[GPU{rank}] Test accuracy", test_acc)
    
    dist.destroy_process_group()

if __name__ == "__main__":
    print("Number of GPUs available:", torch.cuda.device_count())
    torch.manual_seed(123)
    num_epochs = 3
    world_size = torch.cuda.device_count()
    mp.spawn(main, args=(world_size, num_epochs), nprocs=world_size)

內容解密:

  1. ddp_setup函式:設定分散式訓練環境,包括初始化程式群組、設定GPU裝置等。
    • 使用nccl後端進行GPU間的通訊。
    • 設定rankworld_size以識別不同的GPU。
  2. prepare_dataset函式:準備訓練和測試資料集。
    • 使用DistributedSampler確保每個GPU獲得不同的資料子集。
    • 設定pin_memory=True以加速GPU記憶體傳輸。
  3. main函式:執行模型訓練的主要邏輯。
    • 將模型和資料移至對應的GPU裝置。
    • 使用DDP包裝模型以實作梯度同步。
    • 在每個epoch結束時評估模型在訓練集和測試集上的準確率。

多GPU機器的GPU選擇

在多GPU機器上,若要限制使用的GPU數量,可以透過設定CUDA_VISIBLE_DEVICES環境變數來實作。例如:

CUDA_VISIBLE_DEVICES=0 python some_script.py  # 使用索引為0的GPU
CUDA_VISIBLE_DEVICES=0,2 python some_script.py  # 使用索引為0和2的GPU

這種方法簡單有效,無需修改PyTorch指令碼即可管理GPU分配。

執行與驗證

最後,將上述程式碼儲存為ch02-DDP-script.py,並在終端機中執行:

python ch02-DDP-script.py

觀察輸出結果,驗證多GPU訓練是否正確執行。

本文介紹瞭如何利用PyTorch的DDP技術結合多GPU進行模型訓練,顯著提升了訓練效率。透過合理的程式碼設計和GPU資源管理,可以有效地加速深度學習模型的訓練過程。

使用GPU最佳化訓練效能

在深度學習模型的訓練過程中,GPU的運算能力對於提升訓練效率至關重要。PyTorch提供了簡便的方式來利用單一或多個GPU進行模型訓練。

單GPU訓練

當在單一GPU上執行訓練程式碼時,我們可以預期輸出結果如下:

PyTorch版本:2.2.1+cu117
CUDA可用:True
可用的GPU數量:1
[GPU0] 迭代:001/003 | 批次大小 002 | 訓練/驗證損失:0.62
[GPU0] 迭代:001/003 | 批次大小 002 | 訓練/驗證損失:0.32
[GPU0] 迭代:002/003 | 批次大小 002 | 訓練/驗證損失:0.11
[GPU0] 迭代:002/003 | 批次大小 002 | 訓練/驗證損失:0.07
[GPU0] 迭代:003/003 | 批次大小 002 | 訓練/驗證損失:0.02
[GPU0] 迭代:003/003 | 批次大小 002 | 訓練/驗證損失:0.03
[GPU0] 訓練準確率 1.0
[GPU0] 測試準確率 1.0

多GPU訓練

當使用多個GPU進行訓練時,PyTorch的DistributedDataParallel(DDP)模組可以有效地分配訓練任務到不同的GPU上。以下是在兩顆GPU上執行相同程式碼的輸出範例:

PyTorch版本:2.2.1+cu117
CUDA可用:True
可用的GPU數量:2
[GPU1] 迭代:001/003 | 批次大小 002 | 訓練/驗證損失:0.60
[GPU0] 迭代:001/003 | 批次大小 002 | 訓練/驗證損失:0.59
[GPU0] 迭代:002/003 | 批次大小 002 | 訓練/驗證損失:0.16
[GPU1] 迭代:002/003 | 批次大小 002 | 訓練/驗證損失:0.17
[GPU0] 迭代:003/003 | 批次大小 002 | 訓練/驗證損失:0.05
[GPU1] 迭代:003/003 | 批次大小 002 | 訓練/驗證損失:0.05
[GPU1] 訓練準確率 1.0
[GPU0] 訓練準確率 1.0
[GPU1] 測試準確率 1.0
[GPU0] 測試準確率 1.0

在多GPU訓練中,我們觀察到不同的GPU處理不同的批次,這有效地加速了訓練過程。然而,我們也注意到測試準確率被多個GPU重複輸出。這是因為每個GPU上的程式都獨立執行測試並輸出結果。

處理重複輸出

為瞭解決重複輸出的問題,我們可以根據程式的rank來控制輸出陳述式。例如,只有rank為0的程式才輸出測試準確率:

if rank == 0:
    print("測試準確率:", accuracy)
PyTorch的核心元件
  • 張量函式庫
  • 自動微分功能
  • 深度學習實用工具

多GPU訓練的替代API

除了DistributedDataParallel,還有其他的PyTorch API可以用於多GPU訓練,例如開源的Fabric函式庫。

程式碼範例與解析

以下是一個簡單的範例,展示如何使用PyTorch進行多GPU訓練:

import torch
import torch.distributed as dist
import torch.nn as nn

# 初始化分散式訓練環境
dist.init_process_group('nccl', init_method='env://')

# 定義模型和最佳化器
model = nn.Linear(5, 3)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

# 將模型轉換為DistributedDataParallel模式
model = nn.parallel.DistributedDataParallel(model)

# 進行訓練...

程式碼解密:

  1. dist.init_process_group('nccl', init_method='env://') 初始化分散式訓練環境,使用NCCL作為通訊後端。
  2. model = nn.parallel.DistributedDataParallel(model) 將模型包裝成DistributedDataParallel模式,以便在多個GPU上平行訓練。
  3. 在進行分散式訓練時,需要確保每個GPU上的模型引數和最佳化器狀態保持一致。

使用Plantuml圖表展示多GPU訓練架構

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 使用Plantuml圖表展示多GPU訓練架構

rectangle "控制" as node1
rectangle "處理" as node2
rectangle "結果" as node3
rectangle "更新引數" as node4

node1 --> node2
node2 --> node3
node3 --> node4

@enduml

此圖示展示了多GPU訓練的基本架構,其中主機程式控制多個GPU,每個GPU處理不同的資料分片,並將結果傳回引數伺服器進行引數更新。

圖表解密:

  • 主機程式負責協調和管理多個GPU的運算任務。
  • 每個GPU處理不同的資料分片,並將計算結果傳回給引數伺服器。
  • 引數伺服器匯總所有GPU的結果,並更新模型引數。
  • 更新後的引數被同步到各個GPU上,以確保下一次迭代的一致性。