Stanford University CS231n - Lecture3 Loss Functions and Optimization

jaehee kim·2020년 7월 31일
0
post-thumbnail

스탠포드 대학교 cs231n 2017년 강의를 정리하였습니다.

Review


이전 강의에서는 KNN, 하이퍼파라미터를 찾는 방법, linear classifier 에 대해서 배웠습니다.

image → f(x,w)→ class scores (어떤 class의 score가 높으면 분류기는 이미지가 그 class일 것이라고 생각합니다.)

Linear clssification은 고차원 공간에서의 일종의 "결정 경계"를 학습한다는 측면으로 볼 수 있는데, 그 공간의 차원은 이미지의 픽셀 값에 해당하는 것입니다.

그럼 W를 어떻게 만들어내는가? 가장 좋은 행렬 W를 구하는데 어떻게 트레이닝 데이터를 활용해야 하는가?

눈으로 직접 확인하면서, W가 좋은지 아닌지 확인하는 것은 비효율적입니다. 그래서 이런 일을 자동으로 해주는 어떤 알고리즘을 만들고, 어떤 W가 좋은지 나쁜지 확인하기 위해서 정량화를 해야하는데, 이때 이용하는것이 loss function 입니다. W 가 얼마나 좋지 않은지 확인할 수 있도록 하는 것입니다.

이제 저희가 하고싶은것은 W가 될 수 있는 여러가지 경우들 중에서, 가장 괜찮은 것을 찾는 것인데, 이 과정을 optimization 이라고 합니다.



Loss function


이제 그럼 loss function에 대해서 살펴보겠습니다.

어떤 N개 의 트레이닝 데이터가 있다고 할때, x는 이미지로, y는 그 이미지에 대한 클래스로 표현하겠습니다.

f(x,w)는 예측함수이니까 x를 넣었을 때, 어떤 클래스다라고 예측을 할 것입니다.

지금 loss function이 Li로 표현되어 있습니다. 입력으로 예측함수에 의해서 나온 스코어값과, 실제 정답 클래스의 값이 들어값니다. 그럼 결과로 예측 결과가 얼마나 나쁜지 정량화된 수치가 나옵니다.

최종적인 loss 인 L은 전체 N개의 샘플들에 대한 평균이 됩니다.



Muticlass SVM Loss


Multiclass SVM은 여러 클래스를 다루기 위한 binary SVM의 일반화된 형태입니다.

  • svm

SVM에 대한 ratsgo 님의 설명자료입니다.

서포트 벡터 머신 (Support Vector Machine)

f(x,W) = Wx

먼저 f(x,w)함수에 의해 나온 스코어 결과값들을 s라고 하겠습니다.

sy_i는 트레이닝 셋에서 i번째 이미지의 정답 클래스의 스코어이고, sj는 정답이 아닌 클래스의 점수입니다.

sy_i와 sj의 차이가 마진(1=safety margin)보다 크면, loss는 0 이고, loss가 0이면 클래스를 잘 분류한 것이 됩니다.

이제 각각 정답이 아닌 클래스에 대해서 계산을 한것들의 합을 구하면 최종적인 Li가 되는 것입니다.

최종적인 loss L 은 전체 이미지에 대해서 구한 Li들의 평균이 됩니다.

위와 같은 종류의 손실함수를 hinge loss 라고 합니다. 그래프 모양이 힌지처럼 생겨서 그렇다고 합니다.

이 그래프에서 x축은 정답 클래스의 스코어 값이고 y축은 loss를 나타냅니다.

강의에서 몇가지 질문을 합니다.

Q. 만약 car 스코어에 약간 변화가 있으면 loss에 무슨일이 일어날까?

스코어를 바꿔도 margin이 유지되기 때문에, loss가 변하지 않습니다.

Q. SVM loss가 가질수 있는 min/max는 ?

min = 0 - 만약 모든 클래스에 대해서 정답 클래스의 스코어가 가장 크면 모든 트레이닝 데이터에서 loss 가 0이 될것입니다.

max 는 무한대 - 만약 정답 클래스가 엄청 낮은 음수일 경우

Q. 초기에 W는 거의 0에 가까울 것이고, 그로인해 스코어들도 거의 0에 가까울 것이다. 이때 loss 는?

