mirror of
https://github.com/openai/CLIP.git
synced 2026-11-05 01:37:26 +00:00
[GH-ISSUE #111] how to use multiple GPUs,the default is to use the first CUDA device #100
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
openai/CLIP#100
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @h13791565170 on GitHub (Jun 2, 2021).
Original GitHub issue: https://github.com/openai/CLIP/issues/111
the default is to use the first CUDA device if there is any, so,how to use Muti-GPU.I set up multiple GPUs, and it still only uses a single GPU
@vinson2233 commented on GitHub (Jun 4, 2021):
Are you working on single machine or multiple machine?
Have you tried the DataParallel or DistributedDataParallel from pytorch?
@vinson2233 commented on GitHub (Jun 4, 2021):
The simple way to utilize multiple GPU is using DataParallel on the CLIP model like this
and remove
.to(device)in your code since the DataParallel will handle how the data will be scattered across GPU.But this approach is troublesome for the ground_truth since if we pass 100 images on 10 GPU's, then each GPU only receive 10 pairs, and each GPU only return 10x10 cosine similarity matrices, joining the result and you will get 100x10 cosine similarity matrix instead of 100x100 matrix.
My approach is separate the image part and the text part, create data parallel for both of them. So the code goes like this :
@jongwook commented on GitHub (Jul 19, 2021):
The JIT model contains hard-coded CUDA device strings which needs to be manually patched by specifying the
deviceoption toclip.load(), but using a non-JIT model should be simpler. You can do that by specifyingjit=False, which is now the default inclip.load().Once the non-JIT model is loaded, the procedure shouldn't be any different from the standard PyTorch way.
DataParallelas in @vinson2233's example (thanks again!) provides a simpler interface to be used in a single process, e.g. in Jupyter notebook.DistributedDataParallelcan better utilize the GPUs by multiprocessing. Read this tutorial if interested.@nbl97 commented on GitHub (Sep 30, 2021):
@jongwook If I use DDP, one problem is that I have to use the logit_scale parameters outside the forward() function which occurs an error. Under DDP, I have to calculate the similarity outside the forward() function to gather all pairs on multi gpus first and then calculate similarity. Is there a solution? Thanks a lot !
@jongwook commented on GitHub (Sep 30, 2021):
You can put the logit_scale parameter as a single-element
nn.Parameterinside the module that DDP receives, and in each forward() you just need to calculate and return the losses corresponding to the local batch. This comment has an example.@nbl97 commented on GitHub (Sep 30, 2021):
@jongwook Sorry, I understand the clever batch sharding but I still wonder does the gradient is correct bacause all_gather() does not support backward function. Do I need to write backward myself?
Besides, I still don't know what is "put the logit_scale parameter as a single-element nn.Parameter inside the module that DDP receives". Is the code snippet(the mentioned comment) inside or outside the forward? If it is outside, the "some parameter used outside the forward" error still exists.
Last, I have a solution but I don't know whether it is correct, could you pls help me have a look at it?
In this way, the logit_scale is used inside the forward() and the logits_per_image/text are also correct.
The loss on all GPUs are the same, which is not so clever as batch sharding but still works. Is my solution right?
Thanks for your patience!
@jongwook commented on GitHub (Oct 1, 2021):
Your version will basically work! Backproping through all_gather will reduce the compute in the final matmul a little bit, but the majority of compute still happens in the encoders.
The following is a gist of what we were using for backproping through
all_gather; you basically need to callreduce_scatterwhich will calculate the sum of the incoming gradients from all nodes and return the same sum to every node, as if it had calculated the losses for the full batch without sharding.@Wuziyi616 commented on GitHub (Dec 4, 2021):
@nbl97 @jongwook Sorry for disturbing you, I compared some versions of the DDP training code of CLIP. The code presented here calculates logits of shape [local_batch, global_batch] (also here), while some other code calculates logits of shape [global_batch, global_batch]. I'm wondering if there are any difference between these two implementations?
According to my understanding of DDP, they are the same, because PyTorch will propagate and average gradient across GPUs, so only calculating [local_batch, global_batch] is enough. Another question is regarding the ground-truth labels used here, should it still be
torch.arange(B, dtype=torch.long, device=device), or we need to take the local_rank into consideration and usetorch.arange(B, dtype=torch.long, device=device) + B * args.local_rank? I look into theall_gatherdoc, it seems that the gathered tensors look the same on all gpus? Therefore, the correspondence is different in each GPU.Looking forward to your reply! Thanks in advance
EDIT: so I check the features and it seems that my understanding of GT labels is correct. And the loss seems good now.
@durianer-D commented on GitHub (Mar 8, 2022):
I found it necessary to use nn.Module packages CLIP into class. I failed, when I try to just use jit to work on Muti-GPU. But I succeeded, when I use nn.Module packages CLIP into class without jit.
@ajain625 commented on GitHub (Jan 24, 2023):
Would I be correct in believing that
ground_truth = torch.arange(BATCH_SIZE).to(device) # this one still need manually to put on GPUonly works if all batches are of the same size? That is, the total number of training examples is a perfect multiple of BATCH_SIZE?
Wouldn't a more general implementation may be
ground_truth = torch.arange(images.shape[0]).to(device) # this one still need manually to put on GPU@noitanec commented on GitHub (Dec 8, 2023):
@vinson2233 , Will this remain as it is (#83 ) or we're doing this separately for
model_text&model_imagein the training loop?