PyLearnSelfNN 01: [理論編] 深層学習の基礎1

0. 深層学習の現状について

 最近、深層学習(深層化したニューラルネットワーク)が、様々な企業、大学で流行しています。また現在は、理論を理解せずとも、Scikit-learn、TensorFlow、Kerasなどを利用して、サッと深層学習を実装できるような時代になってきました。頭のいい人たちが、理論を理解していない人たちでも、深層学習を実装できるようなライブラリ、モジュールを作ったためです。

 これは大変便利なことです。なぜなら、1から深層学習のプログラムを組むのは、結構大変なためです。この便利なライブラリのおかげで、簡単に深層学習を組むことが可能になりました。端的にいうと、プログラムに慣れている人なら、一ヶ月勉強すれば、深層学習の実装は可能です。昔はむずかしい数式を読まないと実装できなかったので、深層学習とは限られた一部の研究者にしか扱うことができなかったわけですが、今や誰でもできるような技術になりました。したがって、深層学習を実装できることの優位性が下がりました。他のエンジニアや研究者と、あまり差がつかないのです。現在であればまだまだできない人もたくさんいるので、下がったとはいえだいぶ大きな優位性がありますが、10年後はどうでしょう。カラー画像をモノクロ画像に変換するような簡単さで、深層学習が実装できる世の中になるかもしれません。自慢もクソもない世界です。これは深層学習に限りません。便利なものとは、一般人でも使えるように社会が整備されていきます。

 では深層学習をやっても意味がないかというと、そんなことはありません。現状であればまだまだ深層学習を実装できるエンジニアが少ないので、人材獲得の競争になっています。でも、それよりも激しい奪い合いになっているのは、理論を理解した深層学習のエンジニア・研究者です。この理由は3つあります。

1つ目の理由:

 深層学習は発展途上の技術であるため、まだまだ未知の可能性を秘めています。これを明らかにする競争が起きているためです。例えば、NECは少ないデータ数で従来の深層学習に匹敵するモデルを作成するアルゴリズム、富士通は世界一高速に深層学習を構成するアルゴリズムを作りました。こんな感じで、これらを実現してプレスリリースを行うと、莫大な顧客を獲得することができます。この研究は、誰かが用意してくれるライブラリを使うという感覚では、決して不可能です。理論を理解し、緻密に数式を設計しなければいけません。学生の皆さんが直ちにこの土台に乗れるわけではありませんが、理論と実装のどちらも勉強したというアピールができると、就活で強い気がします。

2つ目の理由:

 深層学習に限らず、新技術というのは、儲けを独占できる大チャンスです。例えば、画像からの物体認識技術が十分に普及していなかった頃に、それを実装できるエンジニアがいれば、その企業にソフトウェア開発の依頼が殺到しますし、他の企業ができないわけですから、高額な値段もつけられます。でも今は、物体認識技術なんて画像処理に長けた企業ならどこでもできるので、そんなに価値はありません。それで、新技術などは(英語の)学術論文などで報告されます。論文で報告されて5年くらいたたないと、ライブラリは整備されません。論文に記載されている、おそらく難解な理論をあなたが読めて、実装できるならば、その技術を独占することができるというわけです。うまくすると、大変なビジネスチャンスです。深層学習でトップを走る大企業のエンジニアのリストを見ると気がつくかもしれませんが、工学ではなく、理学の修士や博士を大量に抱えていることに気がつくかもしれません。これは、理学を学んだひとたちは、数式をきちんと読めるためです。理学をやれというわけではありませんし、深層学習に限りませんが、何らかの新技術がでたとき、誰でも使えるように環境が整備されるまで、あなたは待ち続けるのか?という、エンジニアとしての生き方が試される問題といえるかもしれません(必ずしも肯定することが正しいわけではありません。人の幸せは人それぞれなので…)。

3つ目の理由:

 今、深層学習を簡単に組めるようにするため、頭がいい人が色々なライブラリを作っていますが、それは汎用性を重視しているがゆえに、ある課題に特化したモデルは作りにくかったりします。例えば今は、画像から物事を解釈する深層学習は十分に整備されているものの、信号などはまだまだ少ないかもしれません。音声信号はできても、心拍信号だと難しいかもしれません。こんな感じで、ただ用意されているライブラリを使うだけでは、うまいモデルを作れない場合があります。この場合、自分できちんと理論を理解して組んだ方が良いことがあります。汎用的なものは多くの事例に適用できる可能性がある反面、特化型の課題にうまくフィットしない場合があるのです。

