けんごのお屋敷

2016-01-04

やる夫で学ぶ機械学習 - 単回帰問題 -

やる夫で学ぶ機械学習シリーズの第 2 回です。回帰について見ていきます。

第 1 回はこちら。やる夫で学ぶ機械学習 - 序章 -

目次はこちら。やる夫で学ぶ機械学習シリーズ

問題設定

やらない夫
今日は回帰について詳しく見ていく。

やる夫
回帰って響きがカッコいいお。

やらない夫
ここからは、より具体的な例を混じえながら話を進めていこう。

やる夫
具体例は、やる夫の明日のお昼ごはんぐらい大事だお。

やらない夫
まったく意味がわからないたとえなんだが…。そうだな、たとえば、主人公の攻撃力によって、敵キャラに与えるダメージが決まるゲームがあるとしよう。

やる夫
よくある設定だお。

やらない夫
ダメージには揺らぎがあって、常に同じダメージを与えられるとは限らない。さて、実際に何度か敵キャラに攻撃してみて、その時の攻撃力と与えたダメージをグラフにプロットしてみると、こんな風になっていたとしよう。

やる夫
なるほど。攻撃力が高くなればなるほど、与えるダメージも大きくなっているお。

やらない夫
やる夫はコレを見て、攻撃力が 10 の時にどれくらいダメージを与えられるかわかるか?

やる夫
馬鹿にしてるのかお!そんなの簡単だお。だいたい 60 前後くらいだお?

やらない夫
そうだな。俺たちはこれから機械学習を使って、今やる夫がやったように、攻撃力からダメージを予測していく。

やる夫
そんなの、このプロットを見れば、だいたい誰にでもわかるお?

やらない夫
それはこの問題設定が単純だからだよ。実際に機械学習を使って解きたい問題は、複雑な問題であることがほとんだ。そういうものを機械にまかせるために、データから学習させるんだよ。それが機械学習だ。後からもっと複雑な問題も見ていくから、その時もまた同じことが言えるかどうかだな。

やる夫
ふーん。

最小二乗法

やる夫
どうやって学習していくんだお?

やらない夫
関数をイメージするんだ。このプロットの各点を通る関数の形がわかれば、攻撃力からダメージがわかるだろ。ただし、ダメージにはノイズが含まれているから、関数がきっちり全ての点を通るわけじゃない。

やる夫
これは一次関数だお!一次関数は、切片と傾きがわかれば関数の形が決まるから、それを調べることになるのかお?

やらない夫
冴えてるな。俺たちがいまから考える関数は、切片と傾きを $\theta$ を使って表すと、こんな風になる。

$$ y = \theta_0 + \theta_1 x $$

やる夫
うっ、式が出てくると急に数学っぽくなるお…、$\theta$ ってなんだお。

やらない夫
$\theta$ はこれから俺たちが求めていく未知数だ。パラメータとも言う。文字は別になんでもいいんだが、統計学の世界では、未知数や推定値を $\theta$ で表すことが多いので、今回も $\theta$ を使っただけだ。

やる夫
まあ、今の例の場合は切片と傾きだと思っておくお。

やらない夫
今はそれで問題ないだろう。そして、わかっているとは思うが $x$ が攻撃力、$y$ がダメージに対応している。

やる夫
そこは OK だお。

やらない夫
なにか具体的な値を実際に代入して確認してみるとイメージもつきやすいだろう。そうだな、たとえば $\theta_0 = 1$、$\theta_1 = 2$ としてみよう。さっきの式はどうなるかわかるか?

やる夫
やらない夫の質問はいつも優しすぎるお。代入するだけだお。

$$ y = 1 + 2x $$

やらない夫
よし、ではその式の $x$ に何か代入して $y$ を求めてみようか。

やる夫
$x = 5$ の時を計算してみるお。

\begin{eqnarray} y & = & 1 + 2x \\ & = & 1 + 2 \cdot 5 \\ & = & 11 \end{eqnarray}

やらない夫
つまり、パラメータが $\theta_0 = 1$、$\theta_1 = 2$ の場合は、攻撃力が 5 の時に与えるダメージは 11 くらいになるってことだ。

やる夫
でも、さっきのグラフを見ると攻撃力 5 の時は、だいたい 40 〜 50 くらいはダメージを与えてるお。

やらない夫
そうだな。つまり俺たちがいま適当に定義したパラメータは間違ってるってことだ。これから、機械学習を使って、この $\theta_0$ と $\theta_1$ の正しい値を求めていくんだ。

