#関数の最適化について
基本的に最適化数学では、ある関数の最大(最小)を知ることに関心があります。(ニューラルネットワークにおける損失関数を最小化する問題など)(そもそも関数の最適化とは最大最小を求めること)
高校で習う数学においては、微分をすることによって最大、最小を求める(解析的に解く)ことができますが、実際の問題を解く際には対象の関数が微分不可能である場合の方が多いです。(コンピュータでは極限、無限小は扱えない、MLでは関数が複雑になりがち等の理由のため)
そこで、数値微分という方法を使って、数値的に問題を解く方法が考えられました。数値微分とは、微分の定義 $f'(x) = lim_{h\to0}\frac{f(x + h)-f(x)}{h}$から極限の操作を取り除いた$f'(x) = \frac{f(x+h)-f(x)}{h}$において、$h$の値を手動で小さな値(0.0001など)にすることで微分計算の近似をするものです。この方法は2点近似と呼ばれます。
一般的には$f'(x) = \frac{f(x+h)-f(x-h)}{2h}$(中心差分公式)の方が近似の精度が高いためよく用いられています。
以下ではこのような数値的な計算手法を使って関数を最適化する方法をまとめます。
##1.1 勾配法
今回はある関数の最小値を求める勾配法(勾配降下法)について考えます。
まず、初期地$x_0$を設定します。
次に$f'(x_0)$を求め、$f'(x_0)<0$ならば、$x_0$から$x$軸上の正の方向に進み$x_0$を更新します。
$f'(x)>0$ならば負の方向に進み、$x_0$を更新します。
$f'(x)=0$(0にならない可能性があるため、厳密には微小量)となればそこで最小値をとります。
式で表すと以下のようになリます。
$x_{i+1} = x_i - \eta f'(x_i)$
$\eta$は学習率やステップ幅と呼ばれます。これは$x_i$を更新する際にどの位の距離を移動するかを定めるものです。この値はハイパーパラメータと言って人が手動で定めるものです。
Pythonで簡潔に実装すると、以下の通りになります。長くなるので20回ほどの反復にしましたが、だいぶ0に近づいていることがわかります。
#関数(y = x^2)
def f(x):
y = x ** 2
return y
#導関数
def df(x):
dy = 2 * x
return dy
η = 0.1 #学習率
max_iteration = 20 #最大反復回数
x0 = 10 #初期値
values = [x0] #更新する値を格納するリスト
for i in range(max_iteration):
x0 = x0 - η * df(x0) # 勾配降下法
values.append(x0) # 更新した値をリストに格納する
print(i, x0) # 更新した値を出力する
#以下出力結果
0 8.0
1 6.4
2 5.12
3 4.096
4 3.2768
5 2.62144
6 2.0971520000000003
7 1.6777216000000004
8 1.3421772800000003
9 1.0737418240000003
10 0.8589934592000003
11 0.6871947673600002
12 0.5497558138880001
13 0.43980465111040007
14 0.35184372088832006
15 0.281474976710656
16 0.22517998136852482
17 0.18014398509481985
18 0.14411518807585588
19 0.11529215046068471
##1.2 勾配法の問題点
1つ目の問題点は、勾配を式として用いるため、微分できない関数(連続ではない、もしくは尖っている(例: $f(x)=|x|$など)は扱えません。
2つ目の問題点は、最大、最小以外の極値があれば初期値の与え方によっては、最大、最小値以外の極値に到達してしまう可能性があります。(いわゆる局所最適解)
これを避けるためには、最大値、または最小値をとる点に十分近い初期値を推定して与える必要があります。
3つ目の問題点は、極値が一点のみであったとしても、極値付近の関数形によっては極値に達するまでに時間がかかることがあります。
(この問題を改善するための手法としてニュートン法、共役勾配法、ガウス・ニュートン法、レーベンバーグ・マーカート法が挙げられる)
#参考にしたもの
MATLAB
「これなら分かる最適化数学」(金谷、2015)
機械学習のための数学おさらい