मुख्य सामग्री पर जाएँ

डीप लर्निंग (Convolutional Autoencoder) से ब्रेन MRI इमेजों का पुनर्निर्माण

इस ट्यूटोरियल में, आप nifti फ़ॉर्मेट की ब्रेन MRI इमेजें पढ़ना और उन्हें convolutional autoencoder से पुनर्निर्मित करना सीखेंगे और समझेंगे।
· 13 मि॰ पढ़ें

AI के साथ खोजें

आप अपना नेटवर्क ट्रेन करने के लिए 3T ब्रेन MRI डेटासेट का उपयोग करेंगे। अपने मॉडल की प्रभावशीलता देखने के लिए, आप अपने मॉडल का परीक्षण इन पर करेंगे:

  • अनदेखी 3T MRI इमेजें,
  • शोर-युक्त 3T MRI इमेजें, और
  • एक गुणात्मक मैट्रिक: पुनर्निर्मित इमेजों के प्रदर्शन का आकलन करने के लिए पीक सिग्नल-टू-नॉइज़ रेशियो (PSNR)।

यह ट्यूटोरियल मेडिकल इमेजिंग की बारीकियों पर नहीं, बल्कि डीप लर्निंग पक्ष पर केंद्रित रहेगा! नोट: यह ट्यूटोरियल मुख्यतः convolutional autoencoders के व्यावहारिक इम्प्लीमेंटेशन को कवर करेगा। इसलिए, यदि आप अभी तक convolutional neural network (CNN) और autoencoder से परिचित नहीं हैं, तो आप CNN और Autoencoder ट्यूटोरियल देखना चाहेंगे। इस ट्यूटोरियल की सबसे अच्छी बात यह है कि आप 3D वॉल्यूम्स को 2D इमेजों के रूप में लोड करेंगे और उन्हें मॉडल में फीड करेंगे। संक्षेप में, आप आज के ट्यूटोरियल में निम्नलिखित विषयों पर काम करेंगे:

  • शुरुआत में आपको मैग्नेटिक रेज़ोनेंस इमेजिंग (MRI) के बारे में संक्षिप्त जानकारी दी जाएगी,
  • फिर आप ब्रेन MRI डेटासेट को समझेंगे: इसमें किस तरह की इमेजें हैं, मॉड्यूल इम्पोर्ट करना, इमेजें कैसे पढ़ना, इमेजों का ऐरे बनाना, ब्रेन MRI इमेजों का प्रीप्रोसेसिंग ताकि उन्हें मॉडल में फीड किया जा सके, और अंत में ब्रेन MRI इमेजों का अन्वेषण करना।
  • Convolutional autoencoder के इम्प्लीमेंटेशन में: आप प्रीप्रोसेस्ड डेटा को मॉडल में फिट करेंगे, ट्रेनिंग और वैलिडेशन लॉस का प्लॉट विज़ुअलाइज़ करेंगे, प्रशिक्षित मॉडल को सेव करेंगे और अंत में टेस्ट सेट पर प्रेडिक्ट करेंगे।
  • इसके बाद, आप टेस्ट इमेजों में शोर जोड़कर अपने प्री-ट्रेंड मॉडल की मज़बूती का परीक्षण करेंगे और देखेंगे कि मात्रात्मक रूप से मॉडल कितना अच्छा प्रदर्शन करता है।
  • अंत में, आप अपनी भविष्यवाणियों का मूल्यांकन एक मात्रात्मक मैट्रिक पीक सिग्नल-टू-नॉइज़ रेशियो (PSNR) से करेंगे और अपने मॉडल के प्रदर्शन को मापेंगे।

MR इमेजों का संक्षिप्त परिचय

मेडिकल इमेजिंग में विभिन्न प्रणालियाँ उपयोग होती हैं, जिनमें 0.3 टेस्ला (T) चुंबकीय क्षेत्र तीव्रता वाले ओपन MRI यूनिट्स से लेकर 1.0 T तक की एक्स्ट्रीमिटी MRI प्रणालियाँ और 3.0 T (क्लिनिकल उपयोग में) तक की फील्ड स्ट्रेंथ वाले होल-बॉडी स्कैनर शामिल हैं। टेस्ला MR इमेजों के चुंबकीय क्षेत्र की मात्रात्मक तीव्रता की इकाई है। हाई-फील्ड MR स्कैनर (7T, 11.5T) उच्चतर SNR (सिग्नल-टू-नॉइज़ रेशियो) देते हैं, भले ही वोक्सेल (3-आयामी पैच या ग्रिड) आकार छोटा हो, और इसलिए अधिक सटीक निदान के लिए पसंद किए जाते हैं।

