
アンサンブルの「多様性」は本当に効くのか。seed違いの浅い多様性とbagging+幅の多様性を対決させたら不一致率が3.1倍だった
前回のdropoutの記事で、「dropoutは暗黙のアンサンブルだ」という説を検証した。結果は、精度こそほぼ互角(explicit ensemble 0.927 vs MC-dropout 0.930)だったものの、点ごとの予測分散(不確実性)の相関はPearson r=0.13とかなり弱かった。dropoutの「多様性」は、独立に学習した本物のアンサンブルの多様性とは質が違う、というのがそのときの結論だった。
この記事を書きながらずっと引っかかっていたことがある。そもそも「明示的なアンサンブル」同士を比べたとき、多様性の”質”が違えば結果も変わるのかという点は検証していなかった。よく言われる「アンサンブルはメンバーが多様であるほど良い」という説も、dropoutの件と同じく、言葉で聞くだけで終わらせず自分の手で確かめてみることにした。
実験に使ったコードの全文はGitHubに置いています。
今回の対決: 同じ予算で「浅い多様性」と「本物の多様性」
データは前回と同じtwo moons(noise=0.28)。2つの三日月状の点群が絡み合った2クラス分類の定番データセットで、ある点がどちらの三日月から生成されたかを当てるのが今回のタスクだ(実物の形は、少しあとに出てくるブートストラップの図の左側で見せる)。各試行では1000点を生成し、うち700点を訓練データに、残りの300点をテストデータに回す。以降この記事に出てくる「精度」や「不一致率」は、すべて学習には一切使っていないテスト300点の上で測った値だ。MLPも前回と同じ、2入力→隠れ層(tanh)→1出力(sigmoid)を、順伝播・逆伝播・Adamまで全部numpyで自前実装したものをそのまま使い回している。
今回はdropoutではなく、明示的アンサンブル同士を、総パラメータ予算330(=隠れユニット合計80×1ユニットあたり4パラメータ、にメンバーごとの出力バイアス1個×10を足した合計)を揃えたうえで2種類用意した。
- A: shallow diversity(seedのみ) — 全メンバーが隠れ8ユニット固定・訓練データ700点をそのまま使用。違うのは乱数初期化seedだけ(M=10)
- B: real diversity(bagging+幅) — メンバーごとに隠れユニット数を4, 5, 6, 7, 8, 9, 10, 11, 12, 8(合計80、Aと同じ予算)に変え、さらに各メンバーは訓練データをブートストラップ再抽出(700点を重複ありで再抽出)して学習する

Bのブートストラップ再抽出のコードはこれだけだ。
idx = rng.integers(0, n, size=n) # bootstrap: 重複ありで同じ人数だけ再抽出
Xb, yb = X_tr[idx], y_tr[idx]
各メンバーは平均すると訓練データの約63.2%のユニークな点しか見ないことになる(重複込みでn個引くと、ある1点が選ばれない確率は)。同じデータの中から少しずつ違う”世界”を切り出して学習させている、というイメージだ。
言葉と数式だけだとイメージしづらいので、1試行目のメンバー1人目が実際に引いた標本を、元の訓練データと並べて図にしてみた。

