Deep learning/Pose estimation

PoseNet으로 알아보는 Pose estimation [2]

bono. 2021. 2. 3. 07:16

본 포스팅은 PoseNet official blog post [1]와 PoseNet의 single pose estimation을 구현하는데 참고한 논문들 [2,3]을 참고하여 구성하였다.

 

PoseNet

PoseNet은 2018년 Google에서 공개한 On-device 내 real-time pose estimation이 가능한 오픈소스이다. Posenet을 사용하면 single / multi pose를 예측 할 수있다. 하지만 본 포스트에서는 한명의 사람만 존재하는 single pose를 가정한다 (훨씬 쉽다). PoseNet에서 single pose를 예측하는건 크게 다음의 두가지 단계로 진행된다. RGB 형태의 입력을 모델에 넣고, 여러 output을 얻게 된다.

  1. RGB Input → CNN Model
  2. CNN Model output → (poses, pose confidence scores, keypoint positions, and keypoint confidence scores)

그림 01. PoseNet은 각 사람 별 confidence value와 그 사람에 대한 key point confidence 를 return 한다. 예를 들어 single model에서 사람별 confidence value가 높은 사람을 기준으로 output이 만들어진다 [1].

PoseNet model을 이용하기 전, 알아야 할 키워드들이 있다.

  • Pose : higtest level에서 PoseNet은 pose object를 return한다. pose object는 keypoint lists와 각 사람별 instance level의 confidence score를 포함한다.
  • Pose confidence scores : 한 사람에 대해 전반적으로 검출된 pose들의 confidence score를 나타낸다. [0.0 , 1.0] 의 범위를 가지며 충분한 점수를 가지지 못하면 pose를 없앨수도 있다.
  • Keypoint : Nose, right ear, left knee와 같이 사람의 각 부분(관절)에 대한 예측값. keypoint는 position 과 confidence score를 포함한다. PoseNet은 그림 02와 같이 17개의 관절에 대한 keypoint를 예측한다.
  • Keypoint confidence scores : 검출된 각 관절이 얼마나 정확한지 판단1한다. [0.0, 1.0]의 범위를 가진다. 그림 01의 오른쪽 그림을 보면 더 이해가 잘 될 것이라 생각된다.
  • Keypoint positions : 검출된 각 관절의 2D x,y 좌표를 나타낸다.

그림 02. PoseNet에 의해 검출되는 17개 keypoints [1]

 

PoseNet Input (Single pose estimation)

PoseNet을 이용하여 single pose estimation을 하는것 (그림 03.) 은 multi pose estimation을 하는것보다 간단하고, 빠르다. 이를 사용 할 때 이미지 내 단 한사람만 존재하고 그 사람이 정중앙에 위치할 때, 가장 이상적인 성능을 낸다. single pose를 estimation 하는것이니, 여러 사람이 존재하면 인식이 안된다.

그림 03. Single pose estimation 예시 [1]

위와 같은 결과를 얻기 위해서는 PoseNet의 hyperparameter들을 세팅 한 후, 이미지를 입력해야 한다. 입력시 설정해주어야 하는 hyperparameter들은 다음과 같고, 이에대해 간단하게만 설명하겠다. (아래 코드는 Jave Script 기반인데 이름만 보면 된다.)

const imageScaleFactor = 0.50;
const flipHorizontal = false;
const outputStride = 16;
const imageElement = document.getElementById('cat');
// load the posenet model
const net = await posenet.load();
const pose = await net.estimateSinglePose(imageElement, scaleFactor, flipHorizontal, outputStride);
  • Input image element PoseNet에 입력되는 이미지. 정사각형 형태여야함
  • Image scale factor [0.2,1] 의 범위를 가지는 값. 이미지의 scale을 결정한다. scale factor가 낮으면, 정확도가 낮아지는 대신 속도가 빨라진다.
  • Flip horizontal 이미지가 뒤집혀있거나, 반전이 되어있을때 사용하는 hyperparameter.
  • Output stride 입력 이미지를 얼마나 세세히 볼 것인지 정하는 hyperparameter. 32,16,8의 값을 가질 수 있으며, CNN model 내에서 layer의 높이와 넓이에 영향을 준다. 따라서 정확도, 속도와 연관된 parameter라고 생각하면 된다. 큰 값을 가질수록 속도가 빨라지지만, 정확도가 낮아진다.

