ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Tensorflow Keras - 3 (전이학습,VGG16)
    Machine Learning/Tensorflow 2021. 3. 16. 13:20
    반응형

    전이 (transfer learning) 학습 Application
    - 반지도학습( 일부데이터의 레이블이 없음 ) - KNN, Trenductive SVM
    - 가중치 활용 : 그대로 적용
    - 가중치 중 일부만 활용
    - FFNN 부분만 학습해서 사용

     

    pre-trained , fine-tuning (FFNN 부분만 Domain Knowledge) => 가중치는 그대로

     

    banana.jpg
    0.02MB

     

     

    from tensorflow.keras.preprocessing.image import load_img
    from tensorflow.keras.preprocessing.image import img_to_array
    from tensorflow.keras.applications.imagenet_utils import decode_predictions
    from tensorflow.keras.applications import resnet50
    import matplotlib.pyplot as plt
    import numpy as np
    
    filename = 'banana.jpg'
    original = load_img(filename, target_size = (224,224))
    print("PIL image size : ", original.size)
    plt.imshow(original)
    plt.show()
    
    numpy_image = img_to_array(original)
    plt.imshow(np.uint8(numpy_image))
    print("numpy array size : ", numpy_image.shape)
    # expand_dim 차원확대 : 이미지 여러 장 처리가 전재조건 - banana.jpg 한장이므로 3차원을 4차원으로 확장하기 위함
    image_batch = np.expand_dims(numpy_image , axis = 0)
    print("image batch size : ", image_batch.shape)
    #prepare the image for the resnet50 model
    processed_image = resnet50.preprocess_input(image_batch.copy())
    # 기존 : dense를 이용해서 모델을 생성
    # 이미 만들어진 망을 사용할 수 있음
    resnet_model = resnet50.ResNet50(weights = 'imagenet')  # weight ( imagenet을 만들때 사용하던 데이터 중 바나나가 있음 )
    # predict : softmax로 확률값으로 나옴 
    predictions = resnet_model.predict(processed_image)
    label = decode_predictions(predictions, top=3)  # labelling
    print(label)

    PIL image size : (224, 224)

    numpy array size : (224, 224, 3) image batch size : (1, 224, 224, 3) [[('n07753592', 'banana', 0.9999647), ('n03532672', 'hook', 2.5261517e-05), ('n07716906', 'spaghetti_squash', 2.503885e-06)]]

     

    실제 keras에서 제공하는 resnet50을 이용하여, 데이터를 예측해보았습니다.

     

    적용하기 앞서서 이미지 데이터를 불러올때, 사이즈를 모델에 적용된 이미지 사이즈만큼을 적용해줘야 합니다.

    resnet은 224*224*3의 데이터셋으로 학습이 되었기 때문에 불러올때도 224*224로 변환해서 불러와 줍니다.

     

    np.expand_dims를 사용한 이유는 차원을 증가시켜주려고 사용했습니다.

    이 부분도 예측하기전 모델에 적용된 이미지와 맞춰준겁니다.

     

    기존의 가중치로 예측을 해보면 동일하게 바나나라고 예측을 한 모습입니다.



    제 데이터를 이용한 전이학습

    Data download

    import pathlib
    import matplotlib.pyplot as plt
    import tensorflow as tf
    
    dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
    data_dir = tf.keras.utils.get_file(origin=dataset_url, 
                                       fname='flower_photos', 
                                       untar=True)
    data_dir = pathlib.Path(data_dir)

    Data load는 tensorflow의 공식문서에서 가져왔습니다.

    ['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips'] 5개의 꽃의 데이터셋 입니다.

     

    Hyper parameters

    batch_size = 32
    img_height = 180
    img_width = 180
    epochs = 10

    Train Data load

    train_ds = tf.keras.preprocessing.image_dataset_from_directory(
        data_dir,
        validation_split=0.2,
        subset="training",
        seed=119,
        image_size=(img_height, img_width),
        batch_size=batch_size)

    Found 3670 files belonging to 5 classes.
    Using 2936 files for training.

    Validation Data load

    val_ds = tf.keras.preprocessing.image_dataset_from_directory(
        data_dir,
        validation_split=0.2,
        subset="validation",
        seed=123,
        image_size=(img_height, img_width),
        batch_size=batch_size)

    Found 3670 files belonging to 5 classes.
    Using 734 files for validation.

    class_names = train_ds.class_names
    print(class_names)

    ['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips']

     

    시각화

    import matplotlib.pyplot as plt
    
    plt.figure(figsize=(10, 10))
    for images, labels in train_ds.take(1):
        for i in range(9):
            ax = plt.subplot(3, 3, i + 1)
            plt.imshow(images[i].numpy().astype("uint8"))
            plt.title(class_names[labels[i]])
            plt.axis("off")

    for image_batch, labels_batch in train_ds:
        print(image_batch.shape)
        print(labels_batch.shape)
        break

    (32, 180, 180, 3)
    (32,)

     

    Model load

    img_shape = (img_height , img_width, 3)
    # include_top = False인 경우 input_shape = img_size 지정 필요
    # conv에 대한 가중치 학습이 없음
    VGG16_MODEL = tf.keras.applications.VGG16(input_shape = img_shape,
                                             include_top = False,
                                             weights = 'imagenet')

     

    58892288/58889256 [==============================] - 5s 0us/step

     

    keras에서 지원하는 모델인 VGG16 입니다.

    input_shape까지 지원해주니 참 편합니다.

     

    VGG16_MODEL.trainable=False
    # flatten이 없음 ( globalaveragepooling으로 대체 )
    #  ==> 가중치가 필요없음
    global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
    
    # FFNN의 가중치는 학습됨
    prediction_layer = tf.keras.layers.Dense(len(class_names),
                                             activation ='softmax' )
    
    model = tf.keras.Sequential([
        VGG16_MODEL,
        global_average_layer,
        prediction_layer
    ])
    # model : vgg16이 갖고있는 가중치 + FFNN 가중치로 학습

    trainable은 재학습을 할건지를 체크하는 겁니다.

    재학습을 해서 가중치에 변화를 주려면 True로 변경하면 됩니다.

     

    여기서 이제 Flatten을 이용하거나, GlobalAveragePooling2D를 이용하면 됩니다.

    대부분 후자를 선택합니다.

     

    마지막 Dense layer를 추가해서 예측을 해봅시다.

     

    Model fit

    #sparse : 희소 
    # 분류가 아주 많을 때 사용( ex)마트에서 물품 1개 )
    model.compile(optimizer = 'adam',
                 loss = 'sparse_categorical_crossentropy',
                 metrics=['accuracy'])
    history = model.fit(train_ds, epochs=epochs,
                       validation_steps=2,validation_data=(val_ds))

    Epoch 1/30
    92/92 [==============================] - 196s 2s/step - loss: 2.0738 - accuracy: 0.6253 - val_loss: 2.4032 - val_accuracy: 0.7188
    Epoch 2/30
    92/92 [==============================] - 186s 2s/step - loss: 1.1226 - accuracy: 0.7602 - val_loss: 2.1769 - val_accuracy: 0.7500
    Epoch 3/30
    92/92 [==============================] - 205s 2s/step - loss: 0.8133 - accuracy: 0.8018 - val_loss: 0.9480 - val_accuracy: 0.8438
    Epoch 4/30
    92/92 [==============================] - 197s 2s/step - loss: 0.6361 - accuracy: 0.8249 - val_loss: 1.1187 - val_accuracy: 0.7188
    Epoch 5/30
    92/92 [==============================] - 199s 2s/step - loss: 0.5185 - accuracy: 0.8443 - val_loss: 1.3732 - val_accuracy: 0.7812
    Epoch 6/30
    92/92 [==============================] - 198s 2s/step - loss: 0.4368 - accuracy: 0.8593 - val_loss: 1.4068 - val_accuracy: 0.7188
    Epoch 7/30
    92/92 [==============================] - 199s 2s/step - loss: 0.3710 - accuracy: 0.8757 - val_loss: 0.4763 - val_accuracy: 0.8906
    Epoch 8/30
    92/92 [==============================] - 208s 2s/step - loss: 0.3121 - accuracy: 0.8948 - val_loss: 0.8019 - val_accuracy: 0.7812
    Epoch 9/30
    92/92 [==============================] - 207s 2s/step - loss: 0.2820 - accuracy: 0.9012 - val_loss: 1.1796 - val_accuracy: 0.7812
    Epoch 10/30
    67/92 [====================>.........] - ETA: 54s - loss: 0.2563 - accuracy: 0.9118

     

    plt.plot(history.history['accuracy'])
    plt.plot(history.history['val_accuracy'])
    plt.title('model accuracy')
    plt.ylabel('accuracy')
    plt.xlabel('epoch')
    plt.legend(['train','test'], loc = 'upper left')
    plt.show()

    이미지 테스트

    rose_test.jpg
    0.08MB

     

     

    from tensorflow.keras.preprocessing.image import load_img
    from tensorflow.keras.preprocessing.image import img_to_array
    import matplotlib.pyplot as plt
    import numpy as np
    
    img_height = 180
    img_width = 180
    
    label_names = {0 : 'daisy', 1 : 'dandelion',2 :'roses',
                  3:'sunflowers', 4:'tulips'}
    
    filename = 'rose_test.jpg'
    original = load_img(filename, target_size = (img_height,img_width))
    
    numpy_image = img_to_array(original)
    plt.imshow(np.uint8(numpy_image))
    plt.show()
    print("numpy array size : ", numpy_image.shape)
    image_batch = np.expand_dims(numpy_image , axis = 0)
    
    predict = np.argmax(model.predict(image_batch))
    
    print('결과 : ',label_names[predict])

    numpy array size : (180, 180, 3)

    결과 : roses

     

    model의 predict 메소드를 호출하면

    array([[4.7634941e-08, 1.0259466e-15, 1.0000000e+00, 4.8731632e-09, 2.2048249e-10]], dtype=float32)

    이런식으로 결과값을 반환합니다.

    5개인 이유는 우리가 예측할 클래스의 갯수를 5개로 정했기 때문입니다.

     

    np.argmax를 이용해서 가장 높은 값의 인덱스를 반환받고,

    이거를 이용해서, dictionary를 하나 만들어서 간단하게 예측을 해보았습니다.

     

    감사합니다.

    반응형
Designed by Tistory.