---
# System prepended metadata

title: CornerNet Embedding Loss閱讀理解

---

# CornerNet Embedding Loss閱讀理解

本文並未解釋其他部分的程式碼，請搭配網路上相關文章服用。
此文章為[CornerNet官方版本](https://github.com/princeton-vl/CornerNet)的Embedding Loss程式碼解讀。
程式碼段落來自：[princeton-vl/CornerNet/models/py_utils/kp_utils.py](https://github.com/princeton-vl/CornerNet/blob/e5c39a31a8abef5841976c8eab18da86d6ee5f9a/models/py_utils/kp_utils.py#L180)

```language-python
def _ae_loss(tag0, tag1, mask):
    num  = mask.sum(dim=1, keepdim=True).float() #num==正樣本個數
    tag0 = tag0.squeeze() #左上角的embedding值
    tag1 = tag1.squeeze() #右下角的embedding值

    tag_mean = (tag0 + tag1) / 2

    tag0 = torch.pow(tag0 - tag_mean, 2) / (num + 1e-4)
    tag0 = tag0[mask].sum()
    tag1 = torch.pow(tag1 - tag_mean, 2) / (num + 1e-4)
    tag1 = tag1[mask].sum()
    pull = tag0 + tag1

    mask = mask.unsqueeze(1) + mask.unsqueeze(2)
    mask = mask.eq(2)
    num  = num.unsqueeze(2)
    num2 = (num - 1) * num
    dist = tag_mean.unsqueeze(1) - tag_mean.unsqueeze(2)
    dist = 1 - torch.abs(dist)
    dist = nn.functional.relu(dist, inplace=True)
    dist = dist - 1 / (num + 1e-4)
    dist = dist / (num2 + 1e-4)
    dist = dist[mask]
    push = dist.sum()
    return pull, push
```

下面仔細解釋每行的意義：

```language-python
dist = tag_mean.unsqueeze(1) - tag_mean.unsqueeze(2)
```

利用pytorch的廣播機制製造每個元素對每個元素相減的效果。具體操作展示：

```language-python
import torch

a = torch.arange(5).view(1, -1) #shape:(object num, embedding value)
#a == tensor([[0, 1, 2, 3, 4]])
b = torch.ones(5).view(1, -1) #同上
#b == tensor([[1., 1., 1., 1., 1.]])

a.unsqueeze(1) - b.unsqueeze(2)
'''
tensor([[[-1.,  0.,  1.,  2.,  3.],
         [-1.,  0.,  1.,  2.,  3.],
         [-1.,  0.,  1.,  2.,  3.],
         [-1.,  0.,  1.,  2.,  3.],
         [-1.,  0.,  1.,  2.,  3.]]])
'''
a.unsqueeze(1) - a.unsqueeze(2)
'''
tensor([[[ 0,  1,  2,  3,  4],
         [-1,  0,  1,  2,  3],
         [-2, -1,  0,  1,  2],
         [-3, -2, -1,  0,  1],
         [-4, -3, -2, -1,  0]]])
'''
```

若是以batch為單位下去做的話：

```language-python
a = torch.arange(10).view(1, 5, -1) #shape:(batch size, object num, embedding channels)
'''
tensor([[[0, 1],
         [2, 3],
         [4, 5],
         [6, 7],
         [8, 9]]])
'''
b = torch.ones(10).view(1, 5, -1) #同上
'''
tensor([[[1., 1.],
         [1., 1.],
         [1., 1.],
         [1., 1.],
         [1., 1.]]])
'''
c = a.T.unsqueeze(1) - b.T.unsqueeze(2)
c.shape # torch.Size([2, 5, 5, 1])
c.squeeze(-1)
'''
tensor([[[-1., -1., -1., -1., -1.],
         [ 1.,  1.,  1.,  1.,  1.],
         [ 3.,  3.,  3.,  3.,  3.],
         [ 5.,  5.,  5.,  5.,  5.],
         [ 7.,  7.,  7.,  7.,  7.]],

        [[ 0.,  0.,  0.,  0.,  0.],
         [ 2.,  2.,  2.,  2.,  2.],
         [ 4.,  4.,  4.,  4.,  4.],
         [ 6.,  6.,  6.,  6.,  6.],
         [ 8.,  8.,  8.,  8.,  8.]]])
'''
c = a.T.unsqueeze(1) - a.T.unsqueeze(2)
c.squeeze(-1)
'''
tensor([[[ 0, -2, -4, -6, -8],
         [ 2,  0, -2, -4, -6],
         [ 4,  2,  0, -2, -4],
         [ 6,  4,  2,  0, -2],
         [ 8,  6,  4,  2,  0]],

        [[ 0, -2, -4, -6, -8],
         [ 2,  0, -2, -4, -6],
         [ 4,  2,  0, -2, -4],
         [ 6,  4,  2,  0, -2],
         [ 8,  6,  4,  2,  0]]])
'''
```

上面取得對其他embedding的dist方陣後，訓練目的是讓距離值小於1的（embedding值小於delta(1)）變大，且距離越接近0者應該越大。所以讓delta(1)被減去距離值，並用relu過濾掉負數。

```language-python
    dist = 1 - torch.abs(dist) #delta 論文中預設為 1
    dist = nn.functional.relu(dist, inplace=True) #使距離大於delta者不參與梯度下降。
```

這時會發現對角線全為delta(1)，但這個1是我們不需要的，為了除掉這個1，出現了我眼中最詭異的一步：

```language-python
    dist = dist - 1 / (num + 1e-4) #對全部元素減去 (delta / num)
    dist = dist / (num2 + 1e-4)
    dist = dist[mask] #只有前景需要學習embeding
    push = dist.sum()
```

num是正樣本個數。原本push會比預期值多出num\*delta，mask的True共num\*num個。
為了減去這個值，先對dist每個元素都減去delta / num。
但我很困惑，為什麼不使用mask連對角線也mask住就好？像是改成這樣：

```language-python
    dist = 1 - torch.abs(dist) #delta 論文中預設為 1
    dist = nn.functional.relu(dist, inplace=True) #使距離大於delta者不參與梯度下降。
    size = mask.shape[-1]
    mask[..., range(size), range(size)] = False 對角線設為False
    dist = dist[mask] #只有前景需要學習embeding
    push = dist.sum()/ (num2 + 1e-4)
```
