kwan's note

캐글 -petal to medtal (pre trained model) 본문

project/others

캐글 -petal to medtal (pre trained model)

kwan's note 2021. 3. 7. 23:57
반응형

www.kaggle.com/c/tpu-getting-started

 

Petals to the Metal - Flower Classification on TPU

Getting Started with TPUs on Kaggle!

www.kaggle.com

pedal to medal 을 오마주한 꽃 classification 이다.

104종류의 꽃을 classify하는 기본적인 image classification 문제인데 정말 간단한 방법으로 적당한 수준의 classification을 진행했다. 최고의 점수를 받기 위한 방법도 아니고 input도 전체중 일부만 사용하였다.

input data도 다 사용하지 않고 상위30%의 점수를 받았으니 가성비는 좋다고 생각한다.

 

 

def decode_image(image_data):
    image = tf.image.decode_jpeg(image_data, channels=3)
    image = tf.cast(image, tf.float32) / 255.0  # convert image to floats in [0, 1] range
    image = tf.reshape(image, [*IMAGE_SIZE, 3]) # explicit size needed for TPU
    return image



def read_labeled_tfrecord(example):
    LABELED_TFREC_FORMAT = {
        "image": tf.io.FixedLenFeature([], tf.string), # tf.string means bytestring
        "class": tf.io.FixedLenFeature([], tf.int64),  # shape [] means single element
    }
    example = tf.io.parse_single_example(example, LABELED_TFREC_FORMAT)
    image = decode_image(example['image'])
    label = tf.cast(example['class'], tf.int32)

    return image, label # returns a dataset of (image, label) pairs

def read_unlabeled_tfrecord(example):
    UNLABELED_TFREC_FORMAT = {
        "image": tf.io.FixedLenFeature([], tf.string), # tf.string means bytestring
        "id": tf.io.FixedLenFeature([], tf.string),  # shape [] means single element
        # class is missing, this competitions's challenge is to predict flower classes for the test dataset
    }
    example = tf.io.parse_single_example(example, UNLABELED_TFREC_FORMAT)
    image = decode_image(example['image'])
    idnum = example['id']
    return image, idnum # returns a dataset of image(s)

def load_dataset(filenames, labeled=True, ordered=False):
    # Read from TFRecords. For optimal performance, reading from multiple files at once and
    # disregarding data order. Order does not matter since we will be shuffling the data anyway.

    ignore_order = tf.data.Options()
    if not ordered:
        ignore_order.experimental_deterministic = False # disable order, increase speed

    dataset = tf.data.TFRecordDataset(filenames) # automatically interleaves reads from multiple files
    dataset = dataset.with_options(ignore_order) # uses data as soon as it streams in, rather than in its original order
    dataset = dataset.map(read_labeled_tfrecord if labeled else read_unlabeled_tfrecord)
    # returns a dataset of (image, label) pairs if labeled=True or (image, id) pairs if labeled=False
    return dataset

def get_training_dataset():
    dataset = load_dataset(tf.io.gfile.glob(GCS_DS_PATH + '/tfrecords-jpeg-224x224/train/*.tfrec'), labeled=True)
    dataset = dataset.repeat() # the training dataset must repeat for several epochs
    dataset = dataset.shuffle(2048)
    dataset = dataset.batch(BATCH_SIZE)
    return dataset

def get_validation_dataset():
    dataset = load_dataset(tf.io.gfile.glob(GCS_DS_PATH + '/tfrecords-jpeg-224x224/val/*.tfrec'), labeled=True, ordered=False)
    dataset = dataset.batch(BATCH_SIZE)
    dataset = dataset.cache()
    return dataset

def get_test_dataset(ordered=False):
    dataset = load_dataset(tf.io.gfile.glob(GCS_DS_PATH + '/tfrecords-jpeg-224x224/test/*.tfrec'), labeled=False, ordered=ordered)
    dataset = dataset.batch(BATCH_SIZE)
    return dataset

training_dataset = get_training_dataset()
validation_dataset = get_validation_dataset()

