[KT Aivle AI] 8주차 미니프로젝트 4차

hyowon·2024년 4월 28일
0

KtAivle

목록 보기
30/39

차량 파손 여부 분류하기

1) 미션1 : Data Preprocessin

  • 제공된 데이터 : Car_Images.zip
    • Car_Images : 차량의 정상/파손 이미지 무작위 수집

2) 미션2 : CNN 모델링
3) 미션3 : Transfer Learning

1. 환경설정

!pip install keras --upgrade

import os
os.environ['KERAS_BACKEND'] = 'tensorflow'

(1) 라이브러리 불러오기


import gdown, zipfile
import os, glob, shutil
from tqdm import tqdm

import numpy as np
import matplotlib.pyplot as plt

(2) 데이터 다운로드

from google.colab import drive
drive.mount('/content/drive')
import zipfile     # ZIP 파일을 읽고 쓰는 데 필요한 함수와 클래스 제공
path = '/content/drive/MyDrive/Datasets/'

# 변수 path에 저장된 경로와 file1에 저장된 파일 이름을 결합하여 전체 파일 경로 생성
file1 = 'Car_Images.zip'
path + file1

#데이터 압축 해제
data = zipfile.ZipFile(path+file1)
try :
    print('압축을 해제합니다.')
    data.extractall(path)
    print('압축 해제가 완료되었습니다.')
except :
    pass
    print('압축이 이미 해제되었거나 이미 폴더가 존재합니다.')

2. 데이터 전처리

  • 모델링을 위한 데이터 구조 만들기
    • X : 이미지를 array로 변환
    • Y : 이미지 갯수만큼 normal - 0, abnormal -1로 array를 만듭니다.

(1) Y: 클래스 만들기

  • 세부요구사항
    • 전체 데이터에 대한 Y를 생성
    • normal, abnormal 데이터의 수를 확인하고 normal을 0, abnormal을 1로 지정합니다.
# 데이터 갯수 확인
print(f"정상 차량 이미지 데이터는 {len(glob.glob(path+'normal/*'))}장 입니다.")
print(f"파손 차량 이미지 데이터는 {len(glob.glob(path+'abnormal/*'))}장 입니다.")

y_normal = [0] * len(glob.glob(path+'normal/*'))     # Datasets 파일의 normal에 있는 모든 이미지 들고온다.
y_abnormal = [1] * len(glob.glob(path+'abnormal/*')) # Datasets 파일의 normal에 있는 모든 이미지 들고온다.

print(len(y_normal), len(y_abnormal))

Y = y_normal + y_abnormal

(2) X: 데이터 리스트 통합

  • 세부 요구사항
    • 전체 이미지 데이터를 하나의 리스트로 통합
X = [] # 이미지 데이터를 저장할 빈 리스트

normal_data_1 =glob.glob(path+'normal/*')[:]
abnormal_data_2 = glob.glob(path+'abnormal/*')[:]

X.extend(normal_data_1)
X.extend(abnormal_data_2)       # X에 추가해준다.

print(len(X))

(3) 데이터셋 분리

from sklearn.model_selection import train_test_split

# 데이터 스플릿의 비율 (1) : train set, test set = 90%, 10%
# 'Y를 기준으로 데이터 분할
# 위에서 train_test_split 할 것을 X,Y로 지정해줬기 때문에 train_test_split(X_train, y_train) 해줄 필요없다.
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.1, random_state=42, stratify=Y)

# 데이터 스플릿의 비율 (2) : train set, valid set = 90%, 10%
# y_train 기준으로 데이터 분할
X_train, X_valid, y_train, y_valid = train_test_split(X_train, y_train, test_size=0.1, random_state=42, stratify=y_train)

# 클래스 레이블을 배열로 변환
y_train = np.array(y_train)
y_valid = np.array(y_valid)
y_test = np.array(y_test)

# 각 세트의 길이 확인
print("Train set size:", len(X_train))
print("Validation set size:", len(X_valid))
print("Test set size:", len(X_test))

(4) X: image to array

  • 세부요구사항
    • 모델링을 위해서는 np.array 형태로 데이터셋을 만들어야 합니다.
    • Training set/ Validation set/ Test set의 X는 이미지 형태로 되어 있습니다.
    • 이미지 파일을 불러와 Training data, Validation data, Test data 각각 array 형태로 변환해 봅시다.
from keras.preprocessing.image import load_img, img_to_array

# 이미지 데이터를 로드, 크기 조정 및 배열로 변환하는 함수
def load_and_preprocess_images(image_paths):
    images = []
    for image_path in image_paths:
        img = load_img(image_path, target_size=(299, 299))
        img_array = img_to_array(img)
        img_array /= 255.0  # 이미지 데이터를 0에서 1 사이의 값으로 스케일 조정
        images.append(img_array)
    return np.array(images)

X = load_and_preprocess_images(X)

len(X)

3. 모델링1

  • 세부요구사항
    • Conv2D, MaxPooling2D, Flatten, Dense 레이어들을 이용하여 모델을 설계
      학습시 validation_data로 validation set을 사용하시오.
    • 반드시 Early Stopping 적용
    • 평가시, confusion matrix, accuracy, recall, precision, f1 score 등을 이용하시오.
