안녕하세요 ! 지난 번 포스팅에서 작성했던 Linear Classifier에 이어서 설명드리겠습니다 !
위의 학습 자료는
임의의 가중치 행렬 W를 가지고 예측한 10개의 클래스 스코어입니다.
(이 때 스코어는 확률이 아닙니다 !)
굵게 표시한 스코어는 해당 이미지의 정답 클래스를 표시한 것입니다.
왼쪽 고양이 사진을 보면 우리는 당연히 '고양이(cat)'로 구분할 수 있지만, 컴퓨터는 그렇지 않습니다. 가장 높은 스코어는 '강아지(dog)' 클래스네요.
중간에 있는 자동차 이미지는 잘 분류되었지만, 오른쪽 개구리 이미지도 잘못 분류되어있는 것을 확인할 수 있습니다.
그렇다면 이 분류기는 성능이 좋은 분류기라고 할 수 없습니다.
(잘 분류하지 못하니까요!)
어찌보면 당연한 일입니다. 우리는 가장 좋은 W를 선별해서 사용한 것이 아닌,
'임의의' W를 사용했기 때문이죠.
어떤 W가 가장 좋은 지 결정하기 위해서
지금 만든 W가 좋은 지, 나쁜 지 정량화할 방법이 필요합니다.
이 때 필요한 것이 바로 "손실 함수(Loss function)" 입니다.
W를 입력으로 받아서 클래스의 각 스코어를 확인하고,
이 W가 얼마나 나쁜 지 정량적으로 나타내는 것
이번 포스팅에서는 Image Classification에서 사용하는 몇 가지 손실 함수를 소개해드리겠습니다.
이를 실제 상황에 적용해보면,
손실 함수는 행렬 W가 될 수 있는 모든 경우의 수에 대해서
"가장 덜 나쁜" W가 무엇인 지 찾는 것
이 바로 손실 함수의 역할입니다.
'나쁘다'는 것은 '얼마나 분류를 못하는 지'를 뜻합니다.
클래스의 개수가 3개인 새로운 예시입니다.(위의 예시와 다른 예시입니다 !)
이 예제에서는 '고양이' 클래스는 잘 분류되지 못했고, '자동차' 클래스는 잘 분류되었으며, '개구리' 클래스는 정말 최악이네요. 정답 클래스임에도 가장 최저 스코어를 갖습니다.
오른쪽에 있는 수식들을 보겠습니다. 뜬금없는 영어와 수식에 놀라지 마세요. 하나하나 차근차근 살펴보면 우리가 이미 다 알고있는 것들입니다!
한 번 뜯어보겠습니다 !
트레이닝 데이터 x, y
x : Image (이미지)
y : Label or target
(예측하고자 하는 것 - Image Classification에서는 입력된 이미지의 클래스)
만약 CIFAR-10 예제라면 레이블 Y는 1에서 10 사이의 정수값이 됩니다.
클래스(분류해야할 카테고리)가 총 10개이니까요!
(프로그래밍 언어에 따라 0에서 9사이의 정수값이 될 수도 있습니다)
그렇다면 지금 다루고 있는 예시에서 레이블 Y는 1에서 3사이의 정수값이 됩니다.
(프로그래밍 언어에 따라 0에서 2사이의 정수값이 될 수도 있구요!)
예측 함수
입력 이미지 x와 행렬 W를 받아서 y를 예측하는 함수
CIFAR-10 예제의 경우 Y는 10개가 됩니다.클래스(분류해야할 카테고리)가 10개니까요!
손실 함수
예측 함수 f와 정답값 y를 받아 트레이닝 샘플을 얼마나 나쁘게 예측하는 지 정량화
N : 샘플(이미지)의 개수
최종 Loss는 샘플들의 각각의 Loss값의 합을 샘플의 개수(N)만큼 나눈 평균값입니다.
이 수식은 가장 일반적인 Loss function입니다. Image Classification 외에도 확장해서 사용할 수 있습니다. 확장하는 방법은 강의에서 다루지 않았기 때문에 넘어가겠습니다 !
그렇다면 어떤 손실 함수가 있는 지 알아보겠습니다 !
여러 클래스를 다루기 위한 이진 Support Vector Machine의 일반적인 형태
(이진 SVM에 관한 내용을 알지 못해도 이해하실 수 있습니다!)
위 수식은 SVM 에서 Loss를 구하는 방법이며, 아래 수식은 위 수식의 s를 나타냅니다.
s : prediction function을 통해 예측된 스코어
yi : 이미지의 정답 클래스(1~3 정수값)
따라서, s_yi 는 i번째 이미지(샘플)의 정답 클래스의 스코어입니다.
j : 이미지의 오답 클래스(1~3 사이의 정수값 중 정답 클래스가 아닌 값)
(예를 들어 고양이 이미지의 경우, 고양이 클래스가 1이라면 yi = 1, j= 2,3)
따라서, s_j는 i번째 이미지(샘플)의 오답 클래스의 스코어입니다.
한 이미지의 Loss(L_i)를 구하기 위해, 정답 클래스를 제외한 나머지 클래스(오답 클래스들)의 Loss들을 모두 더하는 방식입니다.
개별 클래스의 Loss를 구하는 방식은 다음과 같습니다.
1) 정답 클래스의 스코어와 오답 클래스 합의 스코어를 비교합니다.
고양이 클래스의 스코어와 자동차 클래스의 스코어,
고양이 클래스의 스코어와 개구리 클래스의 스코어를 비교합니다.
2) 만약 정답 클래스의 스코어가 오답 클래스의 스코어보다 더 높으면,
+ 그 격차가 일정 마진(safety margin, 1) 이상이라면,
정답 클래스의 스코어가 다른 오답 스코어보다 훨씬 크다는 것을 의미합니다.
고양이 클래스의 스코어가 자동차(개구리) 클래스의 스코어보다 1 이상 크면,
고양이 클래스의 스코어가 자동차(개구리) 클래스의 스코어보다 훨씬 크다는 것을 의미합니다.
단순히 크기가 큰 것에 넘어서 1이라는 차이를 둘 정도로 크다는 것이니까요!
Safety Margin
정답 클래스의 스코어는 오답 클래스의 스코어들 보다 훨씬 높아야 합니다.
충분히 높지 않으면 Loss값이 높아지게 됩니다.
이 safety margin을 '확신의 정도' 라고 이해하시면 조금 더 와닿으실거에요!
개구리 스코어와 고양이 스코어가 비슷하다는 건 개구리일 수도 고양이일 수도 있다는 것인데, 확신을 갖지 못하고 헷갈려한다는 뜻이죠.
그러니 고양이 스코어가 훨씬 높다는 건 이 이미지를 확실히 고양이라고 분류하겠다는 겁니다.
Safety Margin을 정하는 방법
우리가 궁금한 건 여러 Loss간의 "상대적인 차이"입니다.
오로지 정답 클래스의 스코어가 오답 클래스의 스코어들에 비해 얼마나 더 큰 스코어를 갖고 있는 지에 관심을 둡니다.
라고 강의에서 설명했는데, 아마 safety margin이 몇인지는 크게 중요하지 않다는 뜻인 것 같습니다 ! 혹시 이유를 아시는 분은 댓글로 남겨주세요 !
3) 그렇게 되면 Loss는 0가 됩니다. 정답을 맞췄다는 뜻이죠.
고양이 클래스의 스코어가 자동차(개구리) 클래스의 스코어보다 훨씬 크다는 것은
고양이 이미지가 고양이 클래스일 것이라고 분류한 것이기 때문에 정답을 맞춘 것입니다.
4) 오답 클래스들의 Loss를 합치면 그 값이 바로 한 이미지(샘플)의 최종 Loss값입니다.
고양이 클래스 스코어와 자동차 클래스 스코어를 비교했을 때 나온 Loss값과
고양이 클래스 스코어와 개구리 클래스 스코어를 비교했을 때 나온 Loss값을
더하면 고양이 이미지에 대한 최종 Loss값이 계산됩니다.
이걸 수식화시키면 다음과 같은 수식(if-then)으로 나타낼 수 있습니다.
if : 정답 클래스의 스코어가 가장 높으면
then : max( 0, s_j - s_yi + 1(safety margin) )
0과 s_j - s_yi + 1를 비교해서 더 큰 값을 출력
이렇게 구한 모든 샘플의 Loss들의 평균을 계산해 전체 데이터셋의 Loss를 구합니다.
이런 류의 손실 함수를 'hinge loss'라고 부릅니다. 그래프의 모양때문에 붙여진 이름입니다.
여기서 x축은 s_yi(정답 클래스의 스코어)이며, y축은 Loss값입니다.
정답 스코어가 증가할 수록 Loss가 선형적으로 줄어드는 것을 알 수 있습니다.
이 Loss는 0이 되어도 safety margin을 넘어설때까지 줄어듭니다.
Loss가 0이 되었다는 것은 정답을 잘 맞췄다는 것을 의미합니다.
글자로만 읽으니 많이 복잡하실 것 같은데요. 계산을 한 번 해보면 이해에 큰 도움이 됩니다!
고양이 이미지의 Loss값을 구해보겠습니다.
자동차(car) 클래스의 스코어가 가장 높은 것을 보니 분류가 제대로 되어있지 않습니다.
과연 고양이 이미지는 Loss값이 얼마나 나올까요?
1) 고양이 클래스 스코어(3.2)와 자동차 클래스 스코어(5.1)를 비교합니다.
5.1 - 3.2 + 1(safety margin) = 2.9
2) 고양이 클래스의 스코어가 자동차 클래스의 스코어보다 safety margin 이상으로 더 높은지 확인합니다.
고양이 클래스의 스코어가 자동차 클래스의 스코어보다 safety margin 이상으로 작기 때문에 양수 2.9가 도출됩니다. 이는 0과 비교했을 때 큰 값이므로 자동차 클래스와의 Loss값이 됩니다.
3) 고양이 클래스 스코어(3.2)와 개구리 클래스 스코어(-1.7)를 비교합니다.
-1.7 - 3.2 + 1 = -3.9
4) 고양이 클래스의 스코어가 개구리 클래스의 스코어보다 safety margin 이상으로 더 높은지 확인합니다.
고양이 클래스의 스코어가 개구리 클래스의 스코어보다 safety margin 이상으로 더 높기 때문에 음수 -3.9가 도출됩니다. 이는 0과 비교했을 때 작은 값이므로 개구리 클래스와의 Loss는 0이 됩니다.
5) 위에서 구한 두 Loss값을 더해 고양이 이미지의 최종 Loss값을 구합니다.
2.9 + 0 = 2.9
이렇게 보니 간단하지 않나요?
어쩔 땐 말로 풀어보는 것보다 바로 수식을 통해 이해하는 것이 좋은 것 같습니다 ㅎㅎ
자동차와 개구리 이미지의 경우도 위와 같은 방식으로 Loss값을 구할 수 있습니다.
자동차 이미지의 Loss는 0, 개구리 이미지의 Loss는 12.9가 계산됩니다.
자동차는 분류를 제대로 진행했고, 개구리는 최악의 분류였다는 것을 떠올려보면 Loss가 이를 잘 반영한 것 같습니다 ㅎㅎ
분량 조절을 위해 과정은 생략하겠습니다! (직접 계산해보시는 걸 추천합니다!)
그렇다면 우리가 가진 트레이닝셋(고양이, 자동차, 개구리 이미지)의 최종 Loss는 어떻게 되는 걸까요?
개별 샘플의 Loss값들의 평균이라고 했으니
최종 Loss값은 (2.9 + 0 + 12.9) / 3 = 5.27 이 됩니다 !
이는 즉, 우리의 분류기가 5.3만큼 나쁘게 트레이닝셋을 분류하고 있다는 '정량적 지표'입니다.
이를 numpy 코드로 구현해보면 아래와 같습니다.
def L_i_vectorized(x, y, W):
scores = W.dot(x)
margins = np.maximum(0, scores - scores[y] + 1)
margins[y] = 0
loss_i = np.sum(margins)
return loss_i
강의시간에 나온 Q&A를 살펴보겠습니다.
Q1. 자동차 클래스의 스코어가 조금 변한다면 Loss값에도 변화가 있을까?
A : 자동차 클래스의 스코어는 이미 다른 클래스들의 스코어보다 매우 높기 때문에 자동차 클래스의 스코어를 조금 바꾼다고 해도 각 스코어간의 간격(margin)은 유지되기 때문에 Loss는 변하지 않습니다.
Q2. Loss값의 최솟값과 최댓값은?
A : 손실 함수가 Hinge Loss 모양이라는 것을 떠올려 보면 쉽게 답할 수 있습니다.
최솟값은 0이 되며 최댓값은 무한대가 됩니다.
Q3. 모든 클래스의 스코어가 0에 가깝고, 값이 서로 거의 비슷하다면?
A : 클래스 개수 - 1
모든 클래스의 스코어가 0에 가까운 수라고 가정했기 때문에,
위의 예시에서 s_yi, s_j 모두 0을 대입해 계산을 진행해보겠습니다.
max(0, 0-0+1) + max(0, 0-0+1)
= max(0, 1) + max(0, 1)
= 1 + 1
= 2
(클래스 개수 -1)인 2가 도출되었습니다.
Q4. Loss를 계산할 때 정답 클래스도 포함하여 계산한다면?
A : 1이 더해지기 때문에 평균값인 최종 Loss값에 1이 더해집니다.
정답 클래스를 계산해보면 아래와 같이 1이 도출됩니다.
max(0, s_yi - s_yi + 1)
= max(0, 1)
= 1
이 값이 더해지기 때문에 최종 Loss값에도 1이 더해집니다.
즉, Loss의 최솟값은 1이 됩니다.
Loss가 0이 되어야 우리가 결과를 해석할 때 직관적으로 받아들이기 쉽기 때문에 정답 클래스를 제외하고 계산을 진행합니다.
Q5. Loss에서 전체 합을 구하는 게 아니라 평균을 구한다면?
A : 별다른 영향을 미치지 않습니다.
위에서도 언급했듯 우리는 클래스 스코어의 값이 몇인지는 신경쓰지 않습니다.
스코어간의 간격, 스코어간의 상대적인 차이가 관건이기 때문입니다.
평균값으로 만들어주는 건 그저 스코어들의 범위를 조정해주는 행위일뿐입니다.
Q6. 손실 함수를 제곱항으로 바꾼다면?
기존의 방식은 선형 방식이었습니다. 이를 제곱해주면 비선형 방식으로 바뀌는 것이기 때문에 스코어가 정답에서 멀어질수록 Loss가 급격하게 증가합니다.
이러한 방식은 잘못된 예측에 패널티를 더 많이 주기 위해 사용합니다.
Q7. Loss가 0이 되게 하는 W는 하나뿐일까?
A : 다른 W도 존재합니다. W의 범위는 변하기 때문에 W에 2배를 한다고 해도 Loss값은 변하지 않습니다.
위 예시에서 보이는 노란색 표시는 W와 2W를 비교한 부분입니다.
정답 클래스 스코어와 오답 클래스 스코어 차이의 간격(Margin)또한 2배가 되는 것을 확인할 수 있습니다.
그러니 모든 간격이 1보다 크다면(s_yi가 s_j보다 1보다 크다면),
W가 2W가 되어도 여전히 1보다 클 것이고 Loss값은 0이 될 것입니다.
여기서 흥미로운 점은
만약 손실 함수가 Loss를 0으로 만들어주는 특정 W를 찾아주는 것이라면,
다양한 W 중 하나를 선택하는 것은 모순입니다.
왜냐하면 여기에서는 오직 데이터의 Loss에만 신경쓰고 있고,
분류기에게 트레이닝 데이터에 꼭 맞는 W를 찾으라는 것과 같기 때문입니다.
하지만 실제로 트레이닝 데이터에 얼마나 잘 맞는지는 중요하지 않습니다.
테스트 데이터에 얼마나 잘 맞는지가 중요하기 때문입니다.
이를 설명하기 위해 새로운 예시를 들어보겠습니다.
여기 파란점의 데이터셋이 있습니다.
우리는 어떠한 곡선을 가지고 저 파란색 데이터를 학습시킵니다. 우리가 분류기에게 말할 수 있는 것은 그저 트레이닝 데이터(파란색 점)에 잘 맞게 학습하라고 하는 것입니다.
그러면 분류기는 모든 트레이닝 데이터를 완벽하게 분류해내기 위해 구불구불한 곡선을 만들 것입니다.
하지만 이렇게 학습한 분류기를 테스트 데이터(초록색 점)에 적용하면 곡선은 테스트 데이터를 잘 구분하지 못합니다.
사실 우리가 의도했던 건 초록색 선입니다.
이러한 것을 보완하기 위해 손실 함수에 항을 하나 추가합니다.
보통 손실 함수에 Regularization term을 추가하는데,
이는 모델이 좀 더 단순한 W를 선택하는 데에 도움을 줍니다.
Occam's Razor(오컴의 면도날)
"Among competing hypotheses, the simplest is the best"
학습 자료 우측 하단에 있는 오컴의 면도날은
만약 가지고 있는 다양한 가설들 모두가 어떤 현상에 대해 설명이 가능하다면,
일반적으로 '더 단순한 것'을 선호해야 한다는 것입니다.
왜냐하면 더 단순한(일반적인) 것이 미래에 일어날 현상을 잘 설명할 가능성이 더 높기 때문입니다.
그리고 기계학습은 이런 류의 직관을 적용하기 위해 "Regularization penalty"를 만들었습니다.
Regularization은 보통 R로 표기합니다.
그렇다면 학습 자료의 식에서 알 수 있듯이,
일반적인 손실 함수는 두 항(Data loss, Regularization loss)으로 이루어집니다.
R(W)에 곱해진 것은 하이퍼 파라미터인 람다입니다. 람다는 두 항 간의 trade-off를 나타내며 모델을 훈련시킬 때 고려해야할 중요한 요소입니다!
그러면 우리는 Regularization의 역할에 대해 생각해볼 수 있습니다.
- 모델이 더 복잡해지지 못하도록 하는 것
- 모델에 soft penalty를 추가하는 것
("만약 너가 복잡한 모델을 쓰고 싶으면 이 penalty를 감수해야 할거야!" 라고 말해주는 것)
강의 내용에 따르면 많은 사람들이 Regularization을 위와 같은 내용으로 떠올린다고 합니다. 즉, 모델이 트레이닝셋에 완벽하게 학습되지 않도록 복잡도에 패널티를 부여하는 방법입니다.
Regularization에는 여러 종류가 있는데, 이번 강의에서는 L2, L1 Regularization을 다뤘습니다.
간략히 말해서
L2 Regularization은 가중치 행렬 W에 대한 Euclidean Norm에 패널티를 주는 것이고,
L1 Regularization은 가중치 행렬 W가 희소행렬이 되도록 합니다.
예시를 먼저 들어보겠습니다. 다음과 같이 x는 [1, 1, 1, 1] 벡터로 주어지며 두 개의 서로 다른 가중치가 주어져있습니다.
주어진 x와 가중치 w를 가지고 Linear Classification을 한다면, x와 w의 내적을 구합니다. Linear Classification의 입장에선 w1과 w2는 같습니다. 둘 다 계산해보면 1이 나오기 때문입니다.
그렇다면,
L2 Regularization이 더 선호하는 가중치 행렬은 어느 것일까요?
정답은 w2입니다.
L2는 x의 모든 요소가 output에 영향을 미치는 것을 선호하기 때문입니다. 만약 w1을 사용한다면 x의 첫 번 째 요소만 output에 영향을 끼치게 되므로 모든 요소를 고려한 것이 아닙니다.
즉, w의 요소가 전체적으로 퍼져있을 때 '덜 복잡하다'라고 인식합니다.
반면에,
L1 Regularization은 w1을 선호합니다.
L1에게 있어 '복잡도'는 다르게 정의됩니다. 가중치 w에 0의 개수에 따라 모델의 복잡도를 나눕니다. 때문에 L1이 복잡하다고 느끼고 측정하는 것은 0이 아닌 요소들의 개수가 될 수 있습니다.
사실 이러한 '복잡도'를 정의하는 것, L2가 '복잡도'를 정의하는 것은 가지고 있는 데이터에 따라, 사용할 모델에 따라 다르다고 합니다!
L2와 L1에 관해서 아주 간략하게 짚고 넘어갔는데요 ! 이번 챕터에서는 손실 함수에서 Regularization이 하는 역할과 그 중 L2와 L1이 있구나 정도로 이해하시면 될 것 같습니다!
이후 내용인 softmax classifier와 optimization은 나누어서 포스팅할 예정입니다. 그럼 이번 포스팅도 도움이 되었길 바랍니다!
읽어주셔서 감사합니다!