CNN과제 - 꽃 이미지 분류하기

DYN.kim·2021년 1월 27일
0

과제 목표

  • CNN 모델 만들어 5가지 꽃 품종을 분류하고자 한다.

과제 내용

  • CNN 이론을 이해하고 Tensorflow로 구현하고 CNN의 동작과정을 이해하고자 한다.

  • 주어진 데이터셋을 가지고 5가지 꽃의 품종을 분류하는 CNN모델을 학습시키고자 한다.

사용 라이브러리

tensorflow1.15, tqdm, numpy, matplotlib, tensorflow-datasets 1.2.0

데이터셋 구성

  • 학습시간을 위해 64X64 크기로 사전에 전처리 하였다.

  • 학습데이터: 꽃 이미지 2220장

  • 검증데이터: 꽃 이미지 730장

  • 테스트데이터: 꽃 이미지 720장

기본 코드

데이터 전처리 및 배치사이즈 함수 정의

from tqdm.notebook import tqdm
import tensorflow as tf
import tensorflow_datasets as tfds
import numpy as np
import matplotlib.pyplot as plt
import cv2
import os
import time
tf.reset_default_graph()
tf.compat.v1.disable_eager_execution()

def data():
    train_dataset, validation_dataset, test_dataset=tfds.load(name='tf_flowers', split=[tfds.Split.TRAIN.subsplit(tfds.percent[:60]),
                                                                tfds.Split.TRAIN.subsplit(tfds.percent[60:80]),    
                                                                tfds.Split.TRAIN.subsplit(tfds.percent[80:])
                                                                ],shuffle_files=False)
    return train_dataset, validation_dataset, test_dataset
def preprocess():
    train_dataset, validation_dataset, _ =data()
    
    #-----------------------Train Data 전처리
    train_image_array=[]
    train_label_array=[]
    train_size=0
    for train_data in tfds.as_numpy(train_dataset):
        train_image_data=train_data['image']
        train_image_array.append(train_image_data)
        train_label_data=train_data['label']
        train_label_array.append(train_label_data)
        train_size+=1   
    for i in range(train_size):
        train_image_array[i]=cv2.resize(train_image_array[i], (64, 64))/255
           
    validation_image_array=[]
    validation_label_array=[]
    validation_size=0
    for validation_data in tfds.as_numpy(validation_dataset):
        validation_image_data=validation_data['image']
        validation_image_array.append(validation_image_data)
        validation_label_data=validation_data['label']
        validation_label_array.append(validation_label_data)
        validation_size+=1

    for i in range(validation_size):
        validation_image_array[i]=cv2.resize(validation_image_array[i], (64, 64))/255    
        
    return train_image_array, train_label_array, validation_image_array, validation_label_array
def next_batch(num, data, labels):
    idx=np.arange(0, len(data))
    np.random.shuffle(idx)
    idx=idx[:num]
    data_shuffle=[data[i] for i in idx]
    labels_shuffle=[labels[i] for i in idx]
    
    return np.asarray(data_shuffle), np.asarray(labels_shuffle)

시각화 함수 정의