1. 数学について

 続いて、深層学習の理論をきちんと理解するための学習の流れについて説明します。いきなり深層学習の説明はしません。まず、数学を説明します。何でわざわざと思うかもしれませんが、ちょっとだけ、胸に手を当てて考えてみてください。小学校から大学に至るまで、色々な数学をやりましたね。関数、確率、微分積分、微分方程式、ベクトル、線形代数……など。これら、わかっていますか?

 例えば、$y=x^2$の微分は、$dy/dx=2x$ですが、これ、何かわかりますか?何らかの関数を定積分したら、10だとかそんな数値が出てきた。10って何かわかりますか?微分方程式を解いたら、関数が出てきた。その関数って、いったい何者ですか?

 よくわからないけど、決められたルールに基づいて、足し算や掛け算をたくさんしたり、アルファベットをずらしたという感覚ではありませんか?それ、ただの作業です。あんまり意味がありません。

 なお、こんなことをいう私も、数学が割と苦手です。したがってこの認識で正しいのかわかりませんが、私の場合、英語を日本語に翻訳するように、数式も日本語に翻訳しながら読みます。すると、わからないことはわからないのですが、そこそこわかるようになります。この感覚を大事にしながら数式を見ていってほしいと思います。

2. 斜体とローマン体、関数と写像

というわけで、数学からはじめます。でも、あれもこれもやりません。深層学習に繋げるために最低限の数学のみを行います。まず、斜体(斜めになった文字)とローマン体(斜めになっていない文字)について説明します。以下の式をみてください。


\begin{equation} y=sin(x) \end{equation}

一見サイン関数に見えますが、違います。何故ならば、斜体とは、変数を表すためです。この書き方をすると、 sとiとnを掛け算するという意味になってしまいます。したがって、$s=1, i=2, n=3$なら、$sin=6$です。こんなことにならないように、きちんと、


\begin{equation} y={\rm sin}(x) \end{equation}

と書きましょう。ローマン体を使用すると、変数ではなく、記号として解釈されます。斜体を使ったら、何かが代入される対象であることを覚えてください。sとiとnには、何かが代入されるわけではないですよね。そんなときは、きっちりローマン体です。もう一つ別の例をみてみます。


\begin{equation} t_i \end{equation}

$t$と$i$が斜体です。斜体は変数ですから、何かを代入できることになります。$t_i$にも、$i$にも、何かを代入できるわけです。したがって、


\begin{equation} t_{i=3} = 50 \end{equation}

こんなことが表現可能だよ、という意味になります。それで、


\begin{equation} t_{3} = 50 \end{equation}

も、同じ意味です。$i$を省略しています。これ、すでに$t_i$を上で定義しているから、$t$の右下には$i$があることが、約束されています。ですから$i=$が省略できるわけです。もしも$t_i$を定義せずに書くとわけわかんないのでダメです。使い方としては、$t_0, t_1, t_2, \cdots, t_N$みたいに、類似する意味のたくさんの変数を管理したいときでしょうか。

続いて、


\begin{equation} t_{\rm i} \end{equation}

について考えます。よく見ると、iがローマン体になっています。ローマン体は何かを代入するわけではない、記号でしたね。したがって、


\begin{equation} t_{\rm i} = 50 \end{equation}

という表記は可能でも、i の値を入れることはできません。i はローマン体ですから、変数ではないのです。何でもかんでも斜体にするwebの資料がありますが、きちんとルールがありますので、厳守しましょう。

何でこんなことから説明するのか?研究室に配属された以上、学会発表や論文投稿として、これまでにない新しい何かを報告するかもしれません。このときに、おかしな表記で式を書かれると、恥ずかしいためです。まあでも、手書きでノートに書くと、意識しにくいところです。

続いて関数について。関数というと普通に知っておいてほしいですが、思ったよりもおかしな理解をしている人が多いので、ここからはじめます。まず、


\begin{equation} y=f(x) \tag{2-1} \end{equation}

を、関数$f$といいます。これを見たら、xをfに入れると、yが返ってくるんだと翻訳してください。あれ、$f$って斜体だよね、何が入るの?と思うかもしれません。実はこれ、


\begin{equation} f: [0, 1] \mapsto (0, 1) \tag{2-2} \end{equation}

みたいな記号が入ります。初めて見る人もいるでしょうから、説明します。これを、写像といいます。写像とは、どんなものを入力すると、どんなものが出力されるのかという、約束事です。まず、矢印に注目しましょう。矢印の左側が入力変数$x$、右側が出力変数$y$の取り得る値の範囲です。入力側の取り得る範囲を写像$f$の定義域、出力側の取り得る範囲を写像$f$の値域と言います。

