#0009

知識ゼロで機械学習・AIを理解するために必要なニューラルネットワークの基礎知識

2018-04-16 21:22 2018-05-29 20:58 "ゆざ"

プログラミング未経験の私がPythonの機械学習で手書き文字の識別を行うまで」というテーマで、機械学習の知識ゼロな非エンジニアの人が途中で挫折することないように、わかりやすく伝えることを意識して話していきます。

この記事を読めば、あなたもきっと「ニューラルネットワークとは、何か」を人に伝えらることができるくらい理解することができるはずです。

スポンサーリンク

なぜプログラミングをはじめたのか?

はじめまして、ゆざです。株式会社PLANのインターン生です。まずは、本題に入る前にそもそもなぜ未経験者の私がプログラミングを始めたのかをお話したいと思います。

最初はエンジニアになりたかったからではなく、漠然と「企業で働くってどんなこと?」「ITベンチャー企業とは?」を実際に働きながら知りたいと思い、インターンシップに応募したのが、株式会社PLANと出会ったきっかけです。

株式会社PLANはWebメディアサイトが最も大きい事業だったので、最初はライターとしてメディアの記事を書いたり、記事の大きな枠組みである専門ページを作る側のエディターとして、構造表と呼ばれるWebページの設計図を作る仕事をしていました。

新しいことをするのは、とても楽しくてインターンとしての仕事にやりがいを感じていました。

しかし、半年後、自分の将来について改めて考えた時に、「自分の考えたアイディアが自分の手で実装できるのは、エンジニアだけではないのか。自分はそんな人になりたい。」と思い、プログラミングに対してすごく興味を持ち、独学でPythonや機械学習の勉強を始めました。

そんな中、ちょうど同じタイミングに株式会社PLANのCTOであるみやびさんから「一緒にエンジニアのほうでインターンやってみない?」と声をかけていただき、私にとって絶好のチャンスと思い、二つ返事でお話を受けさせてもらいました。

そして、晴れて私のエンジニアとして道がスタートしました。本当に運と縁に恵まれました。(※ただし、この時点ではPythonとPHPの違いもろくにわからない状態。笑)

プログラミング未経験の私が何をつくったのか?

まずはじめに作ったのは、Pythonを使って機械学習で0から9の手書き文字を認識する識別器を作りました。

これは、MNIST(エムニスト:Mixed National Institute of Standards and Technology database)と呼ばれる0から9の手書き文字が無数に含んだデータセットを用いて行う機械学習の基本的な学習モデルです。

簡単に言うと、手で書かれた0-9の10コの数字から1つ、例えば「8」を作成したモデルに入ると、「あなたが書いた数字は"8"です。」といった判別結果を返してくれます。私が作ったモデルは、MNISTを用いて識別率96%を得ることができました。

全くコードが書けない状態から自分の手で書いた数字を入力すると、正しい値が返ってくるということに私はとても感動を覚えました。皆さんにも是非そのような経験をこの記事を読んで、手を動かすことによって得られたらいいなと思っています。

機械学習で最も重要な基礎であるニューラルネットワーク

では、機械学習をプログラミングで実装する前は、機械学習・ディープラーニング・AIの基礎である最も重要なニューラルネットワークというアルゴリズムの手法について説明していきます。

ココでは、高校数学の知識が少し必要になってきますのが、もし途中で完全に理解できなくてもスルーしてください。機械学習の権威であるスタンフォード大学のAndrew Ng教授も細かな理論ではなく、大枠で理解することが最も大切であると述べていますので安心して下さい。

ニューラルネットワーク(neural network)とは

ニューラルネットワーク(neural network)とは、人間の脳内にある神経細胞(ニューロン)とそのつながりを計算機上のシミュレーションによって、表現することを目指した数学的なモデルのことです。

このモデルは、入力層隠れ層出力層という3つの階層に分かれてます。そして、重み(W)がそのニューロン間のつながりの強さを示します。

1つ1つのニューロンは単純な仕組みですが、それを無数に組み合わせて、この重みを変更することによって、複雑な関数の近似が行うことができます。