やる夫
把握したお。で、どうやって求めていくんだお?

やらない夫
その前に、さっきの式をこのように書き直すぞ。

$$ f_{\theta}(x) = \theta_0 + \theta_1 x $$

やる夫
$y$ が $f_{\theta}(x)$ に変わっただけだお。てか、なんでこんなことするお?

やらない夫
こうすることによって、これが $\theta$ というパラメータを持ち、$x$ という変数の関数だということを明示的に表せるだろう。それに $y$ のままにしておくと、この後に混乱することになるからな。

やる夫
ふーん。まあ、やらない夫がそうするっていうなら、だまって従うお。

やらない夫
肝心の $\theta$ の求め方だが、いま、俺たちの手元には、攻撃力とダメージのデータがある。さっきのグラフにプロットしてあった点だな。つまり学習用のデータだ。これを $f_{\theta}(x)$ に代入して得られた値と、実際の値の差が最小になるように $\theta$ を決定していくんだ。

やる夫
ん、ちょっと何いってるかよくわからないお…

やらない夫
具体的にいくつか学習用データを列挙してみよう。攻撃力に小数点があるのはいささか奇妙だが、とりあえず違和感は置いておこう。

攻撃力($x$) ダメージ($y$)
3.0 30
3.7 35
4.3 33
4.6 44

やる夫
やらない夫は、この 4 つの赤い点のデータを列挙したのかお?

やらない夫
そうだ。さっき、パラメータを $\theta_0 = 1$、$\theta_1 = 2$ という風に適当に決めて、$1 + 2x$ という式を作ったが、これに実際に $x$ の値を代入したものを表に足してみるぞ。

攻撃力($x$) ダメージ($y$) $\theta_0 = 1$、$\theta_1 = 2$ の時の $f_{\theta}(x)$
3.0 30 7.0
3.7 35 8.4
4.3 33 9.6
4.6 44 10.2

やらない夫
これを見て、学習用データの値、つまり $y$ だな、それと $f_{\theta}(x)$ で計算した値が、ズレてることがわかるか?

やる夫
かなりズレてるお。

やらない夫
ただ、$y$ と $f_{\theta}(x)$ の値は一致しているのが理想だ。わかるか?

やる夫
わかるお。$y$ を予測するための関数が $f_{\theta}(x)$ なんだお。

やらない夫
理想に近づけるためには $y$ と $f_{\theta}(x)$ の誤差、つまり $|y - f_{\theta}(x)|$ が小さくなれば良い。全ての学習用データにおいて、誤差の和が最も小さくなるようなパラメータ $\theta$ を見つければいいというわけだ。こういう問題は最適化問題と呼ばれる。ついてこれてるか?

やる夫
うっ、うん、なんとか…

やらない夫
図を使うと、よりわかりやすいかもしれないな。青い点が学習用データ、青い線が $1 + 2x$ のグラフ、そして赤い点線がそれらの差だ。

やる夫
あ、これだとわかりやすいお。誤差を最小にするってことは、この赤い点線の高さを小さくするってことだお。それはつまり、$f_{\theta}(x)$ が学習用のデータにフィットしていくってことになるお。

やらない夫
そういうことだな。学習用データの個数を n 個とすると、誤差の和は以下のような式で表せる。この式では $\theta$ が変数となっているところに注意だ。

$$ E(\theta) = \frac{1}{2}\sum_{i=1}^n (y^{(i)} - f_{\theta} (x^{(i)}))^2 $$

やる夫
いや、いきなり難易度あげすぎだお。まだ心の準備ができてなかったお。

やらない夫
まず、誤解されないように最初に説明しておくと、$x^{(i)}$ や $y^{(i)}$ は i 乗という意味ではなくて、i 番目の学習用データということだ。$x^{(1)}$ は 3.0 で $y^{(1)}$ が 30、それから $x^{(2)}$ は 3.7 で $y^{(2)}$ が 35、という具合だな。

やる夫
そこは、なんとなくそういう雰囲気を感じていたお。

やらない夫
誤差の部分だが、実際には単純な誤差じゃなくて二乗誤差を使っている。なので、誤差の部分を二乗しているんだ。

やる夫
全体を 2 で割ってるのは何だお?

やらない夫
後で $E(\theta)$ を微分することになるんだが、微分した式をちょっとだけ簡単にするためのトリックだ。最適化問題は、何か定数が全体に掛かっていたとしても、求まる答えは変わらないからこういうことができる。まあ、あまり深く考えなくていいさ。

