FaceBoxes: 可以在CPU上实时的人脸检测网络

FaceBoxes: A CPU Real-time Face Detector with High Accuracy

原文地址
论文源码

使用了 SSD 的方法,提取网络不同深度的 feature map 完成人脸分类+bbox回归的任务,也有 RPN 的思想,设置 anchor 提取 proposal,增加检测性能,使用大步长快速缩减特征维度,实现快速计算,使用 C.ReLU 增加少量计算量但增加 channel 数量,防止因为特征维度小而造成检测性能的快速下降;提取网络不同深度、不同维度大小的 feature map 进行人脸检测,可以实现多尺度人脸的检测。

加速:Rapidly Digested Convolutional Layers (RDCL)

  • 缩减输入维度:在卷积层和 pooling 层设置大步长快速降低输入的维度,减少计算量,文中 stride=(4, 2, 2, 2);
  • 选择合适大小的卷积核:选择较大的卷积核加速计算,文中 kernel szie = (77, 55 ,3*3);
  • 减少输出的 channel 数量:减少 channel 数量同样可以减少计算量,文中还用到 C.ReLU ,可以减少计算量,但是性能仅有小幅下降,可以忽略不计;
    C . R e L U = [ R e L U ( x ) , R e L U ( − x ) ] C.ReLU=[ReLU(x), ReLU(-x)] C.ReLU=[ReLU(x),ReLU(x)]

防止检测性能的大幅下降的做法:Multiple Scale Convolutional Layers (MSCL):

  • 提取网络不同深度的 feature map 进行人脸检测,靠近输入层的 feature map 用于检测小尺度人脸,靠近输出层的 feature map 用于检测大尺度人脸;
  • 提取的不同深度的 feature map 的宽度不同,用到了 Inception 结构,多分支进行不同卷积等操作,实现不同感受野的融合,增强对不同尺度人脸的检测;


在这里插入图片描述

Anchor densification strategy: 增加 anchor 稠密的操作

  • aspect ratio: 1:1
  • anchor 的大小:
    Inception:32, 64, 128 像素
    Conv3_2:256 像素
    Conv4_2:512 像素
  • anchor 稠密策略:
    A d e n s i t y = A s a c l e / A i n t e r v a l A_{density}=A_{sacle}/A_{interval} Adensity=Asacle/Ainterval
    其中, A d e n s i t y A_{density} Adensity 是 anchor 的尺度, A i n t e r v a l A_{interval} Ainterval 是 anchor 的间隔,代码中默认 anchor 的间隔分别为 32, 32, 32, 64, 128, 对应的密度为 1, 2, 4, 4, 4,存在明显的不同尺度的 anchor 密度不平衡的问题,相较于大尺度 anchor ( 128 × 128 , 256 × 256 , 512 × 512 128\times 128,256\times 256, 512\times 512 128×128,256×256,512×512),小尺度的 anchor ( 32 × 32 , 64 × 64 32\times 32, 64\times 64 32×32,64×64) 过于稀疏,会导致小尺度人脸的召回率过低。
    为了解决不平衡的问题,对一种 anchor 稠密 n n n倍,在一个感受野的中心均匀放置 A n u m b e r = n 2 A_{number}=n^2 Anumber=n2 个 anchor 用于预测,而不是放置1个。文中稠密 32 × 32 32\times 32 32×32 的 anchor 4 倍,稠密 64 × 64 64 \times 64 64×64 的 anchor 2倍,保证不同尺度的 anchor 有相同的密度,不同尺度的人脸可以匹配相同数量的 abchor;


    在这里插入图片描述

模型


网络结构

  • 通过使用较大的卷积核和步长来快速缩减 feature map 的大小
  • 使用较大的卷积核

模型部分的 pytorch 实现:

def conv_bn_relu(in_channels,out_channels,kernel_size,stride=1,padding=0):
	return nn.Sequential(
        nn.Conv2d(in_channels,out_channels,kernel_size=kernel_size,padding=padding,stride=stride),
        nn.BatchNorm2d(out_channels),
        nn.ReLU(True)
    )


class Inception(nn.Module):
	def __init__(self):
		super(Inception,self).__init__()
		self.conv1 = conv_bn_relu(128,32,kernel_size=1)
		self.conv2 = conv_bn_relu(128,32,kernel_size=1)
		self.conv3 = conv_bn_relu(128,24,kernel_size=1)
		self.conv4 = conv_bn_relu(24,32,kernel_size=3,padding=1)
		self.conv5 = conv_bn_relu(128,24,kernel_size=1)
		self.conv6 = conv_bn_relu(24,32,kernel_size=3,padding=1)
		self.conv7 = conv_bn_relu(32,32,kernel_size=3,padding=1)
	def forward(self,x):
		x1 = self.conv1(x)
		
		x2 = F.max_pool2d(x,kernel_size=3,stride=1,padding=1)
		x2 = self.conv2(x2)

		x3 = self.conv3(x)
		x3 = self.conv4(x3)
		
		x4 = self.conv5(x)
		x4 = self.conv6(x4)
		x4 = self.conv7(x4)

		output = torch.cat([x1,x2,x3,x4],1)
		return output


class FaceBox(nn.Module):
	input_size = 1024 # 使用较大的输入(1024)增强对小目标的检测效果
	def __init__(self):
		super(FaceBox, self).__init__()

		#model
		# 7*7 的卷积核,stride=4,快速缩小 feature map 缩小 4 倍
		self.conv1 = nn.Conv2d(3,24,kernel_size=7,stride=4,padding=3)
		self.bn1 = nn.BatchNorm2d(24)
		# 5*5 的卷积核,stride=2, feature map 缩小 2 倍
		self.conv2 = nn.Conv2d(48,64,kernel_size=5,stride=2,padding=2)
		self.bn2 = nn.BatchNorm2d(64)

		self.inception1 = Inception()
		self.inception2 = Inception()
		self.inception3 = Inception()

		self.conv3_1 = conv_bn_relu(128,128,kernel_size=1)
		# stride=2, feature map 缩小 2 倍
		self.conv3_2 = conv_bn_relu(128,256,kernel_size=3,stride=2,padding=1)
		self.conv4_1 = conv_bn_relu(256,128,kernel_size=1)
		# stride=2, feature map 缩小 2 倍
		self.conv4_2 = conv_bn_relu(128,256,kernel_size=3,stride=2,padding=1)

		self.multilbox = MultiBoxLayer()

	def forward(self,x):
		hs = []
		# input: 3*1024*1024
		# 24*256*256
		x = self.conv1(x)
		x = self.bn1(x)
		# C.ReLU 增加 channel 数量 48*256*256
		x = F.relu(torch.cat((F.relu(x), F.relu(-x)),1))
		
		# feature map = 48*128*128
		x = F.max_pool2d(x,kernel_size=3,stride=2,padding=1)
		# 64*64*64
		x = self.conv2(x)
		x = self.bn2(x)
		# 128*64*64
		x = F.relu(torch.cat((F.relu(x), F.relu(-x)),1))
		
		# 128*32*32
		x = F.max_pool2d(x,kernel_size=3,stride=2,padding=1)
		# 128*32*32
		x = self.inception1(x)
		#128*32*32
		x = self.inception2(x)
		# 128*32*32
		x = self.inception3(x)
		# 提取第三个 inception 结构的输出的 feature map 用于小尺寸人脸检测
		hs.append(x) 

		# 128*32*32
		x = self.conv3_1(x)
		# 128*16*16
		x = self.conv3_2(x)
		# 提取 feature map 用作人脸检测
		hs.append(x)

		# 128*16*16
		x = self.conv4_1(x)
		# 256*8*8
		x = self.conv4_2(x)
		# 使用该层的 feature map 进行大尺寸人脸检测
		hs.append(x)

		loc_preds, conf_preds = self.multilbox(hs)

		return loc_preds, conf_preds

训练

  • 数据集:WIDER FACE 的子集
  • 数据增强:
    • Color distortion
    • Random cropping
    • Scale transformation
    • Horizontal flipping
    • Face-box filter:过滤掉小于20像素的人脸
  • 损失函数:
    • 分类:softmax
    • 回归:smooth L1
      L l o c ( t u , v ) = ∑ y ∈ { x , y , w , h } s m o o t h L 1 ( t i u − v i ) L_{loc}(t^u, v)=\sum_{y\in \{x,y,w,h\}} smooth_{L_1}(t_i^u-v_i) Lloc(tu,v)=y{x,y,w,h}smoothL1(tiuvi),其中, { 0.5 x 2 i f ∣ x ∣ &lt; 1 ∣ x ∣ − 0.5 o t h e r w i s e \left\{\begin{matrix} 0.5x^2 &amp; if |x|&lt;1 \\ |x|-0.5 &amp; otherwise \end{matrix}\right. {0.5x2x0.5ifx<1otherwise

结果


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值