【MediaPipe】Amazon EC2のGPUインスタンスでMediaPipeを動かしてみた

2020.06.29

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

カフェチームの山本です。

今までMediaPipeを動かしてきましたが、使用していた環境はWSLで処理はCPUで行っていました。

【MediaPipe】Windowsで環境構築し、Multi Hand Trackingを動かしてみた

今回は、MediaPipeをGPUで動かすため、AWSのEC2でGPUインスタンスを起動し、そこで環境を構築し、動作を確認しました。利用したバージョンはv0.7.5です。

結論としては、基本的にMediaPipeの公式ガイド通りに進めれば良いのですが、一部プログラムを修正する必要がありました。

(MediaPipeに関連する記事はこちらにまとめてあります。)

【MediaPipe】投稿記事まとめ

準備手順

ステップ1:EC2インスタンスを立ち上げる

通常通り立ち上げます。設定は以下のようにしました。

  • AMIで「UDeep Learning Base AMI (Ubuntu 18.04) Version 25.0 - ami-0b5dcdb9ddb35481a」を選択します。(備考:通常のUbuntu18.04を選択すると、下の「Multi Hand Trackingを実行する(成功ver)」で修正前と同じエラーが出てしまい、先に進めませんでした)
  • インスタンスタイプで「p2.xlarge」を選択します。上のフィルター条件から「GPU インスタンス」を選択すると探しやすいです。「確認と作成」をクリックします。(未確認ですが、g2.2xlarge等でも可能だと思います)
  • 起動時に、新しくキーペアを作成するか、既存のキーペアを利用するか選択します。

起動したあと、一度EC2の画面から再起動してください。

ステップ2:EC2インスタンスに接続する

SSHで、EC2のインスタンスの画面に表示されている「パブリック DNS (IPv4)」にアクセスします。

コマンドは以下のようです。キーペアファイルへのパスを、ステップ1でダウンロードしたファイル(新規作成した場合)へのパスに、アクセス先のアドレスを、アクセス先のインスタンスのアドレスに、それぞれ変更してください。(WindowsであればPowerShellから実行できます)

ssh -i "C:\path\to\key.pem" ubuntu@ec2-000-000-000-000.ap-northeast-1.compute.amazonaws.com

ステップ3:MediaPipe をインストールする

公式ガイドにしたがってインストールしていきます。

Installation

ステップ3-0:Ubuntuをアップデートする

SSHで接続できたら、以下のコマンドを実行します。途中で出てくる設定画面では「keep local version...」を選択します。

sudo apt update
sudo apt upgrade -y

EC2の画面から、インスタンスを再起動します。SSHで再度接続してください。

ステップ3-1:MediaPipeのリポジトリをクローンする

git clone https://github.com/google/mediapipe.git
cd mediapipe

ステップ3-2:bazelをインストールする

インストールガイドに貼られているリンク先に書かれている方法でインストールします。今回は2つ目の方法(Using the binary installer)を利用しました。

今回利用したbazelのバージョンは3.3.0をでしたが、最新のバージョンを確認すると良いと思います。

sudo apt install g++ unzip zip -y

sudo apt-get install openjdk-11-jdk -y

wget https://github.com/bazelbuild/bazel/releases/download/3.3.0/bazel-3.3.0-installer-linux-x86_64.sh
chmod +x bazel-3.3.0-installer-linux-x86_64.sh
./bazel-3.3.0-installer-linux-x86_64.sh --user
rm ./bazel-3.3.0-installer-linux-x86_64.sh 

export PATH="$PATH:$HOME/bin"

ステップ3-3:OpenCVとFFmpegをインストールする

今回は、インストールガイドのOption 2を利用しました。(下のコマンドはcloneしたMediaPipeのフォルダで実行してください)

chmod +x setup_opencv.sh
./setup_opencv.sh

(数十分かかります)

ステップ3-4:GPU用のEGLドライバをインストールする

sudo apt-get install mesa-common-dev libegl1-mesa-dev libgles2-mesa-dev -y

Hello Worldで動作確認

MediaPipeのHello Worldを動かします。

export GLOG_logtostderr=1

bazel run --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11 \
    mediapipe/examples/desktop/hello_world:hello_world

bazelのビルド後(数分かかります)、以下のように「Hello World!」が10回表示がされればOKです。

