Python/ML & DL 공부

[DL] 07-2 심층 신경망

dori_0 2022. 3. 23. 17:38

혼자 공부하는 머신러닝+딥러닝 책을 바탕으로 공부한 내용입니다.

 

CH7 딥러닝 시작 ②

케라스 API를 활용한 심층 신경망

 


 

인공 신경망에 층을 여러 개 추가하여 패션 MNIST 데이터셋을 분류하면서 케라스로 심층 신경망을 만드는 법을 자세히 배워보자

 

▶ 2개의 층

먼저, 데이터셋을 먼저 불러오자

from tensorflow import keras

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

 

7-1장에서 했던 것을 똑같이 해보자

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)
  1. 이미지의 픽셀값을 0-255 범위에서 0-1 사이로 변환
  2. 28 X 28 크기의 2차원 배열을 784 크기의 1차원 배열로 펼치기
  3. 훈련 세트와 검증세트로 나누기

 

 

7-1장 인공 신경망의 성능을 더 높이기 위해 이번에는 인공 신경망 모델에 층을 2개 추가할 것이다!

1절에 만들었던 신경망 모델과 다른 점은 입력층과 출력층 사이에 은닉층(밀집층)이 추가된 것이다.

 

 

활성화 함수 - 신경망 층의 선형 방정식의 계산 값에 적용하는 함수
(1) 출력층에 적용하는 활성화 함수는 종류가 제한되어 있음
     이진 분류 - 시그모이드 함수
     다중 분류 - 소프트맥스 함수
(2) 은닉층의 활성화 함수는 비교적 자유로움
     대표적으로 시그모이드 함수, 렐루 함수가 있음

 

 

시그모이드 활성화 함수를 사용한 은닉층, 소프트맥스 함수를 사용한 출력층을 케라스의 Dense 클래스로 만들어보자

dense1 = keras.layers.Dense(100, activation='sigmoid', input_shape=(784,))
dense2 = keras.layers.Dense(10, activation='softmax')
  • dense1은 100개의 뉴런을 가진 은닉층
  • dense2는 10개의 뉴런을 가진 출력층
  • 케라스에서 신경망의 첫번째 층은 input_shape 매개변수로 입력의 크기를 꼭 지정해주어야 함

 

 

▶ 심층 신경망

이제 dense1, dense2 객체를 Sequential 클래스에 추가하여 심층 신경망(DNN)을 만들어보자

리스트로 전달할 때 가장 처음 등장하는 은닉층에서 마지막 출력층 순서로 나열해야 한다.

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

 

 

▶ 층을 추가하는 다른 방법

Sequential 클래스에 층을 추가하는 다른 방법도 알아보자

 

(1) Sequential 클래스의 생성자 안에서 바로 Dense 클래스의 객체 만들기

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()

  • 모델 이름, 층 이름을 설정해주었음

 

 

(2) Sequential 클래스의 객체를 만들고 add() 메서드를 호출하여 층 추가하기

# add 메서드 사용
model = keras.Sequential()
model.add(keras.layers.Dense(100, activation='sigmoid', input_shape=(784,)))
model.add(keras.layers.Dense(10, activation='softmax'))

model.summary()

  • Sequential 클래스에서 층을 추가할 때 가장 널리 사용하는 방법

 

이제 모델을 훈련해보자

# 모델 훈련
model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')
model.fit(train_scaled, train_target, epochs=5)

  • 훈련 세트에 대한 성능을 보면 추가된 층이 성능을 향상시켰다는 것을 알 수 있다.
  • 몇 개의 층을 추가하더라도 compile(), fit() 메서드의 사용법은 동일하다는 것이 케라스 API의 장점이다.

 

 

▶ 렐루 함수

  1. 이미지 분류 모델의 은닉층에서 많이 사용하는 활성화 함수 
  2. 입력이 양수일 경우 입력값을, 음수일 경우에는 0을 만드는 함수이다.
  3. 심층 신경망에서 뛰어남

 

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'))
  • 앞에서 썼던 reshape()말고 이번에는 Flatten 클래스를 이용했고, 첫번째 Dense 층의 활성화 함수를 'relu'로 바꿔주었다.
  • Flatten 클래스는 배치 차원을 제외하고 나머지 입력 차원을 모두 일렬로 펼치는 역할을 한다.
  • Flatten 층은 입력층 바로 뒤에 추가한다.

 

 

모델의 summary() 메서드를 호출해보자

model.summary()

  • 케라스의 Flatten 층을 신경망 모델에 추가하면 입력값의 차원을 짐작할 수 있다는 장점이 있음
  • 784개의 입력이 첫번째 은닉층에 전달된다는 것을 알 수 있음 (이전 모델에서는 눈치채기 어려웠음)

 

 

이제 훈련 데이터를 다시 준비해서 모델을 훈련해보자