def visualization():    
    print("\n=================================")
    print("        Student Info")
    print("=================================")
    print("이름 : ", student_name)

    print("\n=================================")
    print("        Dataset Info")
    print("=================================")
    print("- 총 3670개의 꽃 이미지 학습 데이터로 구성")

    fig=plt.figure(figsize=(10, 4))

    for i in range(10):
        ax=fig.add_subplot(2, 5, i+1)
        image_show=batch[0]
        label_show=batch[1]
        plt.imshow(image_show[i])
        ax.set_xlabel(label_show[i])
        ax.axes.xaxis.set_ticks([])
        ax.axes.yaxis.set_ticks([])
        if i == 2:
            ax.set_title("Dataset example", fontsize=18)

    plt.show()
    print("0:Dandelion 1:Daisy 2:Tulips 3:Sunflowers 4:Roses")

    print("\n=================================")
    print("        Train Info")
    print("=================================")
    print("학습시간 : {}초".format(round(train_time, 3)))
    print("학습 epoch : ", train_epoch)
    print("dropout rate : ", dropout_rate)

    print("\n=================================")
    print("           Train Loss")
    print("=================================")
    for i in range(len(plt_index)-1):
        print("epoch : {}\tloss : {}".format(plt_index[i+1], round(plt_train_loss[i+1], 5)))

    plt.title("Train loss", fontsize=14)
    plt.xlabel("epoch")
    plt.ylabel("loss")
    if train_epoch >= 10:
        plt.xticks([i for i in range(0, plt_index[-1]+1, int(plt_index[-1]/5))])

    plt.plot(plt_index, plt_train_loss, '-')
    plt.show()

    print("\n=================================")
    print("           Train Accuracy")
    print("=================================")
    for i in range(len(plt_index)-1):
        print("epoch : {}\taccuracy : {}%".format(plt_index[i+1], round(plt_train_accuracy[i+1]*100, 5)))

    plt.title("Train Accuracy", fontsize=14)
    plt.xlabel("epoch")
    plt.ylabel("accuracy")
    plt.plot(plt_index, plt_train_accuracy, "g")
    if train_epoch >= 10:
        plt.xticks([i for i in range(0, plt_index[-1]+1, int(plt_index[-1]/5))])

    plt.show()

    print("\n=================================")
    print("              Validation")
    print("=================================")

    print("Validation Loss : {}".format(round(validation_loss, 5)))
    print("Validation Accuracy : {}%".format(round(validation_accuracy*100, 5)))

    plt.suptitle('Validation Result',fontsize=14)
    plt.subplot(121)
    plt.bar([0, 1, 2], [0, validation_loss, 0], color="orange")
    plt.xticks([1],["Validation Loss"])

    plt.subplot(122)
    plt.bar([0, 1, 2], [0, validation_accuracy, 0], color="blue")
    plt.xticks([1],["Validation Accuracy"])
    plt.show()

CNN 모델링

student_name="이름" #자신의 학번과 이름으로 수정
dropout_rate = 0.5 #드롭아웃 비율 설정
train_epoch=1000 #에폭 설정

def build_CNN_classifier(x):
    # 입력 이미지
    x_image=x

    # 첫번째 convolutional layer
    W_conv1=tf.Variable(tf.truncated_normal(shape=[5, 5, 3, 64], stddev=5e-2))
    b_conv1=tf.Variable(tf.constant(0.1, shape=[64]))
    h_conv1=tf.nn.relu(tf.nn.conv2d(x_image, W_conv1, strides=[1, 1, 1, 1], padding='SAME')+b_conv1)

    # 첫번째 Pooling layer
    h_pool1=tf.nn.max_pool(h_conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')

    # 두번째 convolutional layer
    W_conv2=tf.Variable(tf.truncated_normal(shape=[5, 5, 64, 64], stddev=5e-2))
    b_conv2=tf.Variable(tf.constant(0.1, shape=[64]))
    h_conv2=tf.nn.relu(tf.nn.conv2d(h_pool1, W_conv2, strides=[1, 1, 1, 1], padding='SAME')+b_conv2)

    # 두번째 pooling layer
    h_pool2=tf.nn.max_pool(h_conv2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')

    # 세번째 convolutional layer
    W_conv3=tf.Variable(tf.truncated_normal(shape=[3, 3, 64, 128], stddev=5e-2))
    b_conv3=tf.Variable(tf.constant(0.1, shape=[128]))
    h_conv3=tf.nn.relu(tf.nn.conv2d(h_pool2, W_conv3, strides=[1, 1, 1, 1], padding='SAME')+b_conv3)

    # 네번째 convolutional layer
    W_conv4=tf.Variable(tf.truncated_normal(shape=[3, 3, 128, 128], stddev=5e-2))
    b_conv4=tf.Variable(tf.constant(0.1, shape=[128])) 
    h_conv4=tf.nn.relu(tf.nn.conv2d(h_conv3, W_conv4, strides=[1, 1, 1, 1], padding='SAME')+b_conv4)

    # 다섯번째 convolutional layer
    W_conv5=tf.Variable(tf.truncated_normal(shape=[3, 3, 128, 128], stddev=5e-2))
    b_conv5=tf.Variable(tf.constant(0.1, shape=[128]))
    h_conv5=tf.nn.relu(tf.nn.conv2d(h_conv4, W_conv5, strides=[1, 1, 1, 1], padding='SAME')+b_conv5)

    # 첫번째 Fully Connected Layer 
    W_fc1=tf.Variable(tf.truncated_normal(shape=[16*16*128, 512], stddev=5e-2))
    b_fc1=tf.Variable(tf.constant(0.1, shape=[512]))
    h_conv5_flat=tf.reshape(h_conv5, [-1, 16*16*128])
    h_fc1=tf.nn.relu(tf.matmul(h_conv5_flat, W_fc1)+b_fc1)
    
    h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) 

    # 두번째 Fully Connected Layer 
    W_fc2=tf.Variable(tf.truncated_normal(shape=[512, 5], stddev=5e-2))
    b_fc2=tf.Variable(tf.constant(0.1, shape=[5]))
    logits=tf.matmul(h_fc1_drop, W_fc2)+b_fc2
    y_pred=tf.nn.softmax(logits)

    return y_pred, logits

x=tf.placeholder(tf.float32, shape=[None, 64, 64, 3])
y=tf.placeholder(tf.int64, shape=[None])
keep_prob=tf.placeholder(tf.float32)

#-----------------------Convolutional Neural Networks(CNN) 그래프 생성
y_pred, logits=build_CNN_classifier(x)

#-----------------------Cross Entropy를 비용함수(loss function)으로 정의하고, RMSPropOptimizer 사용
loss=tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=y))
train_step=tf.train.RMSPropOptimizer(0.001).minimize(loss)

