본문 바로가기

딥러닝/밑바닥부터 배우는 딥러닝

3장 신경망

3.1 신경망

신경망은 퍼셉트론을 여러 층 쌓아서 만든 거대한 분류기를 말한다.

첫번째 층을 입력층, 마지막 층을 출력층이라 하고 중간의 모든 층들을 은닉층이라고 한다.

입력층은 0층에서부터 시작해서 1층, 2층, ...의 순으로 나아간다.

은닉층과 출력층은 입력 신호에 가중치를 곱하고 편향을 더한 뒤에 함수로 가공해서 출력 신호를 만드는데 이 때 가공하는 함수를 활성화 함수라고 한다

퍼셉트론은 단층 퍼셉트론과 다층 퍼셉트론으로 나눌 수 있는데, 단층 퍼셉트론에서는 지난 2단원에서 했던, 단 한 개의 층만으로 나타나는 AND, OR 게이트와 같은 퍼셉트론을 말하고(입력값을 경계로 출력이 바뀌는 함수), 다층 퍼셉트론은 XOR 게이트처럼 퍼셉트론 여러 개가필요한, 단층 퍼셉트론에서 층을 더 쌓아서 신경망의 구조로 만든 것이다. (여러 층으로 구성되어 시그모이드 등의 매끈한 활성 함수를 사용하는 네트워크)

 

3.2 활성화 함수

활성화 함수의 필요성

단층 퍼셉트론에서는 입력층에 가중치를 곱하고 편향을 더한 값을 출력으로 정의했으나, 신경망에선 이 값에 활성화 함수를 처리해 준 값을 출력으로 한다. XOR 게이트처럼 선형으로 데이터를 분류할 수 없는 경우엔 활성화 함수를 통해 데이터를 비선형으로 바꿔주는 과정이 필요하다. 즉, 활성화 함수라는 건 출력값을 활성화를 일으키게 할 것이냐를 결정하고 그 값을 부여하는 함수이다.

 

(1) 시그모이드 함수

자연상수를 이용하여 정의한다. 입력에 따라 출력이 부드럽고 연속적으로 변한다. 0 1 사이의 모든 값을 연속형으로 가진다.

 

(2) 계단 함수

입력이 0을 넘으면 1을 출력하고, 그렇지 않으면 0을 출력하는 함수이다. 0값을 기준으로 값이 급격하게 변화한다. 0또는 1값만을 가진다.

 

(3) ReLU 함수

입력이 0을 넘으면 입력을 그대로 출력하고, 아니라면 0을 출력하는 함수이다.

 

활성화 함수는 비선형 함수만을 사용해야 한다.

활성화 함수를 h(x)=cx와 같이 선형 함수로 정의하면, 은닉층을 썼지만 은닉층이 없는 네트워크로 표현된다. 그러니까, 활성화함수로 선형 함수를 쓰면 은닉층을 썼지만 은닉층이 없는 네트워크와 동일해지기 때문에 활성화 함수로 비선형 함수를 사용해야 한다.

 

3.3 다차원 배열의 계산

행렬 A와 B를 곱할 때 A(m*n), B(n*l)로 행렬의 shape이 맞도록 하는 것이 중요하다. 나머지는 생략

 

3.4 3층 신경망 구현하기

입력층에서 출력층까지 신경망의 계산이 어떻게 흘러가는 지 행렬으로 계산을 하는 과정에 대한 내용

입력층에서 은닉층을 거쳐서 출력층까지 신호가 변환되는 과정을 forward propagation이라고 한다.

1층의 첫번째 노드로 신호가 전달될 때는 입력층의 노드들(x1,x2)이 각각에 맞는 가중치(w1,w2) 가 곱해져서 편향과 함께 더해져야 한다. 여기서 마지막으로 각 값을 활성화 함수로 처리해준다. 이 과정을 1층의 모든 노드들에 대해 수행해준다. 이 과정을 1->2층에도 적용해준다. 마지막 은닉층에서 출력층으로는 활성화 함수를 앞 층들과는 다른 함수로 사용한다.

 

