본문 바로가기
딥러닝/혼공머신

[혼공머신] chapter 7. 딥러닝 시작 (신경망 모델)

by 다이노소어 2023. 3. 7.
혼자 공부하는 머신러닝 + 딥러닝의 Chapter 7을 공부하면서 정리한 내용을 기반으로 작성하였다.
7-3 미완

 

 

07-1. 인공신경망


인공 신경망(ANN;artificial neural network)

  • 가장 기본적인 인공 신경망은 확률적 경사 하강법을 사용하는 로지스틱 회귀와 같다. 
  • 이미지 분류 문제에는 인공 신경망이 잘 맞는다.
  • 출력층 z값을 계산하는 단위를 유닛(unit)이라고 부른다. (예전에는 뉴런이라고 부름)
  • 기존의 머신러닝 알고리즘이 잘 해결하지 못했던 문제에서 높은 성능을 발휘하는 새로운 종류의 머신러닝 알고리즘일 뿐이다.
  • GPU(그래픽 처리장치)는 벡터와 행렬 연산에 매우 최적화 되어 있어 곱셈/덧셈이 많이 수행되는 인공 신경망에 큰 도움이 된다.
  • 인공 신경망에서는 교차 검증을 살 사용하지 않고, 검증 세트를 별도로 덜어내어 사용한다.

 

케라스(Keras)

  • Tensorflow의 직관적이고 사용하기 편한 고수준 API
  • 멀티 - 백엔드 케라스 : 케라스의 백엔드로 텐서플로, 씨아노, CNTK와 같은 여러 딥러닝 라이브러리를 사용할 수 있다.
    • 단, 2.3.1버전 이후로 더 이상 개발되지 않는다. 그렇기에, 케라스와 텐서플로는 거의 동의어인 셈이다.
    • 케라스는 텐서플로의 핵심 API가 되었다.

 

데이터셋 인공 신경망에 맞게 처리하자

→ 머신러닝에서는 붓꽃 데이터셋이 유명하지만, 딥러닝에서는 MNIST 데이터셋이 유명하다.

 

  1. 패션 MNIST dataset 받기
  2. 검증세트 20%정도를 빼두기
  3. 각 픽셀이 0~255사이의 정숫값을 가지므로 0~1 사이의 값으로 정규화한다. (표준화 아님!)
  4. 2차원 배열을 1차원 배열로 
    • 여기선 reshape()를 썼지만, 이후 모델에 keras.layers.Flatten()을 이용해서 펼쳐주는 층을 추가할 수 있다.
import tensorflow as tf
from tensorflow import keras
from sklearn.model_Selection import train_test_split

(train_input, train_target), (test_input, test_target) =\ 
	keras.datasets.fashion_mnist.load_data()
    
train_scaled, val_scaled, train_target, val_target = 
	train_test_split(train_scaled, train_target, test_size = 0.2)
    
train_scaled = train_input / 255.0
train_scaled = train_scaled.reshape(-1, 28*28)

코드 - 1

인공 신경망 모델을 만들어 보자

  1. Dense 클래스 : 밀집층 객체를 만들 수 있고, 매개변수로는 다음과 같은 사항을 필요로 한다
    • 뉴런 개수,
    • activation = 뉴런의 출력에 적용할 활성화 함수
    • input_shape = 입력의 크기
  2. Sequential 클래스
    • compile() :  모델 훈련하기 전 설정 단계 손실 함수의 종류를 지정해야 한다.
      • 이진분류 : loss = 'binary_crossentropy'
      • 다중분류 : loss = 'categorical_crossentropy'
    • fit()
      • epochs로 반복횟수를 정하고, 훈련한다.
      • verbose로 훈련과정을 어떻게 나타낼지 지정할 수 있다
        • 0: 훈련 과정 나타내지 않는다.
        • 1 (기본값) : 에포크마다 진행막대와 지표를 보여준다
        • 2 : 진행 막대 빼고 훈련결과 출력
    • evaluate() : keras에서 모델의 성능을 평가하는 메서드로, 반드시 이전에 compile()이 실행되어야 한다.
    • predict() : 새로운 데이터에 대해 예측하는 메서드로, 각 샘플마다 10개의 클래스에 대한 확률을 반환한다. (7-3장 참조)
import tensorflow as tf
from tensorflow import keras

dense = keras.layers.Dense(10, activation = 'softmax', input_shape=(784,))
model = keras.Sequential(dense)
model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')
model.fit(train_scaled, train_target, ephochs = 5)
model.evaluate(val_scaled, cal_target)

