Brain Tumor Classification (MRI)
Classify MRI images into four classes
www.kaggle.com
https://www.kaggle.com/code/rohandeysarkar/tumor-classification
Tumor Classification
Explore and run machine learning code with Kaggle Notebooks | Using data from Brain Tumor Classification (MRI)
www.kaggle.com
Brain Tumor Classification (MRI)
Classify MRI images into four classes
aim is to predict whether a patient has any kind of tumor or not based on a MRI scan of brain.
Steps Involved
- Import all the necessary modules & load the data.
- Observe the data and determine the number of output classes (4 in this case).
- Define labels for each of the output class.
- Read & save the images along with their respective labels.
- Create Train and Test set.
- Define the CNN model & set the number of output classes.
- Train & observe the model, then tune hyperparams accordingly.
- Predict & save our model.
Imports
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import seaborn as sns
import cv2
from sklearn.model_selection import train_test_split
from tensorflow.keras.applications.mobilenet import MobileNet
from keras.applications.mobilenet_v2 import MobileNetV2
from keras.applications.vgg16 import VGG16
from keras.models import Sequential
from keras.callbacks import EarlyStopping
from keras.layers import Dropout, Dense, BatchNormalization
from tensorflow.keras.utils import to_categorical
from keras.preprocessing.image import ImageDataGenerator
from keras.callbacks import EarlyStopping, ReduceLROnPlateau
from tqdm import tqdm
from sklearn.utils import shuffle
Checking available files/folders
path = "../input/brain-tumor-classification-mri"

Define labels of the output classes
labels = ['glioma_tumor','no_tumor','meningioma_tumor','pituitary_tumor']
class_map = {
'no_tumor': 0,
'glioma_tumor' :1,
'meningioma_tumor' :2,
'pituitary_tumor' :3
}
inverse_class_map = {
0: 'no_tumor',
1: 'glioma_tumor',
2: 'meningioma_tumor',
3: 'pituitary_tumor'
}

Set Hyperparameters
h, w = 224, 224
batch_size = 32
epochs = 100
Reading the image & saving as np.array, along with their respective labels
IMAGE = []
LABELS = []
for label in labels:
folderPath = os.path.join('C:/input/brain-tumor-classification-mri/Training', label)
for j in tqdm(os.listdir(folderPath)):
img = cv2.imread(os.path.join(folderPath, j))
img = cv2.resize(img,(h,w))
IMAGE.append(img)
LABELS.append(class_map[label])
for label in labels:
forlderPath = os.path.join('C:/input/brain-tumor-classification-mri/Testing', label)
for j in tqdm(os.listdir(folderPath)):
img = cv2.imread(os.path.join(folderPath,j))
img = cv2.resize(img,(h,w))
IMAGE.append(img)
LABELS.append(class_map[label])
X = np.array(IMAGE)
y = np.array(LABELS)

Looking at different types of tumor
plt.figure(figsize=(16,12))
path = 'C:/input/brain-tumor-classification-mri/Training/'
fileNames = ['glioma_tumor/gg (10).jpg', 'meningioma_tumor/m (108).jpg', 'no_tumor/image (16).jpg', 'pituitary_tumor/p (12).jpg']
fileLabels = ['glioma_tumor', 'meningioma_tumor', 'no_tumor', 'pituitary_tumor']
for i in range(4):
ax = plt.subplot(4,4,i+1)
img = mpimg.imread(path + fileNames[i])
img = cv2.resize(img, (h,w))
plt.imshow(img)
plt.title(fileLabels[i])
plt.axis("off")

Create Train & Test sets
X, y = shuffle(X,y, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, to_categorical(y), test_size=0.1, random_state=42)

