読者です 読者をやめる 読者になる 読者になる

データの境界

なんちゃって理系がデータ分析業界に入ってからの汗と涙の記録。

深層学習で白血球を分類する話の和訳&要約

元ネタ: 

blog.athelas.com

↑の Jupyter notebook : 

wbc-classification/binary_training.ipynb at master · dhruvp/wbc-classification · GitHub

 

元々はバイオ業界にいたので、やはり「バイオ×機械学習」ネタは気になっちゃう。

そして自分もまさにこの記事のトピックになっている "顕微鏡での細胞数カウント" という苦行に苦しめられた一人なので、それを深層学習(CNN)で突破するよという話は心が躍る。

というわけで日本語要約とコメントなど書いてみました。

 

目的

  • 血液中を流れる細胞を種類別に分類したい。対象は以下の5種類の白血球のクラス分類。(しかし最終的に行っているのは2クラス分類(後述))
  • 白血球は "体の防御機構として働く細胞" のこと。体に細菌やウイルスが侵入したとき、これらの細胞が増えて外敵に対応する(=免疫機構)
  • 白血球には以下のようにいろいろな種類があり、そしてそれらが今回の分類対象となっている
    • たしかに見た目が違うのでCNNで分類できそうではある

※1. 和名についている「好」というのは "色素で染まりやすい" という意味
※2. 好中球・好酸球・好塩基球の核(DNAが含まれる領域: 以下画像中の濃い紫色の領域)は、いくつか繋がったように見えるので"多形核白血球"ともいう。ただし核を複数持っているわけではない。(参照)

 

正直、「核のタイプ」の見分け方はよくわからない。おそらく、染色された箇所が一つの細胞内に複数あるように見えるのが "多形核"、一つだけのようにみえるのが "単形核" かなという感じ。各白血球のタイプでどんな働きをしているのかも気になったのでwikiから引っ張ってきてまとめてみた。

f:id:kskbyt:20170405204530p:plain

 

なぜ白血球のタイプを分類したいのか?

血液中に流れるそれぞれの白血球タイプの数によって健康状態を定量できるから。

例えば、病原体に対する防御の働きをする白血球が通常状態よりも増えていると、何らかの病原体が体のどこかで悪いことをしている可能性が高いことがわかる。

また、上記のどのタイプの白血球が増えたかによって、どういった外敵が入ってきたかを予測することができるので重要な情報となる。

 

今まではどうやって分類していたのか?

記事によると、「機械を用いた方法」と「人力でカウントする方法」をやっているらしい。

 

機械を用いた方法

機械的な方法だと、血液を機械に流して、

  • 細胞がチャネルを通過するときの電流の変化を測定する。電流は細胞のタイプの形状およびサイズに比例して減少するのでそこから類推する。
  • レーザーを当てたときの光の屈折率で各白血球タイプを類推する。

(詳細は元記事を参照してください)

 

人力でカウントする方法

文字通り、顕微鏡を覗いて細胞数を根性でカウントする。

 

お察しの通り、この作業が非常にツライ作業だったりする。

顕微鏡を覗き込んで、見えている範囲内の(目的の)細胞をひたすら気合で数える。カウントする道具は自分の目と、交通量調査とか鳥をカウントする時に使うあのカチカチするやつのみ。最終的には「面積当りで●カウントだから、このプレートの面積に拡大すると~~」という大雑把な方法で全体の存在個数を類推する。

大抵の場合、カウントしたい対象(細胞とか微生物とか)は時間が経つと増殖したり死滅したりして、カウントしている間にも増減するのでとにかく迅速にカウントしなければいけない。サンプル数が多い時は一晩かけて気合でやったりするのでドライアイになること必死。白血球など静的な対象ならまだマシで、能動的に動き回る微生物のカウントは何らかの工夫を凝らさない限りツライことになる。

ただ、こんな単純な作業でも専用の機械を買おうとすると目玉が飛び出るほど高い。最近では趣味の人達が自作の細胞カウンターを作ってクラウドファンディングで資金を集めたりもしている

機械コスト的にも人力作業のコスト的にも、深層学習を使ったモデルで簡単に・精度良く・お安くできるようになれば嬉しことは間違いない。

 

利用したデータセット

白血球だけ染色した画像が352枚。画像サイズは640×480。
352枚って、えらいサンプル数すくないなぁ、という印象。

(白血球を染色した画像例↓)

f:id:kskbyt:20170405205313p:plain

白血球のタイプごとにカウントも実施し分布を調べる。← 専門家が分類を判断しカウント(正解データ)

f:id:kskbyt:20170405205354p:plain

Basophil(好塩基球)が最も存在数が少なく、Neutorophil (好中球)が最も多いらしい。

 

