IT/AI\ML

[python/Tensorflow2.0] Mnist 학습 모델 (3)-CNN; Ensemble

개발자 두더지 2020. 4. 20. 23:03
728x90

0. NN Implementation Flow in TensorFlow

1. Set hyper parameters

; learning rate, training epochs, batch size, ect.

2. Make a data pipelining

; use tf.data

# data pipeline이란 데이터 셋을 load하고, 앞에서 설정했던 batch_size만큼 테이터를 가져 와서 네트워크에 공급하는 역할

3. Build a neural network model

; tf.keras의 subclassing 사용

4. Define a loss function

; cross entropy

# 뉴럴 네트워크의 output과 우리가 가진 정답(label)간의 error비교

# classification 문제를 풀어볼 것이므로 cross entropy를 사용

5. Calculate a gradient

; use tf.GradientTape

# loss값을 weight에 대해 미분해 Gradient를 계산

6. Select an optimizer

; Adam optimizer

# Gradient를 이용해 weight를 update

# ---------------------------------------- 여기까지가 사실상 학습부분

7. Define a metric for model's performance

; accuracy

# 테스트 데이터 셋을 이용하여 모델이 얼마나 잘 학습했는지 확인을 위한 성능 측정 metric

# Classification 문제에서는 metric으로 accuracy를 많이 사용

8. (optional) Make a checkpoint for saving

9. Train and Validate a neural network model

 Ensemble로 CNN model을 구성해보고자 한다. 지난 포스팅과 비교하여 코드가 변경되는 부분은 빨간색으로 표시한 부분이다. 3번은 subclassing model에서 인스턴스를 여러 개 생성하는 코드가 수정될 것이며, 7번의 accuracy를 계사하는 부분에 있어서도 모델에 대한 output이 여러 개가 나올 것이므로 그 output을 종합하여 정확도를 계산하는 코드로 변경될 것이며, model이 여러 개 있으므로 9번의 training코드도 변경시켜줘야한다.

여기서는 세 개의 CNN으로 Ensemble을 아래와 같이 구성할 것이다.

똑같은 데이터 셋을 세 개를 각각의 모델에 넣어줘 각각 학습을 실행시키고,

학습하는 중간중간 혹은 학습이 모두 끝난 다음에 inference할 때는 같은 이미지를 넣었을 때 출력되는 각각의 모델의 output을 종합적으로 판단하는 방식


1. Importing Libraries

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.utils import to_categorical
import numpy as np
import matplotlib.pyplot as plt
import os

print(tf.__version__)
print(keras.__version__)

 

2. Hyper Parameters

learning_rate = 0.001
training_epochs = 15
batch_size = 100

tf.random.set_seed(777)

 

3. Creating Checkpoint Directory

cur_dir = os.getcwd()
ckpt_dir_name = 'checkpoints'
model_dir_name = 'minst_cnn_emsemble'

checkpoint_dir = os.path.join(cur_dir, ckpt_dir_name, model_dir_name)
os.makedirs(checkpoint_dir, exist_ok=True)

checkpoint_prefix = os.path.join(checkpoint_dir, model_dir_name)

 

4. MNIST / Fashion MNIST Data

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

## Fashion MNIST Dataset #################################################
#mnist = keras.datasets.fashion_mnist
#class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
##########################################################################

 

5. Datasets

(train_images, train_labels), (test_images, test_labels) = mnist.load_data()    
    
train_images = train_images.astype(np.float32) / 255.
test_images = test_images.astype(np.float32) / 255.
train_images = np.expand_dims(train_images, axis=-1)
test_images = np.expand_dims(test_images, axis=-1)
    
train_labels = to_categorical(train_labels, 10)
test_labels = to_categorical(test_labels, 10)    
    
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)

 

6. Model Class-Model Subclassing

class MNISTModel(tf.keras.Model):
    def __init__(self):
        super(MNISTModel, self).__init__()
        self.conv1 = keras.layers.Conv2D(filters=32, kernel_size=[3, 3], padding='SAME', activation=tf.nn.relu)
        self.pool1 = keras.layers.MaxPool2D(padding='SAME')
        self.conv2 = keras.layers.Conv2D(filters=64, kernel_size=[3, 3], padding='SAME', activation=tf.nn.relu)
        self.pool2 = keras.layers.MaxPool2D(padding='SAME')
        self.conv3 = keras.layers.Conv2D(filters=128, kernel_size=[3, 3], padding='SAME', activation=tf.nn.relu)
        self.pool3 = keras.layers.MaxPool2D(padding='SAME')
        self.pool3_flat = keras.layers.Flatten()
        self.dense4 = keras.layers.Dense(units=256, activation=tf.nn.relu)
        self.drop4 = keras.layers.Dropout(rate=0.4)
        self.dense5 = keras.layers.Dense(units=10)
    def call(self, inputs, training=False):
        net = self.conv1(inputs)
        net = self.pool1(net)
        net = self.conv2(net)
        net = self.pool2(net)
        net = self.conv3(net)
        net = self.pool3(net)
        net = self.pool3_flat(net)
        net = self.dense4(net)
        net = self.drop4(net)
        net = self.dense5(net)
        return net

 

