天天看點

DataParallel 和 DistributedDataParallel 的差別和使用方法1.DataParallel2. DistributedDataParallel

1.DataParallel

DataParallel更易于使用(隻需簡單包裝單GPU模型)。

它使用一個程序來計算模型參數,然後在每個批處理期間将分發到每個GPU,然後每個GPU計算各自的梯度,然後彙總到GPU0中進行求平均,然後由GPU0進行反向傳播更新參數,然後再把模型的參數由GPU0傳播給其他的GPU。

特點:

(1)broadcast 的是模型的參數,是以速度慢,效率低

(2)操作簡單

是以通信很快成為一個瓶頸,GPU使用率通常很低。nn.DataParallel要求所有的GPU都在同一個節點上(不支援分布式),而且不能使用Apex進行混合精度訓練。

https://zhuanlan.zhihu.com/p/113694038

1.DistributedDataParallel支援模型并行,而DataParallel并不支援,這意味如果模型太大單卡顯存不足時隻能使用前者;

2.DataParallel是單程序多線程的,隻用于單機情況,而DistributedDataParallel是多程序的,适用于單機和多機情況,真正實作分布式訓練;

3.DistributedDataParallel的訓練更高效,因為每個程序都是獨立的Python解釋器,避免GIL問題,而且通信成本低其訓練速度更快,基本上DataParallel已經被棄用;

4.必須要說明的是DistributedDataParallel中每個程序都有獨立的優化器,執行自己的更新過程,但是梯度通過通信傳遞到每個程序,所有執行的内容是相同的;

2. DistributedDataParallel

https://pytorch.org/docs/stable/generated/torch.nn.parallel.DistributedDataParallel.html#torch.nn.parallel.DistributedDataParallel

官網連結

main_proc = True
    device = torch.device("cuda")
    is_distributed = os.environ.get("LOCAL_RANK")  # If local rank exists, distributed env
    print("distributed: ", is_distributed)

    if is_distributed:
        device_id = args.local_rank
        torch.cuda.set_device(device_id)
        print(f"Setting CUDA Device to {device_id}")

        os.environ['NCCL_IB_DISABLE'] = '0'
        dist.init_process_group(backend="nccl")
        print("distributed finished........")

        main_proc = device_id == 0  # Main process handles saving of models and reporting

		if is_distributed:
		        train_sampler = torch.utils.data.distributed.DistributedSampler(train_set, shuffle=True) 
		        #train_sampler = db2sampler(SequentialSampler(train_set), batch_size, False, bucket_size_multiplier=len(train_set)//batch_size) 
		 else:
		        train_sampler = torch.utils.data.RandomSampler(train_set)
		        #train_sampler = db1sampler(SequentialSampler(train_set), batch_size, False, bucket_size_multiplier=len(train_set)//batch_size)
		
	    train_loader = torch.utils.data.DataLoader(train_set, batch_size, sampler=train_sampler, num_workers=args.workers, collate_fn = pad_collate)
	    valid_loader = torch.utils.data.DataLoader(valid_set, valid_batch_size, num_workers=args.workers, collate_fn = pad_collate)
	if is_distributed:
        WAP_model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(WAP_model)  #解決了batchnormal的問題
    if is_distributed:
        WAP_model = torch.nn.parallel.DistributedDataParallel(WAP_model, device_ids=[device_id],find_unused_parameters=True)
	for eidx in range(max_epochs):
        n_samples = 0
        ud_epoch = time.time()

        if is_distributed:
            train_sampler.set_epoch(epoch=eidx) 

        for i, (x, y,x_idx, x_name) in enumerate(train_loader):
           	WAP_model.train()
           

注意:在 DataParallel 中,batch size 設定必須為單卡的 n 倍,但是在 DistributedDataParallel 内,batch size 設定于單卡一樣即可

比DataParallel,DistributedDataParallel訓練時間縮減了好幾倍。

一定要用DistributedDataParallel

if is_distributed:
            train_sampler.set_epoch(epoch=eidx)
           

https://zhuanlan.zhihu.com/p/97115875

pytorch(分布式)資料并行個人實踐總結

坑:

(1)DistributedDataParallel 内,batch size 設定于單卡一樣即可

繼續閱讀