본문 바로가기
공허의 유산/영혼을 담는 코드

Image 분류 - 개와 고양이

by 바른생활머시마 2024. 9. 23.
728x90

 

데이터 가져오기

다양한 방법이 있고, 공개 된 데이터셋도 많다.

 

노트북에서 freecodecamp의 데이터를 가져올 경우.

 

!wget https://cdn.freecodecamp.org/project-data/cats-and-dogs/cats_and_dogs.zip

!unzip -q cats_and_dogs.zip

 

 

이미지 읽기

정확히 말하면 이미지 경로 리스트 만들기

import os
from glob import glob
from PIL import Image
import zipfile

import numpy as np
import tensorflow as tf

import matplotlib.pyplot as plt
 
 
# 이미지 패스 지정
train_cat_path = 'cats_and_dogs/train/cats/'
train_dog_path = 'cats_and_dogs/train/dogs/'
valid_cat_path = 'cats_and_dogs/validation/cats/'
valid_dog_path = 'cats_and_dogs/validation/dogs/'
 
# 이미지 패스의 파말 리스트 만들기
train_cat_file = os.listdir(train_cat_path)
train_dog_file = os.listdir(train_dog_path)
valid_cat_file = os.listdir(valid_cat_path)
valid_dog_file = os.listdir(valid_dog_path)
 
 

 

 

라벨링 된 이미지 리스트 만들기

이미지를 읽어서 크기를 줄이고, 0~1 값으로 바꿔서 배열에 추가한다.

학습/검증 구분하지 않고 하나의 리스트에 다 추가

# Class 라벨 정의

class2idx = {'cat' :  0, 'dog' : 1}
idx2class = {0 : 'cat', 1 : 'dog'}
 
# 수작업으로 이미지 리스트와 라벨 리스트 만들기

img_list = []
label_list = []

# Train 데이터를 img_list 리스트에 넣기
train_cat_file = glob(train_cat_path + '*.jpg')
for img_file in train_cat_file :
  img = Image.open(img_file).resize((128,128))
  img = np.array(img)/255.  # 이미지 스케일링
  img_list.append(img)
  label_list.append(0) # cat : 0

train_dog_file = glob(train_dog_path + '*.jpg')
for img_file in train_dog_file :
  img = Image.open(img_file).resize((128,128))
  img = np.array(img)/255.  # 이미지 스케일링
  img_list.append(img)
  label_list.append(1) # dog : 1


# Valid 데이터를 img_list 리스트에 넣기
valid_cat_file = glob(valid_cat_path + '*.jpg')
for img_file in valid_cat_file :
  img = Image.open(img_file).resize((128,128))
  img = np.array(img)/255.  # 이미지 스케일링
  img_list.append(img)
  label_list.append(0) # cat : 0

valid_dog_file = glob(valid_dog_path + '*.jpg')
for img_file in valid_dog_file :
  img = Image.open(img_file).resize((128,128))
  img = np.array(img)/255.  # 이미지 스케일링
  img_list.append(img)
  label_list.append(1) # dog : 1
 
# 이미지 리스트, 라벨 리스트루 numpy array 변경
img_list_arr = np.array(img_list)
label_list_arr = np.array(label_list)
 

 

 

학습/테스트 데이터 분리

from sklearn.model_selection import train_test_split

X_train, X_test , y_train, y_test = train_test_split(img_list_arr, label_list_arr, test_size=0.3, stratify=label_list_arr, random_state=41)
X_train.shape, X_test.shape , y_train.shape, y_test.shape

 

CNN

# Hyperparameter Tunning

num_epochs = 10
batch_size = 32

learning_rate = 0.001
dropout_rate = 0.5

input_shape = (128, 128, 3)  # 사이즈 확인
 
# Sequential 모델 정의
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D

model = Sequential()
model.add(Conv2D(32, kernel_size=(5,5), strides=(1,1), padding='same', activation='relu', input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Conv2D(64,(3,3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(2, activation='softmax'))
 
# 모델 컴파일
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate),  # Optimization
              loss='sparse_categorical_crossentropy',  # Loss Function
              metrics=['accuracy'])  # Metrics / Accuracy

#model.summary()
 

 

학습

# callback : EarlyStopping, ModelCheckpoint

from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint

# EarlyStopping
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=5)

# ModelCheckpoint
checkpoint_path = "my_checkpoint.keras"
checkpoint = ModelCheckpoint(filepath=checkpoint_path,
                             save_best_only=True,
                             monitor='val_loss',
                             verbose=1)
 
# 모델 학습
# num_epochs = 10 ,  batch_size = 32
# 성능 70%

