Lewati ke konten utama

Merekonstruksi Citra MRI Otak Menggunakan Deep Learning (Convolutional Autoencoder)

Dalam tutorial ini, Anda akan belajar dan memahami cara membaca citra magnetic resonance imaging (MRI) otak berformat NIfTI, serta merekonstruksinya menggunakan convolutional autoencoder.
· 13 mnt Baca

Jelajahi bersama AI

Anda akan menggunakan dataset MRI otak 3T untuk melatih jaringan Anda. Untuk mengamati efektivitas model, Anda akan menguji model pada:

  • Citra MRI 3T yang belum pernah dilihat,
  • Citra MRI 3T yang diberi derau (noisy), dan
  • Menggunakan metrik kualitatif: Peak signal to noise ratio (PSNR) untuk mengevaluasi kinerja citra hasil rekonstruksi.

Tutorial ini tidak membahas seluk-beluk pencitraan medis, melainkan berfokus pada sisi deep learning. Catatan: Tutorial ini sebagian besar mencakup implementasi praktis convolutional autoencoder. Jadi, jika Anda belum memahami convolutional neural network (CNN) dan autoencoder, Anda mungkin ingin melihat tutorial CNN dan Autoencoder. Bagian terbaik dari tutorial ini adalah Anda akan memuat volume 3D sebagai citra 2D dan memberikannya ke model. Singkatnya, Anda akan membahas topik-topik berikut dalam tutorial hari ini:

  • Pada awalnya Anda akan mendapat ringkasan tentang Magnetic Resonance Imaging (MRI),
  • Kemudian Anda akan memahami tentang dataset MRI Otak: jenis citra yang dimiliki, mengimpor modul, cara membaca citra, membuat array citra, prapemrosesan citra MRI otak agar dapat dimasukkan ke model, dan akhirnya mengeksplorasi citra MRI otak.
  • Dalam implementasi convolutional autoencoder: Anda akan memasukkan data yang sudah dipraproses ke model, memvisualisasikan plot loss pelatihan dan validasi, menyimpan model terlatih, dan akhirnya melakukan prediksi pada set uji.
  • Berikutnya, Anda akan menguji ketangguhan model pra-terlatih dengan menambahkan derau ke citra uji dan melihat seberapa baik performa model secara kuantitatif.
  • Terakhir, Anda akan menguji prediksi menggunakan metrik kuantitatif peak signal-to-noise ratio (PSNR) dan mengukur kinerja model.

Pengantar Singkat tentang Citra MR

Beragam sistem digunakan dalam pencitraan medis, mulai dari unit MRI terbuka dengan kekuatan medan magnet 0,3 Tesla (T), sistem MRI untuk ekstremitas dengan kekuatan hingga 1,0 T, hingga pemindai seluruh tubuh dengan kekuatan hingga 3,0 T (untuk penggunaan klinis). Tesla adalah satuan untuk mengukur kuat medan magnet pada citra MR. Pemindai MR medan tinggi (7T, 11,5T) menghasilkan SNR (signal-to-noise ratio) yang lebih tinggi meskipun dengan ukuran voxel (patch atau grid 3 dimensi) yang lebih kecil dan karenanya lebih disukai untuk diagnosis yang lebih akurat.

Ukuran voxel yang lebih kecil menghasilkan resolusi yang lebih baik, yang pada gilirannya dapat membantu diagnosis klinis. Namun, kekuatan medan magnet yang digunakan pada pemindai MR memberikan batas bawah pada ukuran voxel untuk menjaga rasio signal-to-noise (SNR) yang baik demi mempertahankan detail citra MR.
Terlepas dari kualitas citra 7T dan 11,5T yang unggul, keduanya jarang digunakan dalam produksi karena kendala biaya.

Menurut publikasi terbaru, jumlah pemindai 3T yang dilaporkan sekitar 20.000 dibandingkan hanya sekitar 40 pemindai 7T.

Memahami Dataset MRI Otak 3T

Dataset MRI otak terdiri dari volume 3D, setiap volume memiliki total 207 irisan/citra MRI otak yang diambil pada irisan berbeda dari otak. Setiap irisan berukuran 173 x 173. Citra berupa grayscale satu kanal. Terdapat total 30 subjek, masing-masing berisi pemindaian MRI seorang pasien. Format citranya bukan jpeg, png, dll., melainkan format NIfTI. Anda akan melihat di bagian selanjutnya cara membaca citra berformat NIfTI.

