iMind Developers Blog

iMind開発者ブログ

FaceNetの論文を読んだメモ

概要

顔認証の勉強中に、FaceNet: A Unified Embedding for Face Recognition and Clusteringを読む。そのメモ書き。

下記がその論文。

下記がその実装。

Abstract

まずはFaceNetとは何かについて。訳はかなり意訳。

that directly learns a mapping from face images to a compact Euclidean space where distances directly correspond to a measure of face similarity.


(こいつは顔の画像をコンパクトなユークリッド距離に変換するよ。生成した距離空間で距離を取ると顔の類似度と一致するよ)


we achieve state-of-the-art face recognition performance using only 128-bytes per face.


(1つの顔につき128バイトで十分な精度が出せるようになったよ)

ということで顔写真を128バイトのユークリッド距離に変換して、距離が近ければ同一人物という判定ができる代物らしい。

人の顔が128バイトの距離で表現できてしまうというのは、詳しくない人間としては浮世離れした世界の話のように見える。word2vecの話が出た時もそんな感じがしたけど。

Introduction

提供されるシステムの内容。

we present a unified system for face verification (is this the same person), recognition (who is thisperson) and clustering (find common people among thesefaces)


(同じ顔かどうか判定するface verificationシステム、この顔が誰か判定するrecognitionシステム、それから顔をクラスタリングするシステムを提案するよ)


A distance of 0.0 means the faces are identical, 4.0 corresponds to the opposite spectrum, two different identities. You can see that a threshold of 1.1 would classify every pair correctly.


(距離が0.0なら等しい、4.0だと正反対。1.1を閾値にするといい感じ)


Our triplets consist of two matching face thumbnails and a non-matching face thumbnail and the loss aims to separate the positive pair from the negative by a distance margin.


(画像A、画像Aと同じ人の画像、画像Aと違う人の画像の3つ組を作って距離を学習させるよ)

結果が距離空間になるわけなので、認証、判定、クラスタリングといった機能ができることは想像しやすい。

内容的に似ている芸能人を検索することもできると思われる。

判定の閾値は1.1になるらしい。

triplet loss

前述に出てきたtriplets(3つ組)という言葉が精度を上げるミソのところで、Triplet lossという名称で各所で取り上げられている。Triplet lossの詳細はPaperの3.1で詳しく説明されている。

が、説明読んでも理解が怪しいのでコードを読む。コメント空行除くとたった7行。

def triplet_loss(anchor, positive, negative, alpha):
    """Calculate the triplet loss according to the FaceNet paper
    
    Args:
      anchor: the embeddings for the anchor images.
      positive: the embeddings for the positive images.
      negative: the embeddings for the negative images.
  
    Returns:
      the triplet loss according to the FaceNet paper as a float tensor.
    """
    with tf.variable_scope('triplet_loss'):
        pos_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, positive)), 1)
        neg_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, negative)), 1)
        
        basic_loss = tf.add(tf.subtract(pos_dist,neg_dist), alpha)
        loss = tf.reduce_mean(tf.maximum(basic_loss, 0.0), 0)

    return loss

https://github.com/davidsandberg/facenet/blob/master/src/facenet.py#L44

基準となるanchorという画像に対して、positiveな画像とnegativeな画像、あとalphaが渡されている。alphaはデフォルトだと0.2になっていた。

https://github.com/davidsandberg/facenet/blob/master/src/train_tripletloss.py#L446

tripletの選び方

3人組作れの時に良い組合せを選ぶことが重要らしい。全パターンを取るのは計算量が膨大だし、ランダムに適当に取るだけでは効率が悪い。

hard-positive(positiveで距離が最大になるヤツ)とhard-negative(negativeで距離が最小になるヤツ)で学習させたいけど、計算量が膨大になるのでやりづらい。

そこで実装ではpositiveについては全パターンの組合せを学習データとし、negativeについては下記のようにalpha以内の距離から選択している。

# 両者の距離を取る
neg_dists_sqr = np.sum(np.square(embeddings[a_idx] - embeddings), 1)

