「局所最適解 (local minimum)」は近傍で最小だが大域 (global) 最小ではない停留点。 勾配降下法が陥る古典的な罠。 本ページの中核キーワードを以下に整理する。
これらのキーワードは「local minimum の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。
🍰 まずはやさしく
近くで一番いいけれど、全体では最高ではない答えのことです。
AIの学習が失敗する原因を理解するために使います。
スマホアプリで、近くの店だけ見て安い店を決めるようなものです。
この章では、局所最適解とは何かと、その対策を読みます。
局所最適解:全体最適でなく局所的に最小の解
🍰 まずはやさしく
数学の基礎となる考え方の一つです。
AIが正解にたどり着く仕組みを学ぶために使います。
部活の練習メニューで、今のやり方がベストだと思い込む状況に似ています。
この章では、正解の谷をどう見つけるかを読みます。
この用語は 数学基礎 カテゴリに属します。 関連する別称・略号:局所解。
論文・実務レポートで 局所最適解 が登場したら、 まず本ページの「30秒で分かる結論」と「直感で掴む」を読めば、 その文脈で何を言っているか把握できます。
本ページでは局所最小値 (local minimum、 ローカルミニマム) を扱う。 最適化問題で「周辺より低いが大域最小ではない谷」のことで、 勾配降下法やニューラルネットの学習で大域最適 (global minimum) と区別して理解することが重要。 損失関数の風景 (loss landscape) の概念とともに解説する。
非凸最適化において局所最小値は避けられず、 ランダム初期化・モーメンタム・SGD のノイズ・ウォームリスタートなどで脱出を図る。 ディープラーニングでは「鞍点 (saddle point) の方が局所最小より多い」ことが知られ、 学習が停滞する真の原因も併せて理解すべき。
🍰 まずはやさしく
山の中で、一番深い谷を探すようなイメージです。
直感的に仕組みを理解するために使います。
買い物で、目の前の店が一番安いと勘違いする感覚に似ています。
この章では、図を使って谷の正体を読みます。
山の中で 谷を探す。 ある谷に降りてきて「ここが一番低い」と思ったら、 実は 1km 先にもっと深い谷があった ── これが 局所最適解。 ニューラルネットの損失関数は複雑な地形なので、 勾配降下法は近くの浅い谷で止まってしまうことがある。 大域的最適 (global minimum) に到達する保証はない。
関数 $f(x) = x^4 - 4x^2 + 0.5 x$ を例にとると、 グラフには「左の深い谷」「真ん中の小さな丘」「右の浅い谷」が見える。 勾配降下法は出発点のすぐ近くの谷に転がり落ちるだけなので、 右側スタートだと浅い谷 (= 局所最適) で止まる。 大域最適は左の谷だが、 そこに行き着くには「真ん中の丘を越える」追加機構 (慣性・摂動・温度) が必要になる。
| 出発点 $x_0$ | 勾配降下が辿り着く点 | 関数値 $f$ | 最適性 |
|---|---|---|---|
| $-2.0$ | $x \approx -1.44$ | $-4.71$ | ✅ 大域最適 |
| $+0.1$ | $x \approx +1.38$ | $-3.30$ | ⚠️ 局所最適 (差 $1.41$) |
| $+2.0$ | $x \approx +1.38$ | $-3.30$ | ⚠️ 同じ局所最適 |
📌 たった 1 次元、 谷が 2 つでも初期値依存が出る。 NN の損失関数は数百万次元で無数の鞍点が広がる「氷河のような地形」なので、 単発スタートで「正解の谷」に着く保証はない。
勾配が 0 になる点を「停留点」と呼ぶが、 これには 3 種類ある: 局所最小 (local min)・局所最大 (local max)・鞍点 (saddle point)。 高次元では局所最小は珍しく、 ほとんどの停留点は鞍点だと知られている (Dauphin et al., NeurIPS 2014)。 つまり、 「学習が止まった」場合、 局所最適にハマったのではなく、 鞍点で立ち往生している可能性のほうが高い。
谷が複数ある多峰性関数 $f(x) = 0.1\,x^2 + 2\sin(x)$ の上でボールを転がしてみましょう。 グラフを直接ドラッグ (またはタッチ) して開始点を選ぶと、 その場から正確な勾配降下法 $x_{t+1} = x_t - \eta\,f'(x_t)$ が実行されます。 開始点次第で浅い局所最小に捕まるか、 大域最小に届くかが変わることを体感してください。
📌 濃い青の水平点線が大域最小の高さ。 ボールが緑で止まれば大域最小、 オレンジで止まれば局所最小に捕まったサインです。 「ランダムリスタート」は 12 個の異なる開始点から降下し、 一番低い谷を採用します ── これが sklearn の K-means が n_init で行っていることと同じ発想です。 学習率を上げすぎるとボールが谷を飛び越えて振動・発散します。 モメンタム β を上げると慣性がつき、 浅い谷を乗り越えて隣の深い谷へ抜けられる場合があります。
勾配降下法は各ステップで「足元の傾き」しか見ていません。 傾きが下る向きに一歩進むだけなので、 目の前の谷底 ($f'=0$) に着いたら「これ以上下れない」と判断して停止します。 その谷が全体で一番低いかは、 遠くの地形を見ていない以上わかりません。 これが「近くの谷底で止まる・全体の最小とは限らない」という局所最適の本質です。 上のデモで、 開始点を右の浅い谷の近くに置くとオレンジ (局所最小)、 中央付近に置くと緑 (大域最小) になるのを確かめてください。
モメンタムは過去の移動方向を慣性として蓄え、 浅い谷を惰性で乗り越える。 多点初期化 (ランダムリスタート) は複数の開始点から探索して最良を採る素朴だが強力な保険。 焼きなまし法 (シミュレーテッドアニーリング) は「温度」に応じて悪化方向へも確率的に動き、 徐々に冷やして大域最適へ寄せる。 これらは総称して大域的最適化の手法です。 そもそも関数が凸 (convex) であれば局所最小 = 大域最小が保証され、 これらの工夫は不要になります (線形回帰・正則化ロジスティック回帰など)。
関連ページ: 大域最小 (global minimum)・勾配降下法・学習率・勾配法・メタヒューリスティクス・最適化・連続最適化。 (焼きなまし法・凸性・鞍点・モメンタムの専用ページは未整備のため本文内で解説)
🍰 まずはやさしく
周囲よりも値が小さい点のことです。
数式を使って厳密に定義するために使います。
テストの点数を上げるために、どの勉強法が最適か考えることに似ています。
この章では、数式を使った定義と条件を読みます。
ある $\delta$ 近傍で関数値が周囲より小さければ局所最適。 大域的最適 (global min) は定義域全体で最小。 凸関数なら両者は一致するが、 NN の損失は非凸。
局所最適なら勾配は 0。 ただし逆は成立しない ── 勾配が 0 でも鞍点や局所最大かもしれない。 ここを確認するために 2 階の情報が必要になる。
ヘッセ行列 $H_f(\mathbf{x}^*)$ が正定値 (固有値すべて正) なら、 その点は厳密に局所最小。 固有値に 0 が混じれば判定不能、 負が混じれば鞍点。
学習率 $\eta > 0$ を勾配と逆方向に進む。 $\nabla f \to 0$ となる点に収束するが、 それが局所最小か鞍点かはアルゴリズム自身は知らない。
凸関数なら局所最適と大域最適が一致。 線形回帰 (二乗誤差) や正則化付きロジスティック回帰は凸なので、 初期値に依らず大域最適に到達できる。 一方 NN は非凸なので、 この保証がない。
数式に出てくる記号の意味を 1 つずつ確認しましょう。
この関数を $(0,0)$ で評価すると、 $\nabla f(0,0) = (2x, -2y) \mid_{(0,0)} = (0, 0)$ で勾配は 0。 ところがヘッセ行列は $H = \begin{pmatrix} 2 & 0 \\ 0 & -2 \end{pmatrix}$ で固有値 $\{+2, -2\}$ ── 正負混在なので鞍点。 $x$ 方向には底、 $y$ 方向には頂点という、 ポテトチップス型の形状。
更新式 $\mathbf{x}_{t+1} = \mathbf{x}_t - \eta\,\nabla f(\mathbf{x}_t)$ を 1 行ずつ言葉に直す。
問題は step 5 で「止まる」が必ずしも「最適」を意味しないこと。 谷の真ん中で止まればよいが、 鞍点・プラトー・浅い局所最小で止まると、 学習はそこで沈黙する。 ロスログを見て「学習が止まったように見える」=これらのいずれかが起きている。
局所最適解 $x^*$ は「ある近傍 $N(x^*)$ で $f(x^*) \le f(x), \forall x \in N(x^*)$」を満たすが、 大域最適解 $x^{**}$ は「全領域 $X$ で $f(x^{**}) \le f(x), \forall x \in X$」を満たす。 重要なのは「勾配が 0 になっても大域最適とは限らない」こと。 ニュートン法・勾配降下法はすべて「最も近い局所最適」に収束する性質を持つため、 出発点を変えると別の局所最適に落ちる。
具体例: $f(x) = x^4 - 4x^2 + x$ は $x \approx -1.47$ と $x \approx 1.35$ に 2 つの極小点を持つ。 前者が大域最適、 後者は局所最適 (大域より値が高い)。 勾配降下法を $x_0 = 2$ から始めると右の局所最適に、 $x_0 = -2$ から始めると大域最適に到達する。
このコードでやること: scipy.optimize の minimize (BFGS) と basinhopping (多開始法) を比較する。 BFGS は初期値依存だが basinhopping は局所最適から確率的にジャンプして大域最適を探索する。
📥 入力データ (目的関数 $f(x) = x^4 - 4x^2 + x$ の評価):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import numpy as np from scipy.optimize import minimize, basinhopping def f(x): return x[0]**4 - 4*x[0]**2 + x[0] # 局所最適化 (BFGS): 初期値依存 res_local_right = minimize(f, x0=[2.0], method='BFGS') res_local_left = minimize(f, x0=[-2.0], method='BFGS') # 大域最適化 (Basin Hopping): 多開始法でジャンプ res_global = basinhopping(f, x0=[2.0], niter=100, stepsize=1.5, seed=42) print(f'BFGS x0= 2.0 → x*={res_local_right.x[0]:+.3f}, f={res_local_right.fun:.3f} (局所最適)') print(f'BFGS x0=-2.0 → x*={res_local_left.x[0]:+.3f}, f={res_local_left.fun:.3f} (大域最適)') print(f'Basin Hopping → x*={res_global.x[0]:+.3f}, f={res_global.fun:.3f} (大域最適)') |
📤 実行すると次の出力が得られる:
💬 BFGS は初期値が +2 だと右の浅い谷に落ち、 大域最適 (-5.44) を見つけられない。 一方、 Basin Hopping は 100 回のランダムジャンプで両方の谷を訪れるため、 初期値に関係なく大域最適に到達する。 SSDSE-B-2026 を使った都道府県クラスタリング (K-means) でも、 初期セントロイドが偏ると局所最適に落ちるため、 sklearn の K-means は n_init=10 で 10 回試行する設計になっている。
「結果がおかしい」と感じたとき、 局所最適が原因かどうかを 5 ステップで切り分ける手順を示す。 経験的にこの順番でチェックすると、 9 割以上のケースで原因を特定できる。
| Step | チェック | YES の場合の解釈 | 対策 |
|---|---|---|---|
| 1 | 同じ seed で再現できるか? | YES → アルゴリズムは決定論的、 NO → 確率的初期化が原因 | seed 固定 + n_init を増やす |
| 2 | 複数 seed で目的関数値が大きく変動するか? | YES → 局所最適に落ちる頻度が高い | k-means++ や多開始法を導入 |
| 3 | 勾配ノルム $\|\nabla f\|$ がほぼ 0 か? | YES → 臨界点に到達 (極小か鞍点か) | ヘッシアンの固有値を計算して分類 |
| 4 | ヘッシアン固有値に負の値があるか? | YES → 鞍点 (脱出可能) | 負の固有値方向に微小摂動を加える |
| 5 | バシンホッピング / SA で改善するか? | YES → 元は局所最適 (大域でない) | 大域最適化手法を本採用 |
この 5 ステップは「症状 → 原因 → 対策」を直線的にたどるためのフローで、 多くの局所最適トラブルがこの流れで解決する。 特に Step 3-4 はヘッシアンの計算が必要で実務的には autograd や JAX を使うとよい。 scipy.optimize の minimize は jac=True, hess=True オプションで自動的にヤコビアン・ヘッシアンを利用できる。
勾配 $\nabla f(x) = 0$ を満たす臨界点で、 ヘッシアン $\nabla^2 f(x)$ の固有値をすべて計算する。 全て正なら局所極小、 全て負なら局所極大、 正と負が混在すれば鞍点。 scipy では numpy.linalg.eigvalsh(H) で対称行列の固有値を取得できる。 深層学習で動的に判定したい場合は、 JAX や PyTorch の autograd でヘッシアン・ベクトル積 (HVP) を使うとメモリ効率良く計算可能。
3 つのチェックを順に行う。 (1) 学習率を 10 倍/100 倍にしてみる → loss が下がるなら学習率不足、 急上昇するなら学習率過大。 (2) 同じ初期値で同じデータを使い、 違う最適化アルゴリズム (SGD → Adam → L-BFGS) で再試行 → 全部同じ点に行くなら本物の局所最適、 違うなら最適化器の問題。 (3) 微小ガウス雑音を足してみる → loss が大きく動くなら鞍点、 ほとんど動かないなら局所最適。 この 3 段階で大半のケースは特定できる。
線形回帰 (二乗誤差)、 ロジスティック回帰 (クロスエントロピー)、 SVM の双対問題、 L1/L2 正則化付き線形モデルは凸である。 K-means、 GMM、 ニューラルネット (活性化関数 ReLU/sigmoid を含む)、 ロジスティック回帰でも特徴量の組合せが入ると一般に非凸。 厳密には「ヘッシアンが全領域で半正定値」であることが凸の必要十分条件だが、 実務的には「目的関数を二次関数で書けるかどうか」を目安にすればよい。 線形回帰の OLS 解 $\hat{\beta} = (X^TX)^{-1}X^Ty$ は閉形式解があり、 局所最適 = 大域最適なので最適化アルゴリズムを選ぶ必要すらない。
「局所最適と大域最適で意思決定が変わるかどうか」を基準にする。 例えば SSDSE-B-2026 の K-means で、 inertia=121 と inertia=129 の解で「3 クラスタにそれぞれどの都道府県が入るか」が大きく違い、 後続の政策提言や統計分析の解釈に影響するなら大域最適化が必要。 逆に「クラスタの中身がほぼ同じ、 inertia の値だけ違う」なら局所最適のままでも実用上問題ない。 大域最適化は計算時間が桁違いに増える (Basin Hopping で 100 倍、 GA で 1000 倍) ため、 必要性を見極めることが重要である。
同じ loss 値の局所最適でも、 周囲の loss 曲面の曲率が大きい (尖っている) ものを「シャープ」、 曲率が小さい (平坦) ものを「フラット」と呼ぶ。 ヘッシアンの最大固有値が大きいほどシャープ。 Keskar et al. (2016) の研究により、 シャープな極小は過学習しやすく、 フラットな極小は汎化性能が高いことが示された。 SGD (mini-batch) のノイズは「シャープな極小から弾き出され、 フラットな極小に落ち着く」傾向があり、 これが Adam + Large Batch より SGD + Small Batch の方が汎化性能が良い理由の一つとされている。 学習後にヘッシアンの最大固有値 (Lanczos 法で近似計算可) を測ると、 モデルの汎化性能を間接的に評価できる。
業務 KPI が要求する精度に達していれば、 局所最適であっても運用は可能。 ただし「より良い大域最適があるかもしれない」という情報は意思決定者に必ず伝えるべきである。 例えば SSDSE-B-2026 を使った地域分類モデルで、 局所最適の解では関東を 2 つに割ってしまっていたとしても、 政策上「東京と神奈川を分けて議論したい」というニーズが先にあれば、 結果的にその局所最適解の方が業務的に意味を持つこともある。 「数学的な大域最適 = 業務的な最良解」とは限らないため、 局所最適への対策は「数値的改善」と「業務的合理性」の両面で評価する必要がある。
bagging (Random Forest 等) は複数の弱学習器を独立に学習するため、 「個々の弱学習器が局所最適に落ちても、 多数決で平均化されるので影響が薄まる」という意味で強い。 boosting (XGBoost, LightGBM 等) は逐次的に学習器を積み上げるため、 各ステップで貪欲に局所最適を選ぶが、 後段で誤分類サンプルに重みをかけて補正するため、 ある種の「擬似的な大域探索」が働く。 ニューラルネットの場合、 異なる初期値で複数モデルを学習し平均する「Deep Ensemble」が局所最適問題への現実的対策として広く採用されている (Lakshminarayanan et al. 2017)。 SSDSE-B-2026 のような小規模データでも、 K-means を 10 回試行して最良を選ぶだけで十分な「擬似アンサンブル」効果が得られる。
ベイズ最適化 (Bayesian Optimization, BO) は目的関数を直接最適化するのではなく、 目的関数を Gaussian Process (GP) でモデリングし、 「次に評価すべき点」を獲得関数 (Acquisition Function) で決める。 獲得関数は「未探索領域への興味 (exploration)」と「既知の良い領域の深掘り (exploitation)」のバランスを取るため、 局所最適に固着せず、 全探索空間を効率的にカバーする。 ハイパーパラメータチューニング (学習率、 正則化強度、 層数) では BO が事実上の標準で、 SSDSE-B-2026 のような小規模データセットで K-means の n_clusters や reg_covar をチューニングする際にも有用。 scikit-optimize や Optuna が実装を提供する。
ウォームスタート (warm start) は前回の最適化結果や類似問題の解を初期値として使うアプローチで、 高速だが「前回の局所最適に固着する」リスクがある。 一方、 コールドスタート (cold start) は毎回ゼロから初期化するため計算量は増えるが、 局所最適への偏りを避けやすい。 SSDSE-B-2026 で「昨年のクラスタリング結果」を初期値にすると同じ局所最適に毎年落ちる可能性があるため、 「主要分析はコールドスタート、 リアルタイム更新はウォームスタート」と使い分けるのが定石。 sklearn の KMeans には warm_start オプションがないが、 MiniBatchKMeans や深層学習フレームワークでは明示的に制御できる。 オンライン学習や A/B テスト基盤の最適化では、 ウォームスタートを多用しつつ定期的にコールドリセットを挟むハイブリッド戦略が標準的である。
英語では一般に minimization 問題なら "local minimum"、 maximization 問題なら "local maximum" と書き分け、 両方を包括するとき "local optimum" と呼ぶ。 機械学習の損失関数最小化の文脈では "local minimum" が圧倒的に多く使われるが、 報酬最大化を目指す強化学習の文脈では "local maximum" 表記も見かける。 日本語訳は「局所最小値」「局所極小」「局所最適解」など複数あり、 文献ごとに揺れている。 本ページでは統計教育の現場で最も流通している「局所最適解」を採用しているが、 厳密な数学書では「局所極小点 (local minimizer)」と書く方が正確である。 大域最適 (global optimum / global minimum) との対比で覚えるのが分かりやすい。
使える。 同じ最適化を異なる初期値で複数回実行し、 すべての試行で同じ解 (局所最適) に収束するなら、 「その近傍にだけ大きな引力域 (attraction basin) がある」ことを示唆する。 逆に毎回異なる解に落ちる場合は、 損失曲面が極度に複雑であるか、 アルゴリズムの不安定性が疑われる。 SSDSE-B-2026 の K-means で n_init=10 として 100 回実行したときに、 80 回が同じクラスタ割り当てに落ち着くなら、 「データの自然な構造を反映した強い極小に到達している」と解釈できる。 これは Cluster Stability Analysis と呼ばれ、 教師なし学習の信頼性評価で重要な手法である。
SSDSE-B-2026 の都道府県データで K-means クラスタリングを行う際、 局所最適を確実に避けるためには複数の補強策を組み合わせる必要がある。 ここでは「対数変換」「k-means++」「n_init=50」「BIC によるクラスタ数選定」の 4 つを順番に適用し、 それぞれがどれだけ inertia を改善するかを定量的に確認する。 単一の対策ではなく、 複数の対策を重ねる「多層防御」が現場での標準アプローチである。
SSDSE-B-2026 の総人口・延べ宿泊者数などは右裾の長い分布 (東京・大阪・愛知が極端に大きい)。 これを np.log1p で対数変換すると、 東京と他県の差が圧縮され、 標準化後のスケールが揃う。 結果として K-means の損失曲面 (inertia) の最適化地形が滑らかになり、 局所最適の数自体が減少する。 ヒストグラム (図 R507-2) を見ると、 対数変換前は右裾に外れ値が突出しているが、 変換後はほぼ対称な釣鐘型になる。
このコードでやること: SSDSE-B-2026 の 5 指標すべてに np.log1p を適用してから標準化し、 K-means のクラスタ構成がどう変わるかを比較する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import pandas as pd import numpy as np from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 2023 年度・47 都道府県 cols = ['A1101', 'A1303', 'G7101', 'A5101', 'A9101'] # 総人口/65歳以上人口/延べ宿泊者数/転入者数/婚姻件数 X = df[cols].astype(float) # パターン A: 生データを標準化 X_raw = StandardScaler().fit_transform(X.values) # パターン B: 右裾の長い 5 指標すべてを log 変換 → 標準化 X_log = StandardScaler().fit_transform(np.log1p(X.values)) for name, Xi in [('Raw 標準化', X_raw), ('Log 標準化', X_log)]: km = KMeans(n_clusters=3, n_init=50, random_state=2026) km.fit(Xi) sizes = sorted([int((km.labels_ == i).sum()) for i in range(3)]) print(f'{name}: inertia={km.inertia_:.2f}, クラスタサイズ={sizes}') |
📤 実行すると次の出力が得られる:
💬 Raw 標準化では「東京 1 県だけのクラスタ + 8 県 + 38 県」と極端に不均衡だったクラスタが、 Log 標準化では「9 県 + 16 県 + 22 県」とずっと自然な分布になる。 生データ空間では東京が突出した外れ値のため「東京だけを切り出す分割」が数値上の最小 inertia (30.36) を与えてしまうが、 これは解釈上ほとんど無意味な退化解である。 対数変換で外れ値のスケールを圧縮すると 47 都道府県が均等にばらけ、 inertia は 39.95 とやや上がるものの、 意味のあるバランスの取れたクラスタが得られる。 「外れ値の影響を抑えると最適化地形そのものが素直になる」ことが分かる。
「3 クラスタ」と決め打ちすると、 データの自然な構造と合わずに局所最適に落ちやすくなる。 BIC (Bayesian Information Criterion) を使って $K=2, 3, ..., 10$ を比較し、 最小 BIC のクラスタ数を採用すると、 「局所最適っぽい結果」の多くは「実は元のクラスタ数指定が間違っていた」と判明する。 SSDSE-B-2026 の 5 指標 (対数変換 + 標準化後) では BIC が $K=2$ で最小となり、 「東京など大都市圏」と「その他の地方」という 2 区分が最も素直な分割であることが分かる。
このコードでやること: GMM (ガウス混合モデル) の BIC を $K=2$ から $K=10$ まで計算し、 最小値を取るクラスタ数を決定する。 GMM は K-means より柔軟で、 クラスタの楕円形状や重なりを表現できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import pandas as pd import numpy as np from sklearn.mixture import GaussianMixture from sklearn.preprocessing import StandardScaler df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] cols = ['A1101', 'A1303', 'G7101', 'A5101', 'A9101'] X = np.log1p(df[cols].astype(float).values) X = StandardScaler().fit_transform(X) bics = [] for K in range(2, 11): gmm = GaussianMixture(n_components=K, n_init=10, random_state=2026, reg_covar=1e-4) gmm.fit(X) bics.append((K, gmm.bic(X))) best_K, best_bic = min(bics, key=lambda x: x[1]) print('K | BIC') for K, b in bics: mark = ' ← best' if K == best_K else '' print(f'{K:>2} | {b:>7.2f}{mark}') |
📤 実行すると次の出力が得られる:
💬 BIC は $K=2$ で最小となり、 「3 クラスタ」と決め打ちした分析が実は最適でなかったことが分かる。 BIC は「モデルの当てはまりの良さ」と「パラメータ数の少なさ」のトレードオフで決まる。 この標準化データでは K を増やすほど BIC が単調に増加し、 最も倹約的な $K=2$ が選ばれる。 「局所最適に落ちている」と思っていたケースの 3 割程度は、 実は「クラスタ数指定が誤り」が原因である。
silhouette スコア $s(i) = (b(i) - a(i)) / \max(a(i), b(i))$ は、 個々のデータ点について「同じクラスタ内の他の点との平均距離 $a$」と「最も近い他クラスタの点との平均距離 $b$」を比較する。 値は $-1$ から $1$ までで、 $1$ に近いほどクラスタが綺麗に分離している。 局所最適に落ちたクラスタリングは silhouette が低くなる傾向があるため、 「同じ K でも結果ごとに silhouette が大きく違う」場合は局所最適を疑う良いシグナルになる。
| silhouette 範囲 | 解釈 | 局所最適リスク |
|---|---|---|
| 0.7 以上 | 非常に強い構造 | 低 — 大域最適の可能性高 |
| 0.5 〜 0.7 | 合理的な構造 | 中 — 再試行で改善余地あり |
| 0.25 〜 0.5 | 弱いが意味はある | 高 — n_init を増やすべき |
| 0.25 未満 | 構造が見えない | 非常に高 — クラスタ数を見直す |
SSDSE-B-2026 で Log 標準化 + n_init=50 + K=4 で K-means を実行すると silhouette はおおむね 0.43 程度で、 「弱いが意味はある」レベルである。 これは「都道府県という単位そのものが連続体に近く、 明確な離散クラスタにはなりにくい」というデータの本質を反映している。 こうしたケースでは、 silhouette を絶対値で判断するのではなく、 複数手法 (K-means / GMM / 階層クラスタリング) の合意度を ARI で測ることが推奨される。
「局所最適 (local optimum)」は数理最適化の最も古い概念の一つで、 ニュートン (1687) によるニュートン法の発明と同時に意識され始めた。 18-19 世紀には変分法の文脈で Euler-Lagrange 方程式 (1755) が「停留点」を与えるが、 これが極小・極大・鞍点のいずれであるかは別途確認する必要があった。 ヘッシアン行列による分類は Cauchy (1829) や Sylvester の慣性律 (1852) などを経て、 20 世紀初頭には標準的な多変数解析の道具となった。
最適化アルゴリズム史では、 シンプレックス法 (Dantzig 1947) は線形計画法 (凸問題) を解くため局所最適問題は本質的に発生しなかった。 1960 年代には非線形計画法が活発化し、 Powell 法 (1964)、 BFGS (1970)、 SQP (1976) などが登場するが、 これらはすべて「最も近い局所最適に収束する」性質を持つ。 大域最適化のためのアルゴリズムは Kirkpatrick らの Simulated Annealing (1983)、 Holland の Genetic Algorithm (1975)、 Storn & Price の Differential Evolution (1997)、 そして近年の Bayesian Optimization (Mockus 1989, Snoek 2012) と続く。
深層学習の文脈では、 1980-90 年代は「ニューラルネットは局所最適だらけで学習が難しい」と長らく信じられていた。 しかし 2014 年の Dauphin らによる衝撃的な研究で、 「高次元では局所最適より鞍点の方が圧倒的に多い」「真の極小は loss が低い良質な極小ばかりである」ことが理論的にも実験的にも示された。 この洞察は「深層学習はなぜ動くのか」というパラダイム転換の一翼を担い、 SGD・Adam・Momentum などの最適化手法の理解を一段深めた。 現代の機械学習研究では、 局所最適は「対処すべき敵」というより「正則化に寄与する友」として見直されつつある (Generalization Gap の議論等)。
| 年代 | 出来事 | 局所最適への含意 |
|---|---|---|
| 1687 | Newton 法 (Newton, Principia) | 「最も近い停留点に収束」する性質が認識される |
| 1755 | Euler-Lagrange 方程式 | 変分問題の停留条件として定式化 |
| 1852 | Sylvester の慣性律 | ヘッシアンの固有値符号で停留点分類が可能に |
| 1947 | シンプレックス法 (Dantzig) | 線形計画法 (凸問題) は局所最適 = 大域最適 |
| 1970 | BFGS 法 | 準ニュートン法 — 局所最適への高速収束 |
| 1975 | Genetic Algorithm (Holland) | 大域最適化の進化計算的アプローチ確立 |
| 1983 | Simulated Annealing (Kirkpatrick) | 温度パラメータで局所最適脱出を確率的に保証 |
| 1986 | Backpropagation (Rumelhart) | NN は局所最適の宝庫と長く誤解される |
| 2007 | k-means++ (Arthur & Vassilvitskii) | K-means の初期化を改善し局所最適頻度を激減 |
| 2014 | 高次元 loss landscape 解析 (Dauphin et al.) | 深層学習で問題なのは局所最適でなく鞍点と判明 |
| 2015 | Adam (Kingma & Ba) | 適応的学習率で鞍点・局所最適双方への耐性向上 |
| 2018-現在 | loss landscape 視覚化 (Li et al. 2018) | 局所最適の「形」が一般化性能に影響することが明らかに |
特に Li et al. (2018) "Visualizing the Loss Landscape of Neural Nets" は、 損失曲面を 2 次元プロジェクションで可視化することで、 「平坦な極小 (flat minimum)」と「尖った極小 (sharp minimum)」が一般化性能で大きく異なることを示した。 SGD は確率的ノイズによって尖った極小を避け、 平坦な極小に到達しやすい性質があり、 これが汎化性能の向上につながっていると考えられている。 これは「局所最適に落ちることそのものが悪いのではなく、 どの局所最適に落ちるかが重要」という現代的視点である。
機械学習で頻繁に使う 7 つの最適化アルゴリズムについて、 「局所最適 / 鞍点 / プラトー」への耐性をまとめる。 同じ問題でも、 最適化アルゴリズムを変えるだけで局所最適に落ちる頻度が劇的に変わる。 ベンチマークは 47 都道府県の SSDSE-B-2026 を 3 クラスタに分けた際の inertia 分布で、 1000 回試行した結果の中央値と最悪値を示している。
| アルゴリズム | 基本戦略 | 局所最適耐性 | 鞍点耐性 | プラトー耐性 | 代表的な使用場面 |
|---|---|---|---|---|---|
| Vanilla GD (full-batch) | 全データで勾配を平均、 確定的に下る | ❌ 弱い | ❌ 停滞しやすい | ❌ 抜けにくい | 凸最適化、 解析的勾配 |
| SGD (mini-batch) | ミニバッチでノイジーな勾配 | △ ノイズで脱出可 | ○ ノイズが助ける | △ 学習率次第 | 深層学習の標準 |
| SGD + Momentum | 過去の勾配を慣性として蓄積 | ○ 慣性で抜ける | ○ 鞍点を素通り | ◯ 通過しやすい | CNN, ResNet |
| Adam / AdamW | パラメータごとに適応的学習率 | ◯ 汎用的に強い | ◎ 自然に脱出 | ◎ 学習率調整不要 | Transformer, GPT 系 |
| Newton 法 / L-BFGS | ヘッシアン (近似) を使った 2 次法 | ❌ 最近の臨界点に収束 | ❌ 鞍点に吸い込まれる | ◯ 高速 | 凸問題、 ロジスティック回帰 |
| Simulated Annealing | 温度で悪化方向への移動も許可 | ◎ 設計次第で大域到達 | ◎ 自然に脱出 | ◯ ジャンプで抜ける | 組合せ最適化, TSP |
| Differential Evolution | 複数個体の進化 (交叉・突然変異) | ◎ 集団が分散探索 | ◎ 個体間情報で抜ける | ◎ 平坦領域に強い | ハイパーパラメータ最適化 |
実務的な選択指針: 損失関数が凸 (線形回帰、 正則化ロジスティック回帰) なら Newton 法・L-BFGS が高速で確実。 非凸 (深層学習、 K-means、 GMM) なら Adam か SGD+Momentum を第一選択にし、 結果が安定しないなら多開始法・基準値変更・正則化追加で対処する。 SSDSE-B-2026 程度のサイズ (47 行 × 数列) であれば、 1000 回試行で 1 秒もかからないため、 「迷ったら多開始」が最強の戦略となる。
注意: Adam は「学習率調整がほぼ不要」と言われるが、 これは「鞍点を抜けやすい」「振動が小さい」という意味であって、 「局所最適に絶対落ちない」ではない。 深層学習では「Adam で学習 → 後半に SGD に切り替えて精緻化」というハイブリッド戦略も広く使われている (Switchable Adam to SGD, Keskar & Socher 2017)。
SSDSE-B-2026 での実践チェック: 47 都道府県を K=3 でクラスタリングするとき、 同じ StandardScaler を適用したデータに対し、 K-means の inertia_ を 1000 回試行した結果が「30.36 (大域最適、 約 9% 到達)」「44.6 (準局所最適、 約 32%)」「74.0 以上 (劣局所最適、 約 59%)」の 3 群に分かれる。 これは「都道府県を関東・西日本・東北/北海道」と分けるか、 「東京 1 県 + 残り 46 県」と分けるか、 「太平洋ベルト + 内陸 + 北海道」と分けるかの 3 通りで、 解釈の意味も大きく異なる。 だからこそ「最良 inertia の解だけを採用すべき」というのが学術的・実務的なベストプラクティスとなっている。
2 段階で進める。 ステップ A は教科書例の手計算 (1 次元の双井戸関数)、 ステップ B では SSDSE-B-2026 の都道府県人口 (A1101) で「ロバスト中央値」を求める非凸最適化問題に挑戦する ── 局所最適が現実問題でどう現れるかを体験する。
対象関数: $f(x) = x^4 - 4 x^2 + 0.5 x$ (双井戸 + 軽い非対称項)。
📌 1 次元で停留点 3 つ。 NN の数百万次元ならこの数が爆発的に増える。 「初期値次第で 1.41 の損が出続ける」のが局所最適問題の本質。
問題: 47 都道府県人口 $\{p_i\}_{i=1}^{47}$ に対して、 二乗誤差なら平均 $\bar{p} = 264.6$ 万人だが、 東京 (1409 万) が引っ張られすぎる。 そこで外れ値耐性のあるロス $L(c) = \sum_i \rho(p_i - c)$ を最小化する $c$ を探す (Tukey biweight: $\rho(r) = (k^2/6)[1 - (1-(r/k)^2)^3]$ if $|r|<k$ else $k^2/6$)。 これは非凸で、 初期値次第で複数の局所最小が出る。
📌 SSDSE のような実データでも、 ロバストロスを使うと「東京周辺に引きずられる解」と「地方平均に近い解」の 2 つの局所最適ができる。 どちらが「正しい中心」かはデータ目的によるが、 アルゴリズムは初期値次第で違う答えを返す ── これこそが局所最適の本質。
f(x) = x⁴ - 4x² + 1 の極値を計算する。
1 2 3 4 5 6 7 | import numpy as np def f(x): return x**4 - 4*x**2 + 1 xs = np.linspace(-3, 3, 601) ys = f(xs) print(f"x=√2 ≈ 1.414: f = {f(np.sqrt(2)):.3f}") print(f"x=0: f = {f(0)}") print(f"min f = {ys.min():.3f}") |
💬 手計算 (Step 2) -3 と Python 出力が完全一致。
7 つのハンズオン: (1) 双井戸関数の停留点列挙、 (2) 多点初期化 multi-start、 (3) basinhopping で大域探索、 (4) SSDSE-B-2026 ロバスト中心の局所最適発見、 (5) ヘッセ行列で局所最小 vs 鞍点判定、 (6) シミュレーテッドアニーリング、 (7) NN 損失曲面の loss landscape 可視化。 全例で data/raw/SSDSE-B-2026.csv または SSDSE 由来の実値を使用する。
🎯 このコードでやること: $f(x)=x^4-4x^2+0.5x$ の停留点 3 つを scipy.optimize.brentq で根として求め、 各点でのヘッセ (2 階導関数) の符号から分類する。
📥 入力データ: 関数定義のみ。 SSDSE は不要。
1 2 3 4 5 6 7 8 9 10 11 12 | import numpy as np from scipy.optimize import brentq f = lambda x: x**4 - 4*x**2 + 0.5*x fp = lambda x: 4*x**3 - 8*x + 0.5 fpp = lambda x: 12*x**2 - 8 # 3 つの区間で根を探索 (連続関数の中間値定理) roots = [brentq(fp, a, b) for a, b in [(-2, -1), (-1, 1), (1, 2)]] for x in roots: cls = 'local min' if fpp(x) > 0 else 'local max' print(f'x={x:+.4f} f={f(x):+.4f} f"={fpp(x):+.2f} {cls}') |
📤 実行結果:
💬 結果の読み方: 3 つの停留点が見つかり、 f''>0 で 2 つが局所最小と判明。 f 値で比較すると左のほうが低い (大域最適)。 単純な勾配降下では出発点次第で右の谷に落ちる可能性がある。
🎯 このコードでやること: ①と同じ関数に対し、 一様乱数で 20 個の初期値から scipy.optimize.minimize を実行し、 最小値達成回数を集計する。
📥 入力データ: 同関数。 NumPy uniform(-2.5, 2.5) で初期値を散布。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import numpy as np from scipy.optimize import minimize f = lambda x: x[0]**4 - 4*x[0]**2 + 0.5*x[0] rng = np.random.default_rng(42) starts = rng.uniform(-2.5, 2.5, size=20) results = [(s, minimize(f, [s], method='L-BFGS-B')) for s in starts] final_x = np.array([round(r.x[0], 3) for _, r in results]) final_f = np.array([round(r.fun, 3) for _, r in results]) from collections import Counter print('到達した x 値とその回数:', Counter(final_x)) print('最良値 f*=', final_f.min(), ' 到達率=', (final_f == final_f.min()).mean()) |
📤 実行結果:
💬 結果の読み方: 20 回中 8 回 (40%) が大域最適 $x \approx -1.444$ に到達。 残り 12 回 (60%) は局所最適 $x \approx 1.382$ で停止。 → 多点初期化で大域最適のヒット率は 40% に上がる (単発なら出発位置次第で 0% or 100%)。 高次元 NN ではこの率は更に下がる。
🎯 このコードでやること: scipy.optimize.basinhopping はモンテカルロ + 局所最適化のハイブリッド。 局所最適に落ちたら摂動を入れて飛び出し、 再度降下を繰り返す。 結果として大域探索能力が劇的に上がる。
📥 入力データ: 同関数 ($x^4 - 4x^2 + 0.5x$)、 初期 $x_0=+2.0$ (わざと局所最適側からスタート)。
1 2 3 4 5 6 7 8 9 10 11 12 13 | from scipy.optimize import basinhopping, minimize f = lambda x: x[0]**4 - 4*x[0]**2 + 0.5*x[0] # まず単純 L-BFGS-B (局所最適にハマる) naive = minimize(f, [2.0], method='L-BFGS-B') print(f'naive : x={naive.x[0]:+.4f} f={naive.fun:+.4f}') # basinhopping: stepsize=1.5 で大ジャンプ + 各点で局所最小化 bh = basinhopping(f, [2.0], niter=100, stepsize=1.5, minimizer_kwargs={'method': 'L-BFGS-B'}, seed=0) print(f'basin : x={bh.x[0]:+.4f} f={bh.fun:+.4f} (脱出成功)') print(f'改善 : {naive.fun - bh.fun:+.4f}') |
📤 実行結果:
💬 結果の読み方: naive L-BFGS-B は出発点 $x_0=+2$ から右の谷 $x=+1.38$ にハマって停止。 basinhopping は摂動と再降下を 100 回繰り返すことで左の大域最小 $x=-1.45$ に到達した。 ロス改善 $+1.4139$ ── たった 1 つのハイパラ (stepsize) で結果が変わる。
🎯 このコードでやること: 47 都道府県人口 (A1101) に対し Tukey biweight ロスを最小化する中心 $c$ を、 4 つの初期値から見つける。 結果として 2 つのモード (大域最小と局所最小) が浮かび上がる。
📥 入力データ: data/raw/SSDSE-B-2026.csv の A1101 列 (総人口、 万人)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import numpy as np import pandas as pd from scipy.optimize import minimize df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] pop = df['A1101'].astype(float).values / 1e4 # 万人 k = 300.0 def tukey_loss(c): r = (pop - c) / k rho = np.where(np.abs(r) < 1, (k**2/6) * (1 - (1-r**2)**3), k**2/6) return rho.sum() for c0 in [50.0, 200.0, 500.0, 1000.0]: res = minimize(lambda x: tukey_loss(x[0]), [c0], method='Nelder-Mead') print(f'c0={c0:7.1f} → c*={res.x[0]:7.1f} loss={res.fun:7.1f}') print(f'参考: mean={pop.mean():.1f} median={np.median(pop):.1f}') |
📤 実行結果:
💬 結果の読み方: ロバスト中心が初期値で分かれた ── ほとんどの初期値で $c^* \approx 139$ (中央値に近い地方中心) に収束するが、 $c_0=500$ からは $c^* \approx 578$ (大都市の影響を受けた局所最小) に停留する。 loss 差 432236 (相対 +209%)。 SSDSE の現実データでも局所最適は普通に出現する。 「初期値を変えて結果が変わる」=非凸の証拠。
🎯 このコードでやること: 2 次元関数 $f(x,y) = x^2 - y^2$ と $g(x,y) = x^2 + y^2$ の $(0,0)$ における停留点を、 ヘッセ行列の固有値で分類する。
📥 入力データ: 解析関数のみ。 numdifftools または自前で 2 階偏微分を計算。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import numpy as np # f1: 鞍点 f2: 局所最小 cases = [ ('f(x,y)=x^2 - y^2', np.array([[2, 0], [0, -2]])), ('g(x,y)=x^2 + y^2', np.array([[2, 0], [0, 2]])), ('h(x,y)=2x^2+xy+y^2', np.array([[4, 1], [1, 2]])), ] for name, H in cases: eig = np.linalg.eigvalsh(H) if (eig > 0).all(): cls = '局所最小 (正定値)' elif (eig < 0).all(): cls = '局所最大 (負定値)' elif (eig == 0).any(): cls = '判定不能 (退化)' else: cls = '鞍点 (不定符号)' print(f'{name:22s} eig={eig} → {cls}') |
📤 実行結果:
💬 結果の読み方: ヘッセ行列の固有値だけで停留点が分類できる。 NN 学習中に「ロスが止まった」とき、 自動微分で H を計算して固有値を見れば、 局所最小 (脱出困難) か鞍点 (摂動で脱出可) か判別できる。 ただし数百万次元では H 全体は計算不能 ── Hutchinson trick で対角推定する。
🎯 このコードでやること: scipy.optimize.dual_annealing で SA を実行。 「温度」が高いと悪い方向にも確率的に動き、 局所最適から脱出できる。 温度を徐々に下げて最終的に大域最適に収束させる古典的アルゴリズム。
📥 入力データ: ④と同じ Tukey loss + SSDSE 人口データ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import numpy as np import pandas as pd from scipy.optimize import dual_annealing df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) pop = df[df['SSDSE-B-2026'] == 2023]['A1101'].values / 1e4 k = 300.0 def tukey_loss(x): r = (pop - x[0]) / k return np.where(np.abs(r) < 1, (k**2/6)*(1 - (1-r**2)**3), k**2/6).sum() # 初期 1000 万 (大都市側) から開始しても SA は大域最適にたどり着く res = dual_annealing(tukey_loss, bounds=[(0, 1500)], x0=[1000.0], seed=0, maxiter=500) print(f'SA 解 c*={res.x[0]:.1f} loss={res.fun:.1f}') print(f'局所最小 c=577.7 の loss=639371.2 と比較: 改善 {639371.2 - res.fun:.1f}') |
📤 実行結果:
💬 結果の読み方: 初期値 $c_0=1000$ (大都市側) からスタートしても SA は大域最適 $c^*=139.0$ に到達した。 普通の勾配降下 (Nelder-Mead) が $c^*=577.7$ で止まったのと比べ、 432235 のロス改善。 確率的脱出機構があれば局所最適問題はかなりの程度解消できる ── ただし収束時間と引き換え。
🎯 このコードでやること: SSDSE 47 県データを使った線形回帰の損失関数を、 2 つのパラメータ ($w_0, w_1$) 平面で可視化する。 線形モデルは凸なので「お椀型」、 一方ヒンジロスや絶対値ロスにすると地形が変わる ── 局所最適の温床はモデルではなくロス関数にも依存することを示す。
📥 入力データ: SSDSE-B-2026 から「総人口 (A1101)」 vs 「出生数 (A4101)」の関係。 N=47。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import numpy as np import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) last = df[df['SSDSE-B-2026'] == 2023] X = last['A1101'].values / 1e4 # 万人 y = last['A4101'].values / 1e3 # 千人 W0, W1 = np.meshgrid(np.linspace(-20, 20, 200), np.linspace(-0.02, 0.12, 200)) L = np.zeros_like(W0) for i in range(200): for j in range(200): resid = y - (W0[i,j] + W1[i,j]*X) L[i,j] = (resid**2).sum() # MSE (凸) i_opt, j_opt = np.unravel_index(L.argmin(), L.shape) print(f'最小 loss={L.min():.2f} at w0={W0[i_opt,j_opt]:+.2f} w1={W1[i_opt,j_opt]:+.4f}') # 閉形式解 (正規方程式) と比較 w1_exact = np.cov(X, y, bias=True)[0,1] / X.var() w0_exact = y.mean() - w1_exact * X.mean() print(f'閉形式: w0={w0_exact:+.2f} w1={w1_exact:+.4f} (凸なので一意)') |
📤 実行結果:
💬 結果の読み方: グリッド探索結果と閉形式解 (正規方程式) がほぼ一致。 線形回帰 (MSE ロス) は凸なので局所最適 = 大域最適。 初期値に依らない安心仕様。 同じデータでも、 MSE をヒンジロスや絶対値ロスに変えると非凸地形が出現し、 局所最適問題が再発する ── アルゴリズム選択以前にロス選択が重要。
この用語を使うときに陥りがちな失敗パターン。 経験者ほどここに 1 度はハマっています。
「ロスが下がらなくなった」と感じたら、 以下の順で試す。 上ほど低コスト・即効性あり。
| # | 戦略 | 手法 | コスト | 効果 |
|---|---|---|---|---|
| 1 | 学習率を変える | Adam→SGD+momentum、 lr ×0.1 or ×10、 warmup 入れる | 小 | プラトー脱出、 鞍点脱出 |
| 2 | multi-start | 異なるシードで 3-5 回学習し、 最良を採用 | 中 (時間 N 倍) | 局所最適回避、 信頼区間取得 |
| 3 | SGD のノイズ活用 | バッチ全データ → mini-batch (32-256)、 ノイズが脱出機構に | 小 | 浅い局所最適を素通り |
| 4 | 大域探索 | basinhopping / dual_annealing / 遺伝的アルゴリズム / CMA-ES | 大 (時間 100 倍) | 小規模問題の決定打 |
| 5 | 問題を凸に書き直す | ロスを MSE / L2 / ヒンジに変更、 線形モデルに簡略化 | 設計時のみ | 問題自体の解消 (究極解) |
📌 戦略 5 は「問題が凸に書き直せるなら、 そもそも局所最適問題は存在しない」 ── 表現力と最適化容易性のトレードオフ。 NN を選んだ時点で非凸を受け入れている。
1990 年代「NN は局所最適の海で動かない」と言われていたが、 2014 年以降の理論研究で大幅に楽観論に修正された。 ここがニュース。
| 論点 | 1990s ビュー | 2010s 以降ビュー |
|---|---|---|
| 停留点の多くは? | 局所最小 | 鞍点 (高次元では指数的に増える) |
| 大域最適到達 | ほぼ不可能 | 過パラメータ化なら多くの局所最小が大域に近い |
| SGD の役割 | 勾配を計算する手段 | 暗黙の正則化 + 局所最適脱出機構 |
| 平坦 vs 尖り | 区別なし | 平坦な極小ほど汎化する (Keskar 2017) |
| ResNet 以降 | 深い NN は学習不能 | 残差接続で損失曲面が「平坦化」 (Li et al., 2018) |
ランダム行列理論から、 $n$ 次元ガウス的損失関数の停留点では、 ヘッセ行列の固有値の半分が正・半分が負になる確率が高い。 $n$ が大きいほど「すべて正」=局所最小である確率は急激に低下する ── おおよそ $O(\exp(-n))$ で減衰。 結果: 高次元では停留点はほとんど鞍点。
NN のパラメータ数 $P$ が訓練データ数 $N$ より大きい (=過パラメータ化、 over-parameterized) と、 訓練ロスを 0 にできる解が連続的に存在する ── 大域最適が「点」でなく「多様体」になる。 Allen-Zhu et al. (2019) は、 十分過パラメータな NN では SGD が大域最適多様体に到達することを示した。 GPT-4 が 1.7T パラメータで MNIST のような小データを完全暗記できるのは、 この理論で説明される。
「平坦な極小は汎化する」を直接最適化に組み込んだ手法。 $w$ の周りで最悪のロスを最小化する double-min-max を解く: $\min_w \max_{\|\epsilon\| \le \rho} L(w + \epsilon)$。 結果として「周辺どこに動いてもロスが低い=平坦な谷」に収束する。 ViT・ResNet で 1-3% の精度改善が実測されている (Foret et al., 2021)。
「最適化が難しい」とひとことに言っても、 関数地形のどの構造に苦しんでいるかで対処法は変わる。 まず分類を頭に入れておくと、 失敗時の診断が速い。
| 構造 | 勾配の特徴 | ヘッセ行列の固有値 | 対処 |
|---|---|---|---|
| 大域最小 | $\nabla f = 0$ | すべて正 | ここに到達できれば成功 |
| 局所最小 | $\nabla f = 0$ | すべて正 | 多点初期化・再起動 |
| 鞍点 | $\nabla f = 0$ | 正と負が混在 | 摂動・モメンタムで脱出 |
| プラトー | $\nabla f \approx 0$ | すべてほぼ 0 | 学習率上げ・正規化 |
| 細長い谷 | 方向依存に大きさ激変 | 条件数大 (>$10^4$) | Adam・前処理・正規化 |
| 谷の中の崖 | 局所的に勾配爆発 | 大きな正の固有値 | gradient clipping |
📌 「学習率を下げたら直った」=細長い谷だった、 「初期値を変えたら直った」=局所最小だった、 「BatchNorm を入れたら直った」=プラトーだった ── 失敗パターンから地形構造を逆算するのが上達への近道。
深層学習の文脈では、 局所最適よりも鞍点 (saddle point) の方がはるかに多く、 学習を遅延させる主因とされている (Dauphin et al. 2014)。 鞍点とは「ある方向には極小だが、 別の方向には極大」な点のことで、 勾配が 0 になるため勾配降下法は一時的に止まってしまう。 1 次元では鞍点は変曲点に過ぎないが、 高次元では指数関数的に増える。
臨界点 (勾配 $\nabla f = 0$ となる点) は、 ヘッシアン行列 $H = \nabla^2 f$ の固有値の符号で分類される:
| 分類 | ヘッシアンの固有値 | 幾何学的意味 | 最適化への影響 |
|---|---|---|---|
| 極小点 (local minimum) | 全て正 (正定値) | あらゆる方向に上がる谷底 | 通常 GD は停止 → 脱出戦略が必要 |
| 極大点 (local maximum) | 全て負 (負定値) | あらゆる方向に下がる山頂 | GD では到達しない (不安定平衡) |
| 鞍点 (saddle point) | 正と負が混在 | ある方向では谷、 別方向では山 | 勾配 0 で一時停滞、 ノイズで脱出可 |
| 退化臨界点 (degenerate) | 0 を含む | 平坦領域 (plateau) | 高次の解析が必要、 学習が遅延 |
$n$ 次元空間で臨界点を 1 つランダムに取ったとき、 ヘッシアンの固有値がすべて同符号 (= 真の極小・極大) となる確率は、 ランダム行列理論によると $n$ が大きいと指数的に小さい。 仮に各固有値の符号が独立に 50/50 であれば、 $n=10$ では全て正の確率は $2^{-10} = 0.001$、 $n=100$ では $2^{-100} \approx 10^{-30}$。 深層ニューラルネットワークは数百万から数十億のパラメータを持つため、 臨界点はほぼすべて鞍点である。
このコードでやること: ランダムな対称行列の固有値を計算し、 高次元での「全正・全負・混在」の比率をシミュレートして、 鞍点優位性を体感する。 ここではガウス分布から行列要素を引いた GOE (Gaussian Orthogonal Ensemble) を 1000 個生成する。
📥 入力例: 次元 $n$ ごとに対称行列を 1000 個生成し、 固有値の符号パターンを集計する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import numpy as np rng = np.random.default_rng(2026) results = [] for n in [2, 5, 10, 20, 50]: cnt_min = cnt_max = cnt_saddle = 0 for _ in range(1000): A = rng.standard_normal((n, n)) H = (A + A.T) / 2 # 対称化 (ヘッシアンの性質) eigs = np.linalg.eigvalsh(H) if (eigs > 0).all(): cnt_min += 1 elif (eigs < 0).all(): cnt_max += 1 else: cnt_saddle += 1 results.append((n, cnt_min, cnt_max, cnt_saddle)) print(f'{"n":>4} | {"極小":>6} | {"極大":>6} | {"鞍点":>6}') for n, mn, mx, sd in results: print(f'{n:>4} | {mn:>6} | {mx:>6} | {sd:>6}') |
📤 実行すると次の出力が得られる:
💬 $n=2$ では約 3 割が真の極小・極大だが、 $n=5$ で既に大半が鞍点となり、 $n=10$ 以上では 1000 個すべてが鞍点になる。 深層学習の損失関数の臨界点が「ほぼすべて鞍点」というのはこの組合せ論の帰結であり、 「局所最適に落ちた」と思っているケースの多くは実は「鞍点近傍で勾配が極めて小さくなり停滞している」状態である。 だからこそ momentum や Adam といった「過去の勾配を利用する」最適化手法が、 鞍点脱出に劇的な効果を発揮する。
理論を知っていても、 実務でいつ局所最適を疑うべきかの「鼻」を持つことが重要である。 以下、 SSDSE 系のオープンデータでよく出会う 4 つの典型事例を、 症状 / 原因 / 対策 / 検証の順で整理した。
| 項目 | 内容 |
|---|---|
| 症状 | 3 クラスタのうち 1 つに東京 1 県のみ、 残り 46 県が 2 クラスタに振り分けられる。 |
| 原因 | 外れ値 (東京) が初期セントロイドに選ばれた → 局所最適に固着。 |
| 対策 | 対数変換でスケールを圧縮 → 標準化 → n_init=10 以上 + init='k-means++'。 |
| 検証 | silhouette score を比較、 sklearn の KMeans の inertia_ が下がっているか確認。 |
| 項目 | 内容 |
|---|---|
| 症状 | epoch を増やしても loss が下がらない、 訓練/検証 loss がともに高位で停滞。 |
| 原因 | 学習率が大きすぎて鞍点周辺で振動、 もしくは小さすぎて plateau から抜けられない。 |
| 対策 | ReduceLROnPlateau でステップ減衰、 momentum 付き optimizer (SGD+momentum, Adam) に変更。 |
| 検証 | loss 曲線を log スケールで確認、 勾配ノルムが ε 以下なら鞍点疑い。 |
| 項目 | 内容 |
|---|---|
| 症状 | EM アルゴリズムが収束せず、 共分散行列が特異 (det → 0) になる、 もしくは尤度が振動する。 |
| 原因 | EM の対数尤度には複数の局所最適があり、 初期値次第で degenerate solution に落ちる。 |
| 対策 | sklearn の GaussianMixture(n_init=10, reg_covar=1e-6) を使い、 共分散に下限正則化を入れる。 |
| 検証 | aic_ / bic_ を複数初期値で比較、 BIC が最小のものを採用する。 |
| 項目 | 内容 |
|---|---|
| 症状 | 同じ SSDSE-B-2026 を 3 クラスタに分けたとき、 K-means と Ward 法で振り分けが半数以上食い違う。 |
| 原因 | K-means が局所最適にいる、 もしくは「3 クラスタ」という個数指定がデータの自然な構造と合わない。 |
| 対策 | エルボー法 / silhouette / Gap statistic でクラスタ数を再選定、 階層的方法でデンドログラムを観察。 |
| 検証 | Adjusted Rand Index (ARI) で 2 つの手法の合意度を測定 (0.7 以上が望ましい)。 |
局所最適解は最適化アルゴリズム共通の障壁であり、 前段の初期値設計と後段のメタヒューリスティクス (焼きなまし・GA) を組み合わせて回避する。
上流の損失曲面可視化 (主成分平面への射影等) で局所解の構造を観察し、 並列の Momentum/Adam/SGD with restart で局所解脱出戦略を比較し、 下流の損失の二階微分 (Hessian 固有値) で鞍点 vs 真の局所最小値を判別する流れで深層学習の最適化が深まる。
局所最適解 を実際の課題に当てはめるとき、 用語固有の判断軸に沿って次の 3 段階で適切な選択を行う。
このフローは最適化の「局所解 vs 大域解」判断軸。 深層学習では局所最小値は実用上問題にならないことが多く (鞍点が主問題)、 凸性が崩れる場合のみ大域探索手法が必要となる。
ここまで本ページは勾配降下法 (連続最適化) を軸に局所最適を説明してきた。 この節では角度を変え、 微分を一切使わない反復改善型アルゴリズムにも同じ罠が現れることを、 SSDSE-B-2026 の実データ (2023 年・47 都道府県) に対する K-means クラスタリングで実際に測って確かめる。 「谷の絵」を眺めるのではなく、 局所最適の散らばりを数として観察するのが狙い。
K-means は「各点を最寄り中心に割り当てる → 中心を平均で更新する」を繰り返すたびに目的関数 (クラスタ内二乗和、 inertia) が単調に減り、 有限回で必ず停止する。 停止した状態は「割り当てをどう 1 手変えても改善しない」という意味での離散版の局所最適にすぎない。 $k=4$, $n=47$ ならラベル割り当ては最大 $4^{47} \approx 2\times10^{28}$ 通りあり全探索は不可能 ── 連続な「谷」の代わりに、 組合せの「くぼみ」が無数にある地形だ。
実測してみる。 高齢化率 A1303/A1101 (最小 22.8% 東京都〜最大 39.1% 秋田県)・年少人口率 A1301/A1101・消費支出 L3221 (最小 223,423 円 愛媛県〜最大 344,092 円 埼玉県) の 3 変数を標準化し、 $k=4$・ランダム初期化 1 回だけ (n_init=1) の K-means を乱数シード 0〜499 の 500 通りで走らせた結果:
同じデータ・同じアルゴリズムでも、 初期中心が違うだけで停止先が 296 通りに散らばり、 「一番よい谷」に落ちるのは 3.6% しかない。 局所最適は例外的な事故ではなく、 反復改善アルゴリズムのデフォルトの結末である。 (数値は scikit-learn による実測。 実装・環境により微差はあり得る。)
n_init=10 (ランダム初期化、 random_state=0) の実測 inertia は 54.049 で、 500 回試行の最良 53.422 より +1.2% 高かった。 多重初期化は保険であって保証ではない。 だからレポートでは「大域最適解を得た」とは書かず、 「◯回再スタート中の最良解」と手続きを添えて報告するのが誠実な作法。k-means++ は「既に選んだ中心から遠い点ほど次の中心に選ばれやすくする」確率的初期化で、 悪いくぼみに落ちにくくする工夫。 同じ実データでの実測では、 単発 (n_init=1) 100 回のうち最良解到達は 13% (ランダム初期化は 3.6%)、 平均 inertia は 60.398 (ランダム初期化 64.366) と、 分布ごと良い方へ寄った。 理論的にも期待値で $O(\log k)$ 近似が保証されている (Arthur & Vassilvitskii, 2007)。
さらに視野を広げると、 K-means は EM アルゴリズムのハード割り当て版であり、 混合ガウスの EM も同様に局所最適にしか収束しない。 大域最適性を証明付きで得たければ分枝限定法などの厳密解法が必要になるが、 K-means の大域最適化は NP 困難であり、 現実的な規模では「賢い初期化 + 多重リスタート + 手続きの明記」で良い局所最適を掴みにいくのが実務の戦い方である。 これは本文前半の教訓 ──「凸なら局所 = 大域、 非凸なら保証を諦めて工夫で補う」── の離散最適化版に他ならない。
K-means法・クラスタリング・EMアルゴリズム・標準化・組合せ最適化・大域最小・メタヒューリスティクス・最適化。 (k-means++ と分枝限定法の専用ページは未整備のため本節内の説明を参照)