PoseNet output

결과적으로 다음과 같은 json output을 얻는다 (일단 형태만 보자).

{
  "score": 0.32371445304906,
  "keypoints": [
    { // nose
      "position": {
        "x": 301.42237830162,
        "y": 177.69162777066
      },
      "score": 0.99799561500549
    },
    { // left eye
      "position": {
        "x": 326.05302262306,
        "y": 122.9596464932
      },
      "score": 0.99766051769257
    },
    { // right eye
      "position": {
        "x": 258.72196650505,
        "y": 127.51624706388
      },
      "score": 0.99926537275314
    },
    ...
  ]
}

 

About PoseNet Model

PoseNet은 크게 ResNet과 MobileNet model을 이용하여 구현되었다 (두가지 version이 있다고 생각하자). ResNet은 mobileNet에 비하여 CNN model의 크기가 크므로, 보다 정확한 pose estimation 결과를 얻을 수 있지만 page load time / inference time이 길어 실시간으로 동작하기에는 적합하지 않을 수 있다. mobileNet은 mobile 환경에서의 실시간 pose estimation을 위해 구현된다. 그림 04는 PoseNet pipeline을 나타낸다.

그림 04. PostNet의 single pose detector pipeline [1].

 

PoseNet model Input : Output Stride

PoseNet model은 입력 이미지의 크기를 변형시키지 않는다 (resize를 하지 않는다). 즉, PoseNet을 사용하면 원본 이미지 (입력 이미지)와 동일한 크기의 output 이미지를 얻게 된다. 하지만 output stride라는 hyperparameter를 이용하여 입력 이미지를 얼마나 세세히 볼 것인지 정하게 된다. 32,16,8의 값을 가질 수 있으며, CNN model 내에서 layer의 높이와 넓이에 영향을 준다. 따라서 정확도, 속도와 연관된 parameter라고 생각하면 된다. 큰 값을 가질수록 속도가 빨라지지만, 정확도가 낮아진다. 그림 05는 output stride에 대한 그림이다.

 

OutputStride를 통하여 이미지의 scale down을 한다 (일단은 이미지 사이즈가 바뀐다. 하지만 곧 복구한다.). 8, 16의 값을 가지는 경우 scale down이 진행되는데, 이를 Atrous convolution을 통하여 upsampling을 진행한다. 32의 값을 가지는 경우에는 적용하지 않는다. TF.js의 경우 Atrous convolution가 구현되어 있지 않기 때문에 PR이란것을 추가하여 구현하였다.

그림 05. Output stride는 직관적으로는 이미지를 얼마나 세세히 볼 것인가를 정한다고 생각하면 된다 [1].

모델로부터 얻어지는 output은 resoultion이라 하는 높이와 너비를 포함한 3D tensor의 형태이다. resolution은 input size와 output stride를 통하여 다음과 같은 공식을 통하여 얻는다.

Resolution = ((InputImageSize - 1) / OutputStride) + 1
// Example: an input image with a width of 225 pixels and an output
// stride of 16 results in an output resolution of 15
// 15 = ((225 - 1) / 16) + 1

 

Model output : heatmap and offset vectors

PostNet에서 이미지를 처리하여 실제로 얻게되는것은 heapmap과 offset vector 이다. 결론적으로 이는 이미지로부터 pose keypoint에 해당하는 confidence area를 찾기위해 이용된다. heatmap과 offset에 대해 간단히 알아보겠다.

