NVIDIA DIGITSを使ったDeep Learning 画像分類モデルの作成

#目的
[前回構築したDIGITS環境](https://qiita.com/otomon10/items/ad965d5f8c1cfa8b1a41)を使って、画像を分類するモデルを作成する。
※[このページ](https://github.com/dusty-nv/jetson-inference#downloading-image-recognition-dataset)のDIGITSに関する部分を日本語で書いているだけです

こちらの画像の下段真ん中のカスタムモデルを作成するイメージです。
![Qiita](https://github.com/dusty-nv/jetson-inference/raw/master/docs/images/digits-workflow.jpg "NVIDIA Deep Learning Tools")

#PC環境
- [前回構築したDIGITS環境を参照](https://qiita.com/otomon10/items/ad965d5f8c1cfa8b1a41#pc%E7%92%B0%E5%A2%83)
- `$nvidia-docker ps -a`でコンテナの状態を確認し、digitsコンテナを実行していること。再起動などの影響で停止している場合は`$nvidia-docker start digits`でコンテナを起動する。

#画像認識データセットの入手
データセットは[ILSVRC12](http://www.image-net.org/challenges/LSVRC/2012/results.html)を利用する。事前にディスク容量が120GB以上あることを確認すること。
今回はDIGITSをdockerコンテナで実行しているため、docker run時に'-v'で指定した共有フォルダ配下にデータセットを作成する必要がある。まずは、フォルダを作成する。※usernameは適宜読み替える

```terminal
$ mkdir -p /home/username/data/datasets/imagenet/ilsvrc12
$ cd /home/username/data/datasets/imagenet/ilsvrc12
```

以下のコマンドを実行する。（100GB程度のデータをダウンロードするので注意）

```terminal
$ wget --no-check-certificate https://nvidia.box.com/shared/static/gzr5iewf5aouhc5exhp3higw6lzhcysj.gz -O ilsvrc12_urls.tar.gz
$ tar -xzvf ilsvrc12_urls.tar.gz
$ rm ilsvrc12_urls.tar.gz
$ wget https://rawgit.com/dusty-nv/jetson-inference/master/tools/imagenet-download.py
$ python imagenet-download.py ilsvrc12_urls.txt . --jobs 100 --retry 3 --sleep 0
```

1000個のフォルダに画像がダウンロードされる（ILSVRC12の各クラスに1つ）。
フォルダ名はクラスのsynset IDであり、クラス名と対応している。[こちら](https://github.com/dusty-nv/jetson-inference/blob/master/data/networks/ilsvrc12_synset_words.txt)で対応を確認できる。

コンテナ内部で共有できているか確認する。以下のコマンドでコンテナ内部に接続し、確認する。

```terminal
コンテナに接続
$ nvidia-docker exec -it digits bash

表示確認
/workspace# ls /data/datasets/imagenet/ilsvrc12/
/workspace# exit
```

#オブジェクトクラスのカスタマイズ

初期状態では1000個のフォルダがあり、DIGITSでは各フォルダ名のクラスに分類される。今回は12個のクラスに分類するようにカスタマイズするため、ディレクトリ構造を生成するスクリプトを実行する。
以下のスクリプトで、上記の1000個のフォルダに対するシンボリックリンクを貼るディレクトリが生成される。
コンテナ内部のパスでリンクを貼るため、ホスト側ではリンクが正しく動作しないが問題ない。

```terminal
$ cd /home/username/data/datasets/imagenet
$ wget https://rawgit.com/dusty-nv/jetson-inference/master/tools/imagenet-subset.sh 
$ chmod +x imagenet-subset.sh 
$ mkdir 12_classes 
$ ./imagenet-subset.sh /data/datasets/imagenet/ilsvrc12 12_classes
```

リンクが貼れているかどうかは以下で確認できる。

```terminal
コンテナに接続
$ nvidia-docker exec -it digits bash

表示確認
/workspace# ls -l /data/datasets/imagenet/12_classes/ball
/workspace# exit
```

#データセットをDIGITSにインポートする

ブラウザで http://localhost:8888 にアクセスしてDIGITSページを開く。
Datasetsのタブページを開き、ImagesドロップダウンからClassificationを選択する。
ログイン画面になるのでユーザー名を適当に入力する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/feac2463-0737-9dde-3588-e92dd23ac1db.png)

以下項目を入力し、Createボタンを押してデータインポートを実行する。（約25分）

- Training Images: `/data/datasets/imagenet/12_classes`
- % for validation: `10`
- Group Name: `ImageNet`
- Dataset Name: `ImageNet-ILSVRC12-subset`

![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/6f6dd00e-30e0-cbd9-9b44-acde6f6b074d.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/c96ac753-a845-cab5-6588-ec2f1ffad603.png)

# 画像分類モデルの作成

DIGITSのホーム画面に戻り、Modelsのタブページを開き、ImagesドロップダウンからClassificationを選択する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/a264e14d-26c6-a1d0-a30a-f36bb463df2b.png)

以下項目を入力し、Createボタンを押してトレーニングを開始する。（約8時間）

- Select Dataset: `ImageNet-ILSVRC12-subset`
- Subtract Mean: `Pixel`
- Standard Networks: `GoogleNet`
- Group Name: `ImageNet`
- Model Name: `GoogleNet-ILSVRC12-subset`

![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/239765bb-9cc9-ed0e-ae57-070ced45985d.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/caadbed3-a3b3-5d0e-0dcc-084dc4b306ba.png)

（補足）
以下のエラーメッセージが出る場合、GPUが古く最新のCUDAライブラリに対応していないことが考えられる。
digitsのバージョンを下げてCUDAライブラリのバージョンを下げるか、新しいGPUに交換する必要がある。

```terminal
Check failed: error == cudaSuccess (48 vs. 0)  no kernel image is available for execution on the device
```

# 画像分類モデルのテスト

トレーニングの結果が以下のように表示される。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/8846ee29-1f78-ecc5-f760-2733be41ab4c.png)

1つのエポックが終わると、好きな画像を入力して分類のテストを行うことができる。
試しに、`/data/datasets/imagenet/ilsvrc12/n02127052/n02127052_1203.jpg`でテストする。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/c0212934-60f8-8b8a-6932-52658bbff7d0.png)

結果、新しい分類モデルでは`cat`が100%となった。
元のGoogleNet-1000モデルでは`Lynx`と判別されるため、新しく画像分類モデルが作成できていることがわかる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/73ccd3af-56cd-5268-a8c5-5ba25c6c7095.png)

# カスタムモデルデータを出力する

組み込み機器であるJetsonで動作させるために、`Download Model`を押してモデルデータを出力する。
JetsonからDIGITSにアクセスしてダウンロードするか、ホストPCにダウンロードしてSCPやUSBメモリ等で転送する。
ダウンロードしたモデルは`tar`コマンドで解凍しておくこと。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/7af4f351-b84c-1dcc-1852-37dec5fa3e46.png)

# 続き
https://qiita.com/otomon10/items/295d190b53900d5fc2cb

#参考元
https://github.com/dusty-nv/jetson-inference#downloading-image-recognition-dataset