この用語『勾配法』を理解するうえで併せて押さえたい関連キーワード群です。 クリック(ホバー)で関連用語ページに飛べます。
🍰 まずはやさしく
正解へ近づくための道しるべです。
一番いい答えを効率よく見つけるために使います。
スマホのアプリが学習する仕組みに似ています。
この手法で何ができるかを短くまとめます。
勾配を使った最適化の総称
gradient method を 30 秒で把握する重要ポイント:
🍰 まずはやさしく
計算を繰り返して答えを出す仕組みです。
AIなどの学習を正しく行うために使います。
データの予測モデルを作る時に役立ちます。
このページで扱う言葉の意味を説明します。
この用語ページは「勾配法」を、 最適化・機械学習の文脈で解説しています。 勾配降下法(GD)、 確率的勾配降下法(SGD)、 Adam、 RMSProp などすべての反復最適化手法の上位概念。 SSDSE-B-2026 の出生数を MLP で予測する際に裏側で動いている学習アルゴリズムです。
🍰 まずはやさしく
山を下りて谷の底を探すような方法です。
一番低い場所を直感的に見つけるために使います。
部活の練習で少しずつ形を直す感覚に似ています。
仕組みをイメージするための例え話を読みます。
勾配法は目的関数 L(θ) の勾配 ∇L を使った 1 階反復最適化アルゴリズムの総称で、 θ ← θ − η∇L(θ) の更新式が骨格。 1847 Cauchy が最初に提案し、 ニュートン法 (2 階) と区別するため "first-order method" とも呼ぶ。 機械学習の学習過程はほぼすべて勾配法の派生 (SGD/Momentum/RMSProp/Adam/AdamW) で、 PyTorch の backward() + optimizer.step() はこの直接実装。
勾配法の収束性は L の性質に強く依存: 凸関数なら大域最小に収束 (Robbins-Monro 1951)、 非凸 (DNN) なら局所最小 or 鞍点。 学習率 η が大きすぎると発散、 小さすぎると停滞、 適切な η の自動調整が Adam (Kingma 2014) 等の動機。 SGD は GPU メモリで全データ載らない大規模問題に必須で、 サンプルノイズ自体が局所最小脱出に寄与する効果も知られる。
勾配法は『目的関数の勾配(傾き)方向に少しずつ動いて、 最小(最大)を探す』最適化手法の総称。 山登りに例えると、 一番急な下り斜面を見つけて一歩進む。 単純だが、 機械学習の学習はほぼすべてこの勾配降下の派生(SGD, Adam, RMSProp など)で行われる。 ニュートン法のように 2 階情報を使う方法と区別して、 1 階情報(勾配)のみを使う方法を指すことが多い。
勾配法の対立軸は 2 階法 (Newton, Quasi-Newton/BFGS) で、 計算コスト O(n²) vs O(n) の差から DNN では 1 階が標準。 一方ロジスティック回帰など中規模の凸問題では scipy.optimize.minimize(method='BFGS') や L-BFGS が高速で、 sklearn の LogisticRegression(solver='lbfgs') はこれを使用。 「いつ 1 階で、 いつ 2 階か」は問題サイズと凸性で判断する。
本ページでは凸関数 f(x,y) = x² + 3y² と二重井戸型の非凸関数を題材に、 学習率 η を変えながら勾配法の収束・発散をインタラクティブに体験できる実験を用意した。 さらに SSDSE-B-2026 の線形回帰(総人口 → 出生数、 標準化済み)を勾配法で解き、 解析解(標準化単回帰では相関係数 r ≈ 0.995 に一致)へ収束することを確認する。
勾配法は「曲面の最も急な下り方向に少しずつ歩いて最小値を探す」反復アルゴリズムです。 以下 3 点の概念図で「学習率の効果」「鞍点とモーメンタム」「収束軌跡の比較」を視覚的に整理します。
→ 学習率 η は勾配法の最重要ハイパーパラメータです。 小さすぎると収束に膨大な反復が必要で、 大きすぎると最小値を飛び越えて発散します。 適切な η は損失曲面の曲率(2 次微分)に依存します。 Adam のような適応学習率は、 各パラメータごとに η を自動調整することでこの問題を緩和します。
→ 高次元では局所最小よりも鞍点が圧倒的に多く、 純粋な SGD は鞍点周辺で勾配がほぼゼロになり停滞します。 Momentum は過去の勾配の指数移動平均を保持することで、 平坦領域を「慣性」で突破します。 Adam は Momentum と RMSProp(適応学習率)を組み合わせ、 現代の深層学習で最も広く使われる最適化手法となっています。
→ 細長い谷では SGD は y 方向(急峻)でジグザグ振動し、 x 方向(緩慢)の進みが遅くなります。 Momentum は y 方向の振動を相殺しつつ x 方向の慣性を蓄積。 Adam は各次元の勾配履歴(2 次モーメント)で軸ごとの実効学習率を調整するため、 ジグザグせず最短に近い経路で収束します。 実務では Adam が default、 BERT/GPT などの大規模学習では AdamW が標準です。
勾配法の挙動を直感する 3 つの図。 損失関数の形状、 OLS の解(勾配 0 の点)、 正則化との関係を順に見る。