Dataset terdiri dari citra MR modalitas T1; sekuens T1 secara tradisional dianggap baik untuk evaluasi struktur anatomi. Dataset yang akan Anda gunakan hari ini terdiri dari MRI Otak 3T.

Dataset ini bersifat publik dan tersedia untuk diunduh di sumber ini.

Tip: jika Anda ingin mempelajari cara mengimplementasikan Multi-Layer Perceptron (MLP) untuk tugas klasifikasi dengan dataset MNIST, lihat tutorial ini.

Catatan : Sebelum mulai, harap dicatat bahwa model akan dilatih pada sistem dengan GPU Nvidia 1080 Ti, prosesor Xeon e5 GeForce, dan RAM 32GB. Jika Anda menggunakan Jupyter Notebook, Anda perlu menambahkan tiga baris kode lagi untuk menentukan urutan perangkat CUDA dan perangkat CUDA yang terlihat menggunakan modul bernama os.

Pada kode di bawah, Anda pada dasarnya menyetel variabel lingkungan di notebook menggunakan os.environ. Disarankan melakukan ini sebelum menginisialisasi Keras agar backend Keras, TensorFlow, menggunakan GPU pertama. Jika mesin tempat Anda melatih memiliki GPU pada 0, pastikan menggunakan 0 alih-alih 1. Anda dapat memeriksanya dengan menjalankan perintah sederhana di terminal: misalnya, nvidia-smi

import os
os.environ["CUDA_DEVICE_ORDER"]="PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"]="1" #model will be trained on GPU 1

Mengimpor Modul

Pertama, Anda mengimpor semua modul yang diperlukan seperti cv2, numpy, matplotlib, dan yang terpenting keras, karena Anda akan menggunakan kerangka kerja itu dalam tutorial hari ini!
Untuk membaca citra berformat NIfTI, Anda juga perlu mengimpor modul bernama nibabel.

import os
import cv2
from keras.layers import Input,Dense,Flatten,Dropout,merge,Reshape,Conv2D,MaxPooling2D,UpSampling2D,Conv2DTranspose
from keras.layers.normalization import BatchNormalization
from keras.models import Model,Sequential
from keras.callbacks import ModelCheckpoint
from keras.optimizers import Adadelta, RMSprop,SGD,Adam
from keras import regularizers
from keras import backend as K
Using TensorFlow backend.
import numpy as np
import scipy.misc
import numpy.random as rng
from PIL import Image, ImageDraw, ImageFont
from sklearn.utils import shuffle
import nibabel as nib #reading MR images
from sklearn.cross_validation import train_test_split
import math
import glob
from matplotlib import pyplot as plt
%matplotlib inline
/usr/local/lib/python3.5/dist-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
  "This module will be removed in 0.20.", DeprecationWarning)

Memuat Data

Anda akan menggunakan modul glob yang akan mengembalikan daftar berisi semua volume di folder yang Anda tentukan.

ff = glob.glob('ground3T/*')

Mari cetak elemen pertama dari daftar dan juga periksa panjang daftar: yang dalam kasus kita seharusnya 30.

ff[0]
'ground3T/181232.nii.gz'
len(ff)
30

Sekarang Anda siap memuat volume 3D menggunakan nibabel. Perhatikan bahwa saat Anda memuat volume format NIfTI, Nibabel tidak langsung memuat array citra. Ia menunggu sampai Anda meminta data array. Cara umum untuk meminta data array adalah memanggil metode get_data().

Karena Anda menginginkan irisan 2D, bukan 3D, Anda akan menginisialisasi sebuah daftar di mana setiap kali membaca volume, Anda akan mengiterasi semua 207 irisan lengkap dari volume 3D dan menambahkan setiap irisan satu per satu ke dalam daftar.

images = []

Mari juga cetak bentuk salah satu volume 3D; seharusnya berbentuk 173 x 207 x 173 (koordinat x, y, z).

Catatan: Anda hanya akan menggunakan 51 irisan tengah otak dan bukan semua 207 irisan. Jadi, mari lihat juga cara hanya menggunakan irisan tengah dan memuatnya.

