stMind

about Arsenal, Arsene Wenger, Tech, Computer vision and Machine learning

A simple yet effective baseline for 3d human pose estimation

https://arxiv.org/pdf/1705.03098.pdf

画像から3次元の関節を推定する論文。ただし、入力は画像ではなく2次元の関節座標で、そこから3次元の関節を回帰する。

2次元から3次元へのマッピングをDNNとして学習する手法は、これまでにも提案されてきているが、それらに共通するのは、3次元座標を2次元(画像や関節座標)から直接推定することはそもそも困難という認識である。本論文では、Dropout、Batch NormalizationとReLU、Redisual Connectionを用いたシンプルなDNNにより、SOTAな手法に負けない精度で3次元座標の推定が可能であることを示している。

Network design and solution methodology

\displaystyle f^* = \min_f \frac{1}{N} \sum_{i=0}^{N} {\cal L} (f( {\bf x_i} ) -  {\bf y_i})

3次元の関節座標へ変換するfを定義し、変換後の関節座標と正解関節座標の差を最小にするf^{\ast}を求める。f^{\ast}は、DNNでモデル化し、次の図のような構成を提案している。

f:id:satojkovic:20190911081741p:plain

図には書かれてないが、二つのlinear layerが入力直後と出力直前に存在し、また図のブロックは二層存在するので、linear layerは合計で6となる。学習パラメータ数は4Mから5M。

Residual connections

Residual connectionsを設けることで、エラーが10%も低下した。

Batch normalizationとdropout

Linear-ReLuとResidual connectionsを用いたシンプルなネットワークの場合、2次元座標のGTで学習すれば良い精度を得られるが、 detectorの2次元座標で学習した場合や、2次元座標のGT で学習してdetectorの2次元座標で推論した場合には精度低下が見られた。Batch normとdropoutを併用することで、これらのケースでの精度を改善することが出来た。

Max-norm constraint

Batch normと組み合わせて、各層の重みのノルムの上限を1.0に正規化することで、汎化性能の向上が見られた。

Data preprocessing

  • 平均を引いて、標準偏差で割る一般的な正規化を入力データと出力データに適用。3次元座標は、hip jointを中心とした相対的な座標(カメラ座標系)。
  • 任意の座標系での3次元座標を2次元座標から求めることは現実的ではないので、カメラを中心としたカメラ座標系が自然な選択となる。3次元座標のGTに対応する2次元座標は、カメラの内部パラメータを用いた変換により求めることが可能。
  • 2次元座標は、Stacked Hourglass(SH)を用いて取得。Human3.6Mデータセットでは人物矩形が含まれているので、矩形の中心に対して440x440の領域をクロップ、256x256にリサイズしてSHに入力する。
  • 既存手法ではCPMを用いていて、2次元座標のGTとの誤差はSHの平均15pixelよりも小さい(平均10pixel)。しかし、MPIIデータセットではわずかに精度が良いこと、10倍の処理速度、の2点の理由でSHを採用している。
  • Human3.6Mデータセットで、SHのFine tuningも行った(SH detections FT)。
  • SHは基本的にはデフォルトの設定だが、メモリの制限でbatch sizeを6から3に変更。学習率は 2.5 x 10^{-4}で、40000iter実行。

Training details

学習時のハイパーパラメータは表のようになっている。

epochs 200
optimizer Adam
learning rate 0.001 (exponential decay)
Initialization Kaiming initialization

Evaluation

評価に使ったデータセットは、Human 3.6MとMPII。Human3.6Mはその名の通り、3.6millionの画像があり、2d / 3d jointsやカメラパラメータのground truth を含む大規模なデータセット。一方のMPIIはもう少し小規模。

Results

  • GTを用いた評価
    • GTの2次元座標で学習、テストした場合、既存手法より43%の改善(37.10mmの誤差)。
    • GTにガウシアンノイズを付加してテストした場合、当然ながら性能は低下していく(それでも比較手法よりもエラーは小さい)。
    • SHを用いてテストした場合でも、既存手法よりも20%程度改善(60.52mmの誤差)
  • detectorの2次元座標を用いた評価
    • SHで求めた2次元座標を用いて学習、テストした場合、既存手法のSOTAな結果よりも4.4mmの改善。SHをHuman3.6MでFTした場合は、9.0mmの改善。
    • 後処理(詳細は読み取れず)を加えた場合、HumanEvaで評価した場合も、既存手法よりもわずかに悪くなっている動作もあるが、総じて比較手法よりも改善されている
  • ネットワーク構成の評価
    • Data preprocessingを行わない場合が性能低下が一番大きく、その次に性能低下が大きいのはBatch normをなくした場合。各構成を含む場合が一番性能は高い。
    • ブロック数を4、8と増やしても性能向上はあまりなく、ブロック数2で頭打ちしている。

