Kaggleの肺炎の鑑別をやってみた

大量の画像データを処理する練習で、Kaggleの「Chest X-Ray Images (Pneumonia)」のデータを使って、肺炎の鑑別を行ってみました。


以前実装練習で、胸部レントゲン画像からコロナ患者の検出にチャレンジしましたが、画像データを全部メモリーに読み込んで処理するというPCに無茶振り&汎用性無しなコーディングを行っていました。
今回は、Kerasの ImageDataGeneratorの使い方を学んで、もう少し汎用性のあるコーディングを目指しました。
ImageDataGeneratorは、設定した数ずつ画像を読み込んで学習に回してくれたり、画像を変形して学習データをアレンジしたりしてくれます。

 

胸部レントゲン画像は5856枚で、学習用5216、検証用16、テスト用624となっており、NormalとPneumonia(肺炎)の2クラスに分かれています。(コロナの時よりシンプルですね)
画像データは128×128pixelにそろえて、GrayScale256段階(0.0~1.0)になるように加工して使います。

f:id:tp5366:20201212011424p:plain

 

学習モデルはCNNで、以下のように設定しました。(KerasのSequential使って記述)

model = Sequential()
model.add(Conv2D(32 , (3,3) , padding = 'same' , activation = 'relu' , input_shape = (128, 128,1)))
model.add(Conv2D(32 , (3,3) , padding = 'same' , activation = 'relu'))
model.add(BatchNormalization())
model.add(MaxPool2D( (2,2) , padding = 'same'))
model.add(Dropout(0.2))

model.add(Conv2D(64 , (3,3) , padding = 'same' , activation = 'relu'))
model.add(Conv2D(64 , (3,3) , padding = 'same' , activation = 'relu'))
model.add(BatchNormalization())
model.add(MaxPool2D( (2,2) , padding = 'same'))
model.add(Dropout(0.2))

model.add(Conv2D(128 , (3,3) , padding = 'same' , activation = 'relu'))
model.add(Conv2D(128 , (3,3) , padding = 'same' , activation = 'relu'))
model.add(BatchNormalization())
model.add(MaxPool2D( (2,2) , padding = 'same'))
model.add(Dropout(0.2))

model.add(Flatten())
model.add(Dense(units = 256 , activation = 'relu'))
model.add(Dropout(0.2))
model.add(Dense(units = 1 , activation = 'sigmoid'))
model.compile(optimizer = "rmsprop" , loss = 'binary_crossentropy' , metrics = ['accuracy'])

3×3のフィルターによる2連続畳み込みは、5×5のフィルターと同様の機能で、パラメータ数を25(5×5)→18(3×3×2)に削減できる事がポイントですね。

 

バッチサイズ64、エポック数16で学習させてみた結果は、

f:id:tp5366:20201213002407p:plain

左のグラフが精度(Accuracy)で、右が損失関数の値(Loss)です。

自分で作ったモデルの性能がじわじわ上がっていく所が萌えですね。

 

学習用データでの最終的な精度は96.34%
検証用データでの最終的な精度81.25%
検証用データの量が少ないのもあって、検証用データの精度の変動が大きすぎですね。


テスト用データで診断させた結果は、

f:id:tp5366:20201213002552p:plain
90.54%の精度で診断できました。

 

評価指数を出してみると、

f:id:tp5366:20201213002705p:plain

 

精度91%といったところですね。

肺炎と診断された患者が実際の肺炎だった割合(Precision)は94%

肺炎の患者が肺炎と診断された割合(Recall)は80%

F1score(PrecisonとRecallの調和平均)は86%

性能としてはまずまずかな?

 

最近は、CNN用の新しい活性化関数としてFRelu(Funnel Relu)が出てきて、実装できればさらに精度アップが期待できそうですが、オールドタイプな自分ではファンネル使えないので、強化するしかないか(笑)