Mendeteksi Virus Corona Melalui Hasil Scan X-Ray Menggunakan Tensorflow dan Keras

Khairu Aqsara Sudirman

Khairu Aqsara Sudirman

Mar 17, 2020 — 8 mins read

Seperti kebanyakan orang, saya sendiri merasa deg-deg-an dengan wabah virus corona ini, pilek dikit takut corona, padahal biasanya juga sering pilek santai aja, tetapi sekarang pilek itu rasanya beda gitu.... Jujur saya, sebagai manusia hal yang paling menakutkan untuk saat ini adalah kurang nya informasi yang benar tentang virus corona, banyak informasi yang simpang siur dan tidak jelas sumbernya.

san-king seringnya mondar-mandir digoogle mencari tentang informasi virus corona hingga saya sampai di sebuah repository github milik dokter Dr.Joseph Cohen, seorang dokter dari Universitas Monteral. Sekitar semingguan yang lalu Pak Joseph Cohen mengumpulkan hasil x-ray pasien yang terinfeksi virus corona, hingga terbesit di kepala saya untuk mencoba menggunakan X-rays tersebut untuk project kurang kerjaan ini.

pada tulisan kali ini saya tidak akan menjelaskan panjang lebar tentang deep-learning, karena saya yakin banyak tutorial yang bisa teman-teman temui di google yang menjelaskan lebih rinci tentang pembahasan deep-learning,tensorflow,keras dan kawan-kawan-nya.

Discalimer

Tulisan tentang mendeteksi virus corona ini hanya bertujuan untuk pembelajaran semata, tidak digunakan untuk menentukan hasil diagnosis ataupun terinfeksinya seseorang.

tujuan tulisan ini cukup simple, saya hanya ingin berbagi bagaiman memanfaatkan computer vision dan deep learning pada bidang kesehatan, siapa tau kedepanya bisa benar-benar dimanfaatkan.

Mendeteksi Corona Melalui Gambar X-Rays

Hingga saat ini hasil test tentang virus corona super sangat susah untuk didapatkan, saya berterima kasih kepada pak dokter Joseph Cohen untuk Gambarnya. Dari informasi yang saya rangkum, Virus corona akan menyerang sel Epitel yang melapisi saluran pernapasan kita, sejujurnya saya juga tidak mengerti akan hal ini, pengetahuan saya tentang ilmu kedokteran adalah Nol Besar.

Tetapi ada satu hal yang membuat saya antusias, prinsip Sederhana Deep Learning adalah melakukan train data dengan dataset yang tersedia, dataset disini maksudnya kita mengumpulkan sebanyak mungkin sample gambar x-rays dari pasien yang terinfeksi virus corona(Positif), dan sample gambar x-rays dari pasien yang sehat (Negatif), kedua sample gambar itu akan ditraining menggunakan metode tertentu sehingga kita mendapatkan model dari kasus negatif dan kasus positif, tentu saja banyaknya data sample akan sangat mempengaruhi tingkat akurasi yang kita dapatkan.

Seperti yang saya utarakan sebelumnya, disini kita akan menggunakan dataset dari repository github milik Dr.Joseph Cohen, Didalam repository tersebut ada beberapa hasil x-rays seperti Virus Corona, MERS, SARS dan ARDS, karena kita hanya membutuhkan gambar x-rays virus corona jadi kita harus memilah-milah gambar yang sesuai, didalam repositorynya juga Pak Dokter menyertkan sebuah file metadata.csv yang menerangkan data gambar yang tersedia.

Sample gambar X-Rays Positif Virus Corona sudah kita dapatkan, sekarang kita butuh gambar X-Rays dari orang/pasien yang Negatif virus Corona, untuk itu saya menggunakan Data Kaggle's Chest X-Ray Image (Pneumonia), data tersebut memiliki hasil x-rays Orang yang terkena Pneunomia dan Hasil X-Rays orang Normal/Sehat, karena kita butuhnya x-rays Orang sehat maka kita cukup mengambil data x-rays orang sehat.