では、入力側について見てみます。$[0, 1]$と書いています。これは0以上1以下の実数を意味します。続いて、出力側にある$(0, 1)$ですが、こちらは0より大きく1未満の実数を意味します。四角いかっこだと「以上・以下」、丸いかっこだと「より大きい・未満」となるわけです。四角いかっこのみで閉じられた範囲を閉区間、丸いかっこのみで閉じられた範囲を開区間と言います。バラバラに使うことも可能で、例えば、$[3, 5)$は「3以上5未満の実数」となります。

この理解で、(2-1), (2-2)式を見ると、

  • 関数$f$はxが入力で、$y$が出力
  • 入力変数$x$は0以上1以下の実数しか入れられない
  • 出力変数$y$は、0より大きく1未満の数字しか返せない

てな感じで、読むわけです。このように写像関係を定義するのは、何事を理解する上でも大変重要です。例えば深層学習では、


\begin{equation} y = g(x) = \frac{1}{1+{\rm exp}(-x)}, \tag{2-3} \end{equation}

\begin{equation} g: (-\infty, \infty) \mapsto (0, 1) \tag{2-4} \end{equation}


という関数/写像$g$、シグモイド関数が登場します。マイナス無限大から無限大(つまり、あらゆる実数)を入力すると、0より大きく1未満の数値に変えてくれるのが、$g$の役割なのか。と読めるわけです。理論を読む上で、定義域と値域の範囲がわからないのは致命的です。書籍などで紹介された関数が有する意味が、よくわからなくなってしまうためです。

ところで、一点補足です。無限大とマイナス無限大を定義域、値域に含めるときは、その箇所は必ず丸括弧にしてください。無限大、マイナス無限大は存在しない数のためです。リミットの計算、例えば、${\rm lim}_{h \rightarrow \infty}$てな感じで書かれていますよね。これ、$h$は無限大にめっちゃ近い数値ですよという意味で、無限大とは言っていません。$h=\infty$などと書くと、無限大を許容してしまうのでアウトです。無限大は存在しないので、含めてはいけないのです。したがって、無限大以下、無限大以上などの表記は、許されません。無限大より大きい、無限大未満、という表記は許容されます。

そしてもう一つ注意点です。(2-3)式の後ろに、カンマがついていますね。数式とは、文章における名詞です。数式を数式だとは思わずに、リンゴやミカンのような名詞だと考え、前後の文章をつなげるとなぜ(2-3)式にだけカンマがあるのか、わかると思います。

続いて、関数の記法について。よく$f$や$g$が関数として扱われますが、


\begin{equation} a=b(c), \end{equation}

という表記も可能です。翻訳はできそうでしょうか。また、


\begin{equation} a=n_i(c), \end{equation}

も可能です。$i$は斜体なので、関数$n_0$, $n_1$を許容できるので、関数がたくさんあると身構える必要があります。当然、


\begin{equation} a=n_{\rm i}(c), \end{equation}

ならば、そんなことはありません。こちらの場合、関数は1個しかありません。

続いて、関数の利用について説明します。まず、


\begin{equation} y = a(x) = 3x, \tag{2-5} \end{equation}

\begin{equation} a: (-\infty, \infty) \mapsto (-\infty, \infty) \end{equation}


を見てみましょう。写像$a$は、実数を突っ込んだら実数が出てくるという意味です。実際、正しそうですね。このとき、


\begin{equation} y = a(x=2) = 3 \times 2 = 6, \end{equation}

という書き方が許容されます。関数の丸括弧の中にある入力変数$x$に、2を代入するという意味で、すると、実際に2が代入されるわけです。同じ意味として、


\begin{equation} y = a(2) = 3 \times 2 = 6, \end{equation}

もokです。ただし、事前に(2-5)式を書いていればです。$a(x)$とすでに約束している場合のみ、$a(2)$などという記法が許されます。(2-5)式を書かずに$a(2)$などを書くと、関数$a$の入力変数が何なのかよくわからないためです。

続いて多変数関数の場合について述べます。入力変数が複数ある場合は、


\begin{equation} y = f(a, b) \end{equation}

と記載します。この場合、$y=ab$だとか、$y=a+b^2$だとか、ともかく$a$と$b$を使って構成可能な関数を扱うことができます。したがって、


\begin{equation} y = f(a) = a + b \end{equation}

などは、意味がわかりません。こういうのはやめましょう。また特別な書き方として、


\begin{equation} y = f(x ; a) \end{equation}

のように、多変数をセミコロンで区切る場合があります。これは、関数$f$は$x$と$a$で構成されるけれど、その用途がちょっと違うと思う場合に、セミコロンで挟みます。例えば、中学生がよく扱う式として、


\begin{equation} y = f(x ; a, b) = ax + b \end{equation}