ココまでが一般的なニューラルネットワークの解説ですが、これで理解できた人は、かなりの天才です。

99.9%の方が何のことかさっぱりだと思いますし、むしろそれで構わないので安心して下さい。それでは、次にもっと簡単な例を挙げて、ニューラルネットワークの本質に迫っていきます。

簡単な例を用いたニューラルネットワークの本質

上記のグラフは横軸を部屋の大きさ、縦軸を住宅価格としたものです。そして、緑の点が実際のデータです。グラフの左下の点は、部屋が小さく価格が安い物件を表しており、右上の点は、部屋が大きくて価格が高い物件を表しています。

この緑の点(実際のデータ)に基づいて住宅価格を予想するための赤い線をキレイに引くことがニューラルネットワークの役割であり、本質です。

次にもっと多くのデータから住宅価格の予測を行っていきます。バリアフリー・間取り・立地条件・築年数・コンビニ/学校が近いをいう5つのデータを使います。

直感的なニューラルネットワークの役割

ここから、バリアフリーで部屋の数が豊富であるなら、家族で住みやすいということがわかったり、立地条件が交通便がいい場所なら、通勤・通学に便利で、新築で耐震工事がさせていて地盤の強い地域にあれば、地震にも安心といったように、さまざまな要素がデータから読み取れます。

そして、そのような要素を総合的に評価することによって住宅価格が決定します。

ニューラルネットワークも同様でデータをインプットして、そこから特徴を抽出して価格を予測することができます。

さらに、ニューラルネットワークには、中間にある隠れ層(hidden-layer)の要素(家族で住みやすいetc.)は自ら発見するため、こちらで見つける必要はありません。

ここまでの話が理解できれば、ニューラルネットワークの基本的な役割を理解したと言っても過言ではありません。それでは、次により実践的な例を踏まえてニューラルネットの構造について解説していきます。

図でわかるニューラルネットワークの構造

イメージしてほしいのは、0から9の手書き文字を認識してその数字を当てる判別装置です。

この判別装置が数字を当てるまでには、

  • データを入れる(入力層)
  • 特徴を抽出する(隠れ層)
  • 予測値をはき出す(出力層)

という段階を踏みます。隠れ層では行列計算と活性化関数を用いて特徴量を抽出します。

1. 手書き文字をインプットする(入力層)

まずは、入力層へ手書き文字の画像をインプットします。

手書き文字のデータは、28*28pixelのグレースケールの画像(1つのpixel値は0-255の値で示す)で、この画像を入力層に入れるには、28*28pixelの正方形の画像をバラバラにしなければいけません。そのため、画像を28*28=748個の縦長のpixelの列に変換します。

ニューラルネットワークにおける入力層の仕組み

上の図の左上にある画像の赤いpixelをx1とおくと、784個すべてのpixelをx2,x3,x4,...,x748といったような値に置き換えることができます。

2. 入力層から隠れ層への伝搬(隠れ層)

そして、次に入力層から隠れ層へデータが伝播されます。入力値xは、このニューロン(白マル)間の繋がりの強さを示す重みWと掛け合わせれ、伝播します。

ニューラルネットワークにおける隠れ層の仕組み①

入力層にある1つのニューロンは、隠れ層にある全てのニューロン(今回は100個)に繋がっており、全てのxに対してWを掛け合わせます。

つまり、1つの隠れ層には入力層のニューロン全て(784個)からの繋がりがあり、そして、Wとxが掛け合わさせた784つの値の合計とバイアスbを加えて、hという隠れ層での値を生み出します(上の図の中央上部)。

バイアスbは、よりデータにばらつきを加える役割として使用します。

3. 活性化関数の活用(隠れ層)

しかし、このままのモデルでは、h=Wx+bという直線(線形)だけしか表すことが出なくなってしまい、表現できるモデル(関数)が少ないです。

そのため、活性化関数と呼ばれる関数にこのhを代入します。

ニューラルネットワークにおける隠れ層の仕組み②

今回使用する関数は、シグモイド関数といって代入した値は0から1の間に収まるような値にしてくれる活性化関数です(z=θ(h):θはシグモイド関数を示す)。

