CenterLoss는 랜덤으로 정의한 각 클래스 중심으로 부터 샘플이 멀수록 패널티를 주어 클래스간 분리성과 클래스 내의 분산을 줄이는 방법으로 학습되도록 돕는다(Seperable Inter-Class differences and Minimizing Intra-Class variations)
Center Loss의 식을 구성하는 각 원소는 아래와 같은 차원을 지닌다.
x : (Batch_Size(32), feat_dim(2))
c_yi : (num_classes(10), feat_dim(2)) 의 사이즈를 지닌다.
각 원소의 사이즈가 위와 같을 때 아래의 빨간 박스 부분을 어떻게 코드로 구현하는지 살펴본다.
위의 식을 풀어 쓰면 아래와 같다
(1) 먼저 $x_i$(32 x 2)를 제곱한다 --> 열 방향으로 더한다(32 x 1) --> (batch_size, num_classes)로 늘려서 (32 x 10) 사이즈가 되게 한다 : $x_i^2$ 계산
(2) $c_{yi}$(10 x 2)를 제곱한다. --> 열 방향으로 더한다(10 x 1) --> (num_classes, batch_size)로 늘려서 (10 x 32)가 되게 한다 : $c_{yi}^2$ 계산
(3) (2)에서 구한 식을 Transpose해서 (1)에 더한다.
(4) 이후 파이토치 .addmm_ 매소드를 이용해서 $x_i$ (32 x 2)와 $c_{yi}$ (10 x 2) 를 곱해서 (32 x 10)이 되게 한다. 그리고 (3)에서 나온 결과와 더한다. $ -2 * x_{i}^2 * c_{yi}^2 $ 계산
(※ (1) ~ (4) 과정을 거치면 샘플 (32개)각 각 클래스에 대해 계산한 거리가 나온다.
★★이 때 올바른 클래스의 중심으로 다가가길 희망하므로(Minimizing Intra-Class variations) 정답 라벨의 거리만 사용한다. 따라서, 아래의 과정을 진행한다.)
(5) [32] 사이즈의 샘플 라벨을 [32, 10] Boolean One-hot 으로 만든다.
(6) Boonlean One-hot 마스킹과 위에서 구한 거리 행렬을 곱한다.
(7) 32개 원소를 다 더한 후 Batch_size 로 나눠 로스 값 평균을 구한다
batch_size = x.size(0)
# (1) (2) (3)
distmat = torch.pow(x, 2).sum(dim=1, keepdim=True).expand(batch_size, self.num_classes) + \
torch.pow(self.centers, 2).sum(dim=1, keepdim=True).expand(self.num_classes, batch_size).t()
# (4)
distmat.addmm_(x, self.centers.t(), beta=1, alpha=-2)
# (5)
classes = torch.arange(self.num_classes).long()
labels = labels.unsqueeze(1).expand(batch_size, self.num_classes) # [32] -> [32, 1] -> [32, 10]
mask = labels.eq(classes.expand(batch_size, self.num_classes))
#(6)
dist = distmat * mask.float() # (32, 10) * (32, 10) element-wise 곱
#(7)
loss = dist.clamp(min=1e-12, max=1e+12).sum() / batch_size
'데이터 과학 > 딥러닝(Deep Learning)' 카테고리의 다른 글
Triplet Loss 구현 (0) | 2022.06.09 |
---|---|
LSTM Autoencoder 설명 (0) | 2021.05.28 |
공분산(Covariance) 정리 (0) | 2021.02.12 |
PCA(주성분 분석) 정리 (0) | 2021.02.10 |
Autoencoder 설명 (0) | 2021.02.06 |