モジュール 4 ・ 目安 90 分
学習のしくみ — 勾配降下と最適化
このモジュールで学ぶこと — なぜ「学習のしくみ」なのか
ここまでのモジュールで、ニューラルネットワークが「パラメータ を持つ関数 」であることを見てきました。ニューロンの重みやバイアス、畳み込みのカーネル、これらはすべて の一部です。では、この の「良い値」は誰が、どうやって決めるのでしょうか。人間が一つひとつ手で調整するのでしょうか。それとも、機械が自動で見つけるのでしょうか。
答えは後者です。そして、その「自動で見つける」しくみこそが、このモジュールの主題である**最適化(optimization)**です。深層学習の4要素(データ・アーキテクチャ・損失・最適化)のうち、これまでは主にアーキテクチャを扱ってきました。今回は残りの「損失」と「最適化」に踏み込みます。ここが分かると、なぜ学習に時間がかかるのか、なぜときどき学習が失敗するのか、そして次のモジュールで扱う「過学習との戦い」がなぜ必要になるのかが、地に足のついた形で理解できるようになります。
機械工学を学ぶ皆さんには、じつはこの分野はとても馴染みやすいはずです。最適化とは要するに「ある評価関数を最小にする設計変数を探す」ことで、構造最適化やパラメータ同定でやっていることと本質は同じです。谷底を探してボールを転がす、勾配を頼りに一歩ずつ降りていく——このイメージを軸に、話を進めていきましょう。
このモジュールの終わりには、実際にブラウザ上でニューラルネットワークを訓練し、学習率やオプティマイザを変えると学習がどう変わるかを自分の手で確かめます。そして最後に、授業課題2(CIFAR-100の分類精度改善)に直結するColabノートブックへとつなげます。
損失関数 — 「どれくらい間違っているか」を一つの数にする
学習を自動化する第一歩は、モデルの良し悪しを一つの数値で測れるようにすることです。この数値を与える関数を 損失関数(Loss Function) と呼びます。損失が小さいほどモデルは正解に近く、大きいほど間違っている、という約束です。
なぜ「一つの数」にすることが重要なのでしょうか。それは、最適化アルゴリズムが「この方向に動かせば損失が下がる」という判断を下すために、比較できる単一の指標が必要だからです。機械工学でいえば、部品の設計で「軽さ」も「強度」も「コスト」も同時に良くしたいけれど、最終的には重み付けして一つの目的関数にまとめないと最適化にかけられない、という事情とよく似ています。
具体的な形は課題によって変わります。連続値を当てる回帰では、予測 と正解 の差の二乗を平均した**平均二乗誤差(Mean Squared Error, MSE)**がよく使われます。
前のモジュールで登場した分類問題では、softmaxの出力とone-hotの正解のずれを測る**交差エントロピー(cross-entropy)**を使いました。どちらの場合も本質は同じで、「予測が正解からどれだけ離れているか」を全データについて集計し、平均した一つの数を返します。この を、パラメータ を動かして小さくしていく——これが「学習する」ということの正体です。
大切なのは、損失 が の関数だと見なせる、という視点です。データは固定して、パラメータだけを動かせる変数と考えると、 という「地形」が頭に浮かびます。谷が深いところほど損失が小さく、良いモデルです。私たちがやりたいのは、この地形の谷底を探すことなのです。
勾配降下法 — 谷底へボールを転がす
損失という地形の谷底を探す、と言いました。ではどうやって探すのか。パラメータの組み合わせは天文学的な数になるので、しらみつぶしは不可能です。ここで登場するのが、機械工学の皆さんにはお馴染みの**勾配(gradient)**という考え方です。
勾配(Gradient) とは、各パラメータについて「損失を増やす向き」を示すベクトル のことです。関数の傾きの多変数版だと思ってください。傾きが分かれば、その逆向きに進めば損失が最も速く下がります。坂道でボールを離すと、いちばん急な下り方向へ転がっていく——あの物理そのものです。この考えに基づいてパラメータを更新する手法が 勾配降下法(Gradient Descent) で、更新則はきわめてシンプルです。
右辺を読み解きましょう。 は損失を増やす向き、その前のマイナス符号で「損失を減らす向き」に反転しています。そして (イータ)が、その向きへどれだけの幅で一歩踏み出すかを決める係数、すなわち 学習率(Learning Rate) です。ボールが転がるたとえで言えば、 は一歩の歩幅にあたります。この一行の更新を何千回、何万回と繰り返すことで、パラメータは少しずつ谷底へと近づいていきます。
学習率は「一歩の幅」— 大きすぎても小さすぎても困る
学習率 の設定は、深層学習でもっとも神経を使うところの一つです。直感的に考えてみましょう。歩幅が小さすぎると、谷底までたどり着くのに気が遠くなるほどの歩数がかかります。学習が「遅い」状態です。逆に歩幅が大きすぎると、谷を一歩でまたいでしまい、反対側の斜面のもっと高いところに着地してしまう。それを繰り返すと、損失はどんどん大きくなり、ついには**発散(diverge)**します。学習が「壊れる」状態です。
つまり良い学習率は「速く、かつ壊れない」ちょうど良い歩幅であり、これは地形の形にも依存します。急峻な谷なら小さめに、なだらかな谷なら大きめに、というのが基本の勘どころです。この感覚は言葉で説明するより、実際に動かして体で覚えるのが一番です。
可視化で試す — 損失地形ビジュアライザ
下の損失地形ビジュアライザでは、2変数の損失関数を等高線で表示し、その上をボールが勾配降下で降りていく様子を見られます。まずは学習率のスライダーをいちばん小さくして、ボールがゆっくり慎重に谷底へ向かうのを観察してください。次に少しずつ学習率を上げていき、降下が速くなる様子を確かめます。そして思い切って大きな値にしてみてください。ボールが谷を飛び越え、外へ弾き飛ばされて発散する——冒頭で説明した「壊れる」状態が目の前で起こるはずです。
さらに、地形を「凸(きれいな一つの谷)」から「鞍点(さどうてん)」や「多峰(谷が複数)」に切り替えてみましょう。多峰の地形では、スタート位置によって落ちる谷が変わり、必ずしもいちばん深い谷( 大域最小(Global Minimum) )に着くとは限らないことが分かります。浅い谷にはまって抜け出せなくなる状態を 局所最小(Local Minimum) と呼びます。この「どの谷に落ちるかは初期値と経路しだい」という事実は、深層学習の学習が毎回微妙に違う結果になる理由の一つです。
損失地形ビジュアライザ
湾曲した溝。SGDはジグザグ、Momentum/Adamは速く進みます。
図をクリックすると開始点を変えられます。
誤差逆伝播 — 連鎖律で勾配をバケツリレーする
勾配降下には 、つまり「すべてのパラメータについての勾配」が必要でした。ここで問題になるのが、深いネットワークにはパラメータが何百万個もある、という事実です。出力の損失から、遠く離れた入力側の重みまで、一つひとつの勾配をどうやって効率よく求めればよいのでしょうか。
その答えが 誤差逆伝播法(Backpropagation) です。数学的な土台は、微積分で習った 連鎖律(chain rule)(Chain Rule) 、つまり合成関数の微分則です。ネットワークは「層を通す」という関数を何重にも合成したものなので、出力側の勾配に各層の局所的な微分を次々と掛け合わせていけば、入力側の勾配まで芋づる式に求められる——これが核心です。
イメージとしては、バケツリレーが分かりやすいでしょう。まず出力の「間違いの大きさ(誤差)」を計算します。それを最終層に渡し、その層は「自分の重みがこの誤差にどれだけ効いているか」を計算しつつ、誤差を一つ手前の層へ渡します。受け取った層も同じことをして、さらに手前へ渡す。こうして誤差の情報が出力から入力へと逆向きに流れ、途中の各層が自分の勾配を受け取っていく。だから「誤差を逆に伝播させる」= 誤差逆伝播、と呼ぶわけです。
大切なのは、この手続きが完全に機械的だという点です。人間が層ごとに微分の式を手で書き下す必要はありません。順方向にどんな計算をしたかさえ記録しておけば、その逆をたどるだけで勾配が自動的に手に入ります。この「機械的に勾配が求まる」性質があるからこそ、私たちは巨大なネットワークでも臆せず勾配降下を回せるのです。導出の詳細まで追う必要はありません。「連鎖律で勾配を層から層へバケツリレーしている」——このイメージを持っておけば十分です。
SGD・ミニバッチ・エポック — 全データを一度に使わない理由
ここまでの説明では、損失 を「全データについての平均」として計算していました。しかし、データが数万枚、数十万枚とあるとき、一回の更新のたびに全データで勾配を計算するのは、あまりに重すぎます。一歩進むのに膨大な計算が必要では、学習が進みません。
そこで実務では、データの一部だけを取り出して勾配を計算し、それで一歩進む、という方法をとります。この「一部」を ミニバッチ(mini-batch)(Mini-batch) と呼び、たとえば32枚や128枚といった単位で区切ります。ミニバッチごとに勾配を計算して更新するやり方を 確率的勾配降下法(Stochastic Gradient Descent, SGD)(Stochastic Gradient Descent) と言います。「確率的」とついているのは、毎回ランダムに選んだ一部のデータを使うため、勾配が本来の値の周りで少し揺らぐからです。
この揺らぎは、じつは悪いことばかりではありません。ボールが少しふらつきながら転がることで、浅い局所最小にはまりかけても振動で抜け出せる、という嬉しい副作用があります。全データを使う勾配降下が「まっすぐ慎重に降りる」のに対し、SGDは「小刻みに揺れながら、速く降りる」イメージです。
関連する用語も押さえておきましょう。訓練データ全体を一通り使い切ることを1 エポック(epoch)(Epoch) と数えます。たとえば1000枚のデータをミニバッチ100枚ずつで回すなら、10回の更新で1エポックです。学習では「何エポック回すか」で全体の学習量を管理します。少なすぎれば学習不足、多すぎれば次のモジュールで扱う過学習の原因になります。
Momentum と Adam — 慣性と適応で、賢く速く降りる
素朴なSGDには弱点があります。谷が細長く曲がっているような地形では、ボールが谷の壁の間で左右に振動してしまい、肝心の谷に沿った方向になかなか進めないのです。ジグザグに時間を浪費する、と言えば機械系の皆さんにはイメージしやすいでしょう。この非効率を改善するために、いくつかの工夫(オプティマイザ)が考案されました。式は結果だけを示します。導出は追いません。
Momentum — 慣性をつける
一つ目の工夫が モメンタム(Momentum)(Momentum) です。名前のとおり、物理の慣性をボールに与える発想です。毎回の勾配で向きをリセットするのではなく、これまで進んできた勢い(速度)を覚えておき、それに新しい勾配を少しずつ足していきます。
ここで が速度、(ベータ、たとえば0.9)が「過去の勢いをどれだけ引き継ぐか」を表す係数です。慣性があると、ジグザグの振動は前後で打ち消し合って小さくなり、谷に沿った一貫した方向には勢いがついて加速します。坂を転がるボールが、細かい凸凹を勢いで乗り越えていく——まさにあの感覚です。
Adam — 方向ごとに歩幅を自動調整する
二つ目が、現在もっとも広く使われている Adam(Adam) です。Adamは慣性の考え(勾配の移動平均)に加えて、パラメータごとに学習率を自動で調整する仕組みを持ちます。具体的には、過去の勾配の大きさを覚えておき、よく大きく動く方向は歩幅を控えめに、あまり動かない方向は歩幅を大きく、と方向ごとに調整します。
が勾配の移動平均(慣性に相当)、 が勾配の大きさの移動平均で、これで割ることで各方向の歩幅が自動調整されます。 はゼロ割りを防ぐ小さな数です。細かい定義を覚える必要はありません。押さえるべきは「Adam = 慣性 + 方向ごとの歩幅の自動調整」で、学習率の初期設定にそれほど神経質でなくても、そこそこ速く安定して学習が進む、という実用上のありがたさです。まず試すオプティマイザとしてAdamが選ばれるのは、この扱いやすさゆえです。
学習率スケジューリング — 歩幅は途中で変えていい
学習率は最初から最後まで同じである必要はありません。むしろ、最初は大きく踏み出してざっくり谷に近づき、終盤は歩幅を小さくして谷底に丁寧に着地する——このように学習が進むにつれて を変えていく方が、うまくいくことが多いのです。この調整を 学習率スケジューリング(learning rate scheduling)(Learning Rate Scheduling) と呼びます。
代表的なやり方が二つあります。一つはStep(ステップ)減衰で、あらかじめ決めたエポック数ごとに学習率をガクッと(たとえば10分の1に)下げる方式です。階段状に歩幅を縮めていくイメージです。もう一つはCosine(コサイン)減衰で、コサインカーブに沿って学習率をなめらかに下げていきます。急に変えず、じわじわと歩幅を絞るので、近年はこちらが好まれる場面も増えています。谷底に近づくほど慎重に、という直感はどちらも同じです。
可視化で試す — ミニNN訓練場でネットワークを学習させる
理屈を一通り見てきたので、最後は実際にニューラルネットワークを訓練してみましょう。下のミニNN訓練場は、ブラウザの中で本物のMLPを学習させられる実験場です。2次元平面上に色分けされた点があり、ネットワークがその境界線(決定境界)を学習していく様子と、損失が下がっていく曲線をリアルタイムで見られます。
まずは既定の設定で「Run」を押し、決定境界が最初のでたらめな状態から、だんだんデータの形に沿って整っていくのを眺めてください。損失曲線が右肩下がりになっていれば、学習が順調に進んでいる証拠です。次に、ここまで学んだことを一つずつ確かめます。
- 学習率を変える: 極端に小さくすると学習がなかなか進まず、大きくしすぎると損失曲線が暴れて境界がぐちゃぐちゃになる(発散)はずです。「速いが壊れない」ちょうど良い値を、自分で探してみてください。
- オプティマイザを切り替える: SGDとMomentum、Adamで、谷底(低い損失)へ着くまでの速さや安定感がどう違うかを見比べます。Adamの手軽さを体感できるはずです。
- データセットと形を変える: XORのように入り組んだデータは、層やノードが少ないと学習しきれません。ネットワークの容量(層数・ノード数)を増やすと表現できる境界が複雑になる——モジュール1で扱った「モデル容量」の話が、ここで最適化とつながります。
うまく学習できないとき、原因が「学習率」なのか「容量不足」なのか「エポック不足」なのかを切り分ける感覚こそ、実際の深層学習でいちばん役に立つ勘どころです。ぜひ手を動かして、失敗も含めて味わってください。
ミニNN訓練場(ブラウザ内で学習)
損失: —
正解率: —
Colabで本物のデータに挑む — 授業課題2への橋渡し
ブラウザの実験場で最適化の感覚をつかんだら、次は本物のデータで同じことをやってみましょう。下のColabノートブック 02_cifar100_basics.ipynb は、100種類の物体が写った画像データセットCIFAR-100を、CNNで分類する基本形です。このノートブックは授業課題2(CIFAR-100の分類精度を改善する)に直結します。まずはこの「その1」で、素朴なネットワークを実際に訓練し、学習率やオプティマイザ、エポック数を変えると精度がどう動くかを、今日学んだ知識をたよりに試してください。
ここで得られるベースラインの精度が、次のモジュール5で学ぶ「過学習との戦い」の出発点になります。まずは動かして、自分の手で損失が下がる様子を確かめることが何よりの学びです。
まとめ
このモジュールでは、ニューラルネットワークが「どうやって自動で学習するか」の中身を開けて見てきました。要点を振り返ります。
- 損失関数は、モデルの間違い具合を一つの数にまとめる。学習とは、この損失をパラメータで最小化する最適化問題である。
- 勾配降下法 は、勾配の逆向きへ一歩ずつ進んで谷底を目指す。学習率 は一歩の幅で、大きすぎれば発散、小さすぎれば低速になる。
- 誤差逆伝播は、連鎖律で勾配を出力から入力へバケツリレーする手続き。自動微分のおかげで人間が手で導出する必要はなくなった。
- SGD/ミニバッチ/エポックは、全データを使わず一部で勾配を計算して学習を回すしくみ。Momentumは慣性、Adamは慣性+方向ごとの歩幅自動調整で、より速く安定に降りる。
- 学習率スケジューリング(Step・Cosine)で、終盤は歩幅を絞って谷底に丁寧に着地する。
次のモジュール5では、「学習が進みすぎるとかえって新しいデータに弱くなる」という過学習の問題と、それに立ち向かうデータ拡張・Dropout・BatchNormを扱います。今日のCIFAR-100ベースラインを、次はどう改善していくか——そこが本番です。
確認クイズ
勾配降下法の更新則 θ ← θ − η ∂L/∂θ について、正しい説明はどれですか。
学習率 η を大きくしすぎると起こりやすいことはどれですか。ボールが谷を転がる例えで考えてください。
誤差逆伝播(バックプロパゲーション)の直感として最も適切なものはどれですか。
ミニバッチと確率的勾配降下法(SGD)について、正しい説明はどれですか。
Momentum と Adam の説明として正しい組み合わせはどれですか。