左が元の700点で、これが今回のデータtwo moonsの実物でもある——青(class 0)とオレンジ(class 1)の三日月が、noise=0.28のせいでかなり深く混ざり合っている。右がこのメンバーに実際に見えている”世界”だ。灰色のxになっている266点は一度も引かれなかった点で、残ったユニークな点は434点(62%)——理論値の63.2%とほぼ一致する。大きい点は重複して何度も引かれた点(最多で6回)で、その点はそのぶん学習で重く扱われる。この”見えている世界”のズレがメンバーごとに違う、というのがBの多様性のもう1つの源泉になっている。
多様性の実測には、メンバー間の予測が食い違う割合(pairwise disagreement rate)を使った。
def pairwise_disagreement(bin_preds):
"""bin_preds: (M, n) boolean array of member predictions. Average pairwise disagreement rate."""
total, n_pairs = 0.0, 0
for i in range(len(bin_preds)):
for j in range(i + 1, len(bin_preds)):
total += (bin_preds[i] != bin_preds[j]).mean()
n_pairs += 1
return total / n_pairs
そして、精度の「ゲイン」はアンサンブル精度 − 個々のメンバー精度の平均として定義した。これが今回の主役の数字だ。
1回の試行だけで結論を出すと運の要素を見誤りかねないので、two-moonsのデータ生成seedを変えて8回試行を繰り返し、ノイズの大きさそのものも一緒に見ることにした。
結果: Bのゲインは全8試行でAを上回った
8試行を集計した結果がこちら。
A(seedのみ): 平均メンバー精度 0.9139±0.0160 アンサンブル精度 0.9138±0.0171
ゲイン -0.0001±0.0034 不一致率 0.0162±0.0044
B(bagging+幅): 平均メンバー精度 0.9088±0.0160 アンサンブル精度 0.9179±0.0180
ゲイン +0.0091±0.0047 不一致率 0.0507±0.0102
まず目を引くのは、Bの個々のメンバー精度はAより低い(0.9088 vs 0.9139)ということだ。ブートストラップで訓練データを間引かれ、幅の狭いメンバー(隠れ4ユニットなど)も混じっているので、単体では弱くなるのは道理にかなっている。ところがアンサンブルにした瞬間、順位が逆転する。Bのアンサンブル精度(0.9179)はAのアンサンブル精度(0.9138)を上回った。「個々には弱いが集めると強い」という、まさにアンサンブルらしい現象が起きている。
ゲイン(アンサンブル精度−平均メンバー精度)で見ると差はもっとはっきりする。Aは−0.0001とほぼゼロ(平均はむしろわずかにマイナスで、8試行中4試行がマイナスだった)なのに対し、Bは+0.0091。8試行それぞれのペア差(B−A)を見ると、
paired per-trial gain diff: mean=+0.0093 std=0.0059 min=+0.0020 max=+0.0187
paired t-test on gain (B vs A): t=4.124 p=0.0044
8試行全部でBのゲインがAのゲインを上回った(最小でも+0.0020)。対応のあるt検定でp=0.0044と、この差はノイズの範囲では説明しづらい。「多様性が大きいほどアンサンブルは伸びる」という直感は、少なくとも今回の設定では実測でも支持された。
メンバー間の不一致率も、Aが0.016なのに対しBは0.051と3.1倍(t検定 p<0.0001)。狙い通り、Bは「本当に多様」なメンバーの集まりになっている。

全16点(A8個+B8個)を不一致率とゲインの散布図にすると、右肩上がりの傾向がかなりはっきり見える。プールした相関係数はr=0.76。ちなみに前回のdropout記事で見た「予測分散の相関r=0.13」とは全く別の相関で、あちらは「アンサンブルとMC-dropoutの分散の一致度」、こちらは「1つのアンサンブル内での不一致率とゲインの関係」なので、混同しないよう注記しておく。

黒い点(各試行の実測値)を見ると、Aのゲインは0付近でプラスマイナス両方に散らばっていて「差があるとは言い切れない」くらいのノイズがあることが分かる。一方Bのゲインは全ての黒点が0より上にあり、試行間のばらつきはあってもマイナスに落ちることはなかった。この「点を全部見せる」ことで、平均値だけでは分からないノイズの大きさが伝わると思う。
決定境界を1本ずつ重ねてみる
数字だけでなく、実際にメンバーの決定境界がどれくらいバラバラなのかを見てみたかったので、10人のメンバーの境界線を1本ずつ重ね描きしていくアニメーションを作った(代表として8試行のうち1試行目を使用。この試行ではA アンサンブル精度0.927、B アンサンブル精度0.930)。

