본문 바로가기
Visual Intelligence/Image Classification

[Image Classification] VGGNet (cats-and-dogs)

by goatlab 2022. 9. 6.
728x90
반응형
SMALL

VGG16

 

케라스 API에서는 이 아키텍처의 구현물을 공식적으로 제공하며 tf.keras.application 패키지를 통해 접근할 수 있다. 이 패키지에는 그 외에도 잘 알려진 모델이 포함되어 있으며 각 모델에 대해 ‘사전에 훈련된’ 매개변수 (특정 데이터셋에서 사전에 훈련시키는 과정에서 저장해둔 매개변수)도 제공한다. 예를 들어, 다음 명령어로 VGG 네트워크를 인스턴스화할 수 있다.

 

Vgg_net = tf.keras.applications.VGG16(
		Include_top = True,
		weights = ‘imagenet’,
		input_tensor = None,
		Input_shape = None,
		pooling = None,
 		classes = 1000)

 

이 기본 인수를 사용해 케라스는 VGG-16 네트워크를 인스턴스화하고 ImageNet에서 훈련이 끝난 후 얻게 된 매개변수 값을 불러온다. 이 단일 명령어로 이미지를 1,000개의 ImageNet 카테고리로 분류 할 준비가 된 네트워크를 갖게 됐다. 만약 처음부터 다시 네트워크를 훈련시키고자 한다면 weights = None으로 고정시켜야 케라스에서 무작위로 가중치를 설정한다.

 

VGG19

 

VGG-19 네트워크를 인스턴스화하고 ImageNet에서 훈련이 끝난 후 얻게 되는 매개변수 값을 로딩하는 코드는 다음과 같다.

 

Vgg_net = tf.keras.applications.VGG19(
		Include_top = True,
		weights = ‘imagenet’,
		input_tensor = None,
		Input_shape = None,
		pooling = None,
		classes = 1000)

 

예제 실습

 

# 데이터 불러오기 : Cats vs Dogs dataset
!curl -O https://download.microsoft.com/download/3/E/1/3E1C3F21-ECDB-4869-8368-6DEBA77B919F/kagglecatsanddogs_5340.zip
import os
import shutil
import zipfile

ROOT_DIR = '/content'

DATA_ROOT_DIR = os.path.join(ROOT_DIR, 'catsanddogs')

with zipfile.ZipFile(os.path.join(ROOT_DIR, 'kagglecatsanddogs_5340.zip'), 'r') as target_file:
    target_file.extractall(DATA_ROOT_DIR)

 

이제, PetImages 폴더 안에 두 개의 하위 폴더 Cat과 Dog가 존재하고, 각 하위 폴더에는 각 범주에 대 한 이미지 파일들이 있다.

 

손상된 이미지 필터링

 

실제 많은 이미지 데이터로 작업할 때 손상된 이미지가 흔히 발생한다. 헤더에 "JFIF"문자열이 포함되 지 않은 잘못 인코딩 된 이미지를 필터링한다.

 

num_skipped = 0

for folder_name in ("Cat", "Dog"):
    folder_path = os.path.join(DATA_ROOT_DIR + "/PetImages", folder_name)

    for fname in os.listdir(folder_path):
        fpath = os.path.join(folder_path, fname)

        try:
            fobj = open(fpath, "rb")
            is_jfif = tf.compat.as_bytes("JFIF") in fobj.peek(10)
        
        finally:
            fobj.close()

        if not is_jfif:
            num_skipped += 1

            # Delete corrupted image
            os.remove(fpath)

print("Deleted %d images" % num_skipped)
Deleted 1590 images

 

데이터셋 생성

 

image_size = (180, 180)
batch_size = 32

train_ds = tf.keras.preprocessing.image_dataset_from_directory(
    DATA_ROOT_DIR + "/PetImages",
    validation_split=0.2,
    subset="training",seed=1337,
    image_size=image_size,
    batch_size=batch_size,
)

val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    DATA_ROOT_DIR + "/PetImages",
    validation_split=0.2,subset="validation",
    seed=1337,
    image_size=image_size,
    batch_size=batch_size,
)
Found 23410 files belonging to 2 classes.
Using 18728 files for training.
Found 23410 files belonging to 2 classes.
Using 4682 files for validation.

 

데이터 시각화

 

훈련 데이터셋의 첫 이미지 9장을 출력한다. 레이블 1은 “dog”이고, 레이블 0은 “cat”으로 한다.

 

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(int(labels[i]))
  
  plt.axis("off")

 

