Curricular Face 구현

Tetrapod·2024년 5월 27일

예전에 Curricular 관련 내용 중 구현된 코드를 찾을 수 없어 Tensorflow로 직접 구현했었다.
다시 정리하는 글을 쓰고자 한다.


  • ArcFace = 코사인 유사도에서 True class에 대하여 마진 패널티 추가
  • CurricularFace = ArcFace + (False class들 중에 hard sample 가중치 추가)

위와 같이 이해하였다.


코사인 유사도

  • 코사인 유사도는 내적 공식으로 부터 얻을 수 있다.
  • 내적 공식을 다음과 같다.
wx=w1x1+w2x2+...=wxcosθ\overrightarrow{w}\cdot\overrightarrow{x} = w_1x_1+w_2x_2+... = |w||x|cos\theta
  • 즉, 두 벡터간 코사인 유사도 값은 다음과 같다.
cosθ=wxwxcos\theta = \frac{\overrightarrow{w}\cdot\overrightarrow{x}}{|w||x|}
  • 내적 연산은 matmul 연산으로 가능하다.
  • 해당 코드 부분을 보면 다음과 같다.
x = tf.nn.l2_normalize(embedding, axis=1) # (N, dim)
w = tf.nn.l2_normalize(self._w, axis=0) # (dim, 10)
cosine_sim = tf.matmul(x, w) # (N, 10)

ArcFace (Positive Forward)

  • True에 해당하는 클래스 처리 방법이다.
  • 코사인 유사도 범위는 [-1, 1]이다.
  • 두 벡터의 각도가 0이면 1, π2\frac{\pi}{2}이면 0, π\pi이면 -1 이다.
  • 코사인 유사도는 위 코드와 같이 임베딩 벡터와 W벡터가 된다. (W는 학습파라미터)
  • 학습이 진행될 수록 W는 자리를 잡게 되고 그에 따라 임베딩도 변화한다.

  • 해당 코드 부분을 보면 다음과 같다.
def positive_forward(self, y_logit):
	cosine_sim = y_logit 
	theta_margin = tf.math.acos(cosine_sim) + self.margin
	y_logit_pos = tf.math.cos(theta_margin)
	return y_logit_pos

Negative Forward

  • False에 해당하는 클래스들의 처리방법이다.
  • 마진을 추가하여 조정한 positive의 코사인 유사도 보다 False에 해당하는 class의 코사인 유사도가 높으면 그 해당 데이터는 hard sample로 간주한다.
  • hard sample에 대한 negative forward의 수식이 바뀌는데 다음과 같다.

  • 해당 코드 부부을 보면 다음과 같다.
def negative_forward(self, y_logit_pos_masked, y_logit):
	hard_sample_mask = y_logit_pos_masked < y_logit # (N, n_classes)
	y_logit_neg = tf.where(hard_sample_mask, tf.square(y_logit)+self.t*y_logit, y_logit)
	return y_logit_neg

적응형 t 변수

  • positive에 대한 코사인 유사도 값이 높을수록 t 변수는 높게 조정되어 Negative Forward에서 hard sample에 대한 가중치가 강화된다.
  • t 변수 수식은 다음과 같다.


softmax head

  • 코사인 유사도 범위는 [-1, 1]이므로 이를 바로 softmax 계산하면 좋지 않다.
  • 따라서 보통 30 정도 scale 값을 곱해준다.
  • 여기서 더 작은 값을 곱하면, calibration 효과가 있다고 한다.


Softmax VS Softmax with CurricularFace

  • 오른쪽이 curricular_face를 적용한 결과이다.
  • 자세한 코드는 아래 깃허브 참조


Reference

0개의 댓글