やる夫
おまじない的なものは気持ち悪いお…、うーん、全体像はわかったけど、ちょっと、まだピンときてないお。

やらない夫
具体的に値を入れて計算してみるか。$\theta_0 = 1$、$\theta_1 = 2$ として、さっき列挙した 4 つの学習用データを実際に代入してみよう。$f_\theta(x^{(i)})$ や $y^{(i)}$ はさっきの表の値を参照すると…

\begin{eqnarray} E(\theta) & = & \frac{1}{2}\sum_{i=1}^n (y^{(i)} - f_{\theta} (x^{(i)}))^2 \\ & = & \frac{1}{2}\left((30 - 7.0)^2 + (35 - 8.4)^2 + (33 - 9.6)^2 + (44 - 10.2)^2\right) \\ \\ & = & \frac{529.0 + 707.5 + 547.5 + 1142.4}{2} \\ & = & 1463.2 \end{eqnarray}

やる夫
1463.2?

やらない夫
この 1463.2 という値自体に特に意味はないが、この値がどんどん小さくなるように、パラメータの $\theta$ を更新していくことが目的だ。

やる夫
あー、この値が小さくなるということは、つまり予測値 $f_\theta(x)$ と、学習用データ $y$ の誤差が小さくなる、ということかお。

やらない夫
そういうことだ。このようなアプローチは最小二乗法と呼ばれる。

最急降下法

やる夫
$E(\theta)$ の値を小さくしたいのはわかったけど、どうやって小さくしていくんだお?$\theta$ を適当に決めて、値を代入して、前の値と比較していくのはさすがに面倒だお。

やらない夫
そんな面倒なことはしないさ。この $E(\theta)$ のことを「目的関数」や「コスト関数」と呼ぶんだが、これを $\theta_0$ と $\theta_1$ について偏微分していく。

やる夫
偏微分?そんなもんで、わかるのかお?

やらない夫
微分の定義を思い出せ。微分は変化の度合いを求めるためのものだったろう。微分を習った時に、増減表を作ったりしなかったか?

やる夫
増減表…、そういえば、そんなものがあったお。なつかしいお。

やらない夫
簡単な例で試してみようか。こういう二次関数があるとしよう。最小値は明らかに $x = 1$ の時の $g(1) = 0$ だな。この二次関数の増減表はどうなる?

やる夫
お…、今回の質問は少し難易度があがったお。えーっと…、まずは関数を微分するお。

$$ \frac{d}{dx}g(x) = 2x - 2 $$

やる夫
んで、導関数の符号を見ながら、増減表を作って…、これでいいかお?

$x$ の範囲 $x < 1$ $x = 1$ $x > 1$
$\frac{d}{dx}g(x)$ の符号 - 0 +
$g(x)$ の増減

やらない夫
よし。この増減表を見ると、$x < 1$ の時は右下がりになっている。逆に $x > 1$ の時は右上がり、これは言い換えると左下がりになっているな。

やる夫
増減表を見ても、グラフを見ても、確かにそうなっているお。

やらない夫
たとえば $x = 3$ からスタートして $g(x)$ の値を小さくするためには、$x$ を少しずつ左にずらしていけばいい。なぜなら、増減表から $x > 1$ の時は、グラフが左下がりになっているのがわかるからだ。$x = -3$ からだと、逆に右にずらしていけばいいな。

やる夫
それって、導関数の符号によって、$x$ をずらす方向が変わるってことかお?マイナスだったら右下がりだから右にずらして、プラスだったら左下がりだから左にずらす、ってことになるお。

やらない夫
その通りだ。導関数は元の関数の傾きを表しているからな。微分して導関数を求めて、その符号によって $x$ の位置をずらす、別の言い方をすると $x$ を更新していくことで、最小値を求めるんだ。$x$ の更新を式にするとこうだな。

$$ x := x - \eta\frac{d}{dx}g(x) $$

やらない夫
この手法を最急降下法と言う。

やる夫
$\eta$ って、なんだお?

やらない夫
$\eta$ は、学習率と呼ばれる正の定数だ。学習率が小さければ、$g(x)$ の最小値にたどり着くまでに何度も $x$ を更新する必要があって、時間がかかってしまう。逆に学習率を大きくすれば、速く $g(x)$ の最小値にたどり着ける可能性があるが、$x$ が定まらず発散してしまう可能性もある。

やる夫
ちょっと待つお…、よくわからんお。

