ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Tensorflow Keras - 2 (CNN,이미지 학습,mnist,cifar10)
    Machine Learning/Tensorflow 2021. 3. 15. 17:15
    반응형

     

    Keras를 이용해서 이미지 data를 학습하고 검증하는 방법을 소개합니다.

     

    Mnist Data set

    %matplotlib inline
    import matplotlib.pyplot as plt
    from tensorflow import keras
    from tensorflow.keras.datasets import mnist
    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import Dense, Dropout, Flatten
    from tensorflow.keras.layers import Conv2D, MaxPooling2D

    keras에서 제공하는 데이터셋을 이용할 예정이고,

    이전글에서 학습했던 Sequential을 이용해서 layer들을 차례대로 쌓아 올릴 예정입니다.

     

    사용되는 레이어는 Dense(회귀),Dropout(확률적으로 레이어를 사용안함), Flatten(1차원배열로 변경)

    Conv2D(2D convolution layer) 이미지용 컨볼루션레이어, MaxPooling2D(2차원용 maxpooling layer)

     

    hyper parameters 설정

    batch_size = 32
    num_classes = 10
    epochs = 10
    img_rows, img_cols = 28, 28
    (x_train, y_train), (x_test, y_test) = mnist.load_data()

    batch_size = 학습될 데이터의 양

    num_classes = 예측될 데이터의 갯수 (mnist는 0~9까지 있습니다.)

    img_rows, img_cols = 이미지의 높이와 가로 길이 입니다.

     

    Mnist 시각화

    first_image = x_train[0,:,:]
    plt.imshow(first_image, cmap = plt.cm.Greys)

    Data preprocessing

    x_train = x_train.astype('float32')   # 타입 변경 ( 255로 나누기 위해서 )
    x_test = x_test.astype('float32')
    x_train /= 255
    x_test /= 255
    print('x_train shape', x_train.shape)
    print(x_train.shape[0] , ' train sample')
    print(x_test.shape[0], ' test sample')
    y_train = keras.utils.to_categorical(y_train, num_classes)
    y_test = keras.utils.to_categorical(y_test, num_classes)

    데이터타입을 먼저 float형으로 변환해줍니다.

    float32는 32bit 입니다.

     

    그 뒤로 255로 나누어줍니다.

    이유는 이미지를 표현하기 위해서는 0~255까지의 숫자로 표현되는데,

    최대값인 255로 나누어서 0~1사이로 줄여주는 역할을 합니다.

     

    y값들은 keras에서 제공하는 to_categorical 함수를 이용해서 원핫인코딩을 해줍니다.

     

    Model create

    model = Sequential()
    
    
    # 32 : filter 수  
    # 3x3 filter
    # 입력데이터 : 128x 28x 28x 1 => (128 x 26 x 26 x 32)
    # padding : valid(default)
    model.add(Conv2D(32, 3, 3 , activation='relu', input_shape=(28,28,1)))   # activation : relu : 음수 제거 
    # 아웃풋 :  32 x 24 x 24 x 64
    model.add(Conv2D(64,3,3, activation = 'relu'))
    # 32 x 12 x 12 x 64
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))
    # 12 x 12 x 64 가 1차원으로 됨( 9216 )
    model.add(Flatten())
    
    # FFNN망 (=FC망)
    # input : 128 x 9216
    # 가중치 : 9216 x 128
    # output : 128 x 128
    model.add(Dense(128, activation='relu'))
    
    model.add(Dropout(0.5))  # 계산회로만 생략
    
    # input : 128 x 128
    # 가중치 : 128 x 10
    # output : 128 x 10
    model.add(Dense(10, activation='softmax'))

    model이란 변수에 Sequential을 인스턴스 해준 뒤

    차곡차곡 레이어를 쌓아올립니다.

     

    Conv2D에 들어가는 파라미터는 필터의 수 32개, 커널사이즈, stride입니다.

    필터의 수는 conv망을 지나서 채널의 수를 증가하거나 줄여주는 역할을 하고,

    커널사이즈는 데이터를 압축하는 크기입니다.

    예를들어서 28*28이 3*3 커널사이즈를 통과하면 26*26이 됩니다.

    식은 (28-3)+1 입니다. 그래서 26*26이 됩니다.

    stride는 커널이 건너뛰는 칸수입니다.

    1로 설정하면 데이터의 손실이 없고, 커질수록 데이터의 손실이 증가합니다.

     

    여기선 빠른학습을 위해서 stride를 3으로 주었습니다.

     

    Model fit

    model.compile(loss=keras.losses.categorical_crossentropy,
                 optimizer = keras.optimizers.Adadelta(),
                 metrics = ['accuracy'])
    
    # train,validation //// test
    class AccuracyHistory(keras.callbacks.Callback):
        # 오버라이딩 ( 재정의 )
        def on_train_begin(self, logs={}):  # 훈련 시작 시 이벤트 발생
            self.acc =[]
        def on_epoch_end(self, batch, logs={}):
            self.acc.append(logs.get('acc'))
    history = AccuracyHistory()
    
    
    history = model.fit(x_train, y_train,
              batch_size = batch_size, epochs = epochs, verbose =1,
              validation_data = (x_test, y_test),
              callbacks = [history])
    score = model.evaluate(x_test, y_test, verbose=0)
    score[0] # loss값
    score[1] # accuracy 값
    

    compile 메소드를 이용해서 loss와 optimizer, metrics를 정해줍니다.

    loss는 손실함수입니다. 어떠한 방법으로 데이터를 검증할건지를 설명해줍니다.

    optimizer는 backpropagation을 진행할때, 어떠한 방식으로 최적화를 할지를 결정합니다.

    metrics는 분류문제이기 때문에 accuracy입니다. 회귀문제에서는 mse나 mae등을 사용합니다.

     

    AccuracyHistory라는 클래스를 keras의 callback을 상속받아서 생성합니다.

    이유는 accuracy를 담기 위해서 입니다.

    사실 사용을 안해도 무방하지만 예를들기위해서 작성했습니다.

     

    데이터 시각화

    import numpy as np
    
    y_vloss = history.history['val_loss']
    y_loss = history.history['loss']
    
    x_len = np.arange(len(y_loss))
    
    plt.plot(x_len, y_vloss, marker='.', c='red', label='val_set_loss')
    plt.plot(x_len, y_loss, marker='.', c='blue', label='train_set_loss')
    plt.legend()
    plt.xlabel('epochs')
    plt.ylabel('loss')
    plt.grid()
    plt.show()

    y_vloss = history.history['val_accuracy']
    y_loss = history.history['accuracy']
    
    x_len = np.arange(len(y_loss))
    
    plt.plot(x_len, y_vloss, marker='.', c='red', label='val_set_accuracy')
    plt.plot(x_len, y_loss, marker='.', c='blue', label='train_set_accuracy')
    plt.legend()
    plt.xlabel('epochs')
    plt.ylabel('loss')
    plt.grid()
    plt.show()

    Model Save

    # HDFS( hadoop file system ) : model 구조 전체 저장
    # 가중치, 구조, optimization statge 등이 저장
    # json으로 저장 가능
    #  - 구조와 가중치 별로도 저장 # web에서 tensorflow 사용 가능
    model.save("model_mnist.h5")
    print("모델이 저장되었습니다. ")
    
    from tensorflow.keras.models import load_model
    
    model = load_model('model_mnist.h5')
    print("모델이 로딩되었습니다.")
    
    model.summary()

    모델이 저장되었습니다. 
    모델이 로딩되었습니다.
    Model: "sequential"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    conv2d (Conv2D)              (None, 9, 9, 32)          320       
    _________________________________________________________________
    conv2d_1 (Conv2D)            (None, 3, 3, 64)          18496     
    _________________________________________________________________
    max_pooling2d (MaxPooling2D) (None, 1, 1, 64)          0         
    _________________________________________________________________
    dropout (Dropout)            (None, 1, 1, 64)          0         
    _________________________________________________________________
    flatten (Flatten)            (None, 64)                0         
    _________________________________________________________________
    dense (Dense)                (None, 128)               8320      
    _________________________________________________________________
    dropout_1 (Dropout)          (None, 128)               0         
    _________________________________________________________________
    dense_1 (Dense)              (None, 10)                1290      
    =================================================================
    Total params: 28,426
    Trainable params: 28,426
    Non-trainable params: 0
    _________________________________________________________________

     



    Cifar10 Data set

     

    Data load

    # airplane, automobile, bird ,cat , deer, dog,
    # frod, horse, ship, truck 10개로 분류
    from tensorflow.keras.datasets import cifar10
    from tensorflow.keras.optimizers import SGD, Adam, RMSprop
    from tensorflow.keras.utils import to_categorical
    
    (X_train, y_train) , (X_test, y_test) = cifar10.load_data()
    print("X_train shape : ", X_train.shape)
    print(X_train.shape[0], 'Train samples')
    print(X_test.shape[0], 'Test samples')
    nb_classes = 10
    y_train = to_categorical(y_train, nb_classes)
    y_test = to_categorical(y_test, nb_classes)
    
    X_train = X_train.astype('float32')
    X_test = X_test.astype('float32')
    X_train /= 255
    X_test /= 255
    
    plt.imshow(X_train[5])
    plt.grid(False)
    plt.show()
    plt.imshow(X_train[6])
    plt.grid(False)
    plt.show()

    Mnist와 동일하게 적용했기 때문에 설명은 안하겠습니다.

     

    X_train shape : (50000, 32, 32, 3) 50000 Train samples 10000 Test samples

    Hyper parameters

    IMG_CHANNELS = 3
    IMG_ROWS = 32
    IMG_COLS = 32
    batch_size = 128
    nb_epoch = 40 # 40
    nb_classes = 10
    verbose = 1
    validation_split = 0.2
    optimizer = RMSprop()

     

    Model Create

    model = Sequential()
    # residual 망의 영향 ( 연속2번 망을 구성- pooling)
    # 입력 : 32 x 32 x 3 => 32 x 32 x 32
    model.add(Conv2D(32, kernel_size=3, padding='same',
                    input_shape = (IMG_ROWS, IMG_COLS, IMG_CHANNELS),
                    activation='relu'))
    model.add(Conv2D(32 , kernel_size=3, padding='same',activation='relu'))
    
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))
    
    model.add(Conv2D(64, kernel_size=3, padding='same', activation='relu'))
    model.add(Conv2D(64,3,3,activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))
    
    model.add(Flatten())
    model.add(Dense(512,activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(nb_classes,activation='softmax'))
    
    model.summary()
    model.compile(loss='categorical_crossentropy', optimizer=optimizer,
                 metrics = ['accuracy'])

    Model: "sequential_5"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    conv2d_10 (Conv2D)           (None, 32, 32, 32)        896       
    _________________________________________________________________
    conv2d_11 (Conv2D)           (None, 32, 32, 32)        9248      
    _________________________________________________________________
    max_pooling2d_4 (MaxPooling2 (None, 16, 16, 32)        0         
    _________________________________________________________________
    dropout_6 (Dropout)          (None, 16, 16, 32)        0         
    _________________________________________________________________
    conv2d_12 (Conv2D)           (None, 16, 16, 64)        18496     
    _________________________________________________________________
    conv2d_13 (Conv2D)           (None, 5, 5, 64)          36928     
    _________________________________________________________________
    max_pooling2d_5 (MaxPooling2 (None, 2, 2, 64)          0         
    _________________________________________________________________
    dropout_7 (Dropout)          (None, 2, 2, 64)          0         
    _________________________________________________________________
    flatten_2 (Flatten)          (None, 256)               0         
    _________________________________________________________________
    dense_5 (Dense)              (None, 512)               131584    
    _________________________________________________________________
    dropout_8 (Dropout)          (None, 512)               0         
    _________________________________________________________________
    dense_6 (Dense)              (None, 10)                5130      
    =================================================================
    Total params: 202,282
    Trainable params: 202,282
    Non-trainable params: 0
    _________________________________________________________________

     

     

    Mnist와 다르게 모델 레이어를 조금 깊게 쌓았습니다.

     

    조금 다른점이 있다면 mnist는 채널이 1개여서,

    흑백이였다면 cifar10은 채널의 수가 3개라서 RGB가 들어간 색상이 있습니다.

     

    그리고 stride가 1로 defalt 값으로 정해져 있기 때문에 데이터의 크기가 손실이 안납니다.

     

     

    Model fit

    history = model.fit(X_train,y_train, batch_size = batch_size,
                       epochs = epochs, validation_split = validation_split,
                       verbose = verbose)

    Epoch 1/12
    313/313 [==============================] - 49s 158ms/step - loss: 1.9862 - accuracy: 0.2638 - val_loss: 1.6807 - val_accuracy: 0.3753
    Epoch 2/12
    313/313 [==============================] - 64s 206ms/step - loss: 1.6658 - accuracy: 0.3850 - val_loss: 1.5275 - val_accuracy: 0.4363
    Epoch 3/12
    313/313 [==============================] - 54s 172ms/step - loss: 1.4990 - accuracy: 0.4536 - val_loss: 1.4079 - val_accuracy: 0.4887
    Epoch 4/12
    313/313 [==============================] - 49s 157ms/step - loss: 1.3917 - accuracy: 0.4935 - val_loss: 1.2828 - val_accuracy: 0.5302
    Epoch 5/12
    313/313 [==============================] - 49s 156ms/step - loss: 1.3137 - accuracy: 0.5297 - val_loss: 1.1935 - val_accuracy: 0.5735
    Epoch 6/12
    313/313 [==============================] - 49s 155ms/step - loss: 1.2495 - accuracy: 0.5545 - val_loss: 1.2331 - val_accuracy: 0.5579
    Epoch 7/12
    313/313 [==============================] - 48s 154ms/step - loss: 1.1978 - accuracy: 0.5738 - val_loss: 1.0820 - val_accuracy: 0.6185
    Epoch 8/12
    313/313 [==============================] - 58s 186ms/step - loss: 1.1449 - accuracy: 0.5950 - val_loss: 1.0895 - val_accuracy: 0.6110
    Epoch 9/12
    313/313 [==============================] - 54s 173ms/step - loss: 1.1189 - accuracy: 0.6029 - val_loss: 1.0658 - val_accuracy: 0.6217
    Epoch 10/12
    313/313 [==============================] - 51s 163ms/step - loss: 1.0718 - accuracy: 0.6205 - val_loss: 1.0399 - val_accuracy: 0.6360
    Epoch 11/12
    313/313 [==============================] - 64s 204ms/step - loss: 1.0557 - accuracy: 0.6279 - val_loss: 1.0533 - val_accuracy: 0.6323
    Epoch 12/12
    313/313 [==============================] - 55s 176ms/step - loss: 1.0319 - accuracy: 0.6365 - val_loss: 1.0620 - val_accuracy: 0.6225

     


    ImageDataGenerator를 이용해서 학습하기

    from tensorflow.keras.preprocessing.image import ImageDataGenerator
    
    datagem = ImageDataGenerator(
        featurewise_center= False,
        samplewise_center = False,
        featurewise_std_normalization = False,
        samplewise_std_normalization = False,
        zca_whitening = False,
        rotation_range=0,
        width_shift_range=0.1,
        height_shift_range=0.1,
        horizontal_flip = True,
        vertical_flip = False)
    datagem.fit(X_train)

    이미지를 생성할수도, 줄일수도, 여러방면으로 변형할수도 있는 함수입니다.

    파라미터의 설명은 이쪽 블로그를 참고해주시면 감사합니다.

    keraskorea.github.io/posts/2018-10-24-little_data_powerful_model/

     

    작은 데이터셋으로 강력한 이미지 분류 모델 설계하기

    Building powerful image classification models using very little data

    keraskorea.github.io

     

    model.fit_generator(datagem.flow(X_train, y_train, batch_size=batch_size),
                       epochs = nb_epoch,
                       verbose = verbose)
    score = model.evaluate(X_test, y_test,
                          batch_size = batch_size, verbose= verbose)
    print("\nTest score : ", score[0])
    print("\nTest accuracy : ", score[1])

    79/79 [==============================] - 2s 31ms/step - loss: 1.3152 - accuracy: 0.5243

    Test score :  1.3151625394821167

    Test accuracy :  0.5242999792098999

     

    Model save

    #json으로 저장
    model_json = model.to_json()
    open('cifar10_architecture.json', 'w').write(model_json)
    model.save_weights('cifar10_weights.h5', overwrite = True)

    Model load

    # json으로 load
    from tensorflow.keras.models import model_from_json
    json_file = open('cifar10_architecture.json','r')
    loaded_model_json = json_file.read()
    json_file.close()
    loaded_model = model_from_json(loaded_model_json)
    loaded_model.load_weights('cifar10_weights.h5')
    print("Loaded model from disk")
    loaded_model.compile(loss="categorical_crossentropy", optimizer="RMSprop", metrics=['accuracy'])
    score = loaded_model.evaluate(X_test, y_test, verbose = 1)

    Model을 다시 재로드를 한뒤에는 compile을 하고나서 평가를 해야합니다.

    물론 모델이 학습된 방법과 동일하게 적용을 해야합니다.

     

    시각화

    # 1. accuracy graph를 출력
    # 2. 이미지 cat, dog를 다운로드한 다음 위의 모델로 예측
    
    plt.plot(history.history['accuracy'])
    plt.plot(history.history['val_accuracy'])
    plt.title('model accuracy')
    plt.legend(['train', 'test'], loc = 'upper left')
    plt.show()

    반응형
Designed by Tistory.