Tensorflow v2.0 에서 Keras 모델 구현하기
Keras로 다층 퍼셉트론 구현
케라스로 다층 퍼셉트론 구현하는 과정입니다.
케라스는 고수준 딥러닝 API로서, 모든 종류의 신경망을 쉽게 만들고 훈련, 평가할 수 있습니다.
사용한 환경은 다음과 같습니다.
Ubuntu 20.04
Python 3.8.2
CUDA 10.2
Tensorflow 2.2.0
Keras 2.3.1
오늘은 가장 기초인 Sequential API를 이용하여 MNIST 이미지 분류기를 만들어보는 작업을 수행하겠습니다.
가장 먼저, fation MNIST dataset을 케라스를 통해 적재합니다.
fashion_mnist_dataset = keras.datasets.fashion_mnist
mnist_dataset = keras.datasets.mnist
(X_train_full, y_train_full), (X_test, y_test) = fashion_mnist_dataset.load_data()
Keras에는 MNIST, Fashion MNIST 등 널리 알려진 dataset을 다운로드 할 수 있는 유틸리티 함수를 제공합니다.
그 중에서 fasthion mnist 데이터를 불러와 사용해 보겠습니다.
fashion mnsit dataset을 불러오게 되면, 60000장의 28x28 크기의 ‘uint8’ 형태의 이미지를 불러옵니다.
이 데이터는 이미 훈련 셋과 테스트 셋으로 나누어져있지만, vaild set은 존재하지 않기 때문에 따로 만들어 주어야합니다. 그리고, uint8 이미지로 0~255 사이의 값으로 이루어진 이미지 이기 때문에, SGD로 training 하기 위해 0~1 사이의 값으로 만들어줍니다.
X_valid, X_train = X_train_full[:5000] / 255.0 , X_train_full[5000:] / 255.0
y_valid, y_train = y_train_full[:5000] , y_train_full[5000:]
X_test = X_test / 255.0
신경망 모델을 만들고, 학습을 진행해보도록 하겠습니다.
def simple_model():
model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape=[28,28]))
model.add(keras.layers.Dense(300,activation='relu'))
model.add(keras.layers.Dense(100,activation='relu'))
model.add(keras.layers.Dense(10,activation='softmax'))
return model
model.summary() 를 통해 model에 대한 정보를 확인할 수 있습니다.
model = simple_model()
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
flatten (Flatten) (None, 784) 0
_________________________________________________________________
dense (Dense) (None, 300) 235500
_________________________________________________________________
dense_1 (Dense) (None, 100) 30100
_________________________________________________________________
dense_2 (Dense) (None, 10) 1010
=================================================================
Total params: 266,610
Trainable params: 266,610
Non-trainable params: 0
_________________________________________________________________
이 코드는 2개의 hidden layer로 이루어진 분류용 다층 퍼셉트론입니다.
첫번째 라인은 Sequential model을 선언합니다. Sequential은 순서대로 연결된 층을 일렬로 쌓아서 구성합니다.
첫번째 층은 Flatten 층으로, 입력 이미지를 1D 배열로 변환합니다. 이 층은 간단한 전처리를 수행할 뿐이며, 어떤 모델 파라미터도 가지지 않습니다.(summary의 param이 0) 모델의 첫 번째 층이므로 input_shape을 지정해야 합니다. MNIST dataset 의 이미지 shape은 (28,28,1)으로, input shape은 이미지의 크기 [28,28]이 됩니다.
두번째 층은 뉴런 300개를 가지는 Dense 층입니다. 이 층은 ReLU 활성화 함수를 사용합니다. Dense 층마다 각자 가중치 행렬을 관리합니다. 이 행렬에는 층의 뉴런과 입력 사이의 모든 연결 가중치가 포함되며, 편향도 벡터로 관리됩니다. 이 층은 데이터를 입력받으면 다음 식을 계산합니다.
세번째 층은 뉴런 100개를 가지는 Dense 층입니다. 마찬가지로, ReLU 활성화 함수를 사용합니다.
마지막으로, 클래스 하나마다 뉴런 갖는, 10개의 뉴런을 가진 Dense 출력층을 지정합니다. softmax함수를 사용합니다.
모든 층의 파라미터는 get_weights() 메소드와 set_weights() 메소드를 통해 접근할 수 있습니다.
Dense 층의 경우 연결 가중치와 편향이 모두 포함되어 있습니다.
Dense 층은 대칭성을 깨뜨리기 위하여 연결 가중치(weights)를 무작위로 초기화합니다. 편향(bias)은 0으로 초기화됩니다. 따라서, 다른 방법을 이용하여 초기화를 수행하고 싶다면, 층을 만들 때 파라미터에 kernel_initializer와 bias_initializer를 추가해주어야 합니다.
모델을 만들고 나서, compile() 메소드를 통해 사용할 손실 함수와 optimizer를 지정합니다. 뿐만 아니라, 훈련과 평가 시에 계산할 지표를 지정할 수 있습니다.
model.compile(loss="sparse_categorical_crossentropy",
optimizer="sgd",
metrics=["accuracy"])
현재 classification 대상인 Fashion MNIST dataset은 샘플마다 타깃 클래스 인덱스가 하나씩 있습니다. 클래스가 배타적(mutually exclusive classes)이므로, sparse_categorical_crossentropy 손실(loss)을 사용합니다.
만약 샘플마다 클래스별 타깃 확률을 갖고 있다면 categorical_crossentropy 손실을 사용해야 하고, 이진 분류를 수행한다면 출력층의 활성화 함수는 sigmoid가 되며, binary_crossentropy 손실을 사용합니다.
optimizer는 SGD를 사용합니다. keras가 backprop을 수행하는 방법으로, 다른 optimizer들 또한 지정하여 사용할 수 있습니다. learning rate를 튜닝하여 사용하기 위해서는 다음과 같이 사용합니다. 위 코드와 같이 사용 시 기본값인 lr=0.01을 사용합니다.
optimizer=keras.optimizers.SGD(lr="Learning Rate")
이제 fit 메소드를 통해 모델을 훈련합니다.
history = model.fit(X_train, y_train, epochs=30,
validation_data=(X_valid,y_valid))
입력(X_train)과 타깃 클래스(y_train), 훈련할 epochs 를 기본적으로 전달하고, 검증 세트도 전달(선택사항)
케라스는 한 epoch마다 검증 set을 이용하여 손실과 추가적인 측정 지표들을 계산합니다. 이 지표는 모델이 얼마나 잘 수행되고 잇는지 확인하는 데 유용합니다.
훈련 세트 성능이 검증 세트보다 월등히 높다면, 훈련 세트에 overfitting 된 경우라고 할 수 있습니다.
fit() 메소드가 반환하는 History 객체에는 훈련 파라미터(history.params), 수행된 epoch 리스트(history.epoch)가 포함됩니다. 이 객체의 가장 중요한 속성은, 에포크가 끝날때 마다 훈련 세트와 검증 세트에 대한 손실과 측정한 지표를 담은 dict를 제공한다는 것입니다.(history.history) 이 dict를 이용하여 pandas dataframe을 만들고, plot 메서드를 호출하면 learning curve 그래프를 그릴 수 있습니다.
pd.DataFrame(history.history).plot(figsize=(8,5))
plt.grid(True)
plt.gca().set_ylim(0,1)
plt.show()
훈련이 진행되는 동안 훈련 정확도와 검증 정확도가 꾸준히 상승하는 것을 볼 수 있고, 훈련 손실과 검증 손실은 감소하는 것을 확인할 수 있습니다. 또한 검증 곡전이 훈련 곡선과 가깝습니다. 이는 크게 overfitting 이 일어나지 않았다는 증거가 됩니다.
모델 성능이 만족스럽지 않다면, 처음으로 되돌아가서 하이퍼파라미터를 튜닝해야 합니다. 맨 처음 확인할 것은 학습률(learning rate)입니다. 학습률이 도움이 되지 않았다면, 다음으로는 다른 optimizer를 테스트해보는 것이 좋습니다.
여전히 성능이 좋지 않다면, 층 개수, 각 층의 뉴런 수, 은닉층이 사용하는 활성화 함수와 같은 모델의 다양한 하이퍼파라미터들을 수정해볼 필요가 있습니다.
모델의 검증 정확도가 만족스럽다면, 모델을 상용 환경으로 배포하기 전에 테스트 세트로 모델을 평가하여 일반화 오차를 추정해야 합니다. 이 때 evaluate() 메소드를 사용합니다.
model.evaluate(X_test, y_test)
모델을 사용하여 예측을 만들 수도 있습니다.
여기서는 실제로 새로운 sample이 없기 때문에, 테스트 세트의 처음 3개 샘플을 사용하였습니다.
X_new = X_test[:3]
y_proba = model.predict(X_new)
y_proba.round(2)
y_pred = model.predict_classes(X_new)
print(y_pred)