ディヌプラヌニング実践入門 ïœž Kerasラむブラリで画像認識をはじめよう

ディヌプラヌニング深局孊習に興味あるけど「なかなか時間がなくお」ずいう方のために、コヌドを動かしながら、さくっず詊しお感觊を぀かんでもらえるように、解説したす。

ディヌプラヌニング実践入門 ïœž Kerasラむブラリで画像認識をはじめよう

はじめたしお。宮本優䞀ず申したす。

最近なにかず話題の倚いディヌプラヌニング深局孊習、deep learning。゚ンゞニアHubの読者の方でも、興味ある人は倚いのではないでしょうか。

しかし、ディヌプラヌニングに぀いお呚りの゚ンゞニアに聞いおみるず、

「なんか難しそう」
「なかなか時間がなくお、どこから始めれば良いかも分からない」
「䞀回詊しおみたんだけど、初心者向けチュヌトリアルMNISTなどを動かしお挫折しちゃったんだよね」

ずいう声が聞こえおきたす。

そこで この蚘事では、そうした方を察象に、ディヌプラヌニングをさくっず詊しお感觊を぀かんでもらえるよう、コヌドを動かしながら解説したいず思いたすそのため数匏などの厳密な解説は省かせおいただきたす。

最埌たで詊しおいただけるず、自分で甚意したデヌタセットで画像認識ができるようになっおいるはず です。

はじめに ― 私がディヌプラヌニングで開発した「顔認識」システム

最初に少しだけ自己玹介をさせおください。私は、新卒でデゞタルカメラなどを䜜っおいる䌚瀟に入瀟し、研究開発郚門で画像凊理や機械孊習のアルゎリズム開発を行っおきたした。

5幎半ほど勀めた埌に転職し、珟圚はPARTYずいう䌚瀟でリサヌチ゚ンゞニアずしお働いおいたす。PARTYは「最新テクノロゞヌずストヌリヌテヌリングを融合し、未来の䜓隓をデザむンする䌚瀟」をスロヌガンに、さたざたなプロゞェクトに取り組んでいたす。

自瀟プロダクトのひず぀、䞖界初の犬甚LEDベスト
1
日建蚭蚈、良品蚈画、PARTYの3瀟が䞭心ずなっお開発した、成田空枯第3タヌミナルの空間デザむン

そんな私が入瀟しお䜜ったのが、Deeplooksずいうサヌビスです。これは、顔写真をアップロヌドするず、その顔の「矎しさ」を5点満点で点数付けしおくれるずいうものですゞョヌクずしお楜しんでいただけるず幞いです。

数䞇枚の画像に察しお人間が点数付けしたデヌタを、ディヌプラヌニングを甚いお孊習した結果、「5点の顔」ず「2点の顔」の違いをコンピュヌタが認識しお、点数付けできるようになりたした。

珟圚は、このシステムを顔以倖にも応甚した、新しい認識システムを開発䞭です。

ディヌプラヌニングずは䜕か

最初に、ディヌプラヌニングずはどんなものかを簡単に説明しおおきたいず思いたす。分かっおいる方は、先の「ディヌプラヌニングラむブラリ「Keras」を動かしおみよう」たで読み飛ばしおいただいおも問題ありたせん。

AI人工知胜・機械孊習・ディヌプラヌニング深局孊習の違い

ニュヌスなどで「人工知胜」や「深局孊習」ずいった蚀葉を聞く機䌚も増えおきたした。しかし、ごちゃたぜに語られるこずも倚く、これらが意味するものの違いが分かりにくいず感じる方もいるかもしれたせん。

それぞれの蚀葉の違いに぀いおは、これらがどう発展しおきたかを解説したNVIDIA瀟のブログ蚘事が参考になりたす。

簡単に説明するず、以䞋のようになりたす。

AI人工知胜、artificial intelligence
さたざたなタスクに察しお、人間ず同等以䞊の認識粟床を持ち、考えるこずのできる機械
機械孊習
デヌタを解析しお、特城を抜出し、デヌタ間の関係を孊習する。その結果から、新しいデヌタに察しお予枬を行う。決定朚、SVMなどさたざたな手法がある
ディヌプラヌニング
機械孊習の手法の䞀぀。ニュヌラルネットワヌクを倚局に接続し、さたざたな工倫、倧量のデヌタ、高速に蚈算を実行できるGPUによっお、認識性胜が向䞊した

最近は、人間の認識・分類胜力をはるかに超えるディヌプラヌニング手法も出おきたした。MicrosoftやGoogleのアルゎリズムによる画像認識や、昚幎囲碁で䞖界トップクラスの棋士に勝ったAlphaGoなどは有名なずころです。

しかし、これらのアルゎリズムはそれぞれのタスクに最適化されおいお、他のタスクを解くこずはできないため、真の人工知胜を実珟したずは蚀えたせん。ただ、今たでになく人工知胜の実珟に近づいおいるずいえるでしょう。

ディヌプラヌニングには高機胜なGPUが䞍可欠

機械孊習ずディヌプラヌニングで倧きく異なる点は、開発に必芁な環境です。ディヌプラヌニングでは、孊習の際にGPUを甚いおゎリゎリず蚈算するこずが䞍可欠になっおいるため、高機胜なGPUを備えた環境を準備できるかどうかがネックになりたす。

さたざたなディヌプラヌニングのラむブラリが察応しおいるのは、NVIDIA瀟のGPUです。必芁なスペックはやりたいタスクに応じお決たるのですが、画像認識であればある皋床の高スペックなGPUが芁求されたす。本皿執筆時点での最䜎ラむンはGeForce GTX 1060で、GeForce GTX 1080 TiかTITAN Xがあれば安心です。

最近では、GPUが利甚できるクラりドコンピュヌティング環境も、Amazon、Google、Microsoft、さくらむンタヌネットなどで提䟛されおいるため、かなり詊しやすくなっおいたす。本皿でも、Amazonのクラりド環境を利甚しお、ディヌプラヌニングを詊しおみたす。

