[feat] Add gather_across_devices parameter to some contrastive losses#3442
Conversation
…STEmbedLoss The first two give more control over the anchor-anchor and positive-positive contrastion, whereas the last one allows you to gather the positives (and negatives) across devices
…ISTEmbedLoss The first two allow you to add more detail to your loss: sometimes setting them to False can improve retrieval performance. The gather_across_devices helps a lot with multi-gpu training
There was a problem hiding this comment.
Pull Request Overview
This PR adds distributed training support to contrastive losses by implementing gather_across_devices functionality and adds utility functions for distributed all-gathers. The main purpose is to enable larger effective batch sizes across multiple GPUs during contrastive learning by gathering embeddings from all devices before computing the loss.
Key changes include:
- Addition of distributed all-gather utility functions (
all_gather,all_gather_with_grad) - Implementation of
gather_across_devicesparameter across multiple contrastive loss classes - Addition of
contrast_anchorsandcontrast_positivesparameters to GIST losses for more flexible training
Reviewed Changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| sentence_transformers/util.py | Adds distributed all-gather utility functions and removes unused logging utilities |
| sentence_transformers/trainer.py | Simplifies evaluation logic by removing conditional logging wrapper |
| sentence_transformers/losses/*.py | Implements gather_across_devices functionality across 8 loss classes |
| sentence_transformers/sparse_encoder/losses/*.py | Adds gather_across_devices support to sparse encoder losses |
|
I've decided to leave this item for a follow-up PR to avoid expanding the scope of this PR too much:
With all of these losses tested (at least, checked that they perform better with gathering, ran without crashes, etc.), I'm ready to merge this. The test failures are related to the datasets v4 release, and the issues were fixed in #3445. I'll merge those into this branch first.
|
|
Hi, thank you for the great work on this project. While reviewing the implementation of In particular, the code computes labels as: if torch.distributed.is_initialized():
rank = torch.distributed.get_rank()
offset = rank * batch_size
labels = torch.arange(offset, offset + batch_size, device=anchors.device)However, if candidates are constructed using |
|
Not sure I get you correctly, but essentially since we are only gathering the queries, this offset is meant to align those with their corresponding positive documents, which as you pointed out are always the first n documents (because we concatenate the positive and then the negatives). |
|
I think @Batwu might be on to something though, although I'm not 100% sure yet. If we have e.g. 1 positive and 8 negatives with 4 devices, then the But the offsetting with instead of offsetting by I'll have to do some more tests, but I think it's likely that the tests I ran only used an anchor and positive, and no negatives. Otherwise I would have noticed a degradation in performance presumably.
|
|
That is actually totally true, I am very sorry I had the PyLate implementation in mind, where you can see that we do not concatenate the positives/negatives before gathering the elements (the "concatenation" is done at the score level), which in this case create PPPNNNNNNNN. Again, deeply sorry @Batwu, should have checked the code of Tom instead of answering based on the code used as base. |
Reverts part of huggingface#3442 cc @arthurbr11
Reverts part of #3442 cc @arthurbr11
Hello!
Pull Request overview
gather_across_devicesto MNRL and CMNRL, etc.contrast_anchorsandcontrast_positivesto GIST and CGIST lossesDetails
This is a work-in-progress. The goal of this PR is to introduce gathering across devices, as @NohTow showed that it was still worthwhile despite the same also being possible with GradCache. Also thanks to @NohTow for writing the code that this PR is based on & for helping debugging.
TODOs:
For Reranker: Rerankers don't benefit from cross-device gathering as they require computing per pair.util.pyinto autilfolder with files for separate components, e.g.negative_mining.py,distributed.py,similarity_functions.py,huggingface.py, etc. It's getting too big.