Insightface----loss

总结下insightface的相关内容,其实,个人理解,这种用于分类的算法,相比较检测的算法来说的话,要来的简单一点。
为了搞清楚整个算法的流程,这里先对arcface_loss做一些在项目过程中的记录。先贴上损失函数公式
在这里插入图片描述
损失函数如上图所示。其实对于arcface的损失函数,网上的理解比比皆是,无非是为了增加分类的准确性,扩大化类间差距,增强类内紧度,引入了参数m。
但是这里看下公式,既然是损失函数,那么我们的网络的输出呢?我们数据的label呢?那么到底是怎么实现的呢?这里再贴上一个简化的网络结构
在这里插入图片描述
ok!看下网络结构,首先输入图片维度为(batch,112,112,3),然后中网络的话使用了Res_net100然后每个block做了改变变为IR,作者解释,更有利于人脸特征的提取!在这里我们暂且不研究网络具体结构,然后再看,以Resnet_100为例,网络输出为(batch,512),也就是生成了一个512维的向量来表示图片特征。其实从embedding到下一个(b,class)层,是我们用来构建arcface的,什么意思呢?也就是我们损失函数中的W矩阵是这一层的矩阵,然后利用BP来更新所有的前面的权重!我们先把这些明确,还有就是无论arcface_loss怎么变,最后我们就是要求一个Wx将(batch,512)映射到(batch,classes)上,然后根据这个再使用softmaxloss,来与label求一个误差!
这里结合arcface_loss实现的代码进行一步一步的解释:
这里再明确一点,我们使用arcloss函数,先确定的是softmax损失函数中相当于Wx的部分

def arcface_loss(embedding,labels,w_init,classes,W,s=64,m=0.5):
	'''
	embedding : (batch,512)
	labels : (batch,classes)  [1,432,64,78......
	classes : 类别数  
	'''
	cos_m = math.cos(m)
	sim_m = math.sin(m)
	mm = sin_m * m
	threshold = math.cos(math.pi - m)
	
	with tf.variable_scope('arcface_loss'):
		#首先求||x||
		embedding_norm = tf.norm(embedding,axis=1,keep_dims=True) #(batch,512)
		embedding = tf.div(embedding,embedding_norm) #(batch,512)
		
		#求||W||
		weights = tf.get_vatiable(name='embedding_wiehgts',shape=(embedding.get_shape().as_list[-1],classes,initializer=w_init,dtype=tf.float32)
		weights_norm = tf.norm(weights,axis=0,keep_dims=True)  #(512,classes)
		weights = tf.dive(weights,weights_norm)  #(512,classes)
		
		#求cos(theta + m)
		#求cos(theta)
		cos_t = tf.matmul(embedding,weights)
		#求sin(theta)
		sin_t = tf.sqrt(tf.subtract(1.0,tf.square(cos_t)))
		#求cos(theta+m)
		cos_mt = s * tf.subtract(tf.multiply(cos_t,cos_m),tf.multiply(sin_t,sin_m))
		
		######################55555##############
        cond_v = cos_t - threshold
        cond = tf.cast(tf.nn.relu(cond_v, name='if_else'), dtype=tf.bool)

        keep_val = s*(cos_t - mm)
        cos_mt_temp = tf.where(cond, cos_mt, keep_val)

        mask = tf.one_hot(labels, depth=classes, name='one_hot_mask')

        inv_mask = tf.subtract(1., mask, name='inverse_mask')

        s_cos_t = tf.multiply(s, cos_t, name='scalar_cos_t')

        output = tf.add(tf.multiply(s_cos_t, inv_mask), tf.multiply(cos_mt_temp, mask), name='arcface_loss_output')
    return output

解释下上述代码。从######################55555##############以上的代码很容易理解
那么之后又都是什么意思呢?
首先我们要保证cos(theta + m)是单调递减的
如何单调递减呢?
0<= theta + m <= pi 为什么是这个区间呢?因为W与X之间的夹角最大不过180
也就是theta的范围在
-m <= theta <= pi - m
而 m是大于0的也就是说我们theta不需要考虑它的左边界。看下示意图
在这里插入图片描述
什么意思呢?我们需要theta+m(实线)的范围在[0,pi]之间才能保证单调。也就是theta的范围必须在[-m,pi- m]这一段之内,然后我们实际考虑下,首先theta不可能为负,那么theta的范围缩小到[0,pi-m]之间。那么再考虑个问题,w与x的夹角不会因为我们给定了角度惩罚后就会变化,也就是说theta的取值范围还可以取到[0,pi],这里理论上来说应该是可以取到pi的。但是当theta取值范围在[pi-m,pi]之间的时候,theta+m就会超过pi而导致函数部单调所以theta的取值范围确定为[0,pi-m]。那么如何映射到cos函数上呢,当cos(theta) > cos(theta + m),也就是上图实线与虚线交点的地方的时候,认为不单调了,这是给它一个定值,类似于relu函数。再看下述代码
(这里再说下为什么部考虑左边界?一个来说它是递增的,另一个来说,不可能落再[m,0]之间)

threshold = math.cos(math.pi - m)
cond_v = cos_t - threshold
cond = tf.cast(tf.nn.relu(cond_v, name='if_else'), dtype=tf.bool)
keep_val = s*(cos_t - mm)
cos_mt_temp = tf.where(cond, cos_mt, keep_val)

在这里插入图片描述

这里有人问了,为什么超过边界的时候要用keep_val = s*(cos_t - mm)???
我也不清楚,还没找到这个的出处。
然后个人认为实现最复杂的部分就是上边这个了,主要是不好理解,然后再看下接下来的函数
这里再次强调,我们这个arcloss返回的并不是完整的公式内容,而是类似于softmax中的wx的部分

mask = tf.one_hot(labels, depth=classes, name='one_hot_mask')

inv_mask = tf.subtract(1., mask, name='inverse_mask')

s_cos_t = tf.multiply(s, cos_t, name='scalar_cos_t')

output = tf.add(tf.multiply(s_cos_t, inv_mask), tf.multiply(cos_mt_temp, mask), name='arcface_loss_output')

所以上述代码就是实现当j != yj的时候,以及等于的时候的部分。

因此上述我们完整的arcface_loss的输出还需要接一个softmax损失部分

loss = tf.reduce_mean(
tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logit, labels=labels)
)

这里tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logit, labels=labels)函数第一步是计算softmax,第二步是计算交叉熵。
至此,我们的arcface_loss的实现过程以及完成。剩下的就是net网络的搭建,以及数据集的制作和选择什么方式训练了。

代码来自于项目https://github.com/auroua/InsightFace_TF

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值