In [0]:
# 런타임 -> 런타임 유형변경 -> 하드웨어 가속도 TPU변경
%tensorflow_version 2.x
#런타임 -> 런타임 다시시작
TensorFlow 2.x selected.

1. Importing Libraries

In [0]:
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
In [0]:
import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt
import os

print(tf.__version__)     # 텐서플로우 버전확인 (colab의 기본버전은 1.15.0) --> 2.0 변경 "%tensorflow_version 2.x"
print(keras.__version__)  # 케라스 버전확인
2.1.0
2.2.4-tf

2. Hyper Parameters

In [0]:
learning_rate = 0.001  # 러닝레이트 
training_epochs = 15   # 에폭
batch_size = 100       # 배치사이즈

3. MNIST Data

In [0]:
## MNIST Dataset #########################################################
mnist = keras.datasets.mnist
class_names = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
##########################################################################

4. Datasets

In [0]:
# MNIST image load (trian, test)
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()    

# 0~255 중 하나로 표현되는 입력 이미지들의 값을 1 이하가 되도록 정규화    
train_images = train_images.astype(np.float32) / 255.
test_images = test_images.astype(np.float32) / 255.

# np.expand_dims 차원을 변경
train_images = np.expand_dims(train_images, axis=-1)
test_images = np.expand_dims(test_images, axis=-1) 

# dataset 인스턴스 만들기(tf.data를 사용하여 데이터셋을 섞고 배치를 만듭니다)
train_dataset = tf.data.Dataset.from_tensor_slices((train_images, train_labels)).shuffle(
                buffer_size=100000).batch(batch_size)
test_dataset = tf.data.Dataset.from_tensor_slices((test_images, test_labels)).batch(batch_size)
# from_tensor_slices : 이미지를 이미지와 라벨로 나누기
# batch : 해당 배치 사이즈 만큼 나누기
# shuffle : 고정된 buffer_size만큼 epoch 마다 이미지를 섞어서 오버피팅이 줄도록 도와줌
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step

5. Model Function

In [0]:
# Sequential 모델 층 구성하기
def create_model():
    model = keras.Sequential() # Sequential 모델 시작
    model.add(keras.layers.Conv2D(filters=32, kernel_size=3, activation=tf.nn.relu, padding='SAME', 
                                  input_shape=(28, 28, 1)))
    model.add(keras.layers.MaxPool2D(padding='SAME'))
    model.add(keras.layers.Conv2D(filters=64, kernel_size=3, activation=tf.nn.relu, padding='SAME'))
    model.add(keras.layers.MaxPool2D(padding='SAME'))
    model.add(keras.layers.Conv2D(filters=128, kernel_size=3, activation=tf.nn.relu, padding='SAME'))
    model.add(keras.layers.MaxPool2D(padding='SAME'))
    model.add(keras.layers.Flatten())
    model.add(keras.layers.Dense(256, activation=tf.nn.relu))
    model.add(keras.layers.Dropout(0.4))
    model.add(keras.layers.Dense(10, activation=tf.nn.softmax))
    return model
In [0]:
model = create_model() # 모델 함수를 model 객체로 변경
model.summary() # 모델에 대한 요약 출력해줌
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 28, 28, 32)        320       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 14, 14, 32)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 14, 14, 64)        18496     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 7, 7, 64)          0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 7, 7, 128)         73856     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 4, 4, 128)         0         
_________________________________________________________________
flatten (Flatten)            (None, 2048)              0         
_________________________________________________________________
dense (Dense)                (None, 256)               524544    
_________________________________________________________________
dropout (Dropout)            (None, 256)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 10)                2570      
=================================================================
Total params: 619,786
Trainable params: 619,786
Non-trainable params: 0
_________________________________________________________________
In [0]:
# 위에서 정한 모델을 그림으로(plot) 보여줌
keras.utils.plot_model(model, to_file='model.png', show_shapes=True, show_layer_names=True) 
Out[0]:

6. Loss, Optimizer, Accuracy