がありますね。$x$と$a, b$って、すべて入力変数ではあるものの、ちょっと意味が違いますよね。$a=1, b=3$のときの、$y=ax+b$のグラフをかけみたいな問題のように、誰かがあらかじめ$a$と$b$を与えたりする経験があると思います。このように、入力変数間の意味が分離されるとき、セミコロンで分けることがよくあります。なお、


\begin{equation} y = f(x, a, b) = ax + b \end{equation}

のように、セミコロンを使わないのも、当然okです。

続いて、集合との関係を説明します。中括弧を使うと、要素を並べた集合を定義できます。例えば、


\begin{equation} A = \{{\rm dog}, {\rm cat}\} \end{equation}

は犬と猫を要素に持つ集合です($dog$のように、斜体にしない理由はわかりますね?)。 集合は大文字のアルファベットで書くことが多いようですが、決まりというわけではありません。それで、


\begin{equation} b \in A \end{equation}

とかくと、$b$には犬か猫が入るんだな、ということになります。また、


\begin{equation} b \in A = \{{\rm dog}, {\rm cat}\} \end{equation}

という書き方も可能です。これは集合$A$と$b$の意味を同時に定義する例です。そのほか、


\begin{equation} b \in \{{\rm dog}, {\rm cat}\} \end{equation}

という表記も可能です。この場合、$A$は定義されませんが、$b$は犬か猫だ!ということはわかります。$\in$の使い方として、中括弧以外も扱えます。例えば、


\begin{equation} b \in D = [0, \infty), \end{equation}

\begin{equation} b \in [0, \infty) \end{equation}


は、bは0以上の実数だ!と読めるわけです。$[0, \infty)$も集合となります。写像に入れることも可能で、


\begin{equation} I = (-\infty, \infty), \end{equation}

\begin{equation} R = \{{\rm dog}, {\rm cat}\}, \end{equation}


\begin{equation} f_{\rm ml}: I \mapsto R \end{equation}


と書けば,関数$f_{\rm ml}$は、実数値を入れると犬か猫かを判定させるモデルであることになります。よく深層学習で画像を入れたら物体認識をしてくれるモデルがありますが、それは、こんな感じの写像関係を有することになります。また、上の写像関係は、


\begin{equation} f_{\rm ml}: (-\infty, \infty) \mapsto \{{\rm dog}, {\rm cat}\} \end{equation}

と書くこともできます。

問題2-1:

以下の意味を説明せよ。


\begin{equation} A = \{0, 1\}, ~~ B = [0, 1], ~~ C = (0, 1), \end{equation}
\begin{equation} a \in \{0, 1\}, ~~ b \in [0, 1], ~~ c \in (0, 1). \end{equation}

問題2-2:

関数$r$を、


\begin{equation} r(m, a) = 3m + a \end{equation}

と定義したとき、$r(2, 1)$はいくつになるか。

問題2-3:

関数$t$を、


\begin{equation} t(x) = x^2 \end{equation}

と定義したとき、その写像関係はどのようになるか。(2-4)式のように記述すること。

問題2-4:

今、集合$D$を、


\begin{equation} D = [0, 1] \end{equation}

と定義する。このとき、$a = D$, $b \in D$ としたならば、$a$と$b$は、集合・要素、どちらか?また、$a$と$b$は具体的にどんなものであるか、書き下せ。

問題2-5:

今、集合$E$を、


\begin{equation} E = \{dog, cat\}, a=3, d= 4, o=g=c=t=2 \end{equation}

と定義する。このとき、$z \in E$における$z$は、集合か、要素か?また、$z$にはいかなる値として考えれば良いか?

問題2-6:

今、ある関数$f$の写像関係が、


\begin{equation} f: [-\infty, 0] \mapsto (0, 1) \end{equation}

と定義されている。この表記として問題があるところは、どこか。

3. Min, Max, Argmin, Argmax演算について

深層学習に限らず、機械学習(さらにそれに限らず、統計も)では、Min, Max, Argmin, Argmax演算がよく出てきます。そんな難しくないので、とりあえず例題を見ながら説明します。例えば、


\begin{equation} y = {\rm Min}~f(x) \end{equation}

は、関数$f$の最小値を$y$に代入しますよ、という意味です。簡単なので、いきなり問題です。

***

問題3-1:


\begin{equation} y = {\rm Min}~x^2, x\in (-\infty, \infty) \end{equation}

と書いた場合、$y$はいくつか?

問題3-2:


\begin{equation} y = {\rm Min}~x^2, x\in [5, 8] \end{equation}

と書いた場合、$y$はいくつか?

問題3-3:


\begin{equation} y = {\rm Min}~x^2, x\in \{-1, 3\} \end{equation}

と書いた場合、$y$はいくつか?

問題3-4:


