Kaggle 실습/Deep Learning

02. Dog-Breed-Identification (강아지 품종 분류) - InceptionNet (2)

망고 ෆ 2024. 6. 22. 01:01

5. Generator 생성

전 페이지의 파일 구조를 기반으로 데이터를 증강하기 위해 generator를 생성해볼 것이다.

 

전처리하기 위해 이미지의 픽셀 정보 확인

import cv2

temp_path = "/content/train_sub/affenpinscher/00ca18751837cd6a22813f8e221f7819.jpg"
temp_img = cv2.imread(temp_path)

print(temp_img.shape)
print('이미지 픽셀의 최소값:',temp_img.min())   # 0
print('이미지 픽셀의 최대값:',temp_img.max())   # 255

 

 

데이터 생성기 만들어 데이터 보강

# 데이터 생성하는 생성기 만들기 + 전처리
train_datagen = ImageDataGenerator(
    validation_split = 0.1,
    rescale = 1./255.,

    # 데이터 보강
    rotation_range = 40,
    width_shift_range = 0.2,
    height_shift_range = 0.2,
    shear_range = 0.2,
    fill_mode = 'nearest'
)

valid_datagen = ImageDataGenerator(
    validation_split = 0.1,
    rescale = 1./255.
)

 

 

이미지 사이즈 및 batch_size 지정

이미지 사이즈는 내 맘대로 정하였고, batch_size는 T4로 돌리기 위해 16정도로 하였다.

image_size = 299
batch_size = 16

 

 

구체적으로 어디에 사용할지 세팅! (train/valid 따로 처리)

train_generator = train_datagen.flow_from_directory(
    # 1) 이미지를 어디서 가져올지 지정
    train_data_sub_folder,
    # 2) 이 셋의 용도 지정
    subset = 'training',
    # 3) 입력에 대한 모양 지정
    target_size = (image_size, image_size),
    # 4) 기타옵션
    seed = 42, shuffle = True,
    batch_size = batch_size,
    class_mode = 'categorical'
)

valid_generator = valid_datagen.flow_from_directory(
    # 1) 이미지를 어디서 가져올 것인지 지정
    train_data_sub_folder,
    # 2) 이 셋의 용도 지정
    subset = 'validation',
    # 3) 입력에 대한 모양 지정
    target_size = (image_size, image_size),
    # 4) 기타옵션
    seed = 42, shuffle = False,
    batch_size = batch_size,
    class_mode = 'categorical'
)

 

6. 모델 구성

InceptionV3 모델에서 ImageNet을 통해 사전 학습된 가중치를 가져올 것이다.

하지만, 이 경우엔 최종적으로 1000개의 분류를 진행하였지만, 나는 120개의 견종을 분류해야하므로 최상위 분류층은 제외하고 가져오도록 하겠다! 

추후에 이 부분은 Transer Learning을 통해 새로운 분류층을 만들어서 조정할 것이다.

import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from keras.applications.inception_v3 import InceptionV3
from keras.layers import Input

# imagenet으로 학습된 가중치 가져오며, 출력층
base_model = InceptionV3(weights='imagenet', include_top=False)
base_model.summary()

 

 

모델의 계층 구조 확인

utils의 plot_model을 통해 모델의 구조를 시각화해서 확인할 수 있으므로 모델의 구조를 확인하고 싶을 때 사용하면 좋다.

from tensorflow.keras.utils import plot_model
plot_model(base_model, show_shapes=True)

 

 

모델 사용 방법 

방법 1) 그대로 사용하기

for layer in base_model.layers:
    layer.trainable = False

 

방법 2) 구조는 좋다고 판단하여 처음부터 끝까지 내 데이터로 다시 학습하기

for layer in base_model.layers:
    layer.trainable = True

 

방법 3) 앞의 이미지 추출은 그대로 사용하되, 중간에 특징 뽑아내는 레이어는 내 데이터로 학습하기

for layer in base_model.layers[:249]:
    layer.trainable = False
for layer in base_model.layers[249:]:
    layer.trainable = True

 

이러한 방법들이 있지만, 일단 방법1로 해보았다.

기존의 InceptionV3는 ImageNet 셋으로 학습하여 최종적으로 1000종류로 분류하였지만, 여기서는 120종으로 분류하여야 하므로 output 쪽을 수정해야겠다.

 

 

출력 부분을 120종에 맞게 수정

# 모델 설계 관련 모듈
from keras.models import Model
from keras.layers import Dense, GlobalAveragePooling2D, Dropout, MaxPooling2D
from keras import backend as K
from keras.layers import Activation, Conv2D
from keras.applications.inception_v3 import preprocess_input
from keras import optimizers

num_classes = len(os.listdir(train_data_sub_folder))

# 출력 부분을 120종에 맞춰 수정
x = GlobalAveragePooling2D()(x)
x = Dropout(0.2)(x)
x = Dense(1024, activation='relu')(x)
x = Dropout(0.2)(x)
x = Dense(1024, activation='relu')(x)
x = Dropout(0.2)(x)
x = Dense(512, activation='relu')(x)

pred = Dense(num_classes, activation='softmax')(x)

model = Model(inputs=base_model.input,
              outputs=pred)

 

 

Model Compile

이미 하위 폴더 구조로 만들었으므로 굳이 원핫인코딩을 해주지 않아도 되므로 loss는 sparse_categorical_crossentropy 대신 categorical_crossentropy 로 사용하였다.

my_adam = optimizers.Adam(learning_rate=0.001, beta_1 =0.9, beta_2=0.999)

model.compile(optimizer=my_adam,
              loss='categorical_croessentropy',
              metrics=['accuracy'])

 

 

CheckPoint 설정

cp_path = 'training/cp--{epoch:04d}.ckpt'
cp_dir = os.path.dirname(cp_path)
cp_callback = tf.keras.callbacks.ModelCheckpoint(
    cp_path,
    verbose = 1,
    save_weights_only = True
)
es_callback = tf.keras.callbacks.EarlyStopping(
    monitor="val_loss",
    patience = 10   # 참을 횟수 (갱신이 되지 않는 횟수)
)

 

 

7. test 문제 풀기

test 문제를 풀 generator 생성하여 모델에 전달

test_datagen = ImageDataGenerator(
    rescale = 1./255.
)

test_generator = test_datagen.flow_from_directory(
    directory = '/content',
    classes = ['test'],
    class_mode = 'categorical',
    shuffle = False,
    batch_size = batch_size
)

test_generator.reset()

output = model.predict(test_generator)

 

 

8. sample_submission에 결과 저장

sample_submission.csv 파일 불러오기

df_submission_v1 = pd.read_csv("/content/sample_submission.csv")
df_submission_v1.head()
id_list = []
for f_path in test_generator.filenames:
    # 1) 서브 폴더 경로 제거
    # 2) 뒤에 확장자 제거
    f_full_name = os.path.basename(f_path)
    f_name = os.path.splitext(f_full_name)[0]
    id_list.append(f_name)

 

 

sample 양식에 내가 test 푼 결과값 저장

120개에 대한 각각의 확률값으로 저장된다.

df_submission_v1["id"] = id_list
df_submission_v1.iloc[:,1:] = output
df_submission_v1.head()