1) 미션1 : Data Preprocessin
- 제공된 데이터 : Car_Images.zip
- Car_Images : 차량의 정상/파손 이미지 무작위 수집
2) 미션2 : CNN 모델링
3) 미션3 : Transfer Learning
!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('압축이 이미 해제되었거나 이미 폴더가 존재합니다.')
- 모델링을 위한 데이터 구조 만들기
- 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)
- 세부요구사항
- 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))
- 세부요구사항
- 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)