NVIDIA社DIGITSでDeep Learningをいじくる
アブストラクト(概要)
Deep Learningのツール「Caffe」を、NVIDIA社の「DIGITS」を使って動かします。DIGITSは比較的インストールが簡単でなおかつ使いやすいので、Deep Learningの理解を深めるのに役立つと思います。記事の前半では、基礎的な用語などについて簡単に説明します。後半では、DIGITSをインストールして動かす方法を説明します。
はじめに:いきさつ
筆者は素粒子原子核宇宙物理系のポスドクで、画像処理をやっています。
2014年ごろから画像分類の技術として「Deep Learning」というのをよく目にするようになりました。筆者はこの技術をなんとか使いこなしたいと思い、2014年の夏から機械学習について、2015年の正月ごろから実際に動かす方法について色々と調べてきました。そして先週(2015年の6月中旬)、NVIDIA社の開発したDIGITSという開発ツールがあることを知りました。これをインストールしてみたところこれまでの苦労はなんだったのかというくらい操作が楽でした。色々サンプルを動かすうちにDeep Learningとは何かということが分かってきて楽しくなってきたわけで、脳内情報の整理のために記事を書こうと思います。なおこの記事は適宜加筆修正しますのでもし参考にされる方いらしたらご注意ください。内容がまちがっていたらご指摘ください。
基礎知識
Deep Learningとは
Deep Learningとは人工ニューラルネットワーク(ANN, Artificial Neural Network)の発展形です。
人工ニューラルネットワーク(ANN)とは
名前の由来はさておき、まずANNの使い道について解説します。ANNをつかう簡単な例として次のような問題を挙げます。
・x-y平面上に2種類の点が分布している。これらを区別するための境界線を決めたい。
ANNを使ってこの境界線を決めます。ANNはこのような状況を与えられると、x-y平面に適当な線をひいてはその妥当性を評価し、また修正した線を引いては妥当性を評価し、試行錯誤を繰り返して、2種類の点たちを一番良く分ける境界線を決めます。つまり「与えられた正解」と「線引きの結果」の食い違いが最小になるように、適当なアルゴリズムに基づいて線の傾きと切片の組み合わせを探索するわけです。
この線引き問題に具体的なストーリーをつけてみましょう。x軸、y軸をある日の温度と湿度。オレンジ、青の2種類の点をその日の天気が晴れか雨か、としましょう。さきほど求めた境界線というのは、温度&湿度のデータをもとに晴れor雨を分類(未知のデータに関しては推測)するのに対応します。この仕組みはれっきとした「人工知能」と言えます。ここに温度と湿度のデータから晴れか雨を判断する人がいて、「こんな仕事は誰かにやってほしいなあ」と思っているとします。そういう状況においては、この線引きの仕組みは「何かしらのデータに基づいて人間に役立つ判断を勝手にやってくれるモノ=人工知能」と言うことができるでしょう。
数学的には
この問題を解くのに、f(x,y) = y - (a*x + b)という関数を考えます。ある点(x,y)が線の上側にあるか下側にあるか、この関数の正負でもって判定をします。「上側にある状態を+1と定義する。下側にある状態を-1と定義する。f(x,y)の結果を見て、正の数だったら+1、負の数だったら-1」というわけです。なおこの関数f(x,y)は、見方を変えると、2つのベクトル:(x,y,1)と(-a,1,-b)の内積を表現しているともいえます。
この関数をかわいく描いたものが「人工(じんこう)ニューロン」です。
数値は左から右へ流れていきます。一番左側にあるのが数値の入り口です。入ってきた数値は線を通ってくる間に適当な係数が掛けられます。それぞれの数値が合計され、場合によっては何かしら処理をしたのち最終的に右に出てきます。
ここまでは境界線の式の形を直線:y=ax+bとして話を進めてきました。ところが状況によっては、1本の直線ではデータを分けることができなくて、境界線を折れ線にしたい場面が出てきます。そういう場合は人工ニューロンを複数用意し、さらに多段に連結することで折れ線が表現できます。こうして人工ニューロンが繋がったものがANNです。ネットワークの段数を増やすと、より複雑な境界線を表すことができ、識別の表現力を上げることができます。
学習
ANNが最適値を探索する経過は、脳の神経回路が最適化されていくことに似せて「学習」、「訓練」と呼ばれています。「与えられた正解のデータ」は、学習の方向性を与えてくれることに対応させて「教師データ」と呼ばれます。各ニューロンのパラメータを最適値に収束させるのに、Back propagationというアルゴリズムが使われます。
ANNと画像認識
ANNを画像認識に使うことが可能です。詳しくは「テンプレートマッチング」、「コンボリューション、たたみ込み演算」、「たたみ込みニューラルネットワーク」で調べてみてください。Nピクセルの画像はN次元のベクトルです。2つの画像の類似度は、ベクトルの内積によって表現できます。そういう認識を持つと、さきほど紹介した線引き問題が画像分類問題の基本形であると理解していただけると思います。
Deepであるということ
ANNの段数を増やし、識別の表現力を増したのがDeep Learningです。ANNの段数をむやみに増やしても学習がうまくいかなくなるのですが、以下にあげるようないくつかの技術によって実用化され、さらには従来の識別手法の性能を凌駕するまでになったとのことです。
・pre-trainingで適当な基底関数を用意する。Autoencoders。Restricted Boltzmann Machines。
・activation functionとしてReLUなど。
・過学習を抑制するDropoutというテクニック。
GPUとの相性
先述の畳み込み演算はまさにGPUが得意とするタイプの演算で、GPUの利用によって高速化が見込めます。もともとGPUは3Dゲームのリアルな映像を表現するために作られた演算装置です。比較的単純な演算を一気に大量のデータに実施するのに特化されています。近年、GPUは3Dゲームのみならず、科学技術計算のためにも使われるようになってきました。
GPUメーカーの大手であるNVIDIA社は、画像認識、Deep LearningをGPUの応用の柱の一つとして位置づけているようで、ソフト、ハード両面からDeep Learning人口を増やすべく色々製品を出してきています。
NVIDIA社によれば、CaffeというDeep LearningのツールでGPUを使うと、CPUの約8~9倍の高速化、さらにcuDNNというライブラリの利用で約16~17倍の高速化ができたとのことです。学習や認識の計算時間が短くなればなるほど開発の試行錯誤を早く繰り返すことができ、実際の応用の幅も広がるので、計算速度はきわめて重要です。
cuDNN v2: Higher Performance for Deep Learning on GPUs | Parallel Forall
python
ネットワークの検証や自作のプログラムへの組み込みにはpythonが良く使われます。pythonを覚えましょう。
Deep Learningのツール
有名どころではCaffe, Pylearn2, Cuda-convnet2, Torch7などが挙げられます。
現在のところ一番はじめやすいのはChainerだと思います(筆者しらべ)。筆者のメインのマシンはWindows7で、WindowsというのはDeep Learningをやるのに向いていない環境のようですが、Chainerはpythonのインストールの枠組み(pip)を使うことで簡単にインストールできます。
しかし、ChainerでGPUを使った演算をしようとするとうまくいきませんでした。pycudaというライブラリのインストールがうまくいきません。しかしこれはインストーラが改良されればクリアできる問題だと思いますので、筆者は今後もひきつづきChainerを注目していきたいと思っています。
DIGITS
こうして色々ツールを試していくなかで筆者が一番楽だと思ったのはCaffe+DIGITSです。Caffeはthe Berkeley Vision and Learning Centerが開発したもので、GitHubのDeep Learningのカテゴリの中で一番人気があると見えます。NVIDIA社もCaffeのことをなんだか贔屓にしているように見えます。そしてNVIDIA社が作ったCaffeの開発ツールがDIGITSです。
DIGITSを動かすまで
環境
筆者の環境は以下のとおりです。
OS:Ubuntu 14.04 LTS
CPU:Corei7-4790@3.60GHz*8
MEM:8GB
DIGITS:1.1 (Downloaded:2015.06.21)
インストール方法
本家サイトからファイル一式をダウンロードします。このファイル一式の中にはcudaやcuDNNの.soファイルがすでに入っています。ただしダウンロードするにはNVIDIAのDeveloper Programsに登録する必要があったと思います。上級者はGitHubから最新版をダウンロードしてきて自分で設定しても良いです。
GitHubのページにインストール方法が載っています。
install.shを実行するとpythonの環境とMNISTのデータがインストールされます。runme.shを実行するとhttpサーバーが起動します。ウェブブラウザでlocalhostを指定し、表示されるページがDIGITSの操作画面です。
チュートリアルの実行
チュートリアルのMNISTのデータをいじってみましょう。MNISTとは手書き数字の画像データを大量に用意したものです。これを使ってLeCun(ルカン)先生の設計したLeNetを学習させます。
DIGITS/GettingStarted.md at master · NVIDIA/DIGITS · GitHub
筆者のマシンではMNIST10kでLeNetを学習させるのに2分40秒程度でした。validationデータのaccuracyは99.07%と出ています。
いっぽうAlexNetやGoogLeNetというもっとDeepなネットワークモデルも選択可能ですが、筆者のマシンで学習を実行したところ、cudaのout of memoryエラーが出て処理が落ちました。Batch sizeというパラメータを最低値の1に設定しても処理が落ちます。どうやら筆者のGPUではメモリが足りないようで、動かすにはもっと大きなメモリをつんだ高級GPUを買ってくれということのようです。
DIGITSのここが便利
・データセット、ネットワークモデルの管理が楽。
・学習の様子がリアルタイムでモニターできる。
・ジョブを連投できる。前のジョブが終わったら勝手に次のジョブが始まる。
・識別の際、ネットワークの各レイヤーで何が起こっているのかをすぐ可視化できる。チューニングにかなり役立つ。
自作データで学習させる
自作のデータで学習をさせてみましょう。ここでは例として抽象的なデータを生成します。画像の生成にはOpenCV2.4を、乱数発生にはnumpyを使っています。
これを実行すると64*64pixのサイズの以下のような3種類の画像が、それぞれ個別のフォルダの中に生成されます。生成する数は10個としています。この後紹介する実験ではこの数字を1万に増やし、計3万枚の画像を使って学習&検証をしています。
ラベル「n」。もやもやした背景+点というノイズを表現した画像
ラベル「c」。中央付近に黒い直線がある。
ラベル「o」。中央付近に黒い丸がある。
これら3つのフォルダを持つ親フォルダを、DIGITSの画面でTraining Imagesのfolderとして指定します。この「n」「c」「o」というフォルダ名がそのまま教師データのラベルになります。フォルダ構造が深い場合は、親フォルダ直下のフォルダ名がラベルになります。デフォルトでは、この中からランダムに選んだ25%ぶんが検証用データになります。
これを使ってLeNetを学習させます。
LeNetはIntended image sizeが28x28(gray)と書いてありますが、チャンネル数(カラーか白黒か)と画像のサイズはこれと一致していなくても動きます。これらのパラメータはデータセットに応じて勝手に調整されます。
ただし画像認識の観点からいうと、設計値とかなり違うサイズの画像を持ってきた場合は良いパフォーマンスが得られないことがあると思います。LeNetは5*5pixコンボリューション→2*2pixプーリング→5*5pixコンボリューション→2*2pixプーリングをしており、この領域に対してあまりに巨大な構造物は認識できません。その場合はコンボリューションのカーネルサイズやプーリングの大きさや層の深さを変更するか、はじめから画像のサイズを小さくしておいたほうがいいです。ネットワークの構造を変更したい場合は「Custom Network」の編集欄で編集しましょう。
学習を始めると学習経過をあらわすグラフが表示され、随時更新されていきます。筆者のマシンでは学習の所要時間は9分50秒、accuracy=99.8%、loss=5.8*10^-3でした。
学習済みのモデルを使って、適当な画像の識別をさせることができます。このとき「Show visualizations and statistics」をオンにすると、中身でどのような計算が行われているのかを覗くことができます。また
・学習の途中の状態(エポック毎のスナップショット)で識別を試せる
という機能もあります。
さいごに
筆者がポスドクの任期が切れて無職になったら、AV業界に転職して、この技術をアダルト動画のモザイク処理に応用したいと思います。
謝辞
機械学習系の情報やUbuntuの設定のしかたを色々おしえてくれる後輩のよこやまくんに御礼もうしあげます。
参考文献
加筆修正の履歴
(2015/06/29.21時)アブストをつけました。筆者が「パーセプトロン」だと思っていたのは、実は「人工ニューロン」と言うのが適切でした。文章の表現を推敲しました。Custom Networkの話を書き足しました。NVIDIA社、GitHubの大文字小文字を正しい表記に修正しました。字をおおきくしました。