facenet-tensorflow人臉識別

facenet-tensorflow人臉識別

專案地址:https://github.com/davidsandberg/facenet

  • facenet基於MTCNN的人臉檢測和Inception-Resnet-v1的人臉識別網路
  • softmax,center loss 訓練結果比triplet loss訓練結果好太多,自己訓練達到99.0% -0.006。利用msceleb訓練集。

一、MTCNN人臉檢測

待補充

二、Inception-resnet-v1人臉識別模組

2.1如何自己重新訓練facenet模型

2.1.1triplet loss原理

triplet loss程式碼如下:

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
  • 可以看出,triplet loss 利用一組三後設資料,分別設為(A,P,N)。其中A代表基準圖片,P是與A同一個人的人臉,N是與A不同人的人臉。輸入的是從網路輸出的embeddings,即最後的特徵值。
  • facenet中embeddings的shape由batchsize和embeddings的shape決定,在此例中,我將batchsize設定為30,embeddings_shape為128.則每次輸入的anchor為(10,128)的資料。P,N也一樣。
  • 計算loss時,由於A和P的距離小於A和N的距離,所以當alpha=0.2時,
    basic_loss=dist(a,p) 0.2−dist(a,n)” role=”presentation” style=”text-align: center; position: relative;”>basic_loss=dist(a,p) 0.2−dist(a,n)basic_loss=dist(a,p) 0.2−dist(a,n)

    basic\_loss = dist(a,p) 0.2-dist(a,n) 此表示式的目的是為了loss減小的同時,可以修改符合dist(a,p) 0.2 > dist(a,n)這組資料,因為此時,pos_dist 0.2 > neg_dist(a,n),要讓pos距離儘可能小,neg距離儘可能大。而在降低loss的同時,就是在做這件事。

解釋了triplet loss,開始訓練。

2.1.2 利用triplet loss 訓練

如何利用triplet loss訓練

  • 首先人臉檢測,裁剪圖片,下載Msceleb或者casia圖片庫,利用MTCNN進行face align,可以crop到160或者182,只需要分別修改margin和imagesize,margin=32對應160,margin=44對應182.如果裁剪到182,訓練時要加–random_crop引數,最後輸入網路的依然是160.如果像MsCeleb這種資料集,大約1000,0000的資料量,即使清洗資料依然有500,0000的人臉資料量。需要利用多GPU裁剪,參考上述連結。5百萬資料,TITAN XP做了14個小時。
  • 接下來訓練識別模型,triplet loss的佇列輸入每次輸入三個圖片算一組。batchsize也必須調整為3的倍數,970,4G我用的30。整個資料訓練流程如下:
    • 這裡要提到images_per_person和images_per_person。首先計算一個epoch要提取的數值,假設images_per_person=45,images_per_person=40,那麼nrof_examples=45*40=1800,在這1800容器中,按挑選45個人提取圖片,輸入進網路計算出embeddings,具體提取過程參考select_triplets()和sample_people(),batchsize=30時,約20000組三後設資料。
    • 佇列讀入資料 ,進行enqueue的op,計算loss,合併正則的loss,此處tf.GraphKeys.REGULARIZATION_LOSSES是在inception-resnet-v1的model中,inference()中slim.arg_scope中定義自動新增到這裡,就是所有的權值正則化項,而weight_decay手動定義,這裡取1e-4,列印正則化項shape,長度133.
    • 計算loss後不斷迭代。

本人triplet loss訓練結果一直不如人意,最終lfw的acc只能停留在86%左右。而換成center loss,一下就99.0%了。玄學triplet loss。

2.1.1 center loss原理

