なるように、なる

徒然なつぶやき、備忘録です。

OpenMMLabのmmposeをwsl2+docker+cudaで動かした話(2022.02)

wslまわりがだいぶ整ってきたので、以前から気になっていたOpenMMLabを動かしてみよう!とトライしてみました。

環境

  • os: windows10 21H2(19044.1466)
  • nvidia driver: 511.65 studio
  • wsl2 kernel: 5.10.60.1-microsoft-standard-WSL2
  • docker: 20.10.12
  • docker-compose: 1.29.2
  • mmpose: dca589a0388530d4e387d1200744ad35dd30768d
  • cuda: 11.6

参考

https://qiita.com/harmegiddo/items/55da6020314a12ba5479 https://qiita.com/okojoalg/items/0ac9a103a1364b06b151 https://docs.nvidia.com/cuda/wsl-user-guide/index.html#ch02-getting-started

概略

  • windwosの最新化
  • nvidia driverの最新化
  • wsl2のインストール
  • kernelのバージョンアップ
  • dockerのインストール
  • docker-composeのインストール
  • cudaのインストール
  • NVIDIA Container Toolkitのインストール
  • mmposeのチェックアウト
  • docker-compose.ymlの作成
  • dockerファイルとrequirementの変更
  • 動作検証
  • おまけ:VSCode Remote Containerの利用

手順

windwosの最新化

version 2004以降だとwsl2のインストールが簡単になっているので、アップデートしておきます。
バージョンの確認はwinverコマンドでできます。

nvidia driverの最新化

nvidia driverが古いとwsl2からgpuが使えない。アップデートしておきます。
game readyだと他のソフト(touch designer)でバグを踏むとの話で、studio版を入れました。

wsl2のインストール

コマンドプロンプトを管理者権限で開き、以下を実行します。
とても簡単になっていて感激しました。

wsl --install

デフォルトでUbuntu20.04が入るので、そのままに使いました。

kernelのバージョンアップ

wsl2上でcudaを使うには、wsl2 kernelのバージョンが5.10.43.3以上が必要とのこと

kernelのバージョン確認は、コマンドプロンプトで以下を実行する。

wsl cat /proc/version

kernelのバージョンアップは、コマンドプロンプトで以下を実行する。

wsl.exe --update

dockerのインストール

ここからはwsl2上での作業になります。

docker公式手順通りにインストールします。

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io -y
sudo usermod -aG docker $USER

docker-composeのインストール

こちらも公式手順通りにインストールします。 (途中でハマったのですが、たぶんdocker-composeが古いとgpuが使えないです。たぶん。)

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

cudaのインストール

こちらから Linux -> x86_64 -> WSL-Ubuntu -> 2.0 -> dev(local) をチョイスすると、インストールコマンドを出してくれます。

wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-wsl-ubuntu.pin
sudo mv cuda-wsl-ubuntu.pin /etc/apt/preferences.d/cuda-repository-pin-600
wget https://developer.download.nvidia.com/compute/cuda/11.6.0/local_installers/cuda-repo-wsl-ubuntu-11-6-local_11.6.0-1_amd64.deb
sudo dpkg -i cuda-repo-wsl-ubuntu-11-6-local_11.6.0-1_amd64.deb
sudo apt-key add /var/cuda-repo-wsl-ubuntu-11-6-local/7fa2af80.pub
sudo apt-get update
sudo apt-get -y install cuda

NVIDIA Container Toolkitのインストール

NVIDIA Container Toolkitってなに? という疑問はこちらが参考になりました。

公式手順通りにインストールします。

distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
curl -s -L https://nvidia.github.io/libnvidia-container/experimental/$distribution/libnvidia-container-experimental.list | sudo tee /etc/apt/sources.list.d/libnvidia-container-experimental.list
sudo apt-get update
sudo apt-get install -y nvidia-docker2

dockerの再起動も必要とのこと。

sudo service docker stop
sudo service docker start