데이터 증강

 

개수가 많은 데이터셋이 없는 경우, 무작위 수평 뒤집기 또는 작은 무작위 회전과 같은 무작위지만 실질적인 변환을 훈련 이미지셋에 적용하여 샘플 다양성을 인위적으로 도입하는 것이 좋다. 이를 통해 overfitting 속도를 늦추면서 학습 데이터의 다양한 측면을 모델에게 학습시킬 수 있다.

 

data_augmentation = keras.Sequential(
    [layers.experimental.preprocessing.RandomFlip("horizontal"),
     layers.experimental.preprocessing.RandomRotation(0.1),]
)

 

data_augmentation 데이터셋의 첫번째 이미지에 반복적으로 적용하여 augmentation sample의 모양을 시각화 한다.

 

plt.figure(figsize=(10, 10))
for images, _ in train_ds.take(1):
  for i in range(9):
    augmented_images = data_augmentation(images)
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(augmented_images[0].numpy().astype("uint8"))
  
  plt.axis("off")

 

데이터 표준화

 

data_augmentation 전처리기를 사용할 수 있는 두가지 방법이 있다.

 

# 모델의 일부로 만들기
inputs = keras.Input(shape=input_shape)
x = data_augmentation(inputs)
x = layers.experimental.preprocessing.Rescaling(1./255)(x)

 

이 옵션을 사용하면 데이터 증가가 나머지 모델 실행과 동시에 device에서 발생하므로 GPU 가속의 이 점을 얻을 수 있다.

 

# 데이터 세트에 직접 적용하기
augmented_train_ds = train_ds.map(
 lambda x, y: (data_augmentation(x, training=True), y))

 

이 옵션을 사용하면 데이터 증가가 CPU에서 비동기적으로 발생하며 모델로 이동하기 전에 버퍼링된다. CPU에서 훈련하는 경우, 이 옵션으로 하는 것이 낫다.

 

성능을 위한 데이터 세트 구성

 

I/O가 차단되지 않고 디스크에서 데이터를 생성할 수 있도록 버퍼링된 프리 패치를 사용해야한다.

 

train_ds = train_ds.prefetch(buffer_size=32)
val_ds = val_ds.prefetch(buffer_size=32)

 

모델 생성

 

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

def make_model(input_shape, num_classes):
  inputs = keras.Input(shape=input_shape)
  
  # Image augmentation block
  x = data_augmentation(inputs)
  
  # Entry block
  x = layers.experimental.preprocessing.Rescaling(1.0 / 255)(x)
  x = layers.Conv2D(32, 3, strides=2, padding="same")(x)
  x = layers.BatchNormalization()(x)
  x = layers.Activation("relu")(x)
  x = layers.Conv2D(64, 3, padding="same")(x)
  x = layers.BatchNormalization()(x)
  x = layers.Activation("relu")(x)
  previous_block_activation = x # Set aside residual
  
  for size in [128, 256, 512, 728]:
    x = layers.Activation("relu")(x)
    x = layers.SeparableConv2D(size, 3, padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.Activation("relu")(x)
    x = layers.SeparableConv2D(size, 3, padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.MaxPooling2D(3, strides=2, padding="same")(x)
    x = layers.SeparableConv2D(1024, 3, padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.Activation("relu")(x)
    x = layers.GlobalAveragePooling2D()(x)
    
    if num_classes == 2:
      activation = "sigmoid"
      units = 1
    
    else:
      activation = "softmax"
      units = num_classes
    
    x = layers.Dropout(0.5)(x)
    outputs = layers.Dense(units, activation=activation)(x)
    
    return keras.Model(inputs, outputs)

model = make_model(input_shape=image_size + (3,), num_classes=2)

keras.utils.plot_model(model, show_shapes=True)

model.summary()

epochs = 50

callbacks = [
 keras.callbacks.ModelCheckpoint("save_at_{epoch}.h5"),
]

model.compile(optimizer=keras.optimizers.Adam(1e-3),
              loss="binary_crossentropy",
              metrics=["accuracy"],
)

model.fit(train_ds, epochs=epochs,
          callbacks=callbacks,
          validation_data=val_ds,
)

 

모델 검증

 

# Evaluate the model on the test data using `evaluate`
print ("Evaluate on test data")

results = model.evaluate(val_ds, batch_size=128)

print ("test loss, test acc:", results)
728x90
반응형
LIST