利用softmax訓練

  • centerloss
    此公式中 cyi” role=”presentation” style=”position: relative;”>cyicyic_{y_i} 代表第i類的中心,只訓練符合此類的 xi” role=”presentation” style=”position: relative;”>xixix_i,使得類內距離儘可能的小。達到了提高精度的效果。在人臉識別更適用,因為同一個人的人臉相差不大,特徵的類內距離更為接近。人臉的中心性更強一些,也就是說一個人的所有臉取平均值之後的人臉我們還是可以辨識是不是這個人。
  • 這裡寫圖片描述
    總的loss是由softmax loss和center loss相加,由λ” role=”presentation” style=”position: relative;”>λλ\lambda控制比例。

關於center loss 原理:center loss 原理

train_softmax.py訓練

def center_loss(features, label, alfa, nrof_classes):
"""Center loss based on the paper "A Discriminative Feature Learning Approach for Deep Face Recognition"
(http://ydwen.github.io/papers/WenECCV16.pdf)
"""
nrof_features = features.get_shape()[1]
centers = tf.get_variable('centers', [nrof_classes, nrof_features], dtype=tf.float32,
initializer=tf.constant_initializer(0), trainable=False)
label = tf.reshape(label, [-1])
centers_batch = tf.gather(centers, label)
diff = (1 - alfa) * (centers_batch - features)
centers = tf.scatter_sub(centers, label, diff)
loss = tf.reduce_mean(tf.square(features - centers_batch))
return loss, centers

2.1.2 利用center loss和softmax訓練

其中新增loss的模組如下:

# Add center loss
if args.center_loss_factor>0.0:
prelogits_center_loss, _ = facenet.center_loss(prelogits, label_batch, args.center_loss_alfa, nrof_classes)
tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, prelogits_center_loss * args.center_loss_factor)
learning_rate = tf.train.exponential_decay(learning_rate_placeholder, global_step,
args.learning_rate_decay_epochs*args.epoch_size, args.learning_rate_decay_factor, staircase=True)
tf.summary.scalar('learning_rate', learning_rate)
# Calculate the average cross entropy loss across the batch
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
labels=label_batch, logits=logits, name='cross_entropy_per_example')
cross_entropy_mean = tf.reduce_mean(cross_entropy, name='cross_entropy')
tf.add_to_collection('losses', cross_entropy_mean)
# Calculate the total losses
regularization_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
total_loss = tf.add_n([cross_entropy_mean]   regularization_losses, name='total_loss')
  • 整體流程與triplet loss類似,此方法是基礎方法,所有顯示的epochsize=1000是對此方法生效的。在triplet loss方法時1000只是一個最低限額,而真正的epochsize次數不是1000.與triplet loss不同的是,每次一張圖片的輸入而不是三元組的輸入。
  • 學習率,開場0.1,150=0.01,180=0.001,210=0.0001到了150時loss和acc有明顯的變化,acc從98%上升到99%,其餘變化點無明顯變化。
  • 收斂迅速,200個epoch達到99%,TITAN XP batchsize=150.

補充:

其餘滑動平均、隨機crop,prewhiten等程式碼中都很詳細。

三、評價模型準確率

  • 如何驗證lfw資料集
  • 評價模型準確率時,利用lfw的pairs做varification。accuracy很好理解,具體參考facenet.calculate_roc(),利用10折交叉驗證,找出最佳accuracy的閾值,從0-4步長0.01.一般在1.2左右。
  • 而Validation rate,和far這個判斷值搞了半天才搞清楚,這個值是在假定誤把不同的人判斷為相同的人的概率設定為FAIR=0.001的情況下,判斷兩個人是同一個人判斷正確的概率。這個是為了儘可能降低將不同人判斷為同一個人的概率。
def calculate_val_far(threshold, dist, actual_issame):
predict_issame = np.less(dist, threshold)
true_accept = np.sum(np.logical_and(predict_issame, actual_issame))
false_accept = np.sum(np.logical_and(predict_issame, np.logical_not(actual_issame)))
n_same = np.sum(actual_issame)
n_diff = np.sum(np.logical_not(actual_issame))
val = float(true_accept) / float(n_same)
far = float(false_accept) / float(n_diff)
return val, far