AIはどのように間違いから学び、賢くなるのでしょうか。その心臓部である「順伝播(予測)」と「誤差逆伝播(学習)」という2つのプロセスを、計算グラフという見やすい地図を使いながら解き明かします。
入力データが計算グラフを通り、最終的な予測値を算出する一方向の流れ。AIが結論を導き出す思考プロセスそのものです。
予測と正解の「誤差」から出発し、逆向きに各パラメータの責任(勾配)を計算。AIが自身を修正する核心部分です。
医学研究者・臨床医の皆様、こんにちは。この「Medical AI with Python」シリーズへ、再びようこそ。
これまでの道のりで、私たちはニューラルネットワークというAIの頭脳にデータを与えると、まるで経験豊富な専門医のように、驚くほど的確な予測を返してくれる例を見てきました。しかし、ここで一つ、とても大切な疑問が浮かび上がります。生まれたばかりのAIは、最初から賢いわけではありません。では、どうやって「間違い」から学び、一人前の専門家のように成長していくのでしょうか?
指導医が研修医に「その診断は少し違う、この所見を見落としているよ」とフィードバックを与えるように、誰かがAIに「その予測は良かった」「ここは見当違いだ」と、一つひとつ教えているのでしょうか?
実は、AIも自己評価と反省を通じて成長します。その「フィードバック」と「学習」の仕組みこそが、今回のメインテーマである誤差逆伝播法(ごさぎゃくでんぱほう、Backpropagation)なんです。これは文字通り、AIが算出した予測の「誤差」を、ニューラルネットワークの回路網に「逆向きに伝播」させて、自身のパラメータを微調整していくプロセスを指します。
そして、そのフィードバックがAIの神経回路の隅々まで、どのように伝わっていくのかを解き明かすための「解剖図」の役割を果たすのが、計算グラフ(Computation Graph)です。
一見すると複雑そうな言葉が並びましたが、心配はいりません。本講座では、このAIの学習メカニズムの心臓部を、計算グラフという分かりやすい地図を頼りに、一緒に探検していきます。
この概念を肌で理解することは、単に技術的な知識を得る以上の意味を持っています。将来、皆さんがAIを単に「使う」だけでなく、ご自身の研究に合わせて「育てる」、あるいはAIが出した結果の妥当性を「吟味する」際に、この知識は揺るぎない自信を与えてくれるはずです。AIを信頼できるパートナーとするための、今日は最も重要な一歩になる、と言っても過言ではないでしょう。
• ノードをドラッグして位置を調整できます
• 「順伝播を開始」で入力から出力への情報伝達を表示
• 「誤差逆伝播を開始」で出力から入力への誤差伝播を表示
• 実際の学習では、この逆伝播で各層の重みが更新されます
計算グラフとは?思考のプロセスを可視化する
AIの「頭の中」を、一度覗いてみたいと思ったことはありませんか? 実は、AIがどのように結論を導き出しているのか、その思考の道のりを地図のように描き出す素晴らしい方法があるんです。それが、今回ご紹介する計算グラフ(Computation Graph)です。
一見すると難しそうに聞こえるかもしれませんが、これは非常に直感的なツールです。計算グラフとは、一言でいえば「計算の流れを可視化した図」のこと。なんだか、料理のレシピに似ているかもしれませんね。レシピでは「材料AとBを混ぜる」「オーブンで焼く」といった各工程を経て、最終的に一つの料理が完成します。
計算グラフでも同様に、一つ一つの単純な計算を「ノード(点や箱)」で、そしてデータの流れを「エッジ(矢印)」で表現します。この考え方を使うと、どんなに複雑に見える計算も、単純なステップの連なりとして分解して理解できるわけです。
百聞は一見に如かず、です。早速、身近な例で試してみましょう。
お題:リンゴとオレンジの合計金額を計算する
- リンゴ:1個100円を2個
- オレンジ:1個150円を3個
- 消費税:10%(計算では係数1.1を掛ける)
この全体の計算式は (100 * 2 + 150 * 3) * 1.1 となります。これを計算グラフにしてみると、次のような図で表現できます。
この図をじっくり見てみましょう。
- 左側の入力値からスタート: まず、計算の元となるデータ(リンゴの値段、個数など)を用意します。これらがグラフの出発点です。
- ノードで計算を実行: 次に、矢印の先にあるノード(
[ × ]や[ + ])で計算を行います。例えば、最初の[ × ]ノードでは、100と2が入力され、200という中間結果が出力されています。 - データが右へ流れていく: 計算結果は、さらに次のノードへと矢印に沿って流れていきます。リンゴの小計(200円)とオレンジの小計(450円)が
[ + ]ノードに集まり、税抜合計(650円)が計算されます。 - 最終結果に到達: 最後に、税抜合計(650円)と消費税率(1.1)が最後の
[ × ]ノードで計算され、最終的な合計金額である715円が算出されました。
このように、まるで川の水が上流から下流へと流れるように、データが左から右へと一方通行で流れて計算が進んでいく様子が、手に取るように分かりますよね。この計算の流れのことを、専門用語で順伝播(じゅんでんぱ、Forward Propagation)と呼びます。
そして面白いことに、このシンプルな仕組みこそ、巨大で複雑なニューラルネットワークが物事を「考える」際の基本プロセスそのものなのです。
例えば、私たちが臨床現場でAIを使う場面を想像してみてください。患者さんの検査値(血圧、血糖値、コレステロール値など)を入力データとしてAIに与えると、AIの内部では、この計算グラフを遥かに巨大にしたようなネットワークの上をデータが駆け巡り、無数のパラメータ(重みやバイアス)と計算を繰り返します。そして、最終的に「2年以内の心筋梗塞発症リスク:85%」といった予測値を弾き出すのです。この一連の予測プロセス全体が、まさに順伝播に他なりません。
なぜ「逆」に進む必要があるのか?AIの自己修正プロセス
先ほどの計算グラフで、データが左から右へ、まるで川の流れのようにスルスルと答えにたどり着く様子は、見ていて気持ちが良かったかもしれませんね。この一方向の流れが「順伝播(Forward Propagation)」でした。
しかし、このプロセスだけでは、AIはただの高性能な計算機に過ぎません。なぜなら、出した答えが「間違っていた」ときに、そこから何も学べないからです。AIが本当に「学習」するためには、自分の間違いを認識し、それを次に活かす仕組みが不可欠です。
例えば、AIがある患者さんの病理画像を見て「良性(Benign)」と予測したとします。ですが、経験豊富な病理医による正解は「悪性(Malignant)」でした。この「AIの予測」と「揺るぎない正解」との間にある、無視できないズレ。これをAIの世界では損失(Loss)または誤差(Error)と呼びます。
この「損失」を、AIの「成績の悪さ」を示す点数だと考えてみてください。予測が正解に近ければ点数は低く(良く)、予測が大きく外れれば点数は高く(悪く)なります。AIの学習における唯一絶対の目標は、「損失という名の悪い点数」を、可能な限りゼロに近づけること、これに尽きます。
「責任の所在」はどこにあるのか?
さて、成績が悪いことは分かりました。では、どうやって改善すればいいのでしょう? ここでAIは、いわゆる「責任の所在」問題(Credit Assignment Problem)という、とても大きな壁にぶつかります。
最終的な間違い(大きな損失)は、計算の途中にあった無数のパラメータ(ニューラルネットワークの文脈では「重み」や「バイアス」と呼ばれます)たちの、誰の、どの判断が、どれくらい影響した結果なのでしょうか?
この状況を図にすると、こんなイメージです。
[入力データ] ---> [層1] ---> [層2] ---> [層3] ---> [予測結果] ---┐
(ズレ) |---> [大きな損失]
[正解データ] ---------------------------------------------┘ ↑
|
(???) この間違いは誰のせい? ------┘
層1、層2、層3にいる、無数のパラメータたちの
うち、誰がどれだけ責任を負うべきか?
この図のように、最終的な「大きな損失」という結果だけを見ても、その原因がネットワークのどこにあるのか、すぐには分かりません。
臨床推論に学ぶ、原因究明のプロセス
実はこの問題、先生方が日常的に行っている臨床推論のプロセスに非常によく似ています。
患者さんが「高熱」という最終結果(=大きな損失)を訴えて来院されたとしましょう。優れた臨床医は、ただ解熱剤を処方する(=最終結果だけを無理やり変える)だけではありませんよね。その「高熱」という症状から、時間を遡るように原因を探ります。
「2日前から喉に痛みはありましたか?」(=層3の出力は?)
「扁桃腺は赤く腫れていますか?」(=層2の出力は?)
「血液検査で白血球やCRPの値は?」(=層1の出力は?)
このように、観察可能な所見を手がかりに原因を一つひとつ遡って特定し、「どうやらこの細菌が原因らしい。ならば、この抗菌薬を処方するのが根本治療だ」と判断を下すはずです。
AIの学習も、これと全く同じアプローチを取ります。AIの世界で、この「原因究明の旅」を実現する手法こそが誤差逆伝播法(Backward Propagation)なのです。計算グラフのゴール地点である「損失」からスタートして、計算の矢印を逆向きに辿りながら、「君の判断のせいで、最終的な間違いがこれだけ増えたよ」という「責任の割合」を、各計算ノード、そして各パラメータに伝えて回るのです。
この「責任の割合」、もう少し専門的な言葉で言うと勾配(こうばい、Gradient)と呼ばれます。勾配が分かれば、AIは「このパラメータ(重み)は損失を増やしてしまっているから、次は少し値を小さくしよう」とか、「このパラメータは損失を減らす良い働きをしたから、もっと値を大きくしてみよう」といった、的確な自己修正が可能になります。
この地道な「反省」と「修正」のサイクルを、膨大なデータを使って何千回、何万回と繰り返すことで、AIは少しずつ賢くなっていくというわけです。
誤差逆伝播の核心:微分の連鎖「連鎖率」
さて、いよいよ誤差逆伝播法の核心部分に迫ります。前のセクションで、私たちは最終的な「損失(Loss)」に対する各パラメータの「責任の割合」を突き止める必要がある、という話をしました。
この「責任の割合」、すなわち勾配(Gradient)を計算するための数学的な道具が、微分です。
ここで「うっ…数学は苦手で…」と感じた方も、どうか安心してください。これからするのは難しい数式を解く話ではありません。微分を、ここでは単純に「ある値がほんの少し変わると、それにつられて別の値がどれくらい変わるか」という「影響度」を測る、便利な物差しだと捉えてみましょう。
そして、この「影響度」の計算を、驚くほどエレガントに、そして効率的にやってのけるのが、高校時代に出会ったかもしれない連鎖率(Chain Rule)なんです。
影響の伝言ゲーム、「連鎖率」
連鎖率とは、その名の通り「影響が連鎖していく法則」のことです。私はこれをよく「影響度の伝言ゲーム」や「微分のドミノ倒し」と呼んでいます。
最終的な結果(例えば損失 L)に与えた影響を、時間を遡るように、一つ前の要素、さらにその前の要素…へと辿っていくことを想像してください。連鎖率が教えてくれるのは、各ステップでの「局所的な影響度」を次々と掛け合わせていけば、最初の入力が最終的な出力に与えたトータルの影響度がわかる、というシンプルなルールです。
数式で書くと、こう表現されます。
ある最終結果 \(y\) が、中間結果 \(u\) によって決まり(\(y = f(u)\))、その中間結果 \(u\) が、最初の入力 \(x\) によって決まる(\(u = g(x)\))とします。
このとき、最初の入力 \(x\) が最終結果 \(y\) に与えるトータルの影響度 \(\frac{dy}{dx}\) は、それぞれの局所的な影響度の掛け算で求められます。
\[ \frac{dy}{dx} = \frac{dy}{du} \cdot \frac{du}{dx} \]
- \(\frac{dy}{dx}\) : \(x\) が少し動いたときの \(y\) の変化量(知りたいトータルの影響度)
- \(\frac{dy}{du}\) : \(u\) が少し動いたときの \(y\) の変化量(出口に近い部分の局所的な影響度)
- \(\frac{du}{dx}\) : \(x\) が少し動いたときの \(u\) の変化量(入口に近い部分の局所的な影響度)
この考え方を使って、実際に計算グラフを逆向きに旅してみましょう。
計算グラフで体験する「微分のドミノ倒し」
ここでは、先ほどのリンゴとオレンジの例を少し単純化した、以下の計算グラフを使います。
順伝播(Forward Propagation)
まず、データが左から右へ流れる順伝播の計算をおさらいします。c=2, d=3 を足して a=5 を作り、その a と b=4 を掛けて、最終結果 L=20 を得るとします。
// Forward Pass:
c=2 ─↘
[+] → a=5 ─↘
d=3 ─↗ [×] → L=20
b=4 ─↗
逆伝播(Backward Propagation)
ここからが本番です。最終結果 L に対する、各入力 b, c, d の勾配(影響度)、つまり \(\frac{\partial L}{\partial b}\), \(\frac{\partial L}{\partial c}\), \(\frac{\partial L}{\partial d}\) を求めていきましょう。
ステップ1:ゴールからスタート
逆伝播は、その名の通りゴールから出発します。自分自身に対する自分自身の変化量(影響度)、つまり \(\frac{\partial L}{\partial L}\) は当然 1 です。これがドミノの最初の一押しになります。
ステップ2:[×] ノードの逆伝播L = a * b という掛け算ノードを考えます。
上流(右側)から伝わってきた勾配は 1 です。ここで、連鎖率を思い出してください。
aの勾配 \(\frac{\partial L}{\partial a}\) を求めるには:
(上流からの勾配) × (Lをaで微分した局所的な勾配) = \(\frac{\partial L}{\partial L} \cdot \frac{\partial (a \cdot b)}{\partial a}\)a * bをaで微分するとbになります。順伝播のときbは4でした。
したがって、aの勾配は \(1 \times 4 = 4\) となります。bの勾配 \(\frac{\partial L}{\partial b}\) も同様に:
(上流からの勾配) × (Lをbで微分した局所的な勾配) = \(\frac{\partial L}{\partial L} \cdot \frac{\partial (a \cdot b)}{\partial b}\)a * bをbで微分するとaになります。順伝播のときaは5でした。
したがって、bの勾配は \(1 \times 5 = 5\) となります。
掛け算ノードは、上流からの勾配に対して、順伝播のときの「相方」の値を掛けて下流に流す、と覚えましょう。
ステップ3:[+] ノードの逆伝播a = c + d という足し算ノードを考えます。
今、上流(a のルート)から 4 という勾配が伝わってきました。
cの勾配 \(\frac{\partial L}{\partial c}\) を求めるには:
(上流からの勾配) × (aをcで微分した局所的な勾配) = \(\frac{\partial L}{\partial a} \cdot \frac{\partial (c + d)}{\partial c}\)c + dをcで微分すると1です。
したがって、cの勾配は \(4 \times 1 = 4\) となります。dの勾配 \(\frac{\partial L}{\partial d}\) も同様に、 \(4 \times 1 = 4\) となります。
足し算ノードは、上流からの勾配を、そのままの値で下流の各入力にコピーして流す、と覚えられますね。
まとめ:勾配の計算結果
この逆伝播の旅によって、私たちは各入力が最終結果 L に与える影響度(勾配)を突き止めることができました。
- \(\frac{\partial L}{\partial b} = 5\)
- \(\frac{\partial L}{\partial c} = 4\)
- \(\frac{\partial L}{\partial d} = 4\)
これはつまり、「もし入力 b を 0.1 だけ増やしたら、最終結果 L はおよそ 0.5 増える」という関係性を意味します。
逆伝播の本質
この一見単純な「局所的な微分を計算して、上流から伝わってきた勾配をそれに掛ける」という操作。これを、計算グラフの終点から始点まで、ドミノ倒しのようにただただ繰り返していくだけ。
たったこれだけのことで、どんなに複雑で何百層もあるような深層ニューラルネットワークであっても、すべてのパラメータが最終的な間違いにどれだけ責任を負っているのか(勾配)を、驚くほど効率的に計算できてしまうのです。これこそが、現代のAIを動かす、誤差逆伝播法の魔法であり、その本質に他なりません。
Pythonで計算グラフを実装し、動きを体感する
理論を学んだところで、今度はそれを「自分の手で」動かしてみたいと思いませんか? ここでは、これまで学んできた計算グラフと逆伝播の仕組みを、Pythonというプログラミング言語で一から組み立ててみます。
これから先、私たちが実際に使うことになるPyTorchのような便利なライブラリは、この作業を全て全自動でやってくれます。ですが、一度その「心臓部」を自作してみる経験は、AIの内部で何が起きているのかを直感的に理解する上で、何物にも代えがたい貴重な体験になるはずです。
今回のシナリオと「設計図」
まずは、今回作成するAIモデルのシナリオを決めましょう。
「2つの臨床検査値(例:最高血圧 \(x_1\)、LDLコレステロール値 \(x_2\))から、将来の心血管疾患の発症リスクスコア \(y\) を予測する」という、ごく単純なAIモデルを考えてみます。
このAIモデルの計算式(これを線形モデルと呼びます)は以下の通りです。
\[ y_{pred} = w_1 \cdot x_1 + w_2 \cdot x_2 + b \]
- \(x_1, x_2\): 入力となる検査値データです。
- \(w_1, w_2\): 各検査値の重要度を表す「重み」です。AIが学習して見つけ出すべき重要なパラメータです。
- \(b\): 全体の結果を底上げする「バイアス」です。これも学習対象のパラメータです。
- \(y_{pred}\): AIが算出した予測リスクスコアです。
そして、この予測がどれだけ正解からズレているかを測る「成績評価」の式(損失関数)も決めておきましょう。今回は、予測値と正解値の差を2乗した二乗誤差を使います。
\[ L = (y_{pred} - y_{true})^2 \]
- \(y_{true}\): 正解の(実際の)リスクスコアです。
- \(L\): 損失(予測のズレの大きさ)。このLを最小化することが目標です。
さて、この一連の計算の流れを、私たちの「設計図」である計算グラフに起こしてみましょう。
// モデルの設計図:y_pred = w1*x1 + w2*x2 + b
w1 --↘ x1 --↘
[×]--→ w1x1 --↘
w2 --↘ x2 --↘ [+]--→ (w1x1+w2x2) --↘
[×]--→ w2x2 --↗ [+]--→ y_pred
b --↗
私たちの最終目標は、この設計図を逆向きに辿って、AIが学ぶべきパラメータ \(w_1, w_2, b\) それぞれの勾配(\(\frac{\partial L}{\partial w_1}\), \(\frac{\partial L}{\partial w_2}\), \(\frac{\partial L}{\partial b}\))を計算することです。
Pythonによる実装
それでは、この設計図を元にPythonコードを書いていきましょう。まずは、計算グラフの部品となる「掛け算ノード」と「足し算ノード」をクラスとして定義します。
以下のコードは、コピー&ペーストすれば、お手元の環境ですぐに実行できます。
# -*- coding: utf-8 -*-
# 日本語のコメントや出力に対応するための記述です。
# --- 計算グラフの部品となる「ノード」をクラスとして定義 ---
class MulNode:
""" 掛け算ノード [×] を表すクラス """
def __init__(self):
# 逆伝播の計算では、順伝播のときの入力値が必要になるので、
# それらを保存しておくための変数を用意します。
self.x = None
self.y = None
def forward(self, x, y):
""" 順伝播:単純な掛け算を実行します """
self.x = x # 逆伝播で使うので、入力値xをインスタンス変数に保存
self.y = y # 入力値yも同様に保存
return x * y
def backward(self, d_out):
""" 逆伝播:上流から伝わってきた勾配に、局所的な勾配を乗算します """
# 掛け算の逆伝播では、順伝播のときの「相方」の値を勾配に乗算するのでしたね。
# xに対する勾配を計算するには、上流の勾配d_outに、順伝播のときの入力yを掛けます。
d_x = d_out * self.y
# yに対する勾配も同様に、上流の勾配d_outに、順伝播のときの入力xを掛けます。
d_y = d_out * self.x
return d_x, d_y
class AddNode:
""" 足し算ノード [+] を表すクラス """
def __init__(self):
# 足し算の逆伝播では入力値は不要なので、変数は特に用意しません。
pass
def forward(self, x, y):
""" 順伝播:単純な足し算を実行します """
return x + y
def backward(self, d_out):
""" 逆伝播:上流の勾配をそのまま下流に流します """
# 足し算の逆伝播は、上流の勾配をそのまま下流に流す「分配器」のような役割でした。
# 局所的な勾配がどちらも1なので、d_out * 1 となります。
d_x = d_out
d_y = d_out
return d_x, d_y
# --- シミュレーションの実行 ---
# Step 0: パラメータと入力データの初期値を設定
# w1, w2, b はAIが学習して更新していくべきパラメータ(最初は適当な値からスタート)
w1_val, w2_val, b_val = 2.0, -3.0, 1.0
# x1, x2 は、ある患者さんの臨床検査値データと仮定
x1_val, x2_val = 1.5, 0.5
# y_true は、この患者さんの正解のリスクスコアと仮定
y_true = 5.0
# 計算グラフの設計図に従って、ノードのインスタンスを生成
mul_node_w1x1 = MulNode()
mul_node_w2x2 = MulNode()
add_node_mid = AddNode()
add_node_final = AddNode()
print("--- 1. 順伝播 (Forward Propagation) の実行 ---")
# 設計図に従って、左から右へ計算を実行し、予測値を算出します
# (1) w1 * x1
w1x1 = mul_node_w1x1.forward(w1_val, x1_val)
print(f"(1) 掛け算ノード1: w1({w1_val}) * x1({x1_val}) = {w1x1}")
# (2) w2 * x2
w2x2 = mul_node_w2x2.forward(w2_val, x2_val)
print(f"(2) 掛け算ノード2: w2({w2_val}) * x2({x2_val}) = {w2x2}")
# (3) (w1 * x1) + (w2 * x2)
sum_w1x1_w2x2 = add_node_mid.forward(w1x1, w2x2)
print(f"(3) 足し算ノード1: {w1x1} + {w2x2} = {sum_w1x1_w2x2}")
# (4) {(w1 * x1) + (w2 * x2)} + b
y_pred = add_node_final.forward(sum_w1x1_w2x2, b_val)
print(f"(4) 足し算ノード2: {sum_w1x1_w2x2} + b({b_val}) = {y_pred} <-- これがAIの予測値")
# (5) 損失 (誤差) の計算 L = (y_pred - y_true)^2
loss = (y_pred - y_true)**2
print(f"\n(5) 損失の計算: (予測値{y_pred} - 正解値{y_true})^2 = {loss:.4f} <-- この値を小さくしたい")
print("\n\n--- 2. 逆伝播 (Backward Propagation) の実行 ---")
# 計算グラフを逆に辿って、各パラメータの勾配を計算します
# (5) 逆伝播の開始点:損失Lを予測値y_predで微分する
# L = (y_pred - y_true)^2 なので、dL/dy_pred = 2 * (y_pred - y_true)
d_loss_ypred = 2 * (y_pred - y_true)
print(f"(5) 逆伝播スタート地点の勾配 (dL/dy_pred): {d_loss_ypred}")
# (4) add_node_final の逆伝播
d_sum_w1x1_w2x2, d_b = add_node_final.backward(d_loss_ypred)
print(f"(4) 足し算ノード2から逆伝播 --> bの勾配(dL/db): {d_b}, 中間値(w1x1+w2x2)の勾配: {d_sum_w1x1_w2x2}")
# (3) add_node_mid の逆伝播
d_w1x1, d_w2x2 = add_node_mid.backward(d_sum_w1x1_w2x2)
print(f"(3) 足し算ノード1から逆伝播 --> 中間値(w1x1)の勾配: {d_w1x1}, 中間値(w2x2)の勾配: {d_w2x2}")
# (2) mul_node_w2x2 の逆伝播
d_w2, d_x2 = mul_node_w2x2.backward(d_w2x2)
print(f"(2) 掛け算ノード2から逆伝播 --> w2の勾配(dL/dw2): {d_w2}")
# (1) mul_node_w1x1 の逆伝播
d_w1, d_x1 = mul_node_w1x1.backward(d_w1x1)
print(f"(1) 掛け算ノード1から逆伝播 --> w1の勾配(dL/dw1): {d_w1}")
print("\n\n--- 3. 学習すべき勾配の計算結果まとめ ---")
print(f"重み w1 に対する損失の勾配: {d_w1:.4f}")
print(f"重み w2 に対する損失の勾配: {d_w2:.4f}")
print(f"バイアス b に対する損失の勾配: {d_b:.4f}")
--- 1. 順伝播 (Forward Propagation) の実行 ---
(1) 掛け算ノード1: w1(2.0) * x1(1.5) = 3.0
(2) 掛け算ノード2: w2(-3.0) * x2(0.5) = -1.5
(3) 足し算ノード1: 3.0 + -1.5 = 1.5
(4) 足し算ノード2: 1.5 + b(1.0) = 2.5 <-- これがAIの予測値
(5) 損失の計算: (予測値2.5 - 正解値5.0)^2 = 6.2500 <-- この値を小さくしたい
--- 2. 逆伝播 (Backward Propagation) の実行 ---
(5) 逆伝播スタート地点の勾配 (dL/dy_pred): -5.0
(4) 足し算ノード2から逆伝播 --> bの勾配(dL/db): -5.0, 中間値(w1x1+w2x2)の勾配: -5.0
(3) 足し算ノード1から逆伝播 --> 中間値(w1x1)の勾配: -5.0, 中間値(w2x2)の勾配: -5.0
(2) 掛け算ノード2から逆伝播 --> w2の勾配(dL/dw2): -2.5
(1) 掛け算ノード1から逆伝播 --> w1の勾配(dL/dw1): -7.5
--- 3. 学習すべき勾配の計算結果まとめ ---
重み w1 に対する損失の勾配: -7.5000
重み w2 に対する損失の勾配: -2.5000
バイアス b に対する損失の勾配: -5.0000
結果の解釈:AIのコンパスを手に入れる
いかがでしたでしょうか。このコードを実行すると、最終的に3つのパラメータ(\(w_1, w_2, b\))が、今回の間違い(損失)に対してどれだけの責任を負っているかを示す「勾配」が、具体的な数値として計算されます。
最終的に得られた勾配、例えば w1 に対する勾配 -7.5 は、AIにとっての「コンパス」のようなものです。この -7.5 という数字は、
「もし \(w_1\) の値をほんの少しだけ増やしたら、最終的な損失(成績の悪さ)は、その7.5倍の勢いで 減ってくれる」
という、非常に重要なメッセージを伝えています(勾配がマイナスなので、損失は減少する方向ですね)。
同様に、w2 の勾配 -2.5 は「\(w_2\) を増やすと損失が2.5倍の勢いで減る」、b の勾配 -5.0 は「\(b\) を増やすと損失が5.0倍の勢いで減る」ことを示唆しています。
この「コンパス」が指し示す方向に、各パラメータをほんの少しだけ動かしてあげる。この一連の調整プロセスが、前回少し触れた勾配降下法(Gradient Descent)です。この小さな一歩を何万回と繰り返すことで、AIモデルは損失という名の谷底へ向かって少しずつ下っていき、やがて最も精度の高いパラメータの値にたどり着くのです。
なぜ私たちは、この複雑な仕組みを学ぶのか?医療AIへの応用と、その先にある未来
ここまで、計算グラフや逆伝播といった、少し抽象的な概念の旅をしてきました。もしかしたら、「こんな細かいことを知っていて、実際の臨床や研究に何の役に立つんだろう?」と感じた方もいらっしゃるかもしれません。
ですが、実はこの誤差逆伝播というエンジンこそが、現代の医療AIを駆動させ、私たちが目にする数々の目覚ましい成果を生み出しているのです。ここでは、その具体的な応用例をいくつかご紹介しながら、この知識が持つ本当の意味を一緒に考えていきたいと思います。
1. 巨大なAIモデルの学習を、現実のものにする
まず何よりも、誤差逆伝播がなければ、現在の高性能な医療AIは「存在すらしない」と言っても過言ではありません。
CTやMRI画像から微小な早期がんを発見したり、病理組織画像から複雑な分類を行ったりするAIモデルは、時に数百万、数億個ものパラメータを持っています。これは、いわば数億個の調整ダイヤルを持つ、超複雑な医療機器を想像してみてください。全てのダイヤルを一つずつ手で回して最適な設定を探す、なんていうのは天文学的な時間がかかり、現実的には不可能です。
誤差逆伝播は、この数億個のダイヤルを「どの方向に、どれだけ回せば性能が良くなるか」という最適ルート(勾配)を、たった一回の計算で効率的に指し示してくれます。この驚異的な効率性があるからこそ、私たちは複雑な医療課題に挑むAIを、現実的な時間で「学習」させることができるのです。
2. AIの「頭の中」を覗き、判断の根拠を知る(Explainable AI, XAI)
AIがどんなに高い精度を誇っても、「なぜそう判断したのか」が分からなければ、私たちは命に関わる臨床現場で、その答えを心から信頼することはできません。この「AIのブラックボックス問題」に光を当て、医師とAIとの間に信頼関係を築く鍵もまた、逆伝播が計算する「勾配」にあります。
この勾配を利用した代表的な技術に Grad-CAM (Gradient-weighted Class Activation Mapping) があります。これは、AIが予測を下す際に、画像のどの部分を重要視したかを可視化する技術です。
その仕組みを、胸部X線写真から肺炎を検出するAIを例に、図で見てみましょう。
[入力画像 (胸部X線)]
↓
[学習済みAIモデル (CNN)] --(順伝播)--> [予測結果: "肺炎の可能性あり"]
↑ |
| (逆伝播) ↓ (勾配情報の活用)
|
[勾配が逆流してくる] <--- 「肺炎」という予測に対する勾配を計算せよ
↓
[モデル内部の特徴と勾配を結合]
↓
[判断根拠のヒートマップ (Grad-CAM)]
+-----------------+
| |
| #### | <-- AIが「肺炎」と判断する根拠とした
| ###### | 肺炎陰影の領域が、このように
| ######## | 赤くハイライトされて可視化される
| ########## |
+-----------------+
この図が示しているのは、まずAIが順伝播で「肺炎の可能性あり」と予測した後、今度は逆伝播を使って「『肺炎』という予測に対する勾配」を計算する、というプロセスです。この勾配は、「画像の各ピクセルが、『肺炎』という最終判断にどれだけ影響を与えたか」という感度マップのような情報を持っています。
Grad-CAMは、この勾配情報を基に、AIが判断の根拠として最も強く注目した領域を、色の濃淡(ヒートマップ)で示してくれます。もし、AIが指し示したハイライト領域と、実際の病変部位とが一致していることを医師自身の目で確認できれば、それは単なる「AIの予測」から、「信頼できる診断のパートナー」へと変わる瞬間だと言えるでしょう。
3. 創薬からゲノム医療まで、新たな発見を加速する
この技術の応用範囲は、画像診断だけにとどまりません。
例えば、創薬の分野では、何百万という候補化合物の中から、特定のタンパク質に強く結合し、かつ副作用の少ない、理想的な薬の候補を見つけ出す必要があります。これは、まさに広大な砂漠で一本の針を探すような作業です。
ここでも勾配が活躍します。AIモデルを使って、ある化合物の化学構造をほんの少し変化させたら、薬としての効果(予測値)がどれくらい良くなるか、その「勾配」を計算します。これにより、やみくもに探すのではなく、最も有望な分子構造の方向へと効率的に探索を進めることができるのです。
また、ゲノム医療においても、特定の遺伝子変異(SNP)が、ある疾患の発症リスクにどれほどの影響を与えるか(勾配)を評価するなど、その応用は日進月歩で広がり続けています。
このように、誤差逆伝播は単なる計算テクニックではありません。AIの学習を可能にし、その判断に透明性を与え、さらには新たな科学的発見を加速させる、まさに現代医療AIの根幹をなす技術なのです。この仕組みを知っていることは、AIの表面的な結果に一喜一憂するのではなく、その能力と限界を深く理解し、真のパートナーとして付き合っていくための第一歩と言えるでしょう。
まとめと次回予告
今回は、AIが「学習」する仕組みの核心である誤差逆伝播法を、計算グラフというツールを使って視覚的・直感的に理解しました。
- 計算グラフは、計算のプロセスをノードと矢印で可視化したものです。
- 順伝播は、入力から出力へと計算を進めるプロセスです。
- 誤差逆伝播は、出力(誤差)から入力へと連鎖率を使いながら逆向きに「勾配」を伝播させ、各パラメータの誤差への貢献度を効率的に計算する手法です。
- この勾配こそが、AIが自身を修正し、賢くなるための「指導書」となります。
本日、私たちはこの重要なメカニズムを理解するために、あえて手作業で実装しました。しかし、実際の研究開発で毎回これを行うのは大変です。
そこで次回、第7回「PyTorch入門:Tensorと自動微分を体験しよう」では、この誤差逆伝播の計算を全自動で行ってくれる、極めて強力なライブラリ「PyTorch」の世界に足を踏み入れます。PyTorchを使えば、今日実装したような複雑な微分計算を意識することなく、より直感的かつ効率的に、遥かに大規模なニューラルネットワークを構築できるようになります。AI開発の実践に向けて、大きな一歩を踏み出しましょう。
参考文献
- Selvaraju RR, Cogswell M, Das A, Vedantam R, Parikh D, Batra D. Grad-CAM: Visual Explanations from Deep Networks via Gradient-based Localization. In: Proceedings of the IEEE International Conference on Computer Vision (ICCV). 2017. p. 618-626.
- Gaudelet T, Day B, Jamasb A, Soman J, Regep C, Liu G, et al. Utilising graph machine learning in drug discovery and development. Brief Bioinform. 2021;22(6):bbab159.
- Rumelhart DE, Hinton GE, Williams RJ. Learning representations by back-propagating errors. Nature. 1986;323(6088):533-6.
- LeCun Y, Bengio Y, Hinton G. Deep learning. Nature. 2015;521(7553):436-44.
- Goodfellow I, Bengio Y, Courville A. Deep Learning. MIT Press; 2016.
- Nielsen MA. Neural Networks and Deep Learning. Determination Press; 2015. http://neuralnetworksanddeeplearning.com/
- Esteva A, Robicquet A, Ramsundar B, Kuleshov V, DePristo M, Chou K, et al. A guide to deep learning in healthcare. Nat Med. 2019;25(1):24-29.
- Paszke A, Gross S, Massa F, Lerer A, Bradbury J, Chanan G, et al. PyTorch: An Imperative Style, High-Performance Deep Learning Library. In: Advances in Neural Information Processing Systems 32. 2019. p. 8024-8035.
ご利用規約(免責事項)
当サイト(以下「本サイト」といいます)をご利用になる前に、本ご利用規約(以下「本規約」といいます)をよくお読みください。本サイトを利用された時点で、利用者は本規約の全ての条項に同意したものとみなします。
第1条(目的と情報の性質)
- 本サイトは、医療分野におけるAI技術に関する一般的な情報提供および技術的な学習機会の提供を唯一の目的とします。
- 本サイトで提供されるすべてのコンテンツ(文章、図表、コード、データセットの紹介等を含みますが、これらに限定されません)は、一般的な学習参考用であり、いかなる場合も医学的な助言、診断、治療、またはこれらに準ずる行為(以下「医行為等」といいます)を提供するものではありません。
- 本サイトのコンテンツは、特定の製品、技術、または治療法の有効性、安全性を保証、推奨、または広告・販売促進するものではありません。紹介する技術には研究開発段階のものが含まれており、その臨床応用には、さらなる研究と国内外の規制当局による正式な承認が別途必要です。
- 本サイトは、情報提供を目的としたものであり、特定の治療法を推奨するものではありません。健康に関するご懸念やご相談は、必ず専門の医療機関にご相談ください。
第2条(法令等の遵守)
利用者は、本サイトの利用にあたり、医師法、医薬品、医療機器等の品質、有効性及び安全性の確保等に関する法律(薬機法)、個人情報の保護に関する法律、医療法、医療広告ガイドライン、その他関連する国内外の全ての法令、条例、規則、および各省庁・学会等が定める最新のガイドライン等を、自らの責任において遵守するものとします。これらの適用判断についても、利用者が自ら関係各所に確認するものとし、本サイトは一切の責任を負いません。
第3条(医療行為における責任)
- 本サイトで紹介するAI技術・手法は、あくまで研究段階の技術的解説であり、実際の臨床現場での診断・治療を代替、補助、または推奨するものでは一切ありません。
- 医行為等に関する最終的な判断、決定、およびそれに伴う一切の責任は、必ず法律上その資格を認められた医療専門家(医師、歯科医師等)が負うものとします。AIによる出力を、資格を有する専門家による独立した検証および判断を経ずに利用することを固く禁じます。
- 本サイトの情報に基づくいかなる行為によって利用者または第三者に損害が生じた場合も、本サイト運営者は一切の責任を負いません。実際の臨床判断に際しては、必ず担当の医療専門家にご相談ください。本サイトの利用によって、利用者と本サイト運営者の間に、医師と患者の関係、またはその他いかなる専門的な関係も成立するものではありません。
第4条(情報の正確性・完全性・有用性)
- 本サイトは、掲載する情報(数値、事例、ソースコード、ライブラリのバージョン等)の正確性、完全性、網羅性、有用性、特定目的への適合性、その他一切の事項について、何ら保証するものではありません。
- 掲載情報は執筆時点のものであり、予告なく変更または削除されることがあります。また、技術の進展、ライブラリの更新等により、情報は古くなる可能性があります。利用者は、必ず自身で公式ドキュメント等の最新情報を確認し、自らの責任で情報を利用するものとします。
第5条(AI生成コンテンツに関する注意事項)
本サイトのコンテンツには、AIによる提案を基に作成された部分が含まれる場合がありますが、公開にあたっては人間による監修・編集を経ています。利用者が生成AI等を用いる際は、ハルシネーション(事実に基づかない情報の生成)やバイアスのリスクが内在することを十分に理解し、その出力を鵜呑みにすることなく、必ず専門家による検証を行うものとします。
第6条(知的財産権)
- 本サイトを構成するすべてのコンテンツに関する著作権、商標権、その他一切の知的財産権は、本サイト運営者または正当な権利を有する第三者に帰属します。
- 本サイトのコンテンツを引用、転載、複製、改変、その他の二次利用を行う場合は、著作権法その他関連法規を遵守し、必ず出典を明記するとともに、権利者の許諾を得るなど、適切な手続きを自らの責任で行うものとします。
第7条(プライバシー・倫理)
本サイトで紹介または言及されるデータセット等を利用する場合、利用者は当該データセットに付随するライセンス条件および研究倫理指針を厳格に遵守し、個人情報の匿名化や同意取得の確認など、適用される法規制に基づき必要とされるすべての措置を、自らの責任において講じるものとします。
第8条(利用環境)
本サイトで紹介するソースコードやライブラリは、執筆時点で特定のバージョンおよび実行環境(OS、ハードウェア、依存パッケージ等)を前提としています。利用者の環境における動作を保証するものではなく、互換性の問題等に起因するいかなる不利益・損害についても、本サイト運営者は責任を負いません。
第9条(免責事項)
- 本サイト運営者は、利用者が本サイトを利用したこと、または利用できなかったことによって生じる一切の損害(直接損害、間接損害、付随的損害、特別損害、懲罰的損害、逸失利益、データの消失、プログラムの毀損等を含みますが、これらに限定されません)について、その原因の如何を問わず、一切の法的責任を負わないものとします。
- 本サイトの利用は、学習および研究目的に限定されるものとし、それ以外の目的での利用はご遠慮ください。
- 本サイトの利用に関連して、利用者と第三者との間で紛争が生じた場合、利用者は自らの費用と責任においてこれを解決するものとし、本サイト運営者に一切の迷惑または損害を与えないものとします。
- 本サイト運営者は、いつでも予告なく本サイトの運営を中断、中止、または内容を変更できるものとし、これによって利用者に生じたいかなる損害についても責任を負いません。
第10条(規約の変更)
本サイト運営者は、必要と判断した場合、利用者の承諾を得ることなく、いつでも本規約を変更することができます。変更後の規約は、本サイト上に掲載された時点で効力を生じるものとし、利用者は変更後の規約に拘束されるものとします。
第11条(準拠法および合意管轄)
本規約の解釈にあたっては、日本法を準拠法とします。本サイトの利用および本規約に関連して生じる一切の紛争については、東京地方裁判所を第一審の専属的合意管轄裁判所とします。
For J³, may joy follow you.