\begin{equation} y = 10 + {\rm Min}~x^2, x\in \{-1, 3\} \end{equation}

と書いた場合、$y$はいくつか?

***

これまでの理解力が問われますね。まあそれはともかく、正解できたら次に行きます。

この演算は、関数に対してだけではなくて、集合に対しても行うことができます。例えば、


\begin{equation} D = \{0, 1, 2\}, \end{equation}

\begin{equation} y = {\rm Min}~D, \end{equation}


とすれば、$y=0$となります。わざわざ集合を定義せずとも、


\begin{equation} y = {\rm Min}~\{0, 1, 2\} \end{equation}

という書き方も可能です。

Max演算については、関数あるいは集合の最大値を返すだけです。例えば、


\begin{equation} y = {\rm Max}~\{0, 1, 2\} \end{equation}

ならば、$y=2$となります。

続いて、Argminに行きます。これは、ある関数の値を最小にする$x$を返す演算です。例えば、


\begin{equation} z = {\rm Argmin}_x ~ f(x), ~~ f(x) = (x-1)^2, ~~ x \in [-2, 2] \end{equation}

としたとき、$x$の定義域に注意しながら、関数$f$が最小となるような$x$が、$z$となります。関数$f$の最小値ではなく、関数$f$を最小化する入力変数$x$ですので、注意してください。今回は$x=1$とすれば$f(x=1)=0$となり最小化されますので、$z=1$が答えになります。

ところで、Argminの右下に$x$がついています。これ、なんでしょうか。多くの場合、関数とは入力が多変数(例えば、$f(x, y)=xy$)になります。多変数関数を最小化する場合、Argminはその変数分返さなくてはいけません。この順番を明示的にするために、Argminの右下に変数をつけます。例えば、


\begin{equation} [c_{\rm opt}, b_{\rm opt}, a_{\rm opt}] = {\rm Argmin}_{c, b, a} ~ |(a-1)^2+b^2+c^3|, ~~ a, b, c\in [0, 1] \end{equation}

と書けば、「関数$|a+b^2+c^3|$を最小化するような$c, b, a$を、$c_{\rm opt}, b_{\rm opt}, a_{\rm opt}$とする」という意味になります。Argminの右下にある順番がミソです。

ところでこの左辺、四角かっこになっています。これ閉区間じゃなかったっけ?という声が聞こえてきそうです。ややこしいのですが、この四角括弧はベクトルで、閉区間ではありません。本来は使い分ける必要がありまが、世の中はあまり使い分けないので、使い分けないでおきます。

***

問題3-5:


\begin{equation} [x_{\rm opt}, y_{\rm opt}, z_{\rm opt}] = {\rm Argmin}_{a, b, c} ~ |(a-1)^2+b^2+c^3|, ~~ a, b, c\in [0, 1] \end{equation}

を日本語に翻訳せよ。また、その答えを求めよ。

問題3-6:


\begin{equation} [x_{\rm opt}, y_{\rm opt}, z_{\rm opt}] = {\rm Argmin} ~ |(a-1)^2+b^2+c^3|, ~~ a, b, c\in [0, 1] \end{equation}

と書かれると、なぜ困るか、議論せよ。

***

続いて、Argmaxです。これは、「最大化するような」となります。ですから、問題3-5の場合、


\begin{equation} [x_{\rm opt}, y_{\rm opt}, z_{\rm opt}] = {\rm Argmin}_{a, b, c} ~ |(a-1)^2+b^2+c^3|, ~~ a, b, c\in [0, 1] \end{equation}

は、「3変数関数$|(a-1)^2+b^2+c^3|$を最大化するような$a, b, c$を$[x_{\rm opt}, y_{\rm opt}, z_{\rm opt}]$とする」と読めるわけです。

***

問題3-7:


\begin{equation} \vec{v} = {\rm Argmin}_{a, b, c} ~ |(a-1)^2+b^2+c^3|, ~~ a, b, c\in [0, 1] \end{equation}

を求めよ(右辺は3つの数字を返すので、左辺はベクトルとしても記載可能)。

***

なお、pythonのnumpyで、最小・最大を求めることができます。数学とプログラムの括弧の形は、意味が違いますので、注意してください。

In [1]:
import numpy as np

# 集合Dの定義
# 集合を英語でSetと言います。これはリストですけどね。
Set_D = [3, 1, 5] 

# Min, Max演算
Min_D = np.min(Set_D)
Max_D = np.max(Set_D)

# 出力
print("最小: ", Min_D)
print("最大: ", Max_D)
最小:  1
最大:  5

Argmin、Argmaxもありますが、最小・最大値が格納されている配列番号を返すだけで、数学のものとはちょっと違いますので注意が必要です。

