본 포스팅은 2022-11-07(월), 국민대학교 김장호교수님의 컴퓨터 비전 수업을 통해 배운내용을 정리하기 위한 게시글입니다.
# Recall
저번 시간에는 오버피팅을 방지하기 위해 정규화(Regularization)를 하는 방법에 대해서 배웠다. 정규화는 L1놈과 L2놈을 이용해서 할 수 있었다. L2놈은 Weight를 제곱했고, L1놈은 Weight의 절대값을 씌웠다. 이렇게 손실함수에 정규화를 해줌으로써 Weight가 지나치게 커져 오버피팅이 되는 것을 방지할 수 있었다.
똑같이 경사하강법을 사용해서 가중치 업데이트를 진행할 수 있으며, 추가된 정규화 부분을 똑같이 미분해 주면 됐다.
# Matrix Operation
multidimensional input과 output을 Matrix Operation을 사용한다면 조금 더 쉽게 표현 할 수 있다.
위 연산을 조금 더 쉽게 시각화 해보자.
input [1, -1] 에 대해서 퍼셉트론에 대한 가중치가 존재 할 것이다. 첫번째 퍼셉트론은 ( 1(input) * 1(weight) + -1(input) * -2(weight) ) + 1(bias)로 표현 할 수 있을 것이다. 두번째 퍼셉트론에 대해서도 똑같이 연산을 적용 할 수 있는데, 이를 행렬의 연산으로 표현해보면 아래와 같다.
즉, 한 퍼셉트론에는 모든 input의 값들이 연결 돼 있고 이 연결 선을 wieght라고 생각하면 된다. 그리고 가중치를 더해주는데, 이 가중치 자체를 행렬 안에 집어 넣을 수도 있을 것이다.
이제 Multilayer Neural Network가 되면 복잡한 것들을 행렬의 연산을 통해 쉽게 표현 할 수 있다.
# Dropout
L1놈과 L2놈을 사용해서 정규화를 하는 것은 Weight를 약하게 만드는 효과가 있었다. Dropout은 연결 자체를 끊어버리는 것이다. 랜덤하게 뉴런을 drop시킴으로써 해당 뉴런에 연결되지 않게 하는 것이다.
ensemble-learning이라는 학습 방법이 존재하는데, 이는 모델을 여려가지로 나누어 사용하는 것이다. 그럴경우 분산값이 낮아져 학습을 잘 시킬 수 있었다. dropout은 이러한 ensemble(앙상블)효과를 내게 할 수 있다. 모델안에서 drop시킴으로써 여러가지 모델을 사용하는 것과 같은 효과를 낼 수 있기 때문이다.
# Early-stopping (조기 종료)
모델 학습을 진행할때 epoch를 지정해준다. 해당 epoch만큼 반복을 돌면서 학습을 할 것 이다. 그러나 이 epoch또한 너무 많다면 오버피팅의 문제에 빠지게 된다. 그렇다고 너무 적게 한다면 언더피팅에 빠지게 되기 때문에, 조기 종료를 통해서( 학습을 멈춤 ) 오버피팅을 방지할 수 있다.
# Backpropagation ( 역전파 )
가중치 업데이트를 하기 위해서 gradients를 구하고 이를 위해서 해당(원하는) 가중치에 대한 편미분을 진행했다. 일반적이게 모든 미분 과정을 Paper에 적어서 static하게 구하는 방법이 존재 하겠다. 모델이 바뀌지 않고 간단하다면 괜찮을 수 있지만, 그리 좋은 방법은 아니다.
예를 들어 위와 같이 Hinge Loss를 사용했다가, Loss 함수를 크로스엔트로피(cross-entropy)로 바꾼다면, 미분의 모든 과정을 다시 Paper에 계산해야 할 것 이다.
좋은 Idea는 Computational Graphs를 사용하는 것에서 나온다. 이를 통해 미분의 과정을 모듈화(캡슐) 시킬 수 있다. tensorflow와 pytorch와 같은 딥러닝 프레임워크를 사용한다면, 이러한 미분의 과정이 Computational Graphs와 같은 방법으로 기록 된다.
정규화가 포함된 손실함수를 구하는 수식은 과정을 위와 같이 표현 할 수 있을 것이다.
- inputdata와 weight를 곱(*)해준다.
- 곱해서 나온 값을 손실함수에 넣어준다
- 그 값에 정규화가 더해진다.
이러한 Operation과정을 도식화 시킨 것이 바로 Computational Graphs이다. 이를 통해 간단하게 Gradient를 계산할 수 있다. 간단한 예제를 통해서 알아 보자.
## 예제
구하고자 하는 편미분 값이 연산에 한번이라도 포함되면 해당 값의 Gradient를 구할 수 있다. 이를 유념하고 예제를 살펴 보자.
먼저 Forward pass를 통해서 Operation들을 간단히 연산 할 수 있을 것이다. 그에 대한 결과값들은 위 예제에서 초록색으로 표시 된다. Forward pass과정에서 우리가 구하고자 하는 어떠한 값이 기여 했다면, 위에서 말한거와 같이 Gradient를 구할 수 있다. 즉 우린 f(x,y,z)에서 x,y,z에 대한 Gradient를 구할 수 있다.
아래 정리를 따라가 보면 x,y,z를 구할 수 있는 것을 알 수 있다.
이제 여기서 Downstream Gradinet , Local Gradient, Upstream Gradinet의 개념이 등장한다.
Local Gradinet를 의존성 없이 해당 순서에서 연산하 Gradinet를 가지고 있고, Back-Propagation과정에서 구해진 UpstreamGradinet를 Local Gradinet를 이용해서 Downstram Gradinet를 구할 수 있게 된다. 여기서 처음 말했던 모듈화와 같은 효과를 낼 수 있는 것이다. 구해전 Downstram Gradinet는 이전 Layer에서 다시 Upstream Gradinet가 되어 과정을 반복하여 원하는 값에 대한 Gradinet를 최종적으로 찾을 수 있게 되는 것이다.