● Chpater 07의 학습목표
1. 딥러닝의 핵심 알고리즘인 인공 신경망을 배웁니다.
2. 대표적인 인공 신경망 라이브러리인 텐서플로와 케라스를 소개합니다.
3. 인공 신경망 모델의 훈련을 돕는 도구를 익힙니다.
● 학습목표: 인공 신경망에 층을 여러 개 추가하여 패션 MNIST 데이터셋을 분류하면서 케라스로 심층 신경망을 만드는 방법을 자세히 배웁니다.
● 키워드: 심층 신경망, 렐루 함수, 옵티마이저
● 지난 시간 - 밀집층 딥러닝 알고리즘 문제 풀이
1. Keras를 이용해 data 불러오기
2. Train set에서 validation set 일부 덜어내기 (train_test_split 사용)
3. Layer 만들기 (keras.layers.Dense)
4. Model 만들기 (keras.Sequential)
5. Loss function 및 측정 지표 정하기 (model.compile(loss = '', metrics = ['']))
6. 훈련하기 (model.fit(val_input, val_target))
● 심층 신경망 딥러닝 알고리즘 문제 풀이
심층 신경망 만들기
심층 신경망: 2개 이상의 층을 포함한 신경망. (종종 다층 인공 신경망, 심층 신경망, 딥러닝과 같은 의미로 사용 됨.)
은닉층 (hidden layer): 입력층과 출력층 사이에 추가된 밀집층
- 은닉층의 활성화 함수: ReLU, Sigmoid (비교적 자유롭게 선택 가능)
- 출력층의 활성화 함수: Sigmoid, Softmax (이것으로 제한적)
- 은닉층의 개수를 지정하는데는 특별한 기준이 없습니다. 몇개의 뉴런을 두어야 할지 판단한기 위해서는 상당한 경험이 필요합니다.
- 단, 은닉층의 개수를 출력층보다는 많이 만들어야합니다.
만들게 될 심층 신경망 모델의 개괄적인 모습은 아래와 같습니다.
# 회귀 분석을 위한 신경망의 출력층에서는 활성화 함수를 사용하지 않습니다. 분류는 활성화 함수를 통해 선형 방정식을 확률로 압축하지만, 회귀의 출력은 어떤 임의의 숫자이기 때문입니다.
#1. Data 불러오기
from tensorflow import keras
(train_input, train_target), (test_input, test_target) = \
keras.datasets.fashion_mnist.load_data()
#2. 데이터 scaling 및 validation set 분리
from sklearn.model_selection import train_test_split
train_reshape = train_input.reshape(-1,28*28)
test_reshape = test_input.reshape(-1,28*28)
train_scaled = train_reshape / 255.0
test_scaled = test_reshape / 255.0
train_scaled, val_input, train_target, val_target = train_test_split(train_scaled, train_target, test_size = 0.2, random_state = 42)
#3. Hidden layer를 포함한 심층 신경망 layer 만들기
dense1 = keras.layers.Dense(100, activation = 'sigmoid', input_shape = (784,))
dense2 = keras.layers.Dense(10, activation = 'softmax')
인공 신경망의 강력한 성능은 층을 추가하여 입력 데이터를 연속적으로 학습하는 능력에서 나옵니다.
Sequential로 심층 신경망 layer로 객체를 만들때는 list로 층을 전달합니다. 단, 마지막에는 출력층의 층을 전달해야합니다.
#4. 심층 신경망 model 객체 만들기
model = keras.Sequential([dense1, dense2])
#5. 심층 신경망 모델 확인하기
model.summary()
심층 신경망 summary
- 첫 줄: 모델 이름
- Layer 이름 (Type, name 변수로 층이름 변경 가능), 출력 크기, 모델 파라미터 개수 (w, b)가 출력
- Output shape의 None: 미니배치 경사하강법을 사용하여 Output을 만드는데, 미니배치 경사하강법의 샘플 개수가 정해지지 않았다는 의미, 샘플 사이즈마다 유연하게 경사하강법으로 model이 학습한다는 의미. (fit method에서 batch_size 매개 변수로 조정 가능)
- 배치 차원: 신경망 층에 입력되거나 출력되는 배열의 첫 번째 차원 (기본적인 미니배치 경사하강에서는 32가 배치 차원임)
# 모델 파라미터 개수 계산하는 방법: 층을 이해하는 하나의 방법이다.
# Hidden layer에 활성화 함수를 적용하는 이유
층을 추가하는 다른 방법
직관적으로 층을 추가하여 model은 만듦.
- 굳이 층을 저장해서 쓸일이 없는 경우 다음과 같이 층을 만들기도 합니다.
- 또한 층의 이름은 반드시 영문이여야합니다.
# 직관적으로 층을 만들기
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()
add 함수를 사용: Sequential 객체 안에 많은 층을 담아야 할 때 사용.
#6. add를 사용해서 층을 추가하기
model = keras.Sequential(name = 'FASHION_MNIST_MODEL')
model.add(keras.layers.Dense(100, activation = 'sigmoid', input_shape = (784,), name = 'Hidden'))
model.add(keras.layers.Dense(10, activation = 'softmax', input_shape = (784,), name = 'Output'))
model.summary()
이제 모델을 훈련해서 model의 성능을 확인해보겠습니다. 점차 손실은 줄어들고 정확도가 증가한다는것을 알 수 있습니다.
#7. model 손실함수와 지표 정하고 훈련하기
model.compile(loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
model.fit(train_scaled, train_target, epochs = 5)
다음은 이미지 분류 문제에서 높은 성능을 낼 수 있는 활성화 함수에 대해 알아보겠습니다.
ReLU 함수
ReLU 함수는 0보다 크면 그대로 함수를 출력하고, 0보다 작으면 0으로 변환하는 activation function 입니다. 이미지를 처리하는데 있어서 좋은 성능을 내는 활성화 함수입니다. sigmoid 함수는 층이 많을수록 양 끝에서 변화가 작기 때문에, 학습이 어려워집니다. ReLU 함수는 이런 문제가 없으며, 계산도 간단합니다.
Flatten
- 입력을 할때, 2차원 데이터를 reshape method를 활용해 1차원으로 펼친후에 사용했습니다.
- Flatten 층을 입력층과 은닉층 사이에 추가하다면, 배치 차원을 제외하고 (= 입력되는 배치의 크기는 그대로 두고) 나머지 입력 차원을 모두 일렬로 펼치는 역할만 합니다.
- 다만, 층의 개수로 인정하지는 않습니다. 학습하는 층이 아니기 때문입니다.
#8. Flatten과 Relu층 추가하기
model = keras.Sequential(name = 'FASHION_MNIST_')
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()
Flatten 함수를 사용하면, 2차원 데이터를 펼치지 않고 keras 신경망 층에 추가하여 바로 전처리 하고 몇개의 pixel 로 이루어졌는지 확인 할 수 있습니다. Keras의 철학은 데이터의 전처리 과정까지 layer에 가능한 넣자는 것입니다.
#9. Flatten과 ReLU 함수 추가하여 model 만들기
(train_input, train_target), (test_input, test_target) = \
keras.datasets.fashion_mnist.load_data()
train_input, val_input, train_target, val_target = train_test_split(train_input, train_target, test_size = 0.2, random_state = 42)
train_scaled = train_input / 255.0
val_scaled = val_input / 255.0
model = keras.Sequential(name = 'Fashion_MNIST')
model.add(keras.layers.Flatten(input_shape = (28,28)))
model.add(keras.layers.Dense(100, activation = 'relu', name = 'ReLU'))
model.add(keras.layers.Dense(10, activation = 'softmax', name = 'Output'))
model.summary()
model.compile(loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
model.fit(train_scaled, train_target, epochs = 5)
model.evaluate(val_input, val_target)
sigmoid 함수를 사용했을 때 정확도보다 모델의 1% 향상 되었습니다.
옵티마이저 (Optimizer)
신경망의 가중치와 절편을 학습하기 위한 알고리즘 또는 방법.
- 기본적 경사하강 옵티마이저
1. SGD: 기본 경사 하강법 옵티마이저 클래스
- learning_rate: 학습률을 지정 (기본값 = 0.01)
- momentum: 0 이상의 값을 지정하면 모멘텀 최적화를 수행, 보통 0.9 이상을 지정
- nesterov: True로 지정하면 네스테로프 모멘텀 최적화를 수행
- 모멘텀 최적화: 이전의 Gradient를 가속도 처럼 사용 사용
- 네스테로프 모멘텀: 모멘텀 최적화를 2번 반복하여 구현. 대부분의 경우 기본 확률적 경사 하강법 보다 더 나은 성능을 제공
- 적응적 학습률: 모델이 최적점에 가까이 갈수록 학습률을 낮추는 과정, 안정적으로 최적점에 수렴.
1. Adagrad: Gradient 제곱을 누적하여 학습률을 나눈다.
- learning_rate: 학습률을 지정 (기본값 = 0.001)
- initial_accumulator_value: 누적 초깃값을 지정한다. (기본값 = 0.1)
2. RMSprop: Gradient 제곱으로 학습률을 나누지만, 최근의 Gradient를 사용하기 위해 지수 감소를 사용.
- learning_rate: 학습률을 지정 (기본값 = 0.001)
- rho: 감소 비율을 지정 (기본값: 0.9)
- 모멘텀 최적화 + RMSprop의 장점을 접목한 옵티마이저
Adam:
- learning_rate: 학습률을 지정 (기본값 = 0.001)
- beta_1: 모멘텀 최적화에 있는 Gradient 지수 감소 평균을 조절
- beta_2: RMSprop에 있는 Gradient 제곱의 지수 감소 평균을 조절
주로 Adam과 RMSprop을 기본적으로 사용하는 좋은 algorith이다.
# SGD 옵티마이저, 미니배치 경사하강
sgd = keras.optimizers.SGD(learning_rate = 0.1) # Default = 0.01
model.compile(optimizer = sgd, loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
model.compile(optimizer = 'sgd', loss = 'sparse_categorical_crossentropy', metrics = ['accuracy']) # 위 두줄과 같음
# 네스트로프 옵티마이저, 미니배치 경사하강
sgd = keras.optimizers.SGD(momentum = 0.9, nestrov = True) # 네스트로프 모멘텀 최적화 경사하강법
model.compile(optimizer = sgd, loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
# 아다그라드 옵티마이저, 미니배치 경사하강
adgard = keras.optimizers.Adagrad() # 아다그라드 옵티마이저
model.compile(optimizer = adgard, loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
# RMSprop 옵티마이저, 미니배치 경사하강
rmsprop = keras.optimizers.RMSprop() # RMSprop 옵티마이저
model.compile(optimizer = rmsprop, loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
#10. Adam을 활용한 심층 신경망 모델
model = keras.Sequential()
model.add(keras.layers.Flatten(input_shape = (28,28)))
model.add(keras.layers.Dense(100, activation = 'relu', name = 'ReLU'))
model.add(keras.layers.Dense(10, activation = 'softmax', name = 'Outputlayer'))
model.summary()
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보다 조금더 나은 성능을 보여주고 있다.
# 복습
## 데이터 불러오기
# 스케일링
# Train Val set split
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_input, val_input, train_target, val_target = train_test_split(train_input, train_target, test_size = 0.2, random_state = 42)
train_scaled = train_input / 255.0
test_scaled = test_input / 255.0
val_scaled = val_input / 255.0
## 층 만들기
# hidden layer sigmoid 함수
# summary
model = keras.Sequential(name = 'Fashion_MNIST_sigmoid')
model.add(keras.layers.Flatten(input_shape = (28,28)))
model.add(keras.layers.Dense(100, activation = 'sigmoid'))
model.add(keras.layers.Dense(10, activation = 'softmax'))
model.summary()
model.compile(loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
model.fit(train_scaled, train_target, epochs = 5)
model.evaluate(val_scaled, val_target)
## 층만들기
# hidden layer Relu 함수
model = keras.Sequential(name = 'Fashion_MNIST_ReLU')
model.add(keras.layers.Flatten(input_shape = (28,28)))
model.add(keras.layers.Dense(100, activation = 'relu', name = 'ReLU'))
model.add(keras.layers.Dense(10, activation = 'softmax', name = 'Softmax'))
model.compile(loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
model.fit(train_scaled, train_target, epochs = 5)
model.evaluate(val_scaled, val_target)
## 층 만들기
# hidden layer Relu 함수
# optimizer = Adam
model = keras.Sequential(name = 'Fashion_MNIST_Adam')
model.add(keras.layers.Flatten(input_shape = (28,28)))
model.add(keras.layers.Dense(100, activation = 'relu', name = 'ReLU'))
model.add(keras.layers.Dense(10, activation = 'softmax', name = 'Softmax'))
model.compile(loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
model.fit(train_scaled, train_target, epochs = 5)
model.evaluate(val_scaled, val_target)