3.5 출력층 설계하기

기계 학습은 분류와 회귀로 나뉜다. 스팸 메일을 분류하는 문제는  0또는 1처럼 비연속적인 값으로 결과가 표현되는 문제를 분류 문제라고 하고, 집값 예측처럼 집의 크기, 방 수와 같은 변수들로 집 값이라는 연속적인 값으로 결과가 표현되는 문제는 회귀 문제라고 한다. 신경망은 분류와 회귀 둘 다에 이용될 수 있는데, 마지막 은닉층에서 출력층으로 신호가 전달 될 때 분류 문제인지 회귀 문제인지에 따라 사용하는 활성화 함수가 다르다. 회귀에서는 항등 함수, 분류에서는 소프트 맥스 함수를 사용한다

 항등함수에서는 출력층의 k번째 값은 그 전층의 k번째 노드의 값에만 영향을 받았는데, 소프트맥스 함수에서는 전 층의 모든 노드의 영향을 받는다

소프트맥스 함수 사용시 단점

'오버플로': 노드의 값을 지수함수로 표현하면 값이 너무 커져서 nan이 출력될 수 있음

 

해결:

소프트 맥스 함수에서 분자 분모에 같은 값을 곱하고, 지수함수 안에 로그 형태로 넣어줄 수 있다. 그러니까 소프트 맥스 함수에서는 입력값에 c’을 더하거나 빼도 같은 결과가 나온다. 그래서 입력값에 주로 입력의 최댓값을 빼줘서 값을 작게 만들어줘서 해결 할 수 있다.

 

소프트 맥스 함수의 장점: 결과를 확률로써 해석 가능하다. 

출력은 항상 0에서 1 사이의 값이 되고 출력의 총 합은 1이 된다. 따라서 출력이 [0.018, 0.245, 0.737]로 계산됐을 때, 2번째 원소일 확률이 24.5%로 가장 높다는 확률적인 이야기를 할 수 있다.

 

3.6 손글씨 숫자 인식

 학습이 완료된 매개변수 W,b를 사용해서 mnist의 시험 이미지를 추론해 볼 것이다. mnist는 손글씨 숫자 이미지 집합이다. 60000장의 train set10000장의 test set을 가지고 있다.

load_mnist로 mnisttrain setx,y, test setx,y를 가져온다.

 

normalize=True

x에 해당하는 값을 정규화 해준다. 정규화는 전처리 과정의 일부인데, 정규화가 중요한 이유는 입력된 변수들 간 값의 범위가 비슷해야 모델의 정확도가 높기 때문이다. 예를 들어 집값을 예측하는 모델을 만든다고 할 때 첫번째 변수로 집의 평수로 평균 1000피트 가 된다고 하고, 두번째 변수로는 방의 개수로 평균 3개가 된다고 하자. 이렇게 변수마다 값의 범위가 크게 차이 나면 모델을 만드는데 시간이 오래 걸려서 효율적이지 않다. 그래서 각 변수의 평균을 빼주고 표준편차로 나눠주거나 해서 모든 변수값이 -11 사이에 있도록 하는 것을 정규화라고 한다. -11 사이에 있지 않아도 된다. 01 사이, -33 사이 등 여하튼 작은 값 안에 포함되면 된다.

 

flatten=True

x에 해당하는 28*28짜리 배열을 784개의 원소로 이루어진 벡터 형태로 만들어 준다. 후에 for문으로 obs마다 W와 b로 forward propagation을 진행해 줄 때 한 행 안에 하나의 example이 있는 것이 좋기 때문에 설정해준다.

 

one_hot_label=True

정답을 표시한 데이터로 0또는 1값만을 가지게 한다. 즉 레이블이 3이면 [0,0,1,0,0,0,..]이 된다. 여기선 defaultFalse로 지정해서 0~9사이의 레이블이 나타나도록 했다.

 