I20200629 11:55:45.702250 28131 hello_world.cc:56] Hello World!
I20200629 11:55:45.702352 28131 hello_world.cc:56] Hello World!
I20200629 11:55:45.702378 28131 hello_world.cc:56] Hello World!
I20200629 11:55:45.702397 28131 hello_world.cc:56] Hello World!
I20200629 11:55:45.702419 28131 hello_world.cc:56] Hello World!
I20200629 11:55:45.702440 28131 hello_world.cc:56] Hello World!
I20200629 11:55:45.702461 28131 hello_world.cc:56] Hello World!
I20200629 11:55:45.702484 28131 hello_world.cc:56] Hello World!
I20200629 11:55:45.702507 28131 hello_world.cc:56] Hello World!
I20200629 11:55:45.702527 28131 hello_world.cc:56] Hello World!

Multi Hand Trackingを動かす

ファイルを移動する

カメラを接続できないため、動画ファイルを転送します。以下のようにscpコマンドでアップロードできます。(下のコマンドだけは、今までのShellウィンドウとは別に、新たなウィンドウを開いて実行してください)

キーペアのファイルパス、動画ファイル、インスタンスのアドレス、転送先のファイルパスは適宜変更してください。

scp -i "C:\path\to\key.pem" -r .\video.mp4 ubuntu@ec2-000-000-000-000.ap-northeast-1.compute.amazonaws.com:/home/ubuntu/mediapipe

Multi Hand Trackingを実行する(エラーver)

Multi Hand TrackingのGPU版をビルドし(数十分かかります)、実行します。転送先のファイルパスを変えた場合は適宜変更してください。

bazel build -c opt --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11 \
  mediapipe/examples/desktop/multi_hand_tracking:multi_hand_tracking_gpu

export GLOG_logtostderr=1
bazel-bin/mediapipe/examples/desktop/multi_hand_tracking/multi_hand_tracking_gpu \
  --calculator_graph_config_file=mediapipe/graphs/hand_tracking/multi_hand_tracking_desktop_live.pbtxt \
  --input_video_path="video.mp4" \
  --output_video_path="video_.mp4"

実行すると以下のようなエラーが出力されます。

I20200629 13:42:14.124982 28141 demo_run_graph_main_gpu.cc:57] Initialize the calculator graph.
I20200629 13:42:14.127943 28141 demo_run_graph_main_gpu.cc:61] Initialize the GPU.
I20200629 13:42:16.027736 28141 gl_context_egl.cc:158] Successfully initialized EGL. Major : 1 Minor: 5
W20200629 13:42:16.027791 28141 gl_context_egl.cc:163] Creating a context with OpenGL ES 3 failed: UNKNOWN: ; eglChooseConfig() returned no matching EGL configuration for RGBA8888 D16 ES3 request.
W20200629 13:42:16.027810 28141 gl_context_egl.cc:164] Fall back on OpenGL ES 2.
E20200629 13:42:16.031584 28141 demo_run_graph_main_gpu.cc:186] Failed to run the graph: ; eglChooseConfig() returned no matching EGL configuration for RGBA8888 D16 ES2 request.

プログラムを修正する

エラーを検索してみると、以下のissueがありました。

Examples using tf-lite with gpu (face_detection_gpu) does not compile on jetson nano · Issue #305 · google/mediapipe

ディスプレイを接続して実行すると動作した、とコメントされています。原因はディスプレイが接続されていないため、OpenGLがコンテキストを取得できなかったことのようです。

Examples using tf-lite with gpu (face_detection_gpu) does not compile on jetson nano · Issue #305 · google/mediapipe

解決方法は、下のコメントで書かれていました。

Examples using tf-lite with gpu (face_detection_gpu) does not compile on jetson nano · Issue #305 · google/mediapipe

上記を参考に、以下のようにプログラムを修正します。修正するファイルはmediapipe/gpu/gl_context_egl.ccの97行目です。vimやnanoなどで開いて、以下のように修正してください。( "| EGL_WINDOW_BIT"を削除します)

修正前

const EGLint config_attr[] = {
      ...
      EGL_SURFACE_TYPE, EGL_PBUFFER_BIT | EGL_WINDOW_BIT,
      ...
  };

修正後

const EGLint config_attr[] = {
      ...
      EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
      ...
  };

Multi Hand Trackingを実行する(成功ver)

再度ビルドし、実行します。

bazel build -c opt --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11 \
  mediapipe/examples/desktop/multi_hand_tracking:multi_hand_tracking_gpu

export GLOG_logtostderr=1
bazel-bin/mediapipe/examples/desktop/multi_hand_tracking/multi_hand_tracking_gpu \
  --calculator_graph_config_file=mediapipe/graphs/hand_tracking/multi_hand_tracking_desktop_live.pbtxt \
  --input_video_path="video.mp4" \
  --output_video_path="video_gpu.mp4"

結果が以下のように表示されれば成功です。最後にSegmatation faultと表示されてしまいますが、ファイルの出力自体はできました。Shutting downの後なので、そこまで影響はなさそうです。修正するには、もう少しプログラムの中を読む必要があるため、今後の課題としたいと思います。

(グラフの内容)
I20200629 13:44:36.920063 28508 demo_run_graph_main_gpu.cc:57] Initialize the calculator graph.
I20200629 13:44:36.922953 28508 demo_run_graph_main_gpu.cc:61] Initialize the GPU.
I20200629 13:44:36.934150 28508 gl_context_egl.cc:158] Successfully initialized EGL. Major : 1 Minor: 5
I20200629 13:44:36.961654 28514 gl_context.cc:324] GL version: 3.2 (OpenGL ES 3.2 NVIDIA 440.33.01)
I20200629 13:44:36.961781 28508 demo_run_graph_main_gpu.cc:67] Initialize the camera or load the video.
I20200629 13:44:37.536909 28508 demo_run_graph_main_gpu.cc:88] Start running the calculator graph.
I20200629 13:44:37.540650 28508 demo_run_graph_main_gpu.cc:93] Start grabbing and processing frames.
INFO: Created TensorFlow Lite delegate for GPU.
I20200629 13:44:40.792667 28508 demo_run_graph_main_gpu.cc:160] Prepare video writer.
I20200629 13:44:45.500483 28508 demo_run_graph_main_gpu.cc:175] Shutting down.
I20200629 13:44:47.819614 28508 demo_run_graph_main_gpu.cc:189] Success!
Segmentation fault (core dumped)

結果は以下のコマンドで、出力ファイルを手元にダウンロードします。元ファイルをアップロードしたときと同様に、別のウィンドウを立ち上げると接続を切らずにすみます。キーペアのファイルパス、接続先のインスタンスのアドレス、出力ファイルのパス、ダウンロード先のファイルパスは適宜変更してください。

scp -i "C:\path\to\key.pem" ubuntu@ec2-000-000-000-000.ap-northeast-1.compute.amazonaws.com:/home/ubuntu/mediapipe/video_gpu.mp4 .

CPUとGPUの処理速度を比較

計測

利用した動画は、ユーザが2人がいて、手が2~3つ映っている動画です。時間は2[s]、解像度は1920*1080[px]、フレームレートは30[fps]でした。

CPUの場合のコマンドは、以下のようです。上記のコマンドの"gpu"を"cpu"に変更したものです。

bazel build -c opt --copt -DMESA_EGL_NO_X11_HEADERS --copt -DEGL_NO_X11 \
  mediapipe/examples/desktop/multi_hand_tracking:multi_hand_tracking_cpu

export GLOG_logtostderr=1
bazel-bin/mediapipe/examples/desktop/multi_hand_tracking/multi_hand_tracking_cpu \
  --calculator_graph_config_file=mediapipe/graphs/hand_tracking/multi_hand_tracking_desktop_live.pbtxt \
  --input_video_path="video.mp4" \
  --output_video_path="video_cpu.mp4"

計測はプログラム実行してから終了までの時間を、目視で計測しました。

結果

処理時間を計測した結果、以下のようになりました。(当然ではありますが)GPUの方がかなり高速に処理できています。メインである検出処理以外の部分(オーバヘッド)もあると思われるので、この数値以上に高速化されていると推測されます。

  • CPU:36秒
  • GPU:5秒

まとめ

MediaPipeをAWS EC2のGPUインスタンス上で動かせるようになりました。さらにプログラムを少し変更する必要はありますが、店舗から画像or動画をAWSにアップロードして、MediaPipeで検出するまでの準備ができました。

今後は、クラウドではなく、エッジでMediaPipeを動かす方法を調べます。