最後に

Linear-ReLu + Batch norm + Dropout + Residual connectionのシンプルな基本構成で、既存手法を超える性能を達成しているのは驚き。論文タイトルにもあるように、これらからの研究のベースラインになる(改善が色々とできそう)手法だと思われるし、detectorの2次元座標があれば手軽に3次元座標が得られるので、応用もしやすそうである。

Tensorflow Object Detection APIを使ってロゴ検出

以前、ナンバープレート認識モデルを参考にして、ロゴ認識CNNを作りました。

stmind.hatenablog.com

前回のモデルは独自モデルだったのと、物体候補領域はSelective Searchで実行していたため計算時間が大きかったので、one stageで標準的なモデルを使用するように変更してみました。

Tensorflow Object Detection APIにあるSSDモデルで、Flickr Logos 27 datasetを学習してみたところ、割と簡単にロゴ検出ができました。

f:id:satojkovic:20190830120140p:plain

f:id:satojkovic:20190830134607p:plain

f:id:satojkovic:20190830135612p:plain

検出した結果を見ると、誤検出はない一方で、未検出が結構多い印象です。領域サイズが小さかったり、向きや傾きが大きい場合に未検出が増えている様子なので、Data augmentationを見直すなどは必要になる感じですね。

github.com

GoogLeNet(Inception V1) and Inception V3 memo

CNNの中でもよく使われるアーキテクチャの一つであるGoogLeNet。GoogLeNetの層を構成するのがInceptionで、今までにv1からv4までの改良が行われていて、またresidual blockを導入したinception-resnetも提案されています。

Mediumの解説記事を参考に、基本となるGoogLeNet(V1)とKerasなどのフレームワークでもよく使われるV3を簡単にメモ。

A Simple Guide to the Versions of the Inception Network

Review: GoogLeNet (Inception v1)— Winner of ILSVRC 2014 (Image Classification)

Inceptionのバージョンについて

Inception V4の論文では、以下のように定義されているので、ここでもそれを参照します。

  • GoogLeNet(Inception V1)
    • [CVPR2015] Going Deeper with Convolutions
  • Inception V2
    • [ICML2015] Batch normalization: Accelerating deep network training by reducing internal covariate shift
    • GoogLeNetに対してBNを導入したもの
  • Inception V3

Inception V1

課題

  • 注目する対象というのは、画像中で任意の場所に様々なサイズで存在
  • 認識するためにフィルタサイズが重要になるが、適切に設定するのは難しい
  • Deepなネットワークは過学習しやすく、計算量も大きい

V1のアイデア

  • どれか一つのサイズを選ぶのではなく、同じ階層で色々なサイズのフィルタを同時に使う!
    • 1x1、3x3、5x5の畳み込みフィルタと3x3のmax pooling
    • 最後にChannle方向にmapを重ねる(concatenate)
  • ただし、このままだと計算量が大きいので、1x1でmap数を削減してから、3x3と5x5のフィルタを適用する
    • 例えば、Inception 3a層では、28 x 28 x 192の入力に対して、28 x 28 x 256の出力を生成する。その内訳は、
      • 1x1 conv→64個のfeature mapを出力
      • 1x1 conv + 3x3 conv→96個のfeature mapにしてから128個のfeature mapを出力
      • 1x1 conv + 5x5 conv→16個のfeature mapにしてから32個のfeature mapを出力
      • 3x3 max pool→32個のfeature mapを出力
    • max poolingの場合は、pooling後に1x1 convを適用

f:id:satojkovic:20181014124527p:plain

  • Inception V1を9ブロック組み合わせたのがGoogLeNetで22層のアーキテクチャ
    • Max Pooling + Convだと27層
  • Deepなネットワークなので、勾配消失の問題が起こりやすい。そのため、中間層(4aと4d)に補助的な識別器を追加して、ロスを計算するようにする