छोटा वोक्सेल आकार बेहतर रेज़ोल्यूशन देता है, जो नैदानिक ​​निदान में मददगार होता है। हालांकि, MR स्कैनर में प्रयुक्त चुंबकीय क्षेत्र की तीव्रता SNR बनाए रखने के लिए वोक्सेल आकार पर एक निचली सीमा निर्धारित करती है, ताकि MR इमेज का विवरण संरक्षित रहे।
7T और 11.5T की बेहतर इमेज गुणवत्ता के बावजूद, लागत बाधाओं के कारण इन्हें शायद ही उत्पादन में तैनात किया जाता है।

हालिया शोधपत्रों के अनुसार, 3T स्कैनरों की रिपोर्टेड संख्या लगभग ~20,000 है, जबकि 7T स्कैनर मात्र ~40 हैं।

ब्रेन MRI 3T डेटासेट को समझना

ब्रेन MRI डेटासेट 3D वॉल्यूम्स से बना है; प्रत्येक वॉल्यूम में दिमाग़ के अलग-अलग स्लाइस पर ली गई कुल 207 स्लाइस/इमेजें होती हैं। प्रत्येक स्लाइस का आयाम 173 x 173 है। इमेजें सिंगल-चैनल ग्रेस्केल हैं। कुल 30 सब्जेक्ट्स हैं, प्रत्येक सब्जेक्ट में एक मरीज का MRI स्कैन होता है। इमेज फ़ॉर्मेट jpeg, png आदि नहीं बल्कि nifti फ़ॉर्मेट है। आप आगे देखेंगे कि nifti फ़ॉर्मेट की इमेजें कैसे पढ़ी जाती हैं।

डेटासेट में T1 मोडैलिटी MR इमेजें हैं; T1 सीक्वेंस परंपरागत रूप से एनाटॉमिक स्ट्रक्चर्स के मूल्यांकन के लिए अच्छे माने जाते हैं। आज जिस डेटासेट पर आप काम करेंगे, वह 3T ब्रेन MRI का है।

यह डेटासेट सार्वजनिक है और इस स्रोत से डाउनलोड के लिए उपलब्ध है।

टिप: यदि आप MNIST डेटासेट के साथ वर्गीकरण कार्यों हेतु मल्टी-लेयर परसेप्ट्रॉन (MLP) लागू करना सीखना चाहते हैं, तो यह ट्यूटोरियल देखें।

नोट : शुरू करने से पहले ध्यान दें कि मॉडल को Nvidia 1080 Ti GPU, Xeon e5 GeForce प्रोसेसर और 32GB RAM वाले सिस्टम पर प्रशिक्षित किया जाएगा। अगर आप Jupyter Notebook उपयोग कर रहे हैं, तो आपको os नामक मॉड्यूल का उपयोग करके CUDA device order और CUDA visible devices निर्दिष्ट करते हुए तीन पंक्तियाँ और जोड़नी होंगी।

नीचे दिए गए कोड में, आप मूलतः os.environ का उपयोग करके नोटबुक में एन्वायरनमेंट वेरिएबल सेट करते हैं। Keras इनिशियलाइज़ करने से पहले यह करना अच्छा है ताकि Keras बैकएंड TensorFlow को पहले GPU तक सीमित किया जा सके। यदि जिस मशीन पर आप ट्रेनिंग कर रहे हैं उस पर GPU 0 पर है, तो 1 की जगह 0 का उपयोग करना सुनिश्चित करें। आप टर्मिनल पर एक साधारण कमांड चलाकर यह देख सकते हैं: उदाहरण के लिए, 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

मॉड्यूल इम्पोर्ट करना

सबसे पहले, आप सभी आवश्यक मॉड्यूल इम्पोर्ट करेंगे जैसे cv2, numpy, matplotlib और सबसे महत्वपूर्ण keras, क्योंकि आप आज के ट्यूटोरियल में इसी फ़्रेमवर्क का उपयोग करेंगे!
nifti फ़ॉर्मेट की इमेजें पढ़ने के लिए, आपको 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)

डेटा लोड करना

आप glob मॉड्यूल का उपयोग करेंगे जो आपके द्वारा निर्दिष्ट फ़ोल्डर में मौजूद सभी वॉल्यूम्स की सूची लौटाएगा!

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

