今日から始めるDeep Learning
こちらはeureka Advent Calendar 2016 13日目の記事です。
前回は田野さんの「go vet の shadow を知る」でした!
こんにちは。Pairs事業部の香取です。
現在、すでに音声認識や顔認識など様々な分野でDeep Learning(深層学習)が利用されていますよね。最近では、AlphaGoが囲碁の試合で欧州チャンピオンに勝利したことや、Deep Learningを用いた自動運転技術が実用化に向かっていることなどからも、着実にその研究が進んでいることが分かります。
そんな世間が注目している技術に関心を持たないエンジニアはいないでしょう。
しかし、なんとなく難しそうなイメージを持っていて、未だにその第一歩を踏み出せていない方は多いのではないでしょうか。または学習コストが大きすぎると感じて「来年こそは」と思っている方はいませんか。
今年中にDeep Learning入門を果たしましょう!
入門は難しくありません。
この記事を読んで、Deep Learningを駆使した独自AIを実装できるように準備をしていきましょう!
なお、この記事の目標は、みなさんがDeep Learningの理論の大筋を理解し、それを駆使した機能を自分で実装できるようになっていただくことです。
※以降を理解するためには以下の知識が必要です。
1次式、論理式、数列の総和(Σ)、微分、偏微分
Deep Learningの理論
実装に取り組む前に、Deep Learningがどのような技術なのか、その概要を示します。
初めに断っておきたいのは、ここでは理論の詳細な説明はしないということです。理由はDeep Learningを用いた実装をする上で、必ずしも理論の深い理解が必要ではないからです。少なくとも入門の段階では概要を理解しておけば十分です。
理論の完璧な理解は後回しでいい
(参照:機械学習をこれから始める人に押さえておいてほしいこと — Qiita)
※ここでは著書「ゼロから作るDeep Learning ――Pythonで学ぶディープラーニングの理論と実装」を参考に説明しています。こちらの本をご覧いただくとより理解が深まります。
1. パーセプトロン
初めはDeep Learningの基本単位となるパーセプトロンについてです。
パーセプトロンとは、いくつかの入力に対して0か1を出力することにより、入力を2種類に分類する(二項分類器と呼ばれる)ことができるアルゴリズムです。
しばしば以下のような図で表されます。
図の◯はニューロン(またはノード)と呼ばれます。
ニューロンは、→で与えられている重み(固定値)を乗算した結果を次(矢印の向く先)のニューロンへ送ります。受け取る側のニューロンは、送られたすべての結果の総和が限界値(固定値)を超えた場合にのみ1を出力します。この限界値をθで表すと、上図のyは次式で得られます。
以上がパーセプトロンに関する簡単な説明です。
このアルゴリズムを使ってどのような問題が解けるかというと、例えば論理積(AND)や論理和(OR)の論理演算です。
実際に、下図のように3つの固定値 (w1, w2, θ)
を適当な値に設定することで、出力yの値が右の真理値表に一致します。
なお、上で設定した値以外にも同様の出力をする固定値の組み合わせは無限に存在します。
さてここで、もう一度式(1)の条件式に注目し、x2について解いてみます。
ご覧の通り、x1に関する1次式となっています。(w1、w2、θは定数)
この式をグラフにすると以下のようになります。
◇が0、○が1を表していて、色を塗った領域はパーセプトロンが0を出力する領域です。
なお、このグラフは前にANDを表現するために設定した (w1, w2, θ)=(0.5, 0.5, 0.7)
を代入したもので、確かに色分けされた領域と真理値表が対応しています。
つまり、パーセプトロンが行っているのは、与えられた入力に対する計算結果がこの直線以下の値であるか、それより大きい値であるかという分類です。
以上で示したような入力層と出力層の2層からなるパーセプトロンは単純パーセプトロンと呼ばれます。
そして、この単純パーセプトロンには欠点があります。それは直線で区切られた線形領域しか表現できないことです。そのため、XOR(排他的論理和)のような1直線で分けられない問題を解くことができません。
しかし、この欠点は層を重ねることによって克服されました。
XORは例えば以下のような論理回路によって表現できます。
これと同じようにパーセプトロンを組み合わせることでXORを表現できるようになります。
赤色の部分をNAND(否定論理積)、青色の部分をOR、黄色の部分をANDの論理演算の役割を果たすパーセプトロンとしています。
このような3層以上で構成されるものを多重パーセプトロンと呼びます。
2. ニューラルネットワーク
さて、ここまででパーセプトロンによってあらゆる分類が可能であることを理解できたと思います。
次は、そのパーセプトロンを発展させたニューラルネットワークの説明に移ります。
ニューロンの繋がり方は多重パーセプトロンと変わりはなく、かなり大雑把に言えば、ニューラルネットワークは多重パーセプトロンに活性化関数というものを導入したものです。そのため、活性化関数を理解すればニューラルネットワークの主な機能を理解したことになります。
活性化関数とは、前のニューロンから送られた値の総和を出力の値に変換する関数です。
実は式(1)でも、内部で活性化関数と同様の計算が行われています。
これは、θを-bとおくと、次式で表すことができます。
このh(x)が活性化関数に当たり、0か1という出力の値へ変換しています。
ニューラルネットワークではこの活性化関数に、別の関数を適用します。
それによく用いられるものに次のシグモイド関数があります。
ここでは、シグモイド関数の詳細は重要ではないため省きます。重要なのはその連続性です。
以下の式(4)と式(5)のグラフを比較してみましょう。
式(4)は0か1しか返さないことに比べて、式(5)は0から1へ滑らかに推移しその間の0.428…といった実数値も返します。
このように出力が徐々に切り替わることによって、0か1に分類する際にどの程度0に近いか(または1に近いか)を評価できるようになるのです。
以上がパーセプトロンとニューラルネットワークの違いです。
3. Machine Learning(機械学習)
ニューラルネットワークが理解できたら、ここからはいよいよ機械学習の説明です。
まず、パーセプトロンの説明の中で、 (w1, w2, θ)=(0.5, 0.5, 0.7)
を設定してANDを表現したことを思い出してください。これは、ANDを表現するための適切なパラメータの一つに (w1, w2, θ)=(0.5, 0.5, 0.7)
があるということです。このように、ニューラルネットワークを用いて目標とする分類器を表現するには、そのための適当なパラメータを設定する必要があります。その適当なパラメータを絞り込んで探すという作業が機械学習で行われていることです。
そして、機械学習は大きく次の2種類に分けられます。
- 教師あり学習
- 教師なし学習
教師あり学習
入力と正解をセットにした教師データを与え、入力に対する出力とその正解の差を小さくしていくものです。
音声認識や画像中の物体認識などで利用されます。
(引用元:ImageNet Large Scale Visual Recognition Competition 2014 (ILSVRC2014))
教師なし学習
入力のみを与え、データに対する特徴量抽出を行います。教師あり学習の前段階の特徴量抽出として利用したり、ある画像から抽出した特徴を別の画像に適応させて新たに合成画像を生成したりすることが可能です。
以下は、現実の風景を写した画像(A)に対して、ゴッホやピカソなどの絵の特徴を混ぜて新たな画像を生成した例です。
(引用元:New Neural Algorithm Can ‘Paint’ Photos In Style Of Any Artist From Van Gogh To Picasso | Bored Panda)
ここでは、比較的理解しやすい(と思う)教師あり学習に絞って、以下のフローに沿って説明します。
- ミニバッチ
- 損失関数を定義
- 勾配算出・重みの更新
1. ミニバッチ
ビッグデータほど膨大な量のデータのすべてから学習するには実行時間がかかり過ぎます。そのため、一般的に、全データからランダムに選択した一部のデータをもとに学習を行い、その結果を全体の近似とすることで学習に要する時間を削減します。これをミニバッチ学習と呼びます。
ここでもミニバッチ学習をするとして、初めに全入力データからランダムに100、1000などといった比較的短時間で学習が完了する量のデータを選択します。
2. 損失関数を定義
損失関数とは、ニューラルネットワークが教師データに対してどれだけ適合していないかを算出する関数であり、ニューラルネットワークの性能の悪さを示す指標となります。機械学習の目標はこの値を0に近づけることです。
すぐに思い付くのは次のように、出力と正解の差の絶対値を平均したようなものだと思います。
より高精度で、損失関数として最もよく用いられる関数として、次の2乗和誤差などが知られています。
式(7)のような、より精度良く性能の悪さを評価できる関数を適用することで、より効率良く、高精度の学習が行えるようになります。
3. 勾配算出・重みの更新
損出関数に対して、各重みに関する微分を行い、それぞれの重みを増やすと損失関数がどう変化するかを求める処理です。(偏)微分によって各重みに関する傾きを求めることを勾配を算出するといいます。
微分した結果が正の値なら、その重みを増やすと損失関数が増加し、
微分した結果が負の値なら、その重みを増やすと損失関数が減少することを意味します。
そして、微分した値の絶対値が大きいほど、その重みの変化が損失関数へ大きく影響するということになります。
つまり、微分した結果が正の値となる重みを小さく、微分した結果が負の値となる重みを大きくすれば損出関数を減少させることができるのです。
この工程では、求めた勾配をもとにこうした重みの更新を行います。
学習と予測
以上の工程を繰り返し行うことによって損失関数が0に近づき、精度が高くなっていきます。これが「学習」です。
そして機械学習の機能には、この「学習」というフェーズに加えて「予測」というフェーズがあります。
予測とは、ニューラルネットワークが未知の入力に対して何らかの出力をすることです。最適に学習が行われることによって、高い精度の予測が可能になります。
4. Deep Learning
最後に説明するのが、機械学習をより発展させたDeep Learningです。2つの違いは、ニューラルネットワークがもつ層の数です。
かつては機械学習にかなりの実行時間がかかることなどが理由で、ニューラルネットワークの層を増やすことが難しいという課題を抱えていました。しかし近年、数値計算の高速化が進んだことなどによってより層を重ねて深く学習することができるようになりました。その結果、その認識精度が格段に改善されました。
Deep Learningを試してみる
理論を理解したところで、ここからはDeep Learningを利用して独自機能の実装を目指します。
ところで、冒頭で入門は難しくないと伝えた理由は、
すでにDeep Learningのためのライブラリが充実しているからです。
実際、Deep Learning自体を実装することは簡単ではありません。しかし、すでに開発されたライブラリを利用して目的の機能を実装することは比較的簡単です。
ライブラリを利用した実装をしていき、その精度に不満を持ったときに自分でDeep Learningを改善するために勉強すればよいと思います。初めはどんどんライブラリを試していきましょう!
前述したようにDeep Learningの学習工程には長時間を要するため、より高速な処理が求められます。そのため、比較的高速に数値計算できるライブラリが存在しているPythonが多く利用されているようです。当然Deep Learningのためのライブラリも充実しています。
なので、ここでは言語はPythonを使用し、TensorFlowというライブラリを利用する方法を紹介します。
ちなみに、先週に天才ハッカージョージ・ホッツがオープンソース化した「自動運転カー」に変える改造キットでもTensorFlowが利用されていました。
なお、PythonにはTensorflow以外にもいくつかライブラリがあります。(参考:他の機械学習ライブラリとの比較)ある程度習得できたら、目的に合わせて他のライブラリを試すと良いでしょう。
1. Python環境を整える
Python公式サイトからダウンロード&インストール
2. TensorFlow
TensorFlow公式サイトからダウンロード&インストール
3. 実装する
以上で、実装する準備は整います。
手始めの実装は、Tensorflowのチュートリアルに沿って行うと良いです。実装しながら様々な手法を学ぶことができます。公式サイトでは英語のみで記述されていますが、日本語翻訳したものをまとめたサイトもあるので英語が苦手な方でも取り組めます。
深い理解は後回しで良いと思いますが、実際にDeep Learningのライブラリを触っていくうちにブラックボックスな部分を解明したくなっていくと思います。上のチュートリアルでは実装に関する理論の解説も添えられているので、進めていけば一緒に理解も付いてくるようになっています。本記事で説明が十分でないところも、このチュートリアルの中で納得が得られるはずです。
一通りのチュートリアルを終えた頃には、きっとDeep Learning入門は完了しているでしょう。
最後に
ここまで読んでくださったみなさんなら、すぐにDeep Learningを始められます。
そして来年からはいよいよ独自AIを実装して新たなアプリ開発に役立てたりしていきたいですね。
明日はCouplesを支えるiOSエンジニア、丹さんの「iOSアプリのUX改善!FacebookのAsyncDisplayKitで60FPSのハイパフォーマンスなiOSアプリを作る」です! お楽しみに。