使用Keras處理和識別醫學影象
阿新 • • 發佈:2019-01-10
最近在做醫學影象的處理,簡單的記錄一下。
預處理
已知的資料集是通過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%,卷積神經網路還是強大)。
結論
對於醫學影象的分類識別,最主要的就是影象特徵的提取,如果直接把原圖放進去訓練效果很差。
使用神經網路來識別不常見的影象資訊,這種方法越來越受到關注,後面試試用機器學習的方法來分類看看效果如何。