#-----------------------정확도 계산
correct_prediction=tf.equal(tf.argmax(y_pred, 1), y)
accuracy=tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

세션 실행, 체크포인트

SAVER_DIR="model"
saver=tf.train.Saver()
checkpoint_path=os.path.join(SAVER_DIR, "model")
ckpt=tf.train.get_checkpoint_state(SAVER_DIR)

#-----------------------세션을 열고 학습 진행
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
            
    train_image_array, train_label_array, validation_image_array, validation_label_array=preprocess()
    plt_train_accuracy=[0]
    plt_train_loss=[0]
    plt_index=[0]
    start=time.time()
    
    print("\n=================================")
    print("          학습 진행 상황")
    print("=================================")
    
    for i in tqdm(range(train_epoch)):
        batch=next_batch(32, train_image_array, train_label_array)
        
        if (i+1)%100 == 0:
            saver.save(sess, checkpoint_path, global_step=i+1)
            train_accuracy=accuracy.eval(feed_dict={x: batch[0], y: batch[1], keep_prob: 1.0})
            train_loss=loss.eval(feed_dict={x: batch[0], y: batch[1], keep_prob: 1.0})
            plt_train_accuracy.append(train_accuracy)
            plt_train_loss.append(train_loss)
            plt_index.append(i+1)

        sess.run(train_step, feed_dict={x: batch[0], y: batch[1], keep_prob: dropout_rate})

    train_time=time.time()-start
    validation_batch=next_batch(730, validation_image_array, validation_label_array)
    validation_loss=sess.run(loss, feed_dict={x: validation_batch[0], y: validation_batch[1], keep_prob: 1.0})
    validation_accuracy=sess.run(accuracy, feed_dict={x: validation_batch[0], y: validation_batch[1], keep_prob: 1.0})
    
visualization()

기본코드 결과

  • 테스트 정확도(Accuracy)

    epoch : 100 accuracy : 31.25%
    epoch : 200 accuracy : 25.0%
    epoch : 300 accuracy : 37.5%
    epoch : 400 accuracy : 50.0%
    epoch : 500 accuracy : 75.0%
    epoch : 600 accuracy : 65.625%
    epoch : 700 accuracy : 71.875%
    epoch : 800 accuracy : 87.5%
    epoch : 900 accuracy : 90.625%
    epoch : 1000 accuracy : 78.125%

  • 테스트 손실(Loss)

epoch : 100 loss : 1.614650011062622
epoch : 200 loss : 1.5362000465393066
epoch : 300 loss : 1.4424500465393066
epoch : 400 loss : 1.0443700551986694
epoch : 500 loss : 0.7260900139808655
epoch : 600 loss : 0.7748000025749207
epoch : 700 loss : 0.7546300292015076
epoch : 800 loss : 0.35062000155448914
epoch : 900 loss : 0.34352999925613403
epoch : 1000 loss : 0.7358199954032898

  • 검증 정확도(Validation Accuracy)

    Validation Accuracy : 58.90411%

  • 검증 손실(Validation Loss)

    Validation Loss : 1.772510051727295

profile
AI 개발자를 목표로 하고 있는 꿈 많은 공대생입니다. a deo vocatus rite paratus

0개의 댓글