こんにちは。
年度が変わりましたね。
そして、春ですね。
久しぶりに機械学習関連の記事を書こうかなと思ったのですが、
ある解説の途中でその前提知識の解説とかが入って、すぐ脇道に逸れてしまうんですよね。
とはいえ、詳しくは他の人が書いてるからググってね!ってすると、
戻ってきた頃には「で、なんだっけ?」ってなっちゃうし、難しいものです。
特に微分積分と線形代数は最低限必要みたい言われるのですが、最初から全部が必要ってわけではないと思うんです。
というわけで、今回はとりあえずこれ覚えとけばなんとかなるんじゃない?
っていう微分テクニックについて書いてみようかと思います。
なんで微分するのって話はこちらをどうぞ。
shironeko.hateblo.jp
高校数学の微分を忘れ去られた記憶から頑張って思い出してみると、
2次関数だったり3次関数だったり、1つの変数を指定することで値が定まる1変数関数だけを対象にしていました。
(というかちゃんと覚えてないんですけど、偏微分って高校数学の範囲じゃないですよね?)
たとえば、1変数の関数
・・・①
を微分すると、
・・・②
になります。
※微分の表現方法にはみたいなのと、
もしくはみたいなのがありますが、意味は同じです。
偏微分の話をするときにはが良さそうなので、今回はこっちを使います。
でも、世の中の関数って1変数で表せることってあんまりないですよね。
例えば、距離は速さ×時間だし、BMIは体重÷身長の2乗なわけです。
機械学習で扱うデータだって1次元のデータなんてものは基本的にはないでしょう。
とすると、多変数の関数
・・・③
とかだって微分できないと困るわけですよね。
微分っていうのは変化量を求めることです。
3xを微分すると3になるっていうのは、いつもいつでもxの変化量は3ということです。
axを微分するとaになるっていうのは、aの値によってxの変化量は変わるよってことです。
を微分すると2xになるっていうのは、xの値によってxの変化量は変わるよってことです。
ということは、他の変数の値によって変化量が変わるという表現を使ってよいのであれば、
上の例はxで微分することも、yで微分することも、zで微分することもできるはずです。
この、「多変数関数をある一つの変数で微分する(他の変数を定数とみなす)」ことを偏微分といいます。
そして、関数をxで微分することを、と表現します。
大切なことは、なにで(「なんで」ではなくて「なにで」)微分するかというのが必ず決まっていることです。
単純に「距離を微分すると何になる?」っていうのは答えがありませんが、
距離を時間で偏微分すると速さになるし、速さで偏微分すると時間になるわけです。
というわけで、③の式をxで偏微分すると、
・・・④
yで偏微分すると、
・・・⑤
になるということです。
合成関数の微分
もうひとつ、よく使うテクニックに合成関数の微分があります。
合成関数とはその名の通り複数の関数を合成したものです。
例えば2つのxの関数
・・・⑥
・・・⑦
があるとき、
・・・⑧
のように関数を組み合わせることができます。
じゃあこれを微分したらどうなるのっていうと、
・・・⑨
なので(あってる?)
・・・⑩
となるわけです。
とてもつらい。
ここでわかりやすくするために⑧の式を
・・・⑪
・・・⑫
とおいてみた場合、
・・・⑬
という変形が成り立ちます。これを合成関数の微分といいます。
・・・⑭
・・・⑮
ですから、
・・・⑯
⑩の式とちゃんと一致しましたね。
これがプログラム的に考えると何が便利かというと、
複数の関数を通してその最終結果を微分する場合、
それぞれの途中の関数の微分ができていれば簡単に計算できてしまうことなんですよね。
※C#っぽい構文ですが、C#では累乗はMath.Powを使います。擬似コードということで。
const int A = 5;
const int B = 3;
int F(int x) {
return A * x ^ 3 + B;
}
int DF(int x) {
return 2 * A * x;
}
int G(int x) {
return x ^ 3;
}
int DG(int x) {
return 3 * x ^ 2;
}
int DFG(int x) {
return 6 * A * x * (A * x ^ 2 + B) ^ 2 ;
}
があるときに、
int x = 2;
int y = G(F(x));
int y_dash = DG(F(x)) * DF(x);
みたいな感じですね。
合成関数の微分を使わない場合、先にDFGを計算しておかなくてはいけないし、
例えば関数Hが現れたらで3種類の微分の結果を先に計算しておかないといけなくなってしまいます。
一方で合成関数の微分を使う場合、関数ごとにその微分の関数も用意しておけば全体の微分ができます。超便利!
で、いつ使うの?
っていわれると難しい。
ニューラルネットワーク作るとめっちゃ使うよってくらい。
でも、他の説明の途中でこういう説明挟み込むのはやっぱり大変なので1つ記事にしました。
いつかそういう場面に出会ったときに、「あぁなるほど!これは便利だ!」ってなるんですよ。
えぇ、なるんですとも。