Skip to content

기계학습 케라스 이미지 분석 #
Find similar titles

Structured data

Category
Programming

TensorFlow Tutorial #

텐서플로우(TensorFlow)를 설치한 후 기계학습과 텐서플로우의 기본적인 내용을 연습하는 목적으로 진행하는 튜토리얼이다. 이번 튜토리얼에서는 대량의 이미지를 종류별로 분석하는 방법을 소개하며, 참고로 사용하는 이미지는 아래와 같은 이미지들이다.

img

(출처 : solarisailab.com)

Minist #

이전에 손글씨를 분석 및 훈련하는 MNIST 튜토리얼이 있다. 본 튜토리얼을 진행하기 전에 MNIST 튜토리얼을 진행하면 기본적인 원리를 이해할 수 있다.

Import Datasets #

우선 설치된 케라스에서 이미지 데이터(datasets)와 필요한 라이브러리(numpy, np_util)를 불러온 후, datasets를 train과 test 변수에 나누어 담는다.

    import numpy as np
    from keras import datasets
    from keras.utils import np_utils

    (train_X, train_Y), (test_X, test_Y) = datasets.cifar10.load_data()

그리고 어떤 파일로 구성되어 있는지 확인해본다.

    print("type: {}, len: {}, ".format(type(train_X), len(train_X)) )
    print("type: {}, len: {}, ".format(type(test_X), len(test_X)) )
  • train_X, Y : 5만 개의 ndarray(숫자 배열)
  • test_X, Y : 1만 개의 ndarray(숫자 배열)
  • train은 훈련용, test는 훈련한 모델을 테스트 목적으로 사용

Pring Images #

어떤 데이터 형태인지 확인 했으니 데이터가 어떤 이미지인지 확인해본다. 그림을 그리기 위해 Matplotlib를 볼러온다.

    import matplotlib.pyplot as plt

그리고 이미지 몇 개를 출력해본다.

    fig = plt.figure()
    plt.subplots_adjust(left=0.1, right=2, top=1.3, bottom=0.1)
    for i in range(9):
    i += 1
    num = '25' + str(i)
    num = int(num)
    ax = fig.add_subplot(num)
    plt.title("train_X[{}] / train_Y[{}]: {}".format(i, i, train_Y[i]) )
    plt.imshow(train_X[i])

    plt.show()

이미지 출력 결과 다양한 종류의 이미지가 있음을 알 수 있다.

img

Data Check #

train 데이터에 있는 이미지가 세부적으로 어떤 구조로 되어 있는지 확인한다.

    print(train_X.shape) 
    print(train_Y.shape)
  • 출력결과 : (50000, 32, 32, 3) / (50000, 1)
  • train_X: 5만 개의 32x32x3의 3차원 배열 / train_Y: 5만 개의 1차원 배열
  • 50000, 32, 32, 3 : 32(가로) x 32(세로) x 3(RGB색상)으로 구성된 이미지가 5만 개가 있다는 의미

train_Y는 1차원 숫자 배열로 이루어져 있는데 이미지 종류의 번호를 의미하며 어떤 수들이 있는지 출력해서 확인해본다.

    import numpy as np
    np.unique(train_Y)
  • unique : 중복값을 생략한 값을 출력
  • 출력결과 : array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8)
  • 0부터 9까지의 숫자로 이루어져 있으며 각 숫자는 특정 종류를 의미

Define Function #