In [0]:
# 훈련에 필요한 옵티마이저(optimizer)와 손실 함수를 선택합니다
loss_object = tf.keras.losses.SparseCategoricalCrossentropy()        # Loss는 CategoricalCrossentropy
optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)    # optimizer는 adam 

# 모델의 손실과 성능을 측정할 지표를 선택합니다. 
# 에포크가 진행되는 동안 수집된 측정 지표를 바탕으로 최종 결과를 출력합니다.
train_loss = tf.keras.metrics.Mean(name='train_loss')
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')
test_loss = tf.keras.metrics.Mean(name='test_loss')
test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='test_accuracy')

7. Calculating Gradient

In [0]:
# `tf.function` 이 데코레이터는 함수를 "컴파일" 한다.
# tf.GradientTape를 사용하여 모델을 훈련합니다
@tf.function
def train_step(images, labels):
  with tf.GradientTape() as tape:
    predictions = model(images)
    loss = loss_object(labels, predictions)
  gradients = tape.gradient(loss, model.trainable_variables)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))

  train_loss(loss)
  train_accuracy(labels, predictions)
In [0]:
# 이제 모델을 테스트합니다:
@tf.function
def test_step(images, labels):
  predictions = model(images)
  t_loss = loss_object(labels, predictions)

  test_loss(t_loss)
  test_accuracy(labels, predictions)

8. Training

In [0]:
# train 함수 정의 (텐서플로우 2.0에서는 직접 함수를 만들어야함)
def train(train_dataset, test_dataset, training_epochs):
  for epoch in range(training_epochs):              # 매 epoch 마다 학습이 진행된다
    for images, labels in train_dataset:
      train_step(images, labels)                    # train 이미지 학습

    for test_images, test_labels in test_dataset:   # test 이미지 학습
      test_step(test_images, test_labels)
    
    # print 보여주기 설정
    template = 'epoch: {}, train_loss: {:.4f}, train_acc: {:.2%}, test_loss: {:.4f}, test_acc: {:.2%}'
    print (template.format(epoch+1,
                           train_loss.result(),
                           train_accuracy.result(),
                           test_loss.result(),
                           test_accuracy.result()))
In [0]:
# train 함수 실행, trian data, test data, epoch 순으로 작성
train(train_dataset, test_dataset, training_epochs)
epoch: 1, train_loss: 0.1722, train_acc: 94.48%, test_loss: 0.0493, test_acc: 98.40%
epoch: 2, train_loss: 0.1084, train_acc: 96.54%, test_loss: 0.0452, test_acc: 98.55%
epoch: 3, train_loss: 0.0822, train_acc: 97.37%, test_loss: 0.0440, test_acc: 98.54%
epoch: 4, train_loss: 0.0675, train_acc: 97.85%, test_loss: 0.0398, test_acc: 98.67%
epoch: 5, train_loss: 0.0577, train_acc: 98.16%, test_loss: 0.0377, test_acc: 98.75%
epoch: 6, train_loss: 0.0505, train_acc: 98.38%, test_loss: 0.0358, test_acc: 98.82%
epoch: 7, train_loss: 0.0450, train_acc: 98.56%, test_loss: 0.0357, test_acc: 98.85%
epoch: 8, train_loss: 0.0407, train_acc: 98.69%, test_loss: 0.0350, test_acc: 98.90%
epoch: 9, train_loss: 0.0373, train_acc: 98.80%, test_loss: 0.0341, test_acc: 98.94%
epoch: 10, train_loss: 0.0343, train_acc: 98.90%, test_loss: 0.0331, test_acc: 98.97%
epoch: 11, train_loss: 0.0319, train_acc: 98.97%, test_loss: 0.0324, test_acc: 99.00%
epoch: 12, train_loss: 0.0298, train_acc: 99.04%, test_loss: 0.0317, test_acc: 99.03%
epoch: 13, train_loss: 0.0280, train_acc: 99.09%, test_loss: 0.0319, test_acc: 99.04%
epoch: 14, train_loss: 0.0264, train_acc: 99.15%, test_loss: 0.0322, test_acc: 99.04%
epoch: 15, train_loss: 0.0250, train_acc: 99.19%, test_loss: 0.0319, test_acc: 99.06%