脳のMRI画像から腫瘍があるか判定するアプリを作ってみた

注意事項

今回の作品は、機械学習を学ぶために作成した個人向けのアプリです。
十分に検証された内容ではありませんので、実際の業務や診療等では使用しないようにご留意下さい。

1.はじめに

最近機械学習やデータサイエンス等の領域にハマっており、産業や業務をハックするためにはどんな使い方をしたらいいか、というのを四六時中考えています。
手始めに、月並みなテーマではありますが、今まで人が診断していた医療画像を機械にやらせたらどうなるか、どれ程の精度が出せるのかを自分で試してみたくなり、脳のMRI画像から腫瘍があるかを判定するアプリを作成してみました。

4_no.jpg

↓作成したアプリはこちらです
https://tumor-detection-app.onrender.com/

↓コードは全てGithubで公開してます
https://github.com/buono/tumor-detection-app

2.開発環境

・MacBook Pro M1 Max
・macOS 13.2.1
・Google Colaborabory(GPU Tesla T4, 525.105.17, 15360 MiB)
・Python(Ver 3.11.3)

3.使用したライブラリ

・TensorFlow:2.12.0使用
Googleが開発した機械学習のためのライブラリ。

・OpenCV:4.8.0使用
Open Source Computer Vision Libraryの略で画像処理・画像解析に使用するライブラリ。

・Numpy:1.23.5使用
Pythonで数値計算を行うためのライブラリ。

・Flask:2.0.1
PythonでWebアプリケーションを作成するためのライブラリ。
DeployするバージョンをRequirements.txt内で指定できます。

※ちなみに、Google colaboratory上で各ライブラリのバージョンを確認する時は下記コマンドを使います。
例:Numpyのバージョン確認方法

4.学習データの準備

Kaggleで公開されている脳のMRIの画像データセットを使用。
"Brain MRI Images for Brain Tumor Detection"
https://www.kaggle.com/datasets/navoneel/brain-mri-images-for-brain-tumor-detection

このZipファイルをあらかじめダウンロードしておき、解凍した上で作業ファイルと同じ階層に保存しておきます。

5.学習モデルの構築

次に、Google Colaboratory上でモデルを作成します。機械学習はこの作業が一番のハイライト。

下準備

まずはGoogle drive上のファイルをColaboratory上から使えるように、ドライブをマウントします。

次に関連ライブラリのインポートします。機械学習用のフレームワークはTensorFlowとPyTorchが二大巨頭で、今回はTensorFlowを使います。
それぞれのライブラリの使い方は別途説明します。

パスと画像リストを取得します。

データの加工

機械学習をしやすいように、画像のリサイズと並べ替え等をします。

モデルの構築

ここと次のセクションが一番機械学習っぽいところです。
今回は転移学習という学習方法を使います。
これは、ゼロからモデルを作り上げるのではなく、あらかじめ作られた学習済みモデルを利用し、それに追加する形でモデルを自分流にカスタマイズするものです(ファインチューニングとも言います)。
モデルをゼロから作るのは労力がものすごいかかるので、一般的にも良く使われています。IT業界でよく言う、「巨人の肩の上に乗る」ってやつですね。

転移学習の元となる学習済みモデルはたくさんの種類がありますが、その中でもスタンダードなVGG16というモデルを使いました。
これは、imagenetという、1400万枚のラベル付き画像を元に作られたいくつかの学習モデルのうちの一つです。
参考:https://paperswithcode.com/dataset/imagenet

転移学習では、元のモデルを完全にそのまま踏襲するか、それとも再学習するかという点も選ぶことができます。
ここでは、下記2行の箇所で、19層目まで、つまり出力層以外の全ての層を固定しているので完全踏襲しています。
(vgg16は出力層合わせて全20層から成っています)

下記が作成したモデルの出力結果です。

モデルの内容が問題なければ、最後にcompileをしてモデルを完成させます。
(ここの処理の概念は分かり辛いですが、自分はモデルをテキストからバイナリファイルに変換するイメージを持ってます)
なお、見慣れない単語が並んでいますが、ここで重要なのは「どのように学習を進めていくか」を設定している点です。

