본문 바로가기
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 이것은 다음 포스팅에서 설명해보도록 하겠습니다.

 

댓글