In [2]:
# Min, Max演算
ArgMin_D = np.argmin(Set_D)
ArgMax_D = np.argmax(Set_D)

# 出力
print("最小の場所: ", ArgMin_D)
print("最大の場所: ", ArgMax_D)
最小の場所:  1
最大の場所:  2

4. 簡単な予測モデルの構築と最適化

今、勉強時間からテストの点数を予測する式を作りたいとします。予測するモデルを作る基本的な方針として、「観測した結果によく当てはまる式は、いろいろな状況を予測できるだろう」と考えます。したがって、観測した結果をとりあえず入手せねばなりません。

このため、2人の結果を見ていました。

  • アリスは10時間勉強したところ、90点でした。
  • ボブは5時間勉強したとき、30点でした。
  • キャロルは8時間勉強したとき、85点でした。

これを、以下のように変数化してみましょう。


\begin{equation} x_{\rm alice} = 10, y_{\rm alice} = 90 \tag{4-1} \end{equation}
\begin{equation} x_{\rm bob} = 2, y_{\rm bob} = 30 \tag{4-2} \end{equation}
\begin{equation} x_{\rm carol} = 7, y_{\rm carol} = 80 \tag{4-3} \end{equation}

続いて、勉強時間$x$から得点の予測値$\hat{y}$を算出するモデルを、


\begin{equation} \hat{y} = f(x; a, b) = ax + b \tag{4-4} \end{equation}

とします。アリスの予測値$\hat{y}_{\rm alice}$を求めるには、$x=x_{\rm alice}$とすればよく、


\begin{equation} \hat{y}_{\rm alice} = ax_{\rm alice} + b \end{equation}

となります。そして、アリスの予測に対する誤差$e_{\rm alice}$は、実測と予測のずれを見ればいいわけですから、


\begin{equation} e_{\rm alice}(a, b) = \sqrt{(y_{\rm alice} - \hat{y}_{\rm alice})^2} = \sqrt{(y_{\rm alice} - (ax_{\rm alice} + b))^2} \end{equation}

となります。プラスのズレとマイナスのズレを強制するために、一度二乗してからその平方根をとるわけです(するとすべて、プラス側の誤差に変換されます)。また、$y_{\rm alice}$と$x_{\rm alice}$は既に値が定まっている定数でしたね?ですから、上の式は、$a, b$のみの関数となるので、$e_{\rm alice}(a, b)$と、2変数の函数となるわけです。こんな感じで3人の誤差を求めると、


\begin{equation} H = \{{\rm alice}, {\rm bob} , {\rm carol}\}, \end{equation}

\begin{equation} e_h(a, b) = \sqrt{(y_h - \hat{y}_h)^2} = \sqrt{(y_h - (ax_h + b))^2}, ~~ h \in H \end{equation}


とかけます。3人分の誤差ですから、3つの誤差があるわけです。3つも誤差があると、複数の予測モデルの中で、優劣をつけることができません。この対策のため、予測モデルの誤差の平均を計算します。これは、


\begin{equation} e(a, b) = \frac{1}{|H|}\sum_{h \in H} e_h(a, b) \end{equation}

となります。こんな総和の書き方知らないと言われそうです。総和記号は通常、$\sum_{i=1}^5$みたいに、$i$を1から5まで増やし、たす、という書き方をします。しかし考えてみてください。この書き方だと、$e_1$や$e_2$は参照できても、$e_{\rm alice}$などは参照できません。そのため、より抽象的な書き方として、上記の記載法があるのです。これは、集合$H$の要素を$h$として1つずつ参照しながら、$e_h$を計算していくという手法です。また、集合を縦棒2本で挟むと、それは集合の要素数となります。結果として、


\begin{equation} e(a, b) = \frac{1}{3}(e_{\rm alice}(a, b) + e_{\rm bob}(a, b) + e_{\rm carol}(a, b)) \tag{4-5} \end{equation}

と同じ意味になります。集合を利用した総和演算ができないと困ることが多々あるので、今後総和を計算するときは、なるべく集合を使ってみてください。

さて、誤差がわかったところで、誤差を計算してみましょう。

***

問題4-1:

(4-1)〜(4-3)式のデータに対しその予測値を、(4-4)式により求めよ。また、(4-5)式によりその誤差を求めよ。

***

この問題を解くと、誤差が求まりますが、$a$と$b$が残ってしまうの、わかりますね。それは当然で、(4-4)式で示した予測式は、$a$と$b$を決めないと、具体的な予測結果が定まらないのです。つまり(4-5)式で求める誤差$e$を、わざわざ$a, b$の関数にした理由は、誤差はこれらの変数に依存するためです。