このステップにより、ニューラルネットワークは自ら特徴を抽出して、複雑な関数近似を表現できるようになります。

4. 隠れ層から出力層への伝搬(出力層)

次は、隠れ層から出力層への伝播です。

これは、先程の処理と同様にWとzが掛け合わさせた値の合計にバイアスbを加えることでoutという値を生み出します(下の図)。

ニューラルネットワークにおける出力層の仕組み①

この出力層では、0から9を表現するために10つのアウトプット、つまりy1からy10が最終的な出力としてあります。

y1は入力層に入力した画像が「1」である確率を示しており、y2は「2」である確率を表しています。

したがって、y1からy10を全て足した値は1(0-9の確率を全て合わせて100%)である必要あるため、そのような値になるように上手くoutを調節する必要があります。

その役割として、ソフトマックス関数(softmax)と呼ばれる関数を使用します。

ソフトマックス関数は、出力を0-1の値に落とし込み、そして、出力された値の合計が1となるように値を返してくれます。

よって、最終的にほしい出力値yは、outをソフトマックス関数に入れることで求めます。これで、y1からy10の中で最も確率が高い値を予測値として得ることができました。

5. インプットからアウトプットまでの処理をおさらい

ここまでの内容をまとめると、以下のようになります。

ニューラルネットワークの全体構造

一度に全てをイメージすることは大変かもしれませんが、処理を分割しながら考えることで理解しやすくなるはずです。1つ1つやっている処理自体は決して難しくないので、どのような処理が行われているかをいくつかに分けて理解していきましょう。

どのやってニューラルネットワークは学習するのか

ここまでニューラルネットワークの構造について説明してきましたが、このままでは、まだ正確な予測をすることができません。なぜなら、まだこのモデルは学習を行えていないからです。

そのために、次はニューラルネットワークが「どのように学習するのか」、「どうやって予測する精度をあげていくのか」についてお話します。

結論から言うと、モデルの精度を高めるためには、予測した値と実際の正しい値との誤差を最も小さくすればいいです。

では、どのようにその誤差を小さくしていくのでしょうか。それは、誤差を最小にするように重みWとバイアスbを更新していきます。

損失関数を用いて誤差を最小にする

まずは、予測値と正解ラベルとの誤差を評価するために損失関数を用います(下の図の中央部)。

これは、誤差が大きくなると値は多くなり、小さくなると値も小さくなるという特性を持っている便利な関数です。

ここでの細かい数学的な理解は、ここでは必要ありません。肝心なのは、この関数をどうやって最小にするかということです。

この関数は、Wとbを更新する値、変数として、実際に下の図の左上部のように3次元的に考えることができます。

ニューラルネットワークにおける学習方法

スタートでは、この図の赤い点のようにL(誤差)が高い位置にありますが、この赤い点をコロコロとWとbを更新することで動かしていき、最終的にの描かれている最も低い位置、つまり誤差の最小となる地点を目指していきます。

実際に計算をして、それを検証するには、3次元的に考えていくと理解が難しくなるので、ここでWとLのみの2次元的に見ていきます。

これにより、上の図のように放物線のようなグラフがみられます。それでは、どのようにこの赤い点を動かしていくかを少しだけ数学的な観点から説明していきます。

そこで重要になるのが「微分」です。微分と聞いただけでアレルギーが出る人がいるかもしれませんが、微分の本質はグラフの傾きを表しているだけです。なので、〇〇を✕✕で微分するといったらその地点でのグラフの傾きに注目してください。

まず、スタート地点でどれだけグラフが傾いているかを示すため、WでLを微分した値を出します(dL/dWはWでLを微分するという意味)。この地点では、グラフは右上向きを向いているので、dL/dWはの値となります。

そして、Wを新しい値に更新するためにW(新しい)=W(古い)-α*dL/dWという計算を行います。αは学習率を表しており、どのくらいの割合で更新をするかを示してます。つまり、αは任意の正の値が入り、dL/dWも正の値なのでWから正の値を引いたことになり、この計算ではW(新しい)はW(古い)により小さな値に更新させました。

