「喰う・書く・逃げる」に棲む処

 動物に関するデータ分析者のブログです

DeepLabCutの使い方(Dockerが正常に機能しない場合)

こんにちは

今回はDeepLabCutの使い方を解説しておきたいと思います。使い方自体はそんなに難しくはなくこちらに記されているとおりに使えばほとんどの機能は正常に動くと思います。

github.com

YouTubeでも解説されています。


Tutorial Part I: DeepLabCut- How to create a new project, label data, and start training


Tutorial Part II: DeepLabCut - network evaluation, refinement, and re-training

しかし、以前に解説したインストール方法を使った場合、Dockerでエラーが出てしまうかもしれません。

krhb.hatenablog.com

そこで、この方法でインストールした場合の使い方を解説しておこうと思います(基本的にDockerを端折るだけです)。Dockerが正常に動く場合は上にマニュアルに従ってください。Ubuntuでの操作を前提にしています。

基本的な解析な流れ

解析は以下の図のような流れで進行します。

f:id:KRHB:20190506203919p:plain
"https://github.com/AlexEMG/DeepLabCut"

  1. はじめに一部の動画(データ)を使って教師データの作成とトレーニング用のニューラルネットワークを構築します(Process: Create project - Create training datasets)。
  2. 次にネットワークのトレーニングを行います(Process: Train network)。
  3. レーニングが終了したらトレーニングの結果を確認と別のデータを使って解析を行います(Process: Evaluate network - Analyze video)。
  4. 満足の行く結果が得られなければ解析したデータから間違えていたフレームを抽出して修正して教師データに加えます(Process: Extract outlier frames - Create training datasets)。
  5. 再びトレーニングを行います(Process: Train network)。
  6. レーニングと解析、修正を繰り返して良い結果が得られるようになれば解析用のニューラルネットワークの完成です。
  7. 最後に、このニューラルネットワークを使ってデータを解析します。

操作方法

Step.1 起動

はじめに仮想環境を起動します。Termianlを起動したら以下のコマンドを入力します。

$ source activate 仮想環境名

すると以下のように$の前の部分が変わります。

(仮想環境名) ユーザー名@パソコン名:~$

次にPythonを起動します。

$ ipython

以下のように表示されたらOKです。

Python 3.6.8 |Anaconda, Inc.| (default, Dec 30 2018, 01:22:34) 
Type 'copyright', 'credits' or 'license' for more information
IPython 6.0.0 -- An enhanced Interactive Python. Type '?' for help.

In []:

次にDeeplabcutを起動します。Deeplabcutを使うとき(再開するとき)は毎回必ずここまでの手順を踏んでください。

In []: import deeplabcut

Step.2 プロジェクトの作成

次にプロジェクトを作成します(Process: Create project)。コマンドの中の日本語は適当な語句に置き換えてください。

In []: config_path=deeplabcut.create_new_project('プロジェクト名','解析者名',['教師データを作成するための動画ファイル'],working_directory='解析用フォルダの作成場所',copy_videos=False)

このコマンドを実行すると以下のように表示されます。

A new project with name プロジェクト名-解析者名-実行日時 is created at 解析用フォルダの作成場所 and a configurable file (config.yaml) is stored there. (省略)

プロジェクト名-解析者名-実行日時というフォルダがworking_directory=で指定したディレクトリの真下に作成されています。また、このフォルダの中にconfig.yamlというファイルが作成されます。このファイル名はどのデータで実行しても同じです。また、上記のコマンドでは冒頭でconfig_path=deeplabcut.crerate_(省略)としています。こうすることでconfig_pathという変数にconfig.yamlへのディレクトリが格納されます。こうすることで後に書くコマンドを短くすることができます。

プロジェクトを作成した後に一旦作業を中断してTermianlを閉じた場合(Pythonや仮想環境を終了した場合)、変数は消去されるので、Deeplabcutをもう一度起動してからconfig_path=<config.yamlのディレクトリ>を実行する必要があります。

Step.3 教師データの作成

まず、config.yamlの一部を書き換えます。config.yamlが存在するフォルダに行き、これをクリックして開きます。するとテキストエディタ(TextEditorかVisualStudioCodeで開かれます)で以下のように表示されます。

