いぬおさんのおもしろ数学実験室

おいしい紅茶でも飲みながら数学、物理、工学、プログラミング、そして読書を楽しみましょう

勾配降下法とは何か、分かりやすく説明します(2)今回は2変数関数!

 今回は次の2変数の関数で勾配降下法を試してみましょう。
f:id:Inuosann:20200807180710p:plain:w200
の最小値を求めます。前回は1変数の関数でしたので普通の微分係数を求めました。2変数だと、「xで微分する」「yで微分する」という操作が必要です。偏導関数と言うのでした。プログラムの gx(x, y) が (x, y) での x による偏微分係数、 gy(x, y) が (x, y) での y による偏微分係数です。何のことはない、例えば gx(x, y) だったら、yを定数だと思ってxで今まで通りに微分するだけです。偏微分については過去の記事で触れています。必要に応じて参照してください。
www.omoshiro-suugaku.com
gx(x, y) はxを少しだけ増やして(f(x + d, y) - f(x, y)) / d で計算しています。前回同様です。念のため。
 グラフは次の通り。立体なのでイメージしやすくするため角度を変えた図を3枚載せます。
f:id:Inuosann:20200807180302p:plain:w300
f:id:Inuosann:20200807180345p:plain:w300
f:id:Inuosann:20200807180428p:plain:w300
 Pythonのプログラムは次です。最小限のコードです。

import sys
import math

def f(x, y):
    return math.sin(x) + math.cos(y)
#
def gx(p, q): # x = p, y = q での偏微分係数(偏導関数の値)を求める
    return (f(p + d, q) - f(p, q))/d
def gy(p, q): # x = p, y = q での偏微分係数(偏導関数の値)を求める
    return (f(p, q + d) - f(p, q))/d
#
x = 4 #xの初期値
y = 4
d = 0.0001 #偏微分係数を求めるためのx、yの増分
e = 0.01 #小さめの値
#
for i in range(1000):
    x = x - e * gx(x, y)
    y = y - e * gy(x, y)
#
print('最小値を与える x, y = ', x, y)
print('最小値', f(x, y))
sys.exit()

実行結果は以下の通り。
最小値を与える x, y = 4.712306836811316  3.141582209513457
最小値 -1.9999999965716773

グラフを見ると、どうやらx、yの値は正しそうですね。念のためもとの式を理屈通りに偏微分してみると
f:id:Inuosann:20200807234558p:plain:w120
です。最小値を取るときにはこの2つの式の値は0になるはずです。1変数のときと同様です。x=3π/2、y=πで0になりますから、やはりさっきの答えは正しそうです!!


 前回は書きませんでしたが、ディープラーニングで勾配降下法がでてくるときプログラムのeは学習率と呼ばれます。よくη(イータ。ギリシャ文字)が使われるようです。
 もうひとつ、やはり前回は書きませんでしたが、勾配降下法がうまく働かないときがあります。例えばグラフの谷底が複数箇所あるときには初期値をうまく選ばないと浅い方の谷底が求まってしまうことがあるのです。2変数なら今回みたいにグラフを描けばどの辺が谷底か分かるからよいのですが、変数がもっと多いとグラフは描けません。一般的な解決法があるのかぼくは知りません。ディープラーニングの本には何か書いてあるかも。