데이터 로드, 전처리
# ! kaggle datasets download -d pranavraikokte/covid19-image-dataset
import os
import cv2
import numpy as np
from sklearn.model_selection import train_test_split
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.applications import VGG19
from tensorflow.keras.layers import Dense, Flatten, Dropout
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from matplotlib import pyplot as plt
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
# 데이터셋 경로 설정
dataset_path = 'C:\\\\Users\\\\seeju\\\\AI4FW\\\\aifw\\\\AI4FW023\\\\Covid19-dataset\\\\train' # Kaggle 데이터셋의 루트 폴더 경로
# 클래스별 레이블 리스트 생성 (폴더 이름이 레이블)
class_names = sorted(os.listdir(dataset_path)) # 폴더 이름을 기준으로 정렬된 클래스 리스트 생성
image_data = []
labels = []
for class_name in class_names:
class_folder = os.path.join(dataset_path, class_name)
for image_name in os.listdir(class_folder):
image_path = os.path.join(class_folder, image_name)
image = cv2.imread(image_path) # 이미지 읽기
if image is not None: # 이미지가 none인지 아닌지 구별하는 if
image = cv2.resize(image, (150, 150)) # 이미지 크기 조정
image_data.append(image)
labels.append(class_names.index(class_name))
else:
print(f"Error loading image: {image_path}")
# 데이터를 NumPy 배열로 변환 및 레이블 One-Hot 인코딩
image_data = np.array(image_data)
image_data = np.expand_dims(image_data, axis=-1) # Conv2D에 맞게 차원 확장
labels = to_categorical(labels, num_classes=len(class_names))
# 학습/검증 데이터셋 분할 (전체 데이터 중 20%를 검증 데이터로 사용)
X_train, X_val, y_train, y_val = train_test_split(image_data, labels, test_size=0.2, random_state=42)
VGG19 로드 및 학습
# VGG19 모델 로드 (사전 학습된 ImageNet 가중치 사용)
# include_top=False로 설정하여 상단의 fully-connected 레이어를 제거한 채 로드
base_model = VGG19(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
# VGG19의 기본 가중치를 고정 (기존 가중치는 학습되지 않도록 설정)
for layer in base_model.layers:
layer.trainable = False
# 커스텀 분류 레이어 추가 (기본 VGG19 모델의 상단에 추가하여 사용할 분류기 정의)
x = Flatten()(base_model.output) # 이미지를 일차원으로 변환 (Flatten 레이어)
x = Dense(128, activation='relu')(x) # 128개의 뉴런을 가진 Dense 레이어와 ReLU 활성화 함수 사용
x = Dropout(0.5)(x) # 과적합 방지를 위해 50% Dropout 적용
x = Dense(len(class_names), activation='softmax')(x) # 출력 레이어 (클래스 수 만큼 노드 생성, 소프트맥스 활성화로 확률 출력)
# 모델 생성 (VGG19 모델과 커스텀 분류 레이어를 결합하여 새로운 모델 생성)
model = Model(inputs=base_model.input, outputs=x) # VGG19 모델과 위에서 우리가 만든 레이어를 합쳐 새로운 모델 생성.
# 모델 컴파일 (Adam 옵티마이저, categorical_crossentropy 손실 함수, 정확도 측정)
model.compile(optimizer=Adam(learning_rate=0.001), loss='categorical_crossentropy', metrics=['accuracy'])
# learning_rate(학습률)가 낮은 이유
#사전 학습된 모델의 미세 조정: VGG19는 많은 데이터를 통해 특징을 잘 학습한 상태.
#사전 학습된 가중치를 완전히 재학습하는 것보다, 모델이 새로운 데이터셋에 적응하도록 조금씩 조정하는 것이 더 효과적
#학습률을 너무 높게 설정하면 이미 최적화된 가중치가 크게 변동되어 오히려 성능이 떨어질 수 있다.
# 모델 요약 출력 (각 레이어의 상세 정보와 총 매개변수 개수 출력)
model.summary()
# 모델 학습 (에포크 10, 배치 사이즈 32로 학습)
epochs = 10
history = model.fit(X_train, y_train, validation_data=(X_val, y_val), epochs=epochs, batch_size=32, verbose=1)
# 학습 결과 시각화 (정확도와 손실을 그래프로 표시)
plt.plot(history.history['accuracy'], label='Train Accuracy')
plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
plt.plot(history.history['loss'], label='Train Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.legend()
plt.show()

VGG19_코드_상세설명 (화살표 클릭)
예측 결과 평가
# 예측 결과 평가
# 검증 데이터셋에 대해 예측 수행
y_val_pred = model.predict(X_val)
y_val_pred_classes = np.argmax(y_val_pred, axis=1) # 예측 결과를 클래스 인덱스로 변환
y_val_true_classes = np.argmax(y_val, axis=1) # 실제 레이블을 클래스 인덱스로 변환
# Classification Report 출력 (정밀도, 재현율, F1 점수 등 평가 지표 제공)
print("Classification Report:")
print(classification_report(y_val_true_classes, y_val_pred_classes, target_names=class_names))
# Confusion Matrix 출력 (모델의 분류 성능을 시각화하여 정확한 예측 및 오류 확인)
cm = confusion_matrix(y_val_true_classes, y_val_pred_classes)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt="d", cmap="Blues", xticklabels=class_names, yticklabels=class_names)
plt.xlabel("Predicted Label")
plt.ylabel("True Label")
plt.title("Confusion Matrix")
plt.show()