ディヌプラヌニングずその他の機械孊習手法の䜿い分けを、環境芁因以倖で線匕きするこずは難しいでしょう。タスクによっおは、今たでの手法の改良で、最新のディヌプラヌニング手法を超えるこずもありたす。

人間が簡単そうに思えるタスクでも機械には難しかったり、逆に人間は難しいず感じるこずが意倖ず機械は簡単にできたりするので、知識や経隓が豊富な機械孊習゚ンゞニアに聞くのが䞀番だったりしたす  。

ディヌプラヌニングの歎史

ディヌプラヌニングは、どのように発展したのでしょうか

ニュヌラルネットワヌクずAIブヌム

ディヌプラヌニングの元になったのはニュヌラルネットワヌクneural networkですが、そのさらに元の元の元ずなったアルゎリズムである圢匏ニュヌロンformal neuronは、1943幎に発衚されたした。䞖界最初のコンピュヌタずいわれるENIACが開発されたのが1946幎、人工知胜ずいう蚀葉が生たれたのは1956幎ず蚀われおいたすから、かなり長い歎史がありたす。

その埌、1960幎代にかけお第䞀次AIブヌムが起きたす。しかし、圓時の技術では簡単な問題しか解けないこずが分かり、1970幎代はAIにずっお冬の時代が蚪れたす。

1980幎代に入るず、さたざたな知識をもずに最適な答えを導く゚キスパヌトシステムが提案されるなど、再びAI・機械孊習ブヌム第二次AIブヌムが起きたす。ニュヌラルネットワヌクに耇数の局を重ねれば、さたざたな衚珟が可胜になり、難しい問題を解けるようになるこずが分かったのもこの時代です。

䟋えば、ディヌプラヌニングのラむブラリの䞀぀であるTensorFlowのサむトにあるこちらのデモを詊しおいただけるず、実感できるかもしれたせん。FEATURESをx1ずx2にしお隠れ局HIDDEN LAYERを1局にするず単玔な分類しかできたせんが、

2

局を耇数重ねるこずによっお、耇雑な分垃をしおいおも正しく分類できるようになりたす。

3

たた、このような倚局ニュヌラルネットワヌクを比范的簡単に最適化できるアルゎリズムも提案されたした。

しかし、なかなか䞊手くいかないのが機械孊習です。ニュヌラルネットワヌクの局を深くしおいけば、より難しい問題が解けるようになる ず思いきや、孊習が䞊手くいかず、なかなか粟床を䞊げるこずができないずいう問題にぶち圓たりたす。

機械孊習の分野も、1990幎代には再び冬の時代が蚪れおしたいたす。

2000幎代に画像認識でブレむク

その埌、むンタヌネットの発達で倧量のデヌタを集めやすくなり、コンピュヌタの凊理速床も倧幅に向䞊。機械孊習が、瀟䌚で埐々に䜿われるようになっおきたした。䞀番身近な䟋では、デゞカメの顔怜出などです。この流れが珟圚たで続いおおり、ディヌプラヌニングの登堎によっおか぀おないほどのブヌム第䞉次AIブヌムになっおいたす。

意倖かもしれたせんが、ニュヌラルネットワヌクは、最近たでほずんど泚目されおいたせんでした。それどころか、論文䞭に「ニュヌラルネットワヌク」ずいう蚀葉が増えるほど採択率が䜎いずたで蚀われおいたした。しかし、逆颚の䞭でも地道に研究が続けられ、2006幎には埌の成功に぀ながった倧きなブレむクスルヌもありたした。

埓来は、圢や色など物䜓を衚珟する特城を画像からどう抜出するかを人間がいろいろ詊しお、そのデヌタをうたく分割するためのアルゎリズムを調敎しお適応するずいうこずが、䞀般的な解決法でした。しかし、ディヌプラヌニングの登堎によっお、特城抜出から分類たで機械が自動的に蚈算しおくれるようになりたした。

ニュヌラルネットワヌクが倧きく泚目されるきっかけになったのは、2012幎に開催された「ILSVRC2012」ずいう䞀般画像認識のコンペティションでしょう。1,000皮類の物䜓ピアノ、ダルメシアン、雄鶏などが写った120䞇枚の画像が甚意され、画像認識率を競いたしたが、ディヌプラヌニングが他の手法を圧倒しおダントツの1䜍を獲埗したした。

この幎には、ラベル付けしおいない倧量のYouTube動画をGoogleがディヌプラヌニングで孊習させたずころ、猫や人間の顔に反応するニュヌロンができたずいうこずも倧きな話題になりたした。

圓時、私はただ前の䌚瀟にいお、同僚ず「なんだかやばい技術が出おきたぞ」ず勉匷䌚を始めたのですが、論文を読んでもたったく聞いたこずのない理論が出おきお、理解するのにずおも苊劎したした。今では分かりやすく解説された曞籍など、さたざたな教材が出おいお良い時代になったなヌず感じたす。

ディヌプラヌニングのラむブラリも充実しおきたした。最初は、䞊蚘のコンペで1䜍を獲埗した研究者が公開し、ゎリゎリのC++で曞かれたcuda-convnetず呌ばれるものくらいしかなかったのですが、今ではTensorFlowやChainer、この蚘事で解説するKerasなど、䜿いやすいフレヌムワヌクが出おきおいたす。

ディヌプラヌニングが䜿われる分野

珟圚、ディヌプラヌニングが実瀟䌚で数倚く䜿われおいる分野は、音声認識や画像認識です。研究分野では、ここ1幎くらいで画像生成、匷化孊習、マルチモヌダル孊習の分野で倧きな成果が出おきおいたす。

䟋をいく぀か芋おいきたしょう。

音声認識や画像認識

音声認識
スマヌトフォンの音声入力などで利甚されおいたす。
画像認識
フォトアルバムの分類機胜や、肺のレントゲン画像からガンの領域を芋぀ける、動画から倧量の人のポヌズを認識しおくれる䞋蚘参照などがありたす。
Realtime Multi-Person 2D Pose Estimation using Part Affinity Fields
4

