
📌요약
- k-ium 의료인공지능경진대회에서 개최한 본 대회는 익명화된 뇌혈관조영술 영상을 기반으로
뇌동맥류 여부를 진단하고, 뇌동맥류가 발견된 위치를 진단하는 소프트웨어를 개발하는 것을
목표으로 한다

🗒️개발 내용
데이터 분석
- 본 대회에서 제공한 데이터는 [train_set] 디렉토리 내에 9016장의 뇌동맥류를 진단할 수 있
는 뇌 혈관 영상과 train.csv 파일이 존재한다.
9016장의 영상은 총 1127명의 환자에 대하여 조영제를 주입한 위치와 촬영한 각도에 따라 각 환자당 8장의 영상이다.
train.csv 파일에는1127명의 환자에 대하여 뇌동맥류 여부와 뇌동맥류가 발견된 위치에 대한 값이 0과 1로 입력되어 있다. 값이 0일때는 뇌동맥류가 발견되지 않았음을 의미하고, 값이 1일때는 뇌동맥류가 발견되었음을 의미한다. 또한, 뇌동맥류가 발견된 환자에 대하여 해당 뇌동맥류가 발견된 위치에 1로 입력이 되어있다.
데이터 전처리
- 본 대회에서 제공한 데이터 총 9016의 영상에 대해서 좌우 반전, 회전, 이동, 전단, 밝기 조절을 통해서 데이터의 양을 증식시켜 훈련에 사용하였다.
총 54096개의 영상 중 44000개를training 이미지로 사용하였고, 8800개의 영상을 validation 이미지로 사용하였다. 나머지1296개의 영상은 test 이미지로 사용하였다.
모델 구성
- 모델은 컴퓨터 자원과 대회 기간을 고려하여 모델을 찾고 fine tuning 하기로 하였고,
backbone은 efficientnetb0를 사용하고 마지막에 21로 구별하여 score을 나타내게 하였다.

