ゼロから作るDeep Learning3 フレームワーク編を読む その⑤ステップ37
はじめに
以下の記事シリーズの続きです。今までは複数ステップで一記事にしていたのですが、今回大いにつまずいたので1ステップで1記事使います。 cha-kabu.hatenablog.com
「ステップ37 テンソルを扱う」の概要
これまで作成してきたDeZeroが、スカラだけでなくテンソルの演算にも実は対応していることの説明です。説明のステップですので新しい実装は無い(コードを使った説明はありますが、後続のステップの実装を先取りして使う)のですが、発展的内容として今のDeZeroでテンソルを使用した時の逆伝播について数式で説明されています。
※「あくまで今のDeZeroに実装された機能に限った逆伝播の話で、テンソルの逆伝播全般の説明ではない」を理解するのに随分時間がかかりました。そう書いてあるんですけどね。
基本的な関数の微分や偏微分はそこまで困らない程度には慣れてきたのですが、ベクトルの微分 / ベクトルでの微分については騙しだましで来てしまったので大いにつまずきました…ということで、書籍にの内容というよりかその前段の基本的なところまとめておきたいと思います。
本記事で扱うのはテンソルを扱った場合の逆伝播計算に必要となる微分計算までで、実際に逆伝播したらどうなるの?はステップ41あたりの記事の時にまとめたいと思います。
なお、書籍によると
ここでは「ベクトル」に限定して話を進めます。ただし、この節で得られる結論(理論)は「テンソル(n階テンソル)」の場合にも、そのまま適用できます。
とのことなので、基本的にはベクトル~せいぜい行列までを扱いたいと思います。また、線形代数の基礎や(偏)微分については自分がつまずいたところだけのまとめになります。
※以下の数式一つ一つは外部情報参考にしたので合っているかと思いますが、説明の日本語や数式の関係性は「こういうことかな?」と自己流に解釈しながら記述したため間違い多発している可能性が高いです。
そもそもofそもそも論
そもそも分野がなんのか
地味にこれが一番困りました…テンソルを扱うので当然(線形)代数学だろうと思ったのですが、自分が理解できる情報だとベクトルや行列をあれやこれやするのが主題で微分には触れられていないか、触れられていても説明があっさりし過ぎていて「良く分からん」となりました。
線形代数も関わる内容ですが、それよりも解析学の中の、特にベクトル解析と呼ばれる分野の話みたいです(最初から最後までドンピシャの情報には当たらなかったので、実際には様々な分野が複合しているのでしょうが)。ネットの検索時や書籍を探す際、そっちの分野をあたった方が望む情報に辿り着きやすいかも知れません。
関数についての解釈を(自分の中で)広げておく
関数と言えば、といった感じで、「何かしらの入力を与えるとそれを変換して出力する装置」をイメージしていました。
この解釈もそう間違ってはいないと思うのですが、この時もし裏で「スカラを入力してスカラを出力する装置」というイメージも持ってしまっているのであれば、考えを改めなければなりません。
例えば以下のベクトルの内積計算を考えます。
この計算結果はで、スカラとなります。別の見方をすると、「ベクトルを入力に受け取ってスカラを出力する関数」が存在するということです。具体的に今回の例でいうと「(二次元)ベクトルを入力に受け取って、との内積を計算=スカラにして出力する」関数が作れます。
ここの頭を切り替えておかないと、例えば以下の様な記号の理解が難しくなります。
※は細字でスカラ、は太字でベクトルを表していることに注意してください。
以前の自分はこれを見ても「なんかよくわからんけどとりあえず偏微分してる」以上の情報を読み取ることができませんでした。しかし、頭の切り替えを行っていれば「入力にはベクトルを受け取って、スカラを出力する関数を偏微分しようとしているんだな」と把握できるようになります。
また、このイメージができると以下のイメージもできるようになります。
下線の情報が把握できた時点で図の黒字部分の情報がイメージできていることになります。そこから、「ベクトルに何かするとスカラになる処理と言えばベクトルどうしの内積では?」だと気付ければ、赤字部分を補完し「ベクトルどうしの内積計算を微分しようとしている」という部分もイメージできる様になります。
※ベクトルを入力に受け取ってスカラを出力する関数は他にも存在するかと思います。あくまで「可能性をイメージできる」というだけで、「決定できる」ではありません。
「そんなの当たり前じゃないか」(もしくは「全然違うぞ」)と思われるかも知れませんが、自分にとってはこの切り替えは以降の内容を理解するのにとても重要でした…
スカラ値関数とベクトル値関数
上述の気付きを得た時、「天才かも知れない」と思ったのですが、「ベクトルの関数」というのは解析学では初歩中の初歩の内容の様です。先ほどの例は出力がスカラだったので(多変数)スカラ値関数なのですが、出力がベクトルとなる関数には「ベクトル値関数」とちゃんと名前がついているそうです。
詳しくはこちらのサイト様をご確認ください。ちょっと考えればそういうものがあるとは気付くのですが、関数という分野とベクトルという分野が頭の中で融合しているのといないのでは以降の内容の理解力の差が激しいです。
本題
目次的なもの
本記事の最終目標は「ベクトル(テンソル)を使った逆伝播理解のための前知識取得」です。つまり、ゆくゆくは「計算グラフのどこかで入出力の片方あるいは両方がベクトルになる」場合を考えることになります。例えば以下の様なグラフです。
この逆伝播を理解するために、「ベクトル"を"微分する / ベクトル"で"微分する」方法について学ぶ必要がありますが、主語と目的語の関係によって計算が別物になることに気を付けて下さい。「スカラをベクトルで微分する」と「ベクトルをベクトルで微分する」では作法が異なります。(一般化した定義は同じなのでしょうが…数学素人には別物に見えます。)
「ベクトル"を"微分する / ベクトル"で"微分する」方法について理解するには、以下の順序で学ぶと個人的には理解しやすかったので、この順序に沿ってまとめて行きます。
【ベクトルをスカラで微分する】ベクトル値関数のスカラ微分の定義
高校で習った微分の定義と見た目は同じなので、素人でもそこまで混乱する内容ではありません。参考にしたのはこちらの名古屋大学の講義ノートです。
ベクトルが変数の関数としたとき、以下の様に定義されます。 ※という表記は数学的に正しいのか分かりませんが…がの関数だということを分かりやすくしたかったのと、右辺の表記と揃える意味で付けています。が意味する様に「が変数のという名前の関数」ではありませんのでご注意ください。
結局「が少しだけ変化したときにがどれだけ変化するか」です。成分で書くとより分かりやすく、が三次元ベクトルだとすると、以下の様にも表せられます。
どの様な計算を行えば良いかは書いてある通りでベクトルの各要素についてで微分すれば良いです。そう考えると当たり前ですが、ベクトルをスカラで微分したものの形状は、ベクトル(出力)と変わっていない(今回でいうと3次元ベクトル→3次元ベクトル)点を覚えておいてください。
続いてスカラをベクトルで微分するパターンについてなのですが、少し脱線(?)します。この全微分、次にまとめているgradと密接に関わっており、それらが分かっていると「ベクトルで微分」の意味合いが捉えやすくなるのでお勧めです。
全微分はこちらのYoutube動画が分かりやすかったです。例えばの全微分は以下で定義されるものです。
右辺は数ⅡBで止まっている身からするとパッと見てもただの記号にしか見えませんが、日本語にすれば難しくはありません。「のでの偏微分×方向の変化量 + での偏微分×方向の変化量」です。もっと一般化して書くと以下の様になります。
具体的なイメージは是非紹介した動画で掴んで頂ければと思いますが、イメージを強めるために理解しておきたいのは「左辺と右辺が表しているのはどっちもただのスカラ」ということです。やらなんやらが出てくるとちょっと身構えてしまいますが、要はこいつも1とか100とかのただの数値です。
がただの数値ということの補足として、(数学力の)次元が低い話をします。
という文字を見て何を思い浮かべるでしょうか。自分は平面上のが浮かびます。では、という文字を見たらどうでしょう。前までの自分はここで何もイメージできなくなっていました。あえて言えば「うわ~文字いっぱいの良く分からない数式が出てきそう」くらいです。
この気持ちを次の様に切り替えることが自分にとっては大事でした。からイメージできる「が決まったらの値が決まる何か」と同様、も「が決まったらの値が決まる何か」でしかない、というイメージです。
つまりなら、ならと、変数とは言え極論ただの数値を表しているに過ぎません。の括弧の中に何文字入っていようと、括弧の中には書かれていない文字の軸の値を表しているだけです。括弧の中が1文字なら2次元、2文字なら3次元をイメージし、3文字なら4次元…ここから先はイメージできませんが、とにかく大事なのは「括弧の中の文字の値が決まると、括弧の中にない文字の値が決まる」というイメージです。
改めての全微分の式を見ています。
は微分の式で良く見る通り変化量です。何の変化量かというと、でもでもない別の何かー何かは良く分からないけど、とりあえずとの値が決まれば値が決まる何か―です。何でも良いのですがここではとしましょう。つまりです。
右辺は先ほど説明した通りですが、それぞれの偏微分×変化量の和です。「偏微分=各要素が個別にちょっと動いたらはどれだけ変化するか」に「変化量=各要素がどれだけ変化したか」を掛けて和をとっているので、上の数式は「もどっちもちょっとだけ変化したら、合わせてがどれだけ変化するか」を表しています。図で具体的にみるとこんな↓感じです。
難しいのは、みたいな形で数式が与えられていればとの関係がグラフに書けるのでが変化したときにがどんな感じに変化するかを直感的に理解することができます。しかし大学数学教育ではそんな優しいことは稀なようで、「とは関係していることだけは分かってるけどどんな関係性かは知らないよ」という感じですので、形から入ることができません。また更に、「に関係する何かがあるよ」という感じで関係する何かの名前すら教えてくれません。
この辺り全然イメージができず長いこと苦しんだのですが、少しずつ数式が読める様になるにつれて頭の中でなんとなーく数式が何を表しているのか分かる様になってきました。まだまだせいぜい大学1年次?くらいの数式しかイメージできませんが、慣れていきたいと思います…
【スカラをベクトルで微分する】grad
脱線が長かったですが話を元に戻して続いてgradです。後の節でも改めてまとめますが、先にネタバレしてしまうとここでやることは「ベクトルで微分」そのものです。gradについての詳細は相変わらずヨビノリさんの動画が分かりやすかったのでそちらご確認ください。講義中に出てくる難しい言葉テイラー展開の講義動画もあります。またもし「内積って数式は知ってるけど結局なんだっけ…」となったら「内積とは」で調べると素晴らしく分かりやすい説明がいっぱい出てきますので是非。
動画の概要をまとめます。gradはスカラ場に定義される演算子で、スカラ場のイメージとしては気温が該当するとのこと。上下左右前後の空間での位置が決まれば一つの気温が定まる様に、のが定まればとは別のひとつのスカラ値が定まるような場をスカラ場と呼びます。このとき、
はの変化が最大となる向きを表します。
出力であるスカラを要素をもつベクトルで微分していると考えられるので、「スカラのベクトル微分」そのものですね。
ここからしばらく、残念ながら自分の中でも全然腹落ちしていない超解釈を記載します。自分でも「間違ってそう」と思っているので、変な先入観を入れたくない場合は次の「全微分とgradの関係」まで飛ばしてもらった方が良いかも知れません。いちいち「違うかもしれない」と触れるのも文章が長くなるので、断定的には記していますが全然違うことを記載しているかもしれません。
自分の理解力が低く間違った解釈をしているかもしれない中引用するのも作者の方に申し訳ないのですが、こちらの九州大学の講義ノートとこちらのサイト様を参考にさせて頂きました。
さて、gradはスカラ場に定義されるとしての三次元空間に限定して考えていました。「せっかくだからn次元空間でも同じことできないの?」と思いますが、答えはイエスです。ここで注目したいのは「スカラ場」というものと、参考動画には出てこなかった「座標系」という概念についてです。
(数学に強い人は違うのでしょうが私は)スカラ場の説明を聞くとどうしても軸がまっすぐに直交して軸となっている空間をイメージしてしまいます。そうすると3つの要素が決まると一点が定まってしまうので、求めるスカラ値を除くと最大でも3つの要素についてしか考えられない気がします。
今考えている様な、昔から慣れ親しんだ直交するまっすぐな座標を使う方法は「デカルト座標」と言い、わざわざ名前が付いていることからお察しの通り、実は座標の取り方=点を一意に定める方法は他にもあります。我々が空間をイメージして何をしたいかというと極論は点(もしくはその集合である線とか面とか立体とか)の位置を一意に表すことで、方法は何でも良いのです。
デカルト座標に慣れてしまっている自分としてはもうその存在の意味すら分からないのですが、「軸は直交していなくても良いし、なんなら曲線でも良いでしょ」とでも言わんとばかりの座標も存在します。
こうなってくると軸は無限に引けますし、スカラ場を三次元に限定して考える必要もなく、4つ以上の要素についても同様に考えることができます。4個でも10個でも100個でも、とにかくそれらの要素が決まったときにそれらとは別のひとつのスカラ値が決まるのであれば、それはスカラ場と呼べそうです。
つまり先ほどの例を改変するとに対して、
も同様に定義できるのです。
※特に言及せず行ベクトルを「これがgradだ」という情報があったり、「転置したものをgrad(勾配ベクトル)と呼ぶ」とわざわざ指定した情報があったりと、転置が必須なのか分かりませんでした…とりあえずここでは参考動画に合わせて行ベクトルで書きます。
※この節は前までの節と同じことを言ってる部分が多いですが、関係性を確認するという意味で改めて書いています。迷子になりませぬよう…
全微分の定義式をおさらいします。
要素どうしの積の和ですので、考えて見ればベクトルの内積で表せそうです。すなわち、
と変形でき、はgradfとまったく同じです。つまり、全微分はの変化が最大となる向きであるgradとその時どれくらい変化するかに分解することができます。
更に、方向だけに注目してー方向ベクトルのノルムを1として―内積を別の形で表すと、
であり、これが最も大きくなるのはのときです。
機械学習や最適化の文脈ではこの方向だけ()が大事です。最急降下法を思い出して欲しいのですが、考えるのは「どっちに行けば一番値が下がるか」だけです。そっちの方向に進んだときに「どれだけ値が下がるか」には注目していません。これは、変化の大きさは現在位置に左右されるからです。(同じ微小量移動した時、一気に値が減るところもあれば、少しずつしか変わらないところもあるが、とにかくその点からは最急降下方向に進むしかない。)
【スカラをベクトルで微分する】スカラ値関数のベクトル微分の定義
gradそのものです。対象となるスカラはそのままスカラ場で求まるアウトプット、微分するベクトルには複数の要素をベクトルとしてまとめただけです。
ベクトルを変数にとり、出力がスカラ値となるスカラ値関数をについて微分すると、
は先ほど記載したようにやなどと表現されることがありますが同じ意味です。またgradの他、勾配ベクトルと呼ばれます。
ここで注目しておきたいのは、スカラをベクトルで微分したものの形状は、ベクトル(入力)と変わっていないという点です。同時に、「ベクトルをスカラで微分」した結果は出力であるベクトルと同じ形状だったことを思いだしておいてください。
【ベクトルをベクトルで微分する】べクトル値関数のベクトル微分の定義
スカラ値関数のベクトル微分と似た形になります。ベクトルを変数にとり、出力がベクトル値となるベクトル値関数のについて微分の微分は以下の式で定義されます。
出力との両方がベクトルの場合、その微分は上記の様に行列の形になります。この行列はヤコビ行列と呼ばれます。
【ベクトルをベクトルで微分する】ヤコビ行列とgradの関係
gradの式を思い出します。
これとヤコビ行列を見比べると、ヤコビ行列の行方向成分がgradだと分かりますので、ヤコビ行列は以下の様にgradが複数個縦に並んだ形で書くこともできます。
すなわち、gradはのヤコビ行列とも言えます。
また、そもそもgradが何だったかを思い出すと、「スカラ値の変化が最大となる向き」を表すものでした。ヤコビ行列もそれに対応しており、「ベクトル値の変化が最大となる向き」を表していると言えます。なぜ行列がベクトルの変化に関係するのかがピンとこない場合は、こちらのヨビノリさんの動画をご確認ください。
最後に
以上で一応目標としていた「ベクトル"を"微分する / ベクトル"で"微分する」まではたどり着けました。本当はここまで学んでも書籍のステップ37の補足の入口に立ったくらいで、このあと「要素ごとの演算だと仮定すると~ヤコビ行列は対角行列で~」と本題が続くのですが、それはあくまでこれまでDeZeroに実装した関数に対する話でこれから実装する関数の逆伝播にはまた別の要素が出てくるのでその時にまとめたいと思います。
書籍の「要素ごとの演算だとヤコビ行列は対角行列」については英語ですがこちらが参考になるかと思います(日本語の説明見つからなかった)。この内容全然身についてはいないのですがもう疲れたので次に進みます…