# 모델 학습(fit)
history = model.fit(
    X_train, y_train ,
    validation_data=(X_test, y_test),
    epochs=num_epochs,
    batch_size=batch_size,
    callbacks=[es, checkpoint]
)
 

 

 

성능 개선

# 모델을 딥하게 만들고 , epochs 늘려 다시 학습 수행
# Sequential 모델 정의

model = Sequential()
model.add(Conv2D(32, kernel_size=(5,5), strides=(1,1), padding='same', activation='relu', input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Conv2D(64,(3,3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(64,(3,3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(128,(3,3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(2, activation='softmax'))
 
# 모델 컴파일
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate),  # Optimization
              loss='sparse_categorical_crossentropy',  # Loss Function
              metrics=['accuracy'])  # Metrics / Accuracy

model.summary()
 
# 모델 학습 : 딥하게, epochs 늘려도 성능향상 없어 보인다.!!
# 성능 70%

num_epochs = 20
batch_size = 32

history = model.fit(
    X_train, y_train ,
    validation_data=(X_test, y_test),
    epochs=num_epochs,
    batch_size=batch_size,
    callbacks=[checkpoint]
)

 

 

예측

# Test 데이터로 성능 예측하기

i=1
plt.figure(figsize=(16, 8))
for img, label in zip(X_test[:8], y_test[:8]):
      # 모델 예측(predict)
      pred = model.predict(img.reshape(-1,128, 128, 3))
      pred_t = np.argmax(pred)
      plt.subplot(2, 4, i)
      plt.title(f'True Value:{label}, Pred Value: {pred_t}')
      plt.imshow(img)
      plt.axis('off')
      i = i + 1

 

 

-------------------------

VGG16을 이용한 전이학습

https://kyeongha-blog.tistory.com/entry/VGG16-%EC%98%88%EC%A0%9C%EB%A5%BC-%ED%86%B5%ED%95%9C-transfer-learning-fine-tuning-%EC%84%A4%EB%AA%85

 

[VGG16] 예제를 통한 transfer learning, fine-tuning 설명

VGG16 - transfer learning, fine-tuning 안녕하세요, 데이터과학을 공부하고 있는 황경하입니다.오늘은 pretrained model 그중 VGG16 모델을 이용한 transfer learning, fine-tuning을 공부해보려 합니다.Google Colab 환경

kyeongha-blog.tistory.com

 

VGG 사용 준비

conv_base = keras.applications.vgg16.VGG16(
    include_top=False,
    input_shape=(180, 180, 3))

 

conv_base.trainable = False

 

데이터 준비

import pathlib
from tensorflow.keras.utils import image_dataset_from_directory

if not os.path.isdir('cats_vs_dogs_small'):
    gdown.download(id='1z2WPTBUI-_Q2jZtcRtQL0Vxigh-z6dyW', output='cats_vs_dogs_small.zip')
    cats_vs_dogs_small = zipfile.ZipFile('cats_vs_dogs_small.zip')
    cats_vs_dogs_small.extractall()
    cats_vs_dogs_small.close()

base_dir = pathlib.Path("cats_vs_dogs_small")

train_dataset = image_dataset_from_directory(
    base_dir / "train",
    image_size=(180, 180),
    batch_size=32)
validation_dataset = image_dataset_from_directory(
    base_dir / "validation",
    image_size=(180, 180),
    batch_size=32)
test_dataset = image_dataset_from_directory(
    base_dir / "test",
    image_size=(180, 180),
    batch_size=32)

 

 

모델 준비와 학습

from keras.layers import Flatten, Dense, Dropout

def build_model(input_shape, num_out):
  inputs = keras.Input(shape=(180, 180, 3))
  x = keras.applications.vgg16.preprocess_input(inputs)
  x = conv_base(x)
  x = Flatten()(x)
  x = Dense(256)(x)
  x = Dropout(0.5)(x)
  outputs = Dense(1, activation="sigmoid")(x)
  model = keras.Model(inputs, outputs)
  return model
model = build_model((180,180,3), 1)

 

model.compile(loss="binary_crossentropy",
              optimizer="rmsprop",
              metrics="accuracy")

callbacks = [keras.callbacks.ModelCheckpoint(
      filepath="feature_extraction.h5",
      save_best_only=True,
      monitor="val_loss")]

history = model.fit(
    train_dataset,
    epochs=50,
    validation_data=validation_dataset,
    callbacks=callbacks)
test_model = keras.models.load_model("feature_extraction.h5")
(test_loss, test_acc) = test_model.evaluate(test_dataset)
print(f"test_loss: {test_loss}")
print(f"test_acc: {test_acc}")

 

Fine tunning은 안해도 될 듯.

 

 

728x90
반응형

댓글