sejauh ini kita memiliki 25 Gambar x-rays positif Corona dan 25 Gambar x-rays Negatif Corona, saatnya kita menentukan struktur folder dan project.

Struktur Folder

Struktur Folder

Implementasi

pada tulisan ini saya menggunakan python dan virtual environtment dengan python package yang tersintall

numpy
tensorflow
opencv-contrib-python
scikit-image
pillow
imutils
scikit-learn
progressbar2

berikut versi open-cv dan tensorflow yang saya gunakan

Versi OpenCV dan Tensorflow

Versi OpenCV dan Tensorflow

kita sudah menyiapkan gambar sample, struktur folder dan package yang dibutuhkan, sekarang kita coba koding dikit-dikit. Buka file train_model.py dan kita coba masukan kode berikut:

from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications import VGG16
from tensorflow.keras.layers import AveragePooling2D
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Input
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.utils import to_categorical
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from imutils import paths
import matplotlib.pyplot as plt
import numpy as np
import argparse
import cv2
import os

kode diatas memperlihatkan bahwa kita akan menggunakan tensorflow.keras, scikit-learn sebagain library machine learning dan OpenCV untuk pengolahan citra/gambar.

coba teman-teman jalankan script diatas, jika tidak ada error berarti semua library sudah terinstall, jika masih ada error sebaiknya teman-teman install dulu library-libray yang kurang.

tahap selanjutnya kita akan membuat terminal interaktif, dengan menggunakan ArgumenParser() dari python, sebenarnya ini tidak wajib, hanya saja bisa menjadi lebih interaktif.

ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
	help="folder dataset")
ap.add_argument("-p", "--plot", type=str, default="plot.png",
	help="Output Gambar Plot")
ap.add_argument("-m", "--model", type=str, default="corona.model",
	help="Nama Model")
args = vars(ap.parse_args())


INIT_LR = 1e-3 # Learning Rate
EPOCHS = 25 # Epoch
BS = 8 # Batch Size

sekarang kita coba untuk membaca gambar dataset yang kita punya dengan OpenCV dan kemudian merubahnya menjadi numpy array agar kita memiliki gambar dalam bentuk key:value

print("[INFO] loading Gambar Dataset...")
imagePaths = list(paths.list_images(args["dataset"]))
data = []
labels = []
# loop sebanyak gambar dalam folder
for imagePath in imagePaths:
	# ambil nama folder sebagai label
	label = imagePath.split(os.path.sep)[-2]
	# load Gambar, swap color channels, dan resize gambar jadi 224x224 pixels
	image = cv2.imread(imagePath)
	image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
	image = cv2.resize(image, (224, 224))

	data.append(image)
	labels.append(label)
# convert data dan labels ke NumPy arrays
# dengan intensities dalam range [0, 255]
data = np.array(data) / 255.0
labels = np.array(labels)

saya rasa potongan kode diatas cukup mudah untuk dipahami, mulai dari baca semua isi folder dataset kemudian loop semua sub folder yang ditemukan, load gambar dengan OpenCV, Konversi warnanya menjadi RGB Channels, resize gambar kedalam ukuran 224x224 pixel (untuk kebutuhan CNN=Convolutional Neural Network) kemudian append/tambah data dan label kedalam list.

langkah selanjutnya, kita akan menggunakan one-hot encoding pada labels dan membuat trainig split-nya.

# one-hot encoding pada labels
lb = LabelBinarizer()
labels = lb.fit_transform(labels)
labels = to_categorical(labels); print(labels)
# partisi data menjadi data training dan testing
# 80% training dan 20% untuk testing
(trainX, testX, trainY, testY) = train_test_split(data, labels,
	test_size=0.20, stratify=labels, random_state=42)
#inisialisasi training data menggunakan augmentation object
trainAug = ImageDataGenerator(
	rotation_range=15,
	fill_mode="nearest")

