인공지능

tensor flow hub -> finetune 사용하기

쿠와와 2020. 12. 20. 16:39
# Day_34_01_tfhub_finetune.py
import tensorflow as tf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import PIL.Image as Image
import tensorflow_hub as hub
from tensorflow.keras.preprocessing.image import ImageDataGenerator


# Fine-tuning 이란
# 남이 만들어 놓은 모듈을 내가 조금만 다듬어서 사용하겠다
# trainable=True to hub.KerasLayer이걸 써서

# resnet_50 모델을 사용해서 꽃 데이터셋에 대해 학습하고 랜덤으로 뽑은 32장의 이미지에 대해 예측한 결과를 출력하세요

# Day_33_02 가져와서 파인튜닝하는 코드로 수정 후에 정확도 계산
def get_image_classifier_with_fine_tune():
    # cnn -> 좋은 피처를 추출하는 것임 그래서 classification 지나치다.
    # tf.keras.applications.VGG16(include_top=True)
    # url = 'https://tfhub.dev/tensorflow/resnet_50/classification/1'

    # tf.keras.applications.VGG16(include_top=False)  # 아래께 더 좋음
    url = 'https://tfhub.dev/tensorflow/resnet_50/feature_vector/1'

    model = tf.keras.Sequential()
    model.add(tf.keras.layers.Input(shape=[224, 224, 3]))
    # 기존의 성능이 안 좋으면 -> fine_tuning 을 쓰는 것이 맞음.
    # 자체적으로 soft_max가 있음
    # 이거 학습하는 것이 너무 오래 걸려서 False 쓸 것임
    model.add(hub.KerasLayer(url, trainable=False))      # 여기서 trainable 쓰는 거임 기본 값 False

    # 앞쪽에서는 학습하지 않음 -> 공통된 feature 만 추출함
    # 밑에 쪽에서는 나만의 레이어 학습하는것
    model.add(tf.keras.layers.Dense(1024, activation='relu'))
    model.add(tf.keras.layers.Dense(5, activation='softmax'))         # 1001개의 데이터를 반환하는데 우리는 5개만있음 그래서 써줌
    # softmax가 여러번 반복되는 안좋음 -> graident vanishing 그리디언트 소실 -> 미분해야하는데 값이 너무 작아짐
    # 하지만 어쩔 수 없음
    model.summary()

    return model


def classify_image_by_generator():
    img_url = 'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz'
    img_path = tf.keras.utils.get_file('flower_photos', img_url, untar=True)    # 압축 풀기 까지
    # print(img_path)         # C:\Users\82103\.keras\datasets\flower_photos

    # 이미지 증강은 의미가 없음 그냥 데이터 32개를 예측만 할거임
    data_gen = ImageDataGenerator(rescale=1 / 255)

    batch_size = 32
    # 3가지 방법 -> (x,y), pandas, 폴더에 있는것
    # 우리 폴더 안에 있는 25000개의 데이터를 무제한으로 가져옴 -> 조심해야함
    data_flow = data_gen.flow_from_directory(
        img_path,
        batch_size=batch_size,
        target_size=(224, 224),  # resize 기능을 제공해줌
        class_mode='sparse',  # "categorical", "binary", "sparse",
    )
    # 써먹을대가 많음
    # print(data_flow.batch_size, data_flow.samples)      # 32 3670
    # print(data_flow.classes)                    # [0 0 0 ... 4 4 4]     3670개에 대해서
    # print(data_flow.class_indices)      # class의 indices 가 들어있음
    # {'daisy': 0, 'dandelion': 1, 'roses': 2, 'sunflowers': 3, 'tulips': 4}
    #   key   : value

    # ['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips'] 정렬 한번 하자.
    labels = sorted([k for k in data_flow.class_indices])
    # print(labels)

    model = get_image_classifier_with_fine_tune()

    # compile을 통해 모델의 부족한 부분을 채워줘야함
    model.compile(optimizer=tf.keras.optimizers.Adam(),
                  loss=tf.keras.losses.sparse_categorical_crossentropy,
                  metrics=['acc'])

    # generator 안써도 잘 돌아감 deprecated 되었기 때문에
    steps_per_epoch = data_flow.samples // data_flow.batch_size
    model.fit(data_flow, epochs=2, steps_per_epoch=steps_per_epoch)

    # 이미지, label
    xx, yy = data_flow.next()       # 1번째 데이터 갯수는 32개
    preds = model.predict(xx)

    preds_arg = np.argmax(preds, axis=1)

    for i, (img, label, pred) in enumerate(zip(xx, yy, preds_arg)):
        # print(i, img.shape, pred)
        plt.subplot(4, 8, i+1)
        plt.title(labels[pred], color='g' if pred == label else 'r')      # 맞은 건 g 틀린건 r
        plt.axis('off')
        plt.imshow(img)     # -> 대부분 꽃 그림이 나옴 데이지를 학습했으니깐

    plt.show()


classify_image_by_generator()