[미니 프로젝트] DL 3. 네트워크를 이용하여 3epoch 학습 Loss Graph 확인 및 결과 확인하기 (3) Tensorflow 모델

DongHyeon·2024년 1월 3일
0
post-custom-banner

Tensorflow

1. 라이브러리 선언

#%% 라이브러리 호출
import numpy as np
import pandas as pd
import os
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from PIL import Image
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.optimizers import Adam
from tensorflow.keras import layers,models,Model
from keras.preprocessing.image import ImageDataGenerator
import tensorflow.keras.backend as K
from tensorflow.keras.applications import resnet50 # ResNet 모델 불러오기 50 layer 모델
from tensorflow.keras.layers import Input,GlobalAveragePooling2D, Conv2D, BatchNormalization, Activation, Add, MaxPooling2D, AveragePooling2D, Flatten, Dense, ZeroPadding2D

각 종 라이브러리를 선언해 주는데, PreTrained 모델을 위해서, 각종 레이어 툴을 한번에 선언하여주었습니다.

2. 시드 고정

import random
os.environ['PYTHONHASHSEED']='1'
os.environ['TF_DETERMINISTIC_OPS']='1'
np.random.seed(5148)
random.seed(5148)
tf.random.set_seed(5148)

동일한 초기 조건에서 실험을 재현하거나 결과를 비교하기 위해 실험의 재현성을 위해 난수 생성을 제어하는 목적으로, Python, NumPy, TensorFlow의 난수 시드를 각각 5148로 설정합니다.

3. GPU 사용

gpus = tf.config.list_physical_devices('GPU')
if gpus:
  try:
    tf.config.set_logical_device_configuration(
        gpus[0],
        [tf.config.LogicalDeviceConfiguration(memory_limit=4*1024)])
    print("GPU를 사용합니다")
  except RuntimeError as e:
    # 프로그램 시작시에 가상 장치가 설정되어야만 합니다
    print(e)

메모리는 기본적으로 4GB를 사용하나, VIT의 경우 4GB로는 진행되지 않아 6GB를 사용하는 등, 제한을 풀어줘야하는 경우가 생김.

4. Data Frame

#%% 이미지 경로와 라벨, encoding된 라벨을 data frame제작
path = "./Rice_Image_Dataset"
data = {"imgpath": [] , "labels": [] ,"encoded_labels":[]}
categories=["Arborio","Basmati","Ipsala","Jasmine","Karacadag"] # 순서대로 0,1,2,3,4

for idx,folder in enumerate(categories):
    folderpath = os.path.join(path,folder)
    filelist = os.listdir(folderpath)
    for file in filelist:
        fpath = os.path.join(folderpath, file)
        data["imgpath"].append(fpath)
        data["labels"].append(folder)
        data["encoded_labels"].append(idx)
df = pd.DataFrame(data)
#%% train:test:validation=6:2:2 로 쪼개어 학습
train_xy,test_xy=train_test_split(df, train_size=0.6,shuffle=True)
test_xy,validation_xy=train_test_split(test_xy,train_size=0.5,shuffle=True)

이미지 폴더에서 경로, 클래스 라벨, 인코딩된 라벨을 이용해 데이터 프레임을 생성
주어진 이미지 경로 내에 있는 정수로 인코딩된 클래스의 라벨을 데이터 프레임의 각 열에 추가합니다. 이후 Train:Validation:test=6:2:2로 데이터를 쪼갬

5. Image Generator

#%% 학습 이미지 데이터를 전처리하는 데이터 제너레이터를 만드는 작업
img_size=(224,224)
generator = ImageDataGenerator(
    rescale=1./255
)
train_images = generator.flow_from_dataframe(
    dataframe=train_xy,
    x_col='imgpath',
    y_col='labels',
    target_size=img_size,
    color_mode='rgb',
    class_mode='categorical',
    batch_size=16,
    shuffle=True,
    seed=42,
)

val_images = generator.flow_from_dataframe(
    dataframe=validation_xy,
    x_col='imgpath',
    y_col='labels',
    target_size=img_size,
    color_mode='rgb',
    class_mode='categorical',
    batch_size=16,
    shuffle=False
)

test_images = generator.flow_from_dataframe(
    dataframe=test_xy,
    x_col='imgpath',
    y_col='labels',
    target_size=img_size,
    color_mode='rgb',
    class_mode='categorical',
    batch_size=16,
    shuffle=False
)

학습 이미지를 전처리 하기위한 Data Generator 생성.
주로 딥러닝 모델을 훈련할 때 사용되고, 이미지 데이터를 실시간으로 처리하고 배치 단위로 모델에 공급할 때 주로 사용하는데, 이미지의 픽셀 값을 0과 1 사이로 정규화하고, 이미지의 크기를 (224,224)로 앞서 설명한 모든 Network에 적절한 이미지 크기로 resize를 진행

6. 모델 호출

def ResNet_50(input_shape=(224, 224, 3), num_classes=5):
    # ResNet50 모델 불러오기 (pretrained weights를 사용)
    base_model = resnet50.ResNet50(weights="imagenet", input_shape=(224, 224, 3), include_top=False)
    # 기존의 마지막 레이어를 제외한 부분 가져오기
    x=base_model.output
    x=GlobalAveragePooling2D()(x)
    x=Dense(num_classes, activation='softmax')(x)
    model=Model(inputs=base_model.input,outputs=x)
    return model

resnet_50=ResNet_50(input_shape=(224, 224, 3), num_classes=5)
# 모델 요약 출력
resnet_50.summary()

keras.applications를 통해서 모델의 선언이 가능하다. weights=None은 Non-Pretrained로 가중치가 사전학습되지않은 모델을 이용하는 것이고, 학습을 하지 않는 경우에는 Included_top=True로 두고 num_classes=5 등 클래스의 개수를 바로 변환시켜 사용가능하지만, keras에서는 사전 학습 되는 경우에 num_classes를 조절할 수 없어, Included_top=False로 두고 FC(Fully Connected)Layer를 직접 설계해야하는 불편함이 있다.
예를 들어 Non_Pretrianed의 경우에는

def ResNet_50(input_shape=(224, 224, 3), num_classes=5):
    # ResNet50 모델 불러오기 (pretrained weights를 사용하지 않음)
    base_model = resnet50.ResNet50(weights=None, input_shape=(224, 224, 3), include_top=True, classes=num_classes)
    # 기존의 마지막 레이어를 제외한 부분 가져오기
    x=base_model.output
    model=Model(inputs=base_model.input,outputs=x)
    return model

다음과 같이 작성 가능하다.

7. Model Train 및 Test

#%% 모델 컴파일 및 학습
resnet_50.compile(optimizer=Adam(learning_rate=0.0003),loss='categorical_crossentropy',metrics=['accuracy'])
with tf.device('/GPU:0'):
  history=resnet_50.fit(
      train_images,
      steps_per_epoch=len(train_images),
      validation_data=val_images,
      validation_steps=len(val_images),
      epochs=3,
      )

results = resnet_50.evaluate(test_images, verbose=0)
print("    Test Loss: {:.5f}".format(results[0]))
print("Test Accuracy: {:.2f}%".format(results[1] * 100))

train_acc = history.history['accuracy']
train_loss = history.history['loss']
valid_acc = history.history['val_accuracy']
valid_loss = history.history['val_loss']

모델을 compile하고 주어진 데이터 제너레이터를 사용하여 모델을 학습시킵니다. 학습된 모델을 Test Data로 평가하고 학습과정에서의 훈련 및 검증 정확도 및 손실을 기록하여 결과를 출력합니다.

profile
I'm Free!
post-custom-banner

0개의 댓글