지난 포스팅에 행렬 계산을 해보았습니다.
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 함수를 사용하겠습니다. 직관적이고 미분도 쉽그등여 ㅎ
그래프가 참 단순하고 예쁘죠? 이 그래프의 수식은 어떻게 될까요?
수학적으로 풀면 중괄호를 치고 두줄짜리 식을 써야겠지만 우린 코딩을 할 거니까 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 함수입니다.
합이 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사이의 값을 갖게 하는 것이 어렵겠죠?
그래서 지수함수를 적용하는 것입니다. 어떤 수가 들어오던 지수 함수는 양의 값을 뱉어주기 때문입니다.
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 함수를 사용합니다.
왜냐 이는 두 개의 집합이 얼마나 다른지 측정해주는 아주 좋은 척도이기 때문이죠
이 식 에서 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 이것은 다음 포스팅에서 설명해보도록 하겠습니다.
'Have Done > MLP' 카테고리의 다른 글
MLP from Scratch with Numpy [5 / 7] - backpropagation1 (0) | 2022.01.06 |
---|---|
MLP from Scratch with Numpy [4 / 7] - feed forward 코딩 흐름 (0) | 2022.01.05 |
MLP from Scratch with Numpy [2 / 7] - feed forward2 (0) | 2022.01.03 |
MLP from Scratch with Numpy [1 / 7] - feed forward1 (0) | 2022.01.03 |
MLP from Scratch with Numpy [0 / 7] - Classification 사전작업 (0) | 2022.01.03 |
댓글