之前只接触过传统方法的人脸识别算法,本以为基于深度学习的方法会使用对比损失之类的函数进行训练,但是Arcface算法基于softmax进行了创新,本文未深究其详细的loss公式原理,在大致明白其方向下,运行了代码,记录如下。
我们知道,若分类问题的 label 有 K 个,则,softmax 最后输出K个概率,
Σ
k
i
=
1
Σk_{i} = 1
Σki=1 ,其中概率值最大的即为预测标签;
下列公式基于 Conv(wx+b)
→
\rightarrow
→ Softmax
→
\rightarrow
→ CrossEntropy Loss:
其中,
f
j
f_{j}
fj 表示类别得分 f 的向量的第 j 个元素 ( j ∈ [1, K],K 是类的数量),N 是训练数据的数量。
注意,这里先忽略b;
由矩阵点乘公式知:两个向量的点乘等于它们的数乘结果乘以两个向量之间夹角的余弦值。 A ⋅ B = ∣ A ∣ ∣ B ∣ c o s θ A·B = |A||B|cosθ A⋅B=∣A∣∣B∣cosθ
即,A,B均为向量,相乘以后,得到一个标量。经常用于相似度计算。
其中, θ j ( θ ∈ [ 0 , π ] ) θ_{j}(θ∈[0, π]) θj(θ∈[0,π]) 是 矢量 w j w_j wj 和 x i x_i xi之间的角度;
如果只有两个类别 a, b,对于输入样本 x 来说(x的 label 为a),softmax强制使得 w a T > w b T w^T_a > w^T_b waT>wbT,即, ∣ ∣ w a ∣ ∣ ∣ ∣ x ∣ ∣ c o s θ a > ∣ ∣ w b ∣ ∣ ∣ ∣ x ∣ ∣ c o s θ b ||w_a||||x||cosθ_a > ||w_b||||x||cosθ_b ∣∣wa∣∣∣∣x∣∣cosθa>∣∣wb∣∣∣∣x∣∣cosθb,以便正确分类x。
为了使得分类更加严格,L-softmax提出了一种decision margin(判定间隔),要求:
∣ ∣ w a ∣ ∣ ∣ ∣ x ∣ ∣ c o s ( m θ a ) > ∣ ∣ w b ∣ ∣ ∣ ∣ x ∣ ∣ c o s θ b ||w_a||||x||cos(mθ_a) > ||w_b||||x||cosθ_b ∣∣wa∣∣∣∣x∣∣cos(mθa)>∣∣wb∣∣∣∣x∣∣cosθb,其中: θ a ∈ [ 0 , π / m ] θ_a∈[0, π/m] θa∈[0,π/m]
即,softmax损失并没有明确地鼓励类内紧凑性和类间可分性。
样本和参数之间的可分性可以分解为具有余弦相似性的幅值和角值:
按照该思路,如下图所示:
ArcFace 提出了 加性角度边距损失 (Additive Angular Margin Loss, ArcFace),以进一步提高人脸识别模型的判别能力,并稳定训练过程。
DCNN 特征和最后一个 FC 层权重之间的点积/内积 等于 特征和权重归一化之后的余弦距离。
先利用 反余弦 (arc-cosine) 函数来计算当前特征与目标权重之间的角度。
然后,把一个 加性角度边距 (additive angular margin) 加到目标角度,然后通过 余弦 (cosine) 函数再次获得目标 logit。
接着,通过固定的特征范数重缩放所有 logit,且后续的步骤与 Softmax Loss 中的步骤完全相同。
基于代码[4]运行程序;
注意:
- 其 test.py 是针对配对样本来进行计算准确率,即,针对测试集的.txt,是6行 12张图片,每行两张图片+label(是否相似);但是在程序测试时,是针对每张图片计算的向量,最后定位.txt中一行两个图片的向量,比较其相似性;
- 以灰度形式读取图片,然后使用 np.dstack 来堆叠一个图像 image 和它的水平翻转版本;在计算特征的时候,级联batch_size个图片,或者一个测试列表的图片,其输入模型的图片就是[12, 1, 128, 128] ---- 这里以6张图片举例。
image = cv2.imread(img_path, 0)
# (128, 128)
image = np.dstack((image, np.fliplr(image)))
# (128, 128, 2)
image = image.transpose((2, 0, 1))
image = image[:, np.newaxis, :, :]
# [2, 1, 128, 128]
- 模型输出之后,取奇偶项的特征,即,还是横向级联一张图片的两种表达形式,将 [12, 512] → \rightarrow → [6, 1024]
fe_1 = output[::2]
fe_2 = output[1::2]
feature = np.hstack((fe_1, fe_2))
但是在项目中,我们需要的是对于某一张图片,在图像集中找出与其同为一人的照片;为此,将 test.py 修改之后,我们进行了 仅包含6~7张 图像集 的简单测试;
因为使用的.pt应该是要求128*128的尺寸,我仅是将图片直接reshape,并未进行其他操作,故而得分都不是很高,但是简单的设置阈值,也能得到正确的结果;
针对同一个人的照片,人脸比对给出的得分在0.5左右,与其他人的得分在0.2左右;
我们的图像集中,7.jpg为阮经天,输入上述图片,测试结果也是7.jpg;
参考:
- ArcFace: Additive Angular Margin Loss for Deep Face Recognition
- https://blog.csdn.net/yiran103/article/details/83684613
- https://blog.csdn.net/qq_39478403/article/details/116788113
- https://github.com/ronghuaiyang/arcface-pytorch
- https://zhuanlan.zhihu.com/p/84261730