• [딥러닝] 케라스(Keras) CNN을 활용한 장롱 이미지 분류하기

    2020. 11. 27.

    by. seo.0

    이전 포스팅에서 총 40000개의 이미지들을 프로세싱하였다. 이번 포스팅에서는 케라스를 이용해서 CNN 모델을 구축하고 전처리한 이미지 데이터셋으로 모델 학습을 시켜볼 것이다.

     

    CNN 모델은 아래 정보를 참고하여 구현하였다.

     

    CNN with Keras

    Explore and run machine learning code with Kaggle Notebooks | Using data from multiple data sources

    www.kaggle.com

     

    아래 코드는 plot history로 train 데이터 셋과 validaton 데이터 셋의 plot loss와 accuracy를 시각화해서 보여준다.

    def plot_history(history):
        loss_list = [s for s in history.history.keys() if 'loss' in s and 'val' not in s]
        val_loss_list = [s for s in history.history.keys() if 'loss' in s and 'val' in s]
        acc_list = [s for s in history.history.keys() if 'acc' in s and 'val' not in s]
        val_acc_list = [s for s in history.history.keys() if 'acc' in s and 'val' in s]
        
        if len(loss_list) == 0:
            print('Loss is missing in history')
            return 
        
        ## As loss always exists
        epochs = range(1,len(history.history[loss_list[0]]) + 1)
        
        ## Loss
        plt.figure(1)
        for l in loss_list:
            plt.plot(epochs, history.history[l], 'b', label='Training loss (' + str(str(format(history.history[l][-1],'.5f'))+')'))
        for l in val_loss_list:
            plt.plot(epochs, history.history[l], 'g', label='Validation loss (' + str(str(format(history.history[l][-1],'.5f'))+')'))
        
        plt.title('Loss')
        plt.xlabel('Epochs')
        plt.ylabel('Loss')
        plt.legend()
        
        ## Accuracy
        plt.figure(2)
        for l in acc_list:
            plt.plot(epochs, history.history[l], 'b', label='Training accuracy (' + str(format(history.history[l][-1],'.5f'))+')')
        for l in val_acc_list:    
            plt.plot(epochs, history.history[l], 'g', label='Validation accuracy (' + str(format(history.history[l][-1],'.5f'))+')')
    
        plt.title('Accuracy')
        plt.xlabel('Epochs')
        plt.ylabel('Accuracy')
        plt.legend()
        plt.show()

    이 코드는 아래 사이트를 참고하였다.

     

    Keras - plot history, full report and Grid Search

    Explore and run machine learning code with Kaggle Notebooks | Using data from Iris Species

    www.kaggle.com

     

    CNN 모델 구현을 위해 필요한 모듈들을 import 하였다.

    import keras
    from keras.models import Sequential
    from keras.callbacks import EarlyStopping, ModelCheckpoint
    from keras.layers import Conv2D, MaxPooling2D, Dense, Dropout, Flatten
    from keras.layers.normalization import BatchNormalization

     

    아래는 CNN 코드이다.

    model = Sequential()
    model.add(Conv2D(32, kernel_size=(3, 3),
                     activation='relu',
                     kernel_initializer='he_normal',
                     input_shape=inputShape))
    model.add(MaxPooling2D((2, 2)))
    model.add(Dropout(0.25))
    model.add(Conv2D(64, (3, 3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.25))
    model.add(Conv2D(128, (3, 3), activation='relu'))
    model.add(Dropout(0.4))
    model.add(Flatten())
    model.add(Dense(128, activation='relu'))
    model.add(Dropout(0.3))
    model.add(Dense(2, activation='softmax'))

    tf.keras.models 모듈의 Sequential을 사용해서 신경망의 각 층을 순서대로 쌓을 수 있다. add()를 호출하여 합성곱 층, 최대 풀링층, 드롭아웃 층을 반복해서 구성해 모델을 구축하였다.

    input_shape은 32*32 크기에, grayscale로 한 개의 채널을 가지므로 (32, 32, 1)이다.

    처음 합성곱 층은 32개의 3*3크기의 필터를 설정하였으며, 활성화 함수는 relu를 사용하였다. 가중치는 'he_normal'로 초기화하였다.

    출처:https://reniew.github.io/12/

    relu 함수는 위의 그림과 같은 함수로 간단하고 사용이 쉬우며 최근 CNN에서 많이 활용되는 활성화 함수이다. 주로 Conv2D 은닉층에서 사용된다.

     

    그 다음 풀링 크기가 2*2인 최대 풀링 층을 추가하여서 공간 방향 차원을 절반으로 줄인다.

    이후 드롭아웃층을 사용하는데 이는 과적합을 방지하기 위해서 학습 시에 지정된 비율(0.25)만큼 임의의 입력 뉴런을 제외시키는 작업이다.

     

    드롭아웃층이 끝나면 이제는 필터의 개수를 64개로 설정해서 두번째 합성곱 층과 최대 풀링층, 드롭아웃층을 통과시키고, 그 다음은 필터의 개수를 128개로 설정해서 세번째 합성곱 층을 통과시킨다.

    풀링 층 다음에 필터 개수를 두 배로 늘리는 것이 일반적인데, 풀링 층이 공간 방향 차원을 절반으로 줄이므로 이어지는 층에서 파라미터 개수, 메모리 사용량, 계산 비용을 크게 늘리지 않고 특성 맵 개수를 두 배로 늘릴 수 있기 때문이다.

     

    세번째 합성곱 층을 통과한 후에는 드롭아웃층에서 0.4비율로 임의의 입력 뉴런을 제외시킨다.

    그리고 Flatten() 함수를 사용해서 2차원의 특성 맵을 전 결합층으로 전달하기 위해서 1차원 형식으로 바꿔주는 작업을 진행해야한다. 이후 Dense()층은 활성화 함수와 이전 계층이 완전히 연결된 계층으로 softmax 활성화 함수를 적용하여 완전연결 층으로 클래스 확률 추정 값을 출력하도록 한다.

     

    신경망을 다 구성하면 해당 모델을 compile한다. 또한 EarlyStopping 콜백을 활용해서 patience 만큼의 epoch동안 모델의 성능이 개선되지 않을 경우 조기종료를 실행하도록 하며, ModelCheckpoint로부터 best model을 다시 로드해서 학습을 재개할 수 있게 한다.

    model.compile(loss=keras.losses.binary_crossentropy,
                  optimizer=keras.optimizers.Adam(lr=1e-4),
                  metrics=['accuracy'])
                  
    callbacks = [EarlyStopping(monitor='val_loss', patience=3),
                 ModelCheckpoint(filepath='model.h5', monitor='val_acc', save_best_only=True)]
    

     

    아래는 모델 구조를 보여주는 코드이다.

    model.summary()

    위와 같은 구조로 모델이 구성되었음 확인하였다.

     

    이제 model.fit() 함수를 사용해서 모델을 학습시켜보자.

    입력 데이터 X_train, y_train을 넣고, batch_size=32로 설정한다. 따라서 한 번 학습할 때 총 32개의 데이터가 사용된다. epochs는 100으로 설정하여 학습 데이터 전체셋을 100번 학습하도록 하였다. 단, epoch를 많이 했을 경우 overfitting이 일어날 수 있음을 고려해야한다. 그리고 validation_data를 X_test, y_test로 설정해서 모델 학습을 시킨다.

    (X_train, y_train, X_test, y_test는 이전 장롱 이미지 데이터 전처리 포스팅에서 train_test_split으로 나눈 데이터셋이다.)

    history = model.fit(X_train, y_train,
                          batch_size=32,
                          epochs=100, 
                          callbacks=callbacks,
                          verbose=0,
                          validation_data=(X_test, y_test))
                          
    plot_history(history)

     

    아래 그림은 모델학습시킨 결과이다.

    가장 좋은 모델은 68 epoch에서 나왔으며 validation accuracy는 99.7%, training accuracy는 98.9%가 나왔다. 

    GPU를 활용하여 실행하였으며 실행시간은 211.165초가 걸렸다.

     

    아래는 이전에 테스트 데이터로 분류한 70장의 데이터 셋으로 이 모델을 평가해보았다.

    predicted_classes = model.predict_classes(scaled_X_test)
    
    y_true = np.concatenate((np.zeros((70,)), np.ones((70,))))
    
    from sklearn.metrics import classification_report
    print(classification_report(y_true, predicted_classes, target_names=['wardrobe', 'not wardrobe']))

    테스트 데이터 셋으로 모델을 평가한 결과, 정확도는 87%로 나왔다.

     

    아무래도 훈련 데이터 셋이 각각 255장의 이미지가 전부이므로 정확도를 높이기에는 데이터가 많이 부족하였다. 좀 더 데이터를 확보한 다음 한번 더 모델 학습을 시켜볼 예정이다.

    댓글