आइए सूची के पहले एलिमेंट को प्रिंट करते हैं और सूची की लंबाई भी जाँचते हैं: जो हमारे मामले में 30 होनी चाहिए।

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

अब आप nibabel का उपयोग करके 3D वॉल्यूम्स लोड करने के लिए तैयार हैं। ध्यान दें कि जब आप Nifti फ़ॉर्मेट वॉल्यूम लोड करते हैं, तो Nibabel तुरंत इमेज ऐरे लोड नहीं करता। यह तब तक प्रतीक्षा करता है जब तक आप ऐरे डेटा नहीं मांगते। ऐरे डेटा मांगने का सामान्य तरीका get_data() मेथड को कॉल करना है।

चूँकि आपको 3D के बजाय 2D स्लाइस चाहिए, आप एक सूची इनिशियलाइज़ करेंगे; जिसमें हर बार जब आप एक वॉल्यूम पढ़ेंगे, तो आप 3D वॉल्यूम की सभी 207 स्लाइसों पर इटरेट करेंगे और प्रत्येक स्लाइस को एक-एक करके सूची में जोड़ देंगे।

images = []

आइए 3D वॉल्यूम में से किसी एक का आकार भी प्रिंट करते हैं, यह 173 x 207 x 173 (x, y, z; निर्देशांक) होना चाहिए।

नोट: आप दिमाग़ की केवल बीच की 51 स्लाइसों का उपयोग करेंगे, सभी 207 स्लाइसों का नहीं। तो, आइए देखें कि केवल सेंटर स्लाइसों का उपयोग कैसे करें और उन्हें कैसे लोड करें।

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)

आइए 207 स्लाइसों में से किसी एक स्लाइस का आकार विश्लेषित करें।

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

डेटा प्रीप्रोसेसिंग

क्योंकि images एक सूची है, आप इसे numpy मॉड्यूल की मदद से numpy ऐरे में बदलेंगे।

images = np.asarray(images)

अब numpy ऐरे का आकार जाँचने का समय है; ऐरे का पहला आयाम क्रमशः 207 x 30 = 6210 होना चाहिए और शेष दो आयाम 173 x 173 होंगे।

images.shape
(1530, 173, 173)

डेटासेट की इमेजें वाकई 173 x 173 आयाम वाली ग्रेस्केल इमेजें हैं, इसलिए डेटा को मॉडल में फीड करने से पहले उसका प्रीप्रोसेसिंग करना बहुत ज़रूरी है। आप पहले प्रत्येक 173 x 173 इमेज को 173 x 173 x 1 आकार के मैट्रिक्स में बदलेंगे, जिसे नेटवर्क में फीड किया जा सकता है:

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

इसके बाद, डेटा को मैक्स-मिन नॉर्मलाइज़ेशन तकनीक से रिस्केल करें:

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

आइए डेटा के न्यूनतम और अधिकतम मान सत्यापित करें, रिस्केलिंग के बाद ये क्रमशः 0.0 और 1.0 होने चाहिए!

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

यह एक महत्वपूर्ण चरण है, यहाँ आप इमेजों को बॉर्डर्स पर ज़ीरो से पैड करेंगे ताकि इमेजों का आयाम सम (even) हो जाए और मॉडल से गुज़रते समय इमेज को दो से डाउनसैंपल करना आसान हो। चलिए तीन पंक्तियाँ और तीन कॉलम में ज़ीरो जोड़ते हैं ताकि आयाम 176 x 176 हो जाए

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

यह सब करने के बाद, डेटा को विभाजित करना ज़रूरी है। अपने मॉडल को अच्छी तरह सामान्यीकृत (generalize) कराने के लिए, आप डेटा को दो भागों में बाँटेंगे: ट्रेनिंग और वैलिडेशन सेट। आप 80% डेटा पर अपने मॉडल को ट्रेन करेंगे और शेष 20% पर वैलिडेट करेंगे।

यह ओवरफिटिंग की संभावना कम करने में भी मदद करेगा, क्योंकि आप वैलिडेशन चरण में ऐसे डेटा पर मॉडल का आकलन करेंगे जो ट्रेनिंग में नहीं देखा गया।

आप scikit-learn के train_test_split मॉड्यूल से डेटा को उचित रूप से विभाजित कर सकते हैं:

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)

