深層学習で動物の身体をトラッキングするdeeplabcutをgoogle colaboratoryで走らせる

#はじめに#

深層学習で動物の身体をトラッキングする[deeplabcut](https://github.com/AlexEMG/DeepLabCut)を[google colaboratory](https://colab.research.google.com/github/googlecolab/colabtools/blob/master/notebooks/colab-github-demo.ipynb)で走らせます。[マニュアルはこちら。](https://www.biorxiv.org/content/biorxiv/early/2018/11/24/476531.full.pdf)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/284801/7937715e-3a1a-e067-9620-b60ef4efcd82.png)

※Marvinに日本語解説が出ています→
[ディープラーニングによるマーカーレス動物追跡：様々な実験動物で利用可能なDeepLabCut](https://marvin.news/6001)

トラッキングの結果の動画を以下で見ることができます。
https://www.youtube.com/watch?v=-SqlNx7wr0w
https://www.youtube.com/watch?v=Mv6wdF9Jt6k
https://www.youtube.com/watch?v=GFLGUO0wDIw

Deeplabcutは革命的なツールで、少なくとも神経科学の運動野・体性感覚野の業界では大騒ぎになっています。日本でもかなり多くの人が使っているはずです。Userがやるのはラベリングだけなので、本来はもっとずっと簡単に使えるはずです（いずれそうしたプラットフォームも整うと思います）が、現状では環境構築がやや面倒です。ここでは普通の人が持っている普通のラップトップの空きスペースと無料のGoogle colaboratoryを使ってDeeplabcut（バージョン2.0.4）を走らせる方法をざっと説明します。

#ラベリング用の環境構築#

まず環境構築は[ここ](https://github.com/AlexEMG/DeepLabCut/blob/master/docs/installation.md)を参考にします。

**ラベリングはgoogle colaboratoryではできない**のでローカルにDeepLabCut用のPython環境を構築する必要がありました。Windows10+Anacondaで構築しようとするとNumpyのバージョン関連等よくわからないエラーが続出して数日費やしましたが解決しませんでした。このエラーは[DeepLabCutのSlack](https://deeplabcut.slack.com/)(このSlackは[Mackenzie Mathis](mackenzie@post.harvard.edu)の承認が必要)でも報告されていますのでそのうち解決すると思いますが諦めてUbuntuを使うことにしました。ラップトップに100Gbのパーティションを作ってデュアルブートします。バージョンはお勧めされている[Ubuntu16.04 LTS](http://releases.ubuntu.com/16.04/)です。ラベリングはどんなコンピュータを使っても大丈夫です。

Ubuntuを立ち上げて、Anacondaを[インストールします](https://www.digitalocean.com/community/tutorials/how-to-install-the-anaconda-python-distribution-on-ubuntu-16-04)。Terminalを開いてPython3.6の仮想環境を構築します。

```ruby:
conda create -n <nameyourenvironment> python=3.6
source activate <nameyourenvironment>
```

その後仮想環境上でdeeplabcutをpip installします。

```ruby:
pip install deeplabcut
```

さらにwxPython（pythonからラベルのために使うGUI）をpip installします。

```ruby:
pip install https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-16.04/wxPython-4.0.3-cp36-cp36m-linux_x86_64.whl
```

ここまで来たら最後にtensorflowをインストールします。ローカルでは訓練しないのでGPU環境は必要ありません。したがってこれだけでOKです。

```ruby:
pip install --ignore-installed tensorflow==1.10
```

何かエラーメッセージが出ていましたが適当に対処します。
ipythonを開いて、

```ruby:
import deeplabcut
```

これでエラーメッセージが出なければOKです。

#動画の前処理#

どんな動画でも構いませんが、コーデックの問題でうまく処理されない可能性があります。私は[XMedia Record](https://forest.watch.impress.co.jp/library/software/xmediarecode/)で映像だけのRaw video(AVI)に変換したのち[ImageJ](https://imagej.nih.gov/ij/download.html)で確認しながら必要なフレーム、場所をクロップし、**AVI(JPEG)で保存**します。ちなみに私の環境では**AVI(PNG)だとエラー**が出ました。

動画は、120 x 160 pix, 約10万フレームのグレースケールで、だいたい300MBくらいです。これを**Google drive**に保存します。Google driveはタダでも15Gb使えますが、**訓練時に10Gbくらいかそれ以上費やす**ようでしたので200GBまで容量を増やしました。費用はだいたい3ドル/月くらいです。ゴミ箱に訓練途中のデータがたまっていくので定期的にごみ箱を空にする必要があります。

ここからはUbuntuマシーンで行います。まずGoogle driveから前処理した動画をダウンロードし、Ubuntuマシン上でのパスをチェックしてください。

ラベリングはMackenzie Mathisの[この動画](https://www.youtube.com/watch?v=7xwOhUcIGio)を見るとわかりやすいと思います。一応ざっと説明します。

仮想環境をActivateして、ipython上でimport deeplabcutしたのちに実行するのはたったの4行です。

```ruby:
deeplabcut.create_new_project('日付','名前',['ファイル名.avi'])
path_config = "Generated の後のconfig.yamlのパス"
deeplabcut.extract_frames(path_config, 'automatic', 'kmeans')
deeplabcut.label_frames(path_config)
```

私はそれぞれの動画に対して100枚くらいラベルしています。config.yamlでラベルの枚数とターゲットの数を指定することができます（動画に説明があります）。

deeplabcut.extract_framesを実行する直前に、path_configで指定したconfig.yamlを開いて、ターゲットの名前とラベルの数を変更し、再度保存します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/284801/727e4f33-e1db-3fa6-abbc-91ab7ab08f08.png)


デフォルトだと、４つのターゲット、20枚のラベル数で自動的にラベル用のフレームが指定されますが、ここでは１つのターゲットの名前をTailにして（青）、ラベル数を100にしています（紫）。このファイル上のパスはUbuntu上で変更する必要はありません。あとでGoogleDrive上で変更しますので今は無視してください。

右クリックでサクサクラベリングしていきます。最後にSaveボタンを押したら終了です。
※ここでラベルの位置が保存されたh5ファイルがUbuntuだと出るのですが、Windows10でやったときはどうしてもこれが出ませんでした。


さて、ラベリングが終わったら出力された４つのFolder(dlc-model, laveled-data, training-datasets, videos)とconfig.yamlをGoogleDriveの新しいフォルダにコピーします。この後はgoogle colaboratoryとGoogleDriveを使った作業ですので、Ubuntuである必要はありません。私はこれ以降は通常使用のWindowsマシンのブラウザ上で処理しています。もちろんWindowsマシンもGPUは要りません。

#GoogleColabのGPUを使って訓練#

google colaboratoryのGPUを使いたいので、[これ](https://colab.research.google.com/github/AlexEMG/DeepLabCut/blob/master/examples/Colab_TrainNetwork_VideoAnalysis.ipynb)を利用します。

[この動画](https://www.youtube.com/watch?v=j13aXxysI2E)がとても分かりやすいですが、一応説明します。

最初の数行は無視して、「Link your Google Drive」まで行きます。GoogleDriveとgoogle colaboratoryを関連付けるために

```ruby:
from google.colab import drive
drive.mount('/content/drive')
```

を実行します。パスワードをコピーして□にペーストします。マウントできたら、deeplabcut等を!pip installしていきます。途中でランタイムを再開する必要がある場合はそうします。

```ruby:
import deeplabcut
```

まで来てエラーが出なければOKです。

次にパスを設定します。

```ruby:
path_config_file = '/content/drive/My Drive/DeepLabCut/Reaching-Mackenzie-2018-08-30/config.yaml' 
```

のところですが、ここは自分のパスに変える必要があります。Ubuntu上で作ったconfig.yamlのパスを使います。

さて、このconfig.yamlですが、この中にdeeplabcutが参照するパスの情報が２つ入っていますので、これを修正するためにconfig.yamlをGoogleDriveから開きます。[Anyfile Notepad](https://anyfile-notepad.semaan.ca/)というChrome上のアプリを使ってyamlファイルを編集しています（あんまり使いやすくないですが）。もう一度同じ写真を貼ります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/284801/d86fa44b-08c1-2164-e304-792ea1adad10.png)



google colaboratoryの左パネルの右上にあるFileからあたらしく作った４つのフォルダとconfig.yamlを置いたフォルダを探し、右クリックでパスをコピーして、config.yaml内にある二つのフォルダ名のうち一つ目（黒）を置き換えます。さらにvideosフォルダ内のaviファイルのパスをコピーし、config.yaml内のもう一つのパス（赤）を置き換えます。これでGoogleColabがGoogleDriveからフォルダと動画にアクセスできるようになりました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/284801/2711a717-e4b5-d786-f3fc-92117e0e1ca2.png)


訓練データを作って、

```ruby:
deeplabcut.create_training_dataset(path_config_file)
```

訓練を開始します。

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

![image.png](https://qiita-image-store.s3.amazonaws.com/0/284801/934b2223-ce11-081c-5ea4-1f08e43b347c.png)

訓練では、500回繰り返すたびに新しいネットワークモデルがGoogleDrive上に保存されます。iteration: の次に来る数字がこの繰り返し数です。20万回くらい繰り返すとだいたいうまくいくようですが、[google colaboratoryは油断すると途中で止まってしまいます](https://qiita.com/enmaru/items/2770df602dd7778d4ce6)ので注意しましょう。私の場合は1万回くらいでもうまくいくものと50万回でもうまくいかない動画があります。平均10万回くらいでしょうか。体感ですが3時間くらいかな。lossが減ってきて、だいたいいいかなと思ったら、強制終了ボタンを押します。うまくいかないと言っても人間が見ても難しいと思えるような動画でのミスであることがほとんどです。印象ですが、トラッキングの精度は非常に高く、隔世の感があります。

さて、あとは順番に実行して結果を見るだけですが、ビデオのパスを自分のAVIファイルのパスに修正するのだけ忘れないようにしてください。

```ruby:
videofile_path = ['/content/drive/My Drive/DeepLabCut/examples/Reaching-Mackenzie-2018-08-30/videos/MovieS2_Perturbation_noLaser_compressed.avi'] #Enter the list of videos to analyze.
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/284801/cd587dcc-8f18-4b14-da85-6f96e9df4ab4.png)


修正したら順番に実行します。このあたりなぜかよくフリーズするのですが、結果はGoogleDriveに保存されていることが多いです。中断しても途中から再開できます。ただし、再開するときは再度Diskをマウントしたりdeeplabcutをpip install したりしないといけません。

#出力を確認する#

Create labeled videoを実行すると、ラベル付きのMPEG動画がGoogleDriveのvideosフォルダのもとに作られます。また、座標のデータもvideosフォルダの"XXX.h5"に格納されています。Matlabで開いて解析するには、Matlab上で

```ruby:
data=h5read('ファイル名.h5','/df_with_missing/table');
```

などとすると取り出せます。

うまくいかなかった場合、再度ラベルを付けなおして訓練しなおすオプションがありますが、それはまたの機会に書きます。

最後にもう一度DeepLabCutで出力されたデモ動画を貼っておきます。

https://www.youtube.com/watch?v=-SqlNx7wr0w
https://www.youtube.com/watch?v=Mv6wdF9Jt6k
https://www.youtube.com/watch?v=GFLGUO0wDIw



#追記（１）　Colaboratoryを複数同時に使う#

Colaboratoryはブラウザ上で走りますので２つ以上同時に使えます。ただし、アカウント１つにつきメモリの制限があって、Deeplabcutの訓練は途中でメモリオーバーで停止します。そこでGoogleアカウントを２つ使うのはどうでしょうか。データをGoogleDriveで共有してそれぞれのアカウントでColaboratoryを開き、独立に実行してみると、**少なくとも２つのGPUマシンを並列して使うことができる**ことがわかりました。GoogleDriveの有料の追加容量200Gbに対し、Family共有設定をしていたので、特にDriveの方の容量を気にすることなく２つ同時に走らせることができました。スピードも見た目ではそれほど変わらないようです。したがって、このやり方でGPUマシンをいくつか同時に使うことができるようです。

# 追記 (2)
データファイルの解析の際、

```python:
deeplabcut.analyze_videos(path_config_file,videofile_path, save_as_csv=True)
```

などのオプションをつかえば、Excel やGoogle スプレッドシートにとりこめる、CSV形式で結果を取り出すことができます。