# The total loss used by the inception net during training.
total_loss = real_loss + 0.3 * aux_loss_1 + 0.3 * aux_loss_2

Inception V3

課題

  • モデルサイズを大きくして精度向上をしつつ、パラメータ数削減による計算効率化を行う
    • パラメータ数削減は、Mobile用途や超大規模データを扱うシナリオでは重要

V3のアイデア

  • Factorization
    • 5x5 convを2層の3x3 convに分解(factorize)=> Figure 5のInception Block(Inception A)
      • 5x5に対し、3x3 + 3x3の2層で約28%のパラメータ数削減
    • n x nのconv層を、1 x nのconv層とn x 1のconv層に分解 => Figure 6のInception Block(Inception B)
      • 3x3の場合は、1x3 convと3x1 convに分解することで、33%程度の削減
    • n x nのconv層を、1 x nのconv層とn x 1のconv層の並列に分解 => Figure 7のInception Block(Inception C)
  • Auxiliary Classifiers
    • 補助的な識別器は、学習初期にはロスが収束することにあまり寄与せず、学習後期になってようやく精度向上に寄与することがわかった
      • 低層部を取り除いても最終精度はあまり変わらない
    • 補助的な識別器は4ブロックのInception Bのあとに1つだけ
      • Batch Normalizationを入れることで性能向上
  • Efficient Grid Size Reduction
    • d x d x kから(d/2) * (d/2) * 2kの特徴マップを得ようとする場合、2つのやり方がある
      • 1 x 1 x 2kのconvolutionをしてから、poolingする→この場合だと、(d x d x k) * (1 x 1 x 2k) = 2 d2 k2が支配的なoperation
      • 逆にpoolingをしてから、1 x 1 x 2kのconvolution→この場合、(d/2 x d/2 x k) * (1 x 1 x 2k) = 2 (d/2)2 k2が支配的なoperationで1/4の計算コスト
    • 先にpoolingをした場合、計算コストは小さくなるが、Representational bottleneckとなって、表現力が低下してしまう
      • d2 kに対して (d/2)2 k
    • strideが2のconvolutionとpoolingを並列に行い、出力をchannel方向にconcatする

42層のモデルで、GoogLeNetに対して2.5倍程度の計算コストで、Top1 errorを5.6%ほど改善している。

f:id:satojkovic:20181014162735p:plain
Inception V3のネットワーク構成