클래스의 수 - 1 입니다. 로스값들이 마진에 의해서 1이 나올 것이고, 정답클래스를 제외한 클래스에 대해서 계산하기 때문입니다.

→ 디버깅 전략으로 유용하게 사용할 수 있습니다.

Q. 만약 정답인 클래스도 더하면?

loss + 1 이 됩니다. 정답인 클래스의 경우 로스가 마진에 의해서 1이 나올 것이기 때문이다.

Q.만약 합 대신 평균을 이용하면?

스케일만 변하므로, 영향을 미치지 않습니다.

Q.손실함수를 제곱으로 바꾸면?

계산 자체가 달라지기 때문에 결과가 달라질 것입니다.

제곱한 것을 사용하는 경우도 있습니다.. (squared hinge loss)

→ loss 에 제곱을 하면 로스가 안좋은 것은 더 안좋아질 것입니다. 그럼 심하게 잘못 분류된 것들을 알수 있습니다. 일반적인 hinge loss 를 사용하면, "조금 잘못된 것" 과 "많이 잘못된 것" 을 크게 신경쓰지 않게 되는 것입니다.

문제에 따라서 손실함수를 잘 설계하는 것이 중요합니다.

  • safety margin 어떻게 결정하는가?

→ 우리가 궁금한건 여러 스코어 간의 상대적인 차이인 것입니다. 우리가 관심있어 하는건 오로지 정답 스코어가 다른 스코어에 비해 얼마나 더 큰 스코어를 가지고 있는지 입니다. 행렬 W를 전체적으로 스케일링한다고 생각해 보면 결과 스코어도 이에 따라 스케일이 바뀔 것입니다. 1이라는 파라미터는 없어지고, W의 스케일에 의해 상쇄됩니다.

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. loss가 0 이 되게하는 W는 unique한가?

다른 W도 존재합니다. W를 2배해도 loss는 변하지 않기 때문입니다.

data loss는 트레이닝 데이터에 최적화되도록 합니다.

우리는 테스트 데이터에 대해서 좋은 성능을 내는 classifier를 원하기 때문에, 트레이닝 데이터에 대한 loss에만 신경을 쓴다면 결과가 좋지 않을 것입니다.

파란색점 = training data

초록색점 = new data

처음에 Data loss 부분만을 이용해서 트레이닝을 하게 된다. 파란색 곡선의 형태가 나올 것입니다. 데이터에 잘 맞지만 아주 복잡한 상태입니다.

초록색 점에도 잘 맞아야 합니다. 이를 위해 regularization항을 추가합니다.

오버피팅되지 않도록 패널티를 주고, 초록색 선과 같이, 좀더 단순한 형태의 결과를 얻어냅니다.

오캄의 면도날 - 같은 현상에 대한 가설이 있을때, 더 간단한쪽이 좋다는 이론

질문 : Wx + lambda*R 이란 것이 도대체 뭐길래 구불구불한 곡선을 직선으로 바꿔 준다는 것입니까?

→ 어떤 regression term을 추가하면 모델이 데이터를 핏 할 떄 저차 다항식을 더 선호하도록 하게 하는 것입니다. 하나는 여러분의 모델이 더 복잡해 지지 못하도록 하는 것이고 또는 모델에 soft penalty를 추가하는 것으로 보는 것입니다.



Regularization


regularization에는 여러가지가 있는데 가장 보편적인 것은 L2 regularization 입니다. weight decay라고도 합니다.

L2 regularization의 메인 아이디어는 가중치 행렬 W의 euclidean norm의 패널티를 주는 것입니다.

Regularization은 모델이 트레이닝 데이터셋에 완벽히 맞지 않도록 모델의 복잡도에 패널티를 부여합니다.

  • l1 l2 차이

L1 , L2 Regularization 에 대해서 정리가 잘되어있는 자료입니다.

딥러닝 용어 정리, L1 Regularization, L2 Regularization 의 이해, 용도와 차이 설명


예시를 보겠습니다.

x = [1,1,1,1]

w1 = [1,0,0,0]

w2 = [0.25,0.25,0.25,0.25]

