コンピュータビジョンの最新論文調査 2D Human Pose Estimation 編

はじめに

こんにちは、AIシステム部でコンピュータビジョンの研究開発をしている加藤です。我々のチームでは、常に最新のコンピュータビジョンに関する論文調査を行い、部内で共有・議論しています。今回は 2D Human Pose Estimation 編として加藤直樹 (@nk35jk) が調査を行いました。

本記事では 2D Human Pose Estimation に関する代表的な研究事例を紹介するとともに、2019年10月から11月にかけて開催されたコンピュータビジョンのトップカンファレンスである ICCV 2019 に採録された 2D Human Pose Estimation の最新論文を紹介します。

過去の他タスク編については以下をご参照ください。

目次

前提知識

Human Pose Estimation の位置付け

Human Pose Estimation / 人物姿勢推定 は人物の映った画像や動画から人物の姿勢に関する情報を特定するタスクであり、以下のサブタスクに大別されます。

2D Pose Estimation

2D Pose Estimation は画像中の単一または複数人物の関節点の2次元座標を特定するタスクです。画像中の人物が単一である場合は推定すべき関節点の数が一定であるためそこまで難しい問題設定ではありません。しかし、推定対象が複数人物である場合、人物同士の重なり合いなどによる遮蔽が存在する環境下で不特定多数の人物の関節点座標を過不足なく推定する必要があるため、難度の高いタスクであると言えます。

2d_pose_estimation.png

2D Pose Estimation [7]

Pose Tracking

Pose Tracking は映像中の複数人物を追跡しつつ、それぞれの人物の2次元関節点座標を特定するタスクで、2D Pose Estimation よりもさらにチャレンジングなタスクとなっています。今回は Pose Tracking の研究の流れの詳細については触れませんので、ここで代表的と思われる研究事例をいくつかリストアップしておきます。興味のある方は論文を読んでみて下さい。