for f in range(len(ff)):
    a = nib.load(ff[f])
    a = a.get_data()
    a = a[:,78:129,:]
    for i in range(a.shape[1]):
        images.append((a[:,i,:]))
print (a.shape)
(173, 51, 173)

Mari analisis bentuk satu irisan dari 207 irisan.

a[:,0,:].shape
(173, 173)

Prapemrosesan Data

Karena images adalah daftar, Anda akan menggunakan modul numpy untuk mengonversi daftar tersebut menjadi array numpy.

images = np.asarray(images)

Saatnya memeriksa bentuk array numpy; dimensi pertama dari array seharusnya 207 x 30 = 6210 dan dua dimensi sisanya 173 x 173.

images.shape
(1530, 173, 173)

Citra pada dataset memang grayscale dengan dimensi 173 x 173, jadi sebelum kita memasukkan data ke model, sangat penting untuk melakukan prapemrosesan. Anda akan terlebih dahulu mengonversi setiap citra 173 x 173 menjadi matriks berukuran 173 x 173 x 1, yang dapat dimasukkan ke jaringan:

images = images.reshape(-1, 173,173,1)
images.shape
(1530, 173, 173, 1)

Selanjutnya, skala ulang data menggunakan teknik normalisasi maks-min:

m = np.max(images)
mi = np.min(images)
m, mi
(3599.0959, -341.83853)
images = (images - mi) / (m - mi)

Mari verifikasi nilai minimum dan maksimum data yang seharusnya 0,0 dan 1,0 setelah penskalaan ulang.

np.min(images), np.max(images)
(0.0, 1.0)

Ini langkah penting: di sini Anda akan menambahkan padding nol pada batas citra agar dimensinya genap dan lebih mudah melakukan downsampling dua kali saat melewatkannya melalui model. Mari tambahkan nol pada tiga baris dan tiga kolom untuk menjadikan dimensinya 176 x 176

temp = np.zeros([1530,176,176,1])
temp[:,3:,3:,:] = images
images = temp

Setelah semua ini, penting untuk membagi data. Agar model Anda dapat melakukan generalisasi dengan baik, Anda membagi data menjadi dua bagian: set pelatihan dan validasi. Anda akan melatih model pada 80% data dan memvalidasinya pada 20% data pelatihan yang tersisa.

Ini juga akan membantu mengurangi kemungkinan overfitting, karena Anda akan memvalidasi model pada data yang tidak dilihat saat fase pelatihan.

Anda dapat menggunakan modul train_test_split dari scikit-learn untuk membagi data dengan tepat:

from sklearn.model_selection import train_test_split
train_X,valid_X,train_ground,valid_ground = train_test_split(images,
                                                             images,
                                                             test_size=0.2,
                                                             random_state=13)

Catatan bahwa untuk tugas ini, Anda tidak memerlukan label pelatihan dan pengujian. Itulah mengapa Anda akan memberikan citra pelatihan dua kali. Citra pelatihan Anda akan bertindak sebagai masukan sekaligus ground truth mirip dengan label pada tugas klasifikasi.

Eksplorasi Data

Sekarang mari analisis bagaimana tampilan citra dalam dataset dan juga lihat kembali dimensinya karena Anda telah menambahkan tiga baris dan kolom ekstra pada citra dengan bantuan atribut array NumPy .shape:

# Shapes of training set
print("Dataset (images) shape: {shape}".format(shape=images.shape))
Dataset (images) shape: (1530, 176, 176, 1)

Dari keluaran di atas, Anda dapat melihat bahwa data berbentuk 6210 x 176 x 176 karena terdapat 6210 sampel, masing-masing berupa matriks berdimensi 176 x 176 x 1.

Sekarang, mari lihat beberapa citra pelatihan dan validasi dalam dataset Anda:

plt.figure(figsize=[5,5])

# Display the first image in training data
plt.subplot(121)
curr_img = np.reshape(train_X[0], (176,176))
plt.imshow(curr_img, cmap='gray')

# Display the first image in testing data
plt.subplot(122)
curr_img = np.reshape(valid_X[0], (176,176))
plt.imshow(curr_img, cmap='gray')
<matplotlib.image.AxesImage at 0x7ff67d5d59b0>
images