mungkin teman-teman banyak yang bingung dengan istilah-istilah pada Machine/Deep learning, One-Hot Encoding maksudnya merubah format label menjadi kira-kira seperti ini

[[0.,1.]
 [0.,1.]]

Setiap hasil encoded pada label memiliki 2 elemen array yang mana 1 disebut sebagai Hot dan 0 Sebagai Not, kemudian ada istilah data augmentation, maksudnya kita membuat semua gambar dirotasi se-arah dan berlawanan arah jarum jam secara random dengan harapan hasil modeling nantinya bisa lebih akurat, karena pada realita nya gambar itu bentuk dan ukuranya macam-macam.

pada tahap ini, saatnya kita menggunakan VGGNet Model pada data yang akan kita training.bingung dengan maksud VGGNet Model ? teman-teman bisa membacanya disini

# VGG16 network
baseModel = VGG16(weights="imagenet", include_top=False,
	input_tensor=Input(shape=(224, 224, 3)))

headModel = baseModel.output
headModel = AveragePooling2D(pool_size=(4, 4))(headModel)
headModel = Flatten(name="flatten")(headModel)
headModel = Dense(64, activation="relu")(headModel)
headModel = Dropout(0.5)(headModel)
headModel = Dense(2, activation="softmax")(headModel)
model = Model(inputs=baseModel.input, outputs=headModel)
# loop semua layer pada base model kemudian set freeze
# agar tidak ikut terupdate pada proses training pertama
for layer in baseModel.layers:
	layer.trainable = False

pada kode diatas, kita membentuk full-connected layer menggunakan POOL=>FC = SOFTMAX dan menginsert hasilnya pada VGG16, dengan begitu kita siap untuk melakukan training model pada data

# Kompail Model
print("[INFO] Memproses Training Model...")
opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
model.compile(loss="binary_crossentropy", optimizer=opt,
	metrics=["accuracy"])

print("[INFO] Sedang Memproses Model...")
H = model.fit_generator(
	trainAug.flow(trainX, trainY, batch_size=BS),
	steps_per_epoch=len(trainX) // BS,
	validation_data=(testX, testY),
	validation_steps=len(testX) // BS,
	epochs=EPOCHS)

pada kode diatas, kita melakukan model training dengan model rate decay dan Adam Optimizer, dengan begitu sekarang kita memiliki 2 Klasifikasi, disini saya menggunakan metode binary_crossentropy dan tidak menggunakan categorical_cronssentropy.

sekarang kita akan menggunakan Keras fit_generator untuk melakukan training sebelumnya dan melakukan testing pada 20% data yang kita split sebelumnya.

# Testing Prediksi
print("[INFO] Evaluasi network...")
predIdxs = model.predict(testX, batch_size=BS)
# Temukan index semua image yang di test
# Tentukan label dari nilai predicted probability tertinggi
predIdxs = np.argmax(predIdxs, axis=1)
print(classification_report(testY.argmax(axis=1), predIdxs,
	target_names=lb.classes_))

pada tahap ini seharusnya model sudah bisa digunakan, tetapi biasanya jika kita melakukan training model pada deep-learning tidak afdol rasanya jika tidak menyertakan classification report

# Hitung confusion matrix
# accuracy, sensitivity, dan specificity
cm = confusion_matrix(testY.argmax(axis=1), predIdxs)
total = sum(sum(cm))
acc = (cm[0, 0] + cm[1, 1]) / total
sensitivity = cm[0, 0] / (cm[0, 0] + cm[0, 1])
specificity = cm[1, 1] / (cm[1, 0] + cm[1, 1])
print(cm)
print("acc: {:.4f}".format(acc))
print("sensitivity: {:.4f}".format(sensitivity))
print("specificity: {:.4f}".format(specificity))

kemudian saatnya kita simpan model hasil traning dalam format h5

print("[INFO] Menyimpan Model...")
model.save(args["model"], save_format="h5")

