Thomas Piacentini
← Workshop

Python exercise

CLIP symmetric contrastive loss

Original text · English30 min

CLIP trains an image encoder and a text encoder together. In a batch of N pairs, image i belongs with text i and with no other text. The loss pulls the matched pairs together and pushes the other N^2 - N pairs apart. Zero-shot classification and image search both use the embeddings that this loss trains.

Task

Write three functions.

  1. similarity_logits(image_emb, text_emb, temperature) returns the N \times N logit matrix.
  2. symmetric_infonce(logits) returns the symmetric contrastive loss as a float.
  3. symmetric_infonce_grad(logits) returns the gradient of that loss with respect to the logits.

Logits. Divide each image row and each text row by its L2 norm. Call the results \hat{I} and \hat{T}. The logits are

S = \frac{\hat{I} \hat{T}^\top}{\tau}

where \tau is the temperature. Row i holds image i against every text. Column j holds text j against every image.

Loss. The target of row i and of column i is index i, the diagonal.

\mathcal{L}_{img} = -\frac{1}{N} \sum_i \log \frac{e^{S_{ii}}}{\sum_j e^{S_{ij}}}, \qquad \mathcal{L}_{txt} = -\frac{1}{N} \sum_j \log \frac{e^{S_{jj}}}{\sum_i e^{S_{ij}}}
\mathcal{L} = \frac{\mathcal{L}_{img} + \mathcal{L}_{txt}}{2}

Gradient. Return \partial \mathcal{L} / \partial S with the same shape as logits. Let R be the softmax of each row of S, and C the softmax of each column of S. The gradient of one cross-entropy is its softmax minus the one-hot target.

Input and output

Name Type Shape Meaning
image_emb float array (N, d) one image embedding in each row
text_emb float array (N, d) one text embedding in each row, row i matches image i
temperature float \tau > 0, the logits are divided by it
logits float array (N, N) a logit matrix, rows are images and columns are texts
  • similarity_logits returns a float array of shape (N, N).
  • symmetric_infonce returns a Python float.
  • symmetric_infonce_grad returns a float array of shape (N, N).

Constraints

  • 1 <= N <= 256 and 1 <= d <= 512.
  • No embedding row is all zeros.
  • 0.01 <= temperature <= 1.
  • symmetric_infonce and its gradient get any finite logits, with absolute values up to 1000. The results must stay finite.
  • Do not change the input arrays.
  • Use numpy only.

Examples

python
image_emb = np.array([[1.0, 0.0], [0.0, 2.0], [1.0, 1.0]])
text_emb = np.array([[2.0, 0.0], [1.0, 1.0], [0.0, 3.0]])
logits = similarity_logits(image_emb, text_emb, 0.5)
text
[[2.         1.41421356 0.        ]
 [0.         1.41421356 2.        ]
 [1.41421356 2.         1.41421356]]
python
symmetric_infonce(logits)
symmetric_infonce_grad(logits)
text
0.9905556060000382
[[-0.13632819  0.09873442  0.02666175]
 [ 0.02666175 -0.23459891  0.19700514]
 [ 0.09873442  0.15772852 -0.23459891]]
python
symmetric_infonce(np.zeros((4, 4)))
text
1.3862943611198906
Code and artifacts 14
What you take away

Saved in your notebook on this device.

Sources and limits

Reading checkpoints are self-reported. Test results are recorded separately and apply to the executed cases.

AI Engineering from Scratch · 3f9715c · MIT

Download this file ↓