2026년 5월 12일 화요일

내 신경망 제작하기

내 신경망 제작하기

이글의 제목은 다분히 "내 칩 제작 서비스"에서 따왔다.

바야흐로 "인공 지능"의 시대다. 일상 다반사가 된 "인공지능"의 기초는 "신경망"이라는데 도데체 그게 뭔가 싶어 찾아보면 알듯 모를듯 하다. 수많은 AI를 내세운 동영상 강좌가 넘쳐난다. 기초라고 하지만 끝까지 시청하기 어렵다. 수식 자랑을 늘어 놓는 탓이다. 그러다가 이 책을 발견 했다.

    Make Your Own Neural Network

마침 한글 번역판도 있다.

    신경망 첫걸음

이 책의 부제 "수포자도 이해하는 신경망 동작 원리와 딥러닝 기초"라는 문구에 동의한다. 다만 책 분량이 만만치 않다. 그래서 요약글을 준비했다. 원서의 제목대로 "내 신경망(My Own Neural Network)"을 제작하기가 목표다. 이 책은 1부에서 신경망의 작동 원리를 곱셈과 덧셈 만으로 설명한다. 약간의 고등 수학처럼 보이는 부분이 가미되어 있지만 1차 방정식과 인수분해 만으로도 충분히 이해할만 한 수준이다. 2부는 '파이썬(Python)'으로 내 신경망을 제작한다. DIY with Python 라니 제목부터 남다르다. 파이썬이라는 컴퓨팅 언어를 모르는 입문자를 배려하여  "아주 부드럽게 시작(A Very Gentle Start with Python)"한다. 1부가 '수포자' 였다면 2부는 '컴포자(컴퓨팅 언어를 포기한자)'를 대상으로 쓰였다고 해줄 만 하다. 텐서플로우니 파이토치니 하는 따위를 사용하지 않고도 MNIST 라는 손글씨 숫자 영상 인식을 수행하는 "내 신경망"을 충분히 코딩하고 실행할 수 있음을 보여준다. 가장 기본적인 numpy, matplot 만 사용한다. 사설이 길었다. 시작해 보자.

신경망이라고 하면서 무슨 생물학(뇌과학)을 들이밀 필요는 없을 것이다. 너무나 많이 들었을테니까!

비례식은 들어봤을 것이다. 예를 들어 거리의 단위로 마일(mile)과 키로미터(km)가 있다. 이 둘 사이의 환산 공식을 아는가? 모른다고 치자. 다행히 두 거리 단위의 관계는 비례한다.

    Mile = A * Kilometer

마일에 숫자(비례 상수 A)를 곱하면 킬로미터가 된다는 의미다. 두 단위의 관계를 그래프로 표현하면 다음과 같다. 가로축에 킬로미터 세로축이 마일이다. '무지렁이' 기계한테 '비례 관계'라는 정보만 주고 그 상수 값 A 를 구하라고 시켜보자. 기계는 아무렇게나 직선을 주욱 긋는다. 이 직선의 기울기가 상수 W 다.

<그림>

제대로 그었는지 확인하기 위해 한 측정 치를 제시한다.

    37mile -> 59.6Km

똑똑한 인간 이라면 단번에 계산할 수 있겠지만 기계는 아무것도 모른다. 자기가 그은 직선과 제시된 측정치와 맞춰보고 오차로부터 기울기를 보정할 줄은 안다.

<그림>

기계가 아무렇게나 그어놓은 직선으로부터 얻은 값을 y 라고 하자. 가로축의 동일한 지점 x 에서 제대로 나와야 할 값은 t 라고 하자.

    y = W*x

    t = (W + delta_W)*x

오차 Err은 t와 y의 차분이다.

    Err = (t - y) = delta_W*x

이로부터 수정해야 할 직선의 기울기의 량을 구했다.

    delta_W = Err / x

이 "보정치 구하기"가 바로 기계학습이다. 예로 돌아가 보자. 기계가 아무렇게 그은 직선의 기울기 W = 0.9 였다고 하자. 제시된 정보에 따르면 x = 37에서 목표치는 59.6 이라고 한다. 기계가 그은 직선에 의하면 x = 37에서 y=0.9*37=33.3 이다. 오차 Err = 59.6 - 33.3 = 26.3이다. 보정해야 할 기울기 delta_W = 26.3/37 = 0.7108 다. 따라서 기계는 그만큼 보정하여 기울기를 수정한다. 

    W_new = W + delta_W = 0.9 + 0.7108 = 1.6181

제시했던 정보를 검산 해보면 약간의 계산 오차가 있지만 마일에서 킬로미터로 변환하는 비례상수 A를 구했다.

    37 * W_new = 37 * 1.6108 = 59.5996

요약해보면,