sekarang mari kita coba menjalankan train_model.py, perhatian, Komputer atau CPU teman-teman akan sedikit menjerit pada saat menjalankan model Training, karena proses ini membutuhkan CPU yang besar (Laptop saya tidak menggunakan Kartu Grafis)

python train_model.py --dataset dataset
Hasil Training Model

Hasil Training Model

setelah model training selesai dilalukan, (Laptop saya butuh waktu sekitar 15 Menit untuk melakukan training) saatnya kita mencoba model hasil training kita, berikut script sederhana untuk melakukan prediksi dengan menggunakan model yang telah kita training sebelumnya

import cv2
import tensorflow as tf
import numpy as np
import argparse
import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
ap = argparse.ArgumentParser()
ap.add_argument("-g", "--gambar", required=True,help="Gambar yang akan dites")
ap.add_argument("-m", "--model", type=str, default="corona.model",help="Nama Model")
args = vars(ap.parse_args())

labels=['Negatif','Positif']
data = []

def prepare(filepath):
    image = cv2.imread(filepath)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    image = cv2.resize(image, (224, 224))
    data.append(image)
prepare(args['gambar'])
data = np.array(data) / 255.0

model = tf.keras.models.load_model(args['model'])
prediksi = model.predict(data)
prediksi_index = np.argmax(prediksi, axis=1)
max_val = int(np.amax(prediksi)*100)
print("Prediksi Hasil {persen}% {hasil} Covid-19".format(hasil=labels[int(prediksi_index[0])],persen=max_val))
Hasil Prediksi Dengan Model

Hasil Prediksi Dengan Model


karena kebijakan Google tidak bisa menayangkan video dengan content virus corona di website, teman-teman bisa melihat videonya di alamat berikut https://drive.google.com/file/d/1G7IAuMenpovHcuP_X01JbDu0Qj9dEIue/view

hasil diatas tidak bisa diklaim sebagai hasil final, ini hanya sekedar pembelajaran, dibutuhkan expert tentang virus serta dokter-dokter yang profesional untuk menentuk apakah seseorang terinfeksi corona atau tidak.

dari video dan gambar diatas, kita bisa melihat bahwa tingkat akurasi untuk mendeteksi infeksi virus corona melalui gambar x-rays mencapai 90-92% dengan menggunakan sample data yang ada pada folder dataset, tingkat akurasi sangat-sangat ditentukan dengan jumlah sample data yang masuk dalam model train, hasil prediksi bisa saja salah (false positive) karena kualitas gambar dari x-rays dan banyaknya sample sangat mempengaruhi hasil dari prediksi itu sendiri.

dengan hanya menggunakan 25 sample data dari Positif dan Negatif hasil dari prediksi ini belum bisa kita katakan benar-benar akurat, sejatinya dibutuhkan ribuan hingga ratusan ribu gambar dataset untuk bisa mendapatkan tingkat akurasi yang mungkin mendekati akurat.

saya harus memperingatkan teman-teman dan semua yang membaca tulisan ini, saya bukan seorang yang ahli dalam per-virusan, sekali lagi tulisan ini hanya untuk tujuan pembelajaran semata.

Sources Code Tersedia DiGithub, silahkan teman-teman download dan coba https://github.com/khairu-aqsara/covid19

linux deep-learning python php
Read More

Memahami Reflection Class pada PHP

dari arti-nya saja teman-teman mungkin sudah bisa menebak maksudnya, ya sederhananya dalam bahasa indonesia refleksi, tetapi dalam dunia pemrograman refleksi ini bisa kita sebut sebagai kemampuan sebuah program untuk mengidentifikasi dirinya sendiri, maksudnya dengan adanya fitur ini sebuah class dapat melihat method dan property apa saja yang dimilikinya.

Read More

Membuat VPN Server Sendiri

VPN hanyalah sebuah jembatan atau jalur lewat data khusus yang ada pada jaringan internet, maksudnya khusus adalah pada saat data di transmisikan(diantar) dalam bentuk tersandikan (enkripsi) untuk menjaga kerahasiannya dari jaringan publik.