linear classification을 할때, x 와 w의 내적을 구하게 되는데, linear classification의 관점에서는 w1과 w2가 같습니다. 왜냐하면 내적의 값이 1로 같기 때문입니다.

L2 Regularization은 w2를 더 선호할 것입니다.

L2의 경우 weight를 가능한 최대로 spread out해서 모든 input feature들을 고려하는것을 원한다. → diffuse over everything.

L2 Regularization이 말하고자 하는것은 x의 모든 요소가 영향을 줬으면 하는 것입니다.

변동이 심한 어떤 입력 x가 있고 그 x의 특정 요소에만 의존하기 보다, 모든 x의 요소가 골고루 영향을 미치길 원한다면, L2 Regularization을 통해 더 강인해 질 수 있을 것입니다.

L1은 정반대로 w1을 선호합니다. L1 Regularization은 가중치 W에 0의 갯수에 따라 모델의 복잡도를 다룹니다.

일반적으로 L1은 sparse한 solutions을 선호한다

L1이 "복잡하다"고 느끼고 측정하는 것은 0이 아닌 요소들의 갯수가 될 수 있습니다.

"복잡도" 를 어떻게 정의하느냐, 그리고 L2 Regularization은 "복잡도"을 어떻게 측정하느냐는 우리가 어떤 문제를 가지고 있으냐에 따라 다릅니다.

우리가 어떤 문제가 있고, 어떤 모델이 있고 데이터가 있을때 "복잡하다"는 것을 어떻게 정의할 지를 반드시 고민해야 할 것입니다.



Softmax Classifier (Multinomial Logistic Regression)


multi-class SVM loss의 경우에는 스코어 자체의 값보다는 정답 클래스의 스코어 값이 다른 클래스들 보다 큰값이 나오도록 하는 것을 원했습니다.

하지만 Multinomial Logistic regression의 로스펑션에서는 스코어 자체의 값에 어떤 의미를 부여합니다.

소프트맥스라고 불리는 함수를 이용해서, 스코어를 가지고 클래스별 확률 분포를 계산합니다.

모든 스코어들에 지수를 취해서 양수가 되도록 만들고, 그 지수들의 합으로 다시 정규화 시킵니다. 그리고 소프트맥스 함수를 거치게 되면 확률분포를 얻게 됩니다. 그것은 바로 해당 클래스일 확률이 되는 것입니다.

loss는 - log (p)가 되게 됩니다.(p = 확률)

log를 최대화시키는 것이 그냥 확률값을 최대화 시키는 것보다 쉽습니다. 그러니 우리는 log를 씁니다.

그런데 손실 함수는 "얼마나 좋은지" 가 아니라 "얼마나 나쁜지"를 측정하기 때문에 앞에 마이너스를 붙힙니다.

-log(정답확률)

확률이기 때문에 0에서 1 사이의 값이고, 모든 확률들의 합은 1이 됩니다.

우리가 원하는 것은 softmax에서 나온 확률이 정답 클래스에 대한 확률을 1에 가깝게 되도록하는 것입니다.

강의에서 몇가지 질문을 합니다.

Q. min/max?

min = 0, max = 무한대

Q. Loss가 0이 되려면 실제 스코어는 어떤 값이어야 할까요?

정답 스코어가 극단적으로 커야합니다. 우리가 확률 1(정답) 과 0(그외) 를 얻으려면, 정답 클래스의 스코어는 +무한대 가 되어야 하고, 나머지는 -무한대 가 되어야 합니다.

Q. 초기에 W는 거의 0에 가까울 것이고, 그로인해 스코어들도 거의 0에 가까울 것이다. 이때 loss 는?

-log(1/클래스의 수)

Softmax vs SVM

SVM에서는 정답 스코어와, 정답이 아닌 스코어 간의 마진(margins)을 신경썼습니다.

반면 softmax (crossentropy) 는 확률을 구해서-log(정답클래스) 에 신경을 씁니다.

Q. 데이터에 약간 변형을 줬을 때, 각 loss는?

SVM의 경우 둔감하다. Softmax는 모든 인자들을 고려하고 확률로 계산되기 때문에 민감하다.



Optimization


