[论文理解]人脸识别论文总结(一)

更新时间:2023-06-06 03:46:35 阅读: 评论:0

[论⽂理解]⼈脸识别论⽂总结(⼀)
Face Recognition Papers Review
主要两个贡献,⼀是把fc 的权重存到不同卡上去,称为model parallel , ⼆是随机选择negative pair 来近似softmax 的分母(很常规的做法)。
Model Parallel :
FC 分类分配到n 台显卡上,每台显卡分C/n 类,每张卡存权重的⼀部分,计算局部每张卡上的exp 和sumexp ,然后交互计算softmax 。考虑梯度回传问题,这样做梯度也是parallel 的,不同于数据parallel 。数据parallel 的话求梯度是需要⽤整个W 才能求W 的梯度的,⽽model paralle 因为有了梯度公式,可知:
∇logits i =prob i −onehot i
这⼀下明朗了,所以求权重W i 的梯度就有
∇W i =X T ∗∇logits i
不需要整个W 就可以求部分W 的梯度啦。
作者觉得尽管model parallel 了,但softmax 的分母部分还是⼤啊,于是借鉴常⽤的⽆监督⽅法,随机sample negative pairs ,不需要全部的negative pair 就可以估计出softmax
的分母了。
主要提出⼀种动态更新权重的池⼦⽅法,⽤单独⼀个特征⽹络来提取特征作为权重,⽽⾮直接学全连接的权重,然后动态更新这个池⼦,就不需要存储⼤量的权重了,加速了训练、。
⽅法其实很朴素。
前⾯那个⽅法是把权重存到不同的GPU 上去,因此,如果ID 越来越多,我们加卡就可以了,但本⽂
的⽅法不需要,也是节约成本的⼀个⽅法。
⽅法⼤致如下:
准备两个⽹络,P ⽹络⽤来训练,G ⽹络是P ⽹络的moving avg ,不训练,最开始随机初始化池⼦,记好当前batch 的id ,如果id 在池⼦⾥,训练P ⽹络⽤CE Loss ,和cosine loss ,如果不在⽤cosine loss ,训练⼀轮后更新G ⽹络。G ⽹络更新最⽼的池⼦,更新池⼦id 。
以此类推。
主要思想:
利⽤特征的模长来表⽰样本的质量,模长越⼩表明质量越低,并且设计损失函数希望⽆监督得达到这⼀⽬的。
⽂章⽤⼀个图说明了传统arcface 存在的问题以及如何解决这⼀问题,对于第⼀个图,作者认为传统arcface 理应对不同样本设置不同的margin ,对于质量⾼的样本,他的margin 应该⼤,⽽对于质量低的样本,他的margin 应该⼩,这是符合直觉的,⾼质量的样本应该具有更好的区分度,⽽低质量的样本由于其质量低可能局部不确定,因此⽤⼩的margin 更加合理;⽂章提出⽤向量模长来表⽰其质量,认为模长越⼤其质量越⾼。图b 则是根据不同模长动态设置margin ,⾼质量样本⼤margin ,低质量样本⼩margin ,但这样也存在⼀个问题,即质量低的样本的可⾏域还是太⼤了,原⽂说是太free 了,训练是⽐较难收敛的;为了解决这⼀问题,⽂章提出对模长(质量)进⾏⿎励,⿎励⾼质量样本的损失,即损失函数是模长的单调递增的函数;再说⼀下图c 中m 和g 的影响,⽂章设计的m 函数的作⽤如图b 其实是希望动态margin 的同时固定住可⾏域,也就是图b 中的三⾓形的区域,对于图c 中的图,低质量样本2和3都超出了可⾏域,因此受m 函数的影响会往可⾏域⾥移动;g 的设计是为了让所有的样本都尽可能贴近可⾏域的边界,因此当两个相反影响抵消时,其达到图d 的分布。
m 函数和g 函数的设计:
m a i =u m −l m
u a −l a a i −l a +l m
λg ≥sK −g ′l a =su 2a l 2a
u 2a −l 2a u m −l m
u a −l a
()()()()Processing math: 100%
m函数通过模长限制了可⾏域为如图所⽰的三⾓形区域,g函数是模长的双曲线函数。
这篇⽂章提出利⽤对抗训练同时分割⼈脸遮挡区域和检测⼈脸;
怎么⽣成mask?
有三种⽅式:
根据关键点来在对应的feature上drop
iwaki随机drop左右上下脸的feature
随机drop⼀半的feature
何处对抗?
对于mask之后的feature,希望分类loss增⼤,没有mask的loss减⼩。
⽂章主要三点贡献
改进⼈脸识别的损失函数,利⽤课程学习帮助优化⼈脸识别
设计了⼀个指⽰函数来表明当前训练的进度
⼤量实验
感激不尽
主要⽬的是想要做到不同的训练stage给easy sample和hard sample不同的权重,希望在训练初期hard sample的权重要⼩⼀些,训练后期hard sample的权重要⼤⼀些。
因此就涉及两个问题,⼀个是训练stage的划分,如何指⽰训练的stage,另⼀个是easy sample和hard sample的区分,如何区分两者。
对于第⼀个问题,⽂章设计了⼀个指⽰函数:
由于发现了平均cos相似度可以⼀定程度反映训练stage,早期显然positive样本由于训练不充分所以⼤部分都是不相似的,训练后期positive样本训练稍微充分,则相似性增⼤,因此可以⽤positive样本的相似性近似表⽰训练stage;此外,使⽤ema的⽅式防⽌stage的估计不稳定。
对于第⼆个问题,⽂章提出下⾯⽅式区分困难样本和简单样本
对于(7)的第⼀⾏为简单样本,第⼆⾏为困难样本,在训练初期,t接近与0,N接近与cos的平⽅,⽐较⼩,训练后期,t接近与1,显然N会增⼤。
提出分组卷积的改进版,⼀般的分组卷积都是组数是超参,训练时固定,根据输⼊的channels的不同为每个组分配不同的channel,⽽VarGNet则是认为每个组应该处理的channel是超参,事先需要定下来,⽽在训练中动态调整的则是组数,这样导致的结果是,输⼊的channel如果多,则组数多,输⼊的channel少,则组数少。
我们知道,模型计算量和组数成反相关,
Cal=k2×Height×Width×C in×C out
单曲循环英文
Groups
所以在输⼊通道过⼤时多⽤组数要计算更划算。
具体的⽹络结构上没有指导,指导的是设计上的意义。
主要贡献
提出⽤VarG卷积⽅式做backbone,并做了⼀些改进
L2损失蒸馏
import torch
from torch import nn
from torchsummary import summary
from config import *什么是同位语从句
import math
functional as F
import Parameter
'''
求Input的⼆范数,为其输⼊除以其模长
⾓度蒸馏Loss需要⽤到
'''
def l2_norm(input, axis=1):
norm  = (input, axis, keepdim=True) # 默认p=2
output = torch.div(input, norm)
return output
'''
变组卷积,S表⽰每个通道的channel数量
'''
def VarGConv(in_channels, out_channels, kernel_size, stride, S):
return nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding=kernel_size//2, groups=in_channels//S, bias=Fal),        nn.BatchNorm2d(out_channels),
nn.PReLU()
)
'''
pointwi卷积,这⾥的kernelsize都是1,不过这⾥也要分组吗??
'''
def PointConv(in_channels, out_channels, stride, S, isPReLU):
return nn.Sequential(
nn.Conv2d(in_channels, out_channels, 1, stride, padding=0, groups=in_channels//S, bias=Fal),
nn.BatchNorm2d(out_channels),
nn.PReLU() if isPReLU el nn.Sequential()
)
'''
SE block
'''
class SqueezeAndExcite(nn.Module):
def __init__(lf, in_channels, out_channels, divide=4):
super(SqueezeAndExcite, lf).__init__()
mid_channels = in_channels // divide
lf.pool = nn.AdaptiveAvgPool2d(1)
lf.SEblock = nn.Sequential(
nn.Linear(in_features=in_channels, out_features=mid_channels),
# nn.ReLU6(inplace=True),
nn.ReLU6(inplace=Fal),
nn.Linear(in_features=mid_channels, out_features=out_channels),
# nn.ReLU6(inplace=True), # 其实这⾥应该是sigmoid的
nn.ReLU6(inplace=Fal)
)
def forward(lf, x):
b, c, h, w = x.size()
out = lf.pool(x)
阅读答案网out = out.view(b, -1)
out = lf.SEblock(out)
out = out.view(b, c, 1, 1)
return out * x
'''
normal block
'''
class NormalBlock(nn.Module):
麦小龙
def __init__(lf, in_channels, kernel_size, stride=1, S=8):
super(NormalBlock, lf).__init__()
out_channels = 2 * in_channels
lf.vargconv1 = VarGConv(in_channels, out_channels, kernel_size, stride, S)
lf.pointconv1 = PointConv(out_channels, in_channels, stride, S, isPReLU=True)
lf.vargconv2 = VarGConv(in_channels, out_channels, kernel_size, stride, S)
lf.pointconv2 = PointConv(out_channels, in_channels, stride, S, isPReLU=Fal)
lf. = SqueezeAndExcite(in_channels, in_channels)
lf.prelu = nn.PReLU()
out = x
x = lf.pointconv1(lf.vargconv1(x))
x = lf.pointconv2(lf.vargconv2(x))
x = lf.(x)
# out += x
out = out + x
return lf.prelu(out)
'''
downsampling block
'''
class DownSampling(nn.Module):
def __init__(lf, in_channels, kernel_size, stride=2, S=8):
super(DownSampling, lf).__init__()
out_channels = 2 * in_channels
lf.branch1 = nn.Sequential(
VarGConv(in_channels, out_channels, kernel_size, stride, S),
PointConv(out_channels, out_channels, 1, S, isPReLU=True)
来自历史故事的成语有哪些
)
lf.branch2 = nn.Sequential(
VarGConv(in_channels, out_channels, kernel_size, stride, S),
PointConv(out_channels, out_channels, 1, S, isPReLU=True)
)
lf.block3 = nn.Sequential(
VarGConv(out_channels, 2*out_channels, kernel_size, 1, S), # stride =1            PointConv(2*out_channels, out_channels, 1, S, isPReLU=Fal)
) # 上⾯那个分⽀
lf.shortcut = nn.Sequential(
VarGConv(in_channels, out_channels, kernel_size, stride, S),
PointConv(out_channels, out_channels, 1, S, isPReLU=Fal)
)
lf.prelu = nn.PReLU()
def forward(lf, x):
out = lf.shortcut(x)
x1 = x2 = x
x1 = lf.branch1(x1)
x2 = lf.branch2(x2)
x3 = x1+x2
x3 = lf.block3(x3)
# out += x3
alive是什么意思out = out + x3
return lf.prelu(out)
class HeadSetting(nn.Module):
def __init__(lf, in_channels, kernel_size, S=8):
super(HeadSetting, lf).__init__()
lf.block = nn.Sequential(
VarGConv(in_channels, in_channels, kernel_size, 2, S),
PointConv(in_channels, in_channels, 1, S, isPReLU=True),
VarGConv(in_channels, in_channels, kernel_size, 1, S),
PointConv(in_channels, in_channels, 1, S, isPReLU=Fal)
)
lf.short = nn.Sequential(
VarGConv(in_channels, in_channels, kernel_size, 2, S),
PointConv(in_channels, in_channels, 1, S, isPReLU=Fal),
)
out = lf.short(x)
x = lf.block(x)
juniorschool# out += x
out = out + x
return out
class Embedding(nn.Module):
def __init__(lf, in_channels, out_channels=512, S=8):
super(Embedding, lf).__init__()
nn.Conv2d(in_channels, 1024, kernel_size=1, stride=1,padding=0, bias=Fal),
nn.BatchNorm2d(1024),
# nn.ReLU6(inplace=True),
nn.ReLU6(inplace=Fal),
nn.Conv2d(1024, 1024, (7, 6), 1, padding=0, groups=1024//8, bias=Fal),
nn.Conv2d(1024, 512, 1, 1, padding=0, groups=512, bias=Fal)
)
lf.fc = nn.Linear(in_features=512, out_features=out_channels)
def forward(lf, x):
x = lf.embedding(x)
x = x.view(x.size(0), -1)
out = lf.fc(x)
return out
class VarGFaceNet(nn.Module):竞选团支书发言稿
def __init__(lf, num_class=512):
super(VarGFaceNet, lf).__init__()
S=8
nn.Conv2d(in_channels=3, out_channels=40, kernel_size=3, stride=1, padding=1, bias=Fal),            nn.BatchNorm2d(40),
# nn.ReLU6(inplace=True)
nn.ReLU6(inplace=Fal)
)
lf.head = HeadSetting(40, 3)
lf.stage2 = nn.Sequential( # 1 normal 2 down
DownSampling(40, 3, 2),
NormalBlock(80, 3, 1),
NormalBlock(80, 3, 1)
)
lf.stage3 = nn.Sequential(
DownSampling(80, 3, 2),
NormalBlock(160, 3, 1),
NormalBlock(160, 3, 1),
NormalBlock(160, 3, 1),
NormalBlock(160, 3, 1),
NormalBlock(160, 3, 1),
NormalBlock(160, 3, 1),
)
lf.stage4 = nn.Sequential(
DownSampling(160, 3, 2),
NormalBlock(320, 3, 1),
NormalBlock(320, 3, 1),
NormalBlock(320, 3, 1),
)
for m dules():
if isinstance(m, nn.Conv2d):
n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
m.al_(0, math.sqrt(2. / n))

本文发布于:2023-06-06 03:46:35,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/135504.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:训练   函数   样本   模长   质量   问题   提出   计算
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图