코드 - 2

  • 원-핫 인코딩 (one-hot encoding)
    • 신경망은 손실을 낮추기 위해서 뉴런의 활성화 함수를 거친 출력값이 가능한 1에 가깝게 만들어야 한다.
    • 원-한 인코딩은 타깃값을 해당 클래스만 1이고, 나머지는 모두 0인 배열로 만드는 것을 말한다.
    • 하지만, 정수로 된 타깃값을 가지고 있다면, 원-핫 인코딩없이 크로스 엔트로피 손실을 계산할 수 있다. 그 때 쓰는 손실함수가 'sparse_categorical_crossentropy'이다.

 

 

07-2. 심층 신경망


활성화 함수

  1. 출력층의 활성화 함수는 다소 정해져 있다.
    • 이진 분류일 경우 시그모이드 함수를 사용
    • 다중 분류일 경우, 소프트맥스 함수를 사용
  2. 은닉층의 활성화 함수는 자유롭다.
    • 모든 은닉층에는 활성화 함수가 있다
    • 시스모이드 함수, 볼 렐수(ReLU)함수가 대표적!
  3. 은닉층에서 활성화 함수를 쓰는 이유는 뭘까
    • a에서 b를 거쳐 c라는 최종값을 얻고자하는 식이 있다고 생각하자. : a * 3 + 2 = b → b * 3 - 5 = c
    • 위 식에서 b는 전달책에 지나지 않아 필요 없어 보인다. 그냥 (a * 3 +2) * 3 - 5 = c로 계산하면, b는 필요 없는 셈이다.
    • 그렇기에, 중간의 b에 log를 씌워 전달하는 등 비선형적으로 비틀어줄 필요가 있다.
  4. 회귀를 위한 신경망에서는 활성화 함수를 적용하지 않는다.
  5. 인공신경망 그림으로 표현할 때, 활성화 함수를 별개의 층이 아니라 층에 포함된 것으로 간주하기에, 생략하는 경우가 많다.

시그모이드 함수

  • 활성화 함수 중 하나로, x값을 0과 1사이로 압축할 수 있다.
  • 함수가 양끝으로 갈 수록 완만해지기 때문에, 올바른 출력을 만드는데 신속하게 대응하지 못한다.

시그모이드 함수
시그모이드 함수 (demos 用)

렐루 함수(ReLU)

  • 시그모이드 함수보다 신속한 대응가능하게 한다. 성능 좋다.
  • ReLU(z) = max(0, z)
    • 음수는 0으로 만든다.
    • 양수는 변동없이 그대로 출력된다.

 

심층 신경망 (DNN;deep neural network)을 만들자

Dense() 할 때 주의사항

  • 신경망의 첫번째 층은 입력의 크기(input_shape)를 꼭 지정해줘야 한다.
  • 은닉층의 뉴런의 개수 > 출력층의 뉴런의 개수
  • 출력층을 가장 마지막에 두어야 한다.

2차원 배열  →  1차원 배열

  • 모델에 데이터를 넣기 전, reshape()을 써서 미리 처리해두기
  • keras.layers.Flatten()을 이용해, 일렬로 펼치는 층을 입력층 바로 뒤에 추가한다. [코드 - 3]

층 추가 방법

  • 코드 - 2 처럼 dense로 따로 저장해 리스트로 주는 방법 [코드 - 3의 flatten]
  • Sequential 생성하면서 같이 생성 [코드 - 3의 relu]
  • add() 함수 사용 [코드 - 3의 softmax]