(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)

  • 7-1장의 은닉층을 추가하지 않은 경우보다 몇 퍼센트 성능이 향상 되었다.

 

 

▶ 옵티마이저

  1. 신경망의 가중치와 절편을 학습하기 위한 알고리즘
  2. 케라스에는 다양한 경사 하강법 알고리즘이 구현되어 있음 (SGD, 네스테로프 모멘텀, RMSprop, Adam 등)

 

① 우리는 compile() 메서드에서 케라스의 기본 경사 하강법 알고리즘인 RMSprop을 사용했었다.

가장 기본적인 옵티마이저는 확률적 경사 하강법인 SGD이다.

model.compile(optimizer='sgd', loss='sparse_categorical_crossentropy', metrics='accuracy')
sgd = keras.optimizers.SGD()
model.compile(optimizer=sgd, loss='sparse_categorical_crossentropy', metrics='accuracy')
  • 이렇게 두 가지 방법으로 SGD 옵티마이저를 사용할 수 있다.
# 학습률
sgd = keras.optimizers.SGD(learning_rate=0.1)
  • SGD 클래스의 학습률 기본값은 0.01이고 이렇게 learning_rate 매개변수에 지정하여 바꿀 수 있다.

 

 

② SGD 클래스의 momentum 매개변수의 기본값은 0이다.

0보다 큰 값으로 지정하면 이전의 그레이디언트를 가속도처럼 사용하는 모멘텀 최적화를 사용한다.

(보통 0.9 이상으로 지정)

sgd = keras.optimizers.SGD(momentum=0.9, nesterov=True)
  • nesterov를 기본값 False에서 True로 바꾸면 네스테로프 모멘텀 최적화를 사용한다.
  • 네스테로프 모멘텀은 모멘텀 최적화를 2번 반복하여 구현함
  • 대부분의 경우 네스테로프 모멘텀 최적화가 기본 확률적 경사 하강법보다 더 나은 성능을 제공

 

 

③ 모델이 최적점에 가까이 갈수록 학습률을 낮출 수 있다.

안정적으로 최적점에 수렴하는 학습률을 적응적 학습률이라 하고, 대표적인 옵티마이저는 Adagrad, RMSprop이다.

adagrad = keras.optimizers.Adagrad()
model.compile(optimizer=adagrad, loss='sparse_categorical_crossentropy', metrics='accuracy')

rmsprop = keras.optimizers.RMSprop()
model.compile(optimizer=rmsprop, loss='sparse_categorical_crossentropy', metrics='accuracy')
  • 이렇게 optimizer 변수에 지정하여 쓸 수 있고, optimizer 매개변수의 기본값이 바로 rmsprop이다.

 

 

④ 모멘텀 최적화와 RMSprop의 장점을 접목한 것이 Adam이다.

마지막으로 Adam 클래스의 매개변수 기본값을 사용해 패션 MNIST 모델을 훈련해보자

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.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics='accuracy')
model.fit(train_scaled, train_target, epochs=5)

  • compile() 메서드의 optimizer를 adam으로 설정하고 5번의 에포크 동안 훈련
  • 기본 RMSprop을 사용했을 때와 adam을 사용했을 때 거의 같은 성능을 보여주는 것을 확인할 수 있다.

 

 

마지막으로 검증 세트에서의 성능을 확인해보면

model.evaluate(val_scaled, val_target)

기본 RMSprop보다 조금 나은 성능을 내는 것으로 보인다.

 

 

 

▶ 정리

  • 키워드 : 심층 신경망, 렐루 함수, 옵티마이저
  • SGD 기본 경사 하강법 옵티마이저 클래스
    1. momentum 매개변수에 0 이상의 값을 지정하면 모멘텀 최적화를 수행
    2. nesterov 매개변수를 True로 설정하면 네스테로프 모멘텀 최적화를 수행
  • Adagrad 옵티마이저 클래스
    1. 그레이디언트 제곱을 누적하여 학습률을 나눔
    2. initial_accumulator_value 매개변수에서 누적 초깃값을 지정할 수 있음 기본값은 0.1
  • RMSprop 옵티마이저 클래스
    1. Adagrad처럼 그레이디언트 제곱으로 학습률을 나누지만 최근의 그레이디언트를 사용하기 위해 지수 감소를 사용
    2. rho 매개변수에서 감소 비율을 지정하며 기본값은 0.9
  • Adam
    1. 모멘텀 최적화에 있는 그레이디언트의 지수 감소 평균을 조정하기 위해 beta_1 매개변수가 있으며 기본값은 0.9
    2. RMSprop에 있는 그레이디언트 제곱의 지수 감소 평균을 조절하기 위해 beta_2 매개변수가 있으며 기본값은 0.999

=> SGD, Adagrad, RMSprop, Adam 모두 learning_rate 매개변수로 학습률을 지정하며 기본값은 0.001이다.