본문 바로가기

딥러닝 공부

신경망의 수학적 구성요소

※ 본 게시글의 내용은 '케라스 창시자에게 배우는 딥러닝'의 내용을 개인적인 이해를 통해 정리한 내용을 작성한 글입니다.

 

0. Tensor(텐서)

 텐서란, 임의의 차원 개수를 갖는 행렬의 일반화된 모습이다. 사실, 많은 사람이 알다시피 텐서란 개념은 딥러닝에서 사용하기 이전에 이미 물리학과 수학에서 쓰이는 개념이었다. 다만, 딥러닝 과정에서 대용량의 데이터를 다루게 되다보니 이를 용이하게 처리하기 위하여 이러한 개념을 도입한 것으로 보인다. 텐서에 대해 검색해보면 수 많은 수학적 물리학적 개념과 이론, 설명을 찾아볼 수 있는데, 물리학에서의 텐서의 개념은 찾 모르겠지만 수학에서의 텐서의 개념은 어느정도 알고있는 것이 중요하다고 생각한다. 

 

우리들이 모델에서 신경망을 구성하고 입력 데이터를 전처리할 때, 데이터의 형태가 어떠한지 즉, 텐서로써 어떻게 표현하고, 어떻게 처리할 것인지에 대해 수학적으로 접근하는 것이 중요하기 때문에, 선형대수를 공부하고 어느 정도의 지식은 갖춰야 한다고 생각한다. 

 

Tensor는 임의의 차원의 개수를 가지며, 다른 말로 rank, axis로 부르기도 한다.

  • 0D Tensor(scalar) : 하나의 숫자만 담고있는 텐서
  • 1D Tensor(vector) : 하나의 축을 갖는 숫자의 배열(우리가 흔하게 쓰는 1차원 배열과 같다. 하지만, 5D Vector와 5D Tensor는 서로 다른 개념이다. 5D Vector는 하나의 축에 5개의 차원이 존재하는 것이고, 5D Tensor는 5개의 축을 갖는다. 둘은 명확히 다른 개념이며, 텐서의 축 개수는 rank라고 표기하는 것이 더 정확하다.)
  • 2D Tensor(matrix) : 벡터의 배열. 2개의 축을 가짐.
  • 3D Tensor and others : 2D Tensor에 하나의 축이 더 생김. matrix를 하나의 배열로 합쳐 직육면체 형태로 해석할 수 있는 3D Tensor => 같은 개념으로 3D Tensor를 하나의 배열로 합치면 4D Tensor가 된다.

 

위의 내용을 보면 사실상 텐서와 배열의 명확한 차이가 없다고 생각한다.(나는 그렇다) 하지만, 분명 쓰는 이유가 존재한다.

https://codingapple.com/unit/tensorflow-2-variable-tensor-constant/

 

Tensorflow 2 빠른기초 & 텐서플로우를 쓰는 이유 혹시 아십니까 - 코딩애플 온라인 강좌

텐서플로우에서 사용하는 텐서라는 자료형이 있습니다.  수학에서의 행렬, 벡터를 파이썬으로 표현하고싶을 때 사용하면 유용합니다.  갑자기 행렬이야기는 왜 나온 것이고 텐서를 왜 쓰는 것

codingapple.com

 

위 글에서 이유를 약간 살펴볼 수 있다. 단순하게 정리하자면, 다른 텐서와의 연산을 쉽게하기 위해서 정도인 듯 하다. 

 

이러한 텐서를 우리는 신경망에 존재하는 모든 노드와 데이터, 결과 값 등 데이터를 다루는 모든 부분에서 사용하게 된다. 이러한 텐서를 처리하기 위해서는 우리는 수학적으로 텐서를 다루는 방법을 알아야 하기 때문에 선형대수학을 배울 수 밖에 없게 된다.

 

1. 그래디언트

앞선 글에서 우리는 신경망을 학습시키는 행위를 할 때, 손실 값을 통해서 네트워크의 가중치를 업데이트한다고 했었다. 

여기서 조금 더 구체적으로 네트워크를 어떤 식으로 업데이트하는지에 대해 생각해보자. 

 

우리가 설계한 네트워크에는 여러 개의 신경망이 존재할 것이고, 각 신경망엔 적개는 수 백개에서 많게는 수 만개까지의 가중치 행렬, 노드가 존재한다. 손실 값을 계산하고, 각 노드에 대해 해당 손실 값을 바탕으로 가중치를 업데이트하는 일은 쉽지 않은 일이다. 심지어 딥러닝에서의 신경망의 개수는 보통 수 십개다. 이러한 전체 네트워크에 대해 업데이트를 일일히 수행하는 일은 너무나 비효율 적이다. 

 

