본문 바로가기
AI/혼공머신

[혼공머신] 07-2 | 심층신경망

by 뒹굴거리는프로도 2024. 11. 22.
반응형

 


 

키워드


심층 신경망

심층 신경망은 2개 이상의 층을 포함한 신경망입니다. 종종 다층 인공 신경망, 심층 신경망, 딥러닝을 같은 의미로 사용합니다.

렐루 함수

렐루 함수는 이미지 분류 모델의 은닉층에 많이 사용하는 활성화 함수입니다. 시그모이드 함수는 층이 많을수록 활성화 함수의 양쪽 끝에서 변화가 작기 때문에 학습이 어려워집니다. 렐루 함수는 이런 문제가 없으며 계산도 간단합니다.

옵티마이저

옵티마이저는 신경망의 가중치와 절편을 학습하기 위한 알고리즘 또는 방법을 말합니다. 케라스에는 다양한 경사 하강법 알고리즘이 구현되어 있습니다. 대표적으로 SGD, 네스테로프 모멘텀, RMSprop, Adam 등이 있습니다.

 

핵심 패키지와 함수


TensorFlow

add()

케라스 모델에 층을 추가하는 메서드입니다.

케라스 모델의 add() 메서드는 keras.layers 패키지 아래에 있는 층의 객체를 입력받아 신경망 모델에 추가합니다. add() 메서드를 호출하여, 전달한 순서대로 층이 차례대로 늘어납니다.

summary()

케라스 모델의 정보를 출력하는 메서드입니다.

모델에 추가된 층의 종류와 순서, 모델 파라미터 개수를 출력합니다. 층을 만들 때 name 매개변수로 이름을 지정하면 summary() 메서드 출력에서 구분하기 쉽습니다.

SGD

기본 경사 하강법 옵티마이저 클래스입니다.

learning_rate 매개변수로 학습률을 지정하며 기본값은 0.01입니다.

momentum 매개변수에 0 이상의 값을 지정하면 모멘텀 최적화를 수행합니다.

nesterov 매개변수를 True로 설정하면 네스테로프 모멘텀 최적화를 수행합니다.

Adagrad

Adagrad 옵티마이저 클래스입니다.

learning_rate 매개변수로 학습률을 지정하여 기본값은 0.001입니다.

Adagrad는 그레이디언트 제곱을 누적하여 학습률을 나눕니다. initial_accumulator_value 매개변수에서 누적 초깃값을 지정할 수 있으며 기본값은 0.1입니다.

RMSprop

RMSprop 옵티마이저 클래스입니다.

learning_rate 매개변수로 학습률을 지정하며 기본값은 0.001입니다.

Adagrad처럼 그레이디언트 제곱으로 학습률을 나누지만 최근의 그레이디언트를 사용하기 위해 지수 감소를 사용합니다. rho 매개변수에서 감소 비율을 지정하며 기본값은 0.9입니다.

Adam

Adam 옵티마이저 클래스입니다.

learning_rate 매개변수로 학습률을 지정하며 기본값은 0.001입니다.

모멘텀 최적화에 있는 그레이디언트의 지수 감소 평균을 조절하기 위해 beta_1 매개변수가 있으며 기본값은 0.9입니다.

RMSprop에 있는 그레이디언트 제곱의 지수 감소 평균을 조절하기 위해 beta_2 매개변수가 있으며 기본값은 0.999입니다.

 

 

07-2 단원 내용


시작하기 전에

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

 


2개의 층

케라스 API를 사용해서 패션 MNIST 데이터셋을 불러오자. 그리고 훈련 세트와 검증 세트로 나누자.

from tensorflow import keras 

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

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이라고 부른다.

출력층에 적응하는 활성화 함수는 종류가 제한되어 있다. 이진 분류일 경우 시그모이드 함수를 사용하고, 다중 분류일 경우 소프트맥스 함수를 사용한다. 이에 비해 은닉층의 활성화 함수는 비교적 자유롭다.

회귀를 위한 신경망의 출력층에서는 어떤 활성화 함수를 사용할까?

회귀의 출력은 임의의 어떤 숫자이므로 활성화 함수를 적용할 필요가 없다. 즉 출력층의 선형 방정식의 계산을 그대로 출력한다. 이렇게 하려면 Dense 층의 activation 매개변수에 아무런 값을 지정하지 않는다.

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

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

 

 


 

심층 신경망 만들기

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

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

 

케라스는 모델의 summary() 메서드를 호출하면 층에 대한 유용한 정보를 얻을 수 있다.


 

층을 추가하는 다른 방법