mmposeのチェックアウト

ここからはmmposeを動かす話になってきます。
mmposeの動作環境をつくるにあたり、mmposeのdockerファイルをベースとすることにしました。
(ベースにする、というのは、そのままでは動きませんでしたということです。。)

mmposeのリポジトリを落としてきます。
また、動作確認時にmmdetも使用するので、合わせて落とし、mmposeからリンクを張っておきます。

git clone https://github.com/open-mmlab/mmpose.git
git clone https://github.com/open-mmlab/mmdetection.git

cd mmpose
ln -s ../mmdetection/mmdet/ mmdet

docker-compose.ymlの作成

~/mmpose/ 直下にdocker-compose.ymlを作成します。

version: '3.7'

services:
  mmpose:
    build:
      context: .
      dockerfile: docker/Dockerfile
    deploy:
      resources:
        reservations:
          devices:
          - 'driver': 'nvidia'
            'capabilities': ['gpu']
    volumes:
      - ./mmdet:/mmpose/mmdet
      - ./app:/mmpose/app
    command: sleep infinity 

mmpose/appはテストコードの置き場に利用します。
若干混乱するのですが、mmposeのDockerfileでは、mmposeのリポジトリをgitからcloneして使用しており、ローカルのファイルは見ていません。
なので、docker内で使用したいコードはマウントして使います。

"command: sleep infinity" は、VSCode Remote Container で利用する際、サービスが上がったままにするためです。

dockerファイルとrequirementの変更

デフォルトのDockerfileでは、残念ながらmmposeが動きませんでした。
(PyTorchやmmcvのバージョンが古いとか、パッケージが足りないとか。)

★がついているところが変更箇所です。

ARG PYTORCH="1.10.0"★
ARG CUDA="11.3"★
ARG CUDNN="8"★

FROM pytorch/pytorch:${PYTORCH}-cuda${CUDA}-cudnn${CUDNN}-devel

ENV TORCH_CUDA_ARCH_LIST="6.0 6.1 7.0 8.6+PTX"★
ENV TORCH_NVCC_FLAGS="-Xfatbin -compress-all"
ENV CMAKE_PREFIX_PATH="$(dirname $(which conda))/../"

RUN apt-get update && apt-get install -y git ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx\
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Install xtcocotools
RUN pip install cython
RUN pip install xtcocotools

# Install MMCV
RUN pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.10.0/index.html★

# Install MMPose
RUN conda clean --all
RUN git clone https://github.com/open-mmlab/mmpose.git /mmpose
WORKDIR /mmpose
RUN mkdir -p /mmpose/data
ENV FORCE_CUDA="1"
RUN pip install -r requirements/build.txt
RUN pip install --no-cache-dir -e .

# --- ★ここから ---

# Install runtime
WORKDIR /workspace
COPY ./requirements/runtime.txt /workspace/tmp/
RUN pip install -r /workspace/tmp/runtime.txt
COPY ./requirements/extends.txt /workspace/tmp/
RUN pip install -r /workspace/tmp/extends.txt

WORKDIR /mmpose

# --- ★ここまで ---

~/mmpose/requirements/extends.txt は、不足していたパッケージです。

terminaltables>=3.1.10
pycocotools>=2.0.4

動作検証

Okojo Vision様の記事に記載のコードで動作検証をさせていただきました! 圧倒的感謝!!

環境の検証

~/mmpose/app/test_version.py を作成します。

# PyTorch, TorchVisionのバージョン確認
import torch, torchvision
print('torch version:', torch.__version__, torch.cuda.is_available())
print('torchvision version:', torchvision.__version__)

# mmposeのバージョン確認
import mmpose
print('mmpose version:', mmpose.__version__)

# cuda, gccのバージョン確認
from mmcv.ops import get_compiling_cuda_version, get_compiler_version
print('cuda version:', get_compiling_cuda_version())
print('compiler information:', get_compiler_version())

これをdocker上で実行します。