Keluaran dari dua plot di atas berasal dari set pelatihan dan validasi. Anda dapat melihat bahwa citra pelatihan dan validasi berbeda; akan menarik untuk melihat apakah convolutional autoencoder mampu mempelajari fitur-fitur dan merekonstruksi citra tersebut dengan baik.

Sekarang Anda siap mendefinisikan jaringan dan memasukkan data ke jaringan. Jadi tanpa basa-basi, mari lanjut ke langkah berikutnya!

Convolutional Autoencoder

Citra berukuran 176 x 176 x 1 atau vektor berdimensi 30976. Anda mengonversi matriks citra menjadi array, menskalakannya antara 0 dan 1, mengubah bentuknya sehingga berukuran 176 x 176 x 1, dan memberikannya sebagai masukan ke jaringan.

Selain itu, Anda akan menggunakan ukuran batch 128; menggunakan batch yang lebih besar seperti 256 atau 512 juga memungkinkan—semuanya bergantung pada sistem tempat Anda melatih model. Ini sangat berpengaruh dalam menentukan parameter pembelajaran dan memengaruhi akurasi prediksi. Anda akan melatih jaringan selama 50 epoch.

batch_size = 128
epochs = 300
inChannel = 1
x, y = 176, 176
input_img = Input(shape = (x, y, inChannel))

Seperti yang mungkin sudah Anda ketahui, autoencoder terbagi menjadi dua bagian: encoder dan decoder.

Encoder: Terdiri dari 3 blok Konvolusi, setiap blok memiliki layer konvolusi diikuti layer batch normalization. Layer max-pooling digunakan setelah blok konvolusi pertama dan kedua.

  • Blok konvolusi pertama memiliki 32 filter berukuran 3 x 3, diikuti oleh layer downsampling (max-pooling),
  • Blok kedua memiliki 64 filter berukuran 3 x 3, diikuti downsampling lainnya,
  • Blok terakhir pada encoder memiliki 128 filter berukuran 3 x 3.

Decoder: Terdiri dari 2 blok Konvolusi, setiap blok memiliki layer konvolusi diikuti layer batch normalization. Layer upsampling digunakan setelah blok konvolusi pertama dan kedua.

  • Blok pertama memiliki 128 filter berukuran 3 x 3 diikuti layer upsampling,
  • Blok kedua memiliki 64 filter berukuran 3 x 3 diikuti upsampling lainnya,
  • Layer terakhir dari encoder memiliki 1 filter berukuran 3 x 3 yang akan merekonstruksi kembali masukan dengan satu kanal.

Layer max-pooling akan melakukan downsampling dua kali setiap kali digunakan, sementara layer upsampling akan melakukan upsampling dua kali setiap kali digunakan.

Catatan: Jumlah filter, ukuran filter, jumlah layer, jumlah epoch pelatihan—semuanya adalah hyperparameter dan sebaiknya diputuskan berdasarkan intuisi Anda sendiri. Anda bebas mencoba eksperimen baru dengan menyetel hyperparameter ini dan mengukur kinerja model. Dan begitulah Anda perlahan mempelajari seni deep learning!

def autoencoder(input_img):
    #encoder
    #input = 28 x 28 x 1 (wide and thin)
    conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(input_img) #28 x 28 x 32
    conv1 = BatchNormalization()(conv1)
    conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv1)
    conv1 = BatchNormalization()(conv1)
    pool1 = MaxPooling2D(pool_size=(2, 2))(conv1) #14 x 14 x 32
    conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(pool1) #14 x 14 x 64
    conv2 = BatchNormalization()(conv2)
    conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv2)
    conv2 = BatchNormalization()(conv2)
    pool2 = MaxPooling2D(pool_size=(2, 2))(conv2) #7 x 7 x 64
    conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(pool2) #7 x 7 x 128 (small and thick)
    conv3 = BatchNormalization()(conv3)
    conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv3)
    conv3 = BatchNormalization()(conv3)


    #decoder
    conv4 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv3) #7 x 7 x 128
    conv4 = BatchNormalization()(conv4)
    conv4 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv4)
    conv4 = BatchNormalization()(conv4)
    up1 = UpSampling2D((2,2))(conv4) # 14 x 14 x 128
    conv5 = Conv2D(32, (3, 3), activation='relu', padding='same')(up1) # 14 x 14 x 64
    conv5 = BatchNormalization()(conv5)
    conv5 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv5)
    conv5 = BatchNormalization()(conv5)
    up2 = UpSampling2D((2,2))(conv5) # 28 x 28 x 64
    decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(up2) # 28 x 28 x 1
    return decoded

