FeedForward Neural Network (FNN)
가장 기본적인 피드포워드 뉴럴넷에 대해 다뤄보도록 하겠습니다.
간단하지만 가장 기초가 되는 내용이라 확실하게 학습하는 것이 중요합니다.
FNN는 단순히 피처들에 weight를 적용하는 것을 넘어 활성함수(Activation function)를 취해줌으로 인해 일종의 비선형모델에 속하게 됩니다.
One Units
NN을 이루는 하나의 빌딩 블록, 즉 하나의 뉴럴넷 유닛에 대해서 먼저 살펴봅시다.
입력값이 예를들어 세개의 피처벡터(x1,x2,x3)로 이루어져 있다면 하나의 뉴럴 유닛에서는 피처 수에 매칭되는 weight값(w1,w2,w3)을 각각 할당하여 다음과 같이 계산하게 될 겁니다.
∑=x1w1+x2w2+x3w3
그리고 여기에 bias(b)를 고려해야합니다.
흔히 매트릭스 합을 편하게 하기위해 bias도 w0=0을 추가하여 다음과 같이 표현하고 합니다.
∑=b(x0)w0+x1w1+x2w2+x3w3
여기서 입력값을 입력벡터 X(x0,x1,x2,x3)라고 표현하고 weight들을 weight vector W(w0,w1,w2,w3)로 표현하면 이는 활성함수 ϕ를 포함하여 뉴럴넷의 하나의 유닛은 다음과 같이 하나의 수식으로 쉽게 표현할 수 있습니다.
y^=ϕ(X⋅W)
Combining Units
먼저 레이어의 개념부터 알아봅시다. 가장 단순한 simple 뉴럴네트워크에서는 1개의 input layer, 1개의 hidden layer, 1개의 output layer를 가정합니다.
이러한 형태를 흔히 "Two layer network"라고 불립니다.
여기서 weight는 은닉층과 출력층으로 유입될 경우에 적용되고, 입력층에서는 적용되지 않습니다.
Matrix Operation
입력층에서 은닉층, 은닉층에서 은닉층, 은닉층에서 출력층으로 전달될때는 각 weight들이 곱해지는데 이를 매트릭스 형태로 표현할 수 있습니다.
이때 weight 매트릭스 W의 dimension은 "이전 layer의 유닛" * "현재 layer의 유닛"로 결정됩니다.
다음과 같이 bias를 포함해 3개의 값이 입력으로 들어온다고 가정해봅시다.
이러한 입력벡터는 다음과 같이 1 * 3 매트릭스로 표현될 것입니다.
[x0x1x2]
그리고 해당 입력값을 받아주는 은닉층의 유닛이 5개라고 가정해봅시다.
각 입력벡터의 값에 곱해지는 w는 입력벡터의 수와 동일해야 하므로 첫번째 은닉층의 유닛에서는 다음과 같이 계산이 수행될 것입니다. 윗첨자는 유닛 번호입니다.
x0w01+x1w11+x2w21
두번째 유닛은 다음과 같습니다.
x0w02+x1w12+x2w22
이를 표준화해서 정리해봅시다.
wi,j에 대하여 i는 이전 레이어의 유닛을 나타내고, j는 현재 레이어의 유닛 을 나타낸다고 표현해보면 weight매트릭스 W는 다음과 같이 3 * 5 매트릭스로 표현됩니다. weight매트릭스에서 하나의 column이 하나의 레이어 유닛에 맵핑되게 됩니다.
⎣⎢⎡w0,1w1,1w2,1w0,2w1,2w2,2w0,3w1,3w2,3w0,4w1,4w2,4w0,5w0,5w0,5⎦⎥⎤
이런 경우에 다음과 같이 입력벡터와 가중치매트릭스를 곱하면 1*5의 각 유닛별 출력값을 저장하고 있는 출력벡터를 손쉽게 구할 수 있게 됩니다.
물론 활성함수를 취하기 전 값으로겠죠.
[x0x1x2]⎣⎢⎡w0,1w1,1w2,1w0,2w1,2w2,2w0,3w1,3w2,3w0,4w1,4w2,4w0,5w0,5w0,5⎦⎥⎤=[a1a2a3a4a5]
여기서는 bias도 입력값의 벡터로 포함시켜 1*3, 3*5, 1*5의 형태로 매트릭스를 전개하였는데 bias를 따로 계산해도 됩니다. 그럴 경우 1*2, 2*5, 1*5의 형태가 될 것이고 bias 매트릭스는 따로 1*5로 구해져서 더해질 겁니다.
참고로, weight 매트릭스를 제외한 입력값 및 각 레이어의 출력값(최종 출력값 포함)의 row는 예제에서는 하나의 샘플인 1로 표현하였지만 통상 batch size의 크기를 가집니다.
예를들어 입력되는 샘플의 개수가 5개라면 위 예제는 코드에서 다음과 같이 표현될 겁니다. 위첨자 괄호는 샘플 인덱스입니다.
⎣⎢⎢⎢⎢⎢⎢⎡x0(1)x0(2)x0(3)x0(4)x0(5)x1(1)x1(2)x1(3)x1(4)x1(5)x2(1)x2(2)x2(3)x2(4)x2(5)⎦⎥⎥⎥⎥⎥⎥⎤⎣⎢⎡w0,1w1,1w2,1w0,2w1,2w2,2w0,3w1,3w2,3w0,4w1,4w2,4w0,5w0,5w0,5⎦⎥⎤=⎣⎢⎢⎢⎢⎢⎢⎡a1(1)a1(2)a1(3)a1(4)a1(5)a2(1)a2(2)a2(3)a2(4)a2(5)a3(1)a3(2)a3(3)a3(4)a3(5)a4(1)a4(2)a4(3)a4(4)a4(5)a5(1)a5(2)a5(3)a5(4)a5(5)⎦⎥⎥⎥⎥⎥⎥⎤
즉, 한번의 매트릭스 곱 수식으로 여러개의 샘플이 포함된 배치를 한번에 계산할 수 있습니다. 아래 설명할 backpropagation도 하나의 샘플을 기준으로 설명하겠지만 배치를 기준으로 진행됩니다.
Backpropagation
이렇게 포워드패스 계산을 통해 y^을 구하면 별도의 오차함수(MSE, CE, CCE 등)을 통해 실제 y와 y^사이의 loss를 이용하여 뉴럴넷의 각 weight 매트릭스를 업데이트 해야합니다. 이러한 업데이트는 경사하강법(gradient descent)를 이용하면 됩니다.
simple FNN에서는 위에도 언급했든 입력층에서 은닉층으로 넘어갈 경우의 weight매트릭스와 은닉층에서 출력층으로 넘어갈 경우의 weight 매트릭스가 존재합니다.
이러한 두 weight 매트릭스를 각각 U와 V라고 칭해봅시다.
이럴 경우 역전파를 통한 업데이트는 chain rule을 통해 다음과 같이 표현됩니다.
먼저 V를 봅시다.
구해야 하는 V 내에서 특정 가중치 v1,3을 가정해봅시다. 이는 이전 레이어의 1번째 유닛과 출력레이어의 3번째 유닛을 매핑하는 가중치일 것입니다.
구해야 하는 gradient는 다음과 같습니다. (loss은 multiclass classification에 사용되는 categorical cross entrophy를 가정)
∂v1,3∂Lcce
먼저 피드포워드 경로를 한번 봅시다.
은닉층 출력값 벡터들의 집합 H에서 weight 매트릭스 V를 곱하고 활성함수(softmax) g를 취한 결과가 y^가 될 것입니다.
y^=g(HV)
여기서 HV를 q라고 표현해 봅시다. 그럼 다음과 같은 수식이 됩니다.
y^=g(q)
반면 CCE에서 하나의 데이터에 대하여 loss를 구하는 수식은 다음과 같습니다.
여기서 k는 라벨의 원핫인코딩 값이 1인 softmax 값, 즉 라벨과 적중한 카테고리의 softmax 출력 값의 인덱스을 의미합니다.
Lcce=−log(yk^)
이제 gradient를 chain rule로 표현해보면 다음과 같습니다.
∂v1,3∂Lcce=∂y^∂Lcce∂g∂y^∂q∂g∂v1,3∂q
이렇게 계산된 gradient를 바탕으로 적절한 하이퍼파라미터 α를 취해 다음과 같이 업데이트 합니다. 모든 파라미터(v)들을 각각 업데이트 합니다.
wt+1=wt−α∇Lcce(y,y^)
U도 마찬가지 입니다만 좀더 chain rule이 길게 형성될 겁니다.
피드포워드 수식을 보면 다음과 같을 겁니다.
입력벡터를 X라고하고 은닉층의 활성함수를 f라 표현해봅시다. 다음과 같은 수식이 나오게 됩니다. XU 를 z라고 표현해봅시다.
y^=g(q(f(XU)))=g(q(f(z)))
이후에 weight u1,2에 대한 gradient는 다음과 같이 표현됩니다.
∂u1,2∂Lcce=∂y^∂Lcce∂g∂y^∂q∂g∂f∂q∂z∂f∂u1,2∂z
입력층에 가까운 weight일수록 gradient를 계산하기위해 곱해지는 편미분값들이 늘어납니다. 이에 따라 만약 활성함수를 sigmoid 등 양단에서 gradient가 굉장히 작아지는 함수를 사용할 경우 gradient vanishing(그래디언트 소실) 현상이 발생할 수 있습니다.
이렇게 하나의 batch를 거칠때마다 feedforward-backpropagation-gradient update가 반복됩니다. 여러 epoch를 지나면서 점점 weight들이 잘 수렴하게되면 FNN의 학습이 완료된 것입니다.
References
[1] nlpdemystified, https://www.nlpdemystified.org/