TL; DR (要約)
AIは、医用画像を「見る」だけでなく、文脈を「理解」し、所見を「言葉にする」ことで、
医師の負担を軽減し、診断を支援する「第二の目」となります。その核心技術の概要です。
① 画像を「見る」AI
(CNN)
CNNというAIの「目」が、画像から線や模様といった単純な特徴を捉え、それらを組み合わせて病変などの複雑なパターンを認識します。
② 文脈を「理解する」AI
(マルチモーダル)
CLIP等の技術で、画像とカルテ情報(テキスト)を結びつけます。「この画像所見」と「この臨床経過」を統合し、より深い診断支援を可能にします。
③ 見たものを「言葉にする」AI
(画像キャプション)
画像の特徴を読み取り、「右肺上葉に結節影あり…」といった読影レポートの草案を自動生成。医師の文書作成業務を大幅に効率化します。
この章の学習目標と前提知識
日々、膨大な数の医用画像と向き合っている皆さんにとって、AI、特に最近話題の「生成系AI」が、自分たちの臨床や研究のフィールドにどのような変化をもたらすのか、期待と少しの疑問が入り混じった気持ちをお持ちかもしれません。この連載「作って理解する!シリーズ医療×生成系AI」では、そんな皆さんと一緒に、AIの可能性を一つひとつ手にとって確かめていくことを目指しています。今回はシリーズ第5回として、「医用画像診断支援AIの開発」という、まさに臨床の最前線に直結するテーマの扉を一緒に開いていきたいと思います。
X線、CT、MRI…。これらの医用画像は、言うまでもなく現代医療における診断の羅針盤です。しかし、山積みの読影依頼リストを前に、私たちは常に高い集中力を求められます。どれだけ経験を積んでも、「この微細な陰影、本当に見逃していないだろうか?」「もしかしたら、別の角度から見れば違う所見があったのでは?」という感覚は、画像診断に真摯に向き合う方ほど、共感いただけるのではないでしょうか。私自身も、そのようなプレッシャーを感じることがあります。
AIは、こうした私たちの負担や不安を解消し、業務の質をもう一段階引き上げてくれる、頼もしい「パートナー」になってくれるかもしれません。AIは決して私たちに取って代わる存在ではなく、むしろ私たちの能力を拡張し、診断の精度と自信を高めてくれる「第二の目」のような存在です。この記事では、AIがどのようにして私たちの「目」となり得るのか、その核心技術の全体像を一緒に見ていきたいと思います。
この記事ではまず、今後の学習の地図となるように、画像診断AIの領域で活躍する代表的な技術をダイジェストで巡っていきます。画像を”見る”AIの基本であるCNN、画像とカルテ情報を賢く結びつけるマルチモーダルAI、さらにはレポート作成を助けてくれる画像キャプション技術まで。少し聞いただけでも、ワクワクするようなテーマが並んでいると感じませんか?
もちろん、一つひとつの技術はとても奥深く、具体的なプログラミングやその背景にある数式の話は、この後の章や、さらに先の個別記事でじっくりと解説していきます。ですから、この導入に続く章では、「AIでこんなことができるのか!」という発見や驚きを大切にしながら、まずはリラックスして読み進めてみてください。さあ、一緒に未来の画像診断の世界を覗いてみましょう。
5.1 診断支援AIの基礎:CNNが画像を「見る」仕組み
さて、いよいよAI技術の中身に少し踏み込んでいきましょう。AIは一体どうやって、私たちと同じようにX線写真やCT画像を見て「何かがある」と判断しているのでしょうか?その答えの鍵を握るのが、画像認識の主役とも言えるCNN(Convolutional Neural Network:畳み込みニューラルネットワーク)です。
このCNN、実は私たちの脳が視覚情報を処理する仕組みにヒントを得て開発された、とても面白いモデルなんです(1)。私たちが物を見るとき、まず輪郭や色、模様といった単純な要素を捉え、それらを組み合わせて「顔」や「車」といった複雑な概念を認識しますよね。CNNもこれと似たようなことを、「畳み込み層」と「プーリング層」という特殊な層を何層にも重ねることで実現しています。
畳み込み層:画像の特徴を見つける「魔法の虫眼鏡」
CNNの心臓部とも言えるのが「畳み込み層」です。ここでは、フィルター(またはカーネル)と呼ばれる小さな正方形の行列を使って、画像の中から特定の特徴を探し出します。
このフィルターは、縦線や横線、特定の色のグラデーションといった、ごく単純なパターンを検出するための「魔法の虫眼鏡」だと考えてみてください。この虫眼鏡(フィルター)を、入力画像の左上から右下へとスライドさせながら、各部分を調べていきます。
上の図のように、フィルターを画像のある部分に重ね合わせ、対応するピクセルの値とフィルターの値をそれぞれ掛け合わせ、最後にすべてを足し合わせます(これを積和演算と呼びます)。この計算結果が、フィルターが探している特徴(この例では対角線的なパターン)に画像がどれだけ似ているかを示すスコアになります。このスコアを集めて作られる新しい画像が特徴マップ(Feature Map)です。
数式で書くと少し難しく見えるかもしれませんが、やっていることは非常にシンプルです。位置\( (i, j) \)における特徴マップのピクセル値は、入力画像\(I\)とフィルター\(K\)を使って以下のように計算されます。
\[ \text{FeatureMap}(i, j) = \sum_{m}\sum_{n} I(i+m, j+n) \cdot K(m, n) \]
この数式は、「画像の各部分とフィルターを重ねて、ピクセル値同士の掛け算を足し合わせている」という、先ほどの図の操作を表しているだけです。
CNNは、こうした異なるパターンを探すためのフィルターを何十、何百と用意し、それらを同時に適用することで、入力画像から多様な特徴マップを生成します。そして、層が深くなるにつれて、初期の層で抽出された「線」や「角」といった単純な特徴を組み合わせて、「目」や「鼻」のような、より複雑で意味のある特徴を捉えていくのです。ここがCNNの面白いところで、まるで職人が少しずつ部品を組み上げて作品を完成させていく過程に似ていると思いませんか?
プーリング層:特徴を要約し、位置のズレに強くする
畳み込み層でたくさんの特徴を抽出した後、次に登場するのが「プーリング層」です。この層の主な役割は2つあります。
- 特徴の要約と強調: 特徴マップを小さな領域に分割し、その領域の代表的な値(例えば最大値)だけを取り出すことで、情報を圧縮し、最も重要な特徴を際立たせます。
- 位置のズレに対する頑健性: 少し位置がズレても同じ特徴として認識できるようにします。例えば、病変が画像の少し右に写っていても、AIが「同じ病変だ」と判断しやすくなります。
この「畳み込み」と「プーリング」のセットを繰り返すことで、CNNは画像の広域的かつ抽象的な特徴を効率的に学習していきます。
2つの主要タスク:分類とセグメンテーション
さて、こうして画像の特徴を捉える力を手に入れたCNNを使って、私たちは主に2つの重要なタスクに挑みます。
1. 画像分類 (Image Classification)
これは、画像全体を見て、それがどのカテゴリに属するかを判定する、いわば「ラベル貼り」のタスクです。胸部X線写真から「正常」「肺炎の疑い」といったラベルを付けたり、皮膚の病変画像から良性か悪性かを判断したりします。
CNNの最終段には全結合層と呼ばれる部分があり、それまでの層で抽出してきた無数の特徴(線の断片、テクスチャ、特定の形状など)をすべて受け取ります。そして、それらの情報を総合的に評価し、「この特徴の組み合わせは、85%の確率で肺炎に合致する」といった最終的な判断を下します。この部分は、様々な科の専門医から集まった情報を元に最終診断を下す、総合診療医のような役割を担っているとイメージすると分かりやすいかもしれません。