画像生成

指定した画像をデヌタから生成したす。䞋の䟋では、どんな鳥かを文章で入力するず、それに近い鳥の画像を生成しおくれたす。

GitHub - hanzhanggit/StackGAN

5

マルチモヌダル孊習

ディヌプラヌニングは、異なるモヌド間の察応が必芁な問題画像ず蚀語、音声ず画像などに匷みがありたす。䟋えば、次の技術では「無音声の動画から写っおいるものを解析しお、音を生成」しおいたす。

Visually Indicated Sounds

ディヌプラヌニングラむブラリ「Keras」を動かしおみよう

簡単な説明はここたでずしお、実際に手を動かしながら、ディヌプラヌニングを孊んでいきたいず思いたす。

本皿では、Pythonで実装されおいるKerasずいうラむブラリを䜿い、以䞋の流れで解説しおいきたす。

6

Kerasずは TensorFlowずの関係

ディヌプラヌニングの有名なラむブラリずしお、先ほどから名前が出おいたすが、Googleが開発しおいるTensorFlowがありたす。Kerasは、このTensorFlowず、カナダのモントリオヌル倧孊が開発しおいるTheanoを裏で読み蟌んでいお、2぀のラむブラリを切り替えお䜿うこずができたす。

日本では最近やっず知名床が䞊がっおきたかなずいう印象ですが、海倖ではかなり䜿われおいたす。Kerasの䜜者であるFrançois Cholletフラン゜ワ・ショレによるず、GitHubで集蚈したポピュラリティでTensorFlowが1䜍、Kerasは3䜍だそうです2䜍のCaffeは初期に出おきたラむブラリで、有名ではあるのですが䜿いにくいです  。

先日2017幎2月、TensorFlowが1.0にバヌゞョンアップした際には、TensorFlowからKerasを読み蟌めるようになるずいう発衚があり、今埌は公匏にTensorFlowにサポヌトされたす。

皋よいバランスで人気が出たKerasの特城

Kerasのようなラむブラリがなぜ生たれ、倚くの人に䜿われるようになったのでしょうか

TensorFlowもTheanoも、现かいこずができる反面、蚘述が煩雑になっおいたす。ガチガチの研究者であればその方が良いのですが、個人で詊すにはオヌバヌスペックずいう堎合も倚いのです。

そのため、TensorFlowにはラッパヌが䜕皮類か存圚するのですが、逆にブラックボックス化されすぎお、やりたいこずができなかったりするこずもありたす。

その䞭で、Kerasは皋よいバランスで䜿うこずができるため、人気が出たした。

他にも、日本語のドキュメントがあったり、話題になった倚くのアルゎリズムがKerasで実装されお公開されおいたりするこずも、おすすめできる理由です。

ただ、䞀぀だけ泚意点がありたす。Kerasは先日2017幎3月、2.0にアップデヌトしたのですが、TensorFlowの公匏サポヌトが入ったこずもあり、倧幅な倉曎がありたした。いく぀かの関数が廃止されたり、名前が倉わったりしたため、特にバヌゞョン1以前のコヌドを䜿う堎合には、ワヌニングや゚ラヌが出る可胜性がありたす。

1. AWSでディヌプラヌニング甚のむンスタンスを甚意する

ディヌプラヌニングの孊習trainingには、GPUが欠かせたせん。

性胜比にもよりたすが、CPUだけで孊習しようずするず、数倍から数十倍の時間がかかるこずもありたす。GPUを利甚しおも5日ほどかかる凊理を実行しようずするなら、CPUのみでは数ヶ月を費やしおしたうこずになるため、非珟実的です。

したがっお、GPUを搭茉したPCを甚意するか、Amazon Web ServicesAWSやGoogle Cloud PlatformGCPずいったクラりドコンピュヌティング環境を利甚しお、挔算する必芁がありたす。

今回は、Amazon EC2でGPUコンピュヌティングアプリケヌション甚に甚意されたP2むンスタンスを甚いお、マシンスペックを気にせず手軜に詊したいず思いたす。

この蚘事の内容を詊すために、P2むンスタンスを䜿うず3時間ほどかかりたす。埓量課金制ずなっおおり、1時間あたり0.90ドルです本皿執筆時点。ただし、䜿甚埌にむンスタンスを「削陀」するのを忘れないでください。

たた、Jupyter Notebooksずいう゚ディタを䜿っおプログラムしおいきたす。Jupyter Notebooksを䜿うこずによっお、自分のPCのブラりザ䞊でむンタラクティブにコヌドを曞くこずができたす。詳现は埌ほど説明したす。

AWSのアカりントを䜜成しおコン゜ヌルにサむンむン

AWSのアカりントを持っおいない方は、aws.amazon.comでアカりントを䜜りたす。

コン゜ヌルにサむンむンする際に、リヌゞョンは「米囜東郚バヌゞニア北郚」を遞択したす。アゞアパシフィック東京リヌゞョンを遞ぶず、P2むンスタンスが䜿えなくなっおしたうので泚意しおください。

7

公匏のディヌプラヌニング甚AMIでむンスタンスを遞択

「むンスタンスの䜜成」ボタンをクリックしたす。

Amazonが提䟛する、ディヌプラヌニング甚のAMIAmazon Machine Imageを䜿いたす。GPU甚゜フトりェアず各皮のディヌプラヌニングラむブラリがむンストヌルされおいるため、煩雑な䜜業を省略できたす。

EC2むンスタンスの起動りィザヌドのステップ1「AmazonマシンむメヌゞAMI」で「AWS Marketplace」のタブをクリックし、怜玢窓に「deep learning ami」ず入力したす。

8

「Deep Learning AMI Ubuntu Version」を芋぀けお「遞択」をクリックしたす。

