2020-04-10 14:36:18

CNN 모델을 훈련시키는 과정을 같이 한번 생각해보겠습니다. CNN 모델을 훈련시킨다는 것은 최적의 모델 가중치들을 찾아가게 한다는 것입니다. 최적의 가중치는 손실함수(loss function)를 0에 가깝게 만들기 만들기 때문에, 모델의 가중치는 훈련 과정을 통해 손실함수를 0에 가까워지게 하는 방향으로 갱신됩니다. 또한 이렇게 훈련된 모델의 성능을 검증셋에서 평가할 때는 평가지표(metric)가 사용됩니다. 손실함수와 평가지표에 대해서 이해가 필요하신 분은 링크를 참고해주세요.

 

keras는 손실함수와 평가지표로 사용할 수 있는 함수로 MSE, MAE, categorical crossentropy 등을 지원합니다. 그런데 만약 keras에서 지원하지 않는 피어슨 상관계수를 손실함수나 평가지표로 사용하고 싶다면 어떻게 해야할까요? 그렇다면 저희가 직접 만들어야 합니다. 어떻게 만들까요?

 

직접 만들기 전에 누군가 이것을 고민하고 만들어본 사람이 있었는지 찾아보는 것이 좋습니다. 시간과 에너지를 아끼기 위해서죠. 웹상에서 검색해봤더니 역시 stackoverflow에 답이 있었습니다[3]. stackoverflow는 개발자들의 네이버지식인과 같은 공간입니다. 많이 애용하시는 것을 추천드립니다. 그 답을 참고해서 피어슨 상관계수를 손실함수 또는 평가지표로 사용하는 법에 대해 알려드리도록 하겠습니다. 

 

1. 피어슨 상관계수를 손실함수로 사용하기

우선 피어슨 상관계수에 대해 간략히 설명을 드리는 것이 필요할 것 같습니다. 피어슨 상관계수는 두 변수의 상관정도를 판단하는데 사용되는 지표입니다. PCC라고 불리기도 하고, PLCC로 불리기도 합니다. 피어슨 상관계수는 -1에서 1사이의 값을 갖습니다. 

 

$-1 \leq PLCC \leq 1$

 

양의 선형성이 크면 클수록 피어슨 상관계수는 1에 가까워지고, 음의 선형성이 크면 클수록 -1에 가까워집니다. 그리고 선형관계가 작으면 작을수록 0에 가까워집니다. 양의 선형성이 크다는 것은 라벨값이 커질 때 예측값도 커지는 경향이 있다는 것입니다. 반대로 음의 선형성이 크다는 것은 라벨값이 커질 때 예측값은 반대로 작아지는 경향이 있다는 것입니다. 

 

따라서 1에 가깝거나 -1에 가깝다면 라벨값과 예측값이 큰 상관관계를 갖는다는 뜻이므로, 그것이 훈련에서 지향하는 방향이 되어야 합니다. 그런데 손실함수는 훈련이 되어갈수록 0에 가깝게 되게 만들어줘야 합니다. 따라서 피어슨 상관계수를 제곱한 것을 1에서 빼줍니다. 그러면 상관관계가 크면 클수록 손실함수는 0으로 수렴하게 되겠죠. 아래 코드가 바로 이것을 반영한 것입니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
from tensorflow.keras import backend as K
 
def plcc_loss(y_true, y_pred):  
    x = y_true
    y = y_pred
    mx = K.mean(x)
    my = K.mean(y)
    xm, ym = x-mx, y-my
    r_num = K.sum(tf.multiply(xm,ym))
    r_den = K.sqrt(tf.multiply(K.sum(K.square(xm)), K.sum(K.square(ym)))) + 1e-12
    r = r_num / r_den
    r = K.maximum(K.minimum(r, 1.0), -1.0)
    return 1 - K.square(r) 
cs

 

2. 피어슨 상관계수를 평가지표로 사용하기 

피어슨 상관계수를 평가지표로 사용할 때는 굳이 상관관계가 강할 때 0에 가깝게 되도록 만들 필요가 없습니다. 원래대로 -1과 1사이의 값이 출력되도 됩니다. 모델의 가중치 갱신에 직접 관여하는 것이 아니라, 훈련이 제대로 되고 있는지 모니터링하는데 사용되기 때문입니다. 따라서 위 코드 블럭에서 아래 두 줄은 제외해줘도 됩니다. 

 

1
2
3
4
5
6
7
8
9
def plcc_metric(y_true, y_pred):  
    x = y_true
    y = y_pred
    mx = K.mean(x)
    my = K.mean(y)
    xm, ym = x-mx, y-my
    r_num = K.sum(tf.multiply(xm,ym))
    r_den = K.sqrt(tf.multiply(K.sum(K.square(xm)), K.sum(K.square(ym)))) + 1e-12
    return r_num / r_den
cs

 

이제 손실함수와 평가지표에 대한 함수를 선언했으므로, 이제 compile 메소드의 loss는 plcc_loss로, metrics는 plcc_metric으로 설정해주면 됩니다. 다음과 같이 말이죠. 

 

1
model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.01), loss=plcc_loss, metrics=[plcc_metric])
cs

 

필요에 따라 피어슨 상관계수를 손실함수로만 사용해도 되고, 평가지표로만 사용해도 됩니다. 잇츠업투유.

 

도움이 되셨길 바라며, 글을 마무리하겠습니다. 항상 질문과 지적은 환영입니다. 빠르게 답변드리도록 노력하고 있으니, 댓글로 남겨주세요.^^ 

 

 

<참고자료>

[1] https://keras.io/ko/metrics/, Keras documentation, "측정항목의 사용법"

[2] https://keras.io/backend/, Keras documentation, "Keras Backend"

[3] https://stackoverflow.com/questions/46619869/how-to-specify-the-correlation-coefficient-as-the-loss-function-in-keras