PoseTrack: Joint Multi-Person Pose Estimation and Tracking [Iqbal et al., CVPR'17]
PoseTrackデータセットを提案するとともに、Pose Tracking のベースライン手法を提案しています。ベースライン手法ではまず動画中の全ての人物の関節点の座標を推定した後、人物関節点のノード、それらを結ぶエッジからなる時空間的なグラフを構築し、整数線形計画問題に基づく最適化を行うことでグラフを分割し、各人物の姿勢情報を含んだ追跡結果を得るというBottom-up型のアプローチを取っています(本記事で紹介するDeepCut/DeeperCutと類似したアプローチです)。

Detect-and-Track: Efficient Pose Estimation in Videos [Girdhar et al., CVPR'18]
動画の数フレームを入力とし、入力された各フレームにおける複数人物の姿勢を人物を同定した上で推定する 3D Mask R-CNN を提案しています。推定された数フレーム分の人物追跡結果をハンガリアン法を用いて時系列的に割り当てていくことにより動画全体に対する人物追跡結果を得ます。ICCV 2017 PoseTrack challenge 首位手法です。

Efficient Online Multi-Person 2D Pose Tracking with Recurrent Spatio-Temporal Affinity Fields [Raaj et al., CVPR'19]
人物の関節点間の部位 (Limb) の存在を表す Part Affinity Fields、Limbの時系列的な動きをを表現する Temporal Affinity Fields を統合した Spatio-Temporal Affinity Fields を用いて人物の紐付けを行うBottom-up型のオンラインな Pose Tracking 手法を提案しました。本手法は約30fpsでの高速な推論が可能であるとともに、PoseTrackデータセットで最先端手法に匹敵する性能を達成しています。

pose_tracking.png

Pose Tracking [23]

3D Pose Estimation

3D Pose Estimation は単一または複数視点の画像や動画から人物関節点の3次元座標を特定するタスクです。ここで言う3次元座標には関節点のワールド座標、カメラ座標、腰を原点とした相対座標などが含まれ、研究の目的によって推定対象は異なります。近年CV分野全体において3D認識についての研究が注目されている流れに逆らわず、Pose Estimation においても2Dから3Dへと研究の対象が移りつつある印象を受けます。3D Pose Estimation の中でも特に盛んに研究されているのが単眼カメラを用いた3次元姿勢推定です。単眼カメラを用いる場合カメラからの関節点の奥行きが不定となるため、基本的にはカメラ座標系において人物の腰を原点としたときの各関節点の相対座標を推定する問題設定となります。

3d_pose_estimation.png

3D Pose Estimation [24]

Shape Reconstruction

3D Pose Estimation が人物のスパースな関節点の座標を推定するタスクであるのに対して、Shape Reconstruction では人物表面の形状を密に推定・復元します。人物の形状は、人物モデルに基づき大まかな体系が推定される場合や、服装を含んだ詳細な形状まで推定される場合もあります。Shape Reconstruction は Pose Estimation の中でも最も新しく、かつチャレンジングなトピックであり、近年特に盛んに研究が行われています。

mesh_reconstruction.png

Shape Reconstruction [25]

本記事のスコープ

今回は上記の中でも最も基本的なタスクである 2D Pose Estimation に焦点を当てて論文を紹介します。まず、代表的な研究事例を時系列順に紹介した後、2019年10月から11月にかけて開催されたコンピュータビジョンのトップカンファレンスである ICCV 2019 に採録された 2D Pose Estimation の最新論文を紹介します。近年注目されているトピックである 3D Pose Estimation、Shape Reconstruction については別の記事で紹介予定です。

関連するデータセット

2D Pose Estimation の論文では主に以下のデータセットが用いられます。この中でも近年はMPIIデータセットとCOCOデータセットを用いて評価が行われることが多い傾向にあります。AI Challenger データセットは他データセットでの評価の際に最終的なモデルの性能を引き上げるために用いられる場合や、その規模の大きさからコンペティションの際の外部データとして用いられる場合があります。

  • Leeds Sports Pose (LSP):2,000枚の単一人物画像から成るデータセット
  • MPII Human Pose:約4万人物の関節点座標がアノテーションされた約2万5千枚の複数人物画像から成るデータセット
  • MS COCO:約15万人物の関節点座標がアノテーションされた約6万枚の複数人物画像から成るデータセット
  • AI Challenger:約70万人物の関節点座標がアノテーションされた30万枚の複数人物画像から成るデータセット

データセット毎の関節点の定義およびアノテーション例は以下のようになっています。

LSPMPIIMS COCOAI Challenger
Right ankleRight ankleNoseRight shoulder
Right kneeRight kneeLeft eyeRight elbow
Right hipRight hipRight eyeRight wrist
Left hipLeft hipLeft earLeft shoulder
Left kneeLeft kneeRight earLeft elbow
Left ankleLeft ankleLeft shoulderLeft wrist
Right wristPelvisRight shoulderRight hip
Right elbowThoraxLeft elbowRight knee
Right shoulderUpper neckRight elbowRight ankle
Left shoulderHead topLeft wristLeft hip
Left elbowRight wristRight wristLeft knee
Left wristRight elbowLeft hipLeft ankle
NeckRight shoulderRight hipTop of the head
Head topLeft shoulderLeft kneeNeck
-Left elbowRight knee-
-Left wristLeft ankle-
--Right ankle-
各データセットの関節点の定義

datasets.png

各データセットのアノテーション例

評価方法

2D Pose Estimation では主に Percentage of Correct Keypoints と Average Precision という評価指標が用いられます。

Percentage of Correct Keypoints

Percentage of Correct Keypoints (PCK) は単一人物姿勢推定において利用される評価指標で、MPIIデータセットでの評価の際に主にこの指標が用いられます。PCKでは、関節点の推定座標と正解座標の距離が、ある閾値よりも小さいときにその関節点の推定を正しいものとし、推定が正しく行われた割合をその評価値とします。PCKの閾値は人物頭部のサイズ(頭部外接矩形の対角線の長さ)に基づき決定されることが多く、これはPCKhと呼称されます。例えばPCKh@0.5の場合、頭部サイズの0.5倍を閾値に設定して評価を行います。

Average Precision

Average Precision (AP) は複数人物姿勢推定の評価に利用される指標で、COCOデータセットと AI Challenger データセットはこの評価指標を採用しています。APは推定姿勢と正解姿勢の類似度を表す尺度である Object Keypoint Similarity (OKS) に基づき算出されます。OKSはアノテーションされている関節点についての推定座標と正解座標の類似度の平均を表す値となっており、次式で表されます。

oks.png

ここで、diは関節点iの推定座標と正解座標の距離、sは人物のサイズ(COCOではアノテーションされている人物領域の面積を用いる)、kiは関節点の種類毎に設定される定数(推定が難しい関節点ほど大きい値を設定する)、viは関節点がアノテーションされているかどうかを表します。OKSは人物の推定姿勢と正解姿勢が完全に一致するとき1となる、物体検出のAPでの評価におけるIoUと同じ役割を持った指標であり、APはこのOKSが閾値を上回っているとき推定結果を正解であるとみなしたときに算出される平均適合率です。COCOの場合、最終的な評価値はOKSの閾値を0.50から0.95まで10段階に変化させたときのそれぞれのAPの値を平均することにより算出されます。

代表的な研究事例

ここでは 2D Human Pose Estimation の既存手法の中でも代表的と思われる手法をピックアップし、それらをTop-down型アプローチ、Bottom-up型アプローチに大別した上でそれぞれを論文が発表された順番に紹介します。今回紹介する手法は全てディープラーニングを用いた手法になっており、ディープラーニング台頭以前の手法については紹介しませんのでご注意ください。使用している図表は紹介論文から引用したものとなります。

Top-down型アプローチ

Top-down型のアプローチでは、まず画像中の各人物を人物検出器などで検出した後、各人物の関節点座標を単一人物用の姿勢推定器を用いて推定します。人物の検出およびそれぞれの人物の姿勢推定を独立して行うシンプルな枠組みとなっており、性能の高い人物検出器を採用することで性能向上が図りやすい点、(畳み込みニューラルネットワークを用いた手法の場合)個々の人物に対する Receptive Field を大きく取ることが容易な点が主な利点です。以下で紹介する研究事例には単一人物姿勢推定を題材としたものも含まれています。

DeepPose (CVPR 2014) [1]

DeepPoseは人物姿勢推定にディープラーニングを適用した初の手法です。この手法では、畳み込みニューラルネットワーク (AlexNet) に固定サイズの画像を入力し、各関節点の2次元座標を回帰により推定します。モデルの出力は(推定すべき関節点数)× 2 次元のベクトルです。このとき、画像の中心が (x, y) = (0, 0)、画像の最も左上の座標、右下の座標がそれぞれ (-0.5, -0.5)、(0.5, 0.5) となるよう正規化された座標を推定します。そして、Mean Squared Error (MSE) をロス関数に用いてモデルを学習します。

deeppose_initial_stage.png

また、この論文ではモデルをカスケードさせることにより、前段ステージで推定された関節点座標をリファインする方法も同時に提案しています。前段ステージで推定された関節点座標を中心に画像をクロップし、前段ステージと同一構造かつパラメータは独立した後段ステージに入力します。後段ステージは前段ステージよりも関節点周辺の高解像度な画像を元に推定ができるため精度向上につながると論文では主張されています。各ステージの学習は第一ステージから順に独立して行います。

deeppose_stage_s.png

実験では最大3ステージを用いたDeepPoseの性能と既存手法の性能を比較し、カスケードの有効性を実証するとともに、既存の非ディープラーニング手法を上回る性能を達成しました。

deeppose_result1.png

LSPデータセットでの Percentage of Correct Parts (PCP)

ただ、既存手法と比べた性能の向上幅はそれほど大きくなく、シングルステージの場合は既存手法に劣る性能となってしまっています。この一因として、畳み込みニューラルネットーワークが基本的に画像の位置に不変な特徴抽出を行うものであるため、画像全体を入力としての関節点座標の直接の回帰は学習が難しいことが挙げられます。

Joint Training of a Convolutional Network and a Graphical Model for Human Pose Estimation (NIPS 2014) [2]

DeepPoseが関節点座標を直接回帰により推定しているのに対し、こちらの研究ではヒートマップを用いた姿勢推定手法を提案しています。モデルの出力は推定すべき関節点数と同数のヒートマップで、各ヒートマップの正解ラベルは関節点座標を中心としたガウス分布により生成されます。ロス関数にはMSEを用いてモデルを学習します。推論時はヒートマップのピーク位置を関節点の推定座標とします。近年の多くの研究でもこの論文で提案されているのと同様のヒートマップの推定に基づく関節点座標推定の枠組みが用いられており、ディープラーニングによる人物姿勢推定の基盤を確立した研究であると言えます。

part_detector.png

本論文ではそれ以外にも主要な主張として、グラフィカルモデルに基づき上記モデル (Part-Detector) の False Positive を削減するためのモデル (Spatial-Model) を提案し、両モデルを併用することによる性能向上を図っていますが、近年の研究ではこのような方法は用いられない傾向にあります。近年用いられるモデルは層数が増えたことにより広い Receptive Field を持ちコンテキストを捉えた推定が可能であるため、単一のモデルでも十分精度良くヒートマップを推定できることがその要因であると考えられます。

本手法はDeepPose(下図中 Pishchulin et al.)を含めた既存手法を大きく越える性能を達成し、ヒートマップに基づく姿勢推定手法の有効性を示しました。

tompson_result1.png

LSPデータセットでの評価結果

本研究以降はヒートマップベースの姿勢推定手法が台頭し、ネットワークの構造の改良にフォーカスした研究が増えていきました。

Convolutional Pose Machines (CVPR 2016) [3]

Convolutional Pose Machines (CPM) では複数ステージからなるモデルの各ステージでヒートマップを段階的にリファインしていく、DeepPoseにおけるモデルのカスケードと似たような試みを行なっています。第一ステージは画像のみを入力に関節点毎のヒートマップを推定しますが、第二ステージ以降は特徴マップおよび前段ステージで推定されたヒートマップを入力にヒートマップを推定します。学習の際は、各ステージで推定されたヒートマップに対するMSEの合計をロスとし、全てのステージをend-to-endに学習します。このように、モデルの中間的な出力に対する教師信号の適用 (Intermediate Supervision) により、勾配消失を軽減させる効果があると論文では述べられています。また、カスケードさせた深いモデルを用いることによりモデルの Receptive Field を広げ、人物構造を暗に考慮した推定が可能になると主張されています。

cpm_architecture.png

Convolutional Pose Machines のアーキテクチャ

下図のように、左右の判別が難しい部位を後段ステージでは適切に推定できています。

cpm_result1.png

各ステージでの右肘のヒートマップの推定結果

Stacked Hourglass Networks (ECCV 2016) [4]

Stacked Hourglass Network もCPMと同様にモデル構造の改良による性能改善を図っています。このネットワークはその名の通り砂時計型の構造を持ったモジュールである Hourglass Module を複数回連ねた構造となっており、複数スケールの特徴を考慮した特徴抽出が可能であることを特徴としています。

hourglass_network.png

個々の Hourglass Module は下図のように、特徴抽出を行いつつ特徴マップのダウンサンプリングおよびアップサンプリングを行うEncoder-Decoder構造を持ち、アップサンプリングの際にはダウンサンプリング時の同一解像度の特徴マップを足し合わせるSkip-connectionを行います(参考までに、同じくEncoder-Decoder構造を持ったモデルであるU-Netでは特徴マップ同士の結合によるSkip-connectionを行います)。基本的な特徴抽出には Residual Module を利用し、ダウンサンプリングには Max Pooling、アップサンプリングにはニアレストネイバーを使用しています。

hourglass_module.png

Hourglass Module の構造

また、各 Hourglass Module の出力特徴マップからヒートマップを推定し(下図青色の部分)、CPMと同様に全ての出力ヒートマップに対するMSEの和をロスとしてモデルを学習します。

hourglass_intermediate_supervision.png

Intermediate Supervision の適用

実験ではスタック数を変化させたレイヤー数およびパラメータ数が等しい複数のモデルの性能を比較し、スタック数を増やすことにより性能が向上することを示しました。

hourglass_result1.png

スタック数の異なるモデルの各ステージの性能

既存手法との性能比較では、Hourglass Network がCPMを含む既存手法を上回る性能を持つことを示しています。

hourglass_result2.png

MPIIデータセットでの実験結果 (PCKh@0.5)

Cascaded Pyramid Network (CVPR 2018) [5]

Cascaded Pyramid Network (CPN) はGlobalNet、RefineNetの2ステージのネットワークからなるモデルです。GlobalNetは Feature Pyramid Network [26] とほぼ同一のアーキテクチャを持ち、複数スケールの出力特徴マップそれぞれからヒートマップを推定します。一方RefineNetではGlobalNetから出力された各スケールの特徴マップを結合し、リファインされたヒートマップを推定します。ピラミッド構造のGlobalNetによるマルチスケールな特徴抽出、RefineNetにおけるそれらの統合が本モデルの肝であると言えます。

cpn.png

CPNはモデル構造だけでなくロスの与え方にも工夫を行なっており、GlobalNetの出力に対しては通常のL2ロスをかけますが、RefineNetの出力に対してはロスの大きい上位M個の関節点にのみL2ロスをかける Online Hard Keypoint Mining を行います。

GlobalNetとRefineNetに対するロスのかけ方を比較する実験を行い、RefineNetに対する Online Hard Keypoint Mining 適用の有効性を示しています。

cpn_result1.png

各ネットワークに対するロスのかけ方の比較
(L2 loss* は Online Hard Keypoint Mining を用いたL2ロス)

アンサンブルされた最終的なモデルは COCO test-dev set で73.0のAPを達成しています。

因みに、ECCV 2018 のワークショップコンペティションとして開催された COCO Keypoint Detection Challenge 2018 では、CPNをベースに用いた手法が首位となりました。

Simple Baselines for Human Pose Estimation and Tracking (ECCV 2018) [6]

CPMや Hourglass Network、CPNはモデルの改良により性能改善を図っていましたが、モデル構造が複雑になっていくについて、それぞれのモデルの各構成要素の性能向上への寄与度やモデル同士の対等な比較がし難くなるという問題が生じてきました。それを踏まえ、この研究では「シンプルなモデルでどれほどの性能を出すことができるのか?」を問いにベースラインとなるモデルを提案し、既存手法を上回る性能を達成しました。

提案されたモデル(下図 )はバックボーンであるResNetの出力特徴マップに複数回のDeconvolutionを行うことで関節点のヒートマップを推定する構造となっており、Hourglass Network やCPNと比べ非常にシンプルな構造となっています。ヒートマップは既存手法と同様、ガウス分布により生成し、L2ロスを用いて学習します。テスト時はFaster R-CNNを用いて人物検出を行い、検出されたそれぞれの人物に対して提案モデルで姿勢推定を行います。

simple_baselines.png

提案されたモデルのアーキテクチャ

実験ではバックボーンに用いるResNetの層数、入力画像サイズ、Deconvolutionの層数およびカーネルサイズによる性能比較を行う Ablation Study を実施しました。結果は下図のようになっており、特に入力画像の大きさが性能向上に大きく寄与することを確認しました。

simple_baselines_result1.png

COCO val2017 での Ablation Study 結果

また、入力画像サイズが同一の Hourglass Network、CPNと性能比較を行い、本手法の性能が上回っていることを示しました(下図)。既存手法の評価値はそれぞれの論文から参照したものであるため実装の良し悪しが性能に影響をもたらしている可能性があるものの、シンプルなモデルでも既存手法と同等またはそれ以上の性能を得ることができると著者らは結論付けています。

simple_baselines_result2.png

COCO val2017 での既存手法との比較

本手法が既存手法の性能を上回った理由については実装の良し悪しである可能性がある以外具体的には明記されていません。また、著者らはあくまでも本研究の目的をアルゴリズム的に優位な手法の提案ではなくベースライン手法の提案であるとしています。実装面が性能に与える影響の大きさ、また適切なベースライン設定の重要性を感じさせられる研究となっています。

High-Resolution Network (CVPR 2019) [7, 8]

High-Resolution Network (HRNet) は Simple Baseline と同一著者らにより発表され、Simple Baseline をベースにモデル構造を改良したものとなっています。

HRNetについては過去のブログ記事や CVPR 2019 の論文調査資料でも解説がありますので、よろしければそちらも併せてご覧ください。

Hourglass Network やCPN、Simple Baseline などの従来のモデルは、一度特徴マップを縮小した後、Deconvolutionやアップサンプリングなどにより特徴マップを拡大することで入力画像のサイズに対して小さすぎない(1/8から1/4程度の)ヒートマップを出力する構造を取っていました。それに対してHRNetは高解像度な特徴マップを保持したまま平行して低解像度な特徴マップを生成していき、それぞれのブランチで特徴抽出を行います。そして、Exchange Unit でのそれぞれのブランチの特徴マップ間での相互な情報のやりとりを複数回に渡り行うことでよりリッチな特徴表現が獲得される構造となっています。

hrnet.png

HRNetのアーキテクチャ

Exchange Unit では下図のように、出力特徴マップのスケールと同一スケールの特徴マップは恒等写像、低解像度な特徴マップはニアレストネイバーによるアップサンプリングを行なった後で 1x1 Convolution、高解像度な特徴マップは複数回のカーネルサイズ3の Strided Convolution を行なった後でそれぞれの特徴マップを足し合わせることで複数ブランチの情報を集約します。各ブランチでの特徴抽出とそれらの統合を複数回に渡り行なった後、最も高解像度な特徴マップを持つブランチからヒートマップを推定します。

exchange_unit.png

Exchange Unit の構造

実験では Simple Baseline を含めた既存手法との性能比較を行い、下図のようにいずれの既存手法をも上回る性能を達成しました。AI Challenger データセットを外部データとして用いたときの COCO test-dev set に対するAPは77.0と、非常に高い性能となっています。大きく話題になったOpenPoseの評価値が61.8であることを見ても、その性能の高さが分かるかと思います。

hrnet_result1.png

COCO test-dev set での性能比較

HRNetは姿勢推定だけでなくクラス分類や領域分割、物体検出など様々なタスクのバックボーンとして有効であることが確認されている [8] と共に、既にHRNetを改良 [9]、または転用 [10] した多くの派生研究が存在しています。

Bottom-up型アプローチ

ここまではTop-down型アプローチの研究事例を紹介しましたが、ここからはもう1つの代表的なアプローチであるBottom-up型アプローチの研究事例について紹介します。

Bottom-up型手法では画像中の全ての人物の関節点座標を人物を区別せずに検出した後、それらを人物毎にグルーピングすることにより複数人物の姿勢を推定します。一度のモデルの順伝播で画像中の全ての人物の関節点を検出するため、Top-down型手法と比べ画像中の人物数が増加しても推論速度が落ちにくいという利点があります。Bottom-up型手法では検出した関節点のグルーピングをどのように行うかがアルゴリズムの肝となっており、その点に着眼した研究が数多く存在します。

DeepCut (CVPR 2016) [11] / DeeperCut (ECCV 2016) [12]

DeepCut/DeeperCutはディーブラーニングを用いたBottom-up型姿勢推定の先駆け的な手法です。これらの手法では画像中の人物関節点を人物を区別せずに検出した後、関節点をノードと見なし、それらを全結合するエッジを作成することによりグラフを構築します(下図左)。グラフの人物毎の部分グラフへの分割、関節点ノードの種類のラベリングを整数線計画問題に基づく最適化により行うことで、人物毎の姿勢推定結果を得ます(下図中央、右)。

deepcut.png

DeeperCutはDeepCutに対し、主に以下の3点の改善を行っています。

  • バックボーンをVGGからResNetに変更することによる関節点検出モデルの改善
  • 画像特徴を用いることによるコスト関数の改善
  • 最適化を体の部位毎に段階的に行うことによる速度・精度改善

これらの手法では関節点候補の検出を畳み込みニューラルネットワークを用いて行なっていますが、最適化の際に用いるコスト関数は主に関節点ペアの距離や角度などの幾何的な関係に基づいたものであり、ディープラーニングにより得られる特徴を十分に活用しきれていないと言えます。また、最適化の計算コストが高く、Bottom-up型手法の利点である関節点検出の高速性を相殺してしまっているという欠点があります。

OpenPose (CVPR 2017, TPAMI 2019) [13, 14]

OpenPoseは高速かつ高精度な人物姿勢推定手法として一時期大きく話題となった手法で、ご存知の方も多いと思います。この手法の一番の特徴は関節候補点のグルーピングの手がかりとなる Part Affinity Fields (PAFs) を畳み込みニューラルネットワークで推定することで、これにより高性能な関節点のグルーピングが可能となる共に、処理コストの低い簡素なグルーピング方法の利用が可能となり、高速に動作するアルゴリズムとなっています。

openpose.png

モデルは下図のようにCPMと類似したステージ構造を持ち、各ステージからヒートマップおよびPAFsを推定します。ヒートマップの正解ラベルはTop-down型手法と同様に関節点を中心としたガウス分布により生成されます。PAFは対応関係にある関節点ペア間の部位 (Limb) の存在を表す2次元ベクトル場で、対応関係にある関節点ペア間の矩形内において一方の関節点からもう一方の関節点へと向かう単位ベクトル、それ以外の領域では零ベクトルとして生成されます。よって、モデルの推定対象は関節点と同数のヒートマップとLimbと同数のPAFとなります。学習時はヒートマップ、PAFsに対する全てのステージでのMSEの和をロスとしてモデルを学習します。

openpose_architecture.png

OpenPoseのモデル構造

推論時はまず、モデルにより推定されたヒートマップの極大点から関節候補点を検出します。次に、対応関係にある全ての関節点ペア間のPAF上で線積分値を求め、それらをそれぞれの関節点ペアを結びつける確信度と見なします。この確信度が大きい関節点ペアから順に結びつけていく工程を関節点ペアの種類毎に行なっていくことにより最終的な人物毎の姿勢推定結果が得られます。

実験ではTop-down型手法であるCPMと処理速度の比較を行い、CPM(下図中Top-down)では画像中の人物数に比例する形で処理時間が増加しているのに対し、OpenPose(下図中Bottom-up)は人物数が増加してもほぼ一定の処理速度(654 × 368 の画像に対して約9fps)で推論ができることを確認しました。

openpose_result1.png

処理時間の比較

Associative Embedding (NIPS 2017) [15]

Associative Embedding は姿勢推定における関節点のグルーピングやインスタンスセグメンテーションにおけるピクセルのグルーピング問題を埋め込み表現を用いて解決しようと試みた研究です。本研究では姿勢推定とインスタンスセグメンテーションそれぞれに対する手法を提案していますが、ここでは姿勢推定手法についてのみ説明します。

associative_embedding.png

本手法では Hourglass Network を用いて各関節点のヒートマップおよびEmbeddingマップを出力します。Embeddingマップは人物のアイデンティティ情報を持った1次元ベクトルのマップとなっており、同一人物の各関節点の位置に対応するEmbeddingマップの値同士が近くなり、画像中の異なる人物の関節点のEmbeddingマップの値同士が遠くなるようロスをかけます。これにより、Embeddingの値の近さが関節点ペアを結び付ける際の指標となります。

associative_embedding_system.png

システム構成

推論時はOpenPoseと同様のグリーディな割り当てをEmbeddingの値の近さに基づき行うことで人物毎の姿勢推定結果を得ます。Embeddingを多次元にすることも可能ですが、性能に大きな違いは見られなかったことが論文で述べられています。

人物毎の各関節点のEmbeddingの値の推定結果は下図右のようになっており、(それぞれの点がどの人物のものであるのか図からは判別できないものの、)人物毎にEmbeddingの値が分離されるようモデルが学習されていることが分かります。

associative_embedding_result1.png

人物姿勢推定結果とそれに対応する人物の各関節点のEmbeddingの値

PersonLab (ECCV 2018) [16]

PersonLabは人物姿勢推定とインスタンスセグメンテーションを同時に行うことのできるBottom-up型手法で、各ピクセルからの関節点のオフセット推定(回帰)を特徴とした手法です。ここでは人物姿勢推定の部分についてのみ説明します。

手法の枠組みは下図のようになっており、姿勢推定に必要となるモデルの推定対象はヒートマップ、Short-range offsets、Mid-range offsets の3つです。ヒートマップは Keypoint Disk と呼ばれる関節点を中心とした半径一定の円内において1、それ以外の領域では0の値をとるバイナリのマップで、Binary Cross Entropy ロスを用いて学習します。Short-range offset は各関節点種の Keypoint Disk 内において、その関節点の座標を回帰する2次元ベクトル場で、L1ロスを用いて学習します。Mid-range offset は各関節点種の Keypoint Disk 内において、その関節点と対応関係にある関節点の座標を回帰する2次元ベクトル場で、Short-range offset と同様にL1ロスで学習します。

personlab.png

PersonLabの枠組み

推論時はまずヒートマップと Short-range offsets を用いたハフ投票により関節点毎のスコアマップを求め、スコアマップの極大点から関節候補点を検出します。次に、スコアマップの値が大きい関節候補点から順に Mid-range offset を用いてグリーディに関節点を割り当てていくことにより人物毎の姿勢推定結果を得ます。このとき、下図のように Short-range offset を足しこむことによりリファインされた Mid-range offset を用いることで割り当ての性能改善を図っています。

mid-range_offsets.png

Mid-range offsets のリファイン

PersonLabは姿勢推定とインスタンスセグメンテーションのマルチタスク学習を行なっているため対等な比較ではないものの、OpenPoseや Associative Embedding を含む既存のBottom-up型手法を上回る性能を達成しています。

personlab_result1.png

COCO test-dev split に対する性能比較

本手法は 801 × 529 の画像に対して約3fpsで姿勢推定およびインスタンスセグメンテーションを行うことが可能です。

ICCV 2019 採録論文の紹介

ここからは ICCV 2019 に採録された 2D Pose Estimation に関する論文を紹介します。私の集計した限りでは、当該トピックでの採録論文はここで紹介する4本のみとなっています。

TRB: A Novel Triplet Representation for Understanding 2D Human Body (Oral) [17]

要約

人物の姿勢および輪郭を表現する Triplet Representation for Body (TRB) を定義し、 TRB推定のためのベースライン手法を提案しました。また、TRBを生成モデルの条件に用いることで人物形状の操作ができることを示しました。

提案内容

Triplet Representation for Body

既存の人物姿勢の表現方法である Skeleton Keypoints は人物の姿勢情報を持っていますが、人物の形状情報に欠けるという欠点があります。一方で、Semantic Human Parsing Representation や DensePose Surface-based Representation は人物の形状情報を持つものの関節点座標の姿勢情報を欠いています。また、3次元人体モデルは人物の姿勢および形状双方を表現することができますが、アノテーションにモーションキャプチャシステムが必要であり、アノテーションコストが非常に高いという欠点があります。

上記を踏まえ、本研究では人物の姿勢および形状を表現可能かつアノテーションの容易な Triplet Representation for Body (TRB) を提案しています。TRBは下図のように従来の Skeleton Keypoints に加え、それらの近傍の人物と背景の境界点である2点の Contour Keypoints からなっており、人物の姿勢、形状両方の情報を持った表現方法となっています。

trb1.png

TRBのアノテーション例

TRB-Net

本研究ではTRB推定手法であるTRB-Netも同時に提案しています。TRB-NetはTop-down型のアプローチを用いており、下図のように人物領域をクロップした画像を入力とし、Skeleton Heatmap と Contour Heatmap を複数ステージからなるモデルで推定する構成となっています。論文には詳細が不明瞭な箇所も多いため、モデルの詳細については要点を絞って紹介します。

trb2.png

TRB-Netのアーキテクチャ

まず、それぞれのモジュールでは2つのブランチの Multi-scale Feature Extraction Block (MS Block) を用いて Skeleton Heatmap および Contour Heatmap を推定します。基本的には推定されたヒートマップに対してL2ロスをかけることによりモデルを学習します。Message Passing Block (MP Block) はそれぞれのブランチ間で相互に情報のやりとりをすることによりヒートマップをリファインするためのブロックで、以下の3つのモジュールを挿入可能です。

  • X-structured Message Passing Block
  • Directed Convolution Unit
  • Pairwise Mapping Unit

X-structured Message Passing Block (Xs MP Block) は下図のようなモジュールで、それぞれのヒートマップに 1x1 Convolution をかけた後特徴マップを結合し、リファインされたヒートマップを推定します。

trb3.png

X-structured Message Passing Block

Directed Convolution Unit (DC Unit) は Xs MP Block における Contour Heatmap 推定に Scattering Convolution を、Skeleton Heatmap 推定に Gathering Convolution を用いたモジュールとなっています。

trb4.png

Directed Convolution Unit

Scattering Convolution と Gathering Convolution は本論文で提案されている Directional Convolution と呼ばれるものの一種で、Skeleton Heatmap では関節点を中心に、Contour Heatmap では関節点の周囲に出るそれぞれのヒートマップの位置合わせを目的に使用しています。Directional Convolution では重みを共有した畳み込みを複数回行いますが、その際に特徴マップにおいて値が更新される位置を Scattering Convolution の場合は内側から外側、Gathering Convolution の場合は外側から内側の順となるよう固定します。

trb5.png

Directional Convolution

Directional Convolution は下図のようにヒートマップを異なるパターンのグリッドに分割した上で並列して適用し、それらを統合したものを最終的な出力とします。このとき、それぞれの畳み込み結果を結合させた特徴マップから各特徴マップの重みをシグモイド関数を適用することで出力し、その値を用いた各グリッドの特徴マップの重み和により出力が得られます。

trb6.png

Directional Convolution の並列的な適用

Pairwise Mapping Unit (PM Unit) は推定される Skeleton Keypoints と Contour Keypoints の一貫性を高めるためのモジュールで、下図のような構造となっています。このモジュールではそれぞれのブランチから変換関数の推定およびそれを用いたヒートマップの変換を行います(詳細は不明)。ヒートマップの変換はあるKeypointのヒートマップからその近傍のSkeleton/Contourヒートマップを推定するように行い、L2ロスをかけ両者を近づけるようモデルを学習します。

trb7.png

Pairwise Mapping Unit

推論時は変換されたヒートマップと変換対象のヒートマップを統合することにより、リファインされたヒートマップを推定します。下図は誤って推定された右手首のヒートマップがContourヒートマップを用いることで修正されている例になります。

trb8.png

Pairwise Mapping unit によるヒートマップのリファイン結果例

実験結果

本研究では実験に際してMPII、LSP、COCOの3つのデータセットに対してTRBをアノテーションすることによりTRBデータセットを構築しています。また、TRB推定の評価には元のデータセットと同一の評価指標を用いています。

まず、既存の姿勢推定手法をTRBを推定できるよう拡張した上で、TRB-Netとの性能比較を行なっています。Contour Keypoints は Skeleton Keypoints と比べ推定が難しいことを確認すると共に、TRB-Netが既存手法よりも優れた性能を持つことを確認しています。

trb_result1.png

MPII_trbデータセットでのTRB推定の性能比較

Directed Convolution に関する Ablation Study では、SkeletonヒートマップとContourヒートマップのマルチタスク学習の有効性、Xs MP Block の有効性、通常の畳み込みに対する Directional Convolution の優位性を確認しています。

trb_result2.png

Directed Convolution に関する Ablation Study 結果

Pairwise Mapping に関する Ablation Study では、ヒートマップの初期の推定結果を用いた場合(下表中stack1-c、stack2-c)と比べ、PM Unit によりリファインされたヒートマップを用いることにより性能が向上することを示しています(下表中stack1-f、stack2-f)。また、DC Unit と PM Unit を併用したときに最も性能が向上することを確認しました。

trb_result3.png

Pairwise Mapping に関する Ablation Study 結果

TRBの応用事例としてTRBを条件とした条件付き画像生成を挙げており、Variational U-Net を用いてTRBを変化させたときの生成画像を確認しています。下図のように、TRBを操作することにより人物形状を操作した画像生成が可能です。

trb_result4.png

Contour Keypoints を操作しての画像生成

Single-Network Whole-Body Pose Estimation [18]

要約

OpenPoseを拡張した単一のネットワークによる全身(Body, Face, Hand, Foot)のポーズ推定手法を提案し、既存手法と比べ高速かつ高精度な全身のポーズ推定を実現しました。

提案内容

モチベーション

本研究の目的は全身のポーズ推定を高速かつ高精度に行うことです。その際に問題となるのが全身のポーズに関するアノテーションを持ったデータセットが存在しないことであり、Body、Face、Hand、Footなど体の各部位に関するアノテーションを持ったデータセットを組み合わせてモデルを学習する必要があります。体の部位毎のモデルを独立して学習すれば全身のポーズ推定を達成することが可能ですが、計算コストが高くなるという問題があります。そのため、本研究では単一のモデルを用いた全身のポーズを推定に取り組んでいます。

提案システム

提案されたモデルは下図のようになっています。基本的なポーズ推定の枠組みはOpenPoseに基づいており、各キーポイントに対するヒートマップおよびLimbに対する Part Affinity Fields (PAFs) を推定するモデルを学習します。推定対象であるヒートマップおよびPAFsは全身のポーズを推定できるよう、体の各部位に関するものを結合させたものとなっています。その際、モデルの学習方法や構造に複数の変更を加えることにより性能改善を図っています。

single-network1.png

モデル構造

学習データのサンプリング

前述したように全身のポーズのアノテーションを持ったデータセットは存在しないため、モデルを単一のデータセットで学習することができません。そのため、各部位に関するデータセットから一定の確率で学習データをサンプリングしてミニバッチを作成します。学習の際は学習サンプルのデータセットに関連する部位のみでロスを計算し、モデルを学習します。

データセットによるデータ拡張方法の変更

下図のようにデータセットによって各部位の写り方が異なっており、Bodyデータセットでは顔、手などの解像度が低く、Faceデータセットでは顔が大きく写るなどの傾向があります。そのためデータセット毎にデータ拡張時のスケールを調整することでそれぞれのデータセットからデータをサンプリングしたときの各部位のスケールが大きく乖離しないようにしています。

single-network2.png

データセットによる人物数、遮蔽、人物のスケールなどの違い
(a) Handデータセット (b) Bodyデータセット (c) Faceデータセット

モデル構造の改善

OpenPoseのモデル構造に以下のような変更を加えています。

  • 入力サイズを 368 × 368 から 480 × 480 に変更
  • PAFsを推定するブランチの畳み込み層を増やすことによる Receptive Filed の拡大、チャネル数の増加、ステージ数の削減による計算コスト調整

その他の改善

上記以外にも以下のように複数の改善を行なっています。

  • 顔、手に関するヒートマップのガウシアンの広がりを小さくする
  • 顔、手、足の False Positive の多さを解決するため、Bodyデータセットで人物が存在しない領域ではそれらの部位に対してロスを与える
  • 人物が写っていない画像を学習に利用する
  • Face, Handデータセットではアノテーションされていない人物が存在するため、Mask R-CNN を用いてそれらをマスクする

実験結果

Body、Foot、Face、Handそれぞれのデータセットを用いて各部位の認識性能を既存手法と比較する実験を行っています。下表において、Shallowはアーキテクチャ改善前のモデル、Deepはアーキテクチャ改善後のモデルです。

Body、Footデータセットでの評価実験では、提案手法の性能はOpenPoseと同等程度の性能となりました。

single-network_result1.png

COCO validation set での性能比較

Faceデータセットでの実験では、OpenPose、提案モデルどちらも実験室環境のデータセットであるFRGGとMulti-PIEに過学習しており、in-the-wildなデータセットであるi-bugに対する性能が低い傾向にあります。提案手法はよりチャレンジングなi-bugにおいてOpenPoseの性能を上回っています。

single-network_result2.png

FRGC、Multi-PIE、i-bugデータセットでの性能比較

Handデータセットでの実験では、よりチャレンジングなMPIIにおいてOpenPoseを大きく上回る性能を達成しました。

single-network_result3.png

Hand Dome、Hand MPII データセットでの性能比較

最後に、提案手法とOpenPoseの全身のポーズ推定の速度比較を行っています。OpenPoseは画像中の人物数が増えると顔や手の推定に時間がかかるため人物数に比例する形で処理時間が増加していますが、提案手法は人物数が増加してもほぼ一定の時間で推定ができるていることが分かります。

single-network_result4.png

提案手法とOpenPoseの速度比較

Single-Stage Multi-Person Pose Machines [19]

要約

Root Joint の推定と Root Joint からその他Jointへのオフセット推定に基づくSingle-stage型の姿勢推定手法である Single-stage multi-person Pose Machine (SPM) を提案し、精度および速度の両面でBottom-up型の既存手法を凌駕しました。

提案内容

モチベーション

人物を検出してからそれぞれの人物の姿勢推定を行うTop-down型手法、関節候補点を検出してからそれらをグルーピングするBottom-up型手法はどちらも二段階の枠組みになっており、十分に効率的ではないと本論文では述べてられています(個人的にはBottom-up型手法における関節点のグルーピングはアルゴリズムによっては処理コストが非常に低くボトルネックにはならないと考えています)。それを踏まえ本研究では、画像中の全ての人物の姿勢を一段階の枠組みで推論するSingle-stage型の姿勢推定手法を提案しています。Single-stage型の既存手法であるCenterNet [20] との差分については後述します。

Structured Pose Representation

既存のアプローチでは、人物姿勢は人物毎の各関節点の座標により表現されていました。それに対して本研究では人物姿勢を人物毎の Root Joint と、Root Joint から各関節点への変位によって表現する Structured Pose Representation (SPR) を提案しています。さらに、SPRを Root Joint を起点とする階層的構造にした Hierarchical SPR を提案し、モデルに取り入れています。

spm1.png

人物姿勢の表現方法

Single-stage multi-person Pose Machine

提案手法である Single-stage multi-person Pose Machine (SPM) のパイプラインは下図のようになっています。このモデルではSPRに基づき、各人物の Root Joint、Root Joint から各関節への変位を推定します。Hierarchical SPR を用いる場合、この階層表現において隣接関係にある関節点ペアの変位をそれぞれ推定します。

spm2.png

提案手法のパイプライン

モデルの推定対象は Root Joint Confidence Map とDense Displacement Maps の2つです。Root Joint Confidence Map は Root Joint を中心としたガウス分布に従い生成されるヒートマップです。Dense Displacement Maps は SPR / Hierarchical SPR において隣接関係にある関節点ペアの一方の関節点を中心とする円内からもう一方の関節点の座標を回帰する2次元のマップです。学習時は Root Joint Confidence Map に対するL2ロスと Dense Displacement Maps に対する smooth L1 ロスを重み和してモデルを学習します。

spm3.png

モデルの推定対象

推論時は Root Joint Confidence Map から各人物の Root を検出した後、Dense Displacement Maps を用いて SPR / Hierarchical SPR において隣接関係にある関節点ペアを順番に結び付けていきます。

Single-stage型の既存手法であるCenterNetは人物矩形の中心点から各関節点を回帰する本手法と類似した手法ですが、本手法は以下の点でCenterNetと異なっています。

  • Hierarchical SPR を用いて階層的に関節点ペア間の変位を推定する
  • CenterNetが人物矩形の中心点のみにL1ロスをかけるのに対し、本手法では関節点を中心とする円内にL1ロスをかける

実験結果

MPIIデータセットで SPR / Hierarchical SPR の性能を比較する Ablation Study を行い、Hierarchical SPR がSPRと同一の処理速度で高い性能を持つことを確認しました。Hierarchical SPR は特に手首や足首など腰から離れた関節点においてSPMよりも優れた性能を示しており、階層的な関節点のオフセット推定の有効性を示す結果となりました。

spm_result1.png

MPII validation set での Ablation Study 結果

また、COCOデータセットでSPMとBottom-up型の既存手法の精度、速度を比較する実験を行い、SPMが両面において既存手法を上回ることを示しました。特に速度面では比較手法の中で最も高速な Associative Embedding よりも4倍以上高速な約17fpsでの推論が可能です。

spm_result2.png

COCO test-dev set での性能比較

本手法は3次元姿勢推定にも適用可能であり、CMU Panoptic データセットでの複数人物3次元姿勢推定において77.8%の3D-PCKを達成しました。推定結果例は下図のようになっています。

spm_result3.png

CMU Panoptic データセットに対する3次元姿勢推定結果例

Dynamic Kernel Distillation for Efficient Pose Estimation in Videos [21]

要約

動画ベースの単一人物姿勢推定において、毎フレームに対して規模の大きなモデルを用いるのは非効率的でした。それを踏まえ、前フレームのヒートマップからカーネルを算出し、現在フレームの特徴マップにそれを畳み込むことにより現在フレームのヒートマップを得る Dynamic Kernel Distillation (DKD) と呼ばれるモデルを提案し、軽量なバックボーンを用いても高精度な推定ができることを示しました。また、DKDの学習に Temorally Adversarial Training を導入することで、時系列的に一貫したカーネルの導出および姿勢推定を可能としました。

提案内容

モチベーション

既存の動画ベースの姿勢推定手法では下図 (b) のように動画の毎フレームに対して規模の大きなモデルを用いて推定を行い、RNNや Optical Flow などによる時系列情報を活用していましたが、このような枠組みは計算コストが高く非効率的でした。それを踏まえ、本研究では下図 (a) のように小規模なモデルを用いて入力フレームから特徴抽出を行い、Pose Kernel Distillator により得られたカーネルと次フレームのヒートマップのマッチング(= 畳み込み)を行うことにより次フレームのヒートマップを得ます。提案手法である Dynamic Kernel Distillation (DKD) は小規模なモデルを用いた特徴抽出、カーネルの畳み込みによる時系列情報の活用を行う効率的なアプローチとなっています。

dkd1.png

Dynamic Kernel Distillation と既存のアプローチの比較

Pose Kernel Distillation

DKDのアーキテクチャは下図のようになっています。まず、動画の第1フレームに対しては比較的規模の大きなモデルである Pose Initializer を用いて各関節点のヒートマップを推定します。Pose Kernel Distillator は各フレームの特徴マップと推定されたヒートマップを入力に Pose Kernel を出力するモジュールです。Pose Kernel は人物の関節点の特徴をエンコードしたテンソルとなっており、第2フレーム以降は前フレームの Pose Kernel を現在フレームの特徴マップに対して畳み込むことによりヒートマップを取得します。Pose Kernel を利用することにより、各フレームの特徴抽出を行う Frame Encoder に小規模なモデルを採用することが可能となります。これらモデルの学習はヒートマップに対するMSEをロスに用いて行い、推論時はヒートマップのピーク位置を各関節点の推定座標とします。

dkd2.png

Dynamic Kernel Distillation のシステム構成

Temporally Adversarial Training

時系列的に一貫した推定を行うことでDKDの性能をより引き上げるための方法として、姿勢推定に Adversarial Learing を適用したChouらの手法 [22] を時系列に発展させた Temporally Adversarial Training を提案しています。Temporally Adversarial Discriminator は連続した2フレームの画像およびそれらに対応した(Ground-truthまたは推定された)ヒートマップを入力とし、ヒートマップの変化を復元します。入力がReal(Ground-truthのヒートマップ)である場合は前後フレームのヒートマップの差分と等しくなるよう復元を行い、入力がFake(推定されたヒートマップ)である場合はヒートマップの差分から乖離した復元を行います。Temporally Adversarial Training を用いる場合、最終的なロス関数はヒートマップに対するMSEロスと Adversarial Loss の和となります。

モデル構造

それぞれのモデルのアーキテクチャは以下のようになっています。

  • Pose Initializer:ResNetをバックボーンとし数層のDeconvolution層を加えた Simple Baseline [6] と同一構造のモデルを使用
  • Frame Encoder:Pose Initializer と同様のモデルだが、より小規模なバックボーンを使用
  • Pose Kernel Distillator:下図のように3層の畳み込み層およびプーリング層からなる
  • Temporally Adversarial Discriminator:Frame Encoder と同一構造のモデルを使用

dkd3.png

Pose Kernel Distillator のアーキテクチャ

実験結果

Frame Encoder のバックボーンの層数を変化させながらDKDの各構成要素の有効性を検証する Ablation Study を行なっています。下表においてBaselineは時系列情報を用いないモデル、DKD-w/o-TAT は Temporally Adversarial Training を用いないモデル、DKD-w/o-PKD は Pose Kernel Distillation を用いないモデルです。バックボーンに小規模なモデルを用いた DKD(ResNet50) および DKD(ResNet34) が Baseline(ResNet101) の性能を上回っており、最も小規模なモデルである DKD(ResNet18) は FLOPSを半分以下に削減しつつ、Baseline(ResNet101) と同等程度の性能を達成しており、DKDの有効性が示されています。また、いずれのバックボーンを用いたときにおいても Pose Kernel Distillation と Temporally Adversarial Training はモデルの性能向上に寄与しており、両者を併用した場合は平均5.5%Baselineから評価値が向上してします。

dkd_result1.png

Penn Action データセットでの Ablation Study 結果

下図は DKD(ResNet34) と Baseline(ResNet34) のヒートマップの定性的な比較結果になっています。(b), (c) を見比べると、DKDは注目人物に対するヒートマップを適切に推定できていることが分かります。また (d), (e) からはDKDが時系列的に一貫したヒートマップを推定できるていることが見て取れます。(ただ、これらモデルは単一人物画像を前提に学習されているため、Baselineの出力が複数の人物に対して出てしまうのは無理もないと思います。個人的にはDKDを複数人物追跡の性能改善に応用できたら面白いと思います。)

dkd_result2.png

ヒートマップの比較結果。(b), (d) は 提案手法である DKD(ResNet34) による推定された右肘、右腰のヒートマップ 。(c), (e) は 同関節点に対する Baseline(ResNet34) の推定結果

既存手法との性能比較では、Convolutional LSTM を用いた手法(下表中 Luo et al.)や Optical Flow を用いた手法(下表中 Song et al.)と比べ、DKDが精度面、速度面共に優れていることを示しました。

dkd_result3.png

Penn Action データセットでの性能比較

おわりに

今回は 2D Human Pose Estimation に関する代表的な手法および最新論文をご紹介しました。Top-down型の姿勢推定手法では関節点のヒートマップ推定がデファクトスタンダードになっており、モデル構造の改善、とりわけいかに複数スケールの特徴を抽出するかに焦点を当てた研究が数多く存在しました。一方でBottom-up型の手法では関節点のグルーピング方法が肝であり、ベクトル場を用いた手法、埋め込み表現を用いた手法、関節点へのオフセット推定を用いた手法などが存在しました。今後は単に精度を追い求める研究ではなく、 ICCV 2019 に採録された論文にも見られたように、より詳細な人物姿勢の認識や、Single-stageアプローチなどによるモデルの精度と速度のトレードオフ改善などが中心的な研究トピックになっていくのではないかと思われます。Human Pose Estimation における研究トピックとしては 3D Pose Estimation や Shape Reconstruction が主流となりつつありますが、当該分野においても今後さらなるブレイクスルーが起きることに期待したいです。DeNA CVチームでは引き続き調査を継続し、最新のコンピュータビジョン技術を価値あるサービスに繋げていきます。

参考文献

[1] A. Toshev, C. Szegedy, "DeepPose: Human Pose Estimation via Deep Neural Networks," In CVPR 2014.
[2] J. Tompson, A. Jain, Y. LeCun, C. Bregler, "Joint Training of a Convolutional Network and a Graphical Model for Human Pose Estimation" In NIPS 2014.
[3] Shih-En Wei, Varun Ramakrishna, Takeo Kanade, Yaser Sheikh, "Convolutional Pose Machines," In CVPR 2016.
[4] A. Newell, K. Yang, J. Deng, "Stacked Hourglass Networks for Human Pose Estimation," In ECCV 2016.
[5] Y. Chen, Z. Wang, Y. Peng, Z. Zhang, G. Yu, J. Sun, "Cascaded Pyramid Network for Multi-Person Pose Estimation," In CVPR, 2018.
[6] B. Xiao, H. Wu, Y. Wei, "Simple Baselines for Human Pose Estimation and Tracking," In ECCV 2018.
[7] K. Sun, B. Xiao, D. Liu, J. Wang, "Deep High-Resolution Representation Learning for Human Pose Estimation," In CVPR, 2019.
[8] J. Wang, K. Sun, T. Cheng, B. Jiang, C. Deng, Y. Zhao, D. Liu, Y. Mu, M. Tan, X. Wang, W. Liu, B. Xiao, "Deep High-Resolution Representation Learning for Visual Recognition," In arXiv preprint arXiv:1908.07919, 2019.
[9] K. Zhang, P. He, P. Yao, G. Chen, C. Yang, H. Li, L. Fu, T. Zheng, "DNANet: De-Normalized Attention Based Multi-Resolution Network for Human Pose Estimation," In arXiv preprint arXiv:1909.05090, 2019.
[10] B. Cheng, B. Xiao, J. Wang, H. Shi, T. S. Huang, L. Zhang, "Bottom-up Higher-Resolution Networks for Multi-Person Pose Estimation," In arXiv preprint arXiv:1908.10357, 2019.
[11] L Pishchulin, E. Insafutdinov, S. Tang, B. Andres, M. Andriluka, P. Gehler, B. Schiele, "DeepCut: Joint Subset Partition and Labeling for Multi Person Pose Estimation," In CVPR, 2016.
[12] E. Insafutdinov, L. Pishchulin, B. Andres, M. Andriluka, B. Schiele, "DeeperCut: A Deeper, Stronger, and Faster Multi-Person Pose Estimation Model," In ECCV, 2016.
[13] Z. Cao, T. Simon, S. Wei, Y. Sheikh, "Realtime Multi-Person 2D Pose Estimation using Part Affinity Fields," In CVPR, 2017.
[14] Z. Cao, G. Hidalgo, T. Simon, S. Wei, Y. Sheikh, "OpenPose: Realtime Multi-Person 2D Pose Estimation using Part Affinity Fields," In TPAMI, 2019.
[15] A. Newell, Z. Huang, J. Deng, "Associative Embedding: End-to-End Learning for Joint Detection and Grouping," In NIPS, 2017.
[16] G. Papandreou, T. Zhu, L. Chen, S. Gidaris, J. Tompson, K. Murphy, "PersonLab: Person Pose Estimation and Instance Segmentation with a Bottom-Up, Part-Based, Geometric Embedding Model," In ECCV 2018.
[17] H. Duan, K. Lin, S. Jin, W. Liu, C. Qian, W. Ouyang, "TRB: A Novel Triplet Representation for Understanding 2D Human Body," In ICCV, 2019.
[18] G. Hidalgo, Y. Raaj, H. Idrees, D. Xiang, H. Joo, T. Simon, Y. Sheikh, "Single-Network Whole-Body Pose Estimation," In ICCV, 2019.
[19] X. Nie, J. Zhang, S. Yan, J. Feng, "Single-Stage Multi-Person Pose Machines," In ICCV, 2019.
[20] X. Zhou, D. Wang, P. Krähenbühl, "Objects as Points," In arXiv preprint arXiv:1904.07850, 2019.
[21] X. Nie, Y. Li, L. Luo, N. Zhang, J. Feng, "Dynamic Kernel Distillation for Efficient Pose Estimation in Videos," In ICCV, 2019.
[22] C.-J. Chou, J.-T. Chien, H.-T. Chen, "Self Adversarial Training for Human Pose Estimation," In CVPR Workshop, 2017.
[23] Y. Raaj, H. Idrees, G. Hidalgo, Y. Sheikh, "Efficient Online Multi-Person 2D Pose Tracking with Recurrent Spatio-Temporal Affinity Fields," In CVPR, 2019.
[24] I. Habibie, W. Xu, D. Mehta, G. Pons-Moll, C. Theobalt, "In the Wild Human Pose Estimation Using Explicit 2D Features and Intermediate 3D Representations," In CVPR, 2019.
[25] A. Kanazawa, M. J. Black, D. W. Jacobs, J. Malik, "End-to-end Recovery of Human Shape and Pose," In CVPR, 2018.
[26] T.-Y. Lin, P. Dollár, R. Girshick, K. He, Bharath Hariharan, Serge Belongie, "Feature Pyramid Networks for Object Detection," In CVPR, 2017.
[27] Leeds Sports Pose Dataset, https://sam.johnson.io/research/lsp.html, 2019.
[28] J. Carreira, P. Agrawal, K. Fragkiadaki, J. Malik, "Human Pose Estimation with Iterative Error Feedback," In CVPR, 2016.
[29] COCO - Common Objects in Context, http://cocodataset.org/#keypoints-2019, 2019.
[30] AI Challenger, https://challenger.ai/dataset/keypoint, 2019.

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

インフラ運用管理共通ツールセット「gi」のこれまでとこれから

IT 基盤部の廣瀬です。

IT 基盤部ではグループ横断で使っている、インフラの運用管理を支援する共通ツールセットがあります。今回は、このツールセットが生まれた背景、存在意義、メリット・デメリット、今までの反省と今後について話します。

gi とは

IT 基盤部には 5 つのグループがあり、弊社で手がけているサービスのほとんどを IT 基盤部の各グループで担当して運用管理しています。

ゲームを始め、ヘルスケア事業、ソーシャル LIVE 事業、スポーツ事業など、多岐にわたるサービスが存在しています。

インフラの運用管理にあたり、それを補助、支援するスクリプトというのはどうしても必要になってきますが、このような状況で、各グループ、各サービス担当チームで各々スクリプトを実装するのはさまざまなデメリットがあるため、IT 基盤部では共通のツールセットをみんなでメンテナンスして使っています。

この共通ツールセットのことを、部内では「gi」と呼んでいます。

gi が生まれた背景

私が入社した 2011 年ごろは、今ほどサービスのバリエーションは多くなく、主軸はゲーム事業でした。

ゲーム事業の開発には内製の MobaSiF と呼ばれる WAF を使っていたのですが、インフラが使うスクリプト群もこの MobaSiF のリポジトリに含まれていました。また、使用している内製のライブラリや、たとえば冗長性の担保といったさまざまなしくみの実装も、ゲームとインフラとで強く結合し、不可分な状態でした。

ソーシャルゲーム勃興期の Mobage のような、急激に成長するサービスを切り盛りするには、このようなモノリシックな構成は一番効率がよいと個人的には思っています。しかし時を経るにつれ、たとえばインフラ側でモジュールを追加したりモジュールのバージョンアップをしようとしても、密結合しているゲームへの影響が怖くて実施できないといった、スピード感が損なわれるケースが散見されるようになってきました。

ちょうどそのような時期に、海外向けのサービスをオンプレではなくクラウドで行うため、インフラ環境をゼロから作る必要がある案件があったり、Perl ではない言語で (MobaSiF は Perl ベースです) サービスを開発する案件が持ち上がりつつありました。

そこでこれを契機に、次のことを実現するために新しいインフラの共通ツールセットを開発しようということになりました。

  • サービスとは独立した、インフラの運用管理のためのツールセット
  • オンプレだけでなくクラウドにも対応

設計と初期の実装は私が行ったのですが、加えて次の点も意識しました。

  • 今後、ゲーム以外のさまざまな新規案件が立ち上がるのを見越して、どんなサービスでも対応できる柔軟性を持たせる
  • 将来的な既存案件のスムーズな移行のために、サービス側でも使っているモジュールやサーバ管理のしくみは互換性を維持する

git log をみたところ最初の commit は 2012-11-12 でした。

初期の実装こそ私が主に行っていましたが、これまで延べ 100 人以上の committer による 45,000 近い commit 、今では IT 基盤部が担当するほぼすべてのサーバで gi は導入されており、gi は IT 基盤部みんなで作り上げたツールセットに成長しています。

共通ツールセットのメリット

質の向上

特に監視や構築スクリプトが顕著ですが、各グループにはそれぞれのノウハウが蓄積されています。

それを持ち寄り共通のスクリプトに実装することで、IT 基盤部全体、ひいては弊社のサービス全体の質の高い安定運用への貢献、また運用作業の効率化が実現できます。

学習コストを低く抑えられる

IT 基盤部ではグループ間の異動がたびたびあります。

もし、グループ間で運用スクリプトがバラバラだったら、たとえば、用途やタグによってサーバを検索するような日常的に使うスクリプトの使い方が全然違っていたら、あるいは、同じミドルウェアなのに構築、運用、監視のスクリプトがまったく異なっていたら、異動後にキャッチアップするまでに時間がかかってしまうでしょう。

ツールセットを共通化することで、こういった時間を最小限にカットできます。

また、異なるグループの人どうしの会話でも、 gi が共通言語になるのでやりとりもスムーズになります。スクリプトの名前を挙げれば、どのグループの人でも何を目的としてどのような動作をするものか頭に浮かぶからです。個人的にはこれがかなり大きなメリットじゃないかと思っています。

共通ツールセットのデメリット

一方でデメリットがまったくないわけではありません。

新規メンバーの学習コストが高い

学習コストについてはメリットの節で挙げたような利点がある一方で、新規メンバーにとっては、膨大な数のスクリプト、さまざまな運用管理のしくみなどをひとつひとつ理解していくのは気が遠くなる作業に感じられるでしょう。

新規メンバーにはメンターがついて OJT で学んでもらっていますが、段階的に学べる教材を用意するのは課題としてあります。

ガラパゴス化の懸念

今ならもっと効率がよかったり信頼性が高かったりするツールやシステムが存在するにもかかわらず、なかなか外に目が向かず、時代遅れの内製実装を使い続ける懸念があります。

導入・移行コストはかかるものの、しっかり見極めてよいものは貪欲に採用していきたいところではあります。

修正に対する気後れ

gi が大きくなった副作用か、「gi はこういうものだ」という現在の状態を絶対視しがちな傾向があるようで、便利なオプションのアイデアを思いついても実装しようとしなかったり、「gi が対応していないからあのミドルウェアは導入できない」といったような話をたまに耳にします。

また、コードの修正が他グループへ影響するのを懸念して亜流が生まれてしまっています。たとえば、ディスクの残量を監視する Nagios プラグインのスクリプトは、対応デバイスが微妙に異なるのが複数存在してしまっています。

これらは、たとえばレビューの強制といったシステム的な手法で改善できるものもありますが、gi の根幹の設計思想やガイドライン、gi はみんなで作り上げるみんなのものだよ、といったことを IT 基盤部のメンバーに伝え続けることが何より足りなかったなと反省しています。

新しい gi

既報のとおり、現在、弊社はオンプレからクラウドへ大規模な移行作業を行っている最中です。

そしてこれを機に、これまでの改善点や反省点を踏まえ、gi とその周辺のインフラ運用管理のための内製のミドルウェアを再設計して実装している真っ最中です。

クラウド移行が落ち着いたら、新 gi とその周辺の話もまた別の機会にできるんじゃないかと思います。

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

Go Conference 2019 Autumn で3名が登壇、コードラボも公開しました!

こんにちは、品質管理部SWETグループの細沼です。

先日、国内最大のGoのカンファレンスであるGo Conference 2019 Autumnが開催されました。DeNAではスポンサーを務めさせていただき、社内からは3名が登壇しました。また、Goコミュニティへの貢献の一環として、社内で利用していたGoの学習教材であるコードラボの一部を当日に公開しています。

本記事ではイベントレポートをしつつ、登壇した3名から発表についての紹介、コードラボを公開した経緯や今後について書きたいと思います。

go_conf_2019_talk.JPG

Go Conference 2019 Autumn

Go Conference 2019 Autumn は2019/10/28に開催されました。Go Conferenceの運営者によると7年近くも続いているイベントとのことで、歴史を感じるカンファレンスとなっています。国内におけるGoのイベントとしては最大で、こうしたイベントによって国内のGoコミュニティが活発化するのはとても良いことだと感じます。

今回は、前回に続いてプロポーザル形式による公募でのトーク採択が行われ、2トラック制で20分と40分、懇親会ではLTの発表も行われました。初心者向けや、技術的に面白みのある発表もあり、多くのGoエンジニアが楽しめるイベントになっていたと感じます。DeNAではスポンサーとして、WiFiと懇親会でのアルコールの提供させていただきました。

WiFiについては今回の会場にネットワーク設備がなく、また公共施設ということで工事も行えないということが分かり、急遽モバイルWiFiルータ14台でネットワーク環境を用意しました。事前に大人数での試験ができず、当日のネットワーク速度は快適とまではいかなかったと思うので、次回以降の経験として活かしていきたいと思います。

go_conf_2019_wifi.jpg

ブースの様子

今回も各社さんがノベルティや飲み物(水やコーヒー)などの提供をしていました。

DeNAでは、弊社で定期的に開催しているDeNA.goという勉強会のステッカーやウェブカメラのカバーを配布していました。

go_conf_2019_booth.JPG

エンジニアによる登壇

つづいて当日に登壇させていただいた3名から、それぞれの発表について紹介させていただきます。

gotestsから学ぶテストコード自動生成のメカニズム

gotestsがどのような仕組みでテストコードの生成をしているかと、生成されるテストコードのカスタマイズ方法についての発表です。

gotestsについて知ったときに、このツールをもっと便利に使うためにはどうしたらいいのだろう?と思い、調べ始めたのが発表のきっかけです。

自動生成はこんな感じの仕組みなのかなというなんとなくのイメージはありましたが、実装を深堀りすることでそれを具体化することができました。

今回得た知識を活かして、自分でも自動生成ツールの実装に挑戦したいと思います。

Go で"超高速"な経路探索エンジンをつくる

カーナビはどうしてあれほど運転ルートを高速に計算できるか、気になったことはありませんか?

本トークでは、 実際にGoで"超高速"な経路探索エンジンを作成したときに用いた、アルゴリズムと実装時の工夫・チューニングを紹介しました。まず経路探索アルゴリズムはどういったものか、ご紹介しました(ダイクストラ、Contraction Hierarchies )。

次にそれらを Go で高速な実装にする工夫を、slice や map の内部アーキテクチャを踏まつつ解説しました。 sliceに関する解説は単体で切り出して記事にしましたので、よろしければそちらもこちらもご覧ください。

Go slice ベストプラクティス

Welcome to Linter

複数のメンバーでチーム開発を行う際、メンバーによってコーディングスタイルが異なっていたり、エラーを無視したようなコードやコード品質の差異が発生してしまうことが多いです。

更に、コードレビューをする際にそういった箇所の指摘が多くなりがちになってしまいます。こういったコードの一貫性等のソースコード品質を機械的に一定レベルを担保し、検査、フィードバックできる仕組みが必要です。

こういった問題は静的解析を行うことによってある程度解決することができます。Go言語では静的解析を行うためのツールセットが整っており、かつ同じ言語で記述することができます。

今回はプロジェクト固有の静的解析ツールを開発する為に必要な知識から、チームに静的解析を導入する為のナレッジを発表しました。

コードラボ公開

当日のお昼くらいにTwitterで周知しましたが、DeNA社内で学習教材として利用していたコードラボの一部をDeNA Codelabsとして公開しました!

以前から社内だけに閉じておくのはもったいないという話は出ていたのですが、なかなか時間がとれず公開までには至らない状態が続いていました。今回、社内において「DeNAとしてのGoコミュニティの貢献の一環としてやろう」という話が持ち上がり、今回のイベントに合わせて公開することができました。

Goのコードラボとしてはgolang.tokyo コードラボもありそちらで公開することも案として上がったのですが、他のプラットフォームのコードラボも公開したいという話が持ち上がり、DeNAオリジナルのコードラボページを作る運びになりました。

go_conf_2019_codelabs.png

go_conf_2019_codelabs_detail.png

現時点では2つのみの公開となっていますが、今後も少しずつ数を増やしていきたいと考えています!

おわりに

DeNAでは、今後も業務で得られた知見を積極的にシェアするなどして、Goコミュニティへの貢献をしていきたいと思っています。

また、Go Conference 2019 Autumnを企画・運営し、日本のGoコミュニティを盛り上げてくださった運営の方々や当日スタッフの方々にこの場を借りてお礼を申し上げます。

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

DeNAのリアルイベントの舞台裏〜ネットワーク構築編

はじめに

こんにちは、IT基盤部の兵藤です。 主に社内ネットワークのインフラを担当しています。

弊社では、DeNA TechConなどの技術系イベント、Pocochaで開催しているリアルイベントなどを主催しており そのイベント会場のネットワーク構築は我々(IT基盤部ネットワークグループ)が行っています。

今回のブログでは、そのイベントの舞台裏となる 会場ネットワーク構築の手順などをお伝えしていこうと思います。

イベントのネットワーク構築の流れ

イベントのネットワーク構築は ざっとこのような手順で行っていきます。

  1. イベント会場のネットワーク状況の把握
  2. ネットワーク設計
  3. キッティング
  4. 当日の構築

一つずつ簡単に説明していきます。

1.イベント会場のネットワーク状況の把握

まずはイベント会場のネットワーク状況について把握する必要があります。 会場によって既設の設備も様々であり、利用させてもらえるものは利用したほうが費用が安く抑えられる場合もあるからです。 無線の設備がある会場もなかにはありますが、こちら側で無線の状態などコントロールができないため、基本的には利用していません。

会場の既設ネットワークの確認では主に以下の項目を確認しています。

  1. 回線の種類は何を使っているのか。 こちらについては利用している回線の種別から、回線の品質についてある程度判断しています。 例えばフレッツ光ネクストを利用しているのであれば、ベストエフォートで1Gbpsの回線であることがわかります。

  2. 回線の実効速度はどの程度か。 回線の種別がかわかったとしても、実効速度がどの程度あるのかを調べておかないと、ベストエフォート回線では致命的になります。 フレッツ回線の場合はまず間違いなく1Gbpsは出ませんので、実際に接続させてもらい、複数の速度測定サイトなどを利用して平均値を測っています。

  3. 回線は安定して利用できているか。 こちらについては情報があればもらうようにしています。 上記で実効速度を測ったとしても、それは観測時点での結果であり、継続してその速度が出る保証はどこにもありません。 なので、ある程度のスパンで回線の状況について計測しているデータが有ればもらうようにしていますが、フレッツを利用しているところは大抵持っていませんので判断に困ります。

上記のようなことを総合して、既設回線を利用するのか、新規に安定した回線を引き込むのかを判断して対応しています。

これまで対応してきた中では、会場の状況については下記のようなものが挙げられます。

  1. 会場の既設ネットワークが利用可能であり、帯域的にも十分利用に耐えうる
  2. 会場の既設ネットワークが利用可能ではあるが、帯域が乏しく利用が難しい
  3. 会場の既設ネットワークが利用不可だが、回線の引き込みは可能
  4. 会場の既設ネットワークが利用不可でありかつ、新たな回線の手配も不可能

ほとんどの会場が2か3に該当することが多く、会場となる場所へ新規にインターネット回線を引き込みさせていただいています。 1ができる会場は稀で、4についてはそもそも会場選びの候補から外してもらっています。

TechConで利用しているヒカリエホールは、1に該当してますが、通常利用ではベストエフォート100Mbpsの帯域のみの利用であるため、帯域を1Gbpsへ拡張するために利用料を上乗せして払っていたりします。

インターネット回線を会場へ引き込む場合、新規の回線敷設には1.5ヶ月〜3ヶ月必要と回線業者から言われることが多く、早め早めに行動することが必要になってきます。 回線敷設については、NTTが絡むことが多く、回線業者でもコントロールすることが難しい部分もあるため、毎度綱渡り状態で回線敷設していたりします。

2. ネットワーク設計

会場の状況が確認でき、インターネット回線利用の方向性が固まったら、次にネットワーク設計をします。 基本的な構成は下図のように設計・構築しているのですが、会場によっては既設部分とのつなぎの仕様を確認したりして柔軟に対応しています。

Network-diagram.png

会場の大きさ、形、有線LAN利用の要望などを考慮し、無線のカバレッジホールができないように、機器の台数、設置位置などについて設計していきますが、、、

DeNAではイベント用に専用のネットワーク機器を確保しているわけではありません。 都度、必要台数を設計し、通常運用で確保している予備機器を利用して、構築しています。 予備機の状況によっては、要件を満たずのが困難だったりもしますが、その時は必要最低限の箇所に絞ってもらい対応するなどしています。

また、論理設計だけでなく、物理設計についても都度会場に合わせて設計をしています。 会場によって、どこに電源があるのか、どこに機器を設置するのか、どのようにケーブルを取り回して配線するのか、など考慮する必要があります。 ケーブルの長さ、本数などが足りなければ購入するなどして対応しています。

3. キッティング

設計が終わればキッティングを実施します。 キッティングと言ってもすでに何度もイベントを実施しているため、基本的な設定はすべて完了しているため、ただただ地道にコンフィグ設定をしていきます。

設定が全て終われば、仮組みをし設定に問題がないか確認します。 仮組みで問題なければ、機器、ケーブル、電源タップなど必要機材一式を梱包し、会場へ配送手配をします。

4. 当日の構築

イベントでは前日に準備日を設けている場合と、そうでない場合があります。 前日準備が可能であれば、構築時間も潤沢にあるので問題ないのですが、当日準備の場合は限られた時間の中で構築する必要があり、NOCメンバー全員で手分けして構築作業をしています。 広い会場では物理的な配線作業が一番時間を要します。多いときは6人で3時間ずっと配線作業していたりします。

物理的な構築が完了したら、無線のカバレッジホールが無いかどうか、会場全体を無線スキャンしながら回ります。 問題がなければ基本的な構築は完了です。あとは本番に向けて監視の設置をしていきます。

監視についてはnagios(機器監視)などを構築して使っていたり、Cisco Meraki機器を利用してネットワーク構築した際などはMeraki Dashboard上でトラフィックの傾向確認をしていたりします。。 機器監視については、本番中に機器が停止していないか、CPUなどのリソースは問題ないかを監視しています。 過去の例では、イベントの関係者が誤って電源を抜いてしまったなどのトラブルがありましたが、監視のおかげですぐさま復旧させ事なきを得ました。

トラフィック傾向確認については、今後のイベントのために傾向を見れるように可視化するために使っています。 過去のTechConでは来場者1000人程度に対して、最大同時接続650台程度で300Mbps程度のトラフィックを観測しています。

イベントが終了したあとは、撤収作業も自分たちで行っています。撤収も時間が限られているため時間との戦いです。 設営のときほど気を使わなくていいので、一気に撤去作業を進めていきます。整理整頓は後でいいので撤去優先でどんどん実施します。

自社によるネットワーク構築のメリットデメリット

このようにイベントにおいて自社でネットワークの環境を構築していると普段あまり体験しないレイヤー1の部分からすべて自分で対応することで、ネットワーク構築の経験を積めるといったメリットがあります。 構築費用面においても、自分たちですべて実施することで、外部への費用流出を抑え低コストで実施できます。 設計についても自分たちでやることで、柔軟に対応でき、スピード感を持って対応することができます。

一方でトラブル時などは全て自分たちで解決しないといけないといったデメリットは懸念されるところですが、事前検証をみっちりやることで未然にトラブルを防ぐようにしています。

おわりに

以上、ネットワーク構築の流れやメリットなどを紹介させて頂きました。

簡単ではありますが、少しでも良い環境構築の参考になれば嬉しく思います。 最後までお読みくださり、ありがとうございました。

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

VimConf 2019参加レポート

MOVのサーバサイドエンジニアをしている古舘(@178inaba_)です。
11月3日に行われたVimConf 2019に参加しましたので参加レポートをお届けします。

VimConfとは

テキストエディタVimの国際会議で2013年から開催されているカンファレンスです。
今年のキーノートスピーカーはvim-lspasync.vimasyncomplete.vimの作者であるPrabir ShresthaさんとNeovimのリードメンテナーであるJustin M. Keyesさんのお二人でした。

国際会議なのでスライドはすべて英語でした。
また、公式サイトを見てもらうと分かる通り英語のセッションが日本語より多かったです。
ですが同時翻訳がしっかり完備され、英語があまり得意でなくてもセッションの内容はわかるようになっていました。

DeNAとVimConf

DeNAはGold SponsorとしてVimConfにスポンサードさせていただきました。
ノベルティとして挿入モードの補完チートシートをお配りさせていただきましたが皆さん使っていただけていますでしょうか。

cheat_sheet.png
ノベルティとして配布させていただいた挿入モードの補完チートシート

実はこちら、弊社の鈴木(@dice_zu)が昨年のVimConf 2018で登壇した資料から作成されたものなのです。

そして、昨年に引き続き今年も鈴木が通常セッションで登壇致しました。
タイトルは「Usage and manipulation of the tag stack」です。
手前味噌ですがtag stackの実装が図を用いて解説されており、非常にわかりやすかったです。
ぜひご一読ください。

懇親会ではスポンサーセッションも行いました。
スポンサーセッションでは鈴木がVimConfをスポンサードする価値を会社にプレゼンした内容を赤裸々に語り、懇親会の盛り上がりに一役買えたのではないかと思います。

セッション

今年のテーマは「how to be more productive with Vim?」という事でVimを使ってより生産性を高める方法が多く紹介されていました。
特にvim-lsp関連のセッションが多かった気がします。
それぞれのセッションについては公式サイトにスライドPDFがありますので詳細はそちらに譲ります。

ここでは筆者が特に気になったセッションをいくつかご紹介します。

"Vim Renaissance" by Prabir Shrestha

筆者も使っているvim-lspの作者であるPrabir Shresthaさんのキーノートです。
lspプロトコルの詳細やvim-lspを作った動機を話されていました。
LSP(Language Server Protocol)の登場以前はエディタ毎に補完やタグジャンプ等の機能を実装しなければならなかったが、LSP登場以後は言語毎にLanguage Serverを作っておけばエディタ側はvim-lspを入れるだけでよくなりました。 これは確かにルネッサンスだなと思いました。
また、次の革命についてVim向けのJavaScriptインタフェースが入ったら多くの人たちがplugin開発に参加しやすくなり革命が起こるだろうと話されていました。

"We can have nice things" by Justin M. Keyes

NeovimリードメンテナーのJustin M. Keyesさんのキーノートです。
2016年まではVimは安定性にフォーカスしており、なかなか新しい機能が入らなかったため新しい機能が頻繁に入るVimを目指してNeovimが産まれたそうです。
実際、4日開発が止まっただけで「Neovimは死んだ?」と言われたそうで、それだけ頻繁に新しい機能が実装されているという事ですよね。
「NeovimのゴールはVimを置き換える事ではない。Vimの最大化がゴール。」と話されていたのが印象的でした。

"make test" by m-nishi

Vim本体のテストについてのセッションです。
このセッションに触発されて自分の手元でmake testしてみたら余計なファイルが残ったので余計なファイルが作成されないようにするPull Requestを提出しました。

https://github.com/vim/vim/pull/5177

結果的には別な修正方法での解決になりましたがきっかけをもらったセッションでした。

"My Vim life" by gorilla0513

DeNAも会場提供させていただいているゴリラ.vimのオーガナイザーであるgorillaさんのセッションです。
約一年前からVimを使いはじめてVimの勉強会を開催したり技術書典でVimの本を頒布したりとバイタリティ溢れる活動をしているgorillaさんがどのようにVimを学んできたかを紹介していました。
個人的にヘルプを読み込むという話は目からウロコでした。
自分は困ったときしかヘルプを読んでいなかったので今後読み物としてVimのヘルプを読んでみようと思いました。

"13 Vim plugins I use every day" by Tatsuhiro Ujihisa

ujihisaさんはVimConfの前身であるujihisa.vimを主催していた方で今回のVimConfの運営もされています。
そんな長年Vimに貢献されているujihisaさんが毎日使っているpluginを紹介するセッションです。
紹介されていた中ではgina.vimlexima.vimが気になりました。
また、ライブコーディングでHTTPサーバを実装するという事もしていて、このライブコーディングが非常に鮮やかでした。
立て板に水ということわざがありますが、筆者はujihisaさんのライブコーディングを見て『立て板にVim』という言葉が思い浮かびました。
それほどすごかったです。
動画がアップされたらぜひとも見返したいセッションです。

お弁当

お弁当がすごかった事はぜひ皆様にお伝えしたいです。

今半のすき焼き弁当です。
運営のujihisaさんが「我々が用意できる最高のものを用意したのでゆっくり楽しんで」とおっしゃっていて、実際に最高でした!

まとめ

本当に最高のカンファレンスでした。
Vimのカンファレンスというのは世界中探してもこのVimConfだけのようです。
そんな世界的なカンファレンスに参加できたことはすごく幸せなことだと思いました。
また、技術への情熱、Vimへの情熱にあふれる方のセッションを聞くことができたのは筆者にとって大変貴重な時間でした。

個人的ではありますがGo言語コミッターであるmattnさんに会えた事はすごく嬉しかったです!
(筆者がmattnさんのgo-mastodonにContributeしたことを覚えてくださっていた事に感激しました。)

Vim漬けの一日で非常に情報量が多く、いい意味で精神的に圧倒された部分もありましたが次回もまた参加したいと思いました。

運営のみなさん、登壇者のみなさん、懇親会で話してくれたみなさん、ありがとうございました!

DeNAはこれからもVimを応援し続けます!

非公式VimConf後夜祭

先述のゴリラ.vimとgirls.vimの共催で非公式VimConf後夜祭が開催されます。
非公式とは言うものの、VimConf運営メンバーのKoRoNさんが「VimConfの作り方」というタイトルで登壇します。
ぜひ足を運んでみてください。

ゴリラ.vim
ゴリラ.vim #10 非公式VimConf後夜祭

girls.vim
girls.vim vol.3 - 非公式VimConf後夜祭

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

Auto Scaling から見るInfra System の構成

こんにちは、IT 基盤部の Wei です。大規模ゲームタイトルおよびゲームプラットフォームのインフラを運用しております。

私のグループが運用しているシステムでは Auto Scaling を導入してからもうすぐ2年が経ちます。

この2年で Infra System の構成は徐々に変わってきました。今回は Auto Scaling という観点から、現時点の Infra System の構成がどのようになっているかをご紹介します。

Instance の台数管理

Auto Scaling を導入する前、Instance の台数管理は人手でした。台数管理には必要台数の計算から Instance の構築・撤去まで Instance 関連の処理が全て含まれるため、人手で行うには多くの工数が掛かります。また、人手で対応するため想定外のトラフィックが押し寄せた場合に台数を増やすのに時間が掛かるというケースも多々ありました。更に、人手だと管理頻度にも限界があり、余剰リソースを持つ時間帯が多く、それゆえ無駄なコストも掛かっていました。

以上の課題を解決するため、Instance の台数管理を自動化する必要があります。当時マネージドの Auto Scaling サービスで我々のシステムの要件を満たすものはなく、また Spot Instance との併用時に求められる柔軟性などを考慮し、Auto Scaling システムは独自に実装することにしました。ちなみに、このシステムは現時点では GCP の Managed Instance Group と連携するなど、一部マネージドサービスの機能も取り込んでいます。

台数管理システムには大きく2つの Component があります。台数維持を担当する Component (以下、Instance Controller)と台数計算を担当する Component (以下、Auto scaler)です。

Instance Controller は、設定された台数を維持することを目標にします。サーバが落ちたら自動的に Instance を作成しますし、Instance 台数が設定値を上回ったら Instance を撤退します。Instance Controller に対する入力は必要台数の総数のみですが、単に台数を足すだけではなく様々な事情を考慮する必要があります。Spot Instance と On-demand Instance の比率をどうするのか、複数の Instance タイプをどのように混在させるのか、どの Availability Zone に Instance を立てるのかなど。例えば Spot Instance が枯渇したら On-demand Instance を利用する必要がありますし、特定の Instance タイプの在庫が枯渇した場合は別な Instance タイプを利用する必要があります。ちなみに、なぜ種類が多いか以前の記事 DeNA の QCT マネジメント を参考できると思います。

一方、Auto scaler は必要台数を計算して Instance Controller に伝えます。台数の計算は、Metrics (基本的にCPU) に基づいていますので、Metrics 集計システムが必要です。一般には CloudWatch、Prometheus などが使われますが、我々のシステムはここも独自実装になっています。フラッピングを避けるため、Auto scaler は CPU 利用率が一定の範囲内に収まるように指示を出します。具体的には CPU 使用率が60%を超えたら台数を増やし、40%を下回ったら台数を減らす、という具合です。そして、Instance の構築はどれだけ高速化を頑張っても数分単位で時間が掛かるため、瞬間的になトラフィック増には間に合いません。そのようなケースは事前に予測可能なことがほとんどなので、事前に台数を増やしておくことで対応しています (そのようなスケジューリング機能も持っています)。

flow0.png

Instance の作成

DeNA にはサーバのメタデータを管理するための専用のシステムが存在します。これは主にオンプレ環境でサーバを維持管理するために必要なシステムでした。クラウドの IaaS 環境においても、このサーバのメタデータ管理システムが必要です。

このメタデータ管理システムと連携するため、Synchronizer と呼ばれるコンポーネントを開発しました。オンプレ環境においてはこのシステムに登録する作業は人手で行なっていましたが、IaaS 環境においては Terrafrom や Google Managed Instance Group や AWS Auto Scaling Group などと連携する必要があり、その処理を自動化するために Synchronizer が必要です。

クラウドのリソース情報をメタデータ管理システムと連携させるにはもう一つ問題があります。それは利用するクラウドの種類が増えるたびに、そのクラウド専用のロジックを実装する必要があることです。この問題を解消するため、我々は Cloud Adapter と呼んでいる抽象化層を実装しました。例えば、Instance にアタッチする Volume として AWS であれば EBS、GCP であれば Persistent Disk がありますが、これらはVolume という概念で抽象化しています。こうすることで他システムからはクラウドサービスの違いを意識することなく統一した Interface で扱うことが可能です。

flow1.png

ちなみに、Interface 自体は、Protocol Buffers で定義しています。例えば、Instance の定義:

 message CloudInstance {
   string id = 1;
   cloud.CloudProvider provider = 2;
   string zone = 3;
   string name = 4;
   // Private IP of first NIC
   string private_ip = 5;
   // Public IP of first NIC
   string public_ip = 6;
   // Subnet Reference of first NIC
   cloud.ResourceReference subnet_ref = 7;
   string instance_type = 8;
   map<string, string> label = 9;
   google.protobuf.Timestamp launch_time = 10;
   string fqn = 11; // Fully qualified name such as self-link, ARN, etc.
 ...
 }

以上で、Instance を作成したら同時にメタデータ管理システムにも登録することが可能になります。同時に Instance の Life cycle も開始されます。

Instance の Life cycle 管理

Instance を作成したら、OS 設定、アプリケーションコードのデプロイ、テスト、監視設定などの作業を行います。この一連の作業はこれまで専用のスクリプトで行なっていましたが、スクリプトだと以下のような問題がありました。

  • スクリプトがどんどん太り、メンテナンスコストが増え続ける
  • 長大なスクリプトは冪等性を担保することが難しい
  • 処理の途中からリトライさせるような処理を書きづらい
  • スクリプトの実行ホストが落ちた場合に構築・撤去処理自体が失敗する
  • 構築・撤去処理がどこまで進んでいるのか見えづらい
  • 構築・撤去処理の負荷分散がしづらい
  • 構築・撤去処理の並列実行やパイプライン化が難しい
  • 実行してるスクリプトを丁寧にキャンセルしにくい

構築台数が増えれば増えるほど、上記の問題は顕在化してきます。この問題を解消するため、Workflow というシステムを開発しました。

Workflow は大きく2つの Component から成ります。タスクの管理とディスパッチを行う Scheduler とタスクを実際に実行する Executor です。Scheduler と Executor はそれぞれ冗長化していますので、数台落ちても Workflow の実行に与える影響は軽微です。Workflow は各処理に対してリトライやタイムアウトを設定することが可能です。またタスクの単位を小さくすることで冪等性も実装しやすくなります。

Workflow は Jenkins のように設定したタスクを順番に実行していきます。さらに、Workflow はタスクの分散処理、パイプライン化、自動リトライ、依存関係を考慮したタスクの実行などを行うことができます。Workflow で実行するタスクを設計する上で二つ重要なポイントがあります。1つ目は各タスクに冪等性を持たせること、2つ目はタスク間の依存関係を減らすことです。この2つを満たすことでタスクの途中失敗を減らすことができます。

flow2.png

Instance の構築タスクは前述の通り様々ありますが、その中で一番難しいのはアプリケーションのデプロイです。デプロイの方法次第では、その処理自体が非常に時間が掛かってしまいます。この問題には、事前に最新のアプリケーションをデプロイした Image を用意しておき、そこから Instance を作成するという方法で対処することにしました。

Instance の撤退

Instance の Life cycle の終わりは、Instance をサービスから完全に切り離し、Instance 自体を削除することです。メタデータ管理システムからの削除も行う必要があります。これで Instance の撤退が完了だと思いますが、実はそうではないです。Volume の Life cycle も考慮する必要があります。

なぜ Volume の Life cycle と Instance の Life cycle が違うかというと、主にログ回収のためです。ログの回収は、エラーログなど即時転送しているログもありますが、データ量によって即時転送していないログもあります。さらに、転送先(例えば Fluentd サーバや Stackdriver Logging など) の障害が起きる可能性があります。障害のタイミングによってログを即時に回収できない場合もあります。溜まっていたログを転送するために、その間 Instance を起動し続けるのは非効率ですし、AWS Spot Instance や GCP Preemptible Instance などは Instance は短時間で削除されてしまうので、Volume の Life cycle と Instance 分けるのは一つの案になります。

そのため、Instance を撤去するときは Instance はそのまま削除しますが、ログがある Volume はまだ消さないようにします。我々のログ回収システムは、使い済みの Instance の Volume を mount して、中身を S3 や Google Cloud Storage に転送しています。ちなみに、転送したログは、AWS Athena と Google BigQuery を活用して、検索することも可能です。

まとめ

今回は Auto Scaling の観点から、私のグループの Infra System の構成を大ざっぱに紹介しました。構成はそんなに複雑ではないですが、様々な問題に対処するため、工夫を凝らしています。そして、紹介したシステムは一気に完成したのではなく、最初は簡単なスクリプトから始まり徐々に進化してきました。現在でもまだ進化中です。もし詳細にご興味をお持ちの方やシステムをより進化させるために一緒に取り組んでくださる方がいらっしゃれば、ぜひ DeNA に join してください。

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

ゲームサーバ開発エンジニアがみた Go Conference 2019 Autumn

Go Conference 2019 Autumn

19新卒の勝倉です。今回、スポンサー枠でGoConference2019に参加させていただきましたので、レポートをお届けいたします。 それぞれのセッションに関しては、Twitterの#goconでスライドが共有されておりますので、詳細はそちらに譲ることとして、普段の開発に役立てられそうな点を振り返りたいと思います。

Go Conferenceに参加するにあたって

どれも非常に面白そうで全部聞きたかったのですが、当日は2会場展開だったため、なるべく業務に役立ちそうなセッションを重点的に聞こうと思いました。 (全体としては、コンテナ技術やデータ解析に絡んだトピックが多かったように思います。) ゲームサーバーを開発するチームに所属しているので、キーワードとしては、「パフォーマンス」「テスト」「自動生成」あたりをメインに、個人的に関心のある「つくってみました」系もいくつか選んで参加しました。

OSS Performance Tuning Tips

概要

スライドはこちら

「OSSで公開されているライブラリのパフォーマンスを向上させていくためには、どのようにアプローチしていけば良いか」というお話でした。 パフォーマンスチューニングの流れとしては、

  • ボトルネックになっている箇所をpprof(またはgithub.com/pkg/profile)を使って絞り込む
  • 怪しい箇所のベンチマークを書く
  • 試行錯誤してベンチマークを向上させる

発表の中では、試行錯誤を行なっていく際に、どういったポイントに目をつけていくとよさそうか、という紹介もありました。 たとえば、

  • 順序が保証される必要のないsliceをmapにかえることで、探索をO(n)からO(1)で終わるようにできる。
  • 何回も読み書きが必要なところは、都度bufferを確保するのではなく、sync.Poolでバッファープールを作ってあげると無駄なメモリ消費を減らせる。
  • 必要以上に強力なhashアルゴリズムを使っているところは、他の軽いアルゴリズムで代替できれば速くなる。

といったtipsが紹介されていました。

感想

はじめてGoに触ったとき、(=はじめて静的型付け言語に触ったとき)、ポインタの仕組みを理解しないで、でっかい構造体のスライスを毎回コピーしていたら、rubyの10倍くらい遅いコードができあがり、「『Goだから速い』のではなく、『Goを正しく使うから速い』」という教訓を得たときのことを思い出しました。

それ以降は、たとえば、

 // hogeは[]string
 s := []string{}
 for _, v := range hoge {
   s = append(s, v)
 }

このような書き方は避けるようになったのですが、このセッションで、他にも書き方のコツを仕入れることができて、良い勉強になりました。

またセッションの中で、メンテナンス性が下がるので非推奨ではありますが、AVOというパッケージを使えば、いい感じにGoのコンパイラの特性を生かしてアセンブリをかけるという紹介もありました。

いつの日か、どうしようもないボトルネックになってしまっている箇所を、アセンブリで華麗に解決できたらと思います。

Continuous Automated Go Fuzz Testing

概要

(スライドは共有されていませんでした。)

gofuzzを使って、Fuzz testingを導入して、コードの品質をあげよう」というお話でした。

Fuzz testingは、テスト対象の関数の引数をビット反転などの演算によってsemi-randomに生成し、カバレッジが閾値を超えるまで回し続けて予期せぬエラーが発生しないかを確認するテストのことだそうです。

このテストを導入することによって、たとえば、

 // fooは、与えられたバイト列が「d.e.n.a」ならtrue、それ以外ならfalseを返す関数
 func foo(s []byte) bool {
   if len(s) >= 3 {
     if s[0] == 'd' && s[1] == 'e' && s[2] == 'n' && s[3] == 'a' {
       return true
     }
   }
   return false
 }

 var testcases = []*struct{
   in []byte
   want bool
 }{
   {
     []byte("dena"),
     true,
   },
   {
     []byte("baystars"),
     false,
   }
 }

このような関数とテストケースを書いてしまった時に、効果を発揮するとのことでした。

Goの標準パッケージでも、Fuzz testingを使って、100件以上のバグが見つかっているらしいです。 https://github.com/dvyukov/go-fuzz#trophies

注意点として、unit testやintegration testの代替となるわけではなく、実装方法に関する不備を見つけ出すためのテスト、ということでした。

感想

最近、チームで負荷試験の話になったときに「1回の負荷試験で数百万円かかる」と聞き、以前にもましてテスト設計をしっかりと考えたり、意識して変な値(絵文字など)を入れたりするようになりました。 Goの標準Testingパッケージでは、命令網羅率を測ってくれますが、上の例を見せられた時に、自分の書いたシナリオでカバレッジが高くても安心できないなと、ドキッとしました。 たとえば、validationのヘルパー関数などはいちいち関数ごとにテストを書くのはなかなか大変ですが、一番ちゃんと書かないといけないところでもあります。

そういった部分を、こういった手法で自動化できれば、いまと変わらないコストで、いまより自信をもってプロダクトを提供できると思いました。

総括

これ以外にも、CPUやVRAMの挙動をgoでエミュレートしてみたり、OCIのcontainer runtimeを実装してみたり、GCの仕組みを紹介してくれたりと、goをいろんな角度からいじっていてとてもよい刺激となりました。普段の業務でアプリケーションのコードを書いているだけではなかなか持ちづらい観点からGoを見ることができました。 持ち帰った知識はプロダクトにもしっかりと反映させて、その経験をコミュニティに還元できたらと思います。

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

Auroraの高速フェイルオーバーと無停止での切り替え

こんにちは、IT基盤部の川原﨑です。

私の所属する第四グループでは、超大規模ゲームタイトルおよびゲームプラットフォームのインフラを運用しております。 そこでのAuroraの高速フェイルオーバーの仕組みと、実際に無停止で切り替えを行った手順について紹介させていただきます。

はじめに

第四グループでは、コストコントロールの一環でInstance数の増減・Instance Typeの変更を頻繁に実施しています。
例えば、

  • イベントなどでリクエスト増加が見込まれるときにInstance数を増やす、またはInstance Typeを1つ上のものに変更する
  • リクエストが減少傾向にあれば、Instance数を減らす、またはInstance Typeを1つ下のものに変更する

などです。
これはWebサーバだけにとどまらず、DBサーバについても同様です。

EC2上でMySQLを運用している環境では、フェイルオーバーの仕組みとしてMHA for MySQLを使用しております。
MHA for MySQLでは数秒でフェイルオーバーが完了するため、ピークタイムを避けた時間帯であればエラー率も無視できるレベルです。 しかし、Aurora導入後はドキュメントに記載されている通り、フェイルオーバーに1分ほど要してしまうことが見込まれるため、フェイルオーバーの品質が大幅に下がってしまう懸念があります。

ダウンタイムの検証

まずは実際にどれぐらいのダウンタイムが発生するのかを確認しました。

検証環境

db.r4.large Multi-AZの3台構成
Auroraバージョン 5.6.10a

事前準備として検証で使用するテーブルを作成しておきます。

 CERATE DATABASE aurora_test;
 CREATE TABLE test (
     col int(10) DEFAULT NULL
 ) ENGINE=InnoDB;
 INSERT INTO test (col) VALUES (unix_timestamp());
確認コマンド
 while sleep 1
 do
     date && echo "update test set col=unix_timestamp();"  | mysql -uroot -p<password> -h<Cluster Endpoint> -N --connect-timeout=1 aurora_test
 done

 

 while sleep 1
 do
     date && echo "select col from test;"  | mysql -uroot -p<password> -h<Reader Endpoint> -N --connect-timeout=1 aurora_test
 done
検証結果

手動フェイルオーバーによるダウンタイム秒数

role1回目2回目3回目4回目5回目
writer28s11s17s14s24s
reader27s21s13s21s12s

1分までとはいかないまでも平均して20秒程度かかっています。

writer側では接続エラーが収まった後に以下のエラーがしばらく継続し、完全に切り替わるようです。

 ERROR 1290 (HY000) at line 1: The MySQL server is running with the --read-only option so it cannot execute this statement

reader側では接続できるときとできないときが上記秒数の間に発生するという状況が確認できました。 これはCluster Endpoint/Reader Endpointの更新までにタイムラグがあることが推測されます。

次にReaderであるInstanceを減らす際のダウンタイムについても計測してみましたが、Reader Endpointに対しての接続エラーは計測 できませんでした。 Instanceの削除には時間がかかり、Statusがdeletingの状態でもしばらく接続ができる状態であるため、接続ができなくなる前にDNSへの変更が完了するからかもしれません。

MHA for MySQLと比較するとフェイルオーバー時のダウンタイムは見劣りしてしまうため、本番サービスにAuroraを導入するにあたり ダウンタイムを短くすることが課題とわかりました。

高速フェイルオーバーの仕組み

Auroraの高速フェイルオーバーの仕組みとして

  • MariaDB Connector/J
  • ProxySQL
  • HAProxy

などが知られていますが、 私たちのチームではこれから紹介させていただく仕組みで高速フェイルオーバーを実現させています。

DeNAでは、ローカルのDNSとしてMyDNSを使用したDNSラウンドロビンの仕組みがあります。 この仕組みでは応答しないサーバを検知してMyDNSのレコードを消して自動でサービスアウトする、アプリケーションはMySQLを直接参照することでDNSラウンドロビンのデメリットである近いIPアドレスに集中しないよう分散させています(書籍『Mobageを支える技術 』参照)。

AuroraもEC2インスタンスと同様にMyDNSに登録しています。 それにより以下のメリットがあります。

  • AuroraのEndpointを使用しないのでDNSへの更新に関するタイムラグがない
  • アプリケーション側は既存の仕組みのままでいい
  • Instance Typeの変更・Instanceの再起動時にはMyDNSからレコードを削除すればよい

ただ、既存の検知の仕組みではサービスアウトさせるということしかできないため、Aurora用に別途検知の仕組みが動いております。

check-aurora.png

  • failoverが実行された際にinnodbreadonlyが0のInstanceでwriterのレコードをREPLACEする
  • readerが応答しない際にweightを0にする
  • すべてのreaderが応答しない際にreaderのレコードにあるwriterのweightを100にする

以下は、failover実行時の時系列での状態です。
aurora-test-w が書き込み用、aurora-test-r が読み込み用のMyDNSに登録されているEndpoint名です。

通常時

endpointinstanceinnodb_read_onlyweight
aurora-test-waurora-test-instance-010100
aurora-test-raurora-test-instance-021100
aurora-test-raurora-test-instance-031100
aurora-test-raurora-test-instance-0100

failover時のWriter候補再起動時

nameinstanceinnodb_read_onlyweight
aurora-test-waurora-test-instance-010100
aurora-test-raurora-test-instance-021100
aurora-test-raurora-test-instance-0310
aurora-test-raurora-test-instance-0100

Writer切り替え後

nameinstanceinnodb_read_onlyweight
aurora-test-waurora-test-instance-030100
aurora-test-raurora-test-instance-021100
aurora-test-raurora-test-instance-0300
aurora-test-raurora-test-instance-0110

旧Writer復帰時

nameinstanceinnodb_read_onlyweight
aurora-test-waurora-test-instance-030100
aurora-test-raurora-test-instance-021100
aurora-test-raurora-test-instance-0300
aurora-test-raurora-test-instance-011100

以下、高速フェイルオーバー導入後のダウンタイムの計測結果です。

手動フェイルオーバーによるダウンタイム秒数

role1回目2回目3回目4回目5回目
writer5s7s4s6s7s
reader6s1s4s7s5s

MHA for MySQLまでとはいかないまでも、ダウンタイムはInstanceが再起動の時だけに限定されるため、かなり早くなりました。

無停止でのAuroraへ切り替え

MySQLからAuroraへ切り替えはメンテナンスを設けずに無停止で以下の手順で実施しました。

まずはMySQLのReplication SlaveとしてAuroraクラスタを構築します。 もし問題があった場合にMySQLに切り戻しができるよう、Auroraのbinlogを有効にしておきます。

migration.png

  1. ttlを1秒にする
  2. MyDNSのslaveの向き先をAuroraのreaderに向ける
  3. MySQL側で書き込み権限があるユーザをRenameし、書き込みを止める
  4. Aurora側に上記がReplicationされてしまっているのでAurora側でユーザ名を戻す
  5. MySQLとAurora間のReplicationを止める
  6. SHOW MASTER STATUSでMaster Positionを確認する
  7. MyDNSのmasterの向き先をAuroraのwriterに向ける
  8. ttlをもとに戻す
  9. 上記7で確認したMaster PositionをもとにMySQLをAuroraのReplication Slaveと設定する

MySQLに戻す場合は上記の手順をMySQLに置き換えて再度実行することになります(実際に切り戻すことはありませんでしたが)。 この状態でしばらく様子を見て、問題なければMySQLを撤去します。

上記の手順のうちエラーが発生するのは3~7の間だけです。実際の切り替え時は手順の1~8までをスクリプト化しており、failoverとほぼ同等レベルのダウンタイムで切り替えることができました。

最後に

以上、Auroraの高速フェイルオーバーの仕組みと無停止による切り替えについて紹介させていただきました。 Auroraに切り替えることで、深夜問わず発生するEC2インスタンスのダウンなどによるDBサーバの再構築という工数が削減できており、インフラエンジニアに優しい運用になりました。
MyDNSの利用による運用はDeNAに特化したことであまり参考にならないかもしれませんが、 Aurora導入の参考になれば幸いです。

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

メールを送信する話

こんにちは、IT基盤部の中村です。 主に社内システムのインフラを担当しています。 現在の業務内容とは少しずれてしまいますが、最近までメール系のインフラには深く携わっていたこともあり、今回はメールシステムについてお話します。

今どきSMTPなどレガシーな話かもしれませんね。しかしながら良くも悪くも枯れたSMTPはインターネット基盤の根底に位置する息の長い技術でもあります。 きっとみんなまだ使ってるはずなのに、あまりノウハウが出回っていないのが辛いと感じているそこの担当者の方、よろしければ少しの間お付き合いください。

サービスでのメールの利用用途

我々がサービスとしてメールを取り扱うとき、その主だった利用用途は下記の2つです。

  1. メールマガジンなどの情報発信
  2. 入会・ユーザ登録時などのユーザ存在確認

メールマガジンはユーザーに情報を新たに届けたり、あらたに弊社の別のサービスに触れて頂く機会を提供するために送信されています。 こちらは単位時間あたりの送信量も送信時間もコントロールが可能ですし、宛先不明メールなどの送信不能メールを予めクリーニングを実施した上で送信できます。

逆に入会系のメールは、とあるゲームやサービスがリリースした直後に爆発的に急増します。こちらは時間帯のコントロールができない上に、流量についてもある程度の予測をしたところでそれを上回ってくる事が多く、さらにユーザ登録時のメールアドレス間違いなどで一定数の宛先不明メールも発生します。

graph.png

これらのメールを確実に(できるだけ)早く先方に届けることがシステム上の命題となります。

特に「入会・ユーザ登録」は大事な顧客獲得のチャンスでもあり、インフラの問題でメールが届かないなんてことは可能な限り避けなければなりません。

今回は、世界に向けて発信したサービスの導入時に発生した、ユーザ登録のメールを相手に届けるにあたって検討・設定したことについてお話したいと思います。

クラウド化に向けて

閑話休題ですが、これらの仕組みをクラウドに持っていくにあたってはAWSのSESなどのマネージドサービスを検討しました。 残念ながら、既存のメール配信のマネージドサービスは、突発的に大量にメールを送信する可能性がある弊社の環境とは相性が良くありませんでした。 逆に、大量のメールを定期的に送信するような環境であれば積極的に利用すべきです。

我々の場合は、クラウド上に自前でメールサーバを構築し、運用するという選択をしました。

メールを送信するということ

メールを送信する。ということは当然受信する相手がいるわけです。 いくらこちらからメールを送り付けたところで、受信者側の対応如何でこちらからのメールは一方的に破棄されてしまいます。 受信者側の対策は世の中には公開されていません。どうすれば100%相手に到達するかといったノウハウは受信側からは提供されません。

受信側はおそらく送り手側が怪しいメールの送信者でないかという観点で受信したメールを受け入れるべきか判断しているはずです。 送信元としてはそれが正しく自分たちの送出したメールであり、さらに迷惑メールを送信するようなサーバではないことを証明し続けるほかありません。

送信ドメイン認証

自らの出自を明らかにするための方法として送信ドメイン認証という考え方があります。 細かい説明はもっと詳しいサイトがあるのでそちらに譲りますが、要するに送信者のアドレスが正規なものであることを証明する技術です。 SPF/DKIM/DMARCなどがあります。 設定の優先度はSPF>DMARC>DKIMの順でしょうか(DMARCはDKIMの設定を実施していなくても設定できます)。

サービス開始当初はSPFとDKIMのみ設定していましたが、一部のフリーメールでは、どちらも正しく設定されているのにスパム判定されてしまいました。 DMARCを投入することで問題なく受け入れてもらえるようになりました(DMARCの投入にはそれなりに面倒がありましたが、それはまたの機会に)。

レピュテーションへの対策

レピュテーションは送信元メールサーバのIPアドレスの「評判」です。行儀の悪いメールサーバの評判は悪くなり、逆に正しく振る舞うほどに評価は上昇します。 評価が悪くなっていく状況を我々はよくIPアドレスが「汚れる」と言っています。 IPアドレスが汚れれば汚れるほど、そこからやってくるメールは、受信側に受け取ってもらえない可能性が高まります。

評判を公表しているサイト

いくつかのベンダーがIPアドレスのレピュテーションを公開してくれています。これが全てではありませんが、我々は以下のようなサイトを参考にしています。 AWSでEIPをとったタイミングでこれらのサイトで検索してみると、近い過去にメールサーバとして使われていたかどうかなどがわかる場合もあります。

DNSBLの監視

最も端的にIPアドレスが汚れているか判断できるのはDNSBLだと思います。 いわゆるブラックリストです。これに登録されてしまうと、即座にブロックが始まるので、できれば迅速に対応したいところです。 どれだけ手厚くみていても、たった一通のバウンスメールで登録されてしまうこともあります。油断は禁物です。

複数のブラックリスト検索には一覧検索に優れたサイトを使います。現状を知るには良い方法です。

影響度が大きいと思われるブラックリストは個別に監視して、登録され次第リストからの消去などのアクションを起こすようにします。 他にもいくつか見ていますが、主に下記あたりは注視しておいたほうがよいです。

それでも問題は起きる

とまあこれだけ対策しても、大量にメールを送信すると問題は発生します。

メール送信が始まってものの10分ほどでとあるドメイン宛のメールがすべて遅延するようになりました。

おそらく単位時間あたりの流量や、それまでのメール送信元サーバのIPアドレスからのメール到達の実績との差異などがトリガーとなっているのだと思われます。 普段はほとんどメール送信がないメールサーバからいきなり大量にメールが送信されると、その挙動そのものが怪しげなものに見えるようです(先述の通り、こちらからするとこれはこれで正しい挙動なのですが)。 一定の期間後メールは受信してもらえるのですが、この遅延は入会へのモチベーションに対しては致命的です。

暖気

確証は有りませんでしたが、通常時のメール流量が殆どないメールサーバーからの送信が怪しいのであれば、最初から少しは流しておけばいいと考えました。 特に流量による制御を実施していると思われるフリーメールに対しては、だいたいサービスリリースの2週間くらい前からメールを定期的に送信しておくようにしました。 我々はメールサーバの暖気と呼んでます。 実際こちらを実施することにより、長期間のメールのブロックはかなり減りました。

IPアドレスは多めに用意

それでも受信側のメールサーバの挙動は分からないことが多いです(特に海外のドメイン)。 メールログからなにか規則性を探ろうとしましたがほとんどが徒労に終わりました。

最後は力技ですが、仕方がありません。

メールキューの監視を行いつつ数十個のIPアドレスを用意して問題があれば利用を停止するようにしました。潤沢なグローバルIPアドレスをあてにするこの手法はパブリッククラウドならではの手法でありました。

まとめ

大量にメールを送りたいなら

  • 送信ドメイン認証は手を抜かず確実に設定しましょう
  • レピュテーションには常に気を配りましょう
  • 暖気も時には有効
  • それでもだめなら力技もあり

最後に

いかがでしたでしょう。 実際、大量のメール送信というユースケースはあまりないかもしれません。 当時は調べても有用な情報が出てこず頭を抱えたものでした。 詳細を省略している部分も多いですが、おおよそ我々がとった対応については記載しました。同じようなことで悩んでいるどなたかの参考になれば幸いです。

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

アプリログを BigQuery に入れるまで

こんにちは、IT基盤部の貴田です。

DeNA では分析環境の BigQuery 移行を進めています。
先の記事では、移行の背景や、 MySQL のデータを Embulk を用いて BigQuery に入れる工程を紹介しました。
今回は、ウェブアプリケーションが出力したログを定常的に BigQuery に入れて活用するフローについて書きます。

文中の料金については、すべて 2019年10月時点の 東京リージョンのものです。

大まかな流れ

applog2BQ.png

  1. アプリがログを吐く
  2. サーバー内の daemon がログを処理し、適切な Cloud Storage Bucket にアップロードする
  3. Cloud Storage から BigQuery に import する

というシンプルな構成ですが、設計するにあたりいくつか考慮した点があるので、順に説明します。 概略図中に、 1 ~ 4 の数字を振っている部分です。

(1) どうして直接 BigQuery にデータを送信せず、 Cloud Storage に格納するのか?

web server から bq load や ストリーミング挿入 を用いて直接 BigQuery にデータを集めることも検討しましたが、コストと安定性を考え、まずは Cloud Storage にデータを格納し、必要なものを必要なタイミングでだけ BigQuery にエクスポートする構成としました。

コスト

1GB・1ヶ月あたりの料金はこのようになっており、 めったに使わないデータは Coldline Storage に置くことでストレージコストを下げられます。

サービス料金
Cloud Storage (Standard Storage)$0.023
Cloud Storage (Coldline Storage)$0.006
BigQuery$0.023

また、 BigQuery のストレージ料金は非圧縮の状態のデータサイズが課金対象となります。
Cloud Storage 上に gzip で圧縮した状態で保持することで、ストレージ料金を大きく下げることができます。

Cloud Storage から BigQuery にエクスポートする際に料金が少しかかりますが、それについては後述します。

安定性

BigQuery のテーブルは型を持っているため、何かしらのバグでログに不正な文字列が入ると、 BigQuery へのインサートは失敗します。その場合にログを web server 内部に溜めてしまうと web server のディスク領域が逼迫したり、本番稼働しているサーバーに入っての復旧作業が必要となったりするデメリットがあります。

まずはどんなデータでも受け入れてくれる Cloud Storage にデータを入れてしまい、その後起きうる問題と web server を切り離す意味でも、まずは Cloud Storage にデータを入れる構成が優位です。

(2) gcs daemon の役割

分析用のアプリログはもともと hdfs に格納することを前提に出力していたため、各行が下記フォーマットになっています。

 ${hdfs上のpath情報}\t${その他メタ情報...}\t${データ本体(JSON または LTSV)}

また、 DeNA の web app は多くの場合、分析用のアプリログを単一のファイルに書き出し続けています。

そのため、

  • hdfs上のpath情報 を Cloud Storage Bucket 名・path への変換を行う
  • ログファイルを一定時間ごと・bucket/pathごとに分割する
  • BigQuery に直接 export できるファイル形式(json.gz) に変換する

という処理を行っています。

(3) BigQuery へのデータ取り込み vs 外部データソースの活用

Cloud Storage に格納されたデータを活用する場合、2通りの方法があります。

  • データを BigQuery にエクスポートする
  • BigQuery の 外部データソース機能 を用いて Cloud Storage 上のデータを直接活用する

DeNAでは前者の BigQuery にエクスポートする方法を採用しました。

ドキュメントに記載があるとおり、後者の方法を用いると、 BigQuery の機能が一部制限されてしまいます。

なかでも、

  • テーブルのパーティショニングがサポートされない
  • クエリの実行結果がキャッシュされない

という制限は致命的で、大規模なデータを扱った場合にクエリ料金が跳ね上がる恐れがあります。

一方、前者の方法でエクスポートする場合、それ自体にほとんど料金が発生しません。
Cloud Storage (Standard Storage) と BigQuery が同リージョンにある場合、エクスポートで発生する料金は下記のもののみです。

  • Cloud Storage の get api 料金 10,000ファイルあたり $0.004
  • BigQuery ストレージ料金 1ヶ月・1Gb あたり $0.023
    • 時間単位での課金なので、利用後すぐに消せば費用が非常に小さくなる

このとおり、 Cloud Storage -> BigQuery へのエクスポートは非常に安価に行うことができます。
エクスポートすれば BigQuery の機能をフルに活用できるため、大規模なデータ分析において外部データソースの機能を使うシーンはほぼ無いと思います。

(4) 型自動判定の夢...

Cloud Storage 上の JSON を BigQuery にエクスポートする際、すべてのカラムの型を明示的に指定しています。
利用者にあらかじめスプレッドシートにカラム名と型を記載してもらうことで実現しています。

BigQuery へのデータ読み込みでは、型の自動判定機能があり(CLI でいうところの --autodetect オプション)、当初はこちらの活用を考えていました。

実際、ほとんどのケースでは自動判定はうまく働きます。
しかし、極稀にエラーが起きてしまうケースがありました。
例えば、ほとんどの行は version: "3.0" と記載されており、実数値として判定されるが、新しく version: "3.0.1" がリリースされるとこれは実数に変換できないのでエラーになる、というケースです。

BigQuery には一部のカラムだけの型を指定してデータを取り込む機能がないため、利用者に全ての型をあらかじめ入力してもらう UX となってしまいました。

BigQuery は型を意識した分析用だと割り切る必要がありそうです。

まとめ

今回の設計を通して得られた知見をまとめます。

  • BigQuery にデータを直接入れるのではなく、 Cloud Storage をデータレイクとして活用することで、安価でかつ安定する
  • Web server 上で BigQuery に読み込ませられる形式に変換・圧縮して Cloud Storage に配置することで、後続の処理をシンプルにできる
  • BigQuery の外部データソース機能は使わず、 Cloud Storage から都度 export するほうがよい
  • BigQuery を使う以上、型を意識した設計にすべき。 型自動判定は万能でなく、アドホックな処理のみに利用する

最後に

hadoop を用いた分析基盤から BigQuery を用いた分析基盤に移行するにあたり、とくに迷った部分・試行錯誤の結果当初の方針を変更した点などを紹介させていただきました。
何かしらの参考になれば幸いです。

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る