這次以卷積神經網路(Convolutional Neural Network)來學習並預測X光片影像資料中使用者可能得到肺炎的機率。
使用到 OpenCV 程式庫。
實作題目是中國大陸廣州婦幼醫院胸部肺炎診斷 X光片(Chest X-Ray for Pneumonia)
胸部X射線圖像(前後)選自廣州市婦幼保健中心的1至5歲兒科患者的回顧性研究。 所有胸部X射線影像都是患者常規臨床護理的一部分。
[資料說明]
數據集分為3個文件夾(訓練,測試,val),並包含每個圖像類別(肺炎/正常)的子文件夾。 有5,863張X射線圖像(JPEG)和2類(肺炎/正常)。
[資料視覺化]
在面對圖形相關處理時,OpenCV 是個好工具可以讓我們讀取與顯示圖片。我用以下的函式來檢視圖片:
def show_image(pathname):
img = cv2.imread(pathname)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
print(img.shape)
顯示的資訊是(1858,2090,3),表示原始的圖片是 1858*2090 ,還加上 3原色(R,G,B)的資料。這樣的資料對有限的電腦記憶體來說已經太大了!至於三原色的部分,在讀取影像時可以直接轉為灰階(gray scale)
讀到原圖 = cv.imread(路徑+檔名, cv.IMREAD_GRAYSCALE)
接下來我們需要縮小圖片(Downsizing)。還好在 OpenCV 程式庫裡面有一個 resize 函式可以直接使用:
改過後的影像 = cv.resize(讀到原圖, (縮小後長度,縮小後寬度)) # downsizing to
這裡我將縮小後的長度和寬度設成 256*256
[資料的設置與讀取方式]
如資料夾所示,這裡有3個資料夾,其中每一個都有 NORMAL 和 PNEUMONIA 目錄。而未來預測時每一筆資料都有NORMAL 和 PNEUMONIA 的結果分類。因此在訓練時應該是每一筆資料都包含 資料 加上 正常/肺炎這兩種內容。在 Python 裡面我們可以用 串列(list) 的方式來包裝 [影像,0 或 1]
在 串列(list) 中可以使用 .index() 將內容順序改成 0,1的數字順序
labels = ['NORMAL', 'PNEUMONIA']
class_num = labels.index(label)
[送入訓練模型前的轉換]
X 只包含 訓練內容,而 y 只包含 one-hot encoding 的資料
因此這裡還要再做一次轉換。
目前的 train_set: (5216, 2)
X=(5863, 2)
目前的資料,每一筆是 (圖片內容,0/1)
可以用以下的迴路一次地將特徵與label 抓取到 X 和 y 兩個串列(list)裡:
for feature, lable in train_set:
X.append(feature)
y.append(lable)
X list(5840) y list(5840)
X_new = np.array(X).reshape(-1, 256,256,1)
每一個元素是 256,256,1:256 是寬度和長度,後面的1是顏色的灰階的部分(gray)
X_new = (5863,256,256,1)
y 的部分也一樣
y_new = np.array(y)
y_new = np.expand_dims(y_new, axis=1)
這裡多了一個維度,是為了配合影像資料 X_new 裡面有一個灰階的維度
y_new = (5840,1)
[CNN 模型的建立]
基本的資料形式都建立好了,接下來就是建立模型。
1. 切割資料:將原始的特徵和 Label 切割為:訓練用特徵、測試用特徵、訓練用Label 和 測試用 Label 等4筆資料:
X_train, X_test, y_train, y_test = train_test_split(X_new, y_new, test_size=0.2, random_state = 32)
2. 特徵數字一般化(normalize)
將 訓練用特徵、測試用特徵 轉換成浮點數,再將數字範圍限制在 0 到 1 之間。在一般 JPG 影像裡面,每一個圖點(pixel) 都在 0 到 255 之間。只要除以最大值就可以限制在
0 到 1 之間。
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
# normalizing: 0..255 to 0..1
X_train = X_train / 255
X_test = X_test / 255
3. 輸出端設成 one-hot encoding
訓練用Label 和 測試用 Label 都轉換成 one-hot encoding
以方便 CNN 和 MLP模型的學習
y_train2 = tf.keras.utils.to_categorical(y_train, output_result)
y_test2 = tf.keras.utils.to_categorical(y_test, output_result)
4. 建立模型
先以 Sequential()建立模型
model = tf.keras.models.Sequential()
CNN(Convolution Neural Network) 模型其實就是 利用濾鏡程序(Filters)抓出訓練資料中的特徵,再將這些特徵送入 多層感知神經網路(Multi-Layer Perceptron) 加以訓練的流程。
濾鏡程序(Filters) 共包含三種函式:Conv2D、MaxPool2D 和Dropout
Conv2D() 設定濾鏡的數量、濾鏡大小、和激發函數
MaxPool2D() 是取出濾鏡輸出的最大值作為圖型特徵
Dropout() 是取出圖型特徵後,刪掉過多的特徵值,以減少計算量
第一次使用 Conv2D() 要注意 輸入 輸入大小 input_shape=(256,256,1) 因為我們使用圖形當作輸入特徵,要加入 長、寬和色階,所以是 (256,256,1)
接下來就是 多層感知神經網路(Multi-Layer Perceptron) 的部分。
Flatten() 將 平面 2維的影響改成一維空間
Dense() 輸入神經層的神經元數量
compile() 放入損失函數、最佳化函數
fit() 啟動訓練模型、訓練模型後再預測準確率
[模型結構]
上圖是 模型的輸出結果,6百多萬個參數需要調整!
[模型輸出與精確度]
上圖是 訓練次數與準確率的曲線圖:次數越多,準確率越高
