[비전공자를 위한 딥러닝] 2.4 신경망 (2) - 가중치 행렬 한방에 이해하기

 

목차 보기


신경망은 이전 층의 특성들의 선형결합을 통해 새로운 특징들을 추출해내는 모델이다.
딥러닝이란 신경망 구조 내의 층들을 깊게(deep) 쌓아 데이터의 특성들을 디테일하게 학습하는 것이다.
물론 지난 장에서 살펴보았듯이 선형 변환은 여러 번 진행하더라도 하나의 선형 변환으로 대체될 수 있기 때문에, 각 노드(node) 마다 비선형 변환을 적용해야 한다.


이전 층의 특성들은 다음과 같이 각각 저마다 다른 가중치와 곱해서 더해지게 된다.
이 때 이전 층의 특성들이 어떤 가중치들로 조합되느냐에 따라 생성되는 특성의 의미가 달라지게 되고, 최종적으로 모델이 학습을 진행함에 따라 바로 이 가중치들이 변해가면서 데이터의 특성을 더 잘 추출하고 더 예측을 잘 하는 모델이 되어가는 것이다.

하나의 특성을 생성하는 가중치들은 다음과 같이 하나의 벡터(vector)로 묶어서 표현할 수 있다.
w 밑의 숫자들은 "1층"의 "1번째" 특성을 생성하는 가중치 벡터임을 가리킨다고 생각하면 된다.

벡터란 쉽게 말해서 여러 개의 값을 묶어놓은 것이다.
행렬은 벡터를 여러 개 묶어놓은 것이다.

신경망 1층의 두 번째 특성을 생성하는 가중치 벡터는 마찬가지로 다음과 같이 표현할 수 있다.



자, 이제 우리의 데이터로 돌아가보자.
세 가지 특성을 가지며, "집의 가격"이라는 타겟을 가지는 집들에 대한 데이터였다.


이 데이터를 학습에 사용하기 위해서 다음과 같이 행렬로 만들 수 있다.
이 때 행렬은 세 가지 특성 벡터들을 묶어놓은 것으로 해석해도 되고, 여러 가지 집 벡터들을 묶어놓은 것으로 해석해도 된다. 첫 번째를 열 벡터 (세로로 길쭉) 라고 하며, 두 번째를 행 벡터 (가로로 길쭉) 라고 한다.


물론, "정답"에 해당하는 타겟은 따로 보관을 해두어야 한다. 모델이 학습하고 내놓는 예측에 대해 얼마나 정답에서 먼 지 체크하고, 어떻게 학습해야 정답과 더 가까워질 수 있을 지 계산해야하기 때문이다.


여기서 그런데 "서울", "광역시"와 같이 숫자가 아닌 값들은 어떻게 처리해야할까?
자연어처리(Natural Language Process) 분야에서는 실제로 텍스트를 입력으로 받아서 모델이 특성을 추출하고 원하는 예측을 진행하기도 한다.
하지만 우리가 살펴볼 단순한 모델은 오직 숫자만을 입력으로 받는다고 하자. 이 경우, 쉬운 방법으로는 텍스트의 종류별로 번호를 하나씩 할당해줄 수 있을 것이다.



하지만 이대로 학습을 진행해도 괜찮을까?
다른 특성들을 살펴보면 숫자들이 서로 비교할 수 있는 값을 가리키고 있는데, 위의 경우에는 단순히 번호에 지나지 않기 때문에 값끼리 비교할 수가 없다.


이런 경우에, 우리는 특성을 여러 개로 쪼개서 문제를 해결할 수 있다.
다음과 같이 지방인지 아닌지, 광역시인지 아닌지, 서울인지 아닌지에 대한 "예/아니오" 변수 세 개로 말이다.



이 과정을 원-핫 인코딩(one-hot encoding)이라고 한다.
"집의 위치"라는 특성 벡터는 다음과 같이 세 개의 원-핫 벡터로 바뀌게 된다.



입력 데이터를 행렬 형태로 바꾸는데 성공했으니, 이제 가중치 행렬이 어떻게 곱해지는지 살펴보자.


다음 벡터 두 개가 있다.
이 두 벡터를 곱하면 다음과 같다.