# 위의 call 메서드까지는 동일하나 변경되는 부분은 이 부분이다.
# 여러 개의 model을 만들 것이므로 models라는 빈 리스트를 임의로 만들어주고, 
# for문을 돌면서 인스턴스를 하나씩 생성해 리스트에 append하는 방식이다.
# 앞서 말했듯 3개의 모델을 만들 것이므로 num_models는 3
models = []
num_models = 3
for m in range(num_models):
    models.append(MNISTModel())

 

7. Loss Function

모델이 여러 개가 되었지만 loss function이나 gradient를 모델 하나하나에 대해 따로 계산을 할 것이므로 코드 이 두 부분에 대한 코드 변경은 없다.

def loss_fn(model, images, labels):
    logits = model(images, training=True)
    loss = tf.reduce_mean(tf.keras.losses.categorical_crossentropy(
        y_pred=logits, y_true=labels, from_logits=True))
    return loss

 

8. Calculating Gradient

def grad(model, images, labels):
    with tf.GradientTape() as tape:
        loss = loss_fn(model, images, labels)
    return tape.gradient(loss, model.variables)

 

9. Calculating Model's Accuracy

# 앞서 말했듯 평가 부분에서 여러 모델을 종합해서 평가하므로 model이 아닌 앞에서 만들었던 models 리스트를 파라미터로 넣어줘야한다.
def evaluate(models, images, labels):
    # 여기의 predictions이 모델 세 개에서 나온 아웃풋을 종합한 결과를 나타낸다.
    # 처음에는 labels와 같은 shape의 0으로 채워진 tensor을 만들어 놓고
    predictions = np.zeros_like(labels)
    # for문으로 models의 리스트에서 모델을 하나씩 꺼내서 그 모델에다가 이미지를 넣어준다.
    for model in models:
        logits = model(images, training=False)
        predictions += logits # 각 모델에서 나온 logits을 predictions에 더함
    # 앙상블 기법을 구현하는 방법은 여러 가지가 있는데, 여기서는 간단하게 각 모델에서 나온 결과를 다 더해서 그 중에 가장 큰 것이 정답이라고 하는 방법을 사용한다.
    correct_prediction = tf.equal(tf.argmax(predictions, 1), tf.argmax(labels, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    return accuracy

 

10. Optimizer

optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)

 

11. Creating Checkpoints

# checkpoints는 모델 별로 따로 저장하기 위해서 리스트 형태로 만들어 주었다.
checkpoints = []
for m in range(num_models):
    checkpoints.append(tf.train.Checkpoint(cnn=models[m]))

 

12. Training

# 기존은 for문은 2개(바깥쪽 for문은 epoch 하나마다 루프를 한 번 도는 것이고 안쪽 for문은 batch 한 번에 한 번 루프를 도는 형식)를 썼지만, 
# 여기서는 batch안에서도 각각의 모델이 학습할 수 있도록 for문 세 개를 사용한다.
# train my model
print('Learning started. It takes sometime.')
for epoch in range(training_epochs):
    avg_loss = 0.
    avg_train_acc = 0.
    avg_test_acc = 0.
    train_step = 0
    test_step = 0    
    
    for images, labels in train_dataset:
        for model in models:
            #train(model, images, labels)
            grads = grad(model, images, labels)                
            optimizer.apply_gradients(zip(grads, model.variables))
            loss = loss_fn(model, images, labels)
            avg_loss += loss / num_models # loss를 계산할 때 모델의 숫자로 나눠준다는 점을 주의!
        acc = evaluate(models, images, labels) # 첫 번째 파라미터 models 리스트
        avg_train_acc += acc
        train_step += 1
    avg_loss = avg_loss / train_step
    avg_train_acc = avg_train_acc / train_step
    
    for images, labels in test_dataset:        
        acc = evaluate(models, images, labels)   # 첫 번째 파라미터 models 리스트     
        avg_test_acc += acc
        test_step += 1    
    avg_test_acc = avg_test_acc / test_step    

    print('Epoch:', '{}'.format(epoch + 1), 'loss =', '{:.8f}'.format(avg_loss), 
          'train accuracy = ', '{:.4f}'.format(avg_train_acc), 
          'test accuracy = ', '{:.4f}'.format(avg_test_acc))
    
    
    for idx, checkpoint in enumerate(checkpoints):
        checkpoint.save(file_prefix=checkpoint_prefix+'-{}'.format(idx))

print('Learning Finished!')

참고자료

https://www.edwith.org/boostcourse-dl-tensorflow/lecture/43747/

https://github.com/deeplearningzerotoall/TensorFlow/blob/master/tf_2.x/lab-11-4-mnist-cnn-ensemble-keras-eager.ipynb

728x90