f:id:satojkovic:20190804161830p:plain
Inception V3のネットワーク構成図(https://ai.googleblog.com/2016/08/improving-inception-and-image.html

intが戻り値の関数でエラーを返すにはどうすればいいか

stackoverflow.com

例えば、ファイルに含まれる数の合計を計算する場合。

int DoSum(const std::string& file);

ファイルに含まれるのが正の値だけであれば、負の値でエラーを示すことができるが、正も負も含まれる場合には適用できない。

3つのやり方

1. 戻り値はエラーにして、合計は引数で指定された領域に格納
int DoSum(const std::string &file, int &sum)
{
    /* return value of zero indicates a sum has been computed
          other values indicate an error status
    */
}
2. エラーと合計を含むデータ構造を定義して戻り値とする
struct ReturnData
{
      int sum;
      int error_indicator;
};

struct ReturnData DoSum(const std::string &file)
{
}
3. 戻り値は合計で、エラーは例外で扱う
int DoSum(const std::string &file)
{
     /*  do calculations */
     if (error_has_occurred)
         throw some_appropriate_exception();
     else
         return calculated_sum;
}

1と2の場合、エラーが致命的でなければ呼び出し側で何もする必要がない一方で、エラー処理をしなくても動くので変な結果で処理が進んでしまうことがある。 3の場合、例外をcatchしなくても処理が異常終了するので変な結果が処理が進むことはないのに対し、この関数を使う全ての呼び出し側でcatchして適切に扱うようにしないといけない。

Googleのコード規模でということなので、自分たちのサイズで考える必要がありますが、既存のコードに対して、例外を導入するコストが高いので、 Google C++ Style Guideでは例外は使わないとしています。 ただ、自分たちの問題で考えてみても、関係する全てのコードで新しく例外処理を実装するのはやはり大変なので、1か2を使うことが多い印象です。

今こそ読みたいグーグルマップ誕生の舞台裏

NEVER LOST AGAIN グーグルマップ誕生 (世界を変えた地図)

NEVER LOST AGAIN グーグルマップ誕生 (世界を変えた地図)

中の人による、キーホール起業からグーグルによる買収、グーグルマップとグーグルアースの成功に向かう物語が書かれた内容は、とても興味深いものでした。個人的なハイライトは、ストリートビューがグーグル内部で始まった当時の描写と、グーグルマップを他社の地図データから自社データへと切り替えることになったGround Truthプロジェクトの章でした。

物理世界を検索可能にするストリートビュー

後にストリートビューとなるプロジェクトを担当していたのは、2004年に入社したLuc Vincent氏。入社した時は、グーグルブックスのチームに所属して世界の書籍をスキャンするタスクを担っていたが、ラリー・ペイジとのミーティングで構想を聞き、スタンフォード大学のMarc Levoy教授と既に始めていたストリートビューをリードする役割を任されたらしい。

最初の検証では、ラリー・ペイジセルゲイ・ブリンマリッサ・メイヤーとドライブしながら助手席でビデオカメラを回して撮った映像!を使ったようだが、Vincent氏はスタンフォード出身のエンジニアとインターン生とともに、撮影車両プロトタイプと360度画像をつなぎ合わせるソフトウェアツールを作り、撮影を行っていた。

何のロゴマークも書かれていない深緑色のシボレーのバンの上にはコンピュータ、カメラ、レーザーセンサーの複合体が取り付けてあり、時速16㎞以下のスピードで走行した。それ以上の速さだと撮影した画像がブレ、使い物にならないのだ。バンから何回か煙が上がったため、電力の安定供給のために今度はホンダのガソリン発電機も屋根に取り付けた。

このプロトタイプでは数々の問題が起こっていたようだが。

この撮影車両の性能は、驚くほど当てにならなかった。毎日、チームがその日の撮影作業を計画し、すべての機器を慎重につないで走行の準備を整える。そうしてインターン生がバンを走らせるのだが、毎日、1時間ほどでコンピュータがクラッシュしたり、他の不具合が起きたりして作業が中断した。少し走ってはマウンテンビューに連絡を入れ、母船に戻って何がうまくいかなかったかを調査するということの繰り返しだった。

それでも、2005年の夏頃には、マウンテンビューとパロアルトの撮影データセットを構築し、グーグルマップと統合したデモを完成させ、正式なプロジェクトに昇格。その後は、2007年にストリートビューアメリカ5都市のみ対応でローンチされ、自動運転のチームも加わった2007年の終わりにはアメリカ中の道路600万マイルのうち100万マイルを走破するまでになった。

Ground Truthプロジェクト

グーグルマップとグーグルアースが大ヒットするのに伴い、地図データのライセンス料の問題が無視できないものになっていた。

グーグルの地図プロダクトの爆発的な人気に伴い、地図データのライセンス料は急騰していた。その中でも最も高額だったのは交通網のデータベースだ。この業界は2社が市場を占領している。オランダに拠点を置くテレ・アトラスとアメリカのナブテックだ。

問題はライセンス料が高いということだけではなく、データをどう使うかまで制限されていたことだという。

彼らは毎年グーグルが支払うデータの利用料金を決定し、またグーグルがどのようにデータを使っていいかを指示していた。ナブテックとテレ・アトラスは、豊富な利益が得られるナビゲーション端末市場に影響がでないようにしたいと考えていた。彼らにとってパーソナルナビゲーション端末を何十億台と販売しているガーミン、トムトム、マゼランとのビジネスの方が重要だった。

当然、とはいえある意味無謀な、自分たちの交通網地図を作る方向に舵を切ることになる。それが、ストリートビューの画像から画像認識技術で交通データを抽出し、全世界の交通網の情報を書き出すプロジェクト「Ground Truth」。

このGround Truthのために内製したのが、地図作成ソフトウェアのアトラスで、2013年のGoogle I/Oスクリーンショットと合わせて紹介されている(下記リンク参照)。アトラスでは、空中写真、衛星写真ストリートビューの画像と、画像認識で自動抽出した道路標識や住所などの道路に付随する情報など、グーグルが持つ特定地域に関する全ての情報を1つの画面で見ることができる。さらに、例えば道路の両側で同じ進行方向の車が撮影されている画像があれば、アトラスがその道路を一方通行であると推測する機能も持っている。ただし、最後は、人間のオペレータがアトラスの解析したデータを確認し、修正して、正確な情報として公開する承認をする。

Google I/O 2013 - Project Ground Truth: Accurate Maps Via Algorithms and Elbow Grease - YouTube

2009年末には、利用料もなく、使用制限もない、グーグル製地図データへの切り替えが行われた。

感想

ユーザを第一に考え、世界の地理情報を整理してアクセス可能にするため、必要なリソースにちゃんと投資し、何十億というユーザが使う現在のグーグルマップを実現してきた裏側は、とても面白かった!

自社製地図データへの切り替えによって、使用用途制限がなくなったことにより、モバイル版グーグルマップで音声道案内が実現されたということを知ると、最近のグーグルマップの地図データ切り替えも、次の新しいユーザ体験の布石かもしれないと思うと、楽しみでなりません。

スーパーカーについて知っていること

最近、YoutubeでライブのPV見て、そこについてるコメントを見てなんか書いてみたくなった。

2005年に解散したスーパーカーは、自分の青春時代そのものだった気がする。当時はまだネットが一般的に使われる前だったし、スマホなんてものは当然なかったから、とにかくインタビューが掲載されている雑誌があれば購入し、スペシャで特集が放送されればビデオに録画して、頑張って東京までライブ見に行ったりしていた。

解散ライブも幸運にもチケット取れて、もしかしたらファーストアルバムの曲やらずに解散あるかも?と心配して行ったけど、creamsodaとかLuckyとか見れて最高に感慨深かった。まあ、MCゼロで歌声以外に声を発することなく終わって、しかもアンコールはなしだったのは、やっぱそうかーと思ったな。

スーパーカーは色々と変わったバンドだと思うんだけど、変わったエピソードといえば、このようなものを雑誌とかで読んだような気がする。でも、本当なのかどうかはわからないけど。

  • ジュンジくんがミキちゃんのバンドメンバー募集に反応したのは、メンバー募集の紙にクマの絵が書いてあったから
  • creamsodaのPVでメンバーが乗っているアメ車は所ジョージさん所有のもの
  • Luckyには当初サビがなかったが、シングルカットされることが決まって「ラッキーなのにね」のところが追加された
  • DRIVEにドラムがないのは、録音されたのがコーダイの加入前だったため
  • ナカコーの声が小さすぎてドラムの音にかき消されてしまうため、初期のライブの配置では真ん中にジュンジくん、両サイドにミキちゃんとナカコーのボーカルだった
  • ナカコーの歌声が無機質な感じなのは、ジュンジくんがナカコーに気持ちを込めて歌わないようにと言っていたため

そういえば、解散した後だったか、スーパーカーのラジオ「オールOK」が一夜限りで復活して、そのときに質問募集してたので、ネットで質問送ったらなんと採用されたという!それで、どう使っていいか分からない鉛筆みたいなのが送られてきたんだよね。でも、当時は会社の寮に住んでて、ラジオが聞けない環境で、どういう風に答えてくれたのか分かってないんだよなぁ... どこかに音源ないだろうかなぁ。

f:id:satojkovic:20181014210823j:plain:w300

Encountered errors while installing torch

ld: library not found for -lSystem
collect2: error: ld returned 1 exit status

Error: Build error: Failed compiling module lfs.so
ld: library not found for -lreadline
collect2: error: ld returned 1 exit status

Error: Build error: Failed compiling module readline.so
/Users/satojkovic/torch/extra/cutorch/lib/THC/THCHalf.cu(40): error: class "__half" has no member "x"

/Users/satojkovic/torch/extra/cutorch/lib/THC/THCHalf.cu(41): error: class "__half" has no member "x"

/Users/satojkovic/torch/extra/cutorch/lib/THC/THCHalf.cu(42): error: class "__half" has no member "x"

/Users/satojkovic/torch/extra/cutorch/lib/THC/THCHalf.cu(80): error: class "__half" has no member "x"

/Users/satojkovic/torch/extra/cutorch/lib/THC/THCHalf.cu(88): error: class "__half" has no member "x"

/Users/satojkovic/torch/extra/cutorch/lib/THC/THCHalf.cu(92): error: class "__half" has no member "x"

/Users/satojkovic/torch/extra/cutorch/lib/THC/THCHalf.cu(122): error: class "__half" has no member "x"

make[1]: *** [lib/THC/CMakeFiles/THC.dir/all] Error 2
make: *** [all] Error 2

Error: Build error: Failed building.