Created
April 13, 2021 19:52
-
-
Save ShairozS/1a5e6953f0533cf19240ae1473eaedde to your computer and use it in GitHub Desktop.
Contrastive loss
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class ContrastiveLoss(torch.nn.Module): | |
| """ | |
| Contrastive loss function. | |
| Based on: http://yann.lecun.com/exdb/publis/pdf/hadsell-chopra-lecun-06.pdf | |
| args: | |
| distance (function): A function that returns the distance between two tensors - should be a valid metric over R; default= L2 distance | |
| margin (scalar): The margin value between positive and negative class ; default=1.0 | |
| miner (function, optional): A function that calculates similarity labels [0,1] on the input if no labels are explicitly provided - should return (embs1, embs2, labels) | |
| """ | |
| def __init__(self, | |
| distance = lambda x,y: torch.pow(x-y, 2).sum(1), | |
| margin=1.0, | |
| miner=None): | |
| super(ContrastiveLoss, self).__init__() | |
| self.margin = margin | |
| self.distance = distance | |
| self.miner = miner | |
| self.reduction = reduction | |
| def forward(self, x, y, label=None): | |
| ''' | |
| Return the contrastive loss between two similar or dissimilar outputs | |
| Args: | |
| x (torch.Tensor) : The first input tensor (B, N) | |
| y (torch.Tensor) : The second input tensor (B,N) | |
| label (torch.Tensor, optional) : A tensor with elements either 0 or 1 indicating dissimilar or similar (B, 1) | |
| ''' | |
| assert x.shape==y.shape, str(x.shape) + "does not match input 2: " + str(y.shape) | |
| if self.miner is not None: | |
| x, y, label = self.miner(x,y) | |
| distance = self.distance(x,y) | |
| # When the label is 1 (similar) - the loss is the distance between the embeddings | |
| # When the label is 0 (dissimilar) - the loss is the distance between the embeddings and a margin | |
| loss_contrastive = torch.mean((label) * distance + | |
| (1-label) * torch.clamp(self.margin - distance, min=0.0)) | |
| return loss_contrastive |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment