Machine Learning/Basic

[7-2] 심층 신경망

jwjwvison 2021. 4. 13. 21:48

이 포스팅은 혼자 공부하는 머신러닝 + 딥러닝을 공부하고 정리한것 입니다.


model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics='accuracy')
model.fit(train_scaled,train_target,epochs=5)

 앞에서 만들었던 인공 신경망의 성능을 더 높여보자.

 

 

2개의 층

from tensorflow import keras

(train_input,train_target),(test_input,test_target)= keras.datasets.fashion_mnist.load_data()

 이미지의 픽셀값을 0~255 범위에서 0~1 사이로 변환하고 28 x 28 크기의 2차원 배열을 784 크기의 1차원 배열로 펼친다. 마지막으로 사이킷런의 train_test_split() 함수로 훈련 세트와 검증 세트로 나눈다.

from sklearn.model_selection import train_test_split

train_scaled=train_input/255.0
train_scaled=train_scaled.reshape(-1,28*28)
train_scaled,val_scaled,train_target,val_target=train_test_split(train_scaled,train_target,test_size=0.2,random_state=42)

 

 이제 인공 신경망 모데렝 층을 2개 추가해 보겠다. 여기서 만들 모델의 대략적인 구조는 다음 그림과 같다.

 앞에서 만든 신경망 모델과 다른 점은 입력층과 출력층 사이에 밀집층이 추가된 것이다. 이렇게 입력층과 출력층 사이에 있는 모든 층을 은닉층(hidden layer)이라고 부른다.

 은닉층의 활성화 함수는 출력층의 종류제한과 다르게 비교적 자유롭다. 대표적으로 시그모이드 함수와 렐루(ReLU) 함수 등을 사용한다.

 그런데 은닉층에 왜 활성화 함수를 적용할까? 다음 그림에 있는 2개의 선형 방정식을 생각해 보자. 왼쪽의 첫 번째 식에서 계산된 b가 두 번째 식에서 c를 계산하기 위해 쓰인다. 하지만 두 번째 식에 첫 번째 식을 대입하면 오른쪽처럼 하나로 합쳐질 수 있다. 이렇게 되면 b는 사라진다. b가 하는 일이 없는 셈이다.

 신경망도 마찬가지이다. 은닉층에서 선형적인 산술 계산만 수행한다면 수행 역할이 없는 셈이다. 선형 계산을 적당하게 비선형적으로 비틀어 주어야 한다. 그래야 다음 층의 계산과 단순히 합쳐지니 않고 나름의 역할을 할 수 있다. 마치 다음과 같다.

 시그모이드 활성화 함수를 사용한 은닉층과 스프트맥스 함수를 사용한 출력층을 케라스의 Dense클래스로 만들어 보겠다. 케라스에서 신경망의 첫 번째 층은 input_shape 매개변수를 입력의 크기를 꼭 지정해 주어야 한다.

dense1=keras.layers.Dense(100,activation='sigmoid',input_shape=(784,))  #은닉층
dense2=keras.layers.Dense(10,activation='softmax')

 dense1은 은닉층이고 100개의 뉴런을 가진 밀집층이다. 은닉층의 뉴런 개수를 정하는데는 특별한 기준이 없다. 몇 개의 뉴런을 두어야 할지 판단하기 위해서는 상당한 경험이 필요하다고 한다. 여기에서 한 가지 제약 사항이 있다면 적어도 출력층의 뉴런보다는 많게 만들어야 한다. 클래스 10개에 대한 확률을 예측해야 하는데 이전 은닉층의 뉴런이 10개보다 적다면 부족한 정보가 전달될 것이다.

 dense2 는 출력층이다. 10개의 클래스를 분류하므로 10개의 뉴런을 두었고 활성화 함수는 소프트맥스 함수로 지정했다.

 

 

심층 신경망 만들기

 이제 앞에서 만든 dense1과 dense2 객체를 Sequential 클래스에 추가하여 심층 신경망(deep neural network. DNN)을 만들어 보겠다.

model=keras.Sequential([dense1,dense2])

model.summary()

 출력 크기를 보면 (None, 100)이다. 첫 번째 차원은 샘플의 개수를 나타낸다. 샘플 개수가 아직 정의되어 있지 않아서 None인데 그 이유는 케라스 모델의 fit()메서드에 훈련 데이터를 주입하면 이 데이터를 한 번에 모두 사용하지 않고 잘게 나누어 여러 번에 걸쳐 경사 하강법 단계를 수행한다. 바로 미니배치 경사 하강법을 사용하는 것이다.

 케라스의 기본 미니매치 크기는 32개이다. 이 값은 fit() 메서드에서 batch_size 매개변수로 바꿀 수 있다. 따라서 샘플 개수를 고정하지 않고 어떤 배치 크기에도 유연하게 대응할 수 있도록 None 으로 설정한다. 이렇게 신경망 층에 입력되거나 출력되는 배열의 첫 번째 차원을 배치 차원 이라고 부른다.

 

 마지막으로 모델 파라미터 개수가 출력된다. (784 x 100 + 100) + (100 x 10 + 10) = 79510개이다.

 간혹 경사 하강법으로 훈련되지 않는 차라미터를 가진 층이 있는데 이런 층의 파라미터 개수는 Non-trainable params 에 표시된다.

 

 

층을 추가하는 다른 방법

model=keras.Sequential([
                        keras.layers.Dense(100,activation='sigmoid',input_shape=(784,),
                                           name='hidden'),
                        keras.layers.Dense(10,activation='softmax',name='output')
],name='패션 MNIST 모델')

model.summary()

 

model=keras.Sequential()
model.add(keras.layers.Dense(100,activation='sigmoid',input_shape=(784,)))
model.add(keras.layers.Dense(10,activation='softmax'))

 이제 모델을 훈련해 보자.

model.compile(loss='sparse_categorical_crossentropy',metrics='accuracy')
model.fit(train_scaled,train_target,epochs=5)

 훈련 세트에 대한 성능을 보면 추가된 층이 성능을 향상시켰다는 것을 잘 알 수 있다.

 

 

렐루함수

 초창기 인공 신경망의 은닉층에 많이 사용된 활성화 함수는 시그모이드 함수였다. 하지만 이 함수에는 단점이 있는데, 이 함수의 오른쪽과 왼쪽 끝으로 갈수록 그래프가 누워있기 때문에 올바른 출력을 만드는데 신속하게 대응하지 못한다.

 특히 층이 많은 심층 신경망일수록 그 효과가 누적되어 학습을 더 어렵게 만든다. 이를 개선하기 위해 렐루 함수가 제안되었다. 이 함수는 입력이 양수일 경우 마치 활성화 함수가 없는 것처럼 그냥 입력을 통과시키고 음수일 경우에는 0으로 만든다.

 렐루 함수는 max(0,z) 와 같이 쓸 수 있다. 이 함수는 z가 0보다 크면 z를 출력하고 z가 0보다 작으면 0을 출력한다. 렐루 함수는 특히 이미지 처리에서 좋은 성능을 낸다고 알려져 있다.

 

model=keras.Sequential()
model.add(keras.layers.Flatten(input_shape=(28,28)))
model.add(keras.layers.Dense(100,activation='relu'))
model.add(keras.layers.Dense(10,activation='softmax'))

 Flatten 층은 reshape() 메서드로 데이터를 1차원으로 펼쳐야 하는 번거로움을 덜어준다. Flatten 클래스는 배치 차원을 제외하고 나머지 입력 차원을 모두 일렬로 펼치는 역할만 해서 인공 신경망의 성능을 위해 기여하는 바는 없다. 그러나 입력층과 은닉층 사이에 추가해야 하기 때문에 이를 층이라고 부른다.

model.summary()

 앞의 출력에서 784개의 입력이 첫 번째 은닉층에 전달되는 것을 알 수 있다. 입력 데이터에 대한 전처리 과정을 가능한 모델에 포함시키는 것이 케라스 API의 철학 중 하나이다.

 

 그럼 훈련 데이터를 다시 준비해서 시작해보자.

(train_input,train_target),(test_input,test_target) = keras.datasets.fashion_mnist.load_data()
train_scaled=train_input/255.0
train_scaled,val_scaled,train_target,val_target=train_test_split(train_scaled,train_target,test_size=0.2,random_state=42)

model.compile(loss='sparse_categorical_crossentropy',metrics='accuracy')
model.fit(train_scaled,train_target,epochs=5)

 시그모이드 함수를 사용했을 때와 비교하면 성능이 조금 향상되었다.

model.evaluate(val_scaled,val_target)

 

 

옵티마이저

앞에서 하이퍼파라미터는 모델이 학습하지 않아 사람이 지정해주어야 하는 파라미터라고 했다. 신경망에는 특히 하이퍼파라미터가 많다. 어떤 하이퍼파라미터가 있는지 알아보자. 지금까지 다룬 하이퍼파라미터는 추가할 은닉층의 개수, 뉴런 개수, 활성화 함수, 층의 종류, 배치 사이즈 매개변수, 에포크 매개변수 등이 있다.

 

 케라스는 기본적으로 미니배치 경사 하강법을 사용하며 미니배치 개수는 32개이다. fit() 메서드의 batch_size 매개변수에서 이를 조정할 수 있으며 역시 하이퍼파라미터 이다. 또한 fit()메서드의 epochs 매개변수도 하이퍼파라미터 이다. 

 마지막으로 compile() 메서드에서는 케라스의 기본 경사 하강법 알고리즘인 RMSprop을 사용했다. 케라스는 다양한 종류의 경사 하강법 알고리즘을 제공한다. 이들을 옵티마이저(optimizer)라고 한다. RMSporp의 학습률 또한 조정할 하이퍼파라미터 중 하나이다.

 SGD 외에도 다양한 옵티마이저 들이 있다.

model=keras.Sequential()
model.add(keras.layers.Flatten(input_shape=(28,28)))
model.add(keras.layers.Dense(100,activation='relu'))
model.add(keras.layers.Dense(10,activation='softmax'))

model.evaluate(val_scaled,val_target)

 환경마다 조금씩 차이가 있을 수 있지만 여기서는 기본 RMSprop 보다 조금 나은 성능을 보여준다

 

 

 

결론


 이번 시간에는 여러 개의 층을 추가하여 다층 인공 신경망을 만드는 방법을 공부했다. 특별히 이런 인공 신경망을 심층 신경망이라고 부른다. 또 케라스 API를 사용하여 층을 추가하는 여러 가지 방법을 알아보았다.

 은닉층에 적용한 시그모이드 활성화 함수 대신에 새로운 렐루 활성화 함수에 대해 공부했고 이를 적용해 약간의 성능을 향상시켰다. 또한 다양한 고급 경사 하강법 옵티마이저들을 적용하는 방법도 살펴보았다.

'Machine Learning > Basic' 카테고리의 다른 글

[8-1] 합성곱 신경망  (0) 2021.04.14
[7-3] 신경망 모델 훈련  (0) 2021.04.13
[7-1] 인공 신경망  (0) 2021.04.13
[6-3] 주성분 분석  (0) 2021.04.13
[6-2] k-평균  (0) 2021.04.13