그럼 이제, 최종 손실 함수가 최소가 되게하는 가중치 행렬이자 파라미터인 w를 찾아야 하는데, 실제로 어떻게 찾아낼지가 optimization에 대한 이야기 입니다.

실제로 NN을 사용하면 "예측 함수", "손실함수"등이 너무 크고 복잡해서, 최적의 솔루션(minima)을 한번에 바로 찾아내는 솔루션을 만드는것이 어렵습니다.

그렇기 때문에 반복적인 방법들을 이용하게 됩니다.

이 방법들은 임의의 지점에서 시작해서 점차적으로 성능을 향상시키는 방법입니다.

Strategy #1: A first very bad idea solution: Random search

임의로 샘플링한 W들을 엄청 많이 모아놓고 Loss를 계산해서 어떤 W가 좋은지를 살펴보는 것입니다. 아주 좋지않은 방법입니다.

Strategy #2: Follow the slope

실제로 더 나은 전략은 지역적인 기하학적 특성을 이용하는 것입니다.

이 방법은 미분을 이용하는 것인데, 어떤 지점에서의 경사를 구해서 최적화를 진행합니다.

x가 벡터이기 때문에 위의 개념을 다변수로 확장시켜야 합니다.

다변수인 상황에서의 미분으로 일반화시켜보면 gradient이고 gradient는 벡터 x의 각 요소를 편도함수들의 집합입니다.

gradient 의 각 요소가 알려주는 것은 바로 "우리가 그쪽으로 갈때 함수 f의 경사가 어떤지" 라는 것입니다.

gradient의 방향은 함수에서 "가장 많이 올라가는 방향" 이 됩니다. gradient의 반대 반향이라면 "가장 많이 내려갈 수 있는 방향" 이 되는 것입니다.

컴퓨터로 이 gradient를 사용할 수 있는 가장 단순한 방법 중 하나는 finite difference methods라는 방법입니다.

예시를 보도록 하겠습니다.

왼쪽에 W가 있고 이것들을 이용한 로스는 1.25347입니다. 우리가 원하는 것은 gradient dw 를 구하는 것입니다. gradient의 각 요소가 말해주는 것은 우리가 그쪽 방향으로 아주 조금 이동했을 때 Loss가 어떻게 변하는지 입니다.

이제 계산을 해보면, W에 아주 작은 값이 h를 더한후, 로스를 계산해보면 다음과 같이 나옵니다. 이제 두 로스를 이용해서 gradient를 계산합니다. 이런식으로 모든 w에 대해서 계산을 합니다.

모든 W에 계산해야 하기때문에 느리고, 좋은 방법은 아닙니다.

그래서 우리는 미분을 이용합니다. 정확하고, 식도 하나로 계산하기 때문에 빠릅니다.

W 의 모든 원소를 순회하는 것이 아니라 gradient를 나타내는 식이 무엇인지 먼저 찾아내고, 그것을 수식으로 나타내서 한번에 gradient dW를 계산해 버리는 것입니다.

Numerical gradient : approximate, slow, easy to write (첫번째 방법)

Analytic gradient : exact, fast, error-prone (두번째 방법)

보통은 Analytic gradient 방법을 사용하지만, 디버깅을 할때, Numerical gradient 방법을 사용하면 유용하다고 합니다.



Gradient Descent


gradient descent 방식을 사용하여 weight update 합니다.

# Vanilla Gradient Descent

while True:
	weights_grad = evaluate_gradient(loss_fun, data, weights)
	weights += - step_size * weights_grad

과정을 보면, 먼저 w를 임의의 값으로 최기화합니다.

그리고 loss와 gradient를 계산한 뒤에 가중치를 gradient의 반대 방향으로 업데이트하는 과정을 반복합니다.

겨기서 stepsize는 learningrate입니다. 하이퍼파리미터로 잘 설정해야합니다.

너무 크면 diverse/explode.

너무 작으면 slow convergence.



Stochastic Gradient Descent (SGD)


우리는 로스를 구할때 전체 트레인데이터의 로스를 구한후 평균을 했었습니다. 근데, 데이터 셋이 엄청나게 클 경우에는 이런 로스를 구하는 과정이 아주 오래걸릴 것입니다.

그래서 SGD라는 방법을 사용합니다.