이미지를 기계학습으로 훈련할 수 있도록 데이터를 변환하는 작업을 진행하기 위해 케라스에서 인식할 수 있는 데이터 양식으로 맞추어야 한다. 데이터 전처리를 위해 해당 함수를 만든다.

    # 함수형으로 만들어 재사용이 가능하도록 제작
    def prepare_classification_data(train_data, test_data):
        train_X, train_Y = train_data
        test_X, test_Y = test_data

        #One-hot Encoding
        train_Y = np_utils.to_categorical(train_Y)   
        test_Y = np_utils.to_categorical(test_Y)

        # Reshaping Input Data
        m, W, H, C = train_X.shape
        train_X = train_X.reshape(-1, W*H*C)
        test_X = test_X.reshape(-1, W*H*C)

        #Normalization
        from sklearn.preprocessing import StandardScaler
        scaler = StandardScaler().fit(test_X)
        train_X = scaler.transform(train_X)
        test_X = scaler.transform(test_X)

        return (train_X, train_Y), (test_X, test_Y)
  • One-hot Encoding : 이미지 종류를 나타내는 번호에 해당하는 인덱스만 1로 만들고 나머지는 0으로 만듦
  • to_categorical : One-hot-encoding으로 만들어주는 함수
  • Reshaping Input Data : 3차원 데이터를 1차원으로 변환
  • reshape : 데이터의 차원을 변환, 여기서는 3차원을 1차원으로 변환
  • reshape 이전에는 32x32x3의 3차원이었지만 이후에는 3072의 1차원 배열
  • Normalization : 데이터 정규화 작업
  • StandardScaler : 데이터를 0부터 1 사이의 값으로 매칭
  • transform : 정규화된 데이터를 변환, 변환된 값을 출력해보면 최소값은 -1.7 최대값은 2.4 정도가 나옴

만든 메소드를 통해 이미지 데이터들을 정규화시켜준다.

    train_data, test_data = datasets.cifar10.load_data()
    (train_X, train_Y), (test_X, test_Y) = \
    prepare_classification_data(train_data, test_data)
  • prepare_classification_data(train_data, test_data) : 위에 만든 함수에 train_data, test_data를 입력하여 정규화된 데이터를 출력

정규화 된 데이터를 출력해서 확인한다.

    train_X[0], train_Y[0]
  • 출력결과 : array([-0.97553309, -1.01870231, -0.87145718, ..., -0.05492909, -0.5482677 , -0.6598775 ]), array([0., 0., 0., 0., 0., 0., 1., 0., 0., 0.]))
  • 앞의 배열은 train_X, 뒤의 배열은 train_Y이며 각각 1차원 배열로 변환된 것을 확인 가능

Neural Class #

이제 변환한 데이터를 훈련시킬 신경망 모델을 만들 준비를 한다. 우선 필요한 라이브러리를 불러온다.

    from keras.models import Sequential
    from keras.layers import Dense

그리고 DNN이라는 이름의 훈련 클래스를 만든다.

    class DNN(Sequential):

        def __init__(self, input_size, output_size, *num_hidden_nodes):
            super().__init__()
            num_nodes = (*num_hidden_nodes, output_size)

            for idx, num_node in enumerate(num_nodes):
                activation = 'relu'
                if idx == 0:
                    self.add(Dense(num_node, 
                    activation=activation, 
                    input_shape=(input_size,)))
                else:
                    if idx == len(num_nodes) - 1:
                        activation = 'softmax'
                    self.add(Dense(output_size, activation=activation))

            self.compile(loss = 'categorical_crossentropy', 
                        optimizer = 'adam',
                        metrics = ['accuracy'])
  • init : init은 초기화를 의미하며 DNN 클래스 실행 시 해당 내용이 실행
  • num_nodes : 신경망의 노드(연결고리)를 명시
  • relu : Rectified Liner Unit 정류한 선형유닛, 0 이하의 값은 0으로 처리, 미분 계산이 간단
  • softmax : 뉴런의 활성함수로 주로 사용. 학습 결과에서 상과 벌의 개념이 확실
  • adam : Adagrad와 RMSProp의 장점을 합침, 안정적으로 최적화 가능

Training #

위의 신경망 모델을 통해 정규화된 이미지 데이터들을 훈련시킨다.

mode = DNN(train_X.shape[1], train_Y.shape[1], 256)
hitory = model2.fit(train_X, train_Y, epochs=10, 
            batch_size=100, validation_split=0.2)
  • epochs=10 : 총 10번 훈련시킴
  • batch_size=100 : 한번 훈련 시 100개의 데이터를 사용
  • 출력 결과
  • Train on 40000 samples, validate on 10000 samples
  • Epoch 1/10
  • 40000/40000 [==============================] - 16s 404us/step - loss: 2.1015 - acc: 0.3792 - val_loss: 1.8382 - val_acc: 0.4132
  • ....
  • 최종적으로 정확도 0.6473가 나옴

Evaluate #

훈련 시킨 모델을 테스트 이미지를 가지로 평가해본다.

    model.evaluate(test_X, test_Y)
  • model : 위에서 훈련시킨 모델을 사용
  • evaluate : 테스트 데이터를 가지고 모델을 평가
  • 출력 결과 : 10000/10000 [==============================] - 2s 234us/step

