TensorFlow2에서 제공하는 모델 구현 API는 크게 3가지 종류가 있다. 신경망 레이어를 순차적으로 쌓아 나가는 방식의 Sequential API, 레이어를 함수형태로 정의하는 Functional API, 그리고 클래스 형으로 모델을 만들 수 있는 Model Subclassing API다.
Sequential API는 간단한 모델을 쉽게 구축할 수 있으며, 빈 깡통 모델을 만들어 놓고 순차적으로 레이어를 추가하거나 한꺼번에 순차적인 모델을 구축할 수 있다.
Functional API는 복잡한 모델을 구축할 때 유리하며 ResNet과 같이 순차적이지 않은 모델도 구축할 수 있다.
Model Subclassing API는 자유도가 제일 높은 모델 구축 방법으로서 사용자 자신의 방법으로 신경망을 만들고 학습시킬 수 있다.
그러면 Sequential API로 간단한 CNN모델을 만들고 MNIST 숫자를 분류해 보자. 프로그래밍 언어를 처음 배울 때 "Hello, World!" 를 출력하는 것으로 시작하는 것처럼 딥러닝을 처음 배울 때는 MNIST 숫자 분류부터 시작한다.
텐서플로2에서는 MNIST 데이터셋도 쉽게 다운로드할 수 있다.
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# adjusting to 0 ~ 1.0
x_train = x_train / 255.0
x_test = x_test / 255.0
x_train와 x_test에는 MNIST 숫자 그림이 y_train와 y_test에는 라벨이 저장된다. MNIST 숫자 이미지를 몇 개 출력해 보면 다음과 같다.
x_train와 x_test의 사이즈를 보면,
print(x_train.shape, x_test.shape)
(60000, 28, 28) (10000, 28, 28)이다. 각각 데이터 개수가 6만개, 1만개이며 사이즈가 \( 28 \times 28 \) 인 흑백 이미지다. CNN의 컨볼루션 레이어는 채널을 가진 데이터형을 받기 때문에 shape를 바꿔준다.
x_train = x_train.reshape(-1,28,28,1)
x_test = x_test.reshape(-1,28,28,1)
그러면 이미지 사이즈는 \( 28 \times 28 \times 1 \) 이 된다.
만들고자 하는 CNN 모델은 다음과 같이 간단한 것이다.
3개의 컨볼루션 레이어와 2개의 완전연결(fully connected) 레이어로 구성되어 있다. 첫 번째 컨볼루션 레이어의 파라미터 개수는 \( (3 \times 3 \times 1+1) \times 16=160 \)개, 두 번째 컨볼루션 레이어의 파라미터 개수는 \( (3 \times 3 \times 16+1) \times 32=4640 \)개, 세 번째 컨볼루션 레이어의 파라미터 개수는 \( (3 \times 3 \times 32+1) \times 64=18496 \)개, 첫 번째 완전연결 레이어의 파라미터 개수는 \( (3 \times 3 \times 64+1) \times 32=18464 \)개, 두 번째 완전연결 레이어의 파라미터 개수는 \( (32+1) \times 10=330 \)개로서 총 42,090개다.
Sequential API를 사용하여 모델을 만들면 다음과 같다.
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(input_shape=(28,28,1), kernel_size=(3,3), filters=16, activation='relu'),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Conv2D(kernel_size=(3,3), filters=32, activation='relu'),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Conv2D(kernel_size=(3,3), filters=64, activation='relu'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(32, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
Functional API를 사용하여 모델을 만들면 다음과 같다. Sequential API에서는 첫 번째 레이어에 input_shape를 정해줘야 한다.
input_shape = (28,28,1)
img_input = tf.keras.layers.Input(shape=input_shape)
h1 = tf.keras.layers.Conv2D(kernel_size=(3,3), filters=16, activation='relu')(img_input)
h1_pool = tf.keras.layers.MaxPooling2D((2,2))(h1)
h2 = tf.keras.layers.Conv2D(kernel_size=(3,3), filters=32, activation='relu')(h1_pool)
h2_pool = tf.keras.layers.MaxPooling2D((2,2))(h2)
h3 = tf.keras.layers.Conv2D(kernel_size=(3,3), filters=64, activation='relu')(h2_pool)
h3_flat = tf.keras.layers.Flatten()(h3)
h4 = tf.keras.layers.Dense(32, activation='relu')(h3_flat)
predictions = tf.keras.layers.Dense(10, activation='softmax')(h4)
model = tf.keras.Model(inputs=img_input, outputs=predictions)
다음과 같이 빈 모델을 먼저 만들고 add 메소드를 이용하여 차례로 레이어를 추가해서 만들 수도 있다.
model = tf.keras.Sequential()
model.add(tf.keras.layers.Conv2D(input_shape=(28,28,1), kernel_size=(3,3), filters=16, activation='relu'))
model.add(tf.keras.layers.MaxPooling2D((2,2)))
model.add(tf.keras.layers.Conv2D(kernel_size=(3,3), filters=32, activation='relu'))
model.add(tf.keras.layers.MaxPooling2D((2,2)))
model.add(tf.keras.layers.Conv2D(kernel_size=(3,3), filters=64, activation='relu'))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(32, activation='relu'))
model.add(tf.keras.layers.Dense(10, activation='softmax'))
모델의 구조를 출력해보면
model.summary()
다음과 같이 나온다.
모델을 컴파일하고 전체 데이터를 5번 사용하여(에폭 5) 학습하면,
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
history = model.fit(x_train, y_train, epochs=5, validation_split=0.25, verbose=2)
이 되고, 결과를 그림으로 그리면 다음과 같다.
plt.figure(figsize=(10,4))
plt.subplot(1,2,1)
plt.plot(history.history['loss'], 'b-', label='loss')
plt.plot(history.history['val_loss'], 'r-', label='val_loss')
plt.xlabel('epoch')
plt.legend()
plt.subplot(1,2,2)
plt.plot(history.history['accuracy'], 'g-', label='accuracy')
plt.plot(history.history['val_accuracy'], 'k-', label='val_accuracy')
plt.xlabel('epoch')
plt.legend()
plt.show()
학습된 모델을 테스트 데이터를 이용하여 평가해 보면,
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
print(test_acc)
0.9874로서 약 98.7%의 테스트 정확도가 나온다.
전체 코드는 다음과 같다.
import tensorflow as tf
import matplotlib.pyplot as plt
# load mnist data
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# adjusting to 0 ~ 1.0
x_train = x_train / 255.0
x_test = x_test / 255.0
print(x_train.shape, x_test.shape)
# reshaping
x_train = x_train.reshape(-1,28,28,1)
x_test = x_test.reshape(-1,28,28,1)
print(x_train.shape, x_test.shape)
# plotting
for c in range(16):
plt.subplot(4,4,c+1)
plt.imshow(x_train[c].reshape(28,28), cmap='gray')
plt.show()
# model
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(input_shape=(28,28,1), kernel_size=(3,3), filters=16, activation='relu'),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Conv2D(kernel_size=(3,3), filters=32, activation='relu'),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Conv2D(kernel_size=(3,3), filters=64, activation='relu'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(32, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
model.summary()
# compile and train
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
history = model.fit(x_train, y_train, epochs=5, validation_split=0.25, verbose=2)
plt.figure(figsize=(10,4))
plt.subplot(1,2,1)
plt.plot(history.history['loss'], 'b-', label='loss')
plt.plot(history.history['val_loss'], 'r-', label='val_loss')
plt.xlabel('epoch')
plt.legend()
plt.subplot(1,2,2)
plt.plot(history.history['accuracy'], 'g-', label='accuracy')
plt.plot(history.history['val_accuracy'], 'k-', label='val_accuracy')
plt.xlabel('epoch')
plt.legend()
plt.show()
# model evaluate
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
print(test_acc)
'프로그래밍 > TensorFlow2' 카테고리의 다른 글
텐서와 변수 - 2 (0) | 2021.02.10 |
---|---|
텐서와 변수 - 1 (0) | 2021.02.09 |
GradientTape로 간단한 CNN 학습하기 (0) | 2021.01.11 |
Model Subclassing API로 간단한 CNN 구현해 보기 (0) | 2021.01.11 |
Functional API로 간단한 CNN 구현해 보기 (0) | 2021.01.11 |
댓글