앞에서는 Dense 클래스의 객체 dense1, dense2를 만들어 Sequential 클래스에 전달했다. 이 두 객체를 따로 저장하여 쓸 일이 없기 때문에 다음처럼 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 모델')
 

 

Sequential 클래스에서 층을 추가할 때 가장 널리 사용하는 방법은 모델의 add() 메서드를 활용하는 것이다.

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)
 

 

렐루 함수

초창기 인공 신경망의 은닉층에 많이 활용된 함수는 시그모이드 함수였다. 그러나 이 함수의 오른쪽과 왼쪽 끝으로 갈수록 그래프가 누워있기 때문에 올바른 출력을 만드는데 신속하게 대응하지 못한다. 이를 개선하기 위해 제안된 함수가 렐루ReLu이다.

렐루 함수는 아주 간단하다. 입력이 양수일 경우 마치 활성화 함수가 없는 것처럼 그냥 입력을 통과시키고 음수일 경우 0으로 만든다.

은닉층의 활성화 함수에 시그모이드 함수 대신 렐루 함수를 적용하기 전에 케라스에서 제공하는 층 하나를 살펴보자. 패션 MNIST 데이터는 28*28 크기이기 때문에 인공 신경망에 주입하기 위해 넘파이 배열의 reshape()를 사용해 1차원으로 펼쳤다. 직접 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'))
 

 

그럼 훈련 데이터를 다시 준비해서 모델을 훈련해보자. 서두에 있던 코드와 동일하지만, reshape() 메서드를 적용하지 않았다.

(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='accurace') 
model.fit(train_scaled, train_target, epochs=5)
 

 

검증 세트에서의 성능을 확인해보자.

model.evaluate(val_scaled, val_target)
 

 

 


 

옵티마이저

케라스는 다양한 종류의 경사 하강법 알고리즘을 제공한다. 이들을 옵티마이저optimizer라고 부른다.

SGD옵티마이저를 사용하려면 compile() 메서드의 optimizer매개변수를 'sgd'로 지정한다.

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

 

다음 코드는 위 코드와 정확히 동일한 기능을 낸다.

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

 

만약 SGD 클래스의 학습률 기본값이 0.01일 때 이를 바꾸고 싶다면 다음과 같이 원하는 학습률을 learning_rate 매개변수에 지정하여 사용한다.

sgd = keras.optimizers.SGD(learning_rate=0.1)
 

 

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

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

SGD클래스의 momentum 매개변수의 기본값은 0이다. 이를 0보다 큰 값으로 지정하면 마치 이전의 그레이디언트를 가속도처럼 사용하는 모멘텀 최적화momentum optimization를 사용한다. 보통 momentum 매개변수는 0.9이상을 지정한다.

다음처럼 SGD클래스의 nesterov 매개변수를 기본값 False에서 True로 바꾸면 네스테로프 모멘텀 최적화nesterov momentum optimization(또는 네스테로프 가속 경사)를 사용한다.

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

 

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

모델이 최적점에 가까이 갈수록 학습률을 낮출 수 있다. 이렇게 하면 안정적으로 최적점에 수렴할 가능성이 높다. 이런 학습률을 적응적 학습률adaptive learning rate라고 한다. 이런 방식들은 학습률 매개변수를 튜닝하는 수고를 덜 수 있는 것이 장점이다.

적응적 학습률을 사용하는 대표적 옵티마이저는 Adagrad와 RMSprop이다. 각각 compile() 메서드의 optimizer 매개변수에 'adagrad'와 'rmsprop'으로 지정할 수 있다. optimizer 매개변수 기본값이 바로 'rmsprop'이다. 이 두 옵티마이저의 매개변수를 바꾸고 싶다면 SGD와 같이 Adagrad와 RMSprop 클래스 객체를 만들어 사용하면 된다.

adagrad = keras.optimizers.Adagrad() 

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

 

RMSprop도 마찬가지다.

rmsprop = keras.optimizers.RMSprop() 

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

 

모멘텀 최적화와 RMSprop의 장점을 접목한 것이 Adam이다. Adam은 RMSprop과 함께 맨처음 시도해 볼 수 있는 좋은 알고리즘이다. Adam 클래스도 keras.optimizers 패키지 아래 있다. 적응적 학습률을 사용하는 이 3개의 클래스는 learning_rate 매개변수의 기본값으로 모두 0.001을 사용한다.

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

 

compile() 메서드의 optimizer를 'adam'으로 설정하고 5번의 에포크 동안 훈련하자.

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

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

 

검증 세트에서의 성능도 확인해보자.

model.evaluate(val_scaled, val_target)
 

 

기서는 기본 RMSprop보다 조금 더 나은 성능을 낸다.


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

 


 

반응형