では、どんな$a, b$が良いのでしょうか?

***

問題4-2:

関数$f$を、(4-4)式の定義とする。このとき、(4-1), (4-2), (4-3)式の誤差が低い予測モデルは、以下のうちどちらか。ここで述べる誤差とは、(4-5)式で定義される値とする。


\begin{equation} \hat{y} = f(x; a=1, b=20) \end{equation}
\begin{equation} \hat{y} = f(x; a=20, b=15) \end{equation}

***

これをきちんと理解した上で解くと、$e(a, b)$が低いほど、その$a, b$が優れていることがわかります。 では、最適な$a, b$とはなんでしょうか。答えは簡単で、$e(a, b)$を最小化するような$a, b$となります。これをきちんと定式化すると、以下のようになります。

***

予測モデル、


\begin{equation} \hat{y} = f(x; a, b) = ax + b \end{equation}

において、最適な$a, b$とは、


\begin{equation} e(a, b) = \frac{1}{|H|}\sum_{h \in H} e_h(a, b) = \frac{1}{|H|}\sum_{h \in H} \sqrt{(y_h - \hat{y}_h)^2} = \frac{1}{|H|}\sum_{h \in H} \sqrt{(y_h - (ax_h + b))^2} \end{equation}

において、


\begin{equation} [a_{\rm opt}, b_{\rm opt}] = {\rm Argmin}_{a, b} ~ e(a, b), ~~ a, b \in [r_1, r_2] \end{equation}

を満たす$a_{\rm opt}, b_{\rm opt}$である。また、これを用いた予測モデル、


\begin{equation} \hat{y} = f(x; a=a_{\rm opt}, b=b_{\rm opt}) = a_{\rm opt}x + b_{\rm opt} \end{equation}

が、最適な予測モデルとなる。

***

ここで定式化された問題を解くことこそが、予測モデルを作るということになります。深層学習だろうがなんだろうが、基本的にはこのように定式化が行われます。ここで、$[r_1, r_2]$という見慣れないものがありますが、これは、$a, b$の探索範囲を表します。厳密には$r_1=-\infty, r_2=\infty$とすべきですが、プログラムで探す場合は暫定的に値を決めねばいけません。

それでは、予測モデルを作ってみましょう。

In [38]:
# 予測モデル
def PredictionModel(x, a, b):
    y_hat = a*x + b
    return y_hat

# 誤差(実測値、予測値)
def Err(y, y_hat):
    return np.sqrt((y-y_hat)*(y-y_hat))

x = [10, 2, 7] # 3人の勉強時間
y = [90, 30, 80] # 3人のテスト特典

必要そうな関数と、集めたデータを入れてみました。$\hat{y}=5x+2$の予測モデルの場合で、10時間勉強した場合は…

In [39]:
PredictionModel(x=10, a=5, b=2)
Out[39]:
52

52点だそうです。まあ、$a$と$b$はてきとうに決めているので、デタラメです。 これではいけないので、いい感じの$a, b$を探します。以下、


\begin{equation} [a_{\rm opt}, b_{\rm opt}] = {\rm Argmin}_{a, b} ~ e(a, b), ~~ a, b \in [r_1, r_2] \end{equation}

をざっくり求めるプログラムです。探索範囲となる$r_1, r_2$は、-20と50にしてみます。

In [41]:
# a, bの探索範囲の最小、最大値
r1 = -20
r2 = 50

# r1 から r2 まで、0.1刻みの数列
# a, bにどんな数字を入れるかに関する、候補
# よくわからない場合は、printすること
s_a = np.arange(r1, r2, 0.1)
s_b = np.arange(r1, r2, 0.1)

# データ数
N = len(x)

# a, b を r1からr2までずらしながら、誤差を計算
rec_ab = []
rec_e = []

import time 
time_start = time.time()

for i in range(len(s_a)):
    for j in range(len(s_b)):
        
        a = s_a[i] # aに設定する値
        b = s_b[j] # bに設定する値
        
        e = 0 # 誤差の総和
        for k in range(N):
            y_hat = PredictionModel(x[k], a, b) # 1人分の予測値の取得
            e = e + Err(y[k], y_hat) # 1人分の誤差を、前の誤差に加算
            
        e = e/N
        
        # a, b, eを記録
        rec_ab.append([a, b])
        rec_e.append(e)
        
        # 分析中の結果を見たい場合は、コメントを外す
        #print("a=", np.round(a, 3), "/ b=", np.round(b, 3), " のときの誤差 ", np.round(e, 3))

time_end = time.time()
elasp_time = np.round(time_end-time_start, 2)
print("実行時間: ", elasp_time, " [秒]")
実行時間:  6.83  [秒]