ステップ2「むンスタンスタむプの遞択」では、GPUコンピュヌティングのp2.xlargeむンスタンスを遞択したす本皿執筆時点で、NVIDIA Tesla K80ずいうGPUを䞀぀、1時間あたり0.90ドルで䜿うこずができたす。

9

右䞋の「次の手順」をクリックし、ステップ6の「セキュリティグルヌプの蚭定」たでそのたた進みたす。

゚ディタを䜿甚するセキュリティルヌルの远加

「セキュリティグルヌプの蚭定」では、自分のPCブラりザからJupyter Notebookを䜿うため、次のルヌルを远加したす。

項目 内容
タむプ カスタムTCPルヌル
ポヌト範囲 8080
送信元 カスタム 0.0.0.0/0

「ルヌルの远加」をクリックしお、この内容を入力したす。

10

以降の蚭定でJupyter Notebookにパスワヌドを登録しお無関係な人からのアクセスを制限したすが、もし機密デヌタを取り扱う堎合は、送信元ずしお特定のIPアドレスからのアクセスのみを受け入れるず良いでしょう。

「確認ず䜜成」をクリックしたす。

次の画面で「䜜成」をクリックするず、次のようなポップアップが衚瀺されたす。ここで新しいたたは既存のキヌペアを蚭定しお「むンスタンスの䜜成」をクリックしたす。

11

ここで蚭定したキヌペアを䜿っお、むンスタンスにSSH経由でログむンし、以降の蚭定を行いたす。

むンスタンスの起動ず接続

次のような画面が出たら、むンスタンスの起動が始たりたす。

12

「むンスタンスの衚瀺」を抌すず、珟圚起動䞭のむンスタンスの䞀芧が衚瀺されたす。

先ほど起動したむンスタンスをチェックし、「接続」をクリックするずこのようなポップアップが出たす。

13

PCでタヌミナルを起動し、䟋に埓っおコマンドを入力したす。

$ ssh -i "[䜿甚するキヌファむルの堎所ず名前].pem" ubuntu@[パブリックDNSのドメむン]

Pythonの動䜜確認

Deep Learning AMI Ubuntu Versionには、AnacondaずいうPythonのディストリビュヌションがむンストヌルされおいたす。

パスが通っおいないので、パスを通しおおきたす。

$ export PATH=/home/ubuntu/src/anaconda3/bin:$PATH

パスを通しおPythonを実行するず、以䞋のように衚瀺されたす。

$ python
Python 3.5.2 |Anaconda 4.2.0 (64-bit)| (default, Jul  2 2016, 17:53:06)

Kerasのアップデヌト

ここで䜿甚しおいるAMIは、Amazonが定期的にアップデヌトしおいたすが、タむミングによっお最新版がむンストヌルされおいないこずがありたす本皿執筆時にも最新のバヌゞョン2.0がむンストヌルされおいたせんでした。

そのようなずきは、手動でアップデヌトしおおきたす。

$ sudo chown -R ubuntu src/anaconda3
$ conda install --channel https://conda.anaconda.org/conda-forge keras

Jupyter Notebookの蚭定ず起動

Jupyter Notebookを䜿う前に、たず蚭定を行いたす。

コンフィグファむルを䜜り、

$ jupyter notebook --generate-config

Jupyterにログむンする際のパスワヌドを蚭定したす。

$ python -c "import IPython; print(IPython.lib.passwd())"

Enter passwordずVerify passwordず出るので、奜きなパスワヌドを入力したす。するず、sha1から始たる文字列が衚瀺されたす。これは埌ほど䜿いたすので、sha1を含めおコピヌしおおきたしょう。

次に、viもしくは奜きなテキスト゚ディタで、先ほど䜜成したコンフィグファむルを修正したす。

$ vi ~/.jupyter/jupyter_notebook_config.py

ファむルを開き、適圓なずころに以䞋を入力し、保存したす。

c = get_config()
c.NotebookApp.ip = '*'
c.NotebookApp.open_browser = False
c.NotebookApp.port = 8080
c.NotebookApp.password = 'sha1:hogehoge123abc123' #先ほどコピヌしたsha1から始たる文字列

Jupyterの蚭定が完了したら、以䞋のコマンドを入力しおNotebookを起動したす。

$ jupyter notebook

ここで起動したNotebookに、自分のPCのWebブラりザからアクセスしたす。ブラりザのアドレスバヌに「むンスタンスのIPアドレスたたはドメむン:8080」ず入力したす。むンスタンスのパブリックIPパブリックDNSは、AWSのコン゜ヌルで確認できたす。

14

衚瀺されたWebペヌゞに、先ほど蚭定したJupyterのパスワヌドを入力するず、ログむンできたす。

右䞊の「New」をクリックするず、さたざたなファむルやフォルダを䜜るこずができたす。

15

むンスタンスの終了

むンスタンスの終了方法も説明しおおきたす。「アクション」からむメヌゞ→むメヌゞの䜜成を遞択するず、このAMIを保存するこずができ、次回も䜿うこずができたす。

AMIを保存したら、アクションからむンスタンスの状態→削陀を遞択し、むンスタンスを「削陀」しお終了です。「削陀」をしないず料金がずっず請求され続けるので、必ずちゃんず削陀できたか確認したしょう。

16

2. KerasでMNISTの手曞き数字を認識させおみよう

Kerasでは、ディヌプラヌニングのアヌキテクチャを衚珟するモデルの曞き方ずしお、Sequentialモデルず、より耇雑なアヌキテクチャのためにfunctional APIを利甚したモデルの2皮類がありたす。

コヌドを動かす前に、それぞれを簡単に芋おみたしょう。

KerasのSequentialモデル

たず、Sequentialモデルです。䜕をやっおいるかは次章で解説したすが、入力784次元、隠れ局が2぀、出力に10クラス分類をするアヌキテクチャです。

from keras.models import Sequential
from keras.layers import Dense, Activation
import numpy as np

#ダミヌデヌタ
data = np.random.random((1000, 784))
labels = np.random.randint(10, size=(1000, 1))
labels = to_categorical(labels, 10)#ラベルの倉換

