본문 바로가기
Have Done/MLP

MLP from Scratch with Numpy [3 / 7] - Activation

by 에아오요이가야 2022. 1. 4.

지난 포스팅에 행렬 계산을 해보았습니다.

Hidden_layer = np.dot(Input_layer ,  W_0)
Output_layer = np.dot(Hidden_layer , W_1)

Output_layer = np.dot(np.dot(Input_layer ,  W_0) , W_1)

저 정도 계산으로 특별한 성능을 기대한다면 너무 욕심이겠죠? 이제 진짜 시작입니다.

 

행렬 계산에 그치지 않고 우리는 Activation function을 적용해 줄 것입니다.

활성 함수라고 하죠 그 이유는 모델 전체에 Nonlinearity (비선형성) 성질을 부여하기 위함입니다.

 

사연이 있는 행위 지만 여기선 간단하게 '어려운 문제 풀기 위해 사용'됐다고 하겠습니다.

(* 전공자시라면 반드시 찾아보시길!)

 

여기선 가장 간단한 Relu 함수를 사용하겠습니다. 직관적이고 미분도 쉽그등여 ㅎ

[그림 1] ReLU(Rectified Linear Unit) 왜 RLU라고 안하고 ReLU라고 했을까요~ 아마도 발음 하기 편하라고 그렇게 이름을 붙인것 같습니다.

그래프가 참 단순하고 예쁘죠? 이 그래프의 수식은 어떻게 될까요?

 

수학적으로 풀면 중괄호를 치고 두줄짜리 식을 써야겠지만 우린 코딩을 할 거니까 ReLU(x) = Max(x,0) 함수라고 이해하시면 됩니다.

def ReLU(x):
	return np.max(0,x)

 

0보다 작은수가 들어오면 0을 내놓고 0보다 큰 수가 들어오면 그 값을 그대로 내놓는 함수입니다.

 

나중을 위한 말이지만 이걸 미분하면 어떻게 될까요~~? ReLU'(x) = 1 (if >0)입니다.

 

def ReLU_derivative(x):
	return x>0

 

이걸 어디에 적용하면 될까요?!! Hidden layer H가 계산된 이후에 적용해주면 됩니다! 

 

그럼 그 이후의 계산식들도 변경이 되겠죠?!

Hidden_layer = np.dot(Input_layer ,  W_0)
Hidden_after_ReLU = ReLU(Hidden_layer)

Output_layer = np.dot(Hidden_after_ReLU , W_1)

Output_layer = np.dot(ReLU(np.dot(Input_layer ,  W_0)) , W_1)

 

그다음에!

 

output layer에서 계산된 값이 어떤 클래스에 속하는지 결정해야 됩니다. 이 부분도 Activation function이라고 볼 수 있겠지요?

 

우리 모델의 목적은 classification이기 때문에 들어온 input이 어디 class에 속하는지를 정해줘야 합니다.

 

억지로 정하는 방법이 있지요 바로 softmax 함수입니다.

 

[그림 2] softmax 식입니다. 엄청 어려워 보이는거 같은데 찬찬히 뜯어보면 별거 없습니다.

 

합이 1이고 각 노드별 최솟값이 0 이 되는 벡터를 만들어 줄 겁니다. 곧 확률 벡터지요.

 

예를 들어 Output layer O의 결과 값이 [0, 4, 3, 2, 1, 0, 1, 3, 3, 3]라고 한다면 어떤 class에 속하는지 모르겠죠 이걸 확률의 설질을 띄는 집합으로 만들어 주는 함수가 softmax인 것입니다.

 

우선 지수함수 e를 빼놓고 먼저 설명하겠습니다.

 

분모엔 모든 원소들의 합이, 분자엔 해당 원소가 들어갑니다.

 

방금 들었던 예를 이용하여 적용해보겠습니다. 모든 원소의 합은 20 이니까

 

[0, 0.2, 0.15, 0.1, 0.05, 0, 0.05, 0.15, 0.15, 0.15]가 되겠지요?

 

그럼 0.2가 나온 두 번째 자리로 이 클래스가 정해지는 것입니다.

 

자세히 보시면 모든 원소의 합이 1이고 각각의 원소들은 0~1 사이의 값을 갖는 정확히 확률 집합의 특성과 일치하는 모습을 볼 수 있습니다.

 

근데 만약에 원소들 중에 음수가 있다면 합했을 때 1이 안되고 0~1사이의 값을 갖게 하는 것이 어렵겠죠?

 

그래서 지수함수를 적용하는 것입니다. 어떤 수가 들어오던 지수 함수는 양의 값을 뱉어주기 때문입니다.

 

[그림 3] 모든정의역에 대해 양의 값을 반환해주는 지수함수의 모습

def softmax(x):
	total = np.sum(np.exp(x))
	return np.exp(x)/total

softmax 함수는 어디에 적용하면 될까요?! Output layer O 에 적용해 주면 됩니다.

 

최종적으로 다음과 같은 계산식이 Output layer O 라고 보시면 됩니다.

Hidden_layer = np.dot(Input_layer ,  W_0)
Hidden_after_ReLU = ReLU(Hidden_layer)

Output_layer = softmax(np.dot(Hidden_after_ReLU , W_1))

Output_layer = softmax(np.dot(ReLU(np.dot(Input_layer ,  W_0)) , W_1))

 

자 이제 우리의 input이가 어디 class에 속하게 됐는지 알게 됐네요! 이는 곧 주어진 문제를 풀어봤다! 요 정도로 해석될 수 있습니다.

 

이제 어떻게 해야 할까요~? 맞았는지 확인해봐야겠죠?!!

 

제가 생각했을 때 ML(Machine Learning)에서 가장 중요하다고 생각하는 Cost function 혹은 Objective function 설정 부분입니다.

 

classification에서는 cross entropy 함수를 사용합니다. 

 

[그림 4] cross entropy 함수

왜냐 이는 두 개의 집합이 얼마나 다른지 측정해주는 아주 좋은 척도이기 때문이죠

 

이 식 에서 p, q는 서로 다른 두 집합을 의미합니다! 근데 이제 원소의 개수는 같은..

 

p와 q의 원소들을 일일이 대조하여 전체 집합이 얼마나 다른지 표현해주는 식입니다.

 

def cross_entropy(p,q):
    true = np.eye(num_class)[q]
    loss = (np.log(p) * true).sum(axis=1)
    return -np.sum(loss)

 

자 이제 최종적인 계산은 다음과 같이 표현될수 있습니다.

Cost_function = cross_entropy(Output_layer, true_Label)
              = cross_entropy(softmax(np.dot(ReLU(np.dot(Input_layer ,  W_0)) , W_1)), true_Label)

이제 계산은 끝났습니다. 즉 feed-forward가 끝났습니다. 즉 다 풀어봤습니다.

 

역시나 처음 풀어본 건 틀렸겠죠? 그럼 어떡해야 할까요~!~! 맞을 때까지 혼을 내줘야 됩니다.

 

Back Propagation 이것은 다음 포스팅에서 설명해보도록 하겠습니다.

 

댓글