GPUなしのNVIDIA DIGITS3で始めるDeepLearning

# はじめに
- 主に下記の動機があってこの記事を書きました。
  - ある理由で単純な画像のカテゴリ分けをしたくなったのですがせっかくなのでDeep Learningを使ってみようと思いました。
  - **NVIDIA製GPUを積んだマシンがない。**
  - [NVIDIA Deep Learning Day 2016](http://www.nvidia.co.jp/object/event-jp.html?id=278)でDIGITSの話を聞いて面白そうだったので試してみたい。
- Deep Learningそのものについての解説は含みません。
- CaffeとDIGITSを使います。どちらも未導入の状態から開始します。
  - TensorFlowやChainerについて試してみたい場合はshu223さんの [ディープラーニングの有名ライブラリ5種を最短距離で試す半日コース（TensorFlow, Chainer, Caffe, DeepDream, 画風変換）](http://d.hatena.ne.jp/shu223/20160105/1451952796)を参照してください（とてもわかりやすいです）。
- 対象読者
  - Deep Learningをとりあえず試してみたいけど、なんだかよくわからない人。
  - なにかのDeep Learningのフレームワークを動かしてみたはいいけどよくわからない数字が出てきてうまく行っているのかどうかわからなかった人。
  - DIGITSを試してみたいけど**GPUが無いから躊躇している人**。
  - Deep Learningに興味はあるけど、**「DIGITSって何？」という人**。

「DIGITS は NVIDIAが公開しているくらいだから NVIDIA の GPUがないと動かないだろうなぁ」と最初勘違いしていたのですが、[DIGITS IN CPU MODE #251](https://github.com/NVIDIA/DIGITS/issues/251)を見て CPU ONLY でも大した手順なしに動作することがわかりました。Caffeのパスを指定する箇所でissueと別の方法が必要で少しつまづきましたがわかってしまえば簡単でしたので共有します。

また、記事の最後でGPUなしで「とりあえず始めた」あとにどこを参照してステップアップすればいいのか、GPUを使うにはどうすればいいのかについて私なりに情報をまとめました。参考になれば幸いです。

## 環境
- ソフトウェア
  - Ubuntu 14.04 64bit
  - DIGITS 3.0.0-rc.3
- ハードウェア
  - Lenovo Thinkpad X240(Core i7, 8GB RAM)

## 参考所要時間
- インストール：30分
- サンプル実行：50分（うち計算時間40分）

## 参考にした手順
- インストール手順
  - https://github.com/NVIDIA/DIGITS/blob/master/docs/UbuntuInstall.md
  - https://github.com/NVIDIA/DIGITS/blob/master/docs/BuildCaffe.md
- サンプル実行手順
  - https://github.com/NVIDIA/DIGITS/blob/master/docs/GettingStarted.md

# DIGITS とは
- [DIGITS](https://developer.nvidia.com/digits) (the **D**eep Learning **G**PU **T**raining **S**ystem) はNVIDIAがオープンソースとして公開したディープラーニングのモデルをトレーニングするためのWebアプリです。
- CaffeやTorchなどの文法を知らなくても簡単に試すことができ、入力画像のフォーマットもjpg, pngなどの一般的な形式で入力できるなど入門者にも扱いやすいです。またリアルタイムに学習状況をグラフで確認できたり、学習結果をWebインタフェースから画像のURLを貼り付けて試してみたりもできます。
- DIGTS2ではGPUでの高速がもできマルチGPU環境ではどのGPUを計算に割り当てるか指定できたり、2016/1/22にリリースされたDIGITS3では学習結果を比較できるようなインタフェースの改善に加え、Torche7(Preview)対応がなされています。2015/8/27に2.0.0がリリースされていて約5ヶ月でのメジャーバージョンアップなので現在かなり活発に開発されているようです。
- この記事の執筆時点では導入できるバージョンはDIGITS3.0.0-rc.3ですが、リポジトリからインストールしていますのでリポジトリへパッケージが公開され次第、apt-get upgradeで正式版へと移行できるはずです。
- 以下はDIGITSのWebインタフェースのスクリーンショットです。

|DIGITSでの学習結果表示|認識結果の各レイヤの可視化|
|---|---|
|![DIGITS_screen1.png](https://qiita-image-store.s3.amazonaws.com/0/3242/4e1144d5-a77d-b9f0-7edd-a28cacb2d47a.png "DIGITSでの学習結果のグラフ表示")|![DIGITS_screen2.png](https://qiita-image-store.s3.amazonaws.com/0/3242/99156284-3d29-5140-7be8-191610c14462.png "認識結果の各レイヤの可視化")|

# インストール手順
- 参考所要時間：30分程度
  - 基本的にはプリビルドのパッケージのインストールで、ビルドが必要なものはcaffeだけです。caffeのビルドも--jobs=4で5分以内に完了しています。

## リポジトリの設定
- ここのコマンドはバージョンが変わるかもしれないので、[上記ページ](https://github.com/NVIDIA/DIGITS/blob/master/docs/UbuntuInstall.md)を確認したほうが良いかもしれません。
- debをインストールしていますが、CUDAと機械学習用のリポジトリの設定のようです。
  - 前半3行のCUDAのリポジトリ設定は一見不要ですがインストールする予定のdigitsの依存パッケージに入っているのでGPUを使用しない場合でも必要だと思われます。

```
CUDA_REPO_PKG=cuda-repo-ubuntu1404_7.5-18_amd64.deb &&
    wget http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1404/x86_64/$CUDA_REPO_PKG &&
    sudo dpkg -i $CUDA_REPO_PKG

ML_REPO_PKG=nvidia-machine-learning-repo_4.0-2_amd64.deb &&
    wget http://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1404/x86_64/$ML_REPO_PKG &&
    sudo dpkg -i $ML_REPO_PKG
```

## パッケージの取得
- digitsをインストールすることで依存パッケージがたくさんダウンロードされます。
  - `sudo apt-get install digits`

- ちなみに私の場合は153MBダウンロード、739MBディスク消費が必要でした。
- ここまでの手順で http://localhost/ にアクセスするとwebインタフェースが開きます。
  - ただし、このままでは学習開始直後にCUDAのドライバのバージョンが不適切とのエラーが出てしまいます。
  - 逆に言うとGPUがある場合は http://www.nvidia.com/Download/index.aspx から適切なドライバをダウンロード・インストールするだけでセットアップが終わるようです。

## Caffeのビルド
- ソースの取得、環境変数の設定、ビルドに必要なパッケージのインストール
  - ここのブランチ名`caffe-0.14`も適宜[元の手順](https://github.com/NVIDIA/DIGITS/blob/master/docs/BuildCaffe.md)を参照してください。

```
cd $HOME
git clone --branch caffe-0.14 https://github.com/NVIDIA/caffe.git
export CAFFE_HOME=${HOME}/caffe
sudo apt-get install \
    libgflags-dev libgoogle-glog-dev libopencv-dev \
    libleveldb-dev libsnappy-dev liblmdb-dev libhdf5-serial-dev \
    libprotobuf-dev protobuf-compiler libatlas-base-dev \
    python-dev python-pip python-numpy gfortran
sudo apt-get install --no-install-recommends libboost-all-dev
```

- GPUが使えないため参照元の手順にある CUDA Toolkit, CuDNNのインストールは省略します。
- 依存するPythonのライブラリをインストール

```
cd $CAFFE_HOME
cat python/requirements.txt | xargs -n1 sudo pip install
```

- Makefile.config.exampleをMakefile.configにコピー、編集。**GPUを使わないようにするために必要。**
  - `cp Makefile.config{.example,}`
  - `CPU_ONLY := 1`をコメントアウトしている#を消す。

```diff
--- Makefile.config.example	2016-01-31 00:33:01.164003614 +0900
+++ Makefile.config	2016-01-31 00:39:47.720010918 +0900
@@ -5,7 +5,7 @@
 # USE_CUDNN := 1
 
 # CPU-only switch (uncomment to build without GPU support).
-# CPU_ONLY := 1
+CPU_ONLY := 1
 
 # uncomment to disable IO dependencies and corresponding data layers
 # USE_OPENCV := 0
```

- ビルド
  - `make install`は不要です。

```
cd $CAFFE_HOME
mkdir build
cd build
cmake ..
make --jobs=4
```

参考までに cmake 時に出力されたconfiguration summaryを載せておきます。なぜかCPU_ONLYはOFFのままですが、これで動作しました。CUDAは期待通りNoになっています。

```
-- ******************* Caffe Configuration Summary *******************
-- General:
--   Version           :   0.14.2
--   Git               :   v0.14.2
--   System            :   Linux
--   C++ compiler      :   /usr/bin/c++
--   Release CXX flags :   -O3 -DNDEBUG -fPIC -Wall -Wno-sign-compare -Wno-uninitialized
--   Debug CXX flags   :   -g -fPIC -Wall -Wno-sign-compare -Wno-uninitialized
--   Build type        :   Release
-- 
--   BUILD_SHARED_LIBS :   ON
--   BUILD_python      :   ON
--   BUILD_matlab      :   OFF
--   BUILD_docs        :   ON
--   CPU_ONLY          :   OFF
--   USE_OPENCV        :   ON
--   USE_LEVELDB       :   ON
--   USE_LMDB          :   ON
--   ALLOW_LMDB_NOLOCK :   OFF
-- 
-- Dependencies:
--   BLAS              :   Yes (Atlas)
--   Boost             :   Yes (ver. 1.54)
--   glog              :   Yes
--   gflags            :   Yes
--   protobuf          :   Yes (ver. 2.5.0)
--   lmdb              :   Yes (ver. 0.9.10)
--   LevelDB           :   Yes (ver. 1.15)
--   Snappy            :   Yes (ver. 1.1.0)
--   OpenCV            :   Yes (ver. 2.4.8)
--   CUDA              :   No
-- 
-- Python:
--   Interpreter       :   /usr/bin/python2.7 (ver. 2.7.6)
--   Libraries         :   /usr/lib/x86_64-linux-gnu/libpython2.7.so (ver 2.7.6)
--   NumPy             :   /usr/lib/python2.7/dist-packages/numpy/core/include (ver 1.8.2)
-- 
-- Documentaion:
--   Doxygen           :   /usr/bin/doxygen (1.8.6)
--   config_file       :   /home/kumadasu/caffe/.Doxyfile
-- 
-- Install:
--   Install path      :   /home/kumadasu/caffe/build/install
-- 
-- Configuring done
-- Generating done
-- Build files have been written to: /home/kumadasu/caffe/build
```

## DIGITSで使用するCaffeのパスを指定
- digitsの設定を変更、反映します。
  - 3行目の`python -m ...`のコマンドで対話的に設定を変更します。
  - とりあえず使用する上では`Caffe`のパス以外はアスタリスク(*)がついているデフォルト設定のままで何もせずにEnterで構いません。
  - Caffeのインストールパスは`/home/kumadasu/caffe`です。入力にはTab補完が使えます。適切でないフォルダを指定した場合は`ERROR: caffe binary not found at "/home/kumadasu"`のように教えてくれます。

```
cd /usr/share/digits
sudo python -m digits.config.edit -v
sudo stop nvidia-digits-server
sudo start nvidia-digits-server
```

これでCPU環境でのDIGITSのインストール完了です！

# 実行
- 参考所要時間：50分（うち計算時間40分）
  - 計算時間は実行環境によって大きく異なると思われます。
  - この章は https://github.com/NVIDIA/DIGITS/blob/master/docs/GettingStarted.md の内容ほぼそのままです。リンク先のほうが画像があってわかりやすいのでここでは簡単に文字だけで説明を書いておきます。

## テスト用のデータセットのダウンロード
- テスト用データMNIST（手書き数字の画像）をダウンロードします。

```
mkdir -p ~/dl/digits
/usr/share/digits/tools/download_data/main.py mnist ~/dl/digits/mnist
```

## データセットをDIGITSに登録
1. ブラウザで https://github.com/NVIDIA/DIGITS/blob/master/docs/GettingStarted.md にアクセス。
1. Datasets, Modelsと大きな枠が2つあるうちのDatasetsの右上の青いプルダウンImagesをクリックしてClassificationを選択するとデータセットの登録画面に遷移。
1. 各種設定を変更してCreateをクリック。
    2. Image type: Gray scale
    3. Image size: 28 x 28
    4. Training Images: /home/kumadasu/dl/digits/mnist/train （環境に合わあせてください。この入力も適宜補完が効きます。）
    5. Separate validation images folderにチェックを入れた上でValidation Images: /home/kumadasu/dl/digits/mnist/test
    6. Dataset name: MNIST
1. データの登録作業が勝手に進みます。しばらく待つとJob StatusがDoneになって完了します。まだ学習が始まっていないのにグラフが出はじめてこの過程だけでもワクワクします。

## 画像を分類するモデルの作成
既存のモデルからさらっと試せます。

1. 画面左上のDIGITSのロゴからトップページへ遷移。
2. 今度はModelsの枠の右上の青いプルダウンImagesをクリックしてClassificationを選択するとモデルの作成画面に遷移。
3. データセットとネットワークを選択してCreateをクリック。
    4. Dataset : MNIST
    5. Standard Networksタブ内のCaffeタブ内のLeNetを選択
    6. Model name : 好きな名前で良いですが例では LeNet(MNIST) としています。

## 学習
- モデルを作成すると勝手に学習が始まります。
- リアルタイムに学習状況がモニタできます。私の環境では41分で計算が終わりました。
    - トレーニング用データ(train)とテスト用データ(val)のそれぞれのloss(モデルの予測が正しいほど0に近づく値)の遷移などが確認できます。
- 学習後は任意の画像を入力して正しく認識できているかどうかを確認できます。
  - DIGITSの特徴の一つで画像認識で使われる特殊なフォーマットに合わせなくても画像サイズがめちゃくちゃ1:1でなくてもDIGITSがうまく扱ってくれて確認に使えます。
  - ファイルの一覧をテキストファイルで作成することで複数画像を一括して確認することもできます。Inkscapeでサンプルデータを作って公開しました。 https://github.com/kumadasu/handwrite-digit-data
  - 上記リポジトリのデータの認識結果が下の画像です。0を除いてtop predictionは正しい結果です。また表示されている%の値も2などは低く、8や3は高いと差がでています。
![MNIST-test-result.png](https://qiita-image-store.s3.amazonaws.com/0/3242/35d912ea-7b0b-f99f-c3c4-e27f05dc1bec.png)

# ステップアップするために
DIGITSでは他にもModelをカスタマイズ・ネットワークの可視化したり、認識結果を出すときに各レイヤーの出力を可視化したりできます。触れそうなところを触ってみると色々楽しめます。最後にこの先に進むために参考になりそうな（私自身が見て行きたい）情報へのリンクを貼っておきます。

## ソフト周り
- https://developer.nvidia.com/deep-learning-getting-started
  - NVIDIAのDeep learningのGetting startedです。
  - 大まかに分けて、基礎、使用するフレームワーク、ハードウェア（GPU）の3点について記載があります。
  - 基礎(Basics)の中に含まれている online deep learning courceはYouTubeの動画・スライドつきのコースです。YouTubeの自動書き起こしの字幕も付いているので聞き取りが苦手でも戦えるかも（一部まだ字幕がついていない動画もあります）。
  - 情報元がしっかりしているのでここを参照すれば間違いないと思います。

## ハード周り
- ハードウェアを購入してしまえば追加費用が電気代だけな一方で、クラウドなら簡単に最新の環境できるメリットがあります。必要な性能とトータルコストのトレードオフになります。
- [低火力ディープラーニングのための環境(自作ハード編)](http://studylog.hateblo.jp/entry/2016/01/28/011100)
  - 本格的にやるためにはやっぱりGPUが欲しい、ということで個人（？）でのハードウェアの入手する場合に参考になりそうです。
  - Jetson TX1は約7万円らしく、TK1のように安くは入手できないようなのでもし購入するならこういう構成もありかもしれません。
- クラウドサービス(IaaS)
  - GPUつきのサービスには Amazon Web Services, IBM Softlayer, Microsoft Azureあたりがあります。
  - IBMは物理サーバを専有することもできる、らしいですが個人でそこまでしないかな？あと月額なので少し使う用途には難しそう。企業の研究開発でガッツリ使う向けかと思います。
  - Azureの場合は学習結果をWebサービスに適用できるのが特徴らしいです。Webインタフェースでネットワークを作るとこまでは無料で、計算が始まってから課金されます。使い方でどこのサービスを使うかも絞られていきそうです。

私の直近の相手はMNISTよりも簡単なデータが相手なのでしばらくはCPUで何とかなりそうです。それとは全然関係ないですが私の最終目標のフィギュアスケートの動画からジャンプの種類の判別・出来栄え点を判定できる日は来るのでしょうか。技術も足りなければ、データ集めるのも大変・・・。