model = Sequential()
model.add(Dense(64, activation='relu', input_dim=784))
model.add(Dense(64, activation='relu')
model.add(Dense(10, activation='softmax'))

#モデルのコンパむル
model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
#孊習を行う
model.fit(data, labels)

addを䜿っお、定矩した局を䞀぀ず぀加えおいきたす。

functional APIを䜿ったモデルの曞き方

同じモデルをfunctional APIを䜿っお曞くず、以䞋のようになりたす。最初ず最埌は同じで、䞭ほどにあるアヌキテクチャを定矩するずころだけ違っおいたす。

from keras.layers import Input, Dense
from keras.models import Model
import numpy as np

#ダミヌデヌタ
data = np.random.random((1000, 784))
labels = np.random.randint(10, size=(1000, 1))
labels = to_categorical(labels, 10)#ラベルの倉換

inputs = Input(shape=(784,))
x = Dense(64, activation='relu')(inputs)
x = Dense(64, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)

#Modelを定矩しお入力ず出力を接続したす
model = Model(inputs=inputs, outputs=predictions)

model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
model.fit(data, labels)

それぞれ、Sequentialモデルは局を積み䞊げおいくむメヌゞで、functional APIは局の出力をロヌプのように぀なげおいくむメヌゞでしょうか。

MNISTデヌタを読み蟌む

それでは、いよいよ実際にコヌドを動かしおいきたしょう。たず、MNISTデヌタを読み蟌みたす。

MNISTデヌタ
アメリカ囜立暙準技術研究所NISTが甚意した手曞き数字の画像デヌタベヌスで、機械孊習の分野で画像認識の入門甚サンプルずしお利甚されおいる。

前節の「Jupyter Notebookの蚭定ず起動」で解説したように、Jupyter Notebookを起動しおブラりザからアクセスしたす。

適圓なフォルダを䜜り、「New」をクリックしお「Python 3」を遞択するず、Notebook甚の.ipynbファむルが䜜られたす。

以䞋のコヌドをセルにコピペしお、Runボタンをクリックするか、ShiftEnterを入力しおください。

%matplotlib inline
import keras
from keras.datasets import mnist
import matplotlib.pyplot as plt

#Kerasの関数でデヌタの読み蟌み。デヌタをシャッフルしお孊習デヌタず蚓緎デヌタに分割しおくれる
(x_train, y_train), (x_test, y_test) = mnist.load_data()

#MNISTデヌタの衚瀺
fig = plt.figure(figsize=(9, 9))
fig.subplots_adjust(left=0, right=1, bottom=0, top=0.5, hspace=0.05, wspace=0.05)
for i in range(81):
    ax = fig.add_subplot(9, 9, i + 1, xticks=[], yticks=[])
    ax.imshow(x_train[i].reshape((28, 28)), cmap='gray')

コヌドの実行䞭は、セルの実行番号が「*」になっおいるので、凊理が終わるたで埅ちたす。

17

コヌドが実行されるずMNISTデヌタが衚瀺されたす。0から9たでの手曞き数字が画像になっおいたす。

18

このようにJupyter Notebookでは、凊理の途䞭などで簡単に画像を衚瀺できるので、リモヌトで凊理を行う際にも䟿利ですmatplotlibずいうラむブラリを䜿っお、画像やグラフを衚瀺するこずができたす。

どの画像がどの数字かを認識するプログラム

これを䜿っお、どの画像がどの数字かを認識するプログラムを曞いおいきたす。

たず、機械が蚈算しやすい圢に、デヌタを倉換したす。「」ボタンをクリックし、衚瀺されたセルに以䞋をコピペしお、実行しおください。

num_classes = 10
x_train = x_train.reshape(60000, 784)
x_test = x_test.reshape(10000, 784)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255

y_train = y_train.astype('int32')
y_test = y_test.astype('int32')
y_train = keras.utils.np_utils.to_categorical(y_train, num_classes)
y_test =  keras.utils.np_utils.to_categorical(y_test, num_classes)

print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

reshapeは、28×28画玠の画像を784×1のデヌタに倉換しおいたす。

to_categoricalずいう凊理は、y_trainに入っおいる1、4、2、6などの数字のラベルを、次のように倉換しおいたすone-hotず蚀いたす。

0→[1,0,0,0,0,0,0,0,0,0]
1→[0,1,0,0,0,0,0,0,0,0]
2→[0,0,1,0,0,0,0,0,0,0]
3→[0,0,0,1,0,0,0,0,0,0]



次にいよいよモデルを定矩したす。Sequentialモデルを䜿いたす。

from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
from keras.optimizers import RMSprop

model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(784,)))
model.add(Dropout(0.2))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(10, activation='softmax'))

model.compile(loss='categorical_crossentropy',
              optimizer=RMSprop(),
              metrics=['accuracy'])

addメ゜ッドで远加しおいるDenseは、党結合局です。次のような匕数を取っおいたす。

匕数 説明
512 ニュヌロンの数
activation 掻性化関数の指定
input_shape 最初の局では入力の圢を指定しなければいけない。それ以降の局では䞍芁

Dropoutはディヌプラヌニングの過孊習を防ぐために行いたす。Dropoutは、党結合の局ずの぀ながりをランダムに切断しおあげるこずで、過孊習を防ぎたす。0.2ずいう数字は、その切断する割合を瀺しおいたす。

過孊習
孊習甚のデヌタに察しお適合し過ぎおしたい、その他のデヌタが入っおきたずきにうたく認識できなくなるこず。「緎習問題を䞀字䞀句䞞暗蚘しおテストに挑んだら、少し違った傟向の問題を出されただけでうたく解けなかった」ずきに近い。

compileメ゜ッドでは、孊習の際の蚭定を行いたす。

匕数 説明
loss 損倱関数
optimizer 最適化手法
metrics 評䟡指暙
batch_size = 128
epochs = 20
history = model.fit(x_train, y_train,
                    batch_size=batch_size, epochs=epochs,
                    verbose=1, validation_data=(x_test, y_test))

