[혼자 공부하는 머신러닝+딥러닝] 18강. 심층 신경망 ▶️인공 신경망에 층을 추가하여 심층 신경망 만들어 보기 - 층을 늘리고 옵티마이저를 추가해보자
https://www.youtube.com/watch?v=JskWW5MlzOg&list=PLJN246lAkhQjoU0C4v8FgtbjOIXxSs_4Q&index=18
- 층을 더 추가해서 성능을 높여보자.
1. 데이터 로그 및 전처리
# 실행마다 동일한 결과를 얻기 위해 케라스에 랜덤 시드를 사용하고 텐서플로 연산을 결정적으로 만듭니다.
import tensorflow as tf
tf.keras.utils.set_random_seed(42)
tf.config.experimental.enable_op_determinism()
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) # 1차원으로 축 변환
# 검증세트 수동으로 분리
train_scaled, val_scaled, train_target, val_target = train_test_split(
train_scaled, train_target, test_size=0.2, random_state=42)
2. 심층 신경망 만들기 (2개 층)
- 은닉층 (Hidden Layer)
- 은닉층 : 입력층과 출력층 사이에 있는 모든 층이며 사용자의 요구에 따라 얼마든지 증가될 수 있다.
- 정보손실 방지를 위해 최소한 출력층의 유닛 개수보다 많게 정의해 주어야 한다.
- 출력층과 마찬가지로 은닉층에도 활성화함수가 적용된다.
- 출력층보다 사용할 수 있는 함수가 비교적 자유롭다.
- 시그모이드, 렐루 등
- 심층신경망 만들기
- 은닉층 activation은 가장 대표적인 시그모이드를 사용한다.
# 100개의 유닛을 가지고 있는 은닉층, 필수로 input_shape를 정의해줘야 한다.
dense1 = keras.layers.Dense(100, activation='sigmoid', input_shape=(784,))
# 10개의 유닛을 가지고 있는 출력층
dense2 = keras.layers.Dense(10, activation='softmax')
# 층 2개를 쌓아서 '심층 신경망' 모델을 정의한다.
model = keras.Sequential([dense1, dense2]) # 은닉층을 먼저 정의하고 출력층을 마지막에 정의한다.
- 모델 정보 확인
- .summary()를 이용해 모델의 정보를 확인할 수 있다.
- Output Shape : (경사하강법, 출력 유닛 개수)를 보여준다.
- 훈련을 몇개의 배치로 할지 모르니 유연하게 받을 수 있도록 None으로 설정되어 있다.
- Param : 모델 파라미터, 즉 각 층의 가중치 & 절편의 개수를 보여준다.
- 첫번째 층 : 784 * 100 (가중치) + 100( 절편 ) = 78,500
- 두번째 층 : 100 * 10 (가중치) + 10(절편) = 1,010
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 100) 78500
dense_1 (Dense) (None, 10) 1010
=================================================================
Total params: 79510 (310.59 KB)
Trainable params: 79510 (310.59 KB)
Non-trainable params: 0 (0.00 Byte)
____________________________________________
- 심층 신경망 만들기 3가지 방법
dense1 = keras.layers.Dense(100, activation='sigmoid', input_shape=(784,))
dense2 = keras.layers.Dense(10, activation='softmax')
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 100) 78500
dense_1 (Dense) (None, 10) 1010
=================================================================
Total params: 79510 (310.59 KB)
Trainable params: 79510 (310.59 KB)
Non-trainable params: 0 (0.00 Byte)
- 층마다 이름도 정의해주고 모델 전체 이름도 정의해준다.
- name으로 정의하는 층 이름은 오직 영어로만 가능하다.
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: "패션 MNIST 모델"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
hidden (Dense) (None, 100) 78500
output (Dense) (None, 10) 1010
=================================================================
Total params: 79510 (310.59 KB)
Trainable params: 79510 (310.59 KB)
Non-trainable params: 0 (0.00 Byte)
- 필드에서 가장 많이 사용하는 방법이다
- 선언 사이에 if로 여러 조건을 설정할 수 있다.
model = keras.Sequential()
model.add(keras.layers.Dense(100, activation='sigmoid', input_shape=(784,)))
model.add(keras.layers.Dense(10, activation='softmax'))
model.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_2 (Dense) (None, 100) 78500
dense_3 (Dense) (None, 10) 1010
=================================================================
Total params: 79510 (310.59 KB)
Trainable params: 79510 (310.59 KB)
Non-trainable params: 0 (0.00 Byte)
- compile() 및 fit() 수행
model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')
model.fit(train_scaled, train_target, epochs=5)
3. 활성화 함수
- 은닉층에 활성화 함수를 적용하는 이유
- 2개의 선형 계산식 결과 값에는 공통되는 미지수가 서로 상쇠되어 사라질 수 있다. 신경망에서 이런 계산식이 이어진다면 중간에 존재하는 은닉층들의 존재 의미가 사라져 버리게 된다.
- 아래 식에서 b가 사라짐으로 b는 결국 하는 일이 없어지게 된다.
- 이와 같은 문제를 해결하기 위해 은닉층의 결과값을 비선형적으로 비틀어주는 계산식이 필요하다.
- 선형 식들이 단순히 합쳐지는 결과를 만들이 않기 위한 작업이다.
- 렐루(ReLU) 함수
- 시그모이드 함수의 단점
- 출력값(z)이 너무 크거나 작을 경우 그래디언트 소실문제가 있다. 이 경우 기울기도 0에 가까워지면서 가중치가 매우 느리게 업데이트 되므로 학습 과정이 늦어지고 뿐만 아니라 신경망이 수렴하기 어렵게 되어 결국 층을 깊게 쌓기 힘들게 된다.
- 새로운 제안, 렐루(ReLU) 함수
- 우리말로 정류된 선형 함수라 하며 간단하게 +/-가 반복되는 신호에서 - 흐름을 차단한다는 의미이다.
- 출력값(z)가 0보다 작으면 0으로 출력하고 0보다 크면 그대로 z를 출력한다.
- 기울기 소실 문제가 발생하지 않는다.
- 유틸리티 층 추가하기
- Flatten() : 다차원 입력데이터를 1차원으로 펼쳐주는 유틸리티 층으로 편의를 위한 층이다.
- summary를 이용해 출력해보면 입력값 개수를 바로 알 수 있다. 전처리 과정을 모델 내 포함시키는 것이다.
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()
Model: "sequential_2"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
flatten (Flatten) (None, 784) 0
dense_4 (Dense) (None, 100) 78500
dense_5 (Dense) (None, 10) 1010
=================================================================
Total params: 79510 (310.59 KB)
Trainable params: 79510 (310.59 KB)
Non-trainable params: 0 (0.00 Byte)
_________________________________________________________________
- 새로운 모델로 재훈련 하기
- reshape() 사용을 더 이상 하지 않는다. 결과적으로 성능이 더 좋아지는 것을 확인할 수 있다.
(train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data()
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)
model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')
model.fit(train_scaled, train_target, epochs=5) # 점수가 조금 더 좋아졌다.
Epoch 1/5
1500/1500 [==============================] - 6s 3ms/step - loss: 0.5290 - accuracy: 0.8114
Epoch 2/5
1500/1500 [==============================] - 5s 4ms/step - loss: 0.3929 - accuracy: 0.8566
Epoch 3/5
1500/1500 [==============================] - 6s 4ms/step - loss: 0.3538 - accuracy: 0.8718
Epoch 4/5
1500/1500 [==============================] - 5s 4ms/step - loss: 0.3316 - accuracy: 0.8806
Epoch 5/5
1500/1500 [==============================] - 5s 4ms/step - loss: 0.3148 - accuracy: 0.8867
model.evaluate(val_scaled, val_target) # 검증세트의 성능 확인 결과 출력층 하나보다 성능이 좋다.
375/375 [==============================] - 1s 3ms/step - loss: 0.3825 - accuracy: 0.8682
[0.38249149918556213, 0.8681666851043701]
4. 옵티마이저
- 신경망의 하이퍼파라미터
- 신경망에는 특히 하이퍼파라미터가 많다.
- 은닉층 뉴런 개수(100), 활성화함수(activation), 층의 종류(Dense, Flatten), 배치크기(batch_size), 반복횟수(epochs) 등이 존재한다.
- 옵티마이저 설정
- 옵티마이저도 하이퍼파라미터 중 하나로, 경사하강법의 종류에 대한 설정을 한다.
- SGD(): 이름은 그냥 SGD인데 실제로는 미니배치 경사하강법을 수행한다( 기본 배치크기 = 32 )
- 설정( compile ) 단계에서 optimizer로 정의할 수 있다.
- ''를 사용해 문자열로 정의하거나 객체를 먼저 생성하여 파라미터에 정의해줄 수도 있다.
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 = keras.optimizers.SGD(momentum=0.9, nesterov=True)
- 아다그라드 하강법 (적응적 학습률)
adagrad = keras.optimizers.Adagrad()
model.compile(optimizer=adagrad, loss='sparse_categorical_crossentropy', metrics='accuracy')
- RMSprop 하강법 (적응적 학습률)
adagrad = keras.optimizers.Adagrad()
model.compile(optimizer=adagrad, loss='sparse_categorical_crossentropy', metrics='accuracy')
- 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)
Epoch 1/5
1500/1500 [==============================] - 7s 4ms/step - loss: 0.5262 - accuracy: 0.8154
Epoch 2/5
1500/1500 [==============================] - 5s 3ms/step - loss: 0.3940 - accuracy: 0.8589
Epoch 3/5
1500/1500 [==============================] - 6s 4ms/step - loss: 0.3546 - accuracy: 0.8702
Epoch 4/5
1500/1500 [==============================] - 8s 5ms/step - loss: 0.3284 - accuracy: 0.8794
Epoch 5/5
1500/1500 [==============================] - 7s 4ms/step - loss: 0.3058 - accuracy: 0.8872
model.evaluate(val_scaled, val_target)
375/375 [==============================] - 2s 3ms/step - loss: 0.3509 - accuracy: 0.8751
[0.3508651852607727, 0.875083327293396]
- 추가 학습
- 회귀 신경망 모델에서는 활성화 함수를 사용하지 않는 이유
- 분류 모델에서 활성화 함수( sigmoid, softmax)를 사용한 이유는 확률로 출력을 하기 위해서이다. 하지만 회귀의 출력값은 임의의 숫자값이기에 필요가 없다. activation에 아무것도 정의하지 않아도 된다.
- 앙상블 알고리즘과 심층 신경망의 비교
- 이미지 출처 : https://velog.io/@simon919/7-2.-%EC%8B%AC%EC%B8%B5-%EC%8B%A0%EA%B2%BD%EB%A7%9D#-to-wrap-up
- reference :
https://velog.io/@simon919/7-2.-%EC%8B%AC%EC%B8%B5-%EC%8B%A0%EA%B2%BD%EB%A7%9D#-to-wrap-up
댓글