→ 勾配法は「曲面を転がるボール」のイメージ。 凸関数なら 1 つの底に必ず到達するが、 非凸(深層学習)では局所最適やサドル点に注意が必要。
→ 全項目に即答できれば、 深層学習の optimizer 選択でも迷わなくなる。
開始点をドラッグして置き、 学習率 η をスライダーで変え、 「ステップ実行」または「▶ 再生」で勾配降下の軌跡を追ってみましょう。 赤い矢印は各反復の最急降下方向(−∇f)、 右のパネルには勾配ベクトルと損失値がリアルタイムで表示されます。 η が小さいと遅く・適切だと速く・大きいと振動や発散することを、 実際に手を動かして体感してください。
更新式 θt+1 = θt − η∇f(θt)。 勾配はすべて解析的に厳密計算しています。
勾配 ∇f は「その地点で損失が最も急に増える方向」を指します。 だから逆向き −∇f が最も急な下り坂。 目隠しで山を下る人が、 足元の傾きだけを頼りに一番急な方向へ一歩ずつ進むのと同じです。 歩幅がその η。 大きすぎれば谷を飛び越え、 小さすぎれば日が暮れます。 詳しくは 勾配降下法・学習率 のページも参照。
これらはすべて 数理最適化/最適化 の枠組みに属し、 誤差逆伝播 が計算した勾配を ニューラルネットワーク の学習に流し込む土台になります。
🍰 まずはやさしく
傾きを使って値を更新する計算ルールです。
数式を使って正確に答えを出すために使います。
買い物で予算に合わせて品を選ぶ感覚に似ています。
詳しい定義と数式の意味について解説します。
目的関数 $f(\theta)$ の勾配 $\nabla f$ を使ってパラメータ $\theta$ を逐次更新し、 最小(または最大)を探す反復最適化の総称: $\theta_{t+1} = \theta_t - \eta \, \nabla f(\theta_t)$。
英語名 Gradient Method。 同義・関連語:勾配降下法。
勾配法の一般形。 $\alpha_k$ はステップサイズ(学習率)、 $\nabla f$ は勾配。
数式の各記号が『何の量で、 どの空間に住み、 どんな単位を持つか』を意識すると、 暗記でなく構造として理解できます。 SSDSE-B の都道府県データに当てはめて、 各シンボルが何に対応するかを上の Python 実装で確認しましょう。
まずは本ページの『💡 30 秒で分かる結論』と『🎨 直感で掴む』で全体像を掴み、 次に『🧮 実値で計算してみる』を 手を動かして追体験するのが最短です。 数式や深い理論はその後で十分。
本ページの『🌐 関連手法・派生』『🔗 拡張関連用語』で対比される手法を確認し、 それぞれの適用条件と得意・不得意を表で比較するのが効果的です。 SSDSE-B のような共通データセットで両方走らせて結果を見ると違いが体感できます。
勾配法の計算量は「1 反復のコスト × 反復回数」で決まります。 1 次法(勾配のみ)の 1 反復は $O(nd)$、 2 次法(ニュートン法)はヘッセ行列 $d \times d$ の構築に $O(nd^2)$、 その逆行列に $O(d^3)$ がかかります。 SSDSE の $d=5$ なら $d^3=125$ で無視できるので 2 次法が有利ですが、 $d=1000$ なら $10^9$ となり 1 反復すら回りません。 $d$ が小さければ 2 次法、 大きければ 1 次法——これが手法選択の第一の分かれ目です。 中間の準ニュートン法(L-BFGS)は直近 $m$ 反復ぶんの履歴だけ持って $O(md)$ に抑える折衷案で、 $m=10$ 程度が標準です。
『点推定値』だけでなく『不確実性(CI、 SE、 分散)』『前提条件のチェック結果』『代替手法との比較』『データ取得日と seed』をセットで報告するのが標準。 査読・レビューで問われる典型ポイントです。
$$ \theta_{t+1} = \theta_t - \eta_t \, \nabla f(\theta_t) $$
| 記号 | 意味 | SSDSE-B-2026 文脈の具体例 |
|---|---|---|
$\theta_t$ | $t$ ステップ時点のパラメータ | MLP の重み行列 $W^{(1)}, W^{(2)}$ など |
$f(\theta)$ | 目的関数(損失) | MSE: $\frac{1}{47}\sum (\text{A4101}_i - \hat{y}_i)^2$(A4101 = 出生数) |
$\nabla f$ | 勾配ベクトル | $\partial f / \partial \theta$、 PyTorch の loss.backward() で自動計算 |
$\eta_t$ | 学習率(ステップサイズ) | 0.01 〜 0.0001、 Adam はステップごとに動的調整 |
学習率 $\eta$ が大きすぎれば発散、 小さすぎれば収束遅延。 SSDSE-B-2026 のように列ごとに桁が違うデータでは標準化が前提。
この用語を理解・使用するときは、 次のような前提を意識してください:
都道府県データの『最適化問題』、 例えば『47 県の人口×経済指標を使い、 重み付けされた幸福度関数を最大化する重みを求める』際、 勾配法で w を反復更新する。 出生数(A4101)と死亡数(A4200)等を組合せ、 合計指標を最大化する重みベクトルを勾配法で求める。
| 項目 | 条件 / 入力 | 結果 / 解釈 |
|---|---|---|
| 最急降下 | x ← x - α ∇f | 1 階情報のみ |
| Momentum | v ← β v - α ∇f | 慣性で加速 |
| AdaGrad | 学習率を要素ごと調整 | 疎勾配に強い |
| RMSProp | 二乗平均で正規化 | 非定常 OK |
| Adam | Momentum + RMSProp | 事実上の標準 |
| ニュートン法 | Hessian の逆行列 | 2 階、 高コスト |
※ 数値は SSDSE-B-2026.csv から抽出した実値、 もしくは典型的な学習設定での目安値です。 細部の数値は前処理・乱数 seed・実装により変動します。
f(x,y) = x²+2y² の勾配降下 1 ステップを計算する。
1 2 3 4 5 6 7 8 | import numpy as np def f(x, y): return x**2 + 2*y**2 x, y = 3.0, 2.0 lr = 0.1 x1 = x - lr * (2*x) y1 = y - lr * (4*y) print(f"(x₁, y₁) = ({x1}, {y1})") print(f"f → {f(x1,y1):.3f}") |
💬 手計算 (Step 2) と Python 出力が完全一致。
SSDSE-B-2026 のような公的統計データを Python で扱う際の基本パターン:
1 2 3 4 5 6 7 8 9 10 11 12 | import pandas as pd import numpy as np # データ読み込み df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) print(df.shape) print(df.dtypes) print(df.describe()) # 「勾配法」の文脈で扱う場合の例: # 分野: 深層学習 # 関連手法は同カテゴリの他用語を参照してください。 |
具体的なコードは ニューラルネットワーク基礎 を参照してください。
分析結果を報告するときに含めるべき情報:
公的データ SSDSE-B(47 都道府県社会・人口統計)を読み込み、 勾配法 を実際に動かす最小コードです。 引数のパスは平易さ優先で直書きしています。
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 df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) X = df[['A1101']].astype(float).values # 総人口 y = df['A4101'].astype(float).values # 出生数 # 線形回帰 y = w*x + b を勾配法で求める X = (X - X.mean()) / X.std() y = (y - y.mean()) / y.std() w, b = 0.0, 0.0 lr = 0.01 for ep in range(200): pred = w * X.flatten() + b err = pred - y grad_w = (2 * err * X.flatten()).mean() grad_b = (2 * err).mean() w -= lr * grad_w b -= lr * grad_b if ep % 50 == 0: loss = (err ** 2).mean() print(f'ep {ep}: loss={loss:.4f}, w={w:.3f}, b={b:.3f}') |
※ 上記スニペットは Python 3.10+ / pandas 2.x / numpy / scikit-learn を想定。 環境構築は『conda create -n ds python=3.11 pandas scikit-learn matplotlib』で十分です。
『勾配法』は『最適化』カテゴリに属する重要概念で、 以下の関連概念群と密接につながっています。
最適化
├── 前提
│ └── 数学・統計の基礎
├── 勾配法 ← このページ
│ ├── 派生 1
│ ├── 派生 2
│ └── 応用
└── 並列・対比される手法
├── 別アプローチ A
└── 別アプローチ B
完全な概念マップは 🗺 概念マップ で確認できます。
1847 年 Cauchy が最急降下法を提唱。 1951 年 Robbins-Monro の確率近似で確率的版が登場。 ニューラルネットの誤差逆伝播 (Rumelhart 1986) で大規模適用が可能に。 2010 年代に Adam (2014), AdamW (2017), Sophia (2023) と発展。
「勾配法」という総称の裏には、 目的の違う 3 系統があります。 Cauchy (1847) の最急降下は決定論的な最適化、 Robbins–Monro (1951) はノイズのある観測への対処、 Rumelhart et al. (1986) の誤差逆伝播は合成関数の勾配を効率的に計算する方法——最後のものは最適化手法ですらなく微分の計算法です。 原典に当たると、 「勾配法」と一括りにされる中身がどれだけ異質かが見えます。
『勾配法』は理論だけでなく、 産業・研究の様々な現場で実用されています。 ここでは代表的な応用を 6 つ挙げます。
どの応用も「何を入力とし、 何を出力すべきか」を整理した上で、 上の Python 実装をベースに拡張するアプローチが定石です。 SSDSE-B のような公開データセットで小さく試し、 動作確認できてから本番データに展開すると安全です。
『勾配法』には多くの派生・バリエーションがあります。 代表的なものを精度・特徴で比較した表です。
| 手法 / バージョン | 指標 / 特徴 | 備考 |
|---|---|---|
| SGD | シンプル | lr 調整必要 |
| Momentum | 慣性追加 | 鞍点脱出 |
| AdaGrad | 学習率自動 | 疎勾配 OK |
| RMSProp | 非定常 OK | Adam の片割れ |
| Adam | 標準 | 汎用 |
数値は論文公表時点のもので、 計測条件(データ・前処理・ハイパーパラメータ)が異なります。 自分の問題で再評価することを推奨。
『勾配法』は周辺の似た用語と混同されがちです。 ここでは特に紛らわしい用語との本質的な違いを整理します。
data/raw/SSDSE-B-2026.csv。 47 都道府県の社会・人口指標| 手法 | 更新式 | 特徴 |
|---|---|---|
| SGD | θ ← θ - η ∇L | シンプル、 lr 調整必要 |
| Momentum | v ← βv + ∇L; θ ← θ - ηv | 慣性で鞍点脱出 |
| Nesterov | 先読み勾配 | 理論収束↑ |
| AdaGrad | 学習率を要素ごとに調整 | 疎勾配 OK、 lr 自動減衰 |
| RMSProp | 二乗勾配の指数移動平均 | 非定常 OK |
| Adam | Momentum + RMSProp | 事実上の標準 |
| AdamW | 重み減衰を切り離す | Transformer 標準 |
| LION (2023) | sign(運動量) | 省メモリ |
凸関数なら最急降下法は O(1/k) の速度で大域最適に収束(k は反復回数)。 強凸関数なら線形収束 O(ρ^k)(ρ<1)。 非凸では局所最適保証のみ。 SGD はミニバッチノイズにより鞍点を脱出しやすく、 大規模深層学習では実用上 batch GD より良いことが多い。
AdaGrad/RMSProp/Adam は各パラメータ毎に学習率を自動調整する。 これにより、 sparse な勾配(NLP の埋め込み層など)でも安定学習が可能。 Adam は深層学習のデフォルトであり、 99% のケースで「とりあえず Adam で lr=1e-3」が動く。
本セクションは『勾配法』の技術的核心を深掘りしました。 表面的な使い方を超えて、 内部の仕組みを理解することで、 トラブル時の診断や応用時のカスタマイズが可能になります。 SSDSE-B のような実データに当てはめながら、 ぜひ手を動かして確認してください。
単純な勾配法 (SGD) は鞍点や谷で振動しやすい。 これを解決するのが Momentum (慣性) と Adam (Adaptive Moment Estimation)。 両者とも「過去の勾配情報」を活用するが、 設計思想が異なる。 SGD = 「現在のみ」、 Momentum = 「速度を保つ物体」、 Adam = 「速度 + 適応的学習率」。 SSDSE-B-2026 の重回帰収束で 3 者の挙動差を体感しよう。
$$m_t = \beta_1 m_{t-1} + (1-\beta_1) g_t \quad\text{(1次モーメント=勾配の指数移動平均)}$$
$$v_t = \beta_2 v_{t-1} + (1-\beta_2) g_t^2 \quad\text{(2次モーメント=勾配二乗の指数移動平均)}$$
$$\hat{m}_t = \frac{m_t}{1-\beta_1^t}, \quad \hat{v}_t = \frac{v_t}{1-\beta_2^t}, \quad \theta_{t+1} = \theta_t - \frac{\eta \hat{m}_t}{\sqrt{\hat{v}_t}+\epsilon}$$
このコードでやること: SSDSE-B-2026 の都道府県データ (総人口 A1101 → 出生数 A4101) を用い、 SGD / Momentum / Adam の 3 optimizer で同じ線形回帰を解き、 収束速度を比較する。
📥 入力データ (47 都道府県, 標準化済み):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import torch, pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) # 標準化: x=総人口(A1101), y=出生数(A4101) X = torch.tensor(((d['A1101']-d['A1101'].mean())/d['A1101'].std()).values, dtype=torch.float32) y = torch.tensor(((d['A4101']-d['A4101'].mean())/d['A4101'].std()).values, dtype=torch.float32) for name, opt_cls, kwargs in [('SGD', torch.optim.SGD, {'lr':0.01}), ('Momentum', torch.optim.SGD, {'lr':0.01, 'momentum':0.9}), ('Adam', torch.optim.Adam, {'lr':0.01})]: w = torch.zeros(1, requires_grad=True) opt = opt_cls([w], **kwargs) for i in range(200): loss = ((w*X - y)**2).mean() opt.zero_grad(); loss.backward(); opt.step() print(f"{name:10s} 200steps: w={w.item():.4f}, loss={loss.item():.6f}") |
📤 実行結果 (典型例):
💬 Momentum は 200 step で真値 $w$≈0.995 にほぼ収束、 SGD は 0.976 と未収束。 Adam は学習率の自動調整で着実に収束する (この例では 0.980)。 一方 Adam は 汎化性能が SGD より劣る 場合があり (Wilson et al., 2017)、 大規模学習では SGD+Momentum が選ばれることも多い。 「Adam が常に最強」は誤解。
PyTorch の torch.optim.Adam の weight_decay は L2 正則化を勾配に加算する実装で、 適応学習率と相互作用して 意図したペナルティと異なる挙動 を示す。 Loshchilov & Hutter (2019) はこれを修正した AdamW を提案し、 現在 Transformer 系の標準。 ViT / BERT / GPT は すべて AdamW で学習されている。
📌 Round 187 補講のポイント: 勾配法は「単純な式」だが、 1 次/2 次モーメント、 バイアス補正、 適応学習率、 weight decay の組合せで複雑化する。 数式を言葉で読み解けば、 ハイパーパラメータ調整の勘所が見える。
「勾配法」は単独で完結する手法ではなく、 隣接領域と連携することで真価を発揮する。
上流の微分可能性・凸性で問題構造を分析し、 並列のニュートン法・座標降下法・共役勾配法と収束特性を比較し、 下流の SGD・ミニバッチ法で実装する。 勾配法は最適化アルゴリズムの基礎として、 用途に応じた変種選択 (バニラ・モメンタム・適応学習率) の判断軸を提供する。
「勾配法」を実際の課題に当てはめるとき、 状況別に何を選ぶかを 3 段階で判定する。
勾配法は最適化アルゴリズムの基礎で、 機械学習・統計推定・制御工学のあらゆる場面に現れる。 二階情報の活用度 (一次 → 準ニュートン → ニュートン) で計算コストと収束速度のトレードオフを設計する。
勾配法は機械学習・最適化の中心技法で、 損失関数の 谷を下る ことで最適パラメータを見つけます。 ここでは GD / SGD / Momentum / Adam の理論と実装を SSDSE-B-2026 を使って深掘りします。
勾配降下法の基本更新式:
$$ \theta_{t+1} = \theta_t - \eta \cdot \nabla L(\theta_t) $$
確率的勾配降下法(SGD、 1 サンプルずつ):
$$ \theta_{t+1} = \theta_t - \eta \cdot \nabla L_i(\theta_t), \quad i \sim \mathrm{Uniform}(1, n) $$
ミニバッチ SGD(B 件のミニバッチ):
$$ \theta_{t+1} = \theta_t - \eta \cdot \frac{1}{B} \sum_{i \in \mathcal{B}} \nabla L_i(\theta_t) $$
Momentum 法:
$$ v_{t+1} = \beta v_t + \nabla L(\theta_t), \quad \theta_{t+1} = \theta_t - \eta v_{t+1} $$
Adam(Adaptive Moment Estimation):
$$ m_t = \beta_1 m_{t-1} + (1-\beta_1) \nabla L_t, \quad v_t = \beta_2 v_{t-1} + (1-\beta_2) (\nabla L_t)^2 $$
$$ \hat{m}_t = m_t / (1-\beta_1^t), \quad \hat{v}_t = v_t / (1-\beta_2^t) $$
$$ \theta_{t+1} = \theta_t - \eta \cdot \hat{m}_t / (\sqrt{\hat{v}_t} + \epsilon) $$
| 記号 | 意味 | 典型値 |
|---|---|---|
| $\theta$ | 学習対象パラメータ | 線形回帰の係数、 NN の重み |
| $\eta$ | 学習率(step size) | 0.001 - 0.1 |
| $\nabla L(\theta)$ | 損失関数の勾配ベクトル | 自動微分で計算 |
| $B$ | ミニバッチサイズ | 32, 64, 128, 256 |
| $v_t$(Momentum) | 勾配の移動平均 | 慣性として機能 |
| $\beta$ | Momentum 係数 | 0.9(標準) |
| $m_t, v_t$(Adam) | 1 次・2 次モーメント推定 | 勾配の平均・分散 |
| $\beta_1, \beta_2$(Adam) | 1 次・2 次モーメント減衰率 | 0.9, 0.999(標準) |
| $\epsilon$ | 数値安定化定数 | 1e-8 |
線形回帰 $\hat{y} = w_0 + w_1 x$ の損失(MSE)と勾配は次のように計算されます。
$$ L(w_0, w_1) = \frac{1}{n} \sum_{i=1}^n (y_i - w_0 - w_1 x_i)^2 $$
$$ \frac{\partial L}{\partial w_0} = -\frac{2}{n} \sum_i (y_i - w_0 - w_1 x_i) $$
$$ \frac{\partial L}{\partial w_1} = -\frac{2}{n} \sum_i x_i (y_i - w_0 - w_1 x_i) $$
SSDSE-B-2026 (2023) で「人口 → 出生数」の線形回帰を行うと、 解析解は w_0 ≈ -677、 w_1 ≈ 0.00610(人口 1 万人増で出生数が約 61 件増える)。 これを GD で逐次的に推定するのが本ブロックの主題。
🎯 このコードでやること:SSDSE-B-2026 の「人口 → 出生数」線形回帰を自前 GD で学習し、 sklearn の解析解と一致するか確認する。
📥 入力データ:SSDSE-B-2026.csv (2023)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) x = d['A1101'].values / 1e6 # 総人口(百万人単位) y = d['A4101'].values / 1e3 # 出生数(千人単位) n = len(x) # 自前 GD w0, w1 = 0.0, 0.0 # 初期値 eta = 0.05 losses = [] for t in range(2000): pred = w0 + w1 * x err = y - pred grad_w0 = -2/n * err.sum() grad_w1 = -2/n * (x * err).sum() w0 -= eta * grad_w0 w1 -= eta * grad_w1 losses.append((err**2).mean()) print(f'自前 GD (2000 iter, eta=0.05):') print(f' w0 = {w0:.4f}, w1 = {w1:.4f}') print(f' 最終 MSE = {losses[-1]:.4f}') # sklearn 解析解 from sklearn.linear_model import LinearRegression lr = LinearRegression().fit(x.reshape(-1, 1), y) print(f'\nsklearn 解析解:') print(f' w0 = {lr.intercept_:.4f}, w1 = {lr.coef_[0]:.4f}') print(f' 最終 MSE = {((lr.predict(x.reshape(-1,1)) - y)**2).mean():.4f}') print(f'\n→ 一致 / 損失収束軌跡:') for t in [0, 10, 50, 100, 500, 1000, 1999]: print(f' iter {t:>4}: MSE = {losses[t]:.4f}') |
📤 実行結果:
💬 結果の読み方:自前 GD で sklearn と完全一致。 初期 MSE 527 → 最終 2.63 と収束。 50 反復で実用上収束、 500 で完全収束。 これが勾配法の威力。 線形回帰は解析解があるので GD は不要だが、 NN や深層学習では 解析解が存在しない ため GD が必須。
🎯 このコードでやること:学習率を 0.001, 0.01, 0.1, 0.5, 1.0 と変えたとき、 GD の収束挙動がどう変わるかを観察する。
📥 入力データ:コード 1 の x, y
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) x = d['A1101'].values / 1e6 y = d['A4101'].values / 1e3 n = len(x) def gd(eta, n_iter=500): w0, w1 = 0.0, 0.0 losses = [] for t in range(n_iter): pred = w0 + w1 * x err = y - pred w0 -= eta * (-2/n * err.sum()) w1 -= eta * (-2/n * (x * err).sum()) loss = (err**2).mean() losses.append(loss) if loss > 1e10: # 発散 break return losses, (w0, w1) print(f'{"学習率":<10}{"50 iter":<14}{"500 iter":<14}{"収束判定":<20}') for eta in [0.001, 0.01, 0.05, 0.1, 0.5, 1.0]: losses, (w0, w1) = gd(eta) l50 = losses[49] if len(losses) > 49 else 'N/A' l500 = losses[-1] if len(losses) >= 500 else 'N/A' if len(losses) < 500: status = '発散!' elif losses[-1] < 2.7: status = '正常収束' elif losses[-1] < 100: status = '緩やか収束' else: status = '未収束' l50_s = f'{l50:.2f}' if isinstance(l50, (int, float)) else str(l50) l500_s = f'{l500:.2f}' if isinstance(l500, (int, float)) else str(l500) print(f'{eta:<10}{l50_s:<14}{l500_s:<14}{status:<20}') |
📤 実行結果:
💬 結果の読み方:学習率 0.001 は遅すぎ、 0.1 以上は発散。 0.01-0.05 のレンジが適切(x 未標準化のため発散境界が低い)。 0.05 で最速収束。 「ちょうど良い学習率」 はデータの規模感に依存し、 標準化前提なら 0.01-0.1 が定番。 大き過ぎると「最小値を飛び越えて発散」、 小さ過ぎると「無限に時間がかかる」。
🎯 このコードでやること:同じデータで バッチ GD、 SGD(1 件ずつ)、 ミニバッチ SGD(10 件)を実装し、 損失の収束軌跡を比較。
📥 入力データ:コード 1 の x, y
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) x = d['A1101'].values / 1e6 y = d['A4101'].values / 1e3 n = len(x) def loss_fn(w0, w1): return ((y - w0 - w1 * x)**2).mean() rng = np.random.default_rng(0) # (1) バッチ GD w0, w1, eta = 0.0, 0.0, 0.05 batch_losses = [] for _ in range(50): pred = w0 + w1 * x err = y - pred w0 -= eta * (-2/n * err.sum()) w1 -= eta * (-2/n * (x * err).sum()) batch_losses.append(loss_fn(w0, w1)) # (2) SGD (1 件ずつ) w0, w1 = 0.0, 0.0 sgd_losses = [] for ep in range(50): idx = rng.permutation(n) for i in idx: err = y[i] - w0 - w1 * x[i] w0 -= 0.005 * (-2 * err) w1 -= 0.005 * (-2 * x[i] * err) sgd_losses.append(loss_fn(w0, w1)) # (3) ミニバッチ SGD (10 件) w0, w1, B = 0.0, 0.0, 10 mb_losses = [] for ep in range(50): idx = rng.permutation(n) for s in range(0, n, B): b_idx = idx[s:s+B] xb, yb = x[b_idx], y[b_idx] err = yb - w0 - w1 * xb w0 -= 0.005 * (-2/len(xb) * err.sum()) w1 -= 0.005 * (-2/len(xb) * (xb * err).sum()) mb_losses.append(loss_fn(w0, w1)) print(f'{"epoch":<8}{"バッチ GD":<14}{"SGD":<12}{"ミニバッチ":<14}') for ep in [0, 5, 10, 20, 30, 49]: print(f'{ep:<8}{batch_losses[ep]:<14.3f}{sgd_losses[ep]:<12.3f}{mb_losses[ep]:<14.3f}') |
📤 実行結果:
💬 結果の読み方:SGD は 1 エポックで 47 回更新されるため序盤(epoch 0-5)の低下が速い。 ただし収束後も損失が振動する(epoch 30 で 3.33 に上振れ)— 1 サンプル勾配の分散のため。 バッチ GD は 1 エポック = 1 更新で序盤は遅いが、 最も低い 2.639 へ安定収束。 ミニバッチが両者の中間で、 大規模データでは SGD/ミニバッチが圧倒的に高速。 なお逐次更新はスケール未標準化だと発散しやすく、 学習率を 1/10 に下げている点に注意。
純粋な SGD には「鞍点で停滞」「平地で遅い」「次元ごとに感度が違う」といった欠点があります。 これを補う適応的手法が機械学習で標準化されています。
| 手法 | 更新式の核 | 特徴 | 典型値 |
|---|---|---|---|
| SGD | $\theta \leftarrow \theta - \eta \nabla L$ | シンプル、 学習率調整が難しい | η = 0.01 |
| Momentum | $v \leftarrow \beta v + \nabla L$ | 慣性で平地を加速、 鞍点を脱出 | η = 0.01, β = 0.9 |
| Nesterov | $v \leftarrow \beta v + \nabla L(\theta - \beta v)$ | 先読みで Momentum を改善 | η = 0.01, β = 0.9 |
| Adagrad | $\theta \leftarrow \theta - \eta / \sqrt{G} \cdot \nabla L$ | パラメータごとに学習率調整 | η = 0.01 |
| RMSprop | $G \leftarrow \alpha G + (1-\alpha) \nabla L^2$ | Adagrad の改良(指数移動平均) | η = 0.001, α = 0.9 |
| Adam | Momentum + RMSprop | 最もよく使われる、 デフォルト | η = 0.001, β1 = 0.9, β2 = 0.999 |
| AdamW | Adam + weight decay 分離 | 正則化を正しく扱う | η = 0.001 + wd = 0.01 |
🎯 このコードでやること:純 SGD と Momentum SGD の収束軌跡を比較。 Momentum が「慣性」で加速する様子を確認する。
📥 入力データ:SSDSE-B-2026 (2023)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) x = d['A1101'].values / 1e6 y = d['A4101'].values / 1e3 n = len(x) eta = 0.005 def gd_pure(n_iter): w0, w1 = 0.0, 0.0 losses = [] for _ in range(n_iter): err = y - w0 - w1 * x w0 -= eta * (-2/n * err.sum()) w1 -= eta * (-2/n * (x * err).sum()) losses.append((err**2).mean()) return losses def gd_momentum(n_iter, beta=0.9): w0, w1 = 0.0, 0.0 v0, v1 = 0.0, 0.0 losses = [] for _ in range(n_iter): err = y - w0 - w1 * x g0 = -2/n * err.sum() g1 = -2/n * (x * err).sum() v0 = beta * v0 + g0 v1 = beta * v1 + g1 w0 -= eta * v0 w1 -= eta * v1 losses.append((err**2).mean()) return losses losses_sgd = gd_pure(200) losses_mom = gd_momentum(200) print(f'{"iter":<8}{"純 SGD":<12}{"Momentum":<12}') for t in [0, 5, 10, 20, 50, 100, 199]: print(f'{t:<8}{losses_sgd[t]:<12.3f}{losses_mom[t]:<12.3f}') print(f'\nMomentum 収束高速化: {losses_sgd[50] / losses_mom[50]:.2f}x faster at iter 50') |
📤 実行結果:
💬 結果の読み方:Momentum は「過去の勾配を慣性として加算」し実効学習率が約 1/(1-β) = 10 倍になるため、 序盤(iter 10-20)はやや振動するが後半で純 GD を追い抜き、 iter 100 で 2.64 vs 3.22、 iter 199 でほぼ最適値 2.630 に到達。 同じ方向への勾配が連続するときに加速する。 平らな谷を高速で進めるイメージ。 ニューラルネット学習で必須の改良。
🎯 このコードでやること:Adam optimizer を自前で実装し、 SGD・Momentum と比較。 Adam が最も安定して速いことを確認。
📥 入力データ:コード 4 と同じ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) x = d['A1101'].values / 1e6 y = d['A4101'].values / 1e3 n = len(x) def gd_adam(n_iter, eta=0.1, b1=0.9, b2=0.999, eps=1e-8): w = np.array([0.0, 0.0]) m = np.zeros(2) v = np.zeros(2) losses = [] for t in range(1, n_iter+1): err = y - w[0] - w[1] * x g = np.array([-2/n * err.sum(), -2/n * (x * err).sum()]) m = b1 * m + (1 - b1) * g v = b2 * v + (1 - b2) * g * g m_hat = m / (1 - b1**t) v_hat = v / (1 - b2**t) w -= eta * m_hat / (np.sqrt(v_hat) + eps) losses.append((err**2).mean()) return losses, w losses_adam, w_adam = gd_adam(200) print(f'Adam 最終: w0={w_adam[0]:.4f}, w1={w_adam[1]:.4f}') print(f'\n{"iter":<8}{"Adam loss":<14}') for t in [0, 5, 10, 20, 50, 100, 199]: print(f'{t:<8}{losses_adam[t]:<14.3f}') |
📤 実行結果:
💬 結果の読み方:Adam は 200 反復で loss 4.06 まで低下するが、 最適値 2.63(sklearn 解析解)にはまだ届かない — この小規模凸問題では素の GD(eta=0.05)の方が速い。 Adam の強みは 「学習率を手動調整しなくても、 多くのケースで動く」 こと。 NN の初期実装では Adam が事実上のデフォルト。 ただし最終的な汎化性能は SGD + Momentum の方が優れる場合あり(Wilson 2017)。
🎯 このコードでやること:PyTorch の torch.optim.SGD / torch.optim.Adam を使い、 ライブラリレベルでの実装感覚を身につける。
📥 入力データ:SSDSE-B-2026 (2023)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import pandas as pd import numpy as np import torch import torch.nn as nn torch.manual_seed(0) # 実行のたびに同じ結果が出るようにする df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) x = torch.tensor(d['A1101'].values / 1e6, dtype=torch.float32).reshape(-1, 1) y = torch.tensor(d['A4101'].values / 1e3, dtype=torch.float32).reshape(-1, 1) # 線形モデル model = nn.Linear(1, 1) criterion = nn.MSELoss() # SGD opt_sgd = torch.optim.SGD(model.parameters(), lr=0.05) for epoch in range(200): pred = model(x) loss = criterion(pred, y) opt_sgd.zero_grad() loss.backward() opt_sgd.step() print(f'PyTorch SGD: w={model.weight.item():.4f}, b={model.bias.item():.4f}, loss={loss.item():.4f}') # Adam で再学習 model2 = nn.Linear(1, 1) opt_adam = torch.optim.Adam(model2.parameters(), lr=0.1) for epoch in range(200): pred = model2(x) loss = criterion(pred, y) opt_adam.zero_grad() loss.backward() opt_adam.step() print(f'PyTorch Adam: w={model2.weight.item():.4f}, b={model2.bias.item():.4f}, loss={loss.item():.4f}') |
📤 実行結果:
💬 結果の読み方:PyTorch SGD は自前 GD・sklearn と同じ解 (w=6.10, b=-0.68) に収束。 Adam は 200 エポックでは未収束で乱数初期値により変動する。 実装の手間は自前 GD の 1/5 程度。 「自前で書ける理解 + ライブラリで効率実装」 が学習者の理想。 PyTorch の autograd(自動微分)が勾配計算を完全自動化。 大規模 NN では autograd なしでは実装不可能。
🎯 このコードでやること:学習開始時は大きな学習率で速く、 終盤は小さい学習率で安定収束する step decay の効果を観察。
📥 入力データ:コード 1 と同じ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) x = d['A1101'].values / 1e6 y = d['A4101'].values / 1e3 n = len(x) def gd_with_lr(get_eta, n_iter=200): w0, w1 = 0.0, 0.0 losses = [] for t in range(n_iter): eta = get_eta(t) err = y - w0 - w1 * x w0 -= eta * (-2/n * err.sum()) w1 -= eta * (-2/n * (x * err).sum()) losses.append((err**2).mean()) return losses # (1) 固定 0.01 l_const = gd_with_lr(lambda t: 0.01) # (2) Step decay: 0.05 → 0.005 (50 iter で減衰) l_step = gd_with_lr(lambda t: 0.05 if t < 50 else 0.005) # (3) Exponential decay: 0.05 * 0.99^t l_exp = gd_with_lr(lambda t: 0.05 * (0.99**t)) # (4) Cosine annealing l_cos = gd_with_lr(lambda t: 0.05 * (1 + np.cos(np.pi * t / 200)) / 2) print(f'{"iter":<8}{"固定":<12}{"Step":<12}{"Exp":<12}{"Cosine":<12}') for t in [0, 10, 50, 100, 150, 199]: print(f'{t:<8}{l_const[t]:<12.3f}{l_step[t]:<12.3f}{l_exp[t]:<12.3f}{l_cos[t]:<12.3f}') |
📤 実行結果:
💬 結果の読み方:Step decay と Cosine annealing が固定学習率より速く収束。 Step は「最初は大きく動き、 途中で繊細に」のヒューリスティック。 Cosine は深層学習でよく使われる滑らかなスケジュール。 大規模学習では学習率スケジューリングが性能を大きく左右する。
🎯 このコードでやること:標準化前後で同じ GD を走らせ、 収束速度の差を観察する。
📥 入力データ:SSDSE-B-2026 (2023)、 多変量回帰
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) # 多変量回帰: 総人口・出生数・合計特殊出生率 → 一般診療所数 X_raw = d[['A1101','A4101','A4103']].values.astype(float) y = d['I5102'].values.astype(float) if 'I5102' in d.columns else d['A4101'].values.astype(float) y = y / y.std() # スケール調整 # (1) 標準化なし def gd_multi(X, y, eta, n_iter=200): n, p = X.shape w = np.zeros(p) b = 0.0 losses = [] for _ in range(n_iter): pred = X @ w + b err = y - pred grad_w = -2/n * X.T @ err grad_b = -2/n * err.sum() w -= eta * grad_w b -= eta * grad_b loss = (err**2).mean() losses.append(loss) if loss > 1e10: return losses, w, b return losses, w, b losses_raw, w_raw, b_raw = gd_multi(X_raw, y, 1e-15) print(f'標準化なし (eta=1e-15):') print(f' iter 0: loss = {losses_raw[0]:.4f}') print(f' iter 199: loss = {losses_raw[-1]:.4f}') # (2) 標準化 X_std = (X_raw - X_raw.mean(axis=0)) / X_raw.std(axis=0) losses_std, w_std, b_std = gd_multi(X_std, y, 0.01) print(f'\n標準化あり (eta=0.01):') print(f' iter 0: loss = {losses_std[0]:.4f}') print(f' iter 199: loss = {losses_std[-1]:.4f}') |
📤 実行結果:
💬 結果の読み方:標準化なしでは学習率を 1e-14 程度まで小さくしないと発散する(1e-13 で発散)。 桁が巨大な列(総人口 ~10⁷)が勾配を支配するため、 学習率の許容範囲が極端に狭い。 標準化ありでは常識的な 0.01 で安定に収束し、 最終損失も 0.049 とわずかに良い。 「標準化は GD の前提条件」 と覚えておく。 sklearn の StandardScaler や PyTorch の BatchNorm が標準解。
🎯 このコードでやること:3 次関数 $f(x) = x^3 - 3x$ で鞍点・局所最小値の挙動を可視化。 GD と Momentum の差を観察。
📥 入力データ:(数式関数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import numpy as np def f(x): return x**4 - 2*x**2 + 0.3*x def grad(x): return 4*x**3 - 4*x + 0.3 # (1) 純 GD(初期値により局所最小に捕まる) def gd(x0, eta=0.05, n_iter=50): x = x0 history = [x] for _ in range(n_iter): x = x - eta * grad(x) history.append(x) return history # (2) Momentum GD def gd_mom(x0, eta=0.05, beta=0.9, n_iter=50): x, v = x0, 0.0 history = [x] for _ in range(n_iter): v = beta * v + grad(x) x = x - eta * v history.append(x) return history for x0 in [-1.5, -0.5, 0.5, 1.5]: h_gd = gd(x0) h_mom = gd_mom(x0) print(f'初期値 x0={x0}:') print(f' 純 GD 最終 x={h_gd[-1]:.4f}, f={f(h_gd[-1]):.4f}') print(f' Mom GD 最終 x={h_mom[-1]:.4f}, f={f(h_mom[-1]):.4f}') print() |
📤 実行結果:
💬 結果の読み方:初期値 x0=1.5 では純 GD は手前の局所最小 x≈0.96 (f≈−0.71) に捕まるが、 Momentum は慣性で山(局所最大 x≈0.08)を越えて全域最小 x≈−1.04 (f≈−1.31) に到達。 これが 「Momentum が局所解・鞍点を脱出する」 数学的根拠。 高次元 NN では鞍点が多数存在し、 Momentum/Adam が必須。
| 分野 | 典型 optimizer | 学習率 | 備考 |
|---|---|---|---|
| 線形回帰・小規模 | 解析解 or L-BFGS | - | GD 不要 |
| ロジスティック回帰 | L-BFGS, SAG | - | sklearn default |
| NLP (Transformer) | Adam, AdamW | 1e-4 - 5e-4 | warm-up 必須 |
| 画像分類 (CNN) | SGD + Momentum | 0.01 - 0.1 | step decay 標準 |
| 強化学習 | Adam, RMSprop | 1e-4 - 3e-4 | 不安定なため低学習率 |
| GAN | Adam (β1=0.5) | 2e-4 | D と G のバランス重要 |
| 大規模事前学習 | AdamW + warmup + cosine | 1e-4 | scaling laws に従う |
勾配法はなぜ動くのか? その数学的根拠を簡潔に説明します。
損失関数 $L$ が L-リプシッツ連続(勾配の変化が L で抑えられる)かつ 凸 なとき、 GD は $\eta \leq 1/L$ で収束保証あり。
$$ L(\theta_t) - L(\theta^*) \leq \frac{||\theta_0 - \theta^*||^2}{2 \eta t} $$
NN の損失関数は非凸(多くの局所最小値・鞍点)ですが、 経験的に SGD が「良好な解」に到達します。 これは:
🎯 このコードでやること:強凸 2 次関数 $f(x) = x^T A x / 2$ で、 GD の収束が指数的になることを SSDSE-B-2026 の共分散行列で検証。
📥 入力データ:SSDSE-B-2026 (2023) の 4 変数共分散行列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) # 4 変数の共分散行列 (PSD かつ通常 PD) X = d[['A1101','A4101','A4103','A1102']].values.astype(float) X = (X - X.mean(axis=0)) / X.std(axis=0) A = X.T @ X / len(X) # 共分散行列 eigs = np.linalg.eigvalsh(A) L = eigs.max() # Lipschitz 定数 mu = eigs.min() # 強凸性 print(f'最大固有値 L = {L:.4f}') print(f'最小固有値 μ = {mu:.4f}') print(f'条件数 κ = L/μ = {L/mu:.4f}') # 2 次関数 f(x) = x^T A x / 2 の最小化 def f(x): return 0.5 * x @ A @ x def grad(x): return A @ x x = np.array([1.0, 1.0, 1.0, 1.0]) eta = 1.0 / L # 凸最適 GD で許される最大学習率 losses = [] for t in range(100): x = x - eta * grad(x) losses.append(f(x)) print(f'\n2 次関数 GD (eta = 1/L):') print(f'{"iter":<8}{"loss":<12}') for t in [0, 5, 10, 20, 50, 99]: print(f'{t:<8}{losses[t]:<12.6f}') |
📤 実行結果:
💬 結果の読み方:強凸 2 次関数で GD は指数的に収束。 50 反復で 4 桁以上減少。 ただし条件数が大きい(約 52,000。 総人口と日本人人口がほぼ共線のため最小固有値が極小)と、 それ以降は最小固有値方向の成分がなかなか減らない。 共分散行列の固有値分布の偏り → 「楕円的な等高線」を GD はジグザグで進むため。 Momentum/Adam はこれを改善。
近年の深層学習は数億〜数兆パラメータを扱います。 単一マシンでは収まらず、 分散学習が必須となります。
| パターン | 概要 | 適用例 |
|---|---|---|
| Data parallelism | 同じモデルを複数 GPU で異なるバッチに適用、 勾配を平均 | 画像分類、 通常の学習 |
| Model parallelism | モデルを複数 GPU に分割(層ごと) | 巨大 NN、 GPT 系 |
| Pipeline parallelism | 層をパイプライン化して並列処理 | Transformer 大規模学習 |
| Tensor parallelism | 1 つのテンソルを複数 GPU に分割 | Megatron-LM |
| ZeRO (DeepSpeed) | optimizer state を分散 | 1T+ パラメータ |
🎯 このコードでやること:4 つの「ワーカー」をシミュレートし、 ミニバッチを分割して並列勾配計算・平均する流れを再現する。
📥 入力データ:SSDSE-B-2026 (2023)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) x = d['A1101'].values / 1e6 y = d['A4101'].values / 1e3 n = len(x) # ワーカーに分割(47 ÷ 4 ≈ 12 件ずつ) n_workers = 4 chunks = np.array_split(np.arange(n), n_workers) def gd_distributed(n_iter=200, eta=0.05): w0, w1 = 0.0, 0.0 losses = [] for _ in range(n_iter): # 各ワーカーが独立に勾配計算 grads_w0, grads_w1 = [], [] for ch in chunks: xb, yb = x[ch], y[ch] err = yb - w0 - w1 * xb grads_w0.append(-2/len(ch) * err.sum()) grads_w1.append(-2/len(ch) * (xb * err).sum()) # All-reduce: 勾配を平均 avg_grad_w0 = np.mean(grads_w0) avg_grad_w1 = np.mean(grads_w1) w0 -= eta * avg_grad_w0 w1 -= eta * avg_grad_w1 # 全体損失 err_all = y - w0 - w1 * x losses.append((err_all**2).mean()) return losses, (w0, w1) losses, (w0, w1) = gd_distributed() print(f'分散 GD (4 ワーカー):') print(f' w0 = {w0:.4f}, w1 = {w1:.4f}') print(f' 最終 MSE = {losses[-1]:.4f}') # 通常 GD と比較 w0, w1 = 0.0, 0.0 eta = 0.05 losses_std = [] for _ in range(200): err = y - w0 - w1 * x w0 -= eta * (-2/n * err.sum()) w1 -= eta * (-2/n * (x * err).sum()) losses_std.append((err**2).mean()) print(f'\n通常 GD:') print(f' 最終 MSE = {losses_std[-1]:.4f}') print(f'\n→ 分散と通常で同じ結果 (data parallelism は数学的に等価)') |
📤 実行結果:
💬 結果の読み方:data parallelism は「全体勾配を分割計算して平均」する方式で、 チャンクサイズが等しければ数学的に完全等価(本例は 47 件を 4 分割するため件数が不揃いで、 ごくわずかな差が残る)。 並列化で計算時間を短縮できる。 実際の分散学習では all-reduce 通信コスト・同期コストが課題。 PyTorch の DistributedDataParallel や DeepSpeed が実装を簡素化。
🎯 このコードでやること:勾配ノルムが閾値を超えたら強制的に縮小する勾配クリッピングを実装。 NN 学習で勾配爆発を防ぐ。
📥 入力データ:SSDSE-B-2026 (2023)、 意図的に高学習率
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) x = d['A1101'].values / 1e6 y = d['A4101'].values / 1e3 n = len(x) def gd_with_clipping(eta, clip_val=None, n_iter=50): w0, w1 = 0.0, 0.0 losses = [] for _ in range(n_iter): err = y - w0 - w1 * x g0 = -2/n * err.sum() g1 = -2/n * (x * err).sum() if clip_val is not None: norm = np.sqrt(g0**2 + g1**2) if norm > clip_val: g0 = g0 * clip_val / norm g1 = g1 * clip_val / norm w0 -= eta * g0 w1 -= eta * g1 loss = (err**2).mean() losses.append(loss) if loss > 1e10: return losses, (w0, w1) return losses, (w0, w1) # (1) 高 eta、 クリッピングなし l1, _ = gd_with_clipping(eta=0.8) print(f'eta=0.8 クリッピングなし: iter 0={l1[0]:.2f}, iter 49={l1[-1]:.2e}') # (2) 高 eta、 クリッピングあり (norm <= 1.0) l2, w = gd_with_clipping(eta=0.8, clip_val=1.0) print(f'eta=0.8 クリッピング 1.0: iter 0={l2[0]:.2f}, iter 49={l2[-1]:.4f}') print(f' → w0={w[0]:.4f}, w1={w[1]:.4f}') |
📤 実行結果:
💬 結果の読み方:高学習率(0.8)でクリッピングなしだと数反復で発散(8.3e10 で打ち切り)。 クリッピングを norm ≤ 1.0 にすると発散せず、 50 反復で loss 4.15 まで低下(最適 2.63 へはさらに反復が必要)。 RNN/LSTM/Transformer では勾配クリッピング必須(時系列で勾配が指数的に増幅するため)。 PyTorch では torch.nn.utils.clip_grad_norm_ で実装。
torch.optim.Adam と数値が一致することを確認。| 手法 | 採用基準 | 学習率の目安 |
|---|---|---|
| GD(バッチ) | 小データ・凸問題 | η = 1/L |
| SGD | 大データ・汎化重視 | η = 0.01-0.1 |
| Mini-batch SGD | 標準的 NN 学習 | η = 0.01-0.1 |
| Momentum | SGD の高速化 | η = 0.01, β = 0.9 |
| Nesterov | Momentum の改良 | η = 0.01, β = 0.9 |
| Adagrad | 疎データ・スパース勾配 | η = 0.01 |
| RMSprop | 非定常目的関数(RL等) | η = 0.001 |
| Adam | NN のデフォルト | η = 0.001 |
| AdamW | Adam + weight decay | η = 0.001, wd = 0.01 |
| L-BFGS | 小規模・高精度 | line search |
線形回帰は解析解があるため GD が不要ですが、 非線形なニューラルネットでは勾配法が唯一の学習手段。 ここでは SSDSE-B-2026 で MLP を学習させ、 optimizer の選択が結果に与える影響を確認します。
🎯 このコードでやること:SSDSE-B-2026 の多変量回帰を 2 層 MLP で学習。 SGD と Adam の収束性能を比較。
📥 入力データ:SSDSE-B-2026 (2023)、 5 特徴量、 ターゲット = 出生数 A4101
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | import pandas as pd import numpy as np import torch import torch.nn as nn df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) # 特徴量: 総人口・日本人人口・合計特殊出生率・15歳未満人口・65歳以上人口 features = ['A1101','A1102','A4103','A1301','A1303'] target = 'A4101' # 出生数 X = d[features].values.astype(np.float32) y = d[target].values.astype(np.float32).reshape(-1, 1) # 標準化 X_mean, X_std = X.mean(axis=0), X.std(axis=0) y_mean, y_std = y.mean(), y.std() X = (X - X_mean) / X_std y = (y - y_mean) / y_std X_t = torch.tensor(X) y_t = torch.tensor(y) class MLP(nn.Module): def __init__(self): super().__init__() self.fc1 = nn.Linear(5, 16) self.fc2 = nn.Linear(16, 8) self.fc3 = nn.Linear(8, 1) self.relu = nn.ReLU() def forward(self, x): return self.fc3(self.relu(self.fc2(self.relu(self.fc1(x))))) torch.manual_seed(0) model_sgd = MLP() opt_sgd = torch.optim.SGD(model_sgd.parameters(), lr=0.01, momentum=0.9) torch.manual_seed(0) model_adam = MLP() opt_adam = torch.optim.Adam(model_adam.parameters(), lr=0.01) criterion = nn.MSELoss() losses_sgd, losses_adam = [], [] for epoch in range(500): # SGD pred = model_sgd(X_t); loss = criterion(pred, y_t) opt_sgd.zero_grad(); loss.backward(); opt_sgd.step() losses_sgd.append(loss.item()) # Adam pred = model_adam(X_t); loss = criterion(pred, y_t) opt_adam.zero_grad(); loss.backward(); opt_adam.step() losses_adam.append(loss.item()) print(f'{"epoch":<8}{"SGD+Mom":<14}{"Adam":<14}') for ep in [0, 50, 100, 200, 300, 499]: print(f'{ep:<8}{losses_sgd[ep]:<14.5f}{losses_adam[ep]:<14.5f}') print(f'\n最終 MSE 比較:') print(f' SGD+Mom: {losses_sgd[-1]:.5f}') print(f' Adam : {losses_adam[-1]:.5f}') |
📤 実行結果:
💬 結果の読み方:Adam が SGD+Momentum より早く深く収束(500 epoch で約 3 倍低い損失。 数値は PyTorch のバージョンで微差あり)。 ただし train loss だけ見ているので過学習の可能性。 実務では必ず validation set で評価。 NN 学習では Adam が「最初に試す」のがデファクト。
🎯 このコードでやること:train/validation 分割で過学習を防ぐ Early Stopping を実装。 validation loss が改善しなくなったら学習を停止する。
📥 入力データ:コード 13 と同じ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | import pandas as pd import numpy as np import torch import torch.nn as nn df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) features = ['A1101','A1102','A4103','A1301','A1303'] X = d[features].values.astype(np.float32) y = d['A4101'].values.astype(np.float32).reshape(-1, 1) X = (X - X.mean(axis=0)) / X.std(axis=0) y = (y - y.mean()) / y.std() # train/val 分割 rng = np.random.default_rng(0) idx = rng.permutation(len(X)) train_idx, val_idx = idx[:35], idx[35:] X_tr, y_tr = torch.tensor(X[train_idx]), torch.tensor(y[train_idx]) X_va, y_va = torch.tensor(X[val_idx]), torch.tensor(y[val_idx]) class MLP(nn.Module): def __init__(self): super().__init__() self.fc1 = nn.Linear(5, 16); self.fc2 = nn.Linear(16, 8); self.fc3 = nn.Linear(8, 1) self.relu = nn.ReLU() def forward(self, x): return self.fc3(self.relu(self.fc2(self.relu(self.fc1(x))))) torch.manual_seed(0) model = MLP() opt = torch.optim.Adam(model.parameters(), lr=0.01) criterion = nn.MSELoss() best_val = float('inf') patience, counter = 20, 0 best_epoch = 0 for epoch in range(500): model.train() pred = model(X_tr); loss = criterion(pred, y_tr) opt.zero_grad(); loss.backward(); opt.step() model.eval() with torch.no_grad(): val_loss = criterion(model(X_va), y_va).item() if val_loss < best_val: best_val = val_loss; counter = 0; best_epoch = epoch else: counter += 1 if counter >= patience: break print(f'Early Stopping: epoch {epoch+1} で停止') print(f' 最良 epoch : {best_epoch}') print(f' 最良 val loss : {best_val:.5f}') print(f' 最終 val loss : {val_loss:.5f}') |
📤 実行結果:
💬 結果の読み方:epoch 27 で最良 val loss、 そこから 20 epoch 改善なしで早期停止(48 epoch。 数値は PyTorch のバージョンで微差あり)。 train loss だけ見続けると無限に下がり過学習。 Early stopping は「validation set で監視」する標準的な過学習対策。 PyTorch の場合、 ベスト時点のモデルパラメータを state_dict で保存しておくのが定番。
🎯 このコードでやること:自動微分の結果が数値微分(有限差分)と一致するか確認。 自前実装のバグ検出に必須。
📥 入力データ:単純な 2 次関数 $f(w) = w_0^2 + 3 w_1^2$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | import numpy as np import torch def f_np(w): return w[0]**2 + 3 * w[1]**2 def grad_analytic(w): return np.array([2*w[0], 6*w[1]]) # 数値微分 (有限差分) def grad_numeric(w, eps=1e-5): grad = np.zeros_like(w) for i in range(len(w)): wp = w.copy(); wp[i] += eps wm = w.copy(); wm[i] -= eps grad[i] = (f_np(wp) - f_np(wm)) / (2*eps) return grad # 自動微分 (PyTorch) def grad_autograd(w): w_t = torch.tensor(w, requires_grad=True) loss = w_t[0]**2 + 3 * w_t[1]**2 loss.backward() return w_t.grad.numpy() # 3 点で確認 print(f'{"w":<20}{"解析":<22}{"数値":<22}{"autograd":<22}') for w in [[1.0, 2.0], [3.0, -1.0], [0.5, 0.5]]: w = np.array(w) g_a = grad_analytic(w) g_n = grad_numeric(w) g_t = grad_autograd(w) print(f'{str(w):<20}{str(g_a.round(4)):<22}{str(g_n.round(4)):<22}{str(g_t.round(4)):<22}') |
📤 実行結果:
💬 結果の読み方:解析微分・数値微分・autograd の 3 つが全て一致。 自前の勾配実装が正しいかを確認する標準手法。 数値微分は 2 次精度(O(eps^2))の中央差分が定番。 eps が小さすぎると浮動小数点誤差、 大きすぎると打ち切り誤差。 1e-5 ± 1e-6 が安全圏。
勾配法は 1847 年 Cauchy にまで遡る古い技法ですが、 現代の深層学習で復権を遂げました。
| 年代 | 事項 |
|---|---|
| 1847 | Cauchy が最急降下法を発表 |
| 1944 | Levenberg-Marquardt 法(2 次的手法) |
| 1951 | Robbins-Monro が確率近似法(SGD の理論的基礎) |
| 1964 | Polyak が Heavy Ball 法(Momentum 法の原型) |
| 1983 | Nesterov が加速勾配法(Nesterov Momentum) |
| 1986 | Rumelhart らが誤差逆伝播法を NN に適用 |
| 2011 | Duchi らが Adagrad |
| 2012 | Tieleman, Hinton が RMSprop |
| 2014 | Kingma & Ba が Adam(爆発的普及) |
| 2017 | Loshchilov らが AdamW(weight decay 分離) |
| 2018 | Reddi らが Adam の収束性問題を指摘、 AMSGrad 提案 |
| 2019- | LAMB, LARS など大規模学習向け改良が続々 |
勾配法は 1 次情報(勾配)のみ使用しますが、 2 次情報(ヘッシアン)を使えば収束が高速化されます。
$$ \theta_{t+1} = \theta_t - H_t^{-1} \nabla L(\theta_t) \quad (\text{ニュートン法}) $$
| 手法 | 使う情報 | 長所 | 短所 |
|---|---|---|---|
| GD(最急降下) | 勾配のみ | 計算軽い | 収束遅い |
| Newton | 勾配 + ヘッシアン | 2 次収束 | ヘッシアン計算が重い |
| BFGS | 勾配 + ヘッシアン近似 | 準 2 次収束 | メモリ O(n²) |
| L-BFGS | 勾配 + 過去 m 個の更新 | メモリ O(nm) | 非凸では振動 |
| Trust Region | 勾配 + 局所近似 | 頑健 | 実装が複雑 |
🎯 このコードでやること:L-BFGS を使って線形回帰を解く。 GD より少ない反復で収束することを確認。
📥 入力データ:SSDSE-B-2026 (2023)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import pandas as pd import numpy as np from scipy.optimize import minimize df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) x = d['A1101'].values / 1e6 y = d['A4101'].values / 1e3 n = len(x) def loss(w): err = y - w[0] - w[1] * x return (err**2).mean() def grad(w): err = y - w[0] - w[1] * x return np.array([-2/n * err.sum(), -2/n * (x * err).sum()]) result = minimize(loss, x0=[0.0, 0.0], jac=grad, method='L-BFGS-B') print(f'L-BFGS 結果:') print(f' w0 = {result.x[0]:.4f}, w1 = {result.x[1]:.4f}') print(f' 反復回数: {result.nit}') print(f' 関数評価回数: {result.nfev}') print(f' 最終損失: {result.fun:.6f}') print(f' 収束: {result.success}') |
📤 実行結果:
💬 結果の読み方:L-BFGS は たった 5 反復で収束(GD の数百反復に対し)。 2 次情報を活用するため線形回帰のような凸問題では圧倒的に速い。 sklearn のロジスティック回帰のデフォルト solver も L-BFGS。 ただし NN では「ヘッシアン近似」が非凸で不安定なため SGD 系が主流。
| 手法 | 特徴 | 適用例 |
|---|---|---|
| Lookahead | 「fast weights」と「slow weights」の 2 系統 | NN 汎化性能向上 |
| RAdam | Adam の warmup を自動化 | NLP 学習安定化 |
| LARS | レイヤーごとの学習率調整 | 巨大バッチ ImageNet 学習 |
| LAMB | LARS + Adam | BERT 大規模事前学習 |
| SAM (Sharpness-Aware) | 損失景観の平坦性を考慮 | 汎化性能向上 |
| Shampoo | ブロック対角ヘッシアン近似 | 巨大 NN の高速学習 |
| K-FAC | Kronecker-Factored 近似 | 分散学習の高速化 |
線形回帰は解析解が存在しますが、 ロジスティック回帰は解析解がなく、 必ず勾配法(または準ニュートン法)が必要。 SSDSE-B-2026 で実装してみます。
$$ P(y=1 \mid x) = \sigma(w^T x + b), \quad \sigma(z) = \frac{1}{1 + e^{-z}} $$
$$ L(w, b) = -\frac{1}{n} \sum_i \left[ y_i \log p_i + (1-y_i) \log(1-p_i) \right] $$
$$ \frac{\partial L}{\partial w} = \frac{1}{n} X^T (p - y), \quad \frac{\partial L}{\partial b} = \frac{1}{n} \sum_i (p_i - y_i) $$
🎯 このコードでやること:SSDSE-B-2026 (2023) で「人口 100 万超」を陽性とし、 ロジスティック回帰を自前 GD で学習。 sklearn と一致するか確認。
📥 入力データ:SSDSE-B-2026 (2023)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | import pandas as pd import numpy as np from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026']==2023].reset_index(drop=True) X = d[['A1102','A4101']].values.astype(float) X = StandardScaler().fit_transform(X) y = (d['A1101'] > 1_000_000).astype(int).values.astype(float) n, p = X.shape def sigmoid(z): return 1 / (1 + np.exp(-np.clip(z, -500, 500))) # 自前 GD w = np.zeros(p) b = 0.0 eta = 0.5 for t in range(2000): z = X @ w + b pred = sigmoid(z) err = pred - y grad_w = X.T @ err / n grad_b = err.sum() / n w -= eta * grad_w b -= eta * grad_b print(f'自前 GD:') print(f' w = {w.round(4)}, b = {b:.4f}') # sklearn (L-BFGS デフォルト) sk = LogisticRegression(C=1e10, max_iter=1000).fit(X, y) # C 大 → 正則化なし print(f'\nsklearn (L-BFGS):') print(f' w = {sk.coef_[0].round(4)}, b = {sk.intercept_[0]:.4f}') # 分類精度 pred_class = (sigmoid(X @ w + b) >= 0.5).astype(int) acc = (pred_class == y).mean() print(f'\n自前 GD 分類精度: {acc:.4f}') |
📤 実行結果:
💬 結果の読み方:このデータは「人口 100 万人超」がほぼ完全に分離できるため、 正則化なしのロジスティック回帰は係数の絶対値が反復とともに際限なく大きくなる(MLE が発散)。 自前 GD(2000 回)は途中経過の係数、 sklearn(C=1e10, L-BFGS)ははるかに大きな係数まで進んだ状態で、 決定境界の向きはほぼ同じ・分類精度はどちらも 100%。 実務では C=1.0 程度の正則化で係数を安定させる。 自前実装で「勾配法の中身」を理解しつつ、 実務ではライブラリ(sklearn)を使うのが最適。
勾配法は最適化手法の一族で、 他にも遺伝的アルゴリズム、 シミュレーテッドアニーリング、 ベイズ最適化など多様な手法があります。
| 手法 | 勾配を使うか | 適用分野 | 長所 | 短所 |
|---|---|---|---|---|
| 勾配法 (GD/SGD/Adam) | 使う | 連続関数、 NN 学習 | 高速、 スケール容易 | 非凸では局所最適 |
| ニュートン/L-BFGS | 使う(2 次情報も) | 凸問題、 中規模 | 収束速い | 大規模で重い |
| 遺伝的アルゴリズム | 使わない | 離散・組合せ最適化 | 勾配不要 | 遅い、 ハイパーパラ多 |
| シミュレーテッドアニーリング | 使わない | NP 困難問題 | 大域探索可能 | 収束遅い |
| ベイズ最適化 | 使わない(GP モデル) | ハイパーパラ調整 | 少評価で良解 | 高次元で劣化 |
| 進化戦略 (CMA-ES) | 使わない | ブラックボックス最適化 | 勾配不要、 強力 | 計算コスト大 |
| 強化学習 | 使う(policy gradient 等) | 逐次意思決定 | 環境相互作用可 | サンプル効率低 |
| シーン | 推奨 | 理由 |
|---|---|---|
| 小データ + 線形回帰 | 解析解 or L-BFGS | GD 不要 |
| 小データ + ロジスティック回帰 | L-BFGS (sklearn デフォルト) | 凸問題で 2 次が速い |
| 中規模 NN (100-1000 サンプル) | Adam (lr=1e-3) | 動かしやすい |
| 大規模 CNN (ImageNet) | SGD + Momentum (lr=0.1) | 汎化性能優れる |
| NLP Transformer | AdamW + warmup + cosine | 業界標準 |
| 強化学習 | Adam (lr=3e-4) | 低学習率で安定 |
| 巨大 LLM 事前学習 | AdamW + ZeRO | メモリ効率 |
勾配法は 「機械学習の心臓部」 と呼ぶに値する基盤技術です。 本ページで紹介した手法を一通り理解した後、 さらに以下のトピックに進むことをお勧めします:
| 項目 | 達成基準 |
|---|---|
| GD 実装 | 白紙から numpy で書ける |
| Momentum 実装 | 更新式を導出し実装できる |
| Adam 実装 | m, v, バイアス補正を含めて実装 |
| 学習率設計 | scale や データ量から目安を立てられる |
| 過学習対策 | early stopping、 正則化を組み込める |
| 勾配チェック | autograd を数値微分で検証 |
| PyTorch 実装 | nn.Module で MLP を書ける |