Loss Datas #

훈련시킨 결과 중 잘못 예측한 이미지들을 확인하기 위해 분류한다.

    target_Y = np.argmax(test_Y, axis=1)
    match = predicted_Y == target_Y
    wrong_label = np.where(match==False)        
    plt.show(test_X[wrong_label[0]].reshape(32, 32, 3))
  • argmax : 원래 이미지 종류의 숫자를 1차원 배열로 생성
  • match : 원래 이미지 종류와 예측 이미지 종류가 맞는지 아닌지 결과를 저장
  • 출력 결과 : array([ True, True, False, False, False, True, True, True, True, True])
  • wrong_label : match 중에서 False(예측이 틀린 이미지)만 분류
  • reshape(32, 32, 3) : 1차원으로 정규화된 값을 원래의 32x32x3의 3차원으로 변환

Check Matching #

원래의 이미지 종류를 불러오기 위해 datasets을 새로 불러와 새로운 변수(test2_origin_Y)에 담는다.

    (train_X, train_Y), (test_origin_X, test2_origin_Y) = \
    datasets.cifar10.load_data()
  • test2_origin_Y : 원래의 이미지의 종류를 의미하는 숫자가 입력

훈련시킨 이미지를 종류에 따라 분류해준다.

    from collections import defaultdict

    def classify_by_label(target_Y, predicted_Y):
        n_classes = len(np.unique(target_Y)) 
        index_for_classes = [defaultdict(list) for _ in \
            range(n_classes)]
        for idx, (target_y, predicted_y) in \
            enumerate(zip(target_Y, predicted_Y)):
            if target_y == predicted_y:
                key = 'correct'
            else:
                key = 'wrong'
            index_for_classes[target_y][key].append(idx)

        return index_for_classes
  • n_classes : 이미지 종류의 유니크한 값들만 추출
  • defaultdict : 이미지 종류만큼의 데이터를 생성
  • target_Y, predicted_Y : 각각 실제 값과 예상 값을 의미
  • ket_count : corret는 예측이 맞은 것, wrong은 예측이 틀린 것을 의미

Result #

우선 예측이 맞은 이미지를 모아서 출력하기 위해 matplotlib를 불러와서 이미지를 그려준다.

    # 맞은 것들을 출력.
    fig = plt.figure()
    plt.subplots_adjust(left=0.1, right=2.2, top=1.5, bottom=0.1)
    i = 0
    for image_idx in index_for_classes[3]['correct'][:9]:
        i += 1
        num = int('25' + str(i))
        ax = fig.add_subplot(num)    
        plt.title("test_X[{}] / test_Y[{}]: {}"
            .format(image_idx, image_idx, test2_origin_Y[image_idx]))
        plt.imshow(test_X[image_idx].reshape(32,32,3).sum(axis=2))

    plt.show()
  • subplots_adjust : 각 그래프 간의 간격을 설정
  • index_for_classes[3]['correct'][:9] : 예측이 맞은 3번 종류의 이미지를 9개를 선택
  • plt.title : 이미지의 타이틀을 설정
  • plt.imshow : 이미지를 화면에 그림
  • plt.show(): 이미지 출력

img

출력된 이미지를 확인해보니 3번 종류는 고양이를 의미한다고 알 수 있다. 이번에는 반대로 틀린 이미지들(고양이 이미지지만 다른 종류로 예상한 이미지들)을 출력해 본다.

    # 틀린 것들을 출력.
    fig = plt.figure()
    plt.subplots_adjust(left=0.1, right=2.2, top=1.5, bottom=0.1)
    i = 0
    for image_idx in index_for_classes[3]['wrong'][:9]:
        i += 1
        num = int('25' + str(i))
        ax = fig.add_subplot(num)    
        plt.title("{} / predicted: {} / label: {}".format(
            image_idx, 
            predicted_Y[image_idx],
            test2_origin_Y[image_idx]
        ))
        plt.imshow(test_X[image_idx].reshape(32,32,3).sum(axis=2))

    plt.show()

img

이상으로 이미지 분석 튜토리얼을 마무리한다.

Suggested Pages #

0.0.1_20140628_0