- 기계는 아무렇게나 기울기를 정해서 직선을 그었다.
- 학습할 정보를 가지고 아무렇게 그은 직선의 기울기를 보정한다.

"아무렇게 그은 직선"이 신경망 학습의 시발점이자 핵심이다. "신경망" 별 것 아닐것 같은가?

직선을 사용하여 세상사를 구분하려고 한다. 세상일이 이렇게 단순하면 좋으련만 수많은 변수가 서로 얼키고 설켜있다. 직선 하나만으로 구분하기 어렵다는 것을 알게됐다. 당장 단 2개의 변수를 가진 XOR 라는 논리함수를 보자. 이 함수의 출력을 두축의 좌표계상에 배치하고 직선 한개로 구분할 방법이 없다.

<그림>

그렇다면 여러개의 직선을 동원하자. 동물의 뇌에서 일어나는 작동을 알아보니 단순하다. 신경 세포들 사이의 작용이 비례관계에 있다. 수많은 신경 세포들이 서로 얽혀있다. 인간의 뇌는 약 8천억개의 신경 세포들이 있다. 초파리는 장애물을 피해 비행하는데 10만개의 신경세포들을 동원한다. 엄청난 수의 직선들이 얽혀 신통한 결정을 하는 셈이다. 신경 세포는 별 것아닐지 몰라도 떼로 모아놓은 "신경망"은 상상을 초월한다. 신경 세포들이 층을 이뤄 연결되어 더욱 위력을 발휘한다. 게다가 이 연결은 유연하다.

<그림>

신경 세포들의 연결망을 다음과 같이 모사한다. 다수의 신경 세포들은 층으로 나눠져 분포되었다. 신경 세포들 사이의 연결을 묘사하는 수식은 1차 함수다. 1차 함수의 기울기가 연결 유연성을 나타내며 이를 가중치라 한다. 연결된 두 신경 세포의 관계는 이전 신경 세포의 출력과 가중치의 곱이다. 한 신경 세포에 다수의 신경 세포들이 연결되어 있으므로 이전 신경 세포의 출력과 연결강도(가중치) 곱의 합이 현재 신경 세포의 입력이다.

<그림>

한 신경 세포는 다수의 입력을 받아 자신의 출력을 결정하는 함수를 가진다. 이 함수를 활성함수라 한다. 연결받을 신경세포의 갯수(함수의 정의 구역의 범위)가 특정되지 않았더라도 출력을 제한할 필요가 있다. 시그모이드 함수는 입력이 무한히 증가 하더라도 그 출력을 수렴 시킬 수 있다.

<그림>

모사한 뇌의 신경 세포 연결망의 규모는 유한할 수 밖에 없다. 연결 강도의 범위를 제한 하는 방법도 있다. 따라서 시그모이드 함수를 적용하지 않더라도 신경 세포의 출력은 예측 가능하다. 계산이 복잡한 시그모이드 함수 대신 단순한 직선식을 적용하기도 한다.

두 층 사이 신경 세포의 연결을 수식으로 표현하려면 매우 많은 1차 식이 동원되어야 한다. 수학의 시그마 기호는 이를 간략하게 표현하는 방법이다. 층 1에서 층 2로 다수의 신경망들이 연결되었다고 하자.

<그림>

층2 신경세포의 입력은,

    Input_0 = W_00*Out_0 + W_10*Out_1 +  W_20*Out_2
    Input_1 = W_01*Out_0 + W_11*Out_1 +  W_21*Out_2
    Input_2 = W_02*Out_0 + W_12*Out_1 +  W_22*Out_2

우변을 일반화 시켜보자.

    Input_0 = {i=0,1,2}(W_i0*Out_i)
    Input_1 = 
{i=0,1,2}(W_i1*Out_i)
    Input_2 = 
{i=0,1,2}(W_i2*Out_i)

세개의 식을 일반화 하면 다음과 같이 한 식으로 표현할 수 있다.

    Input_j = {i=0,1,2)(W_ij*Out_i)
    j=0,1,2

W_ij 는 층 1의 i번째 신경세포의 출력과 층 2의 j번째 신경세포의 입력 사이에 연결 강도를 나타낸다. 

신경망을 2층에서 3개 층으로 확장해도 규칙은 같다.

    Input_k = {j=0,2)(W_jk*Out_j)
    k=0,1,2

위의 합(sigma)을 행렬로 표현하면 다음과 같다.

    |W_00 W_10 W_20|   |Out_0|
    |W_01 W_11 W_21| * |Out_1|
    |W_02 W_12 W_22|   |Out_2|

각 층을 구성하는 신경세포의 출력은,

    Out_j = Sigmoid(Input_j) = Sigmoid({i=0,1,2)(W_ij*Out_i))
    Out_k = Sigmoid(Input_k) = Sigmoid({j=0,1,2)(W_jk*Out_j))