Aの10本の境界線は、束ねてもほとんど1本の太い線にしか見えないくらい重なっている。同じデータを見て同じ構造で学習しているのだから、たどり着く先も似通うのは自然なことだ。対してBの10本は、特にデータが少ない周辺部で明らかにバラけていて、それぞれのメンバーが少し違う”仮説”を持っていることが視覚的にも分かる。前回のdropoutの記事で見た「ensembleのメンバーは毎回別の仮説を見せてくる」という話と同じ構図が、今度はアンサンブル内部の”多様性の強さ”の違いとして現れている格好だ。
正直に書いておくべきこと
ここまでの数字はBに分がある方向で綺麗に揃っているが、いくつか誠実に書いておきたい。
まず、効果自体は決して大きくない。アンサンブル精度そのものの差は0.9138 vs 0.9179で、0.4ポイント程度に過ぎない。ゲインの差(+0.0093)は統計的には有意だが、実務上「劇的に良くなる」というレベルの話ではなく、two-moonsという比較的単純なタスクでの結果でもある。もっと難しいタスクや、もっとメンバー数が多い設定では違う数字になる可能性は十分にある。
次に、Bは「bagging」と「幅の変更」を同時に行っているので、どちらの寄与が大きいのかはこの実験だけでは切り分けられない。ブートストラップだけの効果、幅を変えるだけの効果を別々に測る追加実験をすれば、もう一歩踏み込めるはずだが、今回はその切り分けまでは行っていない。
それから、コンドルセ陪審定理の記事で見た「投票者が独立であるほど多数決は賢くなる」という話とも通じるところがある。あの記事では「独立性が崩れると、名目上の人数より実効的な人数が少なくなる」と書いたが、今回のAはまさにそれに近い状態だったのだと思う。同じデータ・同じ構造で学習した10人は、名目上は10人でも、実質的にはもっと少ない人数分の情報しか持っていない。Bは訓練データと構造の両方をずらすことで、実効的な人数をより10人に近づけた、と言えるかもしれない。
手を動かして意外だったこと
一番意外だったのは、Bの個々のメンバーはAより弱いのに、集めると逆転するという点だった。もし精度だけを見て「どちらのメンバーが優秀か」を判断していたら、Aを選んでいたはずだ。でもアンサンブルとして使うことを前提にするなら、個々の完成度を多少犠牲にしてでも多様性を稼いだ方が得、というのが今回実測して見えた構図だった。「集団としての強さ」と「個体としての強さ」は必ずしも一致しない。
まとめ
- two moonsデータに対し、総パラメータ330(隠れユニット合計80)で揃えた2種類の明示的アンサンブル(M=10)を比較した。A: 隠れ8ユニット固定+同じ訓練データ+seedのみ違う。B: 隠れ幅4〜12を混ぜ+訓練データをブートストラップ再抽出
- 個々のメンバー精度はBの方が低い(A 0.9139 vs B 0.9088)が、アンサンブル精度はBの方が高い(A 0.9138 vs B 0.9179)
- 精度ゲイン(アンサンブル−平均メンバー)はAが−0.0001でほぼゼロ、Bが+0.0091。8試行全部でBがAを上回り、対応のあるt検定でp=0.0044
- メンバー間の予測不一致率はAが0.016、Bが0.051と3.1倍。不一致率とゲインのプールした相関はr=0.76
- 決定境界を可視化すると、Aの10本はほぼ1本に重なるのに対し、Bの10本は特に周辺部で明らかにバラける
- 効果量自体は小さく(アンサンブル精度差0.4ポイント)、bagging由来と幅由来の寄与は今回切り分けていない、という限界も残る
最後に少し私事を。この実験をしていて考えたのは、意見を集めるときの「人数」と「多様性」の違いのことだった。同じ会社の同じチームの、同じ会議で同じ資料を見た5人に意見を聞くのと、全然違う業界・違う年齢・違う立場の5人に意見を聞くのとでは、たとえ人数が同じでも得られるものの質がまるで違う。前者は今回のAに近く、後者はBに近い。個々の意見の”完成度”だけで言えば、専門外の人の意見は的外れに見えることもある——今回のBの個々のメンバーがAより弱かったのと同じだ。それでも、集めて重ねたときに見えてくるものの豊かさは、後者の方が明らかに大きい。自分と同じような人にもう一人聞くよりも、自分とは違う場所に立っている一人に聞く方が、案外遠くまで連れて行ってくれるのかもしれない。
このブログでは、機械学習の仕組みを実際にコードで実装して確かめた実験をテーマ別に整理しています(拡散モデル・Transformer・強化学習・多様体学習・過学習など)。