やらない夫
そういう時はいつでも、簡単な値を代入して、具体的に確認してみるんだ。たとえば $\eta = 1$ として、$x = 3$ からスタートしてみるんだ。

やる夫
やってみるお。$g(x)$ の微分は $2x - 2$ だから、$x$ を更新する式は $x := x - \eta(2x - 2)$ になるお。右辺の $x$ にどんどん代入してみるお。

\begin{eqnarray} x & := & 3 - 1(2\cdot 3 - 2) = 3 - 4 = -1 \\ x & := & -1 - 1(2\cdot -1 - 2) = -1 + 4 = 3 \\ x & := & 3 - 1(2\cdot 3 - 2) = 3 - 4 = -1 \\ \end{eqnarray}

やる夫
これは大変だお!!無限ループするお!!!

やらない夫
じゃぁ、今度は $\eta = 0.1$ として、同じく $x = 3$ からスタートしてみるんだ。

やる夫
やってみるお。面倒くさいから小数は、小数点以下 1 桁までで計算するお。

\begin{eqnarray} x & := & 3 - 0.1\cdot(2\cdot 3 - 2) = 3 - 0.4 = 2.6 \\ x & := & 2.6 - 0.1\cdot(2\cdot 2.6 - 2) = 2.6 - 0.3 = 2.3 \\ x & := & 2.3 - 0.1\cdot(2\cdot 2.3 - 2) = 2.3 - 0.2 = 2.1 \\ x & := & 2.1 - 0.1\cdot(2\cdot 2.1 - 2) = 2.1 - 0.2 = 1.9 \\ \end{eqnarray}

やる夫
うーん、$x$ が 1 に近づいていってるけど、とても近づき方が遅いお…。小数点の計算、面倒だお…

やらない夫
つまり、そういうことだな。$\eta$ が大きいと、$x$ をずらしすぎて、左に行ったり右に戻ったりを繰り返しているのがわかる。一方で、$\eta$ が小さいと、とても少しずつだが、$x$ が左にずれていっているのがわかる。

やる夫
なるほど。さすが、やらない夫だお。

やらない夫
話を目的関数 $E(\theta)$ に戻すぞ。この関数は、変数として $\theta_0$ と $\theta_1$ の 2 つをもつ 2 変数関数だ。つまり各々の $\theta$ の更新を式にすると、こうだ。わかるか?

$$ \theta_0 := \theta_0 - \eta\frac{\partial E}{\partial \theta_0} \\ \theta_1 := \theta_1 - \eta\frac{\partial E}{\partial \theta_1} $$

やる夫
んー、ちょっと複雑になったけど、$g(x)$ が $E$ に変わって、偏微分になっただけだお。

やらない夫
実際に $E$ を偏微分をしてみようか。まずは $\theta_0$ からだ。どうなる?

やる夫
えっ、あ、やる夫がやるのかお。えーっと…、あー、$\theta_0$ 自体は $E$ の中にはなくて、$f_{\theta}(x)$ の中にあるから、まずは代入しないといけなくて…、あ、2 乗されてるから、展開も必要だお。うっ、これは結構、面倒くさいお…

やらない夫
正攻法だと少し面倒くさいから、合成関数の微分を使うともっと楽にできるな。

やる夫
ん、合成関数の微分?

やらない夫
$f$ と $g$ という関数があったとき、これらの合成関数 $f(g(x))$ を $x$ で微分する場合はこうなる。これを使えば簡単になるぞ。

$$ \frac{df}{dx} = \frac{df}{dg}\cdot\frac{dg}{dx} $$

やる夫
お、これを目的関数に適用すればいいのかお?えっと…、こうかお?

$$ \frac{\partial E}{\partial \theta_0} = \frac{\partial E}{\partial f_{\theta}}\cdot\frac{\partial f_{\theta}}{\partial \theta_0} $$

やる夫
それぞれ計算してみるお。まずは $E$ を $f_{\theta}$ で微分するところから…

\begin{eqnarray} \frac{\partial E}{\partial f_{\theta}} & = & \frac{\partial}{\partial f_{\theta}} \left(\frac{1}{2}\sum_{i=1}^n (y^{(i)} - f_{\theta} (x^{(i)}))^2\right) \\ & = & \sum_{i=1}^n (f_{\theta} (x^{(i)}) - y^{(i)}) \end{eqnarray}

やる夫
あー、ここで微分した時に次数の 2 が前に降りてきて、約分されて式が綺麗になるってわけかお。なるほど。次は $f_{\theta}$ の微分だお。