ध्यान दें कि इस कार्य के लिए आपको ट्रेनिंग और टेस्टिंग लेबल्स की आवश्यकता नहीं है। इसलिए आप ट्रेनिंग इमेजों को दो बार पास करेंगे। आपकी ट्रेनिंग इमेजें इनपुट के साथ-साथ ग्राउंड ट्रुथ के रूप में भी काम करेंगी, ठीक वैसे ही जैसे वर्गीकरण कार्य में लेबल्स होते हैं।

डेटा अन्वेषण

आइए अब देखें कि डेटासेट में इमेजें कैसी दिखती हैं और साथ ही NumPy ऐरे के .shape एट्रिब्यूट की मदद से, इमेजों में जो तीन अतिरिक्त पंक्तियाँ और कॉलम जोड़े थे, उसके बाद का आयाम भी एक बार फिर जाँच लें:

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

ऊपर के आउटपुट से आप देख सकते हैं कि डेटा का आकार 6210 x 176 x 176 है क्योंकि 176 x 176 x 1 आयाम के 6210 सैंपल हैं।

अब, अपने डेटासेट में कुछ ट्रेनिंग और वैलिडेशन इमेजों पर नज़र डालते हैं:

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

ऊपर दिए दो प्लॉट्स के आउटपुट क्रमशः ट्रेनिंग और वैलिडेशन सेट से हैं। आप देख सकते हैं कि ट्रेनिंग और वैलिडेशन इमेजें अलग हैं; यह देखना दिलचस्प होगा कि क्या convolutional autoencoder फीचर्स सीखकर इन इमेजों का सही ढंग से पुनर्निर्माण कर पाता है।

अब आप नेटवर्क परिभाषित करने और डेटा को नेटवर्क में फीड करने के लिए तैयार हैं। तो बिना देर किए, अगले चरण पर चलते हैं!

Convolutional Autoencoder!

इमेजों का आकार 176 x 176 x 1 या 30976-आयामी वेक्टर है। आप इमेज मैट्रिक्स को ऐरे में बदलते हैं, उसे 0 और 1 के बीच रिस्केल करते हैं, 176 x 176 x 1 के आकार में रीशेप करते हैं, और इसे नेटवर्क के इनपुट के रूप में फीड करते हैं।

साथ ही, आप 128 का बैच साइज़ उपयोग करेंगे; 256 या 512 जैसे बड़े बैच साइज़ भी बेहतर हो सकते हैं—यह आपके ट्रेनिंग सिस्टम पर निर्भर करता है। यह सीखने के पैरामीटर्स पर बड़ा प्रभाव डालता है और भविष्यवाणी सटीकता को प्रभावित करता है। आप अपने नेटवर्क को 50 epochs तक ट्रेन करेंगे।

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

जैसा कि आप पहले से जानते हैं, autoencoder दो भागों में बँटा होता है: एक encoder और एक decoder।

Encoder: इसमें 3 Convolution ब्लॉक्स हैं, प्रत्येक ब्लॉक में एक convolution लेयर होती है जिसके बाद batch normalization लेयर होती है। पहले और दूसरे convolution ब्लॉक के बाद max-pooling लेयर का उपयोग किया गया है।

  • पहले convolution ब्लॉक में 3 x 3 के 32 फ़िल्टर्स होंगे, जिसके बाद डाउनसैंपलिंग (max-pooling) लेयर होगी,
  • दूसरे ब्लॉक में 3 x 3 के 64 फ़िल्टर्स होंगे, जिसके बाद एक और डाउनसैंपलिंग लेयर होगी,
  • encoder के अंतिम ब्लॉक में 3 x 3 के 128 फ़िल्टर्स होंगे।

Decoder: इसमें 2 Convolution ब्लॉक्स हैं, प्रत्येक ब्लॉक में एक convolution लेयर होती है जिसके बाद batch normalization लेयर होती है। पहले और दूसरे convolution ब्लॉक के बाद upsampling लेयर का उपयोग किया गया है।

  • पहले ब्लॉक में 3 x 3 के 128 फ़िल्टर्स होंगे, जिसके बाद upsampling लेयर होगी,
  • दूसरे ब्लॉक में 3 x 3 के 64 फ़िल्टर्स होंगे, जिसके बाद एक और upsampling लेयर होगी,
  • encoder की अंतिम लेयर में 3 x 3 का 1 फ़िल्टर होगा जो इनपुट के सिंगल चैनल को पुनर्निर्मित करेगा।

max-pooling लेयर हर बार इनपुट को दो गुना डाउनसैंपल करेगी, जबकि upsampling लेयर हर बार इनपुट को दो गुना अपसैंपल करेगी।

