02.4.7
勾配ブースティングの可視化
GradientBoostingRegressor を木 10 本・学習率 0.5 で学習し、reg.estimators_[i][0].predict(X) に学習率を掛けた値を、平均値の初期モデルの上に棒グラフとして積み上げると、各木がどの区間の残差を埋めたかが見えます。1 本目は大きなうねりを、2〜3 本目は細かいずれを直し、5 本目で sin 曲線にかなり近づきます。読み終えると、n_estimators と learning_rate が「何本の棒を、どれだけの高さで積むか」の指定だと図で説明できるようになります。疑似残差と加法モデルの式は 勾配ブースティング で説明しています。このページはその式 \(F_m = F_{m-1} + \nu h_m\) の各項を 1 本ずつ図に描くので、式を先に見ておくと棒グラフの意味がすぐ分かります。
直感 #
貯金の残高グラフを思い浮かべてください。最初に初期残高の線があり、毎月の入金が棒グラフとして上に積み上がり、棒の天井をつないだ線が現在の残高です。勾配ブースティングの予測もこれと同じで、初期残高が全データの平均値 \(F_0\)、毎月の入金が「\(i\) 本目の木の出力 × 学習率 0.5」、残高の線が最終予測 \(F_{10}\) です。違うのは、入金額が \(x\) の位置ごとに異なり、マイナスの入金(予測を下げる)もあることです。このページでは reg.estimators_ から 10 本の木を 1 本ずつ取り出し、その「入金」を棒グラフで積み上げて、赤い最終予測線がどう組み立てられたかを目で確かめます。
何が起きているか(ステップで見る) #
コードを読む前に、この手法が図の上で何をしているかを追ってみましょう。「再生」を押すか、スライダーを動かすと 1 手順ずつ進みます。
見るポイント:灰色の線が前の段階。1 段階で直されるのは残差(縦線)が大きい場所から。
式で見ると棒グラフの 1 本は何か #
加法モデル #
勾配ブースティングは加法モデルとして定式化されます。$M$ 本の木を逐次追加して予測関数を構築し、下のコードでは $M = 10$、$\nu = 0.5$ です:
$$F_M(x) = F_0(x) + \sum_{m=1}^{M} \nu \cdot h_m(x)$$ここで $F_0(x) = \arg\min_c \sum_i L(y_i, c)$(二乗誤差の回帰なら訓練データの平均値)、$\nu$ は学習率です。後の図では $F_0$ が灰色の破線、和の各項 $\nu \cdot h_m(x)$ が 1 本ずつの棒に対応します。
残差の更新 #
各ステージ $m$ で、前段までの予測 $F_{m-1}(x)$ に対する擬似残差を計算します:
$$r_i^{(m)} = -\left[\frac{\partial L(y_i, F(x_i))}{\partial F(x_i)}\right]_{F = F_{m-1}}$$二乗損失 $L = \frac{1}{2}(y - F)^2$ の場合、擬似残差は単純な残差になります:
$$r_i^{(m)} = y_i - F_{m-1}(x_i)$$更新ステップ #
新しい木 $h_m$ を擬似残差 ${r_i^{(m)}}$ に対してフィットし、モデルを更新します:
$$F_m(x) = F_{m-1}(x) + \nu \cdot h_m(x)$$学習率 $\nu \in (0, 1]$ は各木の寄与を縮小し、過学習を抑制します。$\nu = 0.5$ なら木が「残差をすべて埋める」出力を返しても、実際に足されるのは半分です。$\nu$ が小さいほど多くの木が必要ですが、汎化性能は向上する傾向があります。
Python で確かめる #
以下では、まず sin 波に 10 本の木を当てて最終予測を描き、次に estimators_ から木を 1 本ずつ取り出して寄与を棒グラフで積み上げ、最後に 1 本目から 5 本目まで「途中の予測」を順に並べます。
| |
1. 学習と最終予測の確認 #
まず $y = 10 \sin x + 10$ に 0〜10 の一様ノイズを足した 500 点に、木 10 本・学習率 0.5 の勾配ブースティング回帰を学習し、最終的な予測曲線と初期モデル(平均値)の線を重ねます。
| |
灰色の破線が「初期モデル」で、$y$ の平均値だけを返す予測です。赤い線が 10 本の木を足し合わせた最終予測で、平均値から出発して木を 1 本追加するごとに sin 波へ近づいた結果です。次の節でその 10 回の追加を 1 本ずつ分解します。
2. 木ごとの寄与を積み上げて表示 #
次に「各木がどれだけ予測を修正したか」を棒グラフで積み上げます。reg.estimators_[i][0] が $i$ 本目の木で、その predict(X) に学習率 0.5 を掛けた値が式の $\nu \cdot h_m(x)$ です。平均値 $F_0$ の上にこれを 10 段積むと、棒の天井が赤い最終予測と一致するはずです。
| |
薄い棒 1 段が「1 本の木がどれだけ予測を修正したか」で、山の区間では上向き、谷の区間では下向きに伸びています。10 段を累積すると棒の天井が赤い予測曲線と一致します。学習率 0.5 を掛けているので、各木は残差の半分だけを埋め、残りは次の木に持ち越されています。
3. 途中までの積み上げ(段階的な改善) #
さらに「木を 1 本、2 本、……、5 本まで足した時点」の予測を 5 枚の図で順に描きます。1 枚目の赤線が $F_1$、5 枚目が $F_5$ です。
| |
1 本目の木は平均値からの大きなずれ、つまり sin 波の山と谷のおおまかな位置を 8 段の階段で補正します。2〜3 本目は 1 本目が取り残した細かいずれを埋め、5 本目の時点で赤線は sin 曲線にかなり近づきます。残り 5 本を足すと前節の赤い最終予測になります。学習率が 0.5 なので、1 本目の階段の高さは残差のちょうど半分で、これが「一歩ずつ慎重に直す」の実体です。
まとめ #
勾配ブースティングの最終予測は、平均値 $F_0$ の上に「$i$ 本目の木の出力 × 学習率」を $M$ 段積んだ和 $F_M = F_0 + \sum_m \nu h_m$ で、reg.estimators_[i][0].predict(X) * learning_rate を bottom=temp の棒グラフとして積むとその式を図にできます。木 10 本・学習率 0.5 の例では、1 本目が sin 波の大まかな形を、2〜5 本目が細かいずれを埋め、棒の天井が reg.predict(X) の赤線と一致しました。n_estimators は棒の段数、learning_rate は各段の高さの倍率と読めるので、学習率を 0.1 にするなら段数を 5 倍の 50 本前後にする、という調整の意味が図から説明できます。
推定器数と予測 #
スライダーで n_estimators を 1 本から 200 本まで動かすと、このページで 5 本まで追った「途中の予測」がさらに先まで続き、train_mse が下がり続ける一方で test_mse がある本数から上がり始める様子を確認できます。