Effective Negatives from Sharded Contrastive Batches
Problem Statement
Contrastive learning lives or dies by the number of negatives each example sees. When training data-parallel across devices, whether an example sees negatives from other devices depends on whether embeddings are all-gathered. Compute the number of negatives per positive under both regimes.
Background
Let per_device be the local batch size and world_size the number of devices, so the global batch is G = per_device * world_size. For any anchor image, its one matching text is the positive; every other text in the compared set is a negative.
- With all-gather (CLIP/SigLIP as published): each anchor is compared against the global batch, so it sees G - 1 negatives.
- Without all-gather (naive local loss): each anchor only sees its device's per_device texts, i.e. per_device - 1 negatives.
Your Task
Implement:
def effective_negatives(per_device, world_size):
Return a dict with "global_batch", "neg_with_gather", "neg_local", "gain" where gain = neg_with_gather / neg_local rounded to 4 decimals (gain is 0.0 if neg_local is 0).
Input Format
- per_device (int), world_size (int).
Output Format
- A dict: three ints and one float.
Sample
print(effective_negatives(256, 8))
Output:
{'global_batch': 2048, 'neg_with_gather': 2047, 'neg_local': 255, 'gain': 8.0275}
Example
print(effective_negatives(256, 8))
{'global_batch': 2048, 'neg_with_gather': 2047, 'neg_local': 255, 'gain': 8.0275}- Calculate the global batch size by multiplying the local batch size by the number of devices: .
- Determine the number of negatives when using all-gather, which is the global batch size minus the anchor's own positive pair: .
- Determine the number of negatives in the local regime, which is the local batch size minus the anchor's own positive pair: .
- Compute the gain by dividing the global negatives by the local negatives and rounding to four decimal places: .
- The final output is
{'global_batch': 2048, 'neg_with_gather': 2047, 'neg_local': 255, 'gain': 8.0275}.
Constraints
1 <= per_device <= 100000,1 <= world_size <= 4096.neg_with_gather = global_batch - 1,neg_local = per_device - 1.gainrounded to 4 decimals;0.0whenneg_local == 0.