नोट: फ़िल्टर्स की संख्या, फ़िल्टर आकार, लेयर्स की संख्या, मॉडल को जितने epochs तक ट्रेन करते हैं—ये सभी हाइपरपैरामीटर्स हैं और इन्हें अपने अनुभव के आधार पर तय किया जाना चाहिए। आप इन हाइपरपैरामीटर्स में बदलाव करके नए प्रयोग करने के लिए स्वतंत्र हैं और अपने मॉडल के प्रदर्शन को माप सकते हैं। इसी तरह आप धीरे-धीरे डीप लर्निंग की कला सीखेंगे!

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

मॉडल बनने के बाद, आपको इसे RMSProp ऑप्टिमाइज़र के साथ कम्पाइल करना होगा।

ध्यान दें कि आपको loss का प्रकार भी loss आर्गुमेंट के जरिए बताना होगा। यहाँ mean squared error का उपयोग होगा, क्योंकि हर बैच के बाद लॉस, पिक्सेल-दर-पिक्सेल, भविष्यवाणी किए गए आउटपुट और ग्राउंड ट्रुथ के बीच mean squared error से गणना की जाएगी:

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

आइए summary फ़ंक्शन से ऊपर बनाए गए लेयर्स को विज़ुअलाइज़ करें; यह प्रत्येक लेयर के पैरामीटर्स (weights और biases) की संख्या और आपके मॉडल में कुल पैरामीटर्स भी दिखाएगा।

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
_________________________________________________________________

अब Keras की fit() फ़ंक्शन से मॉडल को ट्रेन करने का समय है! मॉडल 50 epochs तक ट्रेन होगा। fit() फ़ंक्शन एक history ऑब्जेक्ट लौटाएगा; इसे fashion_train में स्टोर करके आप बाद में ट्रेनिंग और वैलिडेशन के बीच लॉस प्लॉट बना सकते हैं, जो आपको मॉडल के प्रदर्शन का दृश्य विश्लेषण करने में मदद करेगा।

मॉडल ट्रेन करें

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

आखिरकार! आपने फिंगरप्रिंट डेटासेट पर 200 epochs तक मॉडल को ट्रेन कर लिया, अब ट्रेनिंग और वैलिडेशन डेटा के बीच लॉस प्लॉट बनाते हैं ताकि मॉडल के प्रदर्शन को विज़ुअलाइज़ किया जा सके।

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

अंततः, आप देख सकते हैं कि वैलिडेशन लॉस और ट्रेनिंग लॉस दोनों सिंक में हैं। यह दर्शाता है कि आपका मॉडल ओवरफिट नहीं हो रहा: वैलिडेशन लॉस घट रहा है, बढ़ नहीं रहा, और ट्रेनिंग व वैलिडेशन लॉस के बीच पूरे ट्रेनिंग चरण में बमुश्किल कोई अंतर है।

अतः, आप कह सकते हैं कि आपके मॉडल की जनरलाइज़ेशन क्षमता अच्छी है।

अब Keras की predict() फ़ंक्शन से टेस्ट इमेजों का पुनर्निर्माण करने और यह देखने का समय है कि आपका मॉडल टेस्ट डेटा पर कितना अच्छा पुनर्निर्माण कर पा रहा है।

मॉडल सेव करें

अब प्रशिक्षित मॉडल को सेव करते हैं। डीप लर्निंग में काम करते समय यह एक महत्वपूर्ण चरण है। क्योंकि वेट्स ही उस समस्या के समाधान का केंद्र होते हैं जिस पर आप काम कर रहे हैं!

आप कभी भी सेव किए गए वेट्स को उसी मॉडल में लोड कर सकते हैं और जहाँ ट्रेनिंग रुकी थी, वहीं से आगे ट्रेन कर सकते हैं। उदाहरण: ऊपर दिए मॉडल को फिर से ट्रेन करने पर वेट्स, बायसेज़, लॉस फ़ंक्शन आदि पैरामीटर्स शुरुआत से नहीं होंगे और यह अब फ्रेश ट्रेनिंग नहीं होगी।

सिर्फ एक पंक्ति के कोड से आप वेट्स को मॉडल में सेव और वापस लोड कर सकते हैं।

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

वैलिडेशन डेटा पर प्रेडिक्ट करना

क्योंकि यहाँ आपके पास अलग से टेस्टिंग डेटा नहीं है। चलिए अभी-अभी प्रशिक्षित मॉडल पर भविष्यवाणी के लिए वैलिडेशन डेटा का उपयोग करते हैं।