'''
데이터 증식 , 모델 훈련, 저장 하는 코드입니다
부족한 훈련데이터를 보충하기 위해서 augmentation을 활용하여 데이터 양을 늘려 efficientnet 구조를 활용하여 모델을 작성하고
aug_efficientnet.h5 로 모델을 저장하였습니다
모델의 구조도는 aug_efficientnet.png 파일을 통해 확인할수 있습니다.
모델 훈련시에 사용되는 파일의 경로 잘 지정하여 사용해주세요.
#라이브러리 버전
imgaug version: 0.4.0
tensorflow version: 2.13.0
cv2 version: 4.7.0
pandas version: 1.4.4
numpy version: 1.23.5
'''
import imgaug.augmenters as iaa
from tensorflow import keras
import cv2
import glob
import pandas as pd
import numpy as np
from tensorflow.keras.utils import plot_model
import tensorflow as tf
from tensorflow.keras.applications import EfficientNetB0
from tensorflow.keras.layers import GlobalAveragePooling2D, Dense
from tensorflow.keras.models import Sequential
from tensorflow.keras.callbacks import ModelCheckpoint
import imgaug.augmenters as iaa
import numpy as np
# Augmentation을 위한 객체 생성
augmenter_flip = iaa.Fliplr(1.0) # 좌우 반전
augmenter_rotate = iaa.Affine(rotate=(-180, 180)) # 회전
augmenter_translate = iaa.Affine(translate_percent={"x": (-0.2, 0.2), "y": (-0.2, 0.2)}) # 이동
augmenter_shear = iaa.Affine(shear=(-45, 45)) # 전단
augmenter_brightness = iaa.Multiply((0.8, 1.2)) # 밝기 조절
# 이미지를 저장할 리스트
image_list = []
# 모델 훈련을 위한 train 이미지들 load
# 예시 image_files = glob.glob('C:/Users/USER/Desktop/brain_aneurysm_contest/2023_k_ium_composition/train_set/*.jpg')
image_files = glob.glob('훈련에 사용되는 이미지 폴더 경로/*.jpg')
# 원본 이미지 생성 및 augmentation 적용
for image_file in image_files:
image = cv2.imread(image_file)
# 이미지 크기를 동일하게 조정
image = cv2.resize(image, (224, 224))
# 원본 이미지 추가
image_list.append(image)
# 좌우 반전 augmentation
augmented_flip = augmenter_flip.augment_image(image)
image_list.append(augmented_flip)
# 회전 augmentation
augmented_rotate = augmenter_rotate.augment_image(image)
image_list.append(augmented_rotate)
# 이동 augmentation
augmented_translate = augmenter_translate.augment_image(image)
image_list.append(augmented_translate)
# 전단 augmentation
augmented_shear = augmenter_shear.augment_image(image)
image_list.append(augmented_shear)
# 밝기 조절 augmentation
augmented_brightness = augmenter_brightness.augment_image(image)
image_list.append(augmented_brightness)
# 이미지 리스트를 np.array로 변환
x_train = np.array(image_list)
#######################################################################
# CSV 파일 경로
# 예시 csv_file = ""
csv_file = " 훈련에 사용할 csv 파일의 경로 "
# CSV 파일 읽기
data = pd.read_csv(csv_file)
# 열 이름 리스트
column_names = ['L_ICA', 'R_ICA', 'L_PCOM', 'R_PCOM', 'L_AntChor', 'R_AntChor', 'L_ACA', 'R_ACA',
'L_ACOM', 'R_ACOM', 'L_MCA', 'R_MCA', 'L_VA', 'R_VA', 'L_PICA', 'R_PICA', 'L_SCA',
'R_SCA', 'BA', 'L_PCA', 'R_PCA']
# 데이터를 저장할 리스트
vector_list = []
# 각 열에 해당하는 값을 가져와서 벡터로 만들어 리스트에 추가
for column_name in column_names:
column_values = data[column_name].values
vector_list.append(column_values)
# 리스트의 요소를 열 방향으로 합쳐서 NumPy 배열로 변환
t_train = np.column_stack(vector_list)
# 8배(1사람당 8장) * 6배(augmentation)
t_train = np.repeat(t_train, 48,axis=0)
print(t_train.shape)
###########################################################################
# augmentation 한 데이터를 이용해 모델의 훈련,검증,테스트에 활용하도록 나누었습니다.
x_test = x_train[52800:,:] # 1296
x_val = x_train[44000:52800,:] # 8800
x_train = x_train[:44000,:] # 44000
t_test = t_train[52800:,:] # 1296
t_val = t_train[44000:52800,:] # 8800
t_train = t_train[:44000,:] # 44000
#############################################################################
# 모델 구축
model = Sequential()
model.add(EfficientNetB0(include_top=False, input_shape=(224, 224, 3))) # EfficientNetB0의 합성곱 기반부분만 가져옵니다.
model.add(GlobalAveragePooling2D())
model.add(Dense(21, activation='sigmoid')) # 21개의 뇌 부위에 대한 이진 분류를 위해 sigmoid 활성화 함수를 사용합니다.
# 모델 컴파일
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
# 모델 훈련 중 가장 좋은 성능을 보인 모델 저장을 위한 콜백
checkpoint = ModelCheckpoint('aug_efficientnet.h5', monitor='val_accuracy', save_best_only=True, mode='max', verbose=1, save_format='h5')
# 모델 훈련
history = model.fit(x_train, t_train, epochs=10, batch_size=32, validation_data=(x_val, t_val), callbacks=[checkpoint])
# 모델 구조 시각화
plot_model(model, to_file='aug_efficientnet.png', show_shapes=True)
- 출력된 환자 한명당 8장의 예측값을 Late fusion 기술 중 max 기법을 사용하여 8장 중 확률값이 가장 높은 예측값을 저장한다.
임계값을 설정하여 0과 1 사이의 실수값인 예측값을 0 혹은 1의 정수값으로 21개의 뇌 부위에 대하여 정수값을 저장한다.
앞서 8장을 바탕으로 예측하였던 결과값의 각 row당 임계값 이상의 값이 있다면, row의 최대값을 저장하고, 임계값 미만의 값이 있다면, row의 최소값을 저장하도록 하여 Aneurysm에 실수값을 0과 1 사이의 값으로 저장하였다