전체 데이터셋이 아니라, minibatch 라는 작은 트레이닝 샘플 집합으로 나눠서 학습을 진행합니다.

작은 minibatch를 이용해서 Loss의 전체 합의 "추정치"와 실제 gradient의 "추정치"를 계산하는 것입니다.

# Vanilla Minibatch Gradient Descent

while True:
	data_batch = sample_training_data(data, 256) # sample 256 examples
	weights_grad = evaluate_gradient(loss_fun, data_batch, weights)
	weights += - step_size * weights_grad # perform parameter update

임의의 minibatch를 만들어내고, minibatch에서 Loss와 Gradient를 계산합니다. 그리고 W를 업데이트합니다.

batch사이즈는 cpu의 메모리 수준에 적합하도록 설정합니다.



Image features vs ConvNets


이전의 컴퓨터비전 분야의 이미지 처리 방식을 보면, 이미지의 feature를 이용한 방식들을 많이 사용하였습니다.

이미지가 있으면 여러가지 특징표현을 계산하여, 벡터로 만들어주고, 그것을 linear classifier의 input으로 넣어줍니다.

motivation을 보면, 처음 빨간색과 파란색을 linear classifier로 분리할 수 없습니다. 그래서 feature에 변형을 주어 linear classifier로도 분리가 가능하도록 합니다.

사용 예시를 보도록 하겠습니다.

Color Histogram을 이용하는 방법입니다.

각 픽셀마다 어떤 색상에 해당하는지 개수를 세는 방법인데, 이미지 전체적인 색상을 알 수 있습니다.

이 개구리사진은 초록색이 많은 것을 알 수 있습니다.

다음은 HoG 입니다.

작동방식을 보면, 먼저 어떤 이미지를 88 픽셀들로 나누어 줍니다. 이제 88픽셀 내에서 edge에 대한 계산을 진행하고, 그 계산 결과중 가장 강력하다고 판단되는 edge를 얻어냅니다. 이미지 전체에 어떤 종류의 edge정보가 있는지 알 수 있습니다.

Bag of Words 입니다.

이 아이디어는 자연어처리(NLP)에서 영감을 받은 것이라고 합니다. 어떤 문장이 있고, BOW에서 이 문장을 표현하는 방법은 바로 문장의 여러 단어의 발생 빈도를 세서 특징 벡터로 사용하는 것입니다.

이미지에 그대로 적용하는 것은 쉽지 않기 때문에, visual words 라는 개념을 사용합니다.

2단계의 과정이 있습니다.

엄청 많은 이미지를 가지고, 그 이미지들은 임의대로 조각냅니다. 그리고 그 조각들을 K-means와 같은 알고리즘으로 군집화합니다. 이미지내의 다양한 것들을 표현할 수 있는 다양한 군집들을 만들어 내는 것입니다.

오른쪽은 이미지들에서 다양한 이미지 패치를 뽑아내서 군집화 시켜 놓은 실제 예시입니다.

군집화 단계를 거치고나면, 시각 단어(visual words)는 빨간색, 파랑색, 노랑색과 같은 다양한 색을 포착해냅니다. 다양한 방향의 oriented edges또한 포착할 수 있습니다.

이런 시각 단어(visual words) 집합인 Codebook 을 만들고 나면 그러면 어떤 이미지가 있으면, 이 이미지에서의 시각 단어들의 발생 빈도를 통해서 이미지를 인코딩 할 수 있는 것입니다. 이는 이 이미지가 어떻게 생겼는지에 대한 다양한 정보를 제공합니다.

Image classification의 pipleline을 보면 다음과 같습니다.

예전에는 이미지를 받으면 알고리즘으로 특징을 계산하고, 추출된 특징들을 linear classifier에 입력으로 사용했습니다.

요즘의 cnn이 다른 점은 특징을 만들어 내기 보다는 데이터로부터 특징을 학습한다는 것입니다.

Linear classifier만 훈련하는게 아니라 가중치 전체를 학습합니다.

Reference


Stanford University School of Engineering

Lecture 3 | Loss Functions and Optimization

notion 정리

[notion]Stanford University CS231n - Lecture3 Loss Functions and Optimization

0개의 댓글