# Project definitions (do not edit)
Task: プロジェクト名
scorer: 解析者名
date: 実行日時

(省略)

bodyparts:
- Hand
- Finger1
- Finger2
- Joystick
start: 0
stop: 1
numframes2pick: 20

# Plotting configuration
pcutoff: 0.1

(省略)

書き換えるのはbodyparts:の下4行の - Handなどです。デフォルトの状態では、これら4つの名前の座標を解析で取得することになっています。今回はA_headとB_headの座標の2点を取得するものと仮定します。この場合、以下のように書き換えます。

(省略)
bodyparts:
- A_head
- B_head
start:0
(省略)

もし、6点の座標がほしければbodyparts:の下に - 座標名という書式で6行、書いてください。座標名はアルファベットで書くことを推奨します(日本語での動作確認はしていません)。

次に教師データにするフレームを抜き出します(Process: Extract frames)。以下のコマンドを実行します。

In []: deeplabcut.extract_frames(config_path, 'automatic', 'kmeans')

'automatic'という設定ではその後ろに書いたアルゴリズムでフレームを抽出します。上のコマンドでは'kmeans'というアルゴリズムに基づいて抽出されます。'kmeans'は動画内で大きな変化が起きたところを中心にして抽出するアルゴリズムです。他に'uniform'というアルゴリズムがあります。このアルゴリズムは一定の間隔ごとにフレームを抽出します。

'automatic''manual'に変更できます。'manual'の場合、手動で抜き出すフレームを指定することになります。

上記のコマンドを実行すると以下のように表示されます。

Config file read successfully.
Do you want to extract (perhaps additional) frames for video: 動画ファイル ?
yes/no

ここでyesと打ち込むと以下のように表示されます。

Frames were selected.
You can now label the frames using the function 'label_frames' (if you extracted enough frames for all videos).

以上でフレームの抽出は終了です。

GUIでの操作

次に抽出したフレームに座標を打ちます(Process: Label frames)。

点打ちは下の動画が参考になります。


DeepLabCut: new LABELING GUI demo (11/18/2018) for versions prior to 2.0.4

まずは以下のコマンドを実行します。

In []: deeplabcut.label_frames(config_path)

これを実行するとGUI画面が起動します。

右下のLoad framesをクリックするとプロジェクトの一番上の階層のフォルダが開かれます。その中にlabeled-dataというフォルダがあるのでこれをクリックして、その中のデータ名と同じ名前がつけられているフォルダをクリックします。最後に右下のOpenを押すと点打ち画面になります。

点打ち画面では右クリックで点打ち、左クリックで点を移動することができます。特定の部位を点打ちをすると自動的に別の部位を点打ちをするように切り替わります。今、どの点を打とうとしているのか確認するには右側のSelect a bodypart to labelを参照してください。チェックを入れると点打ちする部位が切り替わります。もし、点打ちする部位が確認できないときは点打ちをしないでそのままにします。1つのフレーム内すべての点が打ち終わると次のフレームに切り替わります。

下のZoomボタンを押して左クリックしたままマウスを動かして四角い線を引くとその部分が拡大されます。拡大が終わったらもう一度Zoomボタンを押して機能をオフにします。Homeボタンを押すと元の倍率に戻ります。Panボタンは拡大中に視野を移動させるために使います。ボタンを押して視野の中で左クリックをしたままマウスを動かすと視野が移動します。NextPreviousボタンはフレームを切り替えるの使います。

尚、座標名を確認するとき、座標点の色は当てにならないので無視してください。カーソルを合わせるとポップアップで座標名が表示されます。

すべてのフレームで座標を打ち終わったらSaveQuitを押してGUI画面を終了します。

点打ちした座標の確認

次に点打ちしたフレームとその座標を確認します。以下のコマンドを実行するとThey are stored in the following folder:のところに確認用の画像が作成されたフォルダの場所が示されます。

In []: deeplabcut.check_labels(config_path)

Creating images with labels by 解析者名.
They are stored in the following folder: フォルダ名_labeled.
If all the labels are ok, then use the function 'create_training_dataset' to create the training dataset!