探索結果が出てきました(下のprintのコメントを外す)。誤差が一番低いものが最適な$a, b$だったので、

In [42]:
res = np.argmin(rec_e)
print("誤差が最も低くなる a, b: ", np.round(rec_ab[res][0], 3), np.round(rec_ab[res][1], 3))
誤差が最も低くなる a, b:  7.5 15.0

となります。すなわち、


\begin{equation} \hat{y}= 7.5 x + 15.0 \end{equation}

が、アリス、ボブ、キャロルの点数を最も精度よく予測してくれるモデルであることがわかりました。予測と実測は、

In [45]:
a_opt = np.round(rec_ab[res][0], 3)
b_opt = np.round(rec_ab[res][1], 3)
print("勉強時間、テスト(実測)、テスト(予測):")
print(" アリス:", x[0], " / ", y[0], " / ", PredictionModel(x[0], a_opt, b_opt))
print(" ボブ:", x[1], " / ", y[1], " / ", PredictionModel(x[1], a_opt, b_opt))
print(" キャロル:", x[2], " / ",  y[2], " / ", PredictionModel(x[2], a_opt, b_opt))
勉強時間、テスト(実測)、テスト(予測):
 アリス: 10  /  90  /  90.0
 ボブ: 2  /  30  /  30.0
 キャロル: 7  /  80  /  67.5

という感じです。このように、Argmin演算を活用し、一番頭のいいモデルとは何か、数理的に定式化します。ここで述べた数理最適化の流れが、機械学習の基本になります。深層学習もこの考えを踏襲していますので、まずはこれが理解できなくてはいけません。

ところで、今回$a, b$を-20から50の範囲で、0.1ずつずらしながら調べましたね。ここで得た$e(a, b)$を可視化することで、最適を一目で見ることができるようになります。

In [46]:
from matplotlib import pyplot as plt

ax_A, ax_B = np.meshgrid(s_a, s_b)

e_ab = np.zeros([len(s_a), len(s_b)])
k=0
for i in range(len(s_a)):
    for j in range(len(s_b)):
        e_ab[i, j] = rec_e[k]
        k=k+1
        
plt.pcolor(ax_A, ax_B, e_ab.T, ) # a, b に対する 誤差 e(a, b)
plt.colorbar() # カラーバー
plt.title('Error value: e(a, b)')
plt.xlabel('a')
plt.ylabel('b')
plt.clim([0, 150]) # 色の最小・最大値(自分で調整)
plt.show()

設定する$a, b$と、そのときの誤差$e(a, b)$を可視化しました。$a$は5から13くらい?の範囲がいいんだなとか、$b$は-20から50まで、幅広くいい値があるなとか、そんなことがわかるわけです。

今回、$a, b$を、指定した範囲で、0.1刻みずつ変化させ、誤差$e(a, b)$を求めましたね。$a, b$を緻密に一つずつ、全部調べていることになります。

このような探索を、全域探索と言います。最も信頼性がありますが、同時に、最も時間がかかる方法です。ですから、探索したいパラメータの数が大きくなると、時間がかかるようになってしまいます。

$a, b$がいくつくらいが良い範囲なのかわかったところで、それとまるで外れている探索範囲で全探索を実施してみましょう。例えば、以下の問題です。

***

問題4-3: \begin{equation} [a_{\rm opt}, b_{\rm opt}] = {\rm Argmin}_{a, b} ~ e(a, b), ~~ a, b \in [-20, 0] \end{equation}

を求め、これに基づく予測式を構成せよ。

***

これを解くと、$a, b$の探索範囲が如何に重要かがわかります。

今回やったように、$a, b$などのパラメータを含む予測モデルを立て、実際にデータを集め、誤差を最小化するような$a, b$を発見する行為を、機械学習(の、教師あり学習)と呼びます。シンプルな予測モデルでしたが、ここが機械学習の第一歩です。今回のことをわからずに次に進むと、大変な目にあうので注意してください。

とりあえずこの辺でおしまい。

確認事項:

  • 斜体とローマン体の違い
  • $=$と$\in$の違い
  • 丸括弧()、四角括弧[]、中括弧{} の意味と違い
  • Min, Max, Argmin, Argmax の意味

プログラムわかんないんだけど?:

ここは機械学習の理論を解説する部分なので、プログラムの解説はしません。わからない場合は、プログラムを解説している部分をよく読んだり、Paizaラーニングで勉強したり、プログラミングを取得してください。

アリス、ボブ、キャロルとはなんなのか:

デイブ、イブとか、いっぱいいます。A, B, C, D, E...みたいに進んでいく人の名前です。情報工学分野で何かを説明するときに、よく出てきます。詳しくは、アリスとボブで検索のこと。