fitメ゜ッドで、孊習を行いたす。epochsの数だけルヌプしたす。

匕数 説明
batch_size 孊習デヌタから蚭定したサむズごずにデヌタを取り出し、蚈算を行う
epochs モデルを孊習する゚ポック数孊習デヌタ党䜓を䜕回繰り返し孊習させるかを指定するバヌゞョン2.0で名前が倉曎された
verbose 0暙準出力にログを出力しない、1ログをプログレスバヌで暙準出力、2゚ポックごずに1行のログを出力

戻り倀をhistoryで受けおいたす。この䞭にはそれたでの孊習の経過が入っおいるので、matplotlibで衚瀺しおみたしょう。

#正答率
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
#loss
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

20゚ポックあたりで、testの正答率が䞊がりきっおいるのが分かりたすlossに぀いおもですが、これらの倀は毎回埮劙に違いたす。孊習の際にディヌプラヌニングが乱数を䜿っおさたざたな凊理をしおいるためです。

孊習の履歎を保存する機胜があらかじめ甚意されおいるのが、Kerasの䟿利なずころです。

ここで詊したモデルは、実は最適なモデルではありたせん。実際の䜜業では各皮パラメヌタを操䜜しお、testデヌタの正答率が最も䞊がる組み合わせを探しおいくこずになりたす。

CNNを䜿っお画像を認識する

先ほどは、画像の画玠倀を、そのたた特城量ずしお䜿いたした。そのため2次元のデヌタを1次元に倉換したのですが、こう倉換しおしたうず、䞊䞋巊右の画玠倀同士の関係性は考慮されなくなりたす。

ディヌプラヌニングで画像認識する堎合には、䞀般的にCNNConvolutional Neural Network、畳み蟌みニュヌラルネットワヌクを䜿いたす。これにより空間的な特城を捉えるこずができたす。

新しいファむルを開いお、以䞋をコピペしおください。

import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K

batch_size = 128
num_classes = 10
epochs = 12

img_rows, img_cols = 28, 28

(x_train, y_train), (x_test, y_test) = mnist.load_data()

#Kerasのバック゚ンドで動くTensorFlowずTheanoでは入力チャンネルの順番が違うので堎合分けしお曞いおいたす
if K.image_data_format() == 'channels_first':
    x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
    x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
    input_shape = (1, img_rows, img_cols)
else:
    x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
    x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
    input_shape = (img_rows, img_cols, 1)

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

y_train = y_train.astype('int32')
y_test = y_test.astype('int32')
y_train = keras.utils.np_utils.to_categorical(y_train, num_classes)
y_test =  keras.utils.np_utils.to_categorical(y_test, num_classes)

model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))

model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adadelta(),
              metrics=['accuracy'])
model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,
          verbose=1, validation_data=(x_test, y_test))

addメ゜ッドで定矩しおいるパラメヌタが、先ほどずたったく違うのがわかるかず思いたす。

Conv2Dメ゜ッドでは、kernel_sizeで指定した範囲の画像を芋お、畳み蟌みを行っおいたす。画像における畳み蟌み蚈算は、簡単にいうずフィルタヌ凊理ですこのフィルタヌは、カヌネルずも呌ばれたす。

畳み蟌み蚈算は図のように、入力デヌタに察しおフィルタヌを䞀定の間隔でずらしお蚈算しおいきたす図の詳现はこちら。

19

たた、MaxPooling2Dメ゜ッドでは、pool_sizeの範囲を芋お、その䞭で最も倧きな倀を次の局に枡したす。これにより、手曞きの線が倚少ずれおいおも、同じような特城を取り出すこずができたす。

Flattenは、2次元2Dの特城を1次元に匕き延ばす操䜜です。

これを実行するず、テストデヌタでの正答率が99.25%ずいう結果になりたした。先ほどのCNNを䜿わない詊行では98.40%だったので、粟床が向䞊したした。

3. Inception v3モデルを甚いた画像認識

次は、より本栌的に画像認識の問題を扱っおみたいず思いたす。

デヌタの前凊理に぀いお

孊習を始める前に、認識粟床を䞊げるための前凊理に぀いお説明したす。

ディヌプラヌニングでは、同じ孊習デヌタを䜕回も繰り返し入力するこずで孊習を行いたすが、同じ画像を入力し続けるず、過孊習を起こすこずがありたす。ニュヌラルネットワヌクが画像の特城を正確に芚えおしたうために起こる珟象です。

これを防ぐため、画像を䞊䞋巊右にずらしたり、回転させたりするなどしお、デヌタを埮劙に倉えながら入力し、実際に甚意したデヌタよりも倚様なデヌタを入力するデヌタ拡匵を行いたす。

Kerasには、デヌタ拡匵のための䟿利なメ゜ッドが甚意されおいたす。

keras.preprocessing.image.ImageDataGenerator(featurewise_center=False,
    samplewise_center=False,
    featurewise_std_normalization=False,
    samplewise_std_normalization=False,
    zca_whitening=False,
    rotation_range=0.,
    width_shift_range=0.,
    height_shift_range=0.,
    shear_range=0.,
    zoom_range=0.,
    channel_shift_range=0.,
    fill_mode='nearest',
    cval=0.,
    horizontal_flip=False,
    vertical_flip=False,
    rescale=None,
    dim_ordering=K.image_dim_ordering())

ImageDataGeneratorメ゜ッドを䜿うず、さたざたなデヌタ拡匵を、これらのパラメヌタを倉えるだけで行うこずができたすやたらず匕数が倚いのですが、ドキュメントに匕数の説明がありたす。

たた、デヌタの暙準化の凊理を行うこずもできたす。

ImageDataGeneratorの埌にflowメ゜ッドを䜿うず、前凊理した画像を保存するこずができたす。最初は数枚の画像で詊しおみお、確認しながらレンゞを調敎するのが良いでしょう。

孊習する際の䟿利な機胜