\begin{eqnarray} \frac{\partial f_{\theta}}{\partial \theta_0} & = & \frac{\partial}{\partial \theta_0} \left(\theta_0 + \theta_1 x\right) \\ & = & 1 \end{eqnarray}

やる夫
おっ、簡単になったお。この微分した結果 2 つを掛ければいいんだから…、答えはこうだお!あってるかお?

\begin{eqnarray} \frac{\partial E}{\partial \theta_0} & = & \sum_{i=1}^n (f_{\theta} (x^{(i)}) - y^{(i)}) \cdot 1 \\ & = & \sum_{i=1}^n (f_{\theta} (x^{(i)}) - y^{(i)}) \end{eqnarray}

やらない夫
よし、いいぞ。$\theta_1$ に関しても、$E$ の微分はまったく同じだし、$f_{\theta}$ の微分は今度は $x$ になるな。要するに、$E$ を $\theta_1$ で偏微分した式はこうだ。

$$ \frac{\partial E}{\partial \theta_1} = \sum_{i=1}^n (f_{\theta} (x^{(i)}) - y^{(i)})x^{(i)} $$

やる夫
合成関数の微分って便利だお。

やらない夫
俺たちは、偏微分した結果を手に入れたので、結局は $\theta$ の更新式は以下のようになる。

\begin{eqnarray} \theta_0 & := & \theta_0 - \eta\sum_{i=1}^n (f_{\theta} (x^{(i)}) - y^{(i)}) \\ \theta_1 & := & \theta_1 - \eta\sum_{i=1}^n (f_{\theta} (x^{(i)}) - y^{(i)})x^{(i)} \end{eqnarray}

やる夫
うーん、だいぶおぞましい式だお…

やらない夫
実装するときの注意点だが、これら 2 つの $\theta$ は同時に更新していかなければならないんだ。$\theta_0$ を更新し終わった後に $\theta_1$ を更新しようとする時、更新済みの $\theta_0$ を使っていけない。更新前の $\theta_0$ を使うんだ。

やる夫
頭の片隅に置いとくお…

やらない夫
これで、すべての道具はそろった。おさらいも兼ねて、まとめよう。

やらない夫
俺たちは、攻撃力からダメージを計算するために、この未知の関数の切片と傾きを調べたかった。

やらない夫
そのため、この関数を以下のように定義した。

$$ f_\theta(x) = \theta_0 + \theta_1 x $$

やらない夫
そして、学習用データと、この関数の値の誤差を、以下のような関数で定義した。これを目的関数と呼ぶんだった。

$$ E(\theta) = \frac{1}{2}\sum_{i=1}^n (y^{(i)} - f_{\theta} (x^{(i)}))^2 $$

やらない夫
俺たちのゴールは、この目的関数の値を最小化する $\theta_0$ と $\theta_1$ を見つけることだ。なぜなら、この目的関数は誤差の関数であり、誤差が小さければ小さいほど $f_\theta(x)$ の正しい形がわかるからだ。そのために、最急降下法を使って以下のようにパラメータ $\theta_0$ と $\theta_1$ を更新していく。

\begin{eqnarray} \theta_0 & := & \theta_0 - \eta\sum_{i=1}^n (f_{\theta} (x^{(i)}) - y^{(i)}) \\ \theta_1 & := & \theta_1 - \eta\sum_{i=1}^n (f_{\theta} (x^{(i)}) - y^{(i)})x^{(i)} \end{eqnarray}

やらない夫
この更新のフェーズを学習と呼ぶことが多いな。更新を止めるタイミングは、目的関数の値が更新の前後であまり変わらなくなってきた時だ。もしくは一定回数だけ繰り返すという場合もある。

やらない夫
具体的な $\theta$ の値がわかったら、あとはもう $f_\theta(x)$ に攻撃力を入れれば、ダメージが出力される。これでめでたく目標達成だ。

やる夫
単純な一次関数の形を見つけるだけなのに、たいした苦労だお…

やらない夫
最初にも言ったが、これは問題設定が単純なので、あまり嬉しさが伝わらないかもしれないが、実際はもっと複雑な問題を解きたいことが多い。次はもう少し複雑な例を見てみるか。

やる夫
ちょっと疲れたから、休憩するお…


やる夫で学ぶ機械学習 - 多項式回帰と重回帰 - へ続く。

  • このエントリーをはてなブックマークに追加