2. 画像セグメンテーション (Image Segmentation)
こちらは、画像全体に一つのラベルを付ける分類とは異なり、画像のピクセル一つひとつに対して「ここは腫瘍」「ここは正常な肝臓」「ここは血管」といったように、細かく領域を塗り分けていく、より緻密なタスクです。
このタスクは、手術計画を立てる際に腫瘍の正確な範囲を特定したり、薬剤治療の効果を測るために病変の体積を経時的に追跡したりする上で、非常に大きな価値を持ちます。有名なU-Net(2)などのモデルは、画像の特徴を一度グッと圧縮し(エンコード)、その情報を元に今度は元の画像サイズへと復元しながら(デコード)、ピクセル単位で精密な塗り絵をしていくような見事な仕組みを持っています。
いかがでしたか?CNNが画像の特徴を捉え、それを元に判断を下す仕組みのイメージが、少しでも掴めたなら嬉しいです。この画像分類とセグメンテーションは、多くの診断支援AIの根幹をなす技術であり、診断の迅速化から治療計画の策定まで、その応用範囲は本当に広いんです。
5.2 マルチモーダルAI:画像と言葉、2つの世界を繋ぐCLIP
さて、先ほどのCNNの話は、AIに非常に優れた「目」を持たせる技術でした。しかし、私たちの臨床診断は「目」からの情報だけで完結することは、ほとんどありませんよね。
例えば、胸部X線で淡い陰影を見つけたとき、私たちは無意識に電子カルテを開き、患者さんの年齢、喫煙歴、発熱の有無といったテキスト情報を確認しているはずです。画像とテキスト、この2つの情報を頭の中で統合して、初めて精度の高い診断にたどり着くわけです。
では、AIにも私たちと同じように、複数の異なる情報源(これをモダリティと呼びます)を統合的に扱わせることはできないのでしょうか?それを実現するのがマルチモーダルAIです。そして、その代表格として今注目を集めているのが、CLIP (Contrastive Language-Image Pre-Training) というモデルです(3)。
CLIPの仕組みを理解する鍵は、その名前にもある「対照学習(Contrastive Learning)」という考え方にあります。これは一言で言うと、「正しいペアを引き寄せ、間違ったペアを遠ざける」という、非常に直感的でパワフルな学習方法です。
CLIPは、インターネット上にある膨大な「画像と、その画像を説明する文章」のペア(例えば、「夕日に照らされる猫の写真」とそのキャプション)を使って学習します。具体的には、以下のようなプロセスをたどります。
- エンコーダによるベクトル化:
画像は「画像エンコーダ」(CNNやVision Transformerなど)を通して、数値のリストである画像ベクトルに変換されます。
テキストは「テキストエンコーダ」(Transformerなど)を通して、同様にテキストベクトルに変換されます。
この「ベクトル」とは、AIが理解できる「意味」の住所のようなものだと考えてみてください。 - 対照学習による「意味空間」の形成:
学習の目的は、ある画像のベクトルと、その画像を正しく説明しているテキストのベクトルを、AIが認識する「意味の空間」の中で、できるだけ近くに配置することです。逆に、関係のない画像とテキストのペアは、その空間上で遠くに引き離します。
この学習を何億回と繰り返すことで、AIは画像の内容と単語の意味の関連性を学び、犬の画像と「犬」という単語、病院の画像と「病院」という単語が、それぞれ意味空間の近い場所にマッピングされるようになります。この「意味の空間」という考え方、なんだか詩的で面白いと思いませんか?初めてこの概念に触れたとき、私はAIがまるで人間のように「概念」を理解しようとしているように感じ、とても興奮したのを覚えています。
このベクトル同士の「近さ(類似度)」は、コサイン類似度という指標で計算されることが一般的です。
\[ \text{similarity} = \cos(\theta) = \frac{\mathbf{A} \cdot \mathbf{B}}{\|\mathbf{A}\| \|\mathbf{B}\|} \]
それでは、「ベクトル同士の近さ(類似度)」を表すコサイン類似度について、視覚的に理解しやすいように動的なイラストで解説しましょう。下のイラストの青いベクトルをドラッグして、角度と値がどう変わるか試してみてください。
数式が出てきましたが、これも本質は難しくありません。これは2つのベクトル \(\mathbf{A}\) と \(\mathbf{B}\) がなす角度 \(\theta\) を見て、その「向き」がどれだけ似ているかを測っているだけです。ベクトルが同じ方向を向いていれば類似度は1に、逆方向なら-1に、直角なら0になります。CLIPはこの類似度スコアが、正しいペアで最大に、間違ったペアで最小になるように学習を進めるわけです。
臨床現場での応用を想像してみる
では、この技術が私たちの臨床現場でどのように役立つのでしょうか?応用例は無限に考えられますが、いくつか想像してみましょう。
- 直感的で高度な画像検索:
例えば、あなたが「間質性肺炎の急性増悪が疑われる症例で、過去の類似画像を探したい」と思ったとします。そのとき、特定のキーワードで検索するのではなく、「咳嗽と呼吸困難で緊急入院した70代男性、CTでGGOパターン」といった普段私たちが使うような自然な文章で問い合わせるだけで、AIがその意味を理解し、膨大なデータベースの中から最も関連性の高い過去の画像とレポートを瞬時に提示してくれる…。そんな未来が想像できます。 - 診断精度の向上と新たな気づき:
あるいは、AIが画像とカルテを同時に読み解き、「このCTの所見は非典型的ですが、患者さんの過去の検査データや臨床経過を考慮すると、特定の希少疾患の可能性が示唆されます」といった、人間では見過ごしがちな情報間の隠れた関連性を見つけ出してくれるかもしれません。これは、診断のダブルチェック機能として、私たちの判断を力強くサポートしてくれるはずです。
CLIPのような技術は、AIを単なる「画像パターン認識機」から、文脈を理解する「思考のパートナー」へと進化させる大きな可能性を秘めています。画像と言葉の世界を自由に行き来できるAIは、私たちの診断能力をこれまでにないレベルへ引き上げてくれる、本当に頼もしいサポーターになるのではないでしょうか。
5.3 画像キャプションモデル:AIは見たものを「言葉」にできるか?
これまでのセクションで、AIが画像を「見る」仕組み(CNN)や、画像と言葉を関連付ける方法(CLIP)について見てきました。だんだんAIが賢いアシスタントに見えてきたのではないでしょうか。では、次の一歩として、AIが見たものを、私たちの使う自然な言葉で「記述する」ことは可能なのでしょうか?
一日の終わりに山積みの読影レポートを前に、キーボードを叩く時間は決して少なくありません。この、診断と同じくらい重要でありながら時間のかかる作業を、AIに手伝ってもらう。それを実現するのが、画像キャプションモデルです。これは文字通り、画像の内容を説明する文章(キャプション)を自動生成する技術で、生成系AIの応用として非常に期待されている分野です。
この技術の根幹にあるのは、エンコーダ・デコーダモデルと呼ばれる仕組みです。これは「画像を理解する部分」と「文章を生成する部分」の2つが連携して動作する、見事なアーキテクチャだと私は思います。
エンコーダ(The Eye):画像の本質を捉える
まず、エンコーダとして、私たちがセクション5.1で学んだCNNが登場します。CNNが医用画像をじっくりと「見て」、その中にある重要な視覚的特徴(例えば、結節の形状、濃度、場所など)を抽出し、それらをコンパクトな数値のリスト(特徴ベクトル)に変換します。これは、いわば画像の「エッセンス」や「指紋」のようなものです。
デコーダ(The Writer):エッセンスを文章に紡ぐ
次に、この画像のエッセンス(特徴ベクトル)を、デコーダであるTransformerなどの言語モデル(4)が受け取ります。デコーダは、この数値情報を頼りに、文法的に正しく、かつ画像の内容に即した文章を、単語を一つひとつ予測しながら生成していくのです。
この連携プレーを図にすると、以下のようなイメージになります。
デコーダが文章を生成する過程は、ただ一気に文章を出力するのではありません。もっと丁寧で、人間が文章を考える過程に少し似ています。
【デコーダによる逐次的な文章生成】
1. [画像ベクトル] を見て、最初の単語 "右肺上葉に" を予測。
2. [画像ベクトル] と "右肺上葉に" を見て、次の単語 "直径約15mmの" を予測。
3. [画像ベクトル] と "右肺上葉に 直径約15mmの" を見て、次の単語 "結節影を" を予測。
4. このプロセスを繰り返し、文末を示す特別な記号が出現するまで続ける。
このように一歩一歩、文脈を考慮しながら単語を紡いでいくことで、AIは驚くほど自然で的確な文章を作り出すことができるのです。
期待される効果:単なる時短以上の価値
この技術が臨床現場に導入されれば、どんな素晴らしいことが起きるでしょうか?
まず考えられるのは、もちろん業務負担の大幅な軽減です。AIがレポートの骨子となる「たたき台」を数秒で作成してくれるだけで、私たちがゼロから文章を組み立てる時間は劇的に短縮されます。その空いた時間を、より複雑な症例の検討や、患者さんとのコミュニケーション、あるいは研究活動といった、人間にしかできない、より本質的な業務に振り分けることができるようになるでしょう。
さらに、レポートの質の標準化にも繋がります。施設や個人の経験によって表現にばらつきが出がちな所見の記述を、AIが良いお手本を示すことで、誰が書いても分かりやすく質の高いレポートへと導いてくれるかもしれません。若手の医師や研修医にとっては、AIが生成した客観的な所見と自分の読影結果を比較検討することが、非常に効果的なトレーニングツールにもなり得ると考えられます。
忘れてはならない「Human-in-the-Loop」の原則
ここで一つ、非常に重要なことを強調しておかなければなりません。それは、AIが生成するのはあくまで「草案」であり、最終的な診断の責任は、必ず人間が担うという「Human-in-the-Loop(人間がループに介在する)」という原則です。
AIは強力なアシスタントですが、完璧ではありません。予期せぬ間違いを犯す可能性は常にあります。AIが生成したレポートを鵜呑みにするのではなく、専門家である私たちがその内容を厳しくレビューし、修正・追記し、最終的な承認を与える。このプロセスが不可欠です。
AIによる自動化を、完全な自動運転車として捉えるのではなく、あくまで世界で最も賢い「運転支援システム」だと考えてみてください。ハンドルを握り、最終的な判断を下し、全責任を負うのは、常にドライバーである私たち自身なのです。この人間とAIの適切な協働関係を築くことこそ、医療AIを安全かつ有効に活用するための鍵となります。
5.4 実践編:Pythonで診断支援AIの第一歩を踏み出そう
さて、これまでのセクションでAIが画像を「見る」「文脈を理解する」「言葉にする」ための理論的な側面を探ってきました。理論を学ぶのも大切ですが、やはり自分の手でコードを動かしてこそ、その面白さや難しさ、そして本当の可能性が実感できるものだと私は思います。
ここからは、いよいよお待ちかねの実践編です。これまでに学んだ知識を総動員して、実際に簡単な診断支援AIモデルを構築するプロセスを一緒に体験していきましょう。
AI開発の全体像:まず「地図」を手に入れよう
本格的なコーディングに入る前に、一般的なAI開発がどのような流れで進むのか、その全体像(ワークフロー)を掴んでおくと、今自分がどの段階にいるのかを見失わずに済みます。
graph TD
subgraph AIモデル開発の基本的なワークフロー
A["[1. 課題設定]
「何を解決したいのか?」
(例: CT画像から肺結節を見つけたい)"]
B["[2. データ収集・準備]
「AIの教科書を集めて、読みやすくする」
(例: 肺結節のCT画像とアノテーションデータを集め、前処理する)"]
C["[3. モデル設計・構築]
「どんな脳(AIモデル)を作るか決める」
(例: CNNベースのモデルを設計する)"]
D["[4. 学習]
「教科書でAIをトレーニングする」
(例: 大量の画像データでモデルを学習させる)"]
E["[5. 評価]
「AIの実力をテストする」
(例: 未知の画像でモデルの精度を評価する)"]
F["[6. デプロイと改善]
「現場で使えるようにし、継続的に賢くする」
(例: 院内システムに組み込み、新しいデータで再学習する)"]
end
A --> B
B --> C
C --> D
D --> E
E --> F
%% スタイル定義: 3番目のステップを強調表示 %%
style C fill:#fff3e0,stroke:#ff9800,stroke-width:3px,stroke-dasharray: 5 5
今回は、この中から特に[3]〜[5]のプロセスを中心に、手を動かしながら学んでいきます。
データセット:AIを育てるための「教科書」
AIの性能は、アルゴリズムの優劣だけでなく、学習に使う「データ」の質と量に大きく左右されます。どんなに優れたAIモデルも、質の悪いデータや偏ったデータで学習させてしまっては、その能力を十分に発揮できません。データは、AIにとっての教科書であり、栄養源なのです。
幸いなことに、医療AI研究の発展のために、世界中の研究機関が質の高い医用画像データセットを公開してくれています。有名なものには、以下のようなものがあります。
- NIH Chest X-ray Dataset(5): 10万枚以上の胸部X線画像という膨大なデータセットで、肺疾患研究のベンチマークとして広く利用されています。
- The Cancer Imaging Archive (TCIA)(6): 様々ながんに関するCT、MRI、PETなどの画像を、臨床情報と共に体系的に集めた巨大なアーカイブです。
- MedPix®: 症例情報と関連付けられた5万枚以上の医用画像データベースで、教育的な価値も非常に高いです。
これらのデータセットを利用する際は、それぞれのライセンス規約をよく確認し、患者さんのプライバシー保護(匿名化など)に最大限の敬意を払うことが、研究者としての大前提となります。
ハンズオン:簡単な図形を識別するCNNモデルを作ってみよう
実際の医用画像データは非常に大きく、扱うには専門的な知識と高い計算能力が必要です。そこで今回は、AI開発の基本ワークフローを体験することを目的に、「円」と「四角」の簡単な図形を識別するという、とてもシンプルなタスクに挑戦します。
「なぜそんな簡単なことから?」と思うかもしれませんが、侮ってはいけません。このシンプルなタスクの中に、データ準備からモデル構築、学習、評価というAI開発のエッセンスがすべて凝縮されています。まずはここで基本の型を身につけ、自信を深めていきましょう。
【実行前の準備】
以下のコードを動かすには、いくつかのライブラリ(便利な機能をまとめたプログラムの集まり)が必要です。pip install tensorflow scikit-learn matplotlib japanize-matplotlib といったコマンドをターミナル(Mac)やコマンドプロンプト(Windows)で実行し、あらかじめインストールしておいてください。
【Pythonコード】
さあ、いよいよコーディングです。以下のコードは、ステップごとに区切られています。一つひとつの命令が何をしているのか、コメントを頼りにじっくりと追いかけてみてください。エラーが出ても大丈夫。それも学習の重要な一部です。
graph TD
subgraph "AI開発プロセス"
A["開始"] --> B["1. データ準備
(円/四角の画像を生成し、学習/テスト用に分割)"];
B --> C["2. モデル構築
(画像の特徴を捉えるCNNモデルを設計)"];
C --> D["3. 学習実行
(学習用データでモデルをトレーニング)"];
D --> E["4. モデル評価
(テストデータで学習済みモデルの性能を評価)"];
E --> F["5. 予測と可視化
(AIに未知の画像を分類させ、結果を表示)"];
F --> G["終了"];
end
# --- 0. 準備運動:必要なライブラリ(道具箱)をインポート ---
import numpy as np # 数値計算や多次元配列を効率的に扱うためのライブラリ
import matplotlib.pyplot as plt # データをグラフや画像として可視化するためのライブラリ
import japanize_matplotlib # Matplotlibで日本語を正しく表示するためのライブラリ
import tensorflow as tf # Googleが開発した深層学習のフレームワーク。AIモデルの構築や学習の心臓部
from tensorflow.keras.models import Sequential # 層を積み重ねるように直感的にモデルを構築するためのクラス
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense # CNNを構成する各層の部品
from sklearn.model_selection import train_test_split # データを訓練用とテスト用に分割する便利な関数
# --- 1. データ準備:AIの教科書(ダミー画像)を作成 ---
# ここでは「円(ラベル=0)」と「四角(ラベル=1)」の白黒画像をプログラムで生成します。
def create_dummy_images(num_images, img_size=28):
images = [] # 生成した画像データを格納するリスト
labels = [] # 各画像が円か四角かを示す正解ラベルを格納するリスト
for i in range(num_images):
fig, ax = plt.subplots(figsize=(img_size/100, img_size/100), dpi=100) # Adjust figsize and dpi for desired pixel size
ax.set_xlim(0, img_size)
ax.set_ylim(0, img_size)
ax.axis('off') # 軸や目盛りは不要なので非表示に
# 偶数番目は円、奇数番目は四角を描画
if i % 2 == 0:
# 円を描画(中心や半径はランダムにして多様性を出す)
center_x, center_y = np.random.randint(10, 18, 2)
radius = np.random.randint(5, 9)
circle = plt.Circle((center_x, center_y), radius, color='black')
ax.add_patch(circle)
labels.append(0) # 円のラベルは0
else:
# 四角を描画(位置やサイズはランダム)
start_x, start_y = np.random.randint(5, 12, 2)
width, height = np.random.randint(8, 15, 2)
rect = plt.Rectangle((start_x, start_y), width, height, color='black')
ax.add_patch(rect)
labels.append(1) # 四角のラベルは1
# 描画した図をピクセルの配列(Numpy配列)に変換
fig.canvas.draw()
# Use buffer_rgba() and convert to RGB
buf = fig.canvas.buffer_rgba()
img = np.asarray(buf)
img = img[:, :, :3] # Remove alpha channel
img = tf.image.rgb_to_grayscale(img) # 白黒画像に変換
img = tf.image.resize(img, [img_size, img_size]) # 28x28ピクセルに統一
images.append(img.numpy())
plt.close(fig) # メモリを消費しないように図を閉じる
# AIが扱いやすいように、ピクセル値を0から1の範囲に正規化
images = np.array(images, dtype=np.float32) / 255.0
labels = np.array(labels, dtype=np.int32)
return images, labels
print("ダミー画像の生成を開始します...")
images, labels = create_dummy_images(200) # 合計200枚の画像を生成
print(f"画像生成完了。画像データの形状: {images.shape}, ラベルデータの形状: {labels.shape}")
# AIの学習用(80%)とテスト用(20%)にデータを分割
# テスト用データは、AIが学習中に一度も見たことがない「実力試験」用の問題です
X_train, X_test, y_train, y_test = train_test_split(images, labels, test_size=0.2, random_state=42)
# --- 2. モデル構築:CNNという「脳」を設計 ---
# Sequentialモデルは、層を順番に積み重ねるだけのシンプルなモデル
model = Sequential([
# 入力層 兼 第1畳み込み層:入力は28x28の白黒画像(チャンネル=1)。3x3のフィルターを32個使用
Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
# 第1プーリング層:画像サイズを半分(13x13)にし、特徴を強調
MaxPooling2D((2, 2)),
# 第2畳み込み層:フィルターを64個に増やし、より複雑な特徴を抽出
Conv2D(64, (3, 3), activation='relu'),
# 第2プーリング層:さらに画像サイズを半分(5x5)に
MaxPooling2D((2, 2)),
# 平坦化層(Flatten):2次元の画像データを、次の全結合層で扱えるように1次元のベクトルに変換
Flatten(),
# 全結合層(Dense):抽出されたすべての特徴を統合して判断する部分
Dense(64, activation='relu'),
# 出力層:最終的に「円」か「四角」かの2択なので、出力ユニットは1つ。
# sigmoid関数で、結果を0(円)〜1(四角)の確率として出力する
Dense(1, activation='sigmoid')
])
# モデルの全体像を確認
print("\n--- モデルの構造 ---")
model.summary()
# --- 3. 学習設定:モデルの「学習方法」を定義 ---
# compileメソッドで、最適化アルゴリズム、損失関数、評価指標を設定
model.compile(optimizer='adam', # 最も一般的に使われる最適化手法の一つ
loss='binary_crossentropy', # 2値分類でよく使われる損失関数(間違いの度合いを測る指標)
metrics=['accuracy']) # 学習の進捗を「正解率」でモニターする
# --- 4. 学習開始:AIのトレーニングを実行 ---
print("\nモデルの学習を開始します...")
# 訓練データ(X_train, y_train)を使って、モデルを10回繰り返し学習(epochs=10)
history = model.fit(X_train, y_train, epochs=10, validation_split=0.2, verbose=1)
print("学習が完了しました。")
# --- 5. 評価:学習済みAIの実力をテスト ---
print("\n学習済みモデルをテストデータで評価します...")
# 学習に使っていないテストデータ(X_test, y_test)で最終的な性能を確認
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=2)
print(f'\nテストデータでの正解率: {test_acc:.4f}')
# --- 6. 予測と可視化:AIに実際に問題を解かせてみる ---
print("\nテストデータに対する予測結果を可視化します...")
predictions = model.predict(X_test)
class_names = ['円', '四角']
plt.figure(figsize=(10, 10))
# テストデータから最初の9枚を取り出して、AIの予測結果と正解を一緒に表示
for i in range(9):
plt.subplot(3, 3, i + 1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(X_test[i].reshape(28, 28), cmap=plt.cm.binary) # 画像を表示
# AIの予測確率が0.5以上なら「四角」、未満なら「円」と判断
predicted_label_index = 1 if predictions[i][0] > 0.5 else 0
true_label_index = y_test[i]
# 予測が正解なら青、不正解なら赤でラベルを表示
color = 'blue' if predicted_label_index == true_label_index else 'red'
plt.xlabel(f"予測: {class_names[predicted_label_index]}\n正解: {class_names[true_label_index]}", color=color)
plt.tight_layout()
plt.show() # 作成したグラフを表示
コードの実行結果と解説
このコードを実行すると、ターミナルやノートブック上には、モデルの構造、学習の進捗、そして最終的な評価結果が表示されます。
ダミー画像の生成を開始します...
画像生成完了。画像データの形状: (200, 28, 28, 1), ラベルデータの形状: (200,)
--- モデルの構造 ---
/usr/local/lib/python3.11/dist-packages/keras/src/layers/convolutional/base_conv.py:107: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.
super().__init__(activity_regularizer=activity_regularizer, **kwargs)
Model: "sequential"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type) ┃ Output Shape ┃ Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ conv2d (Conv2D) │ (None, 26, 26, 32) │ 320 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d (MaxPooling2D) │ (None, 13, 13, 32) │ 0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_1 (Conv2D) │ (None, 11, 11, 64) │ 18,496 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d_1 (MaxPooling2D) │ (None, 5, 5, 64) │ 0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ flatten (Flatten) │ (None, 1600) │ 0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense) │ (None, 64) │ 102,464 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense) │ (None, 1) │ 65 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 121,345 (474.00 KB)
Trainable params: 121,345 (474.00 KB)
Non-trainable params: 0 (0.00 B)
モデルの学習を開始します...
Epoch 1/10
4/4 ━━━━━━━━━━━━━━━━━━━━ 2s 142ms/step - accuracy: 0.5521 - loss: 0.6835 - val_accuracy: 0.5000 - val_loss: 0.6958
Epoch 2/10
4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 48ms/step - accuracy: 0.5792 - loss: 0.6750 - val_accuracy: 0.7188 - val_loss: 0.6520
Epoch 3/10
4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 50ms/step - accuracy: 0.6740 - loss: 0.6456 - val_accuracy: 0.7188 - val_loss: 0.6210
Epoch 4/10
4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 65ms/step - accuracy: 0.7406 - loss: 0.6055 - val_accuracy: 0.7500 - val_loss: 0.5858
Epoch 5/10
4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 50ms/step - accuracy: 0.7781 - loss: 0.5676 - val_accuracy: 0.7500 - val_loss: 0.5518
Epoch 6/10
4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 46ms/step - accuracy: 0.7417 - loss: 0.5474 - val_accuracy: 0.7812 - val_loss: 0.5086
Epoch 7/10
4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 47ms/step - accuracy: 0.8052 - loss: 0.5006 - val_accuracy: 0.8125 - val_loss: 0.4887
Epoch 8/10
4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 68ms/step - accuracy: 0.7781 - loss: 0.4709 - val_accuracy: 0.9062 - val_loss: 0.4373
Epoch 9/10
4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 54ms/step - accuracy: 0.8427 - loss: 0.4298 - val_accuracy: 0.8125 - val_loss: 0.4014
Epoch 10/10
4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 49ms/step - accuracy: 0.8156 - loss: 0.4389 - val_accuracy: 0.8125 - val_loss: 0.3889
学習が完了しました。
学習済みモデルをテストデータで評価します...
2/2 - 0s - 127ms/step - accuracy: 0.7500 - loss: 0.5225
テストデータでの正解率: 0.7500
テストデータに対する予測結果を可視化します...
2/2 ━━━━━━━━━━━━━━━━━━━━ 0s 88ms/step

モデルの構造 (`model.summary()` の出力)
以下は、私たちが構築したCNNモデルの設計図です。データが各層を通過するごとに、その形状(Output Shape)がどう変化していくかが一目瞭然ですね。
--- モデルの構造 ---
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 26, 26, 32) 320
max_pooling2d (MaxPooling2D (None, 13, 13, 32) 0
)
conv2d_1 (Conv2D) (None, 11, 11, 64) 18496
max_pooling2d_1 (MaxPoolin (None, 5, 5, 64) 0
g2D)
flatten (Flatten) (None, 1600) 0
dense (Dense) (None, 64) 102464
dense_1 (Dense) (None, 1) 65
=================================================================
Total params: 121345 (474.00 KB)
Trainable params: 121345 (474.00 KB)
Non-trainable params: 0 (0.00 KB)
_________________________________________________________________
Param # は、AIが学習するパラメータ(重み)の数です。この数が多いほど、より複雑なモデルと言えますが、学習も大変になります。
学習の進捗
model.fit() を実行すると、学習が1エポック(全訓練データを1回見ること)進むごとに、損失(loss)が下がり、正解率(accuracy)が上がっていく様子がリアルタイムで表示されます。これは、AIが間違いから学んで少しずつ賢くなっていく過程そのもので、見ていてとても面白い部分です。
最終結果の可視化
すべてが上手くいけば、最後に表示される9つの画像では、ほとんど(あるいはすべて)の予測が正解し、ラベルが青色で表示されているはずです。AIが、一度も見たことのない「円」と「四角」を正しく見分けられた瞬間です。ちょっと感動しませんか?
まとめと展望
今回は、シリーズ第5回の内容として、医用画像診断支援AIの主要な技術をダイジェストでご紹介しました。
- CNNを基盤とした画像の分類とセグメンテーション
- マルチモーダルAI (CLIP)による画像とテキストの統合的解釈
- 画像キャプションモデルによる診断レポート草案の自動生成
- 公開データセットを用いた実践的なモデル構築への道筋
これらの技術は、もはや遠い未来の話ではありません。診断の精度と効率を飛躍的に向上させ、医師がより人間的な洞察やコミュニケーションに集中できる未来を創り出す、強力なツールとなりつつあります(7)。
本シリーズを通して、これらの技術を理論だけでなく、ご自身のPCでコードを動かしながら「作って理解する」ことで、皆様の臨床や研究における新たな武器となることを目指します。
次回、第6回は「臨床文書の要約と構造化によるナレッジ活用」と題し、AIを用いて電子カルテや医学論文といった膨大なテキスト情報を効率的に処理・活用する技術について探求していきます。
参考文献
- (1) Krizhevsky A, Sutskever I, Hinton GE. ImageNet classification with deep convolutional neural networks. Commun ACM. 2017;60(6):84-90.
- (2) Ronneberger O, Fischer P, Brox T. U-Net: Convolutional networks for biomedical image segmentation. In: Navab N, Hornegger J, Wells WM, Frangi AF, editors. Medical Image Computing and Computer-Assisted Intervention – MICCAI 2015. Cham: Springer International Publishing; 2015. p. 234-41.
- (3) Radford A, Kim JW, Hallacy C, Ramesh A, Goh G, Agarwal S, et al. Learning transferable visual models from natural language supervision. In: Proceedings of the 38th International Conference on Machine Learning. PMLR; 2021. p. 8748-63.
- (4) Vaswani A, Shazeer N, Parmar N, Uszkoreit J, Jones L, Gomez AN, et al. Attention is all you need. In: Advances in Neural Information Processing Systems 30. Curran Associates, Inc.; 2017. p. 5998-6008.
- (5) Wang X, Peng Y, Lu L, Lu Z, Bagheri M, Summers RM. ChestX-ray8: Hospital-scale chest x-ray database and benchmarks on weakly-supervised classification and localization of common thorax diseases. In: 2017 IEEE Conference on Computer Vision and Pattern Recognition (CVPR). Honolulu, HI: IEEE; 2017. p. 3462-71.
- (6) Clark K, Vendt B, Smith K, Freymann J, Kirby J, Koppel P, et al. The Cancer Imaging Archive (TCIA): Maintaining and operating a public information repository. J Digit Imaging. 2013;26(6):1045-57.
- (7) Topol EJ. High-performance medicine: the convergence of human and artificial intelligence. Nat Med. 2019;25(1):44-56.
ご利用規約(免責事項)
当サイト(以下「本サイト」といいます)をご利用になる前に、本ご利用規約(以下「本規約」といいます)をよくお読みください。本サイトを利用された時点で、利用者は本規約の全ての条項に同意したものとみなします。
第1条(目的と情報の性質)
- 本サイトは、医療分野におけるAI技術に関する一般的な情報提供および技術的な学習機会の提供を唯一の目的とします。
- 本サイトで提供されるすべてのコンテンツ(文章、図表、コード、データセットの紹介等を含みますが、これらに限定されません)は、一般的な学習参考用であり、いかなる場合も医学的な助言、診断、治療、またはこれらに準ずる行為(以下「医行為等」といいます)を提供するものではありません。
- 本サイトのコンテンツは、特定の製品、技術、または治療法の有効性、安全性を保証、推奨、または広告・販売促進するものではありません。紹介する技術には研究開発段階のものが含まれており、その臨床応用には、さらなる研究と国内外の規制当局による正式な承認が別途必要です。
- 本サイトは、情報提供を目的としたものであり、特定の治療法を推奨するものではありません。健康に関するご懸念やご相談は、必ず専門の医療機関にご相談ください。
第2条(法令等の遵守)
利用者は、本サイトの利用にあたり、医師法、医薬品、医療機器等の品質、有効性及び安全性の確保等に関する法律(薬機法)、個人情報の保護に関する法律、医療法、医療広告ガイドライン、その他関連する国内外の全ての法令、条例、規則、および各省庁・学会等が定める最新のガイドライン等を、自らの責任において遵守するものとします。これらの適用判断についても、利用者が自ら関係各所に確認するものとし、本サイトは一切の責任を負いません。
第3条(医療行為における責任)
- 本サイトで紹介するAI技術・手法は、あくまで研究段階の技術的解説であり、実際の臨床現場での診断・治療を代替、補助、または推奨するものでは一切ありません。
- 医行為等に関する最終的な判断、決定、およびそれに伴う一切の責任は、必ず法律上その資格を認められた医療専門家(医師、歯科医師等)が負うものとします。AIによる出力を、資格を有する専門家による独立した検証および判断を経ずに利用することを固く禁じます。
- 本サイトの情報に基づくいかなる行為によって利用者または第三者に損害が生じた場合も、本サイト運営者は一切の責任を負いません。実際の臨床判断に際しては、必ず担当の医療専門家にご相談ください。本サイトの利用によって、利用者と本サイト運営者の間に、医師と患者の関係、またはその他いかなる専門的な関係も成立するものではありません。
第4条(情報の正確性・完全性・有用性)
- 本サイトは、掲載する情報(数値、事例、ソースコード、ライブラリのバージョン等)の正確性、完全性、網羅性、有用性、特定目的への適合性、その他一切の事項について、何ら保証するものではありません。
- 掲載情報は執筆時点のものであり、予告なく変更または削除されることがあります。また、技術の進展、ライブラリの更新等により、情報は古くなる可能性があります。利用者は、必ず自身で公式ドキュメント等の最新情報を確認し、自らの責任で情報を利用するものとします。
第5条(AI生成コンテンツに関する注意事項)
本サイトのコンテンツには、AIによる提案を基に作成された部分が含まれる場合がありますが、公開にあたっては人間による監修・編集を経ています。利用者が生成AI等を用いる際は、ハルシネーション(事実に基づかない情報の生成)やバイアスのリスクが内在することを十分に理解し、その出力を鵜呑みにすることなく、必ず専門家による検証を行うものとします。
第6条(知的財産権)
- 本サイトを構成するすべてのコンテンツに関する著作権、商標権、その他一切の知的財産権は、本サイト運営者または正当な権利を有する第三者に帰属します。
- 本サイトのコンテンツを引用、転載、複製、改変、その他の二次利用を行う場合は、著作権法その他関連法規を遵守し、必ず出典を明記するとともに、権利者の許諾を得るなど、適切な手続きを自らの責任で行うものとします。
第7条(プライバシー・倫理)
本サイトで紹介または言及されるデータセット等を利用する場合、利用者は当該データセットに付随するライセンス条件および研究倫理指針を厳格に遵守し、個人情報の匿名化や同意取得の確認など、適用される法規制に基づき必要とされるすべての措置を、自らの責任において講じるものとします。
第8条(利用環境)
本サイトで紹介するソースコードやライブラリは、執筆時点で特定のバージョンおよび実行環境(OS、ハードウェア、依存パッケージ等)を前提としています。利用者の環境における動作を保証するものではなく、互換性の問題等に起因するいかなる不利益・損害についても、本サイト運営者は責任を負いません。
第9条(免責事項)
- 本サイト運営者は、利用者が本サイトを利用したこと、または利用できなかったことによって生じる一切の損害(直接損害、間接損害、付随的損害、特別損害、懲罰的損害、逸失利益、データの消失、プログラムの毀損等を含みますが、これらに限定されません)について、その原因の如何を問わず、一切の法的責任を負わないものとします。
- 本サイトの利用は、学習および研究目的に限定されるものとし、それ以外の目的での利用はご遠慮ください。
- 本サイトの利用に関連して、利用者と第三者との間で紛争が生じた場合、利用者は自らの費用と責任においてこれを解決するものとし、本サイト運営者に一切の迷惑または損害を与えないものとします。
- 本サイト運営者は、いつでも予告なく本サイトの運営を中断、中止、または内容を変更できるものとし、これによって利用者に生じたいかなる損害についても責任を負いません。
第10条(規約の変更)
本サイト運営者は、必要と判断した場合、利用者の承諾を得ることなく、いつでも本規約を変更することができます。変更後の規約は、本サイト上に掲載された時点で効力を生じるものとし、利用者は変更後の規約に拘束されるものとします。
第11条(準拠法および合意管轄)
本規約の解釈にあたっては、日本法を準拠法とします。本サイトの利用および本規約に関連して生じる一切の紛争については、東京地方裁判所を第一審の専属的合意管轄裁判所とします。
For J³, may joy follow you.