함수로 test 데이터를 가져오고, W,b값을 가져오고 출력값을 예측한다. 

 

get_data()

load_mnistmnist 데이터에서 x_test,y_test 값을 불러올 것이다. 지금은 test set에서 모델의 정확도를 예측할 것이기 때문에 train set 대신 test set만 불러온다.

init_network()

ickle 패키지를 사용하여 mnist 데이터를 바로 불러올 수 있게 해준다. (참고로 파이썬에서 pickle 패키지는 텍스트 이외의 자료형을 바로 불러오도록 하는 패키지이다.) 여기서 불러온 network에 가중치(w1,w2,w3), 편향(b1,b2,b3)가 저장되어 있다. 아마도 5단원의 back propagation에서 가중치와 편향을 어떻게 직접 학습하는 지 공부할 것이다. 지금 forward propagation에서는 그것까지는 안하고 이미 network 안의 학습된 가중치와 편향으로 y값을 예측하는 것만 한다.

predict()

network에서 불러온 가중치와 편향으로 forward propagation을 통해 입력에 대해 출력을 예측하는 함수이다. 아까 전에 했던 것처럼 a1 xw1을 곱하고 b1을 더해주고 z1a1에 시그모이드 함수를 처리해주고, a2,z2도 그대로 해주는데, a3에서는 z2,w3을 곱하고 b3를 적용하는데, 시그모이드 함수 대신 소프트 맥스 함수를 처리한다. 앞에서, 기계학습은 분류와 회귀 문제로 나뉘고, 분류 문제는 소프트맥스, 회귀는 항등함수를 사용한다고 했다. 손글씨 문제는 y0부터 9까지 불연속적인 값을 예측하는 분류 문제여서 a3에 소프트맥스 함수를 처리해서 y값을 얻는다. 출력층에는 10개의 노드가 있어서, predict에 입력되는 한 개의 x에 대해 0부터 9까지의 값이 될 확률의 10개의 예측을 내놓는다.

 

test set에서 예측한 y값에 대해 실제 y값으로 예측의 정확도를 구한다.

 

get_data를 통해 x,tx_test,y_test가 들어간다. accuracy_cnt에 정확도를 저장한다. x에는 (10000,784)x_test가 저장되어 있고 총 10000번의 반복문을 실행해 줄 것이다. y에는 x에 따른 0일 확률에서 9일 확률까지 array로 들어간다. p y10가지 값 중 확률이 가장 높은 원소의 인덱스가 나오고 이것이 x_test에 대해 예측된 y_test의 값이다. t는 실제 y_test의 값인데, pt를 비교해서 분류의 정확도를 측정한다. 93%의 정확도가 나왔다.

 

배치 처리

 

방금 전처럼 for문으로 하나하나 관측치에 대해 처리하는 게 아니라 여러 데이터를 하나로 묶어서 한꺼번에 배열로 처리할 수 있다. 묶은 데이터의 단위를 배치라고 하고 이런 처리를 배치 처리라고 한다. 묶음으로 계산을 처리하면 계산 속도가 높아진다. batch size100이라고 했을 때 x_batch는 행이 100, 열이 784개인 배열이 된다. y_batchx_batch에 대해 network의 가중치와 편향으로 예측한 y값인데, y0일 확률부터 9일 확률까지 나타내므로 행이 100, 열이 10개인 배열이 된다. py_batch의 각 행에서 최댓값의 index를 나타내주고, 이를 실제 y값인 t와 비교해줘서 정확도를 예측한다. 아까 for문으로 예측했을 때와 완전히 동일한 정확도를 얻었다.

'딥러닝 > 밑바닥부터 배우는 딥러닝' 카테고리의 다른 글

7장. 합성곱 신경망(CNN)  (0) 2021.03.02
6장. 학습 관련 기술들  (0) 2021.02.23
5장. 오차역전파법  (1) 2021.02.10
4장 신경망 학습  (0) 2021.02.01