본문 바로가기

AI/딥러닝(Deep Learning)

[딥러닝/DL]2. 심층 신경망

728x90
반응형

Pupbani는 완성된 모델을 가지고 마케팅 팀장에게 찾아갔다.
마케팅 팀장은 성능이 조금더 좋았으면 좋겠다고 하였다.
그래서 Pupbani는 층을 더 추가하여 성능을 올려보겠다고 하였다.

여러개의 층

먼저 사용할 데이터를 가져와보겠다.

# MNIST 데이터 가져오기
from tensorflow import keras
(train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data()

# 데이터 정규화 및 1차원 배열로 변경
train_scaled = train_input / 255.0
train_scaled = train_scaled.reshape(-1, 28*28)

# 훈련 세트, 검증 세트로 분류
from sklearn.model_selection import train_test_split
train_scaled, val_scaled, train_target, val_target = train_test_split(
    train_scaled, train_target, test_size=0.2, random_state=42)

이전에 만들었던 모델은 입력층과 출력층만 존재했다.
이 사이에 층을 추가할 수 있는데 사이에 추가되는 층을 은닉층(Hidden Layer)라고 부른다.
출력층은 이진 분류일 때는 sigmoid, 다중 분류일 때는 softmax 함수를 사용해야 한다.

  • ※ 회귀 문제일 경우는 출력층의 활성화 함수를 지정하지 않는다.

은닉층은 이에 비해 자유롭다.(sigmoid, softmax, relu 등)

은닉층을 만들어보자.
은닉층의 뉴런 개수는 출력층 보다는 많아야 한다.

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

은닉층인 dense1은 sigmoid를 활성화 함수로 지정하고 100개의 뉴런을 가지고 있다.

이제 이 층을 가지고 심층 신경망(Deep Neural Network)을 만들어보자.

  • Dense 클래스로로 층을 작성할 때 name 속성을 통해 층의 이름을 설정할 수 있다.
  • Sequential 클래스로 모델을 만들 때 name 속성을 통해 모델의 이름을 설정할 수 있다.
model = keras.Sequential([dense1, dense2],name="패션 MNIST 모델")
# 또다른 방법
# 방법1
"""
    model = keras.Sequential([
        keras.layers.Dense(100, activation='sigmoid', input_shape=(784,), name='hidden'),
        keras.layers.Dense(10, activation='softmax', name='output')
    ], name='패션 MNIST 모델')
"""
# 방법2
"""
    model = keras.Sequential()
    model.add(keras.layers.Dense(100, activation='sigmoid', input_shape=(784,)))
    model.add(keras.layers.Dense(10, activation='softmax'))
"""

만들어진 신경망 모델의 정보를 알고 싶으면 summary() 메서드를 호출하면 된다.

model.summary()

Param의 개수는 "(입력 개수+1(바이어스 개수) ) x 뉴런 개수"이다.

이제 모델을 훈련해보자.

model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')

model.fit(train_scaled, train_target, epochs=5)

정확도가 0.8802로 이전에 층이 1개일 때보다 성능이 더 좋아졌다.

렐루 함수

초장기 인공 신경망의 은닉층에 많이 사용된 활성화 함수는 Sigmoid 함수이다.
하지만 이 Sigmoid 함수는 왼쪽과 오른쪽이 끝으로 갈 수록 누워있는 형태이기 때문에 올바른 출력을 만드는데 신속하게 대응하지 못했다.

이러한 Sigmoid 함수의 단점은 층이 많은 심층 신경망일수록 그 효과가 누적되어 나타나 학습을 어렵게 만들었다.
Sigmoid 함수를 개선하려고 만들어진 함수가 바로 렐루(ReLU) 함수이다.
렐루(ReLU)는 다음과 같은 특징을 갖는다.

  • 입력이 양수일 경우 활성화 함수가 없는 것 처럼 입력을 통과 시킨다.
  • 음수일 경우 0으로 만든다.

이제 렐루를 사용하여 층을 만들고 학습을 진행 해보자.
그 전에 Keras가 제공하는 Flatten이라는 클래스를 통해 2차원 데이터를 1차원으로 펼칠 수 있다.
Flatten은 하나의 층으로 매개변수로 입력 데이터의 형태만 적어주면 된다.

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

모델을 만들었으니 데이터를 준비해보자

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

Flatten 층이 있으므로 reshape로 따로 데이터를 변환할 필요 없다.

model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')

model.fit(train_scaled, train_target, epochs=5)


정확도가 0.8863으로 sigmoid 함수를 사용할 때 보다 더 향상되었다.

model.evaluate(val_scaled, val_target)

검증 세트의 검증 점수는 약 0.8823 이다.

옵티마이저(Optimizer)

신경망에서는 사람이 지정해줘야하는 하이퍼파라미터가 많다.
예1. 학습률을 뜻하는 learning rate는 값에 따라 경사하강법에 큰 영향을 미친다.

예2. fit 메서드에서 batch_size라는 하이퍼파라미터가 있다.

  • 케라스는 기본적으로 미니배치 경사 하강법을 사용하는데 batch_size는 이 미니배치의 개수를 설정하는 하이퍼파라미터이다.
  • batch_size의 기본값이 32이다.

complie 메서드에서는 케라스의 기본 경사 하강법 알고리즘인 RMSprop을 사용한다.
케라스는 다양한 종류의 경사 하강법 알고리즘을 제공한다.
이들을 옵티마이저(Optimizer)라고 부른다.

compile 메서드에서 옵티마이저를 설정해보자.
가장 기본적인 확률적 경사 하강법은 SGD이다.
SGD 옵티마이저를 사용하려면 optimizer 매개변수의 값을 'sgd'로 주면 된다.

model.compile(optimizer='sgd', loss='sparse_categorical_crossentropy', metrics='accuracy')

이 SGD 옵티마이저는 tensorflow.keras.optimizers 패키지 아래 SGD 클래스로 구현되어 있다.
그래서 위의 코드를 다음과 같이 쓸수도 있다.

sgd = keras.optimizers.SGD()
model.compile(optimizer=sgd, loss='sparse_categorical_crossentropy', metrics='accuracy')

SGD의 학습률 기본값이 0.01이인데 이를 바꿀 수 있다.
learning_rate 매개변수를 다른 값으로 주면 된다.

# 학습률을 0.1로 변경
sgd = keras.optimizers.SGD(learning_rate=0.1)

SGD 이외에도 많은 옵티마이저들이 있다.
많이 사용되는 옵티마이저들을 소개해보겠다.

위에 그림을 보면 기본 경사 하강법 옵티마이저는 모두 SGD 클래스에서 제공한다.

sgd = keras.optimizers.SGD(momentum=0.9, nesterov=True)

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

  • momentum이 0보다 큰 경우 : 마치 이전의 그레이디언트 가속도 처럼 사용하는 모멘텀 최적화(Momentum Optimization)를 사용한다.
  • 보통 momentum 매개변수의 값은 0.9 이상을 지정한다.

SGD 클래스의 nesterov 매개변수를 기본값 False이다.
True로 바꾸면 네스테로프 모멘텀 최적화(Nesterov Momentum Optimization)를 사용한다.

  • 모멘텀 최적화를 2번 반복하여 구현한다.
  • 대부분의 경우 기본 확률적 경사 하강법보다 더 나은 성능을 제공한다.

모델이 최적점에 가까이 갈수록 학습률(Learning Rate)을 낮출 수 있다.
학습률이 낮아지면 안정적으로 최적점에 수렴할 가능성이 높다.
이런 학습을 적응적 학습률(Adaptive Learning rate)이라고 한다.

  • 학습률 매개변수를 튜닝하는 수고를 덜 수 있는 것이 장점이다.

적응적 학습률의 대표적인 옵티마이저는 Adagrad, RMSprop이다.

  • Adagrad는 'adagrad'로 지정할 수 있다.
adagrad = keras.optimizers.Adagrad()
model.compile(optimizer=adagrad, loss='sparse_categorical_crossentropy', metrics='accuracy')
  • RMSprop는 'rmsprop'로 지정할 수 있다.
rmsprop = keras.optimizers.RMSprop()
model.compile(optimizer=rmsprop, loss='sparse_categorical_crossentropy', metrics='accuracy')

모멘텀 최적화와 RMSprop의 장점을 접목한 옵티마이저가 있는데 바로 Adam이다.

model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics='accuracy')

위의 3가지 옵티마이저 클래스들은 learning_rate 매개변수의 기본값이 0.001이다.

Adam 옵티마이저를 사용하여 모델 학습을 진행해 보자.

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)

model.evaluate(val_scaled, val_target)

훈련세트의 정확도는 0.8898이고 검증세트의 점수는 0.8783으로 성능이 더 좋아졌다.

Pupbani는 심층 신경망을 통해 더 나은 딥러닝 모델을 만들었다. 이제 다시 마케팅 팀장에게 가보자.

728x90
반응형