# 세 번째 모델 정의
model = Sequential()

# 첫 번째 레이어에 Input(shape)를 사용하여 입력 크기 명시
model.add(Conv2D(64, (3, 3), activation='relu', input_shape=(299, 299, 3)))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())

model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(1, activation='sigmoid'))

optimizer = Adam(learning_rate=0.0001)

# 모델 컴파일
model.compile(optimizer=optimizer, loss='binary_crossentropy', metrics=['accuracy'])

early_stopping = EarlyStopping(patience=5, monitor='val_loss', restore_best_weights=True)

# 모델 학습
history = model.fit(X_train, y_train, epochs=50, batch_size=32, validation_data=(X_valid, y_valid), callbacks=[early_stopping])

# 예측 및 평가 메트릭 계산
y_pred = (model.predict(X_test) > 0.5).astype(int)
print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred))

4. 모델링2

  • 세부요구사항
    • image_dataset_from_directory를 이용하여 training set, validation set을 만들어봅시다.
    • 성능을 높이기 위해서 다음의 두가지를 시도해 봅시다.
      • Image Preprocessing Layer, Image Augmentation Layer를 통해 이미지를 변형시켜 봅시다.
      • 사전 학습된 모델(Transfer Learning)을 가져다 사용해 봅시다.
import tensorflow as tf

# 이미지 데이터를 불러올 경로 설정
train_path = path + 'Car_Images_train'
val_path = path + 'Car_Images_val'
test_path = path + 'Car_Images_test'

# 학습 데이터셋 생성
train_dataset = tf.keras.utils.image_dataset_from_directory(
    train_path,
    validation_split=0.2,
    #label_mode='binary',  # 클래스가 두 개인 경우 binary로 설정
    class_names = ['normal','abnormal'],          # 순서 잘 체크
    batch_size=32,
    image_size=(299, 299),  # 이미지 크기 조정
    seed=2024,  # 시드 설정
    subset="training"  # subset 설정
)

# 검증 데이터셋 생성
validation_dataset = tf.keras.utils.image_dataset_from_directory(
    train_path,
    validation_split=0.2,
    #label_mode='binary',
     class_names=['normal', 'abnormal'],  # 클래스 이름 지정
    batch_size=32,
    image_size=(299, 299),
    seed=2024,
    shuffle=False,  # 검증 데이터셋에서는 셔플하지 않음
    subset="validation"  # subset 설정
)

# 테스트 데이터셋 생성
test_dataset = tf.keras.utils.image_dataset_from_directory(
    test_path,
    #label_mode='binary',
     class_names=['normal', 'abnormal'],  # 클래스 이름 지정
    batch_size=32,
    image_size=(299, 299),
    seed=2024,
    shuffle=False,  # 테스트 데이터셋에서는 셔플하지 않음
)

1) ImageDataGenerator 생성

from tensorflow.keras.preprocessing.image import ImageDataGenerator

import tensorflow as tf
from tensorflow import keras

from tensorflow.keras.backend import clear_session
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Input, Dense, Conv2D, MaxPool2D, Flatten

from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint
from sklearn.metrics import classification_report, confusion_matrix
# ImageDataGenerator를 초기화합니다.
train_gen = ImageDataGenerator(
    rotation_range=90,  # 이미지 회전 각도 범위
    width_shift_range=0.2,  # 이미지 가로 이동 범위
    height_shift_range=0.2,  # 이미지 세로 이동 범위
    shear_range=0.2,  # 전단변환 범위
    zoom_range=0.2,  # 이미지 확대/축소 범위
    horizontal_flip=True,  # 수평 뒤집기
    fill_mode='nearest',  # 이미지를 증강할 때 사용할 픽셀 채우기 방법
    rescale=1./255,
)

valid_gen = ImageDataGenerator(rescale=1./255)
test_gen = ImageDataGenerator(rescale=1./255)

2) 구조 설계

# 모델 정의
model = Sequential()

model.add(Conv2D(64, (3, 3), activation='relu', input_shape=(299, 299, 3)))
model.add(MaxPooling2D())
model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D())
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D())
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D())
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D())
model.add(Flatten())

model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(1, activation='sigmoid'))

optimizer = Adam(learning_rate=0.0001)

# 모델 컴파일
model.compile(optimizer=optimizer, loss='binary_crossentropy', metrics=['accuracy'])

early_stopping = EarlyStopping(patience=5, monitor='val_loss', restore_best_weights=True)

3) 학습

# 모델 학습
history = model.fit(
    train_dataset,
    validation_data=validation_dataset,
    epochs=50,
    callbacks=[early_stopping]
)

from sklearn.metrics import classification_report, confusion_matrix

# 예측 및 평가 메트릭 계산
y_pred = (model.predict(X_test) > 0.5).astype(int)
print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred))

# 학습이 완료된 후에 테스트 데이터셋을 사용하여 모델을 평가합니다.
test_loss, test_accuracy = model.evaluate(test_dataset)
print('Test Loss:', test_loss)
print('Test Accuracy:', test_accuracy)
profile
안녕하세요. 꾸준히 기록하는 hyowon입니다.

0개의 댓글