그림 06. heatmap과 offset [1]

Heatmap

  • Heatmap은 resolution x resolution x 17의 3D tensor size를 가진다. 여기서 17은 Postnet이 찾고자 하는 keypoint 갯수이다.
  • 예를 들어 225x225 이미지에 output stride = 16의 값으로 PoseNet inference를 한다면 15x15x17의 크기를 가지는 heatmap이 생성된다.
  • 즉, 각 keypoint마다 heatmap을 가지게 된다.
  • 여기서 하나 더 주목 할 만한것은, 225x255 → 15x15가 된다는것이다. Pooling을 통하여 크기가 작아졌으므로 이 값으로부터 원본 이미지의 정확한 값을 추정하는것은 어렵다.
  • 따라서 추가적인 정보인 offset이란 것을 도입한것이 아닌가 생각한다.
  • heatmap은 해당 위치에 keypoint가 존재할 확률인 confidence score값을 가진다.

Offset

  • Offset은 resolution x resolution x 34의 3D tensor size를 가진다. 34는 keypoints x 2의 값이다.
  • 예를 들어 225x225 이미지에 output stride = 16의 값으로 PoseNet inference를 한다면 15x15x34의 크기를 가지는 offset이 생성된다.
  • Heatmap이 각 keypoint가 어디에 존재하는지 나타내는 근사치이다. Offset은 keypoint의 정확한 위치를 확정하는데 사용된다.
  • Heatmap point에 해당하는 지점에서부터 vector를 따라 이동하며 정확한 위치를 추정한다.
  • 34개의 offset을 얻는데, 이중 앞의 17개는 vector의 x를 포함하고, 나머지 17개는 vector의 y를 가진다.
  • Offset vector의 scale은 original image와 동일하다.

Offset이란 개념은 생소한 개념이다. 다음의 그림과 수식을 통하여 이해해보자.

  • Offset, $F_k(x_i) = l_k - x_i$
  • $x_i$는 픽셀의 location 을 의미한다.
  • $_k$는 임의의 key point (여기서는 17개중 하나)를 의미한다.
  • $l_k$는 key point (ground-truth로 이해) 위치
  • 즉, offset이란 keypoint로부터 거리가 얼마나 떨어져 있냐이고, 그림 07은 이것을 시각화 한 것

그림 07. Network output으로 생성되는 heatmap과 offset [2]

 

PoseNet 내부 구조에 대해 더 알고 싶다면...

위의 내용은 PoseNet을 만든 google team에서 작성한 블로그 글을 정리한 내용이다. 이것만 봐서는 조금 부족하다는 생각이 든다. PoseNet은 PersonLab[2] 이라는 논문을 기반으로 만들어졌다. 이때 single pose에 대하여 pose estimation 부분은 towards accurate multi-person pose estimation in the wild[3] 와 동일하다. 만약 PoseNet이 내부적으로 어떻게 동작하는지 정확히 알고싶다면, 다음의 논문을 읽어보는것을 추천한다.

  • PersonLab: Person Pose Estimation and Instance Segmentation with a Bottom-Up, Part-Based, Geometric Embedding Model (ECCV, 2018)
  • Towards accurate multi-person pose estimation in the wild (CVPR, 2017)

 

Reference

[1] PoseNet Official blog post : https://medium.com/tensorflow/real-time-human-pose-estimation-in-the-browser-with-tensorflow-js-7dd0bc881cd5

[2] G. Papandreou, T. Zhu, L.-C. Chen, S. Gidaris, J. Tompson, and K. Murphy, “Personlab: Person pose estimation and instance segmentation with a bottom-up, part-based, geometric embedding model,” in ECCV, 2018.

[3] G. Papandreou, T. Zhu, N. Kanazawa, A. Toshev, J. Tompson, C. Bregler, and K. Murphy, “Towards accurate multi-person pose estimation in the wild,” in CVPR, 2017.