Udacity Deep Learning Nanodegree Foundation を修了してみての感想

1月末から始まり約4ヶ月にわたったUdacity Deep Learning Nanodegree Foundation、無事に修了できました。 :-)

f:id:sanshonoki:20170524213626p:plain

ブログ用に講座のトップページをキャプチャしてみたんですが599ドル ?!

Oh My God、200ドルも値段上がってるよー ((( ;゚Д゚)))

費用対効果についてはあとで触れますが599ドルだったら多分受講してなかった(正確に書くと、受講させてもらえなかった)と思います。。

他の方の記事

国内の他の受講者の方が早くも記事を書いていますね。参考になると思います。 講座の内容はこれらのほうが断然詳しく書かれているのでこれらをご参照ください。 今回も他人のふんどしで相撲を取るスタイルです。。(; ̄ー ̄川

私の感想

少し辛口なところもありますが率直な感想。 (`・ω・´)

SirajのYouTube動画

  • イントロ
    • 凝った動画で「AIでこんなことできるのね」と、イントロとして面白い
    • 5-10分で短いので集中して見れる
    • 本編はTensorFlowオンリーだけどここではKerasがよく使われる。。
  • Live session
    • 約1時間のLive coding。時間の都合でスキップしたりエラーを解消できずに放置して結局コピペだったりグダグダ。集中力を保って最後まで見るのは難しい
  • Coding Challenge も取り組めればスキル向上しそう。でもこの講座を受けるレベルの人にはそんな余裕はないかも。。

このYouTube講座は公開されていてUdacityの受講者じゃなくても見れます。 www.youtube.com

修了できたのでCoding Challengeもトライしてみようかなぁ

本編の学習コンテンツ

  • 技術解説
    • アニメーションも使った動画解説は英語の解説記事を読むより敷居が低く効率的なのは確か
    • でも、結局は咀嚼できるまで何度も読み返すプロセスがないと “理解できた気がする” で終わってしまいそう
  • 練習課題
    • プロジェクト課題と違ってミニテスト形式じゃないので最後までコーディングしてみたもののうまく動かずどこで詰まっているか分からないというパターンに苦しむ人は多いかも
    • MatのSolution解説の適当さ感が気になる。「とりあえず説明したから」的な。そう思うのは私だけだろうか…

これもGithubでJupyter Notebookのコンテンツは公開されています。

github.com

通常の練習課題にもテストコード入れて欲しいなと思います。Solutionに手が伸びてしまう人は多いと思う。。

提出課題(プロジェクト)

  • 各所でテストコードがあり、step by stepで確認しつつ進められたのは良かった
  • 参考となる直前の練習課題と同じようにやっていたらハマる箇所が何箇所かあってちょっといじわる
  • レビューは「ok」「Hyperparameterのチューニングの余地あり」「もっとpythonらしいコードの書き方がある」ぐらいしか返ってこなかった。。

練習課題と同じようにやっていたらハマる所はもう少しヒント(「ここは練習課題と違うからしっかり考えてみてね」的な注意書き)があってもいいかなと思います。レビューは気に入らなかったら何回でも出せるみたいです。

運営

  • いつの間にか過去のweekのコンテンツが増えていたりする
  • GithubのコンテンツもWeeklyのコンテンツ公開に合わせたアップデート以外にもバグ修正含めてちょこちょこ更新されている
  • でも、運営側から通知が何もないので基本的に気づかない

これ、絶対に改善してほしいです。><

ユーザーフォーラム

  • 同じ質問があふれている。。
  • たまには自分にとって役に立つ情報もあるが全部目を通すのは辛い…

同じ質問がたくさん出るというのはみんな同じ箇所でスタックしているということで学習コンテンツの改善の余地があると思います。既出の質問かどうかちゃんとチェックするのは大変なので同じ質問が出るのは致し方ないところですね。。

その他(TensorFlow)

  • 前半は tf.Variableを使ってWeightやbiasを明示的に実装するが後半は基本的に高レベルAPI(tf.contrib.layersやtf.layers)が使われる
  • FullConnectedの実装が tf.contrib.layers.fully_connected になって、それがいつの間にか tf.layers.dense になったりで混乱する
  • TFLearnを1回だけ使う。謎。TFLearn を使うぐらいなら Keras を使ってほしい

特に説明がなかった気がするけど基本的には高レベルAPIを使っていけばいいのでしょうか。それにしてもTensorFlowはAPIの変化が激しすぎます。。 ┌┤´д`├┐

まとめ

  • Deep Learningのメインストリームの各種技術のつかみを一通りおさえられる。でも、身に付くというのはまた別の話。。
  • 勉強にはなる。お金をかけてかつ〆切りもあるので怠けず続けられる
  • 費用対効果は疑問。。

高いクオリティの無料の講座もある中、学習コンテンツの現状クオリティを考えると399ドル(当時)はやっぱり高いんじゃないかなー。599ドルになるとなおさら感あります。

受講生のみアクセスできる教材、フォーラムやレビュー(提出課題のフィードバック)に値段相応の価値を感じなかったので高い意志力を持って怠けずに続けられる人は無料公開されているSirajのYouTubeビデオGithubJupyter Notebookでも十分なのかなと思いました。。

無料の講座

人工知能に関する断創録」のブログで紹介されていて知ったfast.aiの講座(Practical Deep Learning For Coders)をやってみようと思ってます

競走馬のパドック画像から距離適性をディープラーニングで予測する

まだまだ改善したいですが競馬の祭典ダービー当日ということでいったん現状をまとめてみます。

やりたいこと

短距離馬と長距離馬は馬体の特徴が違うと言われています。 それをAIで判別できるようにしたい! というのが今回の試みです。

パッと見た瞬間に、胴が短いな、詰まっているなと思ったら、短距離馬の胴体である。反対に、胴が長く、窮屈なところがないなと感じたら、長距離馬の胴体である。 (ガラスの競馬場: 集中連載:「馬を見る天才になる!」第4回 より)

果たして、ウマくいくのか〜?! o(´Д`*)o

短距離馬 長距離馬
http://keibado.cplaza.ne.jp/keibabook/031006/images/pp08.jpg http://keibado.cplaza.ne.jp/keibabook/110516/images/pp09.jpg

(写真は競馬道のPHOTOパドックのサイトから)

学習データの生成

1. パドック画像の収集

入力となるパドック画像は競馬道のサイトからクローラで収集してきます。

2017年1/23時点で のべ頭数 8707頭、ユニーク頭数としては 2528頭分の画像を収集できました。

sanshonoki.hatenablog.com

2. ラベル(距離適性)の収集

次に画像に対してラベル(距離適性)をつけていきます。

Netkeibaの各馬のページの適性レビューのデータを使って距離適性のグラフから数値(0.0-1.0) として取得します。

sanshonoki.hatenablog.com

学習

いよいよ学習です。

CNN で 回帰(Regression)学習します。

  • input: パドック画像 (32 x 32)
  • target: 距離適性の値 (1.0 - 10.0): 0.0-1.0 を10倍にスケール
  • モデル f:id:sanshonoki:20170525051758p:plain
  • 学習最適化アルゴリズム: Adam
  • データセット
    • test: 2016年のGIレース8レース分
    • validation: テストを除く2016年のデータ
    • train: 2016年以外のデータ

いろいろやって現状の最善の学習結果は以下です。 validationエラーが全然下がってきません…。 (´Д`。)

f:id:sanshonoki:20170525054508p:plain:w400

どちらとも言えないのであれば、平均的な馬体の馬なのであろう。必ずしも、体型のみで短距離・長距離を見分けられるわけではなく、どっちつかずの体型の馬の方が圧倒的に多いのが実際である。 (ガラスの競馬場: 集中連載:「馬を見る天才になる!」第4回 より)

とのことなので仕方ないのでしょうか..

やったこと
  • 学習データを増やす
    • flip画像の生成
    • コントラストを少しずつ変えた画像の生成
  • 初期化アルゴリズム で He のアルゴリズム を使う
  • 平均画像(mean.npy)を作成して入力を正規化する

あと、最初はターゲットを0.0-1.0としていましたが性能がよくなかったです。誤差関数が MSE(mean squared error) ということで二乗することにより誤差がより小さく出るので誤差逆伝搬が効果的に働いてなかったのだと思います。

いろいろとお膳立てされていて試行錯誤を必要としないチュートリアルと違ってホント苦しんでいます・・その分勉強になってますが。 validationエラーはあまり下がりませんでしたが素人が予測するよりかはマシな印象はあります。

予測結果の例

以下は2016年のGIレースから6頭分の予測結果です。 みなさんの目による予測はいかがでしょうか。。? (´・с_・`)

画像 DL予測 正解
f:id:sanshonoki:20170525050551j:plain 0.254587 こちら
f:id:sanshonoki:20170525051022j:plain 0.336478 こちら
f:id:sanshonoki:20170525051135j:plain 0.472271 こちら
f:id:sanshonoki:20170525050830j:plain 0.513455 こちら
f:id:sanshonoki:20170525050658j:plain 0.603956 こちら
f:id:sanshonoki:20170525051236j:plain 0.705816 こちら

0.0に近いほど短距離、1.0に近いほど長距離です

改善のために…

果たしてこれでうまくいくのかは分かりませんが改善として今思いつくこと

  • Preprocess処理(特にハンドエンジニアリング)をがんばる
    • 馬体部分だけを抽出した画像で学習するとか..
  • 入力画像サイズを大きくして(64x64 etc..)転移学習をやってみる

引き続きやっていこうと思います。

デモサイト

Heroku上で試せるようにしました。 興味ある方は遊んでみてください。。

https://padock-photo-classify.herokuapp.com/

また今回使ったコードは以下にあります。

(学習) github.com

(Webアプリ) github.com

参考記事

性能改善のために参考になった記事です。 ブログ記事にも書いたAndrew Ng先生のNIPS2016での講義ももちろん参考になりました。(●´Д`●)

Nuts and Bolts of Applying Deep Learning

CS231の講義の関連動画を辿ってAndrew Ng先生がNIPS2016で行った講演「Nuts and Bolts of Applying Deep Learning」を見つけました。これがすごく面白い内容だったので超主観的にポイントをまとめてみます。

講演のビデオやスライド、Web上で見つけたブログは以下にあります。

スライドと1番目のBlog記事がよくまとまっているのでそれを読めば十分な気はします。が、自分の勉強としてまとめていきます。。

Major Deep Learning Trends [2:50]

  • データが少ないときは ハンドエンジニアリングで性能の差がつく
  • ビッグデータ時代は データ量で性能が決まる

To hit the top margin, you need a huge amount of data and a large NN model.

定式化: データ量 x 大きなモデル = 性能

End-to-end Deep learning [13:57]

  • End-to-endアプローチは 莫大なデータがある場合においてうまくいく
  • 例えば、自動運転では精度を満たすだけのデータが足りずまだ難しい
  • そういうケースではハンドエンジニアリングは依然として重要である

End-to-end works only when you have enough (x,y) data to learn function of needed level of complexity.

データ量万歳\(^o^)/です。

Bias-Variance tradeoff [27:04]

  • どんな状況であれ やるべきことは Bigger modelMore data
  • Bias と Variance を同時に改善できる(トレードオフの関係にならなくなる)
  • New model architectureの検討はハードル高いし大抵の問題はそこまで必要ない

基本的なワークフロー f:id:sanshonoki:20170520204228p:plain

Data synthesis (Data augmentation)[31:46]

  • データ合成はデータ量を増やせて性能改善にとても有効(More data)
    • ex. ノイズのない音声にノイズをのせるetc..
  • とはいえ、あくまでも人工的なデータなので学習にあまり効かない場合もある

Mismatched train/test (new bias/variance) [38:53]

学習用データの環境とアプリケーションの環境が異なるケースが増えてきている

学習環境とアプリケーション環境のデータセットの違いも考慮したワークフロー f:id:sanshonoki:20170520204239p:plain

Human-level performance [51:26]

  • 人間の認識精度をリファレンスとすべき
  • リファレンスと学習結果の差を見て 何にフォーカスするか判断できる

    human-levelエラーとtrainエラーの差が大 trainエラーとdevエラーの差が大
    Biasにフォーカス Varianceにフォーカス

What can AI/DL do ? [1:06:33]

AIアプリケーションとして有望なもの

  • 人間が1秒以内でできるタスク
  • 繰り返しシーケンスの次の結果の予測
    • ex. ユーザーが次の広告をクリックするかどうか

Personal advice (building ML career) [1:10:32]

  • 論文をたくさん読んで結果を再現する
  • Dirty work(データ収集、前処理、パラメータチューニング、デバッグ、データベースの最適化 etc…)をしよう

Dirty workは進捗がなかなか実感できないので勇気づけられます。「No magic」ということなので愚直にやりましょうということですね。。

ストリートビューのパノラマ画像をダウンロードする

React VRで使うパノラマ画像のサンプルとしてストリートビューの画像を使いたいなーと思ってネットで探したら extract-stretviewというツールを発見しました。

これがなかなか良かったので紹介します。(^○^)

www.npmjs.com

インストー

$ npm install extract-streetview -g

使い方の例

基本的に

$ extract-streetview 緯度 経度 -o 出力ファイル

です。

例えば、渋谷のスクランブル交差点 の緯度経度は

  • 緯度(latitude): 35.6595126
  • 経度(longitude): 139.7005696

なので

$ extract-streetview 35.6595126,139.7005696 -f jpg -q 100 -z 2 -s outdoor -o panorama.jpg

でダウンロードできます。

f:id:sanshonoki:20170512213334j:plain

ダウンロードした画像は アスペクト比 2:1 の Equirectangular形式になっていて そのまま各種VRアプリケーションの入力画像として使えるはずです。

ちなみに、 -zオプション は画像サイズとなっており目安は以下のようになります。

-z 画像サイズ ファイルサイズ
0 416 x 208 54 KB
1 832 x 416 165 KB
2 1664 x 832 568 KB
3 3328 x 1664 1.9 MB
4 6656 x 3328 5.6 MB

This tool is experimental とありますが パノラマ、VRを身近にする便利なツールだと思います。(*´ー`)

Cordovaで React VR をスマホアプリにしてみる

先日React VRがリリースされました。

以前VR系のベンチャー会社で働いていたので VRと聞くとつい触ってみたくなります。 ( ̄ー ̄)

以下の記事を参考に、Cordovaを使って React VR で作った Webアプリ を スマホアプリ化 してみました。

qiita.com

インストー
  1. cordovaのインストー

     $ npm install -g cordova
    
  2. React VRのインストー

     $ npm install -g react-vr-cli
    
プロジェクトの作成
  1. cordovaプロジェクトの作成

    $ cordova create path/to/your/dir com.example.hello.reactvr HelloCordovaReactVr
    

    createのパラメータは corodva create ディレクトリ 識別子 アプリ名 です。

    識別子でハイフンやアンダースコアを使うとハマるので要注意です。(AppIDとしてiOSではアンダースコア、Androidではハイフンを使えないため)

  2. iOSAndroidのプラットフォームを追加

     $ cordova platform add ios --save
     $ cordova platform add android --save
    
  3. React VRのプロジェクトを作成

    corodvaプロジェクトのルートディレクトリでReact VRのプロジェクトを作成します。

     $ react-vr init react_vr
    

    initのパラメータは react-vr init アプリ名です。

アプリのビルドとコードの修正
  1. React VRアプリのコード (js) の修正

    パノラマのテクスチャ画像をデフォルトから変更したいときは static_assetsディレクトリにEquirectangularのパノラマ画像を配置して index.vr.js を以下のように修正します。

    <View>
       <Pano source={asset('tsujido-house-pano.jpg')}
         style={{
           transform: [
             {rotateY : 0}
           ] }}
       />
      ....
     </View>
    
  2. React VRアプリをビルド

     $ cd react_vr
     $ npm run bundle
    
  3. React VRアプリのコード (html) の修正

    vr/index.html をエディタで編集します

    1. index.htmlにcordova.jsを追加

      <body>
            .....
           <script type="text/javascript" src="cordova.js"></script>
      </body>
      
    2. ビルドした js を使うようにパスを修正

      2箇所修正します。.jsをつけないとNGのようです

      client.bundle.js <script src="./build/client.bundle.js?platform=vr"></script>

      index.bundle.js './build/index.bundle.js?platform=vr&dev=true'

    3. static_assets が index.html があるディレクトリから見えるようにする

       ln -s ../static_assets .
      
    4. assetsRootのパラメータを追加

       ReactVR.init(
           // When you're ready to deploy your app, update this line to point to
           // your compiled index.bundle.js
           './build/index.bundle.js?platform=vr&dev=true',
           // Attach it to the body tag
           document.body,
           { assetRoot: 'static_assets' }  // 追加
         );  
      
  4. cordovaのwwwディレクトリがReact VRのコンテンツを参照するようにする

    cordovaプロジェクトのルートディレクトリに移動して

    $ mv www www.orig
    $ ln -s react_vr/vr www
    
  5. cordovaアプリをビルド

     $ cordova build [ios/android]
    

    この状態で $ cordova serve ios をするとブラウザ上で動作確認できます。

    f:id:sanshonoki:20170506174311g:plain

エミュレーターで確認

続いてエミュレーターで動作確認します

  1. iOS

     $ cordova emulate ios 
    

    必要に応じて --target=iPhone-6sのようにターゲット端末をオプションで指定します。

    f:id:sanshonoki:20170506152558p:plain:w250

    おお、出ました! ただし、シミュレーターではジャイロが使えないため真下向きのままから動きません… (´Д`。)

  2. Android

    Android は 最初にエミュレーターを起動してから コマンドを打ってください

     $ cordova emulate android
    

    f:id:sanshonoki:20170506152630p:plain:w250

    orz.. AndroidエミュレーターWebGLをサポートしてないようです..

実機で確認

手持ちのiPad mini でやってみます。

そのまま、$ cordova run ios すると

 `Code Sign error: No code signing identities found: No valid signing identities (i.e. certificate and private key pair) were found.` 

のエラーが出るので Xcodeのプロジェクトを開きます

$ open platforms/ios/HelloCorodvaReactVr.xcodeproj

Fix issueしてXcode上でビルド、実行します。 f:id:sanshonoki:20170511151122j:plain:w300

アプリは起動したもののテクスチャが表示されません..。(ノ゚ο゚)ノ
iPad miniが古いせいでしょうか…

Androidは手持ちのNexus5がいつの間にやら(Android6.0にアップデートしてから?)USBデバッグ接続できなくなっていて実機で確認できませんでした..

iOSAndroidとも最新の実機では動いてくれると信じています。。

実機で確認(続)

iPad mini の OS を10.3 に アップデートしたら見れるようになりました! ヾ(´▽`)ノ f:id:sanshonoki:20170507095044g:plain

アップデート前は動いてなかったThree.jsのサンプルがOSアップデート後に動くようになったのでそれでWebGL対応を判定できそうです。 https://threejs.org/examples/#webgl_animation_cloth

パッケージをアップデートしたらNVIDIAが認識されなくなった...

事件発生!

Ubuntuマシンで毎回パッケージアップデートのダイアログが出てウザいので何気なくパッケージアップデートを実行しました。

そして翌日、いつものように学習プログラムを走らせる

と、 あれ、GPUのエラー ?!?!

$ nvidia-smi してみる。

NVIDIA-SMI has failed because it couldn’t communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.

マジか Σ( ̄ロ ̄ lll)

あぁ、やっちまった..。要らんことしなかったら良かった・・  o(;△;)o

解決。。

ドライバを再度インストールしたら直りました。。

wget http://us.download.nvidia.com/XFree86/Linux-x86_64/367.57/NVIDIA-Linux-x86_64-367.57.run
chmod a+x NVIDIA-Linux-x86_64-367.57.run
sudo service lightdm stop
sudo bash ./NVIDIA-Linux-x86_64-367.44.run --no-opengl-files

ふ〜焦ったよ.. ε-(´∀`*)

気をつけよう。

ディープラーニング学習メモ #5 CNN

Karpathy先生のCS231nの講義スライドも使いつつ覚えておきたいポイントをまとめてみます。

畳み込み(Convolution)のイメージ図

f:id:sanshonoki:20170410064711p:plain:w500

ポイント

  • 入力のdepthとフィルタのdepthは同じ。フィルタを適用して1つの値を出力
  • フィルタをスライドさせながら適用して 1枚の アクティベーションマップを 出力
  • N枚のフィルタから N枚のアクティベーションマップを 出力
畳み込みの演算

F = フィルタサイズ

np.sum(X[x:x+F, y:y+F, :] * W) + b
  • フィルタサイズで切り取った X に W を elementwise掛け算 して
  • 演算結果をすべて足し込んでさらに bias を足す


別の書き方をすると

np.dot(X[x:x+F, y:y+F, :].flatten(), W.flatten()) + b

とも書ける。

ネットワーク全体のイメージ図

INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC
  • N: 0 ~ 3程度
  • M: 0 ~
  • K: 0 ~ 3程度

f:id:sanshonoki:20170408074722j:plain

CONV層 + RELU層 と POOL層を重ねて 高次元の特徴を 複数抽出し、全結合(FC)レイヤで 各特徴の重みを学習する というイメージです。

覚えておきたい計算式

  1. アクティベーションマップのサイズ

    ( W − F + 2P ) / S +1

    TensorFlowの padding=‘same'は P=ceil(F/2)、padding='valid'はP=0です。正確な定義はこちらです。

  2. パラメータ数

    ( F * F * 入力フィルタ数 + 1) * 出力フィルタ数

    +1 は bias項になります。

  3. 必要なメモリサイズ

    ( W * H * フィルタ数 ) * 4 (=float32) バイト

    バッチサイズはGPUのメモリサイズに依存します。(GPUのメモリ上にのる限りは大きくしたほうがよい)

    VGGNetの場合だと

    • 画像1枚あたり 93 M (backwardもいれると x 2) となるようです。。

なぜディープにするのがよいのか?

7x7フィルタを1回適用した場合と3x3フィルタを3回適用した場合を比較してみます。

イメージ パラメータ数
7x7フィルタを1回 f:id:sanshonoki:20170408062235p:plain:w150 (7 * 7 * 3 + 1) * 3 = 444
3x3フィルタを3回 f:id:sanshonoki:20170408062304p:plain:w320 (3 * 3 * 3 + 1) * 3 * 3 = 252

出力アクティベーションマップのサイズは 26 x 26 で同じですが3層に積み重ねるほうがより大きな表現力があり(非線形処理を3回適用するので)、またパラメータ数も少なくなり学習効率がよくなります。

一方でメモリサイズはより必要になってくるのでトレードオフの関係にはなります。 GPUのスペックが向上することでよりディープに学習することが可能になったと言えるでしょう。

どんどんディープになっていくトレンドですが ILCVRC'15の勝者の ResNet は なんと.. 152層 です。 w|;゚ロ゚|w

f:id:sanshonoki:20170408071259j:plain

なぜCNNは成功しているのか?

次のような理解で大体あっていると思う。。

画像認識に適したアーキテクチャ
  • 畳み込み: 何層も畳み込むことで高次元の抽象的な特徴を抽出できる
  • プーリング: 位置のずれにロバストになる
以下の2つの大きな課題があったが解決された
  • 過学習 (Overfitting)
  • 勾配消失問題 (Vanishing gradient problem)
解決の要因
  • 手法の進化
    • ReLU: 深いネットワークでも勾配が逆伝搬できるようになった
    • Dropout: 擬似的にアンサンブル学習することで汎化性能が上がり過学習を抑制できるようになった
  • ハードウェアの進化(特にGPU
    • 大量のデータ、大量のパラメータを処理できるようになった

勾配降下法(gradient descent)の実装サンプル

1次元データでCNNのgradient descentをNumpyで実装してみました。 スクラッチで実装すると少し自信がつく気がします。。 (o・ω・o)

github.com

今回は以上です。次は RNN の記事を書いてみようと思います。