トッカンソフトウェア

最急降下法(Gradient descent)

前々回、線形回帰とは、y = ax + b のa、bを求めることで未知のxに対し、yを予想できるようになると書き、前回
a、bを求めるために最小二乗法という方法があると書きましたが、今回の最急降下法というものを使って、実際にa、bを求めてみます。



y = ax + b のa、bをどうやって求める?

前回は、y = ax + b のa、bに適当な値を入れて、実績値のxを使って計算して計算結果と実績値のyの値を近づけるということをやりましたが、 このa、bはどうやって最終的な値に持っていけば良いでしょうか?

a、bに適当な値を入れて、実績値y、xを使って計算して、a、bを適当に変えてまた計算して・・・を繰り返し行えば、いつかは適当なa、bがわかるかもしれませんが、a、bをどのように変えて 再計算させるかを考えるのは大変だと思います。

そこで今回の最急降下法(Gradient descent)というものを使います。最急降下法を使うと、a、bに入れるべき値を自動で算出してくれます。

最急降下法

y = ax + b の a、b の値を少しづつ上げていくと、最初はかなり差異のある状態から段々、差異がなくなっていき、
ある時点で差異が一番小さくなり、それからまた差異が増えていきます。

aと差異合計のイメージ


bと差異合計のイメージ


最急降下法とは、このグラフの傾きから答えを求める方法です。

どこかにスタート地点を決めて、差異のグラフに傾きがあるうちは、傾いている方向に値を移動していき、傾きがなくなったら、そこが求めている値(差異が一番ない状態)になります。

傾きは目的関数を微分することで求められます。

目的関数は前回でてきた最小二乗法の式になります。

\(J(\theta_0, \theta_1) = \frac{1}{2m}\sum_{i=1}^m(h_\theta (x_i) - y_i)^2 \)

微分

微分すると傾きが求められると書きましたが、少し微分の復習をします。

微分とは、以下と言われます。
・傾きを求めること。
・ある地点の接線を求めること。
・導関数を求めること。


どういうことかというと、xの変化量とyの変化量を極限まで縮めると、


xの時点の傾き(グラフ接線)になります。


上記のように変化量を極限まで縮め、傾き(グラフ接線)を求めることを微分するといいます。

ちなみに微分の公式は以下です。
\( (x^n)'=nx^{n-1} \)

a、bを求めるのに微分した値をどのように使うか

最小二乗法で出てきた式をa、bに対してそれぞれ微分すると、以下になります。
(a、bのそれぞれに対し微分するには、偏微分というものを使うのですが、ここでは説明を省略します。ググって下さい)

元となる目的関数(最小二乗法で出てきた式)
\(J(\theta_0, \theta_1) = \frac{1}{2m}\sum_{i=1}^m(h_\theta (x_i) - y_i)^2 \)

aを微分
\({ \sum_{i=1}^m (h_\theta (x^{(i)}) - y^{(i)}) } x_j ^{(i)} \)

bを微分
\({ \sum_{i=1}^m (h_\theta (x^{(i)}) - y^{(i)}) }\)

a、bに初期値として適当な値を入れておき、テストデータ(y、x)を使って、上記の式を行うと、微分した値(傾き)の合計値が求められます。

その値がプラスの場合、グラフは右上がりの状態(答えとなるべき値を超えている)なので、a、bの値を少し減らします。
その値がマイナスの場合、グラフは右下がりの状態(答えとなるべき値に至っていない)なので、a、bの値を少し増やします。

学習率 (learning rate)

微分した値(傾き)の合計値をa、bに対して引けば上記の計算がされることになりますが、

(仮) 次の計算で使うaを求める計算
\(a - { \sum_{i=1}^m (h_\theta (x^{(i)}) - y^{(i)}) } x_j ^{(i)} \)

(仮)次の計算で使うbを求める計算
\(b - { \sum_{i=1}^m (h_\theta (x^{(i)}) - y^{(i)}) }\)

a、bに与える値がプラスでもマイナスでも大きすぎるとと、答えにたどり着くことができず、
小さすぎると答えにたどり着くまで時間が掛かります。

大きすぎる場合

小さすぎる場合


なので微分した値(傾き)の合計値を適度な大きさに変換するのに学習率 (learning rate)というものを使います。

次の計算で使うaを求める計算(\(\alpha\)は学習率)
\(a - \alpha{ \sum_{i=1}^m (h_\theta (x^{(i)}) - y^{(i)}) } x_j ^{(i)} \)

次の計算で使うbを求める計算(\(\alpha\)は学習率)
\(b - \alpha{ \sum_{i=1}^m (h_\theta (x^{(i)}) - y^{(i)}) }\)

コロンイコール(定義)

a、bに対して微分した値をプラス、マイナスした後に、次のa、bに値をセットすることを表すのは := を使用します。
:= は プログラムで使われる = と同じ意味です(a = a + 1;のイコールと同じ意味)。

次の計算で使うaを求める計算(\(\alpha\)は学習率)
\(a := a - \alpha{ \sum_{i=1}^m (h_\theta (x^{(i)}) - y^{(i)}) } x_j ^{(i)} \)

次の計算で使うbを求める計算(\(\alpha\)は学習率)
\(b := b - \alpha{ \sum_{i=1}^m (h_\theta (x^{(i)}) - y^{(i)}) }\)

上記の計算を繰り返すとそのうちa、bの変動がなくなるので、その状態になるまで繰り返します。

計算するときに
aを計算 → bを計算 → a、bの値を修正 → aを計算 → bを計算 → a、bの値を修正 → ・・・
のようにaの計算とbの計算は同時に行う必要があります。

ページのトップへ戻る