今までのテスト勉強や受験勉強を思い出せば分かると思いますが、自分の進むべき道が分からないとどう勉強していいか分からないですよね。
それを設定しているのがここの行です。
専門的には損失関数や最適化関数と言い、どうやって、どれくらいのスピードで精度を上げていくかといったことをここでパラメータとして設定します。
(このように人が調整するパラメータを、ハイパーパラメータと呼んだりします)

このあたりは下記ページの解説が分かりやすいので、余力のある人は見てみて下さい。
https://qiita.com/omiita/items/1735c1d048fe5f611f80

6.モデルの学習と評価

それでは、作成したモデルに入力データと出力ラベルを割り当て、学習を進めます。
ここでいう学習とは、それぞれの重みとバイアスが最適になるように値を調整する事です。
model.fitを使って訓練データを与え、バッチサイズ、エポック数を設定することで学習を開始してくれます。
バッチサイズは学習データをいくつかのグループに分けた際の各グループのデータ数のことで、エポック数は何回学習を繰り返すか、ということです。
いずれも数を増やせばいいのか、というとそうでもなく、処理時間や過学習や目標精度などを考慮し、トライ&エラーで数を選びます。
ここではバッチサイズ100、エポック数10としました。

一度学習したモデルは保存しておくと後で使い回せて便利なので、良い結果が出たら保存しておきましょう。
また、このモデルは後ほどアプリ内でも使用します。

ここでは、model.evaluateでテストデータと比較した結果、0.80の精度(的中率80%)が出たのでまずまずの結果だと思います。

あと、後ほど学習履歴をグラフ化するためにmodel.fitでの学習履歴をhistory変数に入れておきます。

学習履歴
image.png

7.検証

これでモデルの作成は完了ですが、正しく画像を判定できているかも念のため確認しておきましょう。

以下は出力結果の一部です。
image.png
1/1 [==============================] - 0s 37ms/step
no

8.Renderへのデプロイ

最後の仕上げとして、作成したモデルを使ってWEBアプリを作成していきます。
モデルができたら、Google Colaboratoryの役目は終了です。
コードエディタを立ち上げ、以下ファイルを作成していきます。

今回は機械学習によるモデル作成の説明がメインなので、説明は割愛します。詳細は下記GitHubのコードをご覧ください。
https://github.com/buono/tumor-detection-app

下記が完成したサイトです。Renderを使用しています。ローカル環境と同じように、画像をアップすると概ね正しく腫瘍の有無を判定してくれている事が確認できました。
https://tumor-detection-app.onrender.com/

9.まとめ

考察

Kaggleで公開されている腫瘍の画像は数100枚しかなく、高い精度が出せないかと思いましたが80%程度の精度は出す事ができました。
ただし、学習履歴を見る限り、精度が右肩上がりになっていないので学習がうまくいっているとは完全に言えない状況です。

今後の展望としては、画像反転や回転、位置ずらしなどによる画像数の増加等でさらに精度アップが期待できると思います。

また、モデルの選定や損失関数・最適化関数の選定も十分にできたとは言えないので、そちらに関しても他のを選ぶことでもっと精度が良くなる可能性もあると思います。

コードは全て公開していますので、もし興味のある方はトライしてみてはいかがでしょうか。

所感

機械学習が産業・業務にどのように活かせるか?を確認したく、今回、このようなアプリを作成しました。
結果として、プロトタイプの完成度ながらも高い精度が出せたので、やはり機械学習のポテンシャルは高く、今後更に浸透していくのではないかと感じさせられました。
その意味で、今回の目的は十分に達成できました。

ただし一方で、精度を上げる事の難しさも分かり、今回のように人の命に関わるようなところで機械学習を使用する場合、やはり人の目も必要だという事を実感できました。
ということで、当面は人と機械が共存する未来が見えました。

改めてですが、今回の作品は、機械学習を学ぶために作成した個人向けのアプリです。
十分に検証された内容ではありませんので、実際の業務や診療等では使用しないようにご留意下さい。

それでは今回の検証は以上となります。