먼저 왼쪽 벡터의 (왼쪽에서) 첫번째 값과 오른쪽 벡터의 (위에서) 첫번째 값이 곱해진다.
그리고 왼쪽 벡터의 두번째 값과 오른쪽 벡터의 두번째 값이 곱해진다.
세번째 역시 마찬가지다.
그리고 나서, 이 세 값들을 더해주면 최종 결과값이 나온다.


이를 행렬곱(matrix multiplication)이라고 하는데, 한 줄이 아닌 여러 줄인 경우도 살펴보자. *

* 위 두 벡터를 1 x 3 행렬, 3 x 1 행렬로 해석한 것이다.


왼쪽이 행렬인 경우인데, 이걸 가로로 길쭉한 행벡터 두 개로 생각하면 이해하기 쉽다.

왼쪽 행렬의 첫번째 행벡터와 오른쪽 벡터가 행렬곱 연산을 통해 하나의 값이 나온다.
왼쪽 행렬의 두번째 행벡터와 오른쪽 벡터가 행렬곱 연산을 통해 하나의 값이 나온다.
이 두 값을 2X1 행렬*의 1행, 2행에 각각 넣으면 결과가 된다.

* 행렬의 크기는 m x n 형태로 나타낸다. (m: 행 개수, n: 열 개수)



행렬곱을 활용하면, 입력 데이터 행렬과 가중치 행렬을 쉽게 계산할 수 있다.
우선 그림과 같이 입력 데이터 2개가 묶인 행렬과 가중치 벡터를 생각해보자.





먼저 데이터1의 특성들과, 각각 특성의 가중치가 곱해져서 하나의 값이 나온다.
데이터2의 경우도 마찬가지다.

여기서 중요한 점은 여러 데이터가 들어오지만 가중치는 동일한 값들이 사용된다는 점이다.
수많은 데이터의 특성을 추출하고 학습하는 딥러닝의 원리를 생각해보면, 여러 데이터를 표현할 수 있는 일반화된 가중치 행렬을 구하는 것이 바로 학습의 목표라고 할 수 있는 것이다.


데이터 행렬에 1이 있는 열을 하나 추가하고, 가중치 벡터에 b (bias) 를 추가하면 완전한 선형변환이 된다.
물론 행렬에 직접 b를 각각 더해줘도 되지만, 행렬간의 곱으로 한번에 표현하는 방법이 있다는 사실을 알아두면 좋다.


이제 선형회귀가 좀 더 와닿지 않는가?

물론 행렬곱을 사용하지 않고도 순차적으로 하나씩 계산을 할 수 있다. 하지만, 행렬 계산의 경우 GPU를 사용해 병렬적으로 계산이 가능하기 때문에 훨씬 더 빠르다. 학계에서 잊혀져가던 신경망 모델이, GPU 성능의 비약적인 발전과 함께 2010년대에 부활한 것은 우연이 아니라고 할 수 있다.


데이터가 여러 개 들어오는 경우는 확인했지만, 가중치가 여러 개 들어오는 경우에는 어떤 일이 일어날까?
가중치 벡터가 여러 개가 되면, 새로 생성하는 다음 층의 특성의 개수가 여러 개로 늘어난다.


그림과 같이, 가중치 행렬의 첫번째 열벡터가 데이터1 벡터와 선형결합을 통해 "새 특성1" 결과값을 만든다.
두번째 가중치 벡터와 데이터1 벡터의 선형결합은 "새 특성2" 결과값을 만든다.




방금 살펴본 행열 연산은 이 그림의 연산과 같은 의미다.


데이터 행렬과 가중치 행렬을 이런 모양으로 기억해둔다면, 딥러닝을 학습할 때 여러 모로 도움이 될 것이다.

데이터가 더 많아지면, 행렬곱 (즉, 선형회귀) 으로 출력되는 결과 행렬의 행이 같은 개수만큼 늘어난다.


가중치 벡터가 더 많아지면, 새로 추출되는 특성의 개수가 늘어나 결과 행렬의 열이 같은 개수만큼 늘어난다.

우리 데이터로 다시 돌아가보자.
이 경우에는 특성의 개수가 5개이므로, 5개의 가중치 변수가 필요하다. (1과 b는 bias를 계산하려고 포함한 것임을 잊지 말자)


