DeepLabCutをWindows+google colaboratoryで使ってみた

# はじめに
###記事の内容
[DeepLabCut](https://github.com/AlexEMG/DeepLabCut)のWindows機(+ Google Colaboratory)での使い方を載せました。

>DeepLabCut
>Markerless tracking of user-defined features with deep learning - http://www.mousemotorlab.org/deeplabcut

###何ができるか？
数十枚〜数百枚のお手本となるキーポイント(e.g. 指先、関節点、道具)をラベリングすれば、残りのフレームのキーポイントを抽出してくれます。

抽出する特徴点をユーザーが自由に決められるのがウリということで、[OpenPose](https://github.com/CMU-Perceptual-Computing-Lab/openpose)とは別の使い方ができるのではないでしょうか。

私はヒトの動画を対象にやってみましたが、手作業でデジタイズするのとほとんど変わらないクオリティなんじゃないかと思います。
野球のスイングやゴルフのスイングなど、特定の種類の動作に対して学習を行うことができるので、動作解析には比較的強いのかもしれません。
(これは私見と希望的観測です)

###経緯
はじめはGPU ver.をローカルで走らせようとしていたのですが、[condaの環境構築](https://github.com/AlexEMG/DeepLabCut/tree/master/conda-environments)でつまづいてしまいました。幸いにもGoogle Colaboratory上で動かせる[デモ](https://github.com/AlexEMG/DeepLabCut/tree/master/examples)が用意されていましたので、代わりに試してみることにしました。
※Google Colaboratory上の開発が早く、DLCがキャッチアップできなくなるかもよ～とはいわれているので、動かなくなってしまったらあしからず。
>Warning: Colab updates their CUDA/TensorFlow likely faster than we can keep up, so this may not work at all future points in time (and, as a reminder, this whole package is released with a LICENSE that implies no Liability and no Warranty).

# 参考にした記事
「[深層学習で動物の身体をトラッキングするdeeplabcutをgoogle colaboratoryで走らせる](https://qiita.com/riichirohira/items/b92723278ba92fb42db9)」
大変参考にさせていただきました。ありがとうございました。

ローカル環境でのラベリング後に、ラベリングデータが格納されたHDF5ファイルが出力されない症状は私も同じでしたが、Google Colaboratory上で.csvから.h5を生成することで解決しました。

# 環境
- 解析環境
    - windows10 home (64bit)
    - Google Colaboratory (python3)
    - Miniconda 
- ライブラリ([DeepLabCut](https://github.com/AlexEMG/DeepLabCut))
- その他
    - Google account (容量大きめ)

# 動画の準備
解析したい動画を用意します。

# Windows機ローカルで行うこと
Window上では、ラベリングを行います。これは、Google colaboratory上では行えません。

まずは、Minicondaを[インストール](https://docs.conda.io/en/latest/miniconda.html)して、Anaconda prompt(orコマンドプロンプト)を起動します。

仮想環境を作成します。

```python:
conda create -n pydlc python=3.6
conda activate pydlc
```
仮想環境上でdeeplabcutをインストールします。

```python:
(pydlc) pip install deeplabcut
```
続いて、wxPython、tensorflowもインストールします。

```python:
(pydlc) conda install -c anaconda wxpython
```

```python:
(pydlc) pip install --ignore-installed tensorflow==1.10
```



### ラベリング作業
ラベリングをする際に動画へのシンボリックリンクを作成する必要があるので、管理者権限でAnaconda promptを実行し、pythonを立ち上げます。

```python
(pydlc) python
```
deeplabcutをimportし、新しくプロジェクトを作成します。

```python:python
>>> import deeplabcut
>>> deeplabcut.create_new_project('task(タスクの名前)','name(ラベル付けをした人の名前)',['C:\\usr\\demo_video.avi(動画の名前)'])
```
カレントディレクトリに'project-name-2019-03-29'という名前のフォルダが作られるので、その中からconfig.yamlという名前のファイルを探します。このファイルのパスをpath_configとします。

```python:python
>>> path_config = "C:\\usr\\project-name-2019-03-29\\congif.yaml(create後のconfig.yamlのパス)"
```

このとき、config.yamlを書き換えることによって、ラベリングを行うフレームの枚数とターゲットの数を指定することができます。

```python:config.yaml
# Project definitions (do not edit) ←勝手に記入される
Task: task
scorer: name
date: Mar29

# Project path (change when moving around) ←Google driveに移動した後変える
project_path: C:\usr\project-name-2019-03-29

# Annotation data set configuration (and individual video cropping parameters) ←Google driveに移動した後変える
video_sets:
  C:\usr\project-name-2019-03-29\videos\video.avi:
    crop: 0, 832, 0, 747 # ←画像のサイズ
bodyparts: # ←ラベリングしたいパーツ
- part1
- part2
- part3
- part4
start: 0
stop: 1
numframes2pick: 20 # ←ラベリングする数

~
```
設定ができたら保存して閉じます。

続いて、以下の関数を実行するとラベリングのためのGUIが立ち上がりますので、**右クリック**でラベリングしていきます。

```python:python
>>> deeplabcut.extract_frames(path_config, 'automatic', 'kmeans') 
```

ラベリングし終わったら、saveを押して閉じるのですが、numpyのバージョンの関係やら、Windowsのせいやらで、.h5ファイルが生成されません。

私の場合は、以下のようなエラーがでました。

```python:python
ValueError: numpy.ufunc size changed, may indicate binary incompatibility. Expected 216 from C header, got 192 from PyObject
```

しかし、.csvファイルの作成に成功していれば、今は気にしなくてよいです。訓練に必要な座標は.csvファイルに残っています。

この後はブラウザに移動します。

# Google Colaboratoryで行うこと

###プロジェクトファイルの引っ越し
ローカル環境で作成したプロジェクトファイルをGoogle Driveにコピーします。

> project-name-2019-03-29/
  &nbsp;&nbsp;  ├ dlc-models/
  &nbsp;&nbsp;  ├ labeled-data/
  &nbsp;&nbsp;  ├ traning-datasets/
  &nbsp;&nbsp;  ├ videos/
  &nbsp;&nbsp;  └ config.yaml
    
以上のフォルダごと、Google Drive上にコピーします(My Drive//deeplabcut_demo//project-name-2019-03-29という場所に置いたと思ってください。)。

ついでに、config.yamlの中に書かれているパスを**二か所**変更します。

```python:config.yaml(変更後)
# Project definitions (do not edit) 
Task: task
scorer: name
date: Mar29

# Project path (change when moving around) 
project_path: /content/drive/My Drive/deeplabcut_demo/project-name-2019-03-29 # ←drive上のプロジェクトのパスに変更！！！

# Annotation data set configuration (and individual video cropping parameters) 
video_sets:
  /content/drive/My Drive/deeplabcut_demo/project-name-2019-03-29/videos/video.avi: # ←drive上の動画のパスに変更(ここは変えなくてよいかも)
    crop: 0, 832, 0, 747 
bodyparts: 
- part1
- part2
- part3
- part4
start: 0
stop: 1
numframes2pick: 20 

~
```
変更したら保存して閉じておきます。
※config.yamlファイルの編集はブラウザアプリでも可能です。
※※Google Driveのマイドライブは、content/drive/My Drive/に相当するようです。また、この段階ではGoogle Colaboratoryからドライブ内のファイルにアクセスすることはできません。この後のマウント作業が必要です。
※※※バックスラッシュ(\\)からスラッシュに変更しましょう(/)。


###Google Colaboratoryのノート上での作業
Google Colaboratory上のデモのやり方は[ココ](https://github.com/AlexEMG/DeepLabCut/tree/master/examples)です。
また、デモ用のノートは以下です。
>Alternatively, you can use Google Colaboratory to demo running the training and analysis of new videos, i.e. the parts that need a GPU! Here is a demo of us using it: https://www.youtube.com/watch?v=j13aXxysI2E
<a href="https://colab.research.google.com/github/AlexEMG/DeepLabCut/blob/master/examples/Colab_TrainNetwork_VideoAnalysis.ipynb" rel="nofollow"><img src="https://camo.githubusercontent.com/52feade06f2fecbf006889a904d221e6a730c194/68747470733a2f2f636f6c61622e72657365617263682e676f6f676c652e636f6d2f6173736574732f636f6c61622d62616467652e737667" alt="Open in Colab" data-canonical-src="https://colab.research.google.com/assets/colab-badge.svg" style="max-width:100%;"></a>


###Google Driveをマウント
これ以降は基本的にはノートを見ながら、上から順に実行していきます。


```ruby:
#Now, let's link to your GoogleDrive. Run this cell and follow the authorization instructions:
#(We recommend putting a copy of the github repo in your google drive if you are using the demo "examples")

from google.colab import drive
drive.mount('/content/drive')
```
こちらを走らせると、以下がURLが出力され、ユーザー入力待機状態になります。URLのリンク先を開き、コードをコピペします。

```
Go to this URL in a browser: https://accounts.google.com/~~

Enter your authorization code:
[ここに貼り付ける]
```

マウントが完了すると、以下が出力されます。

```
Mounted at /content/drive
```

###パッケージのインストール
deeplabcut
失敗したら再起動します。何度か繰り返すとうまくいきます。

```ruby:
#(this will take a few minutes to install all the dependences!)

!pip install deeplabcut
```

その他

```ruby:
#These are some Colab specific work-arounds, but they work! (typically not required, as they are installed with "pip install deeplabcut")

!pip install Pillow==4.0.0

from PIL import Image
def register_extension(id, extension): Image.EXTENSION[extension.lower()] = id.upper()
Image.register_extension = register_extension
def register_extensions(id, extensions): 
  for extension in extensions: register_extension(id, extension)
Image.register_extensions = register_extensions

!pip install ruamel.yaml==0.15
!pip install pandas==0.21.0
```

###DeepLabCutのインポート
ディレクトリを変更します。

```ruby:
#Be sure you have a copy of your project folder in your Google Drive. Then, let's go to your deeplabcut folder!
%cd /content/drive/My Drive/deeplabcut_demo
```
deeplabcutをインポートします。

```ruby:
import deeplabcut

#sometimes the backend kernel is defaulting to something other than what we want
#if you see the warnings, you can re-run this cell and they go way, as we re-set the backend! :) 

#possible warning--> UserWarning: This call to matplotlib.use() has no effect because the backend has already
#been chosen; matplotlib.use() must be called *before* pylab, matplotlib.pyplot, or matplotlib.backends is imported for the first time.
```
config.yamlのパスを指定します。

```ruby:
#create a path variable that links to your google drive copy:
path_config_file = '/content/drive/My Drive/deeplabcut_demo/project-name-2019-03-29/config.yaml' #change to yours!
```
###【重要】.csvファイルから.h5ファイルを生成します。
※この行程は元々のノートブックには記載がありません。Windows環境でHDF5ファイルの作成に失敗しているが、CSVファイルが作成できている場合に行ってください。

コードセルを追加し、以下のコードを書き込み、実行します。

```ruby:
deeplabcut.convertcsv2h5(path_config_file)
```
これで、labeled-data/video/の下に.h5ファイルが生成されれば成功です。

###トレーニング以降
トレーニングデータセットを作ります。
Windowsでラベリングを行った場合は、ここで適切な変換を行ってくれます。


```ruby:
# If you are using the demo data (i.e. examples/Reaching-Mackenzie-2018-08-30/), first delete the folder called dlc-models! 
#Then, run this cell. 
deeplabcut.create_training_dataset(path_config_file)
```
トレーニングを開始します。
モデルのトレーニングの表示、モデルの保存頻度を指定できます。

```ruby:
#let's also change the display and save_iters just in case Colab takes away the GPU... 
#if that happens, you can reload from a saved point. Typically, you want to train to 200,000 + iterations.
#more info and there are more things you can set: https://github.com/AlexEMG/DeepLabCut/blob/master/docs/functionDetails.md#g-train-the-network

deeplabcut.train_network(path_config_file, shuffle=1, displayiters=10,saveiters=500)

#this will run until you stop it (CTRL+C), or hit "STOP" icon, or when it hits the end (default, 1.03M iterations). 
#Whichever you chose, you will see what looks like an error message, but it's not an error - don't worry....
```

いい感じのところで停止させたら、モデルを動画に適用します。

```ruby:
videofile_path = ['/content/drive/My Drive/deeplabcut_demo/another_video.mp4'] #Enter the list of videos to analyze.
deeplabcut.analyze_videos(path_config_file,videofile_path)
```
解析が終了したら、ラベル付きの動画を作成してみてみましょう。

```ruby:
deeplabcut.create_labeled_video(path_config_file,videofile_path)
```

###座標データを取得するには
以下のようにすると、動画の存在するフォルダ内から.h5ファイルを探して、同じ場所に.csvファイルを作成してくれます。

```ruby:
deeplabcut.analyze_videos_converth5_to_csv(videofile_path)
```

#最後に
OpenPoseといい、DeepLabCutといいめちゃめちゃすごいですね！！！
皆様もぜひ試してみてください。

#追記(2019/04/05)
人を対象にトレーニングを行う場合は、resnet50(デフォルト)ではなく、resnet101を使ったほうがいいと思います。

その場合は

```ruby:
deeplabcut.create_training_dataset(path_config_file)
```
の後の[オプション](https://github.com/AlexEMG/DeepLabCut/blob/master/docs/functionDetails.md)で一番初めに使うモデルを変更できます。

>Specifically, the user can edit the pose_cfg.yaml within the train subdirectory before starting the training. These configuration files contain meta information with regard to the parameters of the feature detectors.

>At this step, the ImageNet pre-trained ResNet-50 and ResNet-101 weights will be downloaded. If they do not download (you will see this downloading in the terminal, then you may not have permission to do so (something we have seen with some Windows users - see the WIKI troubleshooting for more help!). If you are labeling adult human data, you may also want to use a human-pretrained network. A ResNet-101 pre-trained on MPII is available. Download it and move to the pretrained folder (this will be in your site-packages, under ../pose-tensorflow/models/pretrained).

###やり方

terminalを開いて、以下のコードを実行して三つのファイルをダウンロードし、deeplabcut_demo/deeplabcut/pose_estimation_tensorflow/models/pretrainedの中に入れます。

```
   curl -L -O https://datasets.d2.mpi-inf.mpg.de/deepercut-models-tensorflow/mpii-single-resnet-101.data-00000-of-00001 
   curl -L -O https://datasets.d2.mpi-inf.mpg.de/deepercut-models-tensorflow/mpii-single-resnet-101.meta
   curl -L -O https://datasets.d2.mpi-inf.mpg.de/deepercut-models-tensorflow/mpii-single-resnet-101.index
```

dlc-models/iteration-0/projectdate~/train内のpose_cfg.yamlを書き換えます。

```ruby:pose_cfg.yaml(train/)
all_joints:
- - 0
- - 1
- - 2
- - 3
all_joints_names:
- part1
- part2
- part3
- part4
bottomheight: 400
crop: true
cropratio: 0.4
dataset: training-datasets/iteration-0/UnaugmentedDataSet_project_date/project_name95shuffle1.mat
display_iters: 1000
global_scale: 0.8
init_weights: /content/drive/My Drive/deepLabCut_demo/deeplabcut/pose_estimation_tensorflow/models/pretrained/mpii-single-resnet-101 #ここを変える！！！
 # or /content/drive/My Drive/deeplabcut_demo/project-name-2019-03-29/dlc-models/iteration-0/projectdate-trainset95shuffle1/train/snapshot-5000 (途中からトレーニングする際)。
intermediate_supervision: false
intermediate_supervision_layer: 12
leftwidth: 400
location_refinement: true
locref_huber_loss: true
locref_loss_weight: 0.05
locref_stdev: 7.2801
max_input_size: 1500
metadataset: training-datasets/iteration-0/UnaugmentedDataSet_project_date/Documentation_data-project_95shuffle1.pickle
min_input_size: 64
minsize: 100
mirror: false
multi_step:
- - 0.005
  - 10000
- - 0.02
  - 430000
- - 0.002
  - 730000
- - 0.001
  - 1030000
net_type: resnet_101 #ここも変える！！！
num_joints: 7
pos_dist_thresh: 17
project_path: /content/drive/My Drive/deepLabCut_demo/project-name-2019-03-29
rightwidth: 400
save_iters: 50000
scale_jitter_lo: 0.5
scale_jitter_up: 1.25
topheight: 400

```
colaboratoryが止まってしまって途中から学習を続けたい場合も上記のinit_weightsを変更すればよいようです。

私は人のパーツを推定していますが、確かにresnet101を使った方が学習も早く、推定精度もよいように思います。

#追記(2019/07/12)
先日公開された、deeplabcut2.0.7では、windows 10でも、.h5ファイルが生成されます。チュートリアルに従えば、ラベリング、学習、推定と行えますね。
また、.h5ファイルの生成に成功したので、Windows 10機でトレーニングを行ってみました。Geforce GTX 1050Tiですが、問題なくdeeplabcutを使うことができました。
※学習時間はかかりますが。

とりあえず、報告まで。