# 距離がalphaより近いものを取る
all_neg = np.where(neg_dists_sqr-pos_dist_sqr<alpha)[0] # VGG Face selecction

We call these negative exemplars semi-hard, as they are further away from the anchor than the positive exemplar, but still hard because the squared distance is close to the anchor-positive distance.


我々はこのネガティブの標本をセミハードと呼んでる。ネガティブはポジティブよりはアンカーから遠くなるけど、それほど大きく距離が変わるわけではないので判別が難しい問題になる。

CNN

学習についてはDeep CNNを利用している。

具体的にはこういう流れらしい。

layer size-in size-out kernel param FLPS
conv1 220×220×3 110×110×64 7×7×3,2 9K 115M
pool1 110×110×64 55×55×64 3×3×64,2 0
rnorm1 55×55×64 55×55×64 0
conv2a 55×55×64 55×55×64 1×1×64,1 4K 13M
conv2 55×55×64 55×55×192 3×3×64,1 111K 335M
rnorm2 55×55×192 55×55×192 0
pool2 55×55×192 28×28×192 3×3×192,2 0
conv3a 28×28×192 28×28×192 1×1×192,1 37K 29M
conv3 28×28×192 28×28×384 3×3×192,1 664K 521M
pool3 28×28×384 14×14×384 3×3×384,2 0
conv4a 14×14×384 14×14×384 1×1×384,1 148K 29M
conv4 14×14×384 14×14×256 3×3×384,1 885K 173M
conv5a 14×14×256 14×14×256 1×1×256,1 66K 13M
conv5 14×14×256 14×14×256 3×3×256,1 590K 116M
conv6a 14×14×256 14×14×256 1×1×256,1 66K 13M
conv6 14×14×256 14×14×256 3×3×256,1 590K 116M
pool4 14×14×256 7×7×256 3×3×256,2 0
concat 7×7×256 7×7×256 0
fc1 7×7×256 1×32×128 maxout p=2 103M 103M
fc2 1×32×128 1×32×128 maxout p=2 34M 34M
fc7128 1×32×128 1×1×128 524K 0.5M
L2 1×1×128 1×1×128 0
total 140M 1.6B

深い。見るからに重そう。こんなんうちの貧弱なサーバーで動かせるのだろうか。

Experiments

If not mentioned otherwisewe use between 100M-200M training face thumbnails consisting of about 8M different identities


(特に言及がなければ我々は800万人の個人の顔の1億〜2億のサムネイル画像を利用しているよ)

Googleの論文って個人じゃ手が出せない単位をしれっと使うよね。

A face detector is run on each image and a tight bounding box around each face is generated.


(すべての画像は顔認識で顔のところをBOXで抜いてあるよ)


Input sizes range from 96x96 pixels to 224x224 pixels in our experiments.


(経験的に顔のピクセルは96x96〜224x224を使ってるよ)

ここまでの内容でFaceNetの実装がどうなっているかはなんとなく想像できる情報は集まった。

Effect of CNN Model

JPEGの圧縮率による精度の変化について。

jpeg q val-rate
10 67.3%
20 81.4%
30 83.9%
50 85.5%
70 86.1%
90 86.5%

10%とか無茶をするとかなりスコアが下がるけど普通に見られるレベルの圧縮をする分には影響は大きくはなさそう。

ピクセル数について。

pixels val-rate
1,600 37.8%
6,400 79.5%
14,400 84.5%
25,600 85.7%
65,536 86.4%

96x96=9216くらいはあると良さそう。

続いてトレーニングに使うイメージ数。

training images VAL
2,600,000 76.3%
26,000,000 85.1%
52,000,000 85.1%
260,000,000 86.2%

100万ではもの足りない。自前で何かしらデータを集めてモデルを生成しようと思ったら、ある程度自動でデータを集められる仕組みを用意しないと無理そうだし、学習にかかるコンピュータリソースについても確保する必要がある。

手持ちのリソースでこれに対してどの程度アプローチできるか、要検討。

改定履歴

Author: Masato Watanabe, Date: 2019-05-01 記事投稿