chapter_7_2
심층 신경망
인공신경망에 층을 여러 개 추가하여 패션 MNIST 데이터셋을 분류한다.
동시에 케라스로 심층 신경망을 만들어본다.
368p 그림 참고
케라스로 API를 사용해 패션 MNIST 데이터셋을 불러온다.
1 | from tensorflow import keras |
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz
32768/29515 [=================================] - 0s 0us/step
40960/29515 [=========================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26427392/26421880 [==============================] - 0s 0us/step
26435584/26421880 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
16384/5148 [===============================================================================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4423680/4422102 [==============================] - 0s 0us/step
4431872/4422102 [==============================] - 0s 0us/step
- 이미지의 픽셀값을 0 ~ 255 범위에서 0 ~ 1로 변환
- 28x28 크기의 2차원 배열을 784 크기인 1차원 배열로 펼친다.
- train_test_split() 함수로 훈련 세트와 검증 세트로 나눈다.
1 | from sklearn.model_selection import train_test_split |
입력층과 출력층 사이에 밀집층을 만들 예정이다.
은닉층 : 입력층과 출력층 사이에 있는 모든 층
케라스의 Dense 클래스로 다음 내용을 만든다.
- sigmoid 활성화 함수를 사용한 은닉층
- softmax 함수를 사용한 출력층
층을 추가하는 방법
- Dense 클래스의 객체 dense1, 2를 만들어 Sequential 클래스에 전달한다.
1 | dense1 = keras.layers.Dense(100, activation='sigmoid', input_shape=(784,)) |
- dense1이 은닉층이고 100개의 뉴런을 가진 밀집층이다.
- 활성화 함수를 ‘sigmoid’로 지정했고 매개변수로 입력의 크기를 (784,)로 지정했다.
- dense2는 출력층이다.
- 10개의 클래스를 분류하므로 10개의 뉴런을 두었고 활성화 함수는 softmax로 지정했다.
심층 신경망
컨셉만 이해하라!
직접 신경망 만들 일은 없고 가져다 쓰기만 하면 된다.
앞의 dense1과 dense2 객체를 Sequential 클래스에 추가하여 심층 신경망을 만들 예정이다.
1 | model = keras.Sequential([dense1, dense2]) |
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 100) 78500
dense_1 (Dense) (None, 10) 1010
=================================================================
Total params: 79,510
Trainable params: 79,510
Non-trainable params: 0
_________________________________________________________________
- 위와 같이 Sequential 클래스의 객체를 만들 때 여러 개의 층을 추가하려면 층을 리스트로 만들어 전달해야 한다.
- model.summary()로 층에 대한 정보를 얻을 수 있다.
- 첫 줄에 모델의 이름이 나온다.
- 이 모델에 들어 있는 층이 순서대로 나열된다.
- 이 순서는 맨 처음 추가한 은닉층에서 출력층의 순서로 나열된다.
- 층마다 층 이름, 클래스, 출력 크기, 모델 파라미터 개수가 출력된다.
- name 매개변수로 이름을 지정하지 않으면 디폴트인 ‘dense’로 네이밍된다.
- 출력 크기는 (None,100)인데, 첫 번째 차원은 샘플 개수를 나타낸다.
- None인 이유는 어떤 배치 크기에도 잘 대응하기 위함이다.
- 두 번째 차원인 100은 뉴런 개수가 100이며, 따라서 100개의 출력이 나옴을 나타낸다.
층을 추가하는 다른 방법
- Sequential 클래스의 생성자 안에서 바로 Dense 클래스의 객체를 만든다.
1 | model = keras.Sequential([ |
Model: "패션 MNIST 모델"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
hidden (Dense) (None, 100) 78500
output (Dense) (None, 10) 1010
=================================================================
Total params: 79,510
Trainable params: 79,510
Non-trainable params: 0
_________________________________________________________________
층을 추가하는 다른 방법 2
- Sequential 클래스의 객체를 만들고 이 객체의 add() 메서드를 호출하여 층을 추가한다.
1 | model = keras.Sequential() |
Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_2 (Dense) (None, 100) 78500
dense_3 (Dense) (None, 10) 1010
=================================================================
Total params: 79,510
Trainable params: 79,510
Non-trainable params: 0
_________________________________________________________________
- 이제 모델을 훈련한다.
- 반복할 에포크 횟수를 epochs 매개변수로 지정
1 | model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy') |
Epoch 1/5
1500/1500 [==============================] - 6s 3ms/step - loss: 0.5628 - accuracy: 0.8069
Epoch 2/5
1500/1500 [==============================] - 4s 3ms/step - loss: 0.4087 - accuracy: 0.8522
Epoch 3/5
1500/1500 [==============================] - 5s 3ms/step - loss: 0.3747 - accuracy: 0.8645
Epoch 4/5
1500/1500 [==============================] - 4s 3ms/step - loss: 0.3506 - accuracy: 0.8737
Epoch 5/5
1500/1500 [==============================] - 4s 2ms/step - loss: 0.3344 - accuracy: 0.8784
<keras.callbacks.History at 0x7f5bcb861b50>
렐루 함수
- 층이 많은 신경망일수록 그 효과가 누적되어 학습이 어려워진다.
- 이를 개선하기 위한 활성화 함수이다.
- relu() 함수는 입력이 양수일 그냥 통과시키고, 입력이 음수라면 0으로 만든다.
Flatten 클래스
- 배치 차원을 제외하고 나머지 입력 차원을 모두 일렬로 펼친다.
- Flatten 클래스를 층처럼 입렬층과 은닉층 사잉에 추가하기 때문에 이를 층이라 부른다.
- 다음 코드처럼 입력층 바로 뒤에 추가한다.
1 | model = keras.Sequential() |
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: 79,510
Trainable params: 79,510
Non-trainable params: 0
_________________________________________________________________
- 훈련 데이터를 다시 준비해서 모델을 훈련한다.
1 | (train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data() |
- 모델을 컴파일하고 훈련한다.
1 | model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy') |
Epoch 1/5
1500/1500 [==============================] - 4s 2ms/step - loss: 0.5283 - accuracy: 0.8151
Epoch 2/5
1500/1500 [==============================] - 4s 3ms/step - loss: 0.3926 - accuracy: 0.8602
Epoch 3/5
1500/1500 [==============================] - 3s 2ms/step - loss: 0.3562 - accuracy: 0.8713
Epoch 4/5
1500/1500 [==============================] - 4s 2ms/step - loss: 0.3336 - accuracy: 0.8809
Epoch 5/5
1500/1500 [==============================] - 3s 2ms/step - loss: 0.3203 - accuracy: 0.8853
<keras.callbacks.History at 0x7f5bcb762a10>
- 시그모이드 함수를 사용했을 때와 비교하면 성능이 조금 향상되었다.
- 검증 세트에서의 성능도 확인하자.
1 | model.evaluate(val_scaled, val_target) |
375/375 [==============================] - 1s 3ms/step - loss: 0.3713 - accuracy: 0.8717
[0.3712655007839203, 0.871749997138977]
- 검증 성능도 향상되었다.
1 | (train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data() |
1 | model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy') |
Epoch 1/5
1500/1500 [==============================] - 4s 2ms/step - loss: 0.3094 - accuracy: 0.8890
Epoch 2/5
1500/1500 [==============================] - 4s 2ms/step - loss: 0.2989 - accuracy: 0.8951
Epoch 3/5
1500/1500 [==============================] - 3s 2ms/step - loss: 0.2902 - accuracy: 0.8974
Epoch 4/5
1500/1500 [==============================] - 4s 2ms/step - loss: 0.2825 - accuracy: 0.9018
Epoch 5/5
1500/1500 [==============================] - 3s 2ms/step - loss: 0.2781 - accuracy: 0.9024
<keras.callbacks.History at 0x7f5bcb835d10>
1 | model.evaluate(val_scaled, val_target) |
375/375 [==============================] - 1s 1ms/step - loss: 0.4110 - accuracy: 0.8792
[0.41104814410209656, 0.8791666626930237]
옵티마이저의 개념
–> Adam 사용하라
–> why Adam? 최고점을 찾기 위해서
- 스텝방향 & 스템사이즈를 모두 고려한 옵티마이저
- 스텝방향 : GD, SGD, Momentum, NAG
- 스텝사이즈 : GD, SGD, Adagrad, RMSProp
- 하이퍼 파라미터는 사람이 지정해야 하는 파라미터
- 신경망에는 특히 하이퍼 파라미터가 많다.
- 은닉층의 뉴런 개수도 하이퍼 파라미터이다.
- compile() 에서는 케라스의 기본 하강법 알고리즘인 RMSprop을 사용했다.
- 케라스는 다양한 종류의 경사 하강법 알고리즘을 제공한다.
- 이들을 ‘옵티마이저’라고 부른다.
옵티마이저
- 381p
- SGD 옵티마이저를 사용하려면 compile() 메서드의 optimizer 매개변수를 ‘sgd’로 지정
1 | model.compile(optimizer='sgd', loss='sparse_categorical_crossentropy', metrics='accuracy') |
- ‘sgd’ 문자열은 이 클래스의 기본 설정 매개변수로 생성한 객체와 동일하다.
- 다음 코드는 위의 코드와 정확히 동일하다.
1 | sgd = keras.optimizers.SGD() |
- 382p
- learning_rate = 0.1
- 만약 SGD 클래스의 학습률 기본값이 0.01일 때 이를 바꾸고 싶다면 다음와 같이 지정한다.
- 랜덤서치, 그리드서치
- 딥러닝에서도 하이퍼파라미터 튜닝
1 | sgd = keras.optimizers.SGD(learning_rate = 0.1) |
- 기본 경사 하강법 옵티마이저는 모두 SGD 클래스에서 제공한다.
- SGD 클래서의 momentum 매개변수의 기본값은 0이다. 보통 0.9이상을 지정한다.
- 다음처럼 SGD 클래스의 nesterov 매개변수를 기본값 False 에서 True로 바꾸면 네스테로프 모멘텀 최적화를 사용한다.
- 테스테로프 모멘텀은 모멘텀 최적화를 2번 반복하여 구현한다.
- 대부분의 경우 네스테로프 모멘텀 최적화가 기본 확률적 경사 하강법보다 더 나은 성능을 제공한다.
1 | sgd = keras.optimizers.SGD(momentum = 0.9, nesterov = True) |
적응적 학습률
- 모델이 최적점에 가까이 갈수록 학습률을 낮출 수 있다.
- 이렇게 하면 안정적으로 최적점에 수렴할 가능성이 높다.
- 이런 학습률을 적응적 학습률이라고 한다.
Adagrad() 클래스
- 적응적 학습률을 사용하는 대표적인 옵티마이저이다.
- optimizer 매개변수에서 지정할 수 있다.
- optimizer 매개변수의 기본값이 바로 rmsprop이다.
1 | adagrad = keras.optimizers.Adagrad() |
- RMSprop() 클래스
- 적응적 학습률을 사용하는 대표적인 옵티마이저이다.
- optimizer 매개변수에서 지정할 수 있다.
- optimizer 매개변수의 기본값이 바로 rmsprop이다.
1 | rmsprop = keras.optimizers.RMSprop() |
다만, Adam을 사용하는 것이 더 좋다.
Adam
- 모멘텀 최적화와 RMSprop의 장점을 접목한 것이 Adam이다.
- 적응적 학습률을 사용하는 이 3개의 클래스는 learning_rate 매개변수의 기본값을 0.001로 두고 사용한다.
Adam 클래스의 매개변수 기본값을 사용해 패션 MNIST 모델을 훈련해본다.
일단 모델을 다시 생성한다.
1 | model = keras.Sequential() |
- compile() 메서드의 optimizer를 ‘adam’으로 설정하고 5번의 에포크 동안 훈련한다.
1 | model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics='accuracy') |
Epoch 1/5
1500/1500 [==============================] - 4s 2ms/step - loss: 0.5293 - accuracy: 0.8155
Epoch 2/5
1500/1500 [==============================] - 3s 2ms/step - loss: 0.3980 - accuracy: 0.8571
Epoch 3/5
1500/1500 [==============================] - 3s 2ms/step - loss: 0.3542 - accuracy: 0.8713
Epoch 4/5
1500/1500 [==============================] - 4s 3ms/step - loss: 0.3287 - accuracy: 0.8798
Epoch 5/5
1500/1500 [==============================] - 3s 2ms/step - loss: 0.3081 - accuracy: 0.8867
375/375 [==============================] - 1s 2ms/step - loss: 0.3296 - accuracy: 0.8806
[0.32961416244506836, 0.8805833458900452]
- 결과를 보면 기본 RMSprop을 사용했을 때와 거의 같은 성능을 보인다.
- 검증 세트에서의 성능도 확인한다.
1 | model.evaluate(val_scaled, val_target) |
375/375 [==============================] - 1s 3ms/step - loss: 0.3296 - accuracy: 0.8806
[0.32961416244506836, 0.8805833458900452]
환경마다 차이가 있을 수 있지만 여기서는 기본 RMSprop보다 조금 더 나은 성능을 보인다.
Reference : 혼자 공부하는 머신러닝 + 딥러닝
You need to set
install_url
to use ShareThis. Please set it in _config.yml
.