여기서 잠시 언급하고 넘어갈 부분이 있다.
특성 2의 경우, "집의 연도"에 해당하는 값들이기 때문에 숫자들의 크기가 매우 크다.
이렇게 되면, 이 값들에 곱해지는 w2 가중치에 따라 결과값이 크게 좌지우지되고, 결국 집이 언제 지어졌냐에만 집중해서 집의 가격을 예측해버리는 왜곡된 모델을 얻게된다.

이 문제를 어떻게 해결할 수 있을까?
단순한 방법으로는, 특성의 숫자들이 가지는 범위가 제각각이므로, 각 특성의 평균을 구한 뒤 평균에서 얼마나 멀어진 값인지를 대신 적는 것이다.

특성 1의 경우는 평균이 21.7이므로, 세 값에서 평균을 빼면 -1.7, -7.7, 9.3이 된다.
특성 2의 경우는 평균이 2004.3이므로, 세 값에서 평균을 빼면 -10.3, 4.7, 5.7이 된다.

이렇게 특성들의 범위를 비슷하게 맞춰주는 것을 데이터 스케일링(scaling), 또는 정규화(normalization)라고 한다.*
실제로 사용되는 스케일러의 경우 표준편차 등의 통계치도 활용해서 계산한다.

*엄밀하게는 (x - 최솟값) / (최댓값 - 최솟값) 공식을 통해 모든 값을 0~1 사이로 바꾸는 과정이다.

이제 가중치 벡터를 더 추가해보자.
가중치 벡터의 개수가 바로 다음 층에 새로 추출될 특성의 개수다.


5개의 특성에 가중치 벡터 3개 짜리 가중치 행렬이 나타내는 신경망을 나타낸 그림이다.


데이터 1이 들어왔을 때, 위와 같이 첫번째 가중치 벡터와 곱해지면 다음 층 첫번째 특성에 해당하는 값이 나온다. 남은 두 개의 특성도 마찬가지로, 데이터 1이 두번째, 세번째 가중치 벡터와 곱해지면 값이 나올 것이다.


이제 복잡하게 연결된 신경망 그림이 눈에 들어오기 시작할 것이다.
결국 다음 층의 노드 개수가 바로 이전 층과 곱해질 가중치 벡터의 개수인 것이다.



다음 장에서는 파이썬으로 데이터 행렬과 가중치 행렬을 생성하고 곱해볼 것이다. 이번에도 물론 아주 쉽게 준비할 것이니 걱정할 필요는 없다.

댓글 쓰기

8 댓글

  1. 혹시 궁금한게 있는데 답변해주시나요?? 너무 재밌게 잘 보면서 따라하고 있습니다. 퍼셉트론의 가중치 행렬을 만들라고 하면 바이어스로 주어진 값도 입력층의 가중치로 포함해서 표기해야 하나요~?

    답글삭제
    답글
    1. 그럼요, 질문하시면 답변해드립니다.
      표기는 weight 행렬과 bias 행렬을 따로 할 수도 있고, 본문에서처럼 weight 행렬 속에 bias를 포함하는 형식으로 표기할 수도 있습니다. 후자가 병렬 연산을 한 번에 할 수 있어서 효율적이지만, 꼭 지켜야하는 법칙은 전혀 아니라서 "해야한다"고 말씀드리긴 어려울 것 같네요.

      삭제
  2. 감사합니다 이해안됬던거 완전히 한방에 이해되고 너무 쉽고 직관적으로 가독성 높게 써주셨고 글쓴느데 얼마나 고민하고 노력했을지 예상이 안될정도네요 정말 감사합니다

    답글삭제
    답글
    1. 안녕하세요, 도움이 되었다니 기쁘네요.
      마음이 뿌듯해지는 댓글을 달아주셔서 저도 감사합니다 :)

      삭제
  3. 책을 몇권 봐도 이해 안갔는데 이렇게 싑게 설명 해주셔서 감사합니다.

    답글삭제
    답글
    1. 감사합니다! 정말 반가운 말씀이네요 :)

      삭제
  4. 이 내용이 비진공자를 위한 딥러닝 책에 있나요?

    답글삭제
    답글
    1. 네, 맞습니다. 책에는 개정된 내용을 담았고, 실습과 부록을 추가했습니다.

      삭제