このことによって、グラフの赤い点も左下に移動しました。つまり、誤差を小さくなるようにWが修正させたことが、ご理解いただけたのではないでしょうか。これを繰り替えることによって、誤差が最小になる地点に到達します。

今の説明では、重みWだけだったのですが、バイアスbも同様にして更新していくことができるので、b(新しい)=b(古い)-α*dL/dbという式で更新を行うことができます。

ここまで、理解するまでにかなりの労力を要したと思いますが、これが軸となるニューラルネットワークによるモデルの学習プロセスです。

複数のデータで誤差の最小にするためのコスト関数

この段階では、1つのデータにおいてW,bに対する誤差を最小にする動きでしたが、実際は複数のデータを用いるので、次はそこだけ簡単に説明していきます。

コスト関数を用いた誤差最小法

先程の説明との違いは、損失関数をベースとしたコスト関数を使用するという点だけです。

コスト関数とは、下の図に書かれている数式にあるようにデータの総数m個分の損失関数(オレンジの部分)を足して(青の部分)、その値をmで割る(緑の部分)、要はデータ1つ分の誤差平均値を計算します。

一見難しそうですが、先程の損失関数との違いは、データを1つ使用しているか、複数のデータを使用して平均値を使用しているかだけです。

なので、あまり難しく考えすぎないで下さい。もし、コスト関数を使ったとしてのW,bの更新する方法は全く同じで、出てくる値が配列として得られるか、単一の数字として得られるかの違いのみです。

モデルを更新するための誤差逆伝播

そして、最後に1つだけ伝えたいのが、誤差後ろから順番に更新させていくということです。モデルを更新するための誤差逆伝播法

順方向で入力させたデータは、ニューロンの繋がりを通って入力層・隠れ層・出力層を経て、予測値としてはき出されます。

その予測をより精度を高めるために、後ろから順番にW,bを先程の示した数式を使って更新していくという流れです。

この後ろから前に戻ってくる流れのことを誤差逆伝播と呼び、これを繰り替えることによって精度の高い予測が実現します。

以上が、ニューラルネットワークの仕組みです。

今回のまとめ

今回は、「プログラミング未経験の私がPythonの機械学習で手書き文字の識別を行うまで」の前半として機械学習・AIを理解するために必要なニューラルネットワークの基礎知識をお伝えしました。

ここまで、私の拙いはじめての記事を読んでいただき本当にありがとうございました。

この記事を読んで少しでもニューラルネットワークとは何かを理解する手助けになれてたら幸いです。以下に今回の記事を簡単にまとめます。

  1. ニューラルネットワークは、住宅価格を予測するためにキレイに曲線と書くことと同じ。
  2. ニューラルネットワークの構造は、入力層隠れ層(全てのW*x足すbをした値を活性化関数に入れる)・出力層(全てのW*隠れ層から出てきた値足すbをした値をソフトマックス関数に入れる)でできている。
  3. 重みWとバイアスbを更新することでモデルは学習する。
  4. 順方向の伝播と誤差逆伝播を繰り替えすことによって、学習していく。

次回は、より実践的に私が書いたコードを見ながら、Pythonによる機械学習で手書き文字(MNIST)識別について解説していきます。

>>後半:MNIST実行環境の準備から手書き文字識別までを徹底解説はコチラ

また、AnacondaでのTensorFlow環境構築と基礎的な使い方を先に読んでおくと基本的なライブラリの使い方がわかるのでコードの理解が早いかもしれません。

この記事を書いた人

学生Webエンジニア PLANインターン生 PHP Laravel Python HTML CSS JS

【名前】 "ゆざ"

【関連】 株式会社PLAN / MIYABI Lab / Tmeet(twitterユーザーマッチングサービス) /

【MIYABI Lab運営】23歳/同期がト◯タやMicr◯softに就職する中、ベンチャーに未経験でWebエンジニアになるのを選んだ脳科学専攻の理系院生◆人見知り日本縦断◆機械学習/Web歴5ヶ月

Twitterやってます

最新の技術ブログはこちら