하지만, 다행인 것은 이런 네트워크에 사용된 모든 연산은 미분이 가능하다. 이 말인 즉슨, 네트워크의 전체 변화율을 예측하여 원하는 방향으로 네트워크의 변화를 유도할 수 있다는 것이다. 이렇게 텐서를 입력으로 받는 함수에 변화율 개념을 확장하여 그래디언트라는 것을 사용하여 전체 네트워크의 업데이트를 원하는 방향으로 유도가 가능하다. 

 

 

2. Gradient Descendent(경사 하강법)

앞서 얘기한 그래디언트와 미분 가능하다는 특성에서 미적분을 배운 사람이라면 가장 먼저 떠올리는 부분이 있을 것이다. 도함수의 절편! 전체 네트워크의 가중치의 크기에 따라 그리는 손실함수의 그래프에서 가장 작은 값인 극솟값을 찾는다면, 해당 네트워크는 가장 최적화된 네트워크라고 얘기할 수 있다. 아주 심플하고 명료한 얘기가 아닐 수 없다. 손실함수가 2차 3차 같은 수준이 아닌 수백, 수천 차원인 것만 뺀다면.

 

최고 차항의 계수가 수백, 수천이 되는 함수의 극값을 구할 수 있겠는가? 영원히 살 수 있는 미치광이가 아니고서야 이딴 짓을 할리가 없다. 하지만, 이에 유사하게 다가갈 수 있는 방법이 경사 하강법이다. 

 

 

 

위 이미지는 쉽게 높은곳(빨간 곳)에서 낮은곳(파란곳)으로 순차적으로 내려가는 모습을 시각화한 것이다. 이것이 경사 하강법이다. 극솟값을 찾기 위해 어딘진 모르지만, 특정 지점을 시작점으로 점점 더 낮은 곳을 찾아 내려가는 것(step by step). 이렇게 된다면 결국 우리는 극솟값 중 하나에 안착할 수 있게 될 것이다. 여기서 유의할 점은 우리가 극솟값을 찾기 위해 한 걸음 한 걸음 내려갈 때(step을 통해) step의 크기를 고려하지 않을 수 없다.

 

일정한 크기의 step을 통해 네트워크를 업데이트하는 과정에서 step이 너무 클 경우, 적절한 안장점에 위치하지 못 하고 너무 다른 값으로 튈 가능성이 커지면, step이 너무 작은 경우엔 안장점을 찾기까지 너무 많은 자원이 소모되게 될 수 있다.

 

--> 적절한 step을 찾더라도 극솟값이 아닌, 극값 중 하나를 취하게 될 수도 있다고 생각할 수 있다. 우리가 연산을 수행하는 공간은 차원의 크기가 수백 이상이기에 지역 최솟값에 갇힐 가능성은 매우 낮다.

 

우리는 이러한 방식을 통해 전체 네트워크를 업데이트할 것이다.

 

2-1. SGD(Stochastic Gradient Descendent, 확률적 경사 하강법)

앞서 얘기한 그래디언트가 그리는 그래프에서 극솟값을 찾기 위해 모든 loss에 대한 결과값을 계산하는 것은 너무 많은 자원을 사용하기 때문에 우리는 모든 데이터를 사용하는게 아닌, 무작위로(stochastic) 선택한 일부 데이터를 통해 네트워크를 업데이트하는 방식을 갖는다.

 

이러한 SGD에는 다양한 변종들이 존재한다. 이러한 변종들을 포함한 모든 네트워크를 업데이트하기 위한 방법들을 묶어 최적화 방법(optimization method) 혹은 옵티마이저(optimizer)라 한다. 이러한 변종 중 모멘텀이라는 개념을 사용하는 변종 들이 있다. 

 

앞서 언급한 내용처럼 SGD는 수렴속도와 지역 최솟값에 갇힐 수 있다는 문제점이 있는데, 이를 해결하기 위해 모멘텀이라는 개념이 등장하였다. 모멘텀은 현재 기울기 값에 현재 속도를 함께 고려하여 다음 step을 결정하는 기법이다.

https://sonstory.tistory.com/70

 

[DL] 최적화 - Stochastic Gradient Descent, SGD Momentum, overshooting, Nesterov Momentum, AdaGrad, RMSProp, Adam

확률적 경사 하강법 확률적 경사 하강법은 손실 함수의 곡면에서 경사가 가장 가파른 곳으로 내려가다 보면 언젠가 가장 낮은 지점에 도달한다는 가정으로 만들어졌다. 그러나 가정이 단순하기

sonstory.tistory.com

이와 관련된 내용은 위 글에 상당히 자세하게 잘 설명되어있다. 

 

3. 역전파 알고리즘

미적분에서는 연쇄법칙을 사용하여 합성함수의 미분을 수행할 수 있다. 우리는 이런 법칙을 사용하여 여러 개의 층이 있는 신경망에 대해 미분을 수행하고 결과값을 전체 네트워크에 반영할 수 있다. 이에 대한 더 자세한 내용은 나중에 추가로 서술하겠다.