일단 데이터를 받아왔는데 전체 데이터중 사이즈가 224인 일부만 받아왔다.

만약 성능을 높이고 싶으면

1. 다른데이터를 받아온 후 resize한다

2. 다른데이터를 받아서 각각 학습하고 앙상블한다.

두가지의 option이 있을 것  같고 어쩌면 두가지 모두 사용하는게 나을지도 모르겠으나 이번에는 둘다 하지 않았다.

 

from keras.callbacks import EarlyStopping
early_stopping = EarlyStopping(monitor='val_loss', min_delta=0.01, patience=6, verbose=1) # 조기종료

다음으로 early stopping을 정의하고

inception v3를 불러왔다.

 

이 코드의 핵심이다. inception v3를 이용해 출력층을 제외하고 동결시킨다음 global average pooling, dense layer로 학습시켰다. optimizer는 adam을 사용하였다.

with strategy.scope():    
    pt_model= tf.keras.applications.InceptionV3(
    include_top=False, weights='imagenet', input_tensor=None,
    input_shape=[*IMAGE_SIZE, 3]
    )
    pt_model.trainable=False
    
    model = tf.keras.Sequential([
        tf.keras.Input(shape=(*IMAGE_SIZE, 3)),
        layers.experimental.preprocessing.RandomFlip("horizontal_and_vertical"),
        pt_model,
        layers.GlobalAveragePooling2D(),
        layers.Dense(104, activation='softmax'),
    ])
        
    model.compile(
        optimizer='adam',
        loss = 'sparse_categorical_crossentropy',
        metrics=['sparse_categorical_accuracy']
    )

model.summary()

historical = model.fit(training_dataset, 
          steps_per_epoch=STEPS_PER_EPOCH,
          epochs=EPOCHS, 
          validation_data=validation_dataset, callbacks=[early_stopping])

early stopping이 호출되지 않고 20번까지 그냥 학습하였는데 74%의 정확도가 나왔다.

 

역시 학습이 overfitting된 것이 input값이 많이 부족한게 보인다.

데이터를 늘려야 하는데 augmentation하는것도 좋은 방법이 될 것 같다.

하지만 여기서는 하지 않았고 다음으로 2개층을 풀어서 학습시켰다.

대신 이때는 adam을 사용하지 않고 momenum with decay를 사용하였는데

learning rate를 줄이기 위해서였다.

with strategy.scope():    
    for i in range(1,4):
        model.layers[-i].trainable=True
    
        
    model.compile(
        optimizer=tf.keras.optimizers.SGD(lr=0.02,momentum=0.9,decay=0.001),
        loss = 'sparse_categorical_crossentropy',
        metrics=['sparse_categorical_accuracy']
    )

historical = model.fit(training_dataset, 
          steps_per_epoch=STEPS_PER_EPOCH,
          epochs=EPOCHS, 
          validation_data=validation_dataset, callbacks=[early_stopping])

 

 

마지막으로 모든층의 동결을 풀고 learning rate를 더 줄여서 학습시켰다.

with strategy.scope():    
    model.trainable=True


    model.compile(
        optimizer=tf.keras.optimizers.SGD(lr=0.01,momentum=0.9,decay=0.001),
        loss = 'sparse_categorical_crossentropy',
        metrics=['sparse_categorical_accuracy']
    )

historical = model.fit(training_dataset, 
          steps_per_epoch=STEPS_PER_EPOCH,
          epochs=EPOCHS*2, 
          validation_data=validation_dataset, callbacks=[early_stopping])

 

굉장히 빨리 earlystop 했다. overfitting이 심각하긴하다.

해결방법으로는 제공된 input 이미지를 모두 사용하는는것, zoom, shift, rotate등의 augmentation, 그리고 black box를 이용한 앙상블등 다양한 방식이 있을 것이다.

그럼에도 불구하고 inception v3의 pre trained model을 이용해서 이런 간단한 방법으로도 상위30%정도는 할 수 있었다.

반응형