import tensorflow as ts
from tensorflow import keras
(train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data()
train_scaled = train_input / 255.0

'''
2차원 -> 1차원 : Flatten ()
add dense : list, add()
'''

# make_model : 모델 생성 함수
def make_model(aLayer = None) :
	flatten = keras.layers.Flatten(input_shape=(28, 28), name = 'flatten')
	model = keras.Sequential([flatten,keras.layers.Dense(100, activation = 'relu', name = 'relu')])
	if(aLayer)
    	model.add(aLayer)
    model.add(keras.layers.Dense(10, activation = 'softmax', name ='softmax'))
    return model

model = make_model()
model.summary()

코드 - 3

 

Optimizer(옵티마이저)

▷ 모델 환경설정(compile())할 때 매개변수 optimazer에 지정할 수 있다 (default : rmsprop)

 keras.optimizers 클래스 객체 만들 때의 매개변수

  • learning_rate : 학습률을 지정할 수 있다 (default : 0.01)
  • momentum :  0보다 큰 값을 지정하면 momentum optimization을 사용한다 (보통 0.9 이상을 지정함) (default : 0)
  • nesterov : nesterov momentum optimization을 사용여부 지정(default : False)

1. SGD(Stochastic Gradient Descent) 

  • 확률적 경사하강법, 가장 기본적인 옵티마이저
  • learning_rate :  (default : 0.01)

2. Adam(추천!)

  • 적응적 학습률(adaptive learning rate; 모델이 최적점에 가까워질수록 학습률을 낮춰 안정적으로 최적점에 수렴하도록 함)을 사용한다.
  • momentum optimization과 RMSprop의 장점을 접목한 것
  • learning_rate : (default : 0.001)

3. Adagrad

  • 적응적 학습률을 사용한다.
  • learning_rate : (default : 0.001)

4. RMSprop(Root Mean Square Propagation)

  • 적응적 학습률을 사용한다.
  • learning_rate : (default : 0.001)
'''
keras.optimizer 클래스 객체 만들기
- 매개변수 바꾸고 싶을 때
keras.optimizers.SGD()
Keras.optimizers.Adagrad()
keras.optimizers.RMSprop()
keras.optimizers.Adam()
'''
sgd = keras.optimizer.SGD(learning rate = 0.1, momentum = 0.9, nesterov = True)
model.compile(optimizer = sgd, loss = 'sparse_categorical_crossentropy', metrics = 'accuracy')

'''
compile()의 optimizer 매개변수에 지정
sgd
adam
adagrad
rmsprop
'''
model.compile(optimizer = 'adam', loss = 'sparse_categorical_crossentropy', metrics = 'accuracy')

model.fit(train_scaled, train_target, epoches = 5)
model.evaluate(val_scaled, val_target)

코드 - 4

 

 

07-3. 신경망 모델 훈련


검증 손실

손실 곡선과 정확도 곡선

  • history 객체에는 훈련 측정 값이 담겨 있는 history 딕셔너리가 들어 있다.
print(history.history.keys())

#dict_keys(['loss', 'accuracy'])

 

  • matplotlib.pyplot의 plot() 함수를 통해서 손실, 정확도 그래프를 그릴 수 있다.
    • y축 : history.history['loss'] 혹은 history.history['accuracy']
    • x축 : epoch

 

검증 손실

  • 인공 신경망은 모두 일종의 경사 하강법을 사용하기 때문에, 과대/과소적합을 막기 위해서는 훈련세트와 검증세트에 대한 손실을 모두 확인해야 한다.
  • 모델이 잘 훈련되었는지 판단하려면 정확도보다는 손실 값을 확인해야 하고, 손실 함수가 최적화 되어야 한다.
  • fit() 함수의 validation_data에 튜플로 검증세트를 전달할 수 있고, 검증세트에 대한 손실과 정확도는 각각 val_loss와 val_accuracy에 들어 있다.
model.fit(train_scaled, train_target, expochs = 20, verbose = 0, 
	validation_data = (val_scaled, val_target))
import matplotlib.pyplot as plt
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
ply.legend(['train', 'val'])
plt.show()

과대적합 확인

 

인공 신경망 최적화

- 과대적합 막는 방법

- 앞서 검증 손실 부분에서 훈련세트와 테스트세트에 대해서 에포크 당 손실 그래프를 그렸다. 이는 과대적합 확인할 수 있는 방법으로, 이번엔 과대적합을 막는 여러 방법을 정리해보자.

1) Optimizer (Adam, RMSprop 등)를 이용해보자

  •  compile()로 모델 설정할 때, optimizer를 지정해주면 된다.

2)  Early Stopping(조기 종료)

  • epoch 매개변수를 이용해 학습률을 학습률을 조정해보자
  • fit()에 epoch를 지정해주는데, optimizer를 지정해주면 된다.
  • keras.callbacks.EarlyStopping() : 조기 종료 콜백함수
    • 매개변수 patience에 횟수를 지정하여, 그 횟수만큼 검증 손실이 줄어들지 않으면 훈련을 중지한다.
    • early_stopping_cb.stopped_epoch로 훈련이 중지된 게 몇 번째 에포크인지 확인할 수 있다.
    • 예를들어, patience를 2로 지정했고, 에포크 12번째 때 중지되었다면, 최적의 모델은 2 에포크 전의 모델인 셈이다. 