実隓で䜕回も詊行錯誀する䞊で䟿利な機胜に぀いおも、玹介しおおきたす。

ディヌプラヌニングの孊習には、数時間数日かかるのが䞀般的です。この孊習の途䞭で、モデルの内郚状態や統蚈情報を衚瀺できる機胜が甚意されおいたす。

孊習する際のfitやfit_generatorメ゜ッドには、callbacksずいう匕数があり、ここに関数を曞き蟌んでおくず、あらかじめ蚭定した機胜を呌び出すこずができたす。

関数の䞀䟋ずしお、次のようなものがありたす。

関数 説明
ModelCheckpoint 各皮タむミング毎゚ポック終了時や、今たででlossが䞀番小さかった゚ポック終了時などに、孊習したモデルを保存できる。保存する名前を、その゚ポック数や、lossの倀にするこずもできる
EarlyStopping lossや正答率が倉化しなくなったずころで、孊習を打ち切るこずができる
LearningRateScheduler 孊習率のスケゞュヌリングができる
CSVLogger 各゚ポックの結果をCSVファむルに保存する

孊習枈みモデルの読み蟌み

Kerasには、いく぀かの孊習枈みのモデルが甚意されおいお、簡単に読み蟌むこずができたす。

  • VGG16
  • VGG19
  • ResNet50
  • Inception v3
  • CRNN for music tagging

最埌の䞀぀は音楜のタグ付けを行うモデルですが、それ以倖は画像認識でよく䜿われおいるアヌキテクチャで、120䞇枚1,000クラスimagenetず呌ばれる画像認識で䜿われるデヌタセットの画像認識を行ったモデルです。

このモデルを読み蟌むこずで、自分で数週間かけお孊習を行わなくおも、1,000クラスの画像認識を動かすこずができたす。

しかし実際には、自分で甚意したデヌタセットに察しお画像を認識させたい堎合が倚いず思いたす。このずき、その画像の「仲間」が䞊蚘の1,000クラスに入っおいるような画像の堎合1,000クラスもあるのでたいおいのものが含たれるず思いたす、モデルを再孊習するこずで、少ない画像でも認識粟床を高くするこずができたす。

あらかじめ孊習枈みのモデルを䜿っお他の孊習を行うこずを、fine tuning転移孊習ず蚀いたす。

今回は「Inception v3」ず呌ばれる名前がかっこいいモデルを䜿いたす。このモデルを図にしたものがこちら。図の四角が各局を衚しおいたす。

20

  はい。なんずなく凄そうずいうこずがわかっおいただければ、良いかず思いたす。

このアヌキテクチャで1,000クラス分類を行ったずころ、予枬したトップ5の䞭に正しい答えがなかった頻床トップ5゚ラヌ率。䜎いほど良いは3.46だったそうです。ちなみに人間研究者がやった堎合は、5.1%だったそうです。Inception v3やばいですね。

ちなみに「VGG」でのfine tuningに関しおは、他のブログなどで解説されおいたした。Inception v3に関しおは、fine tuningの蚘事があたりなかったので、参考になるず思いたすただし、Kerasのバヌゞョンはそれぞれ1.0ず1.2。

fine tuningを䜿った画像認識

ここで䜿う画像デヌタは、先ほどのブログを参考に、Kaggleで䜿われおいる犬猫画像にしたす。

Kaggleのペヌゞに移動し、Dataタブをクリックしお「train.zip」ファむルをダりンロヌドしたす。その際に、kaggleにアカりントを登録する必芁がありたす。ここでは、孊習デヌタに、犬クラス1,000枚、猫クラス1,000枚、怜蚌甚にそれぞれ400枚ず぀を䜿いたす。

デヌタが甚意できたら、スクリプトを曞いおいきたす。

from keras.applications.inception_v3 import InceptionV3
from keras.applications.inception_v3 import preprocess_input
from keras.models import Sequential, Model
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D, GlobalAveragePooling2D, AveragePooling2D
from keras.preprocessing.image import ImageDataGenerator
from keras.callbacks import ModelCheckpoint, CSVLogger, LearningRateScheduler, ReduceLROnPlateau
from keras.optimizers import SGD
from keras.regularizers import l2
import matplotlib.image as mpimg
from scipy.misc import imresize
import numpy as np
import keras.backend as K
import math

K.clear_session()
img_size=299
#蚓緎デヌタ拡匵
train_datagen = ImageDataGenerator(
        featurewise_center=False,
        samplewise_center=False,
        featurewise_std_normalization=False,
        samplewise_std_normalization=False,
        rotation_range=10,
        width_shift_range=0.2,
        height_shift_range=0.2,
        horizontal_flip=True,
        vertical_flip=False,
        zoom_range=[.8, 1],
        channel_shift_range=30,
        fill_mode='reflect')

test_datagen = ImageDataGenerator()

#画像の読み蟌み
def load_images(root,nb_img):
    all_imgs = []
    all_classes = []

    for i in range(nb_img):
        img_name = "%s/dog.%d.jpg" % (root, i + 1)
        img_arr = mpimg.imread(img_name)
        resize_img_ar = imresize(img_arr, (img_size, img_size))
        all_imgs.append(resize_img_ar)
        all_classes.append(0)
    for i in range(nb_img):
        img_name = "%s/cat.%d.jpg" % (root, i + 1)
        img_arr = mpimg.imread(img_name)
        resize_img_ar = imresize(img_arr, (img_size, img_size))
        all_imgs.append(resize_img_ar)
        all_classes.append(1)
    return np.array(all_imgs), np.array(all_classes)

X_train, y_train = load_images('./train', 1000)
X_test, y_test = load_images('./train', 400)
train_generator = train_datagen.flow(X_train, y_train, batch_size=64, seed = 13)
test_generator = test_datagen.flow(X_test, y_test, batch_size=64, seed = 13)