★ Q. to_categorical 함수를 이용하여 원-핫 인코딩을 하는 이유 ?
to_categorical(y)
훈련 데이터의 개수가 n이고 클래스의 개수가 k일 때, to_categorical 함수는 입력받은 (n) 크기의 1차원 정수 배열을 (n, k) 크기의 2차원 배열로 변경합니다. 이 배열의 두 번째 차원의 인덱스가 클래스 값을 의미한다.
예를 들어 to_categorical([0, 2])는 [[1, 0, 0], [0, 0, 1]]을 반환한다.
Define CNN mode
# base_model = MobileNet(
# input_shape=(h, w, 3),
# weights='imagenet',
# include_top=False,
# pooling='avg'
# )
base_model = VGG16(
input_shape=(h,w,3),weights='imagenet',include_top=False,pooling = 'max')
base_model.summary()
★ 전이학습 ★
딥러닝 모델 훈련을 위한 전이학습
전이학습은 하나의 작업을 위해 훈련된 모델을 유사 작업 수행 모델의 시작점으로 활용하는 딥러닝 접근법입니다. 일반적으로 신경망은 처음부터 새로 훈련하는 것보다 전이학습을 통해 업데이트하고 재훈련하는 편이 더 빠르고 간편합니다. 이 접근법은 여러 응용 분야 중에서도 특히 객체 검출, 영상 인식, 음성 인식 분야에 흔히 사용됩니다.
전이학습은 다음과 같은 이유로 널리 쓰입니다.
- 대용량 데이터셋으로 이미 훈련된 널리 쓰이는 모델을 재사용함으로써 더 적은 레이블 지정 데이터를 사용하여 모델을 훈련할 수 있습니다.
- 훈련 시간과 연산 리소스를 줄일 수 있습니다. 전이학습에서는 사전 훈련된 모델이 이전의 학습을 기반으로 이미 가중치를 학습했으므로 가중치가 처음부터 새로 학습되지 않습니다.
- GoogLeNet과 ResNet처럼 널리 쓰이는 아키텍처를 포함해 딥러닝 연구 커뮤니티에서 개발되는 모델 아키텍처를 활용할 수 있습니다.
전이학습 응용 분야에 가장 적합한 모델
선택할 수 있는 전이학습 모델이 많은 만큼 각각의 장단점과 프로젝트의 전반적 목표를 염두에 두는 것이 중요합니다. 예를 들어 정확도가 비교적 낮은 신경망이라도 새로운 딥러닝 작업에는 완벽하게 잘 맞을 수 있습니다. 바람직한 접근법은 다양한 모델을 시험하여 원하는 응용 분야에 가장 잘 맞는 모델을 찾는 것입니다.
시작하는 데 적합한 단순한 모델. AlexNet, GoogLeNet, VGG-16, VGG-19와 같은 단순한 모델을 사용하면 빠르게 반복하면서 다양한 데이터 전처리 단계와 훈련 옵션을 실험할 수 있습니다. 어떤 설정이 효과적인지 파악한 다음에는 더 정확한 신경망을 시험해 보면서 결과가 개선되는지 확인할 수 있습니다.
가볍고 연산적으로 효율적인 모델. 배포 환경에서 모델 크기가 제한되는 경우에는 SqueezeNet, MobileNet-v2 및 ShuffleNet을 사용하는 것이 좋습니다.
심층 신경망 디자이너를 사용하여 다양한 사전 훈련된 모델이 프로젝트에 맞는지 신속히 평가하고 서로 다른 모델 아키텍처의 장단점을 더 정확히 파악할 수 있습니다.
https://dodonam.tistory.com/347
https://kr.mathworks.com/discovery/transfer-learning.html
Set the no. of output class of the model
base_model.trainable = False # layer.trainable =False : 모든 레이어의 가중치 훈련 불가능 설정
output_class = 4
model = Sequential([
base_model,
Dropout(rate=0.5),
Dense(output_class, activation='softmax')
])
model.compile(loss='categorical_crossentropy',optimizer='adam', metrics=['accuracy'])
model.summary()
Defining Callbacks
조기종료(early stopping)은 Neural Network가 과적합을 회피하도록 만드는 정칙화(regularization) 기법 중 하나이다[1]. 훈련 데이터와는 별도로 검증 데이터(validation data)를 준비하고, 매 epoch 마다 검증 데이터에 대한 오류(validation loss)를 측정하여 모델의 훈련 종료를 제어한다. 구체적으로, 과적합이 발생하기 전 까지 training loss와 validaion loss 둘다 감소하지만, 과적합이 일어나면 training loss는 감소하는 반면에 validation loss는 증가한다. 그래서 early stopping은 validation loss가 증가하는 시점에서 훈련을 멈추도록 조종한다.
TensorFlow 1.12에 포함된 Keras에서, EarlyStopping은 두 개의 파라미터를 입력받는다. monitor는 어떤 값을 기준으로 하여 훈련 종료를 결정할 것인지를 입력받고, patience는 기준되는 값이 연속으로 몇 번 이상 향상되지 않을 때 종료시킬 것인지를 나타낸다. 위 예제로 보면 early stopping은 validation loss를 기준으로 훈련을 제어할 것이다. 이 때 validaion loss가 이전 epoch보다 증가되었다고 하여 바로 중지하지는 않고, 5번 연속으로 validaion loss가 낮아지지 않는 경우에 종료하도록 설정하였다. 즉, patience는 모델이 아직 더 향상될 수 있지만, 우연히 validation loss가 낮게 나와버려서 훈련이 종료되버리는 상황을 피하기 위한 옐로우 카드라고 생각하면 된다.
- monitor : 어떤 값을 기준으로 하여 훈련 종료를 결정할 것인가
- patience : 기준이 되는 값이 연속으로 몇 번 이상 향상되지 않을 때 종료
earlystop = EarlyStopping(monitor = 'val_loss', patience=5)
# early stopping은 validation loss를 기준으로 훈련을 제어
# 5번 연속으로 validation loss 가 낮아지지 않는 경우에 종료
learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc',
patience=2,
verbose=1,
factor=0.5,
min_lr=0.00001)
callbacks = [earlystop, learning_rate_reduction]
Image Augmentation
datagen = ImageDataGenerator(rescale=1./255,shear_range=0.2,zoom_range=0.2,horizontal_flip=True)
Training our model
history = model.fit(datagen.flow(X_train,y_train,batch_size=batch_size), validation_data=(X_test,y_test),
steps_per_epoch = len(X_train) / batch_size , epochs = epochs, callbacks = callbacks)
Checking model performance
Predicting with our model
Checking prediction accuracy with confusion matrix