cd ~/mmpose
docker-compose build
docker-compose run mmpose bash

cd app
python3 test_version.py

私の環境では以下のようになります。

torch version: 1.10.0 True
torchvision version: 0.11.0
mmpose version: 0.23.0
cuda version: 11.3
compiler information: GCC 7.3

mmposeの実行

~/mmpose/app/test_pose_2d.py を作成します。

import cv2
from mmpose.apis import (inference_top_down_pose_model, init_pose_model,
                         vis_pose_result, process_mmdet_results)
from mmdet.apis import inference_detector, init_detector

# 使用する姿勢推定モデルの設定
pose_config = '../configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/hrnet_w48_coco_256x192.py'
# 使用する姿勢推定モデルの学習済のチェックポイント
pose_checkpoint = 'https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w48_coco_256x192-b9e0b3ab_20200708.pth'
# 使用する物体検出モデルの設定
det_config = '../demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py'
# 使用する物体検出モデルの学習済のチェックポイント
det_checkpoint = 'https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'

# 姿勢推定モデルの作成
pose_model = init_pose_model(pose_config, pose_checkpoint)
# 物体検出モデルの作成
det_model = init_detector(det_config, det_checkpoint)

# お試しに使う画像のパス
img = '../tests/data/coco/000000197388.jpg'

# 物体検出モデルの推論
mmdet_results = inference_detector(det_model, img)

# extract person (COCO_ID=1) bounding boxes from the detection results
# COCOのカテゴリIDが1の物体(人間)の情報だけ切り出す。
person_results = process_mmdet_results(mmdet_results, cat_id=1)

# 人間に対して姿勢推定する
pose_results, returned_outputs = inference_top_down_pose_model(pose_model,
                                                               img,
                                                               person_results,
                                                               bbox_thr=0.3,
                                                               format='xyxy',
                                                               dataset=pose_model.cfg.data.test.type)

# 推論結果画像を作る(out_fileオプションの指定を追加し、画像に保存しています。)
vis_result = vis_pose_result(pose_model,
                             img,
                             pose_results,
                             dataset=pose_model.cfg.data.test.type,
                             show=False,
                             out_file="posed_000000197388.png")

これをdocker上で実行します。

cd ~/mmpose
docker-compose build
docker-compose run mmpose bash

cd app
python3 test_pose_2d.py

~/mmpose/app/posed_000000197388.png というファイルが作成されたら成功です。
やったね!

f:id:Shampagne:20220212155134p:plain

おまけ:VSCode Remote Containerの利用

今後開発するにあたり、Remote Containerが使いたかったので、設定ファイルを用意しました。

~/mmpose/.devcontainer/devcontainer.json を用意します。

// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.158.0/containers/docker-existing-docker-compose
// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
{
    "name": "dev-container", // コンテナ表示名
    "dockerComposeFile": [
        "../docker-compose.yml" // Docker Composeのファイルパス
    ],
    "service": "mmpose", // Docker Composeの接続サービス名
    "remoteUser": "$USER", // デフォルトユーザをrootから切り替える
    "workspaceFolder": "/mmpose", // Workspaceのフォルダを指定
    "extensions": [ // コンテナ内でインストールするVS Codeの拡張機能ID
        "ms-python.python",
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "kddejong.vscode-cfn-lint"
    ],
    "settings": { // コンテナ内に追加するVS Codeの設定
        "python.linting.pylintEnabled": false,
        "python.linting.flake8Enabled": true,
        "editor.formatOnSave": true,
        "python.linting.flake8Args": [
            "--max-line-length=150"
        ],
        "eslint.workingDirectories": [
            { "mode": "auto" }
        ],
        "cfnLint.path": "/home/jmc-dev/.pyenv/shims/cfn-lint",
    },
    "runArgs": ["--gpus", "all","--shm-size","8gb"]
}

remoteUserをrootから切り替える場合は、Dockerfile内でユーザ追加をしておく必要があります。