Setelah model dibuat, Anda harus mengompilasinya dengan optimizer RMSProp.

Perhatikan bahwa Anda juga harus menentukan jenis loss melalui argumen loss. Dalam kasus ini, mean squared error, karena loss setelah setiap batch akan dihitung antara batch keluaran prediksi dan ground truth menggunakan mean squared error piksel demi piksel:

autoencoder = Model(input_img, autoencoder(input_img))
autoencoder.compile(loss='mean_squared_error', optimizer = RMSprop())

Mari memvisualisasikan layer yang Anda buat pada langkah di atas menggunakan fungsi summary; ini akan menampilkan jumlah parameter (bobot dan bias) pada setiap layer serta total parameter pada model Anda.

autoencoder.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_2 (InputLayer)         (None, 176, 176, 1)       0         
_________________________________________________________________
conv2d_18 (Conv2D)           (None, 176, 176, 32)      320       
_________________________________________________________________
batch_normalization_11 (Batc (None, 176, 176, 32)      128       
_________________________________________________________________
conv2d_19 (Conv2D)           (None, 176, 176, 32)      9248      
_________________________________________________________________
batch_normalization_12 (Batc (None, 176, 176, 32)      128       
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 (None, 88, 88, 32)        0         
_________________________________________________________________
conv2d_20 (Conv2D)           (None, 88, 88, 64)        18496     
_________________________________________________________________
batch_normalization_13 (Batc (None, 88, 88, 64)        256       
_________________________________________________________________
conv2d_21 (Conv2D)           (None, 88, 88, 64)        36928     
_________________________________________________________________
batch_normalization_14 (Batc (None, 88, 88, 64)        256       
_________________________________________________________________
max_pooling2d_6 (MaxPooling2 (None, 44, 44, 64)        0         
_________________________________________________________________
conv2d_22 (Conv2D)           (None, 44, 44, 128)       73856     
_________________________________________________________________
batch_normalization_15 (Batc (None, 44, 44, 128)       512       
_________________________________________________________________
conv2d_23 (Conv2D)           (None, 44, 44, 128)       147584    
_________________________________________________________________
batch_normalization_16 (Batc (None, 44, 44, 128)       512       
_________________________________________________________________
conv2d_24 (Conv2D)           (None, 44, 44, 64)        73792     
_________________________________________________________________
batch_normalization_17 (Batc (None, 44, 44, 64)        256       
_________________________________________________________________
conv2d_25 (Conv2D)           (None, 44, 44, 64)        36928     
_________________________________________________________________
batch_normalization_18 (Batc (None, 44, 44, 64)        256       
_________________________________________________________________
up_sampling2d_5 (UpSampling2 (None, 88, 88, 64)        0         
_________________________________________________________________
conv2d_26 (Conv2D)           (None, 88, 88, 32)        18464     
_________________________________________________________________
batch_normalization_19 (Batc (None, 88, 88, 32)        128       
_________________________________________________________________
conv2d_27 (Conv2D)           (None, 88, 88, 32)        9248      
_________________________________________________________________
batch_normalization_20 (Batc (None, 88, 88, 32)        128       
_________________________________________________________________
up_sampling2d_6 (UpSampling2 (None, 176, 176, 32)      0         
_________________________________________________________________
conv2d_28 (Conv2D)           (None, 176, 176, 1)       289       
=================================================================
Total params: 427,713
Trainable params: 426,433
Non-trainable params: 1,280
_________________________________________________________________

Akhirnya saatnya melatih model dengan fungsi fit() Keras. Model dilatih selama 50 epoch. Fungsi fit() akan mengembalikan objek riwayat; dengan menyimpan hasil fungsi ini ke dalam fashion_train, Anda dapat menggunakannya nanti untuk membuat plot fungsi loss antara pelatihan dan validasi yang akan membantu Anda menganalisis kinerja model secara visual.

Latih Model

autoencoder_train = autoencoder.fit(train_X, train_ground, batch_size=batch_size,epochs=epochs,verbose=1,validation_data=(valid_X, valid_ground))
Train on 1224 samples, validate on 306 samples
Epoch 1/300
1224/1224 [==============================] - 7s - loss: 0.1201 - val_loss: 0.0838
Epoch 2/300
1224/1224 [==============================] - 7s - loss: 0.0492 - val_loss: 0.0534
...
Epoch 299/300
1224/1224 [==============================] - 7s - loss: 1.3101e-04 - val_loss: 6.1086e-04
Epoch 300/300
1224/1224 [==============================] - 7s - loss: 1.0711e-04 - val_loss: 3.9641e-04

Akhirnya! Anda telah melatih model pada dataset sidik jari selama 200 epoch. Sekarang, mari plot kurva loss antara data pelatihan dan validasi untuk memvisualisasikan kinerja model.

loss = autoencoder_train.history['loss']
val_loss = autoencoder_train.history['val_loss']
epochs = range(300)
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
training and validation loss

Pada akhirnya, Anda dapat melihat bahwa loss validasi dan loss pelatihan selaras. Ini menunjukkan bahwa model Anda tidak overfitting: loss validasi menurun dan tidak meningkat, serta nyaris tidak ada celah antara loss pelatihan dan validasi sepanjang fase pelatihan.

Karena itu, dapat dikatakan bahwa kemampuan generalisasi model Anda baik.

Terakhir, saatnya merekonstruksi citra uji menggunakan fungsi predict() dari Keras dan melihat seberapa baik model Anda merekonstruksi data uji.

Simpan Model

Sekarang mari simpan model yang telah dilatih. Ini adalah langkah penting saat Anda bekerja dengan Deep Learning. Karena bobot adalah inti dari solusi untuk masalah yang sedang Anda tangani.

Anda dapat memuat kembali bobot yang disimpan kapan saja ke model yang sama dan melanjutkan pelatihan dari titik terakhir. Misalnya: Jika model di atas dilatih lagi, parameter seperti bobot, bias, fungsi loss, dll. tidak akan mulai dari awal dan pelatihan tidak lagi dari nol.

Hanya dengan satu baris kode Anda dapat menyimpan dan memuat kembali bobot ke dalam model.

autoencoder = autoencoder.save_weights('autoencoder_mri.h5')
autoencoder = Model(input_img, autoencoder(input_img))
autoencoder.load_weights('autoencoder_mri.h5')

Prediksi pada Data Validasi

Karena di sini Anda tidak memiliki data pengujian, mari gunakan data validasi untuk melakukan prediksi pada model yang baru saja Anda latih.

Anda akan melakukan prediksi pada 306 citra validasi yang tersisa dan memplot beberapa citra hasil rekonstruksi untuk memvisualisasikan seberapa baik model merekonstruksi citra validasi.

pred = autoencoder.predict(valid_X)
plt.figure(figsize=(20, 4))
print("Test Images")
for i in range(5):
    plt.subplot(1, 5, i+1)
    plt.imshow(valid_ground[i, ..., 0], cmap='gray')
plt.show()    
plt.figure(figsize=(20, 4))
print("Reconstruction of Test Images")
for i in range(5):
    plt.subplot(1, 5, i+1)
    plt.imshow(pred[i, ..., 0], cmap='gray')  
plt.show()
Test Images
Test Images
Reconstruction of Test Images
Reconstruction of Test Images

Dari gambar di atas, Anda dapat mengamati bahwa model Anda melakukan pekerjaan yang sangat baik dalam merekonstruksi citra uji yang Anda prediksi menggunakan model. Setidaknya secara kualitatif, citra uji dan citra hasil rekonstruksi tampak hampir sama persis.

Mungkin model bisa sedikit lebih baik dalam merekonstruksi beberapa detail lokal yang ada pada citra 3T asli.

Prediksi pada Citra 3T yang Berderau

Pertama, mari tambahkan sedikit derau ke citra validasi dengan mean nol dan deviasi standar 0,03.

[a,b,c,d]= np.shape(valid_X)
mean = 0
sigma = 0.03
gauss = np.random.normal(mean,sigma,(a,b,c,d))
noisy_images = valid_X + gauss

Sekarang saatnya melakukan prediksi pada citra validasi yang berderau. Mari lihat seberapa baik model Anda bekerja pada citra berderau meskipun tidak dilatih dengan citra tersebut.

pred_noisy = autoencoder.predict(noisy_images)
plt.figure(figsize=(20, 4))
print("Noisy Test Images")
for i in range(5):
    plt.subplot(1, 5, i+1)
    plt.imshow(noisy_images[i, ..., 0], cmap='gray')
plt.show()    
plt.figure(figsize=(20, 4))
print("Reconstruction of Noisy Test Images")
for i in range(5):
    plt.subplot(1, 5, i+1)
    plt.imshow(pred_noisy[i, ..., 0], cmap='gray')  
plt.show()
Noisy Test Images
noisy test images
Reconstruction of Noisy Test Images
Reconstruction of Noisy Test Images

Tampaknya model melakukan pekerjaan yang cukup baik, bukan? Bagaimanapun, citra hasil rekonstruksi terlihat lebih baik daripada citra berderau. Terlebih lagi, model sebenarnya tidak pernah melihat citra berderau saat dilatih.

Metrik Kuantitatif: Peak Signal-to-Noise Ratio (PSNR)

Blok PSNR menghitung peak signal-to-noise ratio, dalam desibel (dB), antara dua citra. Rasio ini sering digunakan sebagai pengukuran kualitas antara citra asli dan citra hasil rekonstruksi. Semakin tinggi PSNR, semakin baik kualitas citra hasil rekonstruksi.

Jadi, pertama-tama mari hitung kinerja antara citra validasi dan citra validasi hasil rekonstruksi.

valid_pred = autoencoder.predict(valid_X)
mse =  np.mean((valid_X - valid_pred) ** 2)
psnr = 20 * math.log10( 1.0 / math.sqrt(mse))
print('PSNR of reconstructed validation images: {psnr}dB'.format(psnr=np.round(psnr,2)))
PSNR of reconstructed validation images: 34.02dB

Berikutnya, mari hitung PSNR antara citra validasi asli dan citra berderau yang diprediksi.

noisy_pred = autoencoder.predict(noisy_images)
mse =  np.mean((valid_X - noisy_pred) ** 2)
psnr_noisy = 20 * math.log10( 1.0 / math.sqrt(mse))
print('PSNR of reconstructed validation images: {psnr}dB'.format(psnr=np.round(psnr_noisy,2)))
PSNR of reconstructed validation images: 32.48dB

Nah, tampaknya secara kuantitatif hanya ada perbedaan sekitar 1,54 dB antara PSNR rekonstruksi tanpa derau dan dengan derau. Selain itu, Anda tidak melatih model untuk menangani derau. Bukankah ini menakjubkan?

Lanjutkan Lebih Jauh

Tutorial ini merupakan awal yang baik untuk memahami cara membaca citra berformat NIfTI MRI, menganalisis, melakukan prapemrosesan, dan memasukkannya ke model menggunakan dataset MRI otak 3T. Ini menunjukkan salah satu aplikasi autoencoder yang menarik secara praktis. Jika Anda dapat mengikutinya dengan mudah atau dengan sedikit usaha ekstra, bagus sekali!

Anda dapat bereksperimen dengan arsitektur dan mencoba meningkatkan prediksi baik secara kuantitatif maupun kualitatif. Mungkin dengan menambah layer, mungkin dengan melatihnya lebih lama? Coba kombinasi ini dan lihat apakah itu membantu.

Masih banyak yang perlu dipelajari, jadi mengapa tidak mengikuti kursus Deep Learning in Python dari DataCamp jika Anda belum melakukannya. Anda akan belajar dari dasar dan perlahan beralih menuju penguasaan domain deep learning; ini tak diragukan lagi akan menjadi sumber yang sangat berharga saat Anda belajar bekerja dengan convolutional neural network di Python, cara mendeteksi wajah, objek, dan sebagainya.

Topik

Terkait

blogs

Tutorial Korelasi di R

blogs

40 Pertanyaan Wawancara DBMS Teratas di 2026

blogs

Spaghetti Plot dan Jalur Badai