フォルダの中の画像を開いて確認します。問題がなければ次に進みます。

Step.4 トレーニング用ニューラルネットワークの作成・トレーニン

レーニング用のニューラルネットワークを作成します(Process: Create training datasets)。以下のコマンドを実行すると作成されます。

In []: deeplabcut.create_training_dataset(config_path)

The training dataset is successfully created. Use the function 'train_network' to start training. Happy training!

次はトレーニングです(Process: Train network)。以下のコマンドで実行します。トレーニングはiterationが1030000になるまで続きます。20-24時間程度の時間が必要です。時間がなければiterationが200000になったところで強制終了([CTRL+C])しても良いようです(確認していませんがおそらく精度は落ちます)。最後にエラーのような表示が含まれていますが無視して問題ありません。

In []: deeplabcut.train_network(config_path)

Config:
(省略)
Starting training....
iteration: 1000 loss: 0.148 lr: 0.02
(省略)
iteration: 1029000 loss: 0.0007 lr: 0.001
iteration: 1030000 loss: 0.0007 lr: 0.001
Exception in thread Thread-3292:
Traceback (most recent call last):
(省略)
CancelledError (see above for traceback): Enqueue operation was cancelled
     [[node fifo_queue_enqueue (defined at /home/ユーザー名/.conda/envs/仮想環境名/lib/python3.6/site-packages/deeplabcut/pose_estimation_tensorflow/train.py:39)  = QueueEnqueueV2[Tcomponents=[DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT], timeout_ms=-1, _device="/job:localhost/replica:0/task:0/device:CPU:0"](fifo_queue, _arg_Placeholder_0_0, _arg_Placeholder_1_0_1, _arg_Placeholder_2_0_2, _arg_Placeholder_3_0_3, _arg_Placeholder_4_0_4)]]


The network is now trained and ready to evaluate. Use the function 'evaluate_network' to evaluate the network.

Step.5 トレーニングの評価

レーニング結果を評価します。以下のコマンドを実行します。

In []: deeplabcut.evaluate_network(config_path,plotting=True)

