1. 程式人生 > >使用Keras處理和識別醫學影象

使用Keras處理和識別醫學影象

 最近在做醫學影象的處理,簡單的記錄一下。

預處理

已知的資料集是通過labelimg工具打好標籤的圖片(如下圖所示),總共區分三種病例。但標籤框的大小不一致,必須要統一大小,以滿足後期製作統一格式的資料集(*.npz、*.tfrecord等)。

但如果只是簡單的將圖片取出來再統一大小,圖片的解析度可能會受影響,所以這裡先將所有的標籤框統一大小(取最大值)再把圖片取出來(如下圖)。

通過分析,發現樣本資料不平衡,其中常見的病例佔了近90%,不利於模型的訓練。

查閱了資料找到了兩種方法:

一.可以採用資料少的資料集裡面資料增廣的方式:
1.影象crop
2.影象旋轉
3.影象平移
二.可以採用修改損失函式的方式,在資料量小的樣本上增大權重
樣本數量差別很大,會導致少樣本的類別基本不被預測到,就像傳統機器學習一樣。
引數調節個人感覺主要在損失函式的計算上。

這裡我使用了第一種方法(第二種後面再試試)。Keras內建的ImageDataGenerator用來生成資料非常方便,而且這個生成器還提供很多增強識別效果的特徵提取方法,如:去中心化、均值化、ZCA白化等。

製作npz格式資料集

訓練網路

用Keras簡單構建了卷積神經網路,程式碼如下:

#! /usr/bin/env python
# -*- coding:utf-8 -*-
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPool2D
from keras.utils import np_utils
import numpy as np

# 全域性變數
batch_size = 128    # 每批次多少樣本
nb_classes = 3     # 類別總數
epochs = 50         # 遍歷次數
img_rows, img_cols = 100, 100
nb_filters = 32         # 卷積個數
pool_size = (2, 2)      # 池化面積大小
kernel_size = (3, 3)    # 卷積核大小
'''
    第一步,載入資料
'''
# 自定義資料
(x_train, y_train), (x_test, y_test) = np.load('train_data_1.npy', 'test_data_1.npy')
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
# 將標籤資料轉換為二維
y_train = np_utils.to_categorical(y_train, nb_classes)
y_test = np_utils.to_categorical(y_test, nb_classes)
'''
    第二步,構建網路層
'''
# 卷積神經網路
model = Sequential()
model.add(Convolution2D(nb_filters, (kernel_size[0], kernel_size[1]),
                        padding='same',
                        input_shape=(100, 100, 1)))   # 卷積層1
model.add(Activation('relu'))
model.add(Convolution2D(nb_filters, (kernel_size[0], kernel_size[1])))  # 卷積層2
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=pool_size))   # 池化層

model.add(Convolution2D(nb_filters, (kernel_size[0], kernel_size[1])))  # 卷積層3
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=pool_size))   # 池化層

model.add(Convolution2D(nb_filters, (kernel_size[0], kernel_size[1])))  # 卷積層4
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=pool_size))   # 池化層

model.add(Flatten())      # 拉成一維資料
model.add(Dense(128))   # 全連線層
model.add(Activation('relu'))
model.add(Dense(nb_classes))
model.add(Activation('softmax'))
'''
    第三步,編譯訓練
'''
model.compile(loss='categorical_crossentropy', optimizer='adadelta', metrics=['accuracy'])

'''
    第四步,訓練
'''
print('開始訓練')
model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_test, y_test))
'''
    第五步,輸出
'''
print('開始評估')
scores = model.evaluate(x_test, y_test, verbose=1)
print('Test score:', scores[0])
print('Test accuracy:', scores[1])
# 儲存模型
# model.save('model.h5')

評估後的準確率為96%,通過調整損失函式和引數優化等,準確率還能提高點(ps:剛開始直接用的Keras的神經網路例子,準確率只有50%,卷積神經網路還是強大)。

結論

對於醫學影象的分類識別,最主要的就是影象特徵的提取,如果直接把原圖放進去訓練效果很差。

使用神經網路來識別不常見的影象資訊,這種方法越來越受到關注,後面試試用機器學習的方法來分類看看效果如何。