実施した画像の前処理

深層学習のモデルに突っ込む前に、画像に対して以下の前処理を行ったらしい。前処理大切。

  1. 一枚の画像に複数の染色された細胞が映っている画像は除外
  2. Basophils (好塩基球)は絶対量がそもそも少なかったので今回の分類対象からは除外
  3. 画像サイズを120×160にダウンサンプリング(学習スピードアップ!)
  4. ラベルの変更。好中球・好酸球 → 多核、単球・リンパ球 → 単核。つまり、5クラス分類問題からバイナリ分類問題に変換。(最初とだいぶ話を変えたな...)
  5. Image Augumentationを行い、訓練画像データを 2500枚*4種類 (= total 10,000枚) に増やした
  6. ピクセルの値を 0~1に正規化

 

モデル

CNN部分は単純なLeNet構造をKerasで実装。(input_sizeのデータ形式を見る感じ、バックエンドは tensorflowではなく theano?)

パラメータとして、

  • エポック数: 20, バッチサイズ: 32, 
  • レイヤー数: 3, フィルタ数: 32 (最後のレイヤーは64), カーネルサイズ: 3*3, 活性化関数: relu (最後はsigmoid), loss関数 : binary_crossentropy
  • Dropoutを0.7入れる

学習には、訓練画像281枚(元の画像データセットの80%相当枚数)をImage Augumentation(rotations, shifts, zooms)で増やしたものを使い、Amazon P2 インスタンスで学習を実行

以下CNN部分のスクリプトのみ抜粋

 

結果

元の訓練画像データセットの20%に当たる71枚の画像をvalidationとして実行し、accuracy 98.6%を得た。精度高い。

f:id:kskbyt:20170405210946p:plain

本当は多形核なのに単形核と予想したサンプルが1つだけあった。ちなみにその間違えた1つの画像が以下。人間が見ても判断が割れそう

f:id:kskbyt:20170405211036p:plain

 

結果に対する注意書き

  • 今回使用した訓練画像データセットは均一な環境で撮影した少数サンプルのものであるので、本当は細胞の形態や照明条件など多様な条件下で撮影した画像をもっと含めるべきだった。そうするともっと汎化的なモデルができるはず。
  • 同モデルを、最初の5クラス分類問題として同様に実行すると accuracy は86%となる。多クラスをうまく分類するにはさらに工夫が必要らしい。

 

やってみたけどうまくいかなかったアイデア

「実は他にもいろいろなアイデアでやってみたんだけど結局 精度アップには繋がらなかったんだ。そしてそれこそ共有すべきだと思うからそれも一緒に書いとくね」、とのこと。素敵。

 

染色された細胞核だけマスクして、その画像をCNNにかけてみた → 精度が88%に低下

  • つまり、核の形状以外の余分だと思われる情報を落としてCNNしてみた、ということ
  • なぜダメだったか?
    • 指定したカラーマスクのレンジが、照明条件の違いによってデータセットの全ての画像をうまく一般化できてなかったっぽい
    • 細胞のタイプを予測するには核の形状以外の画像情報(細胞質とよばれる核以外の細胞構造)も重要っぽい

f:id:kskbyt:20170405211148p:plain

(左が元画像で、右がカラーマスクによって染色した核領域だけ取り出した画像)

 

学習データセットをクラス分布を維持したままImage Augumentationしたらクラスの偏りが強すぎてうまくいかなかった → 学習データセットをクラス間でバランスさせるとうまくいくようになった
  • 元のデータセットでは多形核細胞の存在個数の偏りが強く、数が少ない単形核細胞ではrecallが低くなった
  • なので、元の分布に関係なく各クラスで2,500枚ずつAugumentationした画像を学習に使った

 

VGGNetを使って転移学習しようとしたけどうまくいかなかったよ → さすがに"白血球"の画像の分類には特徴として貢献しなかったっぽい
  • 白血球のデータセットはImageNetとは違いすぎたみたい
  • VGGNetのモデルはさすがに細胞核パターンの検出にむいてないみたい

 

VGGNet with ImageNetを使っても多クラス分類問題はうまく機能しなかった
  • バイナリ分類問題では上記のLeNetベースのモデルと同程度の精度をだすけど、他クラス分類問題はうまく機能しなかった
  • なので、よりシンプルなLeNetでやっぱり良いよね

 

結論

  • LeNetのような簡単なモデルでも(バイナリ分類問題だけど)精度良く分類することができたよ
  • 本当はもっと汎化的なモデルとなるように、多様な条件下で撮影した画像を含めるべきだと思っているよ
  • 白血球だけでなくその他の血中細胞やガン細胞にまでもこのような技術が使えることにエキサイトしているよ