Config:
{'all_joints': [[0], [1]],
(省略)
Could not load matplotlib icon: can't use "pyimage703" as iconphoto: not a photo image
Could not load matplotlib icon: can't use "pyimage721" as iconphoto: not a photo image
Could not load matplotlib icon: can't use "pyimage739" as iconphoto: not a photo image
The network is evaluated and the results are stored in the subdirectory 'evaluation_results'.
If it generalizes well, choose the best model for prediction and update the config file with the appropriate index for the 'snapshotindex'.
Use the function 'analyze_video' to make predictions on new videos.
Otherwise consider retraining the network (see DeepLabCut workflow Fig 2)

評価はトレーニングされたネットワークと教師データを使って予測と教師データとの誤差を計算しているようです。evaluation-results/iteration-0のフォルダに評価の結果CSVファイルと教師データに予測した点をプロットした画像が保存されているので確認してください。

今回使っている例ではプロジェクトのフォルダ/evaluation-results/iteration-0の中にcsvとトレーニングで使ったデータにプロットした結果が保存されています。

次にデータの解析を試験的に行います(Process: Analyze video)

まず、解析する動画ファイルのディレクトリをvideo_pathという変数の中に格納します。今回の例では以下のようになります。Terminalにドラッグアンドドロップした後にvideo_path=[]で囲めば完了です。

In []: video_path=['新しい動画ファイル']

以下のコマンドを実行すると動画が解析されて推測された座標がcsvファイル、h5ファイルなどが解析した動画ファイルと同じフォルダの中に出力されます。

In []: deeplabcut.analyze_videos(config_path,video_path,save_as_csv=True)

Config:
{'all_joints': [[0], [1]],
(省略)
Starting to extract posture
210it [00:07, 27.24it/s]                                                       Detected frames:  204

Saving results in /home/...
Saving csv poses!
The videos are analyzed. Now your research can truly start! 
 You can create labeled videos with 'create_labeled_video'.
If the tracking is not satisfactory for some videos, consider expanding the training set. You can use the function 'extract_outlier_frames' to extract any outlier frames!

以下のコマンドを実行すると解析で得られた座標がプロットされます。図はも同じく動画ファイルと同じフォルダの中に出力されます。

In []: deeplabcut.plot_trajectories(config_path,video_path)

/home/(省略)/動画ファイル
Starting %  /home/(省略) ['動画ファイル']
/home/(省略)  already exists!
Loading  /home/(省略)/動画ファイル and data.
Could not load matplotlib icon: can't use "pyimage757" as iconphoto: not a photo image
Could not load matplotlib icon: can't use "pyimage766" as iconphoto: not a photo image
Could not load matplotlib icon: can't use "pyimage775" as iconphoto: not a photo image
Plots created! Please check the directory "plot-poses" within the video directory

以下のコマンドを実行すると解析した動画に解析で得られた座標を重ね合わせた動画を作成してくれます。この動画も同じく元の動画と同じフォルダの中にmp4で出力されます。

In []: deeplabcut.create_labeled_video(config_path,video_path)

Starting %  /home/(省略) ['動画ファイル']
Loading  /home/(省略)/動画ファイル and data.
False 0 1280 0 768
204
Duration of video [s]:  6.8 , recorded with  30.0 fps!
Overall # of frames:  204 with cropped frame dimensions:  1280 768
Generating frames and creating video.
100%|█████████████████████████████████████████████████████████| 204/204 [00:01<00:00, 176.11it/s]

これらの結果から、予測の精度が低いと判断されるときはStep.6に進みます。精度が十分ならばStep.7に進みます。

Step.6 教師データの追加・再トレーニン

次に解析した結果から予測精度の低い部分の動画のフレームを抽出します(Process: Extract outlier frames)。他のフレームの座標の位置と比較して明らかに間違えていると判定される座標が含まれている部分を抽出するようです。以下のコマンドを実行します。

In []: deeplabcut.extract_outlier_frames(config_path,video_path)

network parameters: DeepCut_resnet50_test_runMar4shuffle1_1030000
Method  jump  found  43  putative outlier frames.
Do you want to proceed with extracting  20  of those?
If this list is very large, perhaps consider changing the paramters (start, stop, epsilon, comparisonbodyparts) or use a different method.
yes/no

ここでyesと打ち込むと抽出が始まります

Loading video...
Duration of video [s]:  6.8 , recorded @  30.0 fps!
Overall # of frames:  204 with (cropped) frame dimensions: 
Kmeans-quantization based extracting of frames from 0.0  seconds to 6.8  seconds.
Extracting and downsampling... 43  frames from the video.
43it [00:00, 263.36it/s]
Kmeans clustering ... (this might take a while)
Let's select frames indices: [28, 13, 91, 6, 29, 61, 15, 77, 58, 46, 56, 75, 54, 36, 49, 67, 34, 70, 2, 30]
Could not load matplotlib icon: can't use "pyimage793" as iconphoto: not a photo image
(省略)
Could not load matplotlib icon: can't use "pyimage1117" as iconphoto: not a photo image
Could not load matplotlib icon: can't use "pyimage1135" as iconphoto: not a photo image
Creating the symbolic link of the video
AUTOMATIC ADDING OF VIDEO TO CONFIG FILE FAILED! You need to do this manually for including it in the config.yaml file!
Videopath: 動画ファイル Coordinates for cropping: None
The outlier frames are extracted. They are stored in the subdirectory labeled-data\(省略).
Once you extracted frames for all videos, use 'refine_labels' to manually correct the labels.

次に抽出されたフレームの座標を修正します(Process: Refine labels)。以下のコマンドを実行すると上記で説明した点打ちの画面が現れます。

In []: deeplabcut.refine_labels(config_path)

使い方はほとんど同じですが、フォルダは新たに解析したデータ名が記されているフォルダを選択し、その中のh5ファイルを開くと先程とほとんど同じ点打ちモードになります。今度は点が打たれた状態で表示されます。座標は左クリックで移動することができます。また、座標を削除したい場合は右クリックすると消えます。座標名を識別するのに色は完全に当てにならないので、カーソルを座標に合わせてポップアップで表示された座標名で識別します。修正が終わったらSaveQuitで終了します。すると、Terminalでは以下のような表示になります。

Closing... The refined labels are stored in a subdirectory under labeled-data. Use the function 'merge_datasets' to augment the training dataset, and then re-train a network using create_training_dataset followed by train_network!

次に修正したデータを教師データとして付け加えます(Process: Merge datasets)。はじめにconfig.yamlを修正します。これをフォルダからクリックして開くと以下のようになっていると思います(今回使っている例では)。

# Project definitions (do not edit)
Task: プロジェクト名
scorer: 解析者名
date: 実行日時

# Project path (change when moving around)
project_path: プロジェクトのパス

# Annotation data set configuration (and individual video cropping parameters)
video_sets:
  /home/(省略)/動画ファイル:
    crop: 0, 1280, 0, 768
bodyparts:
- A_head
- B_head
start: 0
stop: 1
numframes2pick: 20

9行目の# Annotation data set configuration (and individual video cropping parameters) video_sets:の部分に新たに解析した動画/home/(省略)/動画ファイル2を付け加えて以下のようにします。

# Annotation data set configuration (and individual video cropping parameters)
video_sets:
  /home/(省略)/動画ファイル:
  /home/(省略)/動画ファイル2:
    crop: 0, 1280, 0, 768

画面サイズが動画ごとに異なる場合はそれぞれcrop: 0, 横px, 0, 縦pxを書き加えます

次に以下のコマンドを実行して修正したデータを教師データに加えます。

In []: deeplabcut.merge_datasets(config_path)

Merged data sets and updated refinement iteration to 1.
Now you can create a new training set for the expanded annotated images (use create_training_dataset).

別のデータを追加したい場合は以下のコマンドを実行します

deeplabcut.add_new_videos(config_path,[新しい動画ファイル],copy_video=False)

次に

In []: deeplabcut.check_labels(config_path)

Creating images with labels by 解析者名.
(省略)
Could not load matplotlib icon: can't use "pyimage2197" as iconphoto: not a photo image
Could not load matplotlib icon: can't use "pyimage2215" as iconphoto: not a photo image
If all the labels are ok, then use the function 'create_training_dataset' to create the training dataset!

labeled-dataのフォルダの中に元データごとに元データ名_labeledという名前のフォルダにまとめられているのですべて確認します。問題がなければStep.4に戻ってやり直します。尚、Step.5video_pathという変数を作成していますが、新たに動画を解析する場合はその動画のパスを使って変数を作り直してください。

Step.7 解析

Step.4からStep.6を繰り返して精度が十分になったら動画の解析行います。ここでは

In []: deeplabcut.analyze_videos(config_path,video_path,save_as_csv=True)

また、動画と座標を重ねたければ以下のコマンドを実行します。

In []: deeplabcut.create_labeled_video(config_path,video_path)

以上で解析終了です。

補足情報

  • ここまでの説明では動画を1つずつ扱っていましたが、複数の動画を扱うことができます。ここまで動画ファイルのパスをすべて[]で囲って来ました。複数の動画をまとめて扱いたい場合は['video1','video2',....,'videoX']とします。

  • レーニングに必要なフレーム数はデータによって様々です(目の虹彩の動きの追跡:40フレーム、マウスの手の動きの追跡:180フレーム、魚の動きの追跡:250フレーム、踏み車でのマウスの動きの追跡:825フレームなど)。

  • レーニングには様々な条件のデータを使うと精度が良くなります(例えば、明るいときと暗いときの両方を使うなど)。

  • 条件が変わらなくても複数のデータを使ってトレーニングすることが推奨されています。

  • レーニングを繰り返すとGPUのメモリが振り切ってエラーになることがあります。このときはTerminalを新しく開いてnvidia-smiを実行します。Process namecondaという文字が含まれているものを探します。おそらく、それのGPU Memory Usageの数字が異様に高い値を示しているはずです。それのPIDを特定したらsudo kill -9 PIDの番号を実行します。これでGPUのメモリが解放されるのでトレーニングを再開することができます。

  • 公開されているマニュアルを参考にしていますが一部の操作が異なります。

参考

www.biorxiv.org

www.mousemotorlab.org

github.com