आप शेष 306 वैलिडेशन इमेजों पर प्रशिक्षित मॉडल से भविष्यवाणी करेंगे और कुछ पुनर्निर्मित इमेजों को प्लॉट करेंगे ताकि देखा जा सके कि आपका मॉडल वैलिडेशन इमेजों का पुनर्निर्माण कितनी अच्छी तरह कर रहा है।

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

ऊपर दिए चित्रों से आप देख सकते हैं कि मॉडल ने टेस्ट इमेजों के पुनर्निर्माण में शानदार काम किया है। कम-से-कम गुणात्मक तौर पर, टेस्ट और पुनर्निर्मित इमेजें लगभग एक जैसी दिखती हैं।

शायद यह मूल 3T इमेजों में मौजूद कुछ स्थानीय विवरणों के पुनर्निर्माण में थोड़ा और बेहतर कर सकता है।

शोर-युक्त 3T इमेजों पर प्रेडिक्ट करना

पहले वैलिडेशन इमेजों में औसत शून्य और 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

अब शोर-युक्त वैलिडेशन इमेजों पर भविष्यवाणी करने का समय है। देखते हैं कि बिना शोर पर ट्रेन हुए भी आपका मॉडल शोर-युक्त इमेजों पर कितना अच्छा प्रदर्शन करता है।

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

लगता है मॉडल ने काफ़ी अच्छा काम किया है, है न? आखिरकार, पुनर्निर्मित इमेजें शोर-युक्त इमेजों से बेहतर दिखती हैं। साथ ही, मॉडल ने ट्रेनिंग के दौरान वास्तव में शोर-युक्त इमेजें देखी ही नहीं थीं।

मात्रात्मक मैट्रिक: पीक सिग्नल-टू-नॉइज़ रेशियो (PSNR)

PSNR ब्लॉक दो इमेजों के बीच पीक सिग्नल-टू-नॉइज़ रेशियो (डेसीबल, dB में) की गणना करता है। यह अनुपात अक्सर मूल और पुनर्निर्मित इमेज के बीच गुणवत्ता के मापन के रूप में उपयोग होता है। PSNR जितना अधिक, पुनर्निर्मित इमेज की गुणवत्ता उतनी बेहतर।

तो, पहले वैलिडेशन और पुनर्निर्मित वैलिडेशन इमेजों के प्रदर्शन की गणना करते हैं।

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

अगला, मूल वैलिडेशन और प्रेडिक्टेड नॉइज़ी इमेजों के बीच PSNR की गणना करते हैं

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

ठीक है, लगता है कि मात्रात्मक रूप से बिना-शोर पुनर्निर्माणों और शोर-युक्त पुनर्निर्माणों के PSNR में सिर्फ 1.54 dB का अंतर है। साथ ही, आपने अपने मॉडल को शोर संभालने के लिए ट्रेन नहीं किया है। क्या यह अद्भुत नहीं है?

आगे बढ़ें!

यह ट्यूटोरियल MRI nifti फ़ॉर्मेट इमेजें पढ़ना, उनका विश्लेषण, प्रीप्रोसेसिंग, और ब्रेन MRI 3T डेटासेट का उपयोग करते हुए उन्हें मॉडल में फीड करना समझने की अच्छी शुरुआत था। इसने आपको autoencoders के एक बढ़िया अनुप्रयोग को practically दिखाया। यदि आप आसानी से—या थोड़े अतिरिक्त प्रयास के साथ—साथ चल पाए, बहुत बढ़िया!

आप आर्किटेक्चर के साथ खेल सकते हैं और मात्रात्मक व गुणात्मक दोनों रूप से भविष्यवाणियों में सुधार करने की कोशिश कर सकते हैं। शायद और लेयर्स जोड़कर, शायद अधिक समय तक ट्रेन करके? ये संयोजन आज़माएँ और देखें कि क्या मदद मिलती है।

कवर करने के लिए अभी बहुत कुछ है, तो क्यों न DataCamp का Deep Learning in Python कोर्स करें? यदि आपने अभी तक नहीं किया है। आप बुनियाद से सीखेंगे और धीरे-धीरे डीप लर्निंग डोमेन में महारत हासिल करेंगे; यह निस्संदेह एक अनिवार्य संसाधन होगा जब आप Python में convolutional neural networks के साथ काम करना, चेहरों, ऑब्जेक्ट्स आदि का पता लगाना सीखेंगे।

विषय