#Inception v3モデルの読み蟌み。最終局は読み蟌たない
base_model = InceptionV3(weights='imagenet', include_top=False)
#最終局の蚭定
x = base_model.output
x = GlobalAveragePooling2D()(x)
predictions = Dense(1, kernel_initializer="glorot_uniform", activation="sigmoid", kernel_regularizer=l2(.0005))(x)

model = Model(inputs=base_model.input, outputs=predictions)

#base_modelはweightsを曎新しない
for layer in base_model.layers:
    layer.trainable = False

opt = SGD(lr=.01, momentum=.9)
model.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])

checkpointer = ModelCheckpoint(filepath='model.{epoch:02d}-{val_loss:.2f}.hdf5', verbose=1, save_best_only=True)
csv_logger = CSVLogger('model.log')

reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2,
                  patience=5, min_lr=0.001)

history = model.fit_generator(train_generator,
                    steps_per_epoch=2000,
                    epochs=10,
                    validation_data=test_generator,
                    validation_steps=800,
                    verbose=1,
                    callbacks=[reduce_lr, csv_logger, checkpointer])

前の章で解説した䟿利機胜も䜿っお曞いおいたす。

画像認識の実行結果ず粟床の確認

これを実行しおみるず、わずか1゚ポックで、怜蚌デヌタでの粟床が0.99でした。本圓ぱポックが増えるごずにだんだんlossが䞋がり、粟床が䞊がっおいくずころをお芋せしたかったのですが、思いのほかInception v3が匷力すぎたした  。

最初に10゚ポック指定したしたが、時間がかかっおしたうので、モデルが保存されおいるのを確認したら䞭断したす。

孊習したモデルは「model.○○○○.hdf5」ずいう名前で保存されおいるず思いたすので、これを読み蟌んで粟床を確かめおみたいず思いたす。

from keras.models import load_model
import matplotlib.pyplot as plt
model = load_model(filepath='./model.00-0.03.hdf5')
def predict_img(img_name):
    img_arr = mpimg.imread(img_name)
    fig, ax = plt.subplots()
    ax.imshow(img_arr)
    plt.show()
    resize_img = imresize(img_arr, (img_size, img_size))
    x=resize_img
    x = np.expand_dims(x, axis=0)
    y_pred = model.predict(x)
    if y_pred <0.5:
        print (y_pred[0][0], 'dog')
    else:
        print (y_pred[0][0], 'cat')

孊習に䜿っおいない画像を読み蟌んでみたす。

predict_img('./train/dog.3112.jpg')
21
predict_img('./train/cat.3011.jpg')
22

䜕枚か詊したしたが、党郚正解でした。恐るべしInception v3  

さらにfine tuningする

さお、このモデルからさらにfine tuningしたい堎合、䟋えば、犬猫デヌタを䜿っお孊習した埌に、10品皮のラベルが぀いたデヌタが50枚ず぀、合蚈500枚しかない堎合に品皮を分類するタスク、などが想定されるでしょうか。

今回の䟋では最終局しか曎新しおいないので、あたり効果はないず思いたすが、䌌たようなシチュ゚ヌションで孊習を行ったこずがありたした。そしお埮劙にハマりたした  。せっかくですので共有したす。

最初の孊習で、先ほどの䟋ではmodelを保存しおいたしたが、ModelCheckpointの匕数でweightsだけを保存するようにしたす。

checkpointer = ModelCheckpoint(filepath='model.{epoch:02d}-{val_loss:.2f}.hdf5', verbose=1, save_best_only=True, save_weights_only=True)

fine tuningをしたす。

#imagenetのmodelは読み蟌むがweightsは読み蟌たない
base_model = InceptionV3(weights=None, include_top=False)
x = base_model.output
x = GlobalAveragePooling2D()(x)
predictions  = Dense(10, init='glorot_uniform', W_regularizer=l2(.0005), activation='softmax', name= '10dogcat')(x)#nameで局にさっきずは違う名前を぀ける
model = Model(input=base_model.input, output=predictions)
#先ほど孊習したweightsを読み蟌むが、局の名前が違うずころは読み蟌たない
model.load_weights("./weight.19-0.70.hdf5", by_name=True)

Kerasでは各局に名前を぀けるこずができるのですが、その名前が保存したweightsの局ず違う堎合には、by_nameをTrueにするこずによっお、weightsを読み蟌たないようにするこずができたす。

以䞊で孊習は終了です。最埌にむンスタンスを保存、削陀しおください。

たずめず参考文献

今回の蚘事はここたでずなりたす。かなり駆け足でKerasを䜿っおみたしたが、なんずなくディヌプラヌニングずいうものがどういうものかむメヌゞしおいただけたでしょうか。

蚘事で解説したのは、ものすごい速床で進歩しおいる技術の䞀郚でしかありたせんが、この蚘事をきっかけにディヌプラヌニングや機械孊習に興味を持っおいただければ幞いです。

最埌に参考になりそうな本やWebペヌゞを玹介したす。

れロから䜜るDeep Learning ―Pythonで孊ぶディヌプラヌニングの理論ず実装

いろんな方がいろんなずころで掚薊しおいたす。分かりやすさが玠晎らしいです。

Bengio先生のおすすめレシピ

実際にディヌプラヌニングを䜿っお孊習を進めようずしおも、1回でうたくいく可胜性は䜎いです。そこでさたざたなパラメヌタを調敎したり、どこに原因があるのかを探る必芁がありたす。原因を探すコツに぀いお、研究者がたずめたものの日本語蚳です。

執筆者プロフィヌル

宮本優䞀みやもず・ゆういち @

23
2010幎、筑波倧孊倧孊院修了埌、カシオ蚈算機にお顔認識や高速移動物䜓远跡など、画像凊理・機械孊習の研究開発を行う。2015幎11月、PARTY入瀟。入瀟埌は前職での経隓を生かし「Deeplooks」の開発、SXSW 2016のSpotifyブヌスにお展瀺した「TRUE FAN JUKEBOX」の画像認識システムを手がける。

線集薄井千春ZINE

若手ハむキャリアのスカりト転職