3) Drop Out(드롭아웃)

  • WHAT 뉴런이 랜덤하게 드롭아웃되는데, 드롭할 뉴런의 개수는 우리가 지정할 수 있다. (하이퍼파라미터임)
  • WHY 랜덤하게 뉴런을 드롭시켜, 일부 뉴런의 출력을 0으로 막아  특정 뉴런에 과하게 의존하는 경향을 줄일 수 있다. 그렇기에, 드롭아웃을 통해 과대적합을 줄이고 보다 안정적인 예측을 만들 수 있는 것이다.
  • 일부 뉴런의 출력을 0으로 만들지만 전체 출력 배열의 크기는 바뀌지 않는다.
  • 훈련이 끝난 뒤에는 훈련된 모든 뉴런을 사용해야 예측을 잘 할 수 있기에, 훈련이 끝난 뒤에는 드롭아웃을 적용해서는 안된다.
  • 다행히 텐서플로와 케라스는 모델을 평가하고 모델을 가지고 예측할 때는 자동으로 드롭아웃을 적용하지 않는다.

4) Callback(콜백)

  • fit()의 훈련 중간에 특정 작업들을 수행할 수 있게 한다.
  • fit()의 하이퍼 파라미터 callbacks에 리스트형태로 지정해주면 된다.
  • keras.callbacks.ModelCheckpoint() : 모델 저장 콜백함수
    • 매개변수 best_only= True로 두면, 가장 검증 손실이 낮은 모델을 저장할 수 있다.
    • 기본적으로는 에포크마다 모델을 저장한다.
  • keras.callbacks.EarlyStopping() : 조기 종료 콜백함수
# 드롭아웃
model.add(keras.layers.Dropout(0.3))

# 콜백
modelCheck = keras.callbacks.ModelCheckpoint('best-model.h5', save_best_only = True)
model.fit( ... , callbacks = [modelCheck]

 

모델 저장과 복원

1. 모델 저장

  • save_weights() : 모델 파라미터를 체크포인트 포맷으로 저장한다.
  • save() : 모델구조와 모델 파라미터를 SavedModel 포맷으로 저장한다.
  • 인자로 전달하는 파일의 확장자가 .h5라면 HDF5 포맷으로 저장한다

2. 모델 복원

  • load_weights()
    • 이전에 저정했던 모델 파라미터를 복원하여, 새로운 모델에 해당 모델 파라미터를 적재할 수 있다.
    • save_weights()의 쌍으로 저장된 모델과 정확히 같은 구조를 가지지 않으면 에러가 발생한다.
  • load_model()
    • 모델 파라미터, 모델구조, 옵티마이저 상태까지 모두 복원한다.
    • save()로 저장된 모델을 load_model()로 복원할 수 있다.
# 모델 저장
model.save_weights('model-parameters.h5')
model.save('model-whole.h5')

# 모델 복원
new_model = make_model() #코드3 의 make_model() 함수로 모델 생성함
model_parameter.load_weights('model-parameters.h5')
model_whole = keras.model.load_model('model-whole.h5')

 

predict()

import numpy as np
val_labels = np.argmax(model.predict(val_scaled), axis = -1)
print(np.mean(val_labels == val_target))

 

 

 


**참고

1. 표준화(Nomalization)
→ 값의 최대-최소 범위를 벗어나지 않고, 공통 척도를 기준으로 변경하는 것
보통 0~1사이의 고정된 범위로 조정된다.
Min-Max scaling을 Normalization이라고 부르기도 한다.

 Xnorm = ( X Xmin ) / ( Xmax Xmin )
2. 정규화(Standardization)
 feature들이 표준 정규 분포 특성을 가지게 하는 것

 z = ( x- μ ) / σ
[epoche와 batch size]

1 epoch = 100 / batch size = 10 iteration

→ epoches : 전체 데이터셋에 대해서 한 번 학습을 완료한 상태
batch size : 한번 전달되는 데이터셋의 샘플 사이즈

길게 늘어뜨려서 이해해보자.
전체 데이터셋 중 batch size만큼의 일부가 전달되고 학습되는 과정이 반복(iteration)된다.
여러 반복이 후,  전체 데이터셋이 한 번 학습이 완료된다.
이 총 과정을 몇 번 반복할지 epoche로 정한다.
[tuple]

ex ) (1,)

→ 값이 중복될 수 있지만, 내부 값을 특정해서 변경하거나 삭제할 수 없다. 물론, 튜플 자체 삭제는 가능하다.
[np.argmax()]

가장 큰값의 인덱스 반환
- axis = -1 : 마지막 차원을 따라 최댓값의 인덱스 반환
- axis = 0 : row를 따라 column 별 최댓값의 인덱스 반환
- axis = 1 : column을 따라 row 별 최대값의 인덱스 반환