【MediaPipe】Amazon EC2のGPUインスタンスでMediaPipeを動かしてみた
カフェチームの山本です。
今までMediaPipeを動かしてきましたが、使用していた環境はWSLで処理はCPUで行っていました。
今回は、MediaPipeをGPUで動かすため、AWSのEC2でGPUインスタンスを起動し、そこで環境を構築し、動作を確認しました。利用したバージョンはv0.7.5です。
結論としては、基本的に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 をインストールする
公式ガイドにしたがってインストールしていきます。
ステップ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がありました。
ディスプレイを接続して実行すると動作した、とコメントされています。原因はディスプレイが接続されていないため、OpenGLがコンテキストを取得できなかったことのようです。
解決方法は、下のコメントで書かれていました。
上記を参考に、以下のようにプログラムを修正します。修正するファイルは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を動かす方法を調べます。