人脸识别技术总结

专业术语

FPS

FPS: 每秒传输帧数(Frames Per Second)

FPS也可以理解为我们常说的“刷新率(单位为Hz)”,例如我们常在CS游戏里说的“FPS值”。我们在装机选购显卡和显示器的时候,都会注意到“刷新率”。一般我们设置缺省刷新率都在75Hz(即75帧/秒)以上。例如:75Hz的刷新率刷也就是指屏幕一秒内只扫描75次,即75帧/秒。而当刷新率太低时我们肉眼都能感觉到屏幕的闪烁,不连贯,对图像显示效果和视觉感观产生不好的影响。

电影以每秒24张画面的速度播放,也就是一秒钟内在屏幕上连续投射出24张静止画面。有关动画播放速度的单位是fps,其中的f就是英文单词Frame(画面、帧),p就是Per(每),s就是Second(秒)。用中文表达就是多少帧每秒,或每秒多少帧。电影是24fps,通常简称为24帧。

常见参数

媒体 FPS帧率
电影 24 fps
电视 (PAL) 25 fps
电视 (NTSC) 30 fps
CRT显示器 > 75 fps
液晶显示器 60 fps

影响FPS的因素

既然刷新率越快越好,为什么还要强调没必要追求太高的刷新率呢?其中原因是在显示“分辨率”不变的情况下,FPS越高,则对显卡的处理能力要求越高。电脑中所显示的画面,都是由显卡来进行输出的,因此屏幕上每个像素的填充都得由显卡来进行计算、输出。
当画面的分辨率是1024×768时,画面的刷新率要达到24帧/秒,那么显卡在一秒钟内需要处理的像素量就达到了“1024×768×24=18874368”。如果要求画面的刷新率达到50帧/秒,则数据量一下子提升到了“1024×768×50=39321600”。

FPS与分辨率、显卡处理能力的关系如下:
$$\text{处理能力} = \text{分辨率}*\text{刷新率}$$
这也就是为什么在玩游戏时,分辨率设置得越大,画面就越不流畅的原因了。分辨率建议设置为显示器分辨率,过高或过低可能造成画面变形。

显示器的刷新率

刷新频率:即屏幕刷新的速度。
刷新频率越低,图像闪烁和抖动的就越厉害,眼睛疲劳得就越快。采用70Hz以上的刷新频率时才能基本消除闪烁,显示器最好稳定工作在允许的最高频率下,一般是85Hz。
普通显示器的刷新频率在15.75kHz-95kHz间。15.75kHz是人体对显示器最低要求的刷新频率。在游戏过程中一般人能接受的最低FPS约为30Hz,基本流畅等级则需要>60Hz。

人脸识别专业术语

FPS

一些对人脸识别算法的描述如下:

人脸检测速度最快可达1500+ FPS!
人脸识别涉及到的运算量很大,我的电脑最快的识别速度也就是0.2S识别一张照片,算下来帧数就是5帧左右,最后的显示效果就给人一种卡卡的感觉,很不好。
人脸检测领域每年都会有大量算法被提出,拼精度当然很重要,但真正要做到实际的应用里,算法还必须要快。

视频其实是有很多张图片(帧)组成的,那么只要把图片中的人脸检测出来,那么视频就迎刃而解了。
帧数就是在1秒钟时间里传输的图片的量,也可以理解为图形处理器每秒钟能够刷新几次,通常用fps(Frames Per Second)表示。每一帧都是静止的图象,快速连续地显示帧便形成了运动的假象。高的帧率可以得到更流畅、更逼真的动画。帧数 (fps) 越高,所显示的动作就会越流畅。

检测、识别、验证

  1. 人脸检测
    检测图片里面有没有人脸
  2. 人脸识别
    首先检测出图片中的人脸,再与已知的人脸做对比,看这个人脸是张三的,还是李四的

涉及技术

多进程来处理大数据

人脸识别帧数太低的解决方法
python使用pyqt多线程来显示视频

算法设计

人脸检测领域每年都会有大量算法被提出,拼精度当然很重要,但真正要做到实际的应用里,算法还必须要快。算法设计时,追求复杂度低和适合硬件加速(比如适合GPU运算等)是算法加速的两大方向。

亚毫秒级人脸检测算法

视频其实是有很多张图片(帧)组成的,那么只要把图片中的人脸检测出来,那么视频就迎刃而解了。

Python 人脸检测方法总结

目标跟踪

利用目标跟踪来提高实时人脸识别处理速度

One/zero-shot learning

如此小的训练集不足以去训练一个稳健的神经网络。

迁移学习的两种极端形式是一次学习(one-shot learning)和零次学习(zero-shot learning),有时也被称为零数据学习(zero-data learning)。只有一个标注样本的迁移任务被称为一次学习;没有标注样本的迁移任务被称为零次学习。
只有在训练时使用了额外信息,零数据学习(Larochelle et al., 2008)和零次学习(Palatucci et al., 2009; Socher et al., 2013b)才是有可能的。

零次学习是迁移学习的一种特殊形式。同样的原理可以解释如何能执行多模态学习(multimodal learning),学习两种模态的表示,和一种模态中的观察结果$x$与另一种模态中的观察结果$y$组成的对($x,y$)之间的关系(通常是一个联合分布)(Srivastava and Salakhutdinov, 2012)。通过学习所有的三组参数(从$x$到它的表示、从$y$到它的表示,以及两个表示之间的关系),一个表中的概念被锚定在另一个表示中,反之亦然,从而可以有效地推广到新的对组。

deeplearningbook-chinese

打个广告,我们刚刚release了我们在cvpr 2018的用gcn做zero-shot learning的代码。比起之前所有zero-shot learning的结果都有巨大的提升,在ImageNet上面的部分指标接近accuracy x 2。
相比起之前的方法,我们做出的主要改变是不单单利用word embeddings,还把knowledge graph的信息通过graph convolution network利用起来。我们相信这是zero shot learning之后发展的方向。
paper
github

在Deepmind用LSTM作为controller的Neural Turing Machine解one-shot learning的paper中, 用到的一个dataset是Omniglot, 这个dataset有1600个class每个class只有少量数据。
这篇Paper一个好的insight是meta-learning分为一种慢的可以用于许多task并基于gradient descent的学习方式和一种快的学一个specific task学三四遍就学会基于augment memory的学习方式。而此Paper test自己model有多好的方法也很有趣,只测试未在训练集中出现过的class,并且看这个class在慢的学习过多少个episode之后快的学习新知识有多快。如下图所示。
如果要一句话总结的话应该是:“他山之石可以攻玉”吧。
paper

zero-shot learning是一种学习范式,这种方式学出来的模型能够预测没在训练集中出现过的类怎么做?考虑图片分类任务,训练类是“马”,“老虎”,“熊猫”,测试类是“马”,“老虎”,“熊猫”和“斑马”步骤取训练类和测试类的并集,对其中每一个类加一个描述,描述是<key,value>对的集合,举个例子,“马”这个类可以是{‘horse_like’:yes,’stripes’:no,’black&white’:no},“老虎”是{‘horse_like’:no,’stripes’:yes,’black&white’:no},“熊猫”是{‘horse_like’:no,’stripes’:no,’black&white’:yes},“斑马”则是{‘horse_like’:yes,’stripes’:yes,’black&white’:yes}根据“马”,“老虎”,“熊猫”的训练样本训练一个mapping,这个mapping能将图片feature映射到对应的描述(这个mapping理应关注到图片的动物有没有像马,有没有条纹,是不是黑白的,只有这样才能得到正确的描述,从而在训练集上得分)将测试图片通过2中的mapping,得到预测的描述,根据这个描述和类的一一对应关系得到预测的类(如果一张图是斑马,根据2的分析mapping应该会得到{‘horse_like’:yes,’stripes’:yes,’black&white’:yes},从而成功预测出斑马)zero-shot learning的好处?极大节省标注量,在传统分类任务中,假设每个类别需要500个样本,增加10个“斑马”就要标注5000个样本,而zero-shot只需要增加10个描述。

就像人的“触类旁通”。举个简单的例子。假设1,小明知道斑马是一个黑白条纹,外形像马动物。假设2,小明未见过斑马。小明见到斑马大概率能认出这个是斑马。
零样本学习就是这种:可见类学习模型+辅助性知识、边缘描述+判断识别的过程。

transfer learning

domain adaption

重新训练

人脸识别虽然看起来是一个分类任务,但是在很多实际应用中很难用普通的分类器来处理,原因之一是每个类(人)的训练样本很少。比如我们做一个门禁系统,每个员工可能只能提供几张照片,不可能让每个人提供几百几千张照片,而且员工总数可能也很少,小型企业一般只有几十或者几百人。当然我们可以把非公司的其他人的照片也拿过来作为训练数据和分类,如果分类为其他人,那么就不能通过门禁。

这样似乎可以解决数据不够的问题,但是还有一个更难处理的问题——重新训练。通常公司的人员是经常变动的,每次人员变动都要重新训练模型,这样的门禁系统估计没人会买。

那怎么办呢?有没有不需要训练的分类器?KNN这是排上用场了。KNN是不需要训练的分类器,或者说训练的过程这是把训练数据存储下来,这显然很适合人脸识别的这类应用。之前KNN被诟病的一个问题就是需要存储所有的训练数据,因此速度很慢而且需要大量空间。而在这个场景下都不是问题,门禁系统的训练数据是非常少的,因此两两计算距离(相似度)不是问题。

比如1-NN算法:来了一个人的照片,我们计算这张照片和库里的所有照片一一计算距离,选择最相似的照片作为它的分类。但是我们还要寻找一个距离阈值,如果小于这个阈值,我们就判断它们是同一个人,否则就认为是其他人。

因此问题的关键是计算两张人脸照片的距离(相似度)。一种方法是学习一个神经网络,输入是两张照片,输出是它们的距离或者相似度。这就是所谓Siamese Network——它的输入是两个物体,而不是分类器的一个物体;输出是它们的距离(区别),而不是分类概率。

Siamese是连体人的意思,那为什么叫Siamese网络呢?比如下图是一种Siamese网络。第一张图片经过一个深度神经网络最后变成一个特征向量,而第二张照片也经过一个完全一样的网络变成另外一个特征向量,最后把它们组合起来用另外一些网络层来判断它们是否同一个物体。因为问题的对称性,dist(x, y)==dist(y, x),所以我们通常要求这两个提取特征的网络是完全一样的,包括参数。因此这种网络结构是对称的,很像一个连体人(Siamese),故名为Siamese网络。

使用Siamese实现的学习算法是一种One-Shot Learning(当然还有其它的One-Shot Learning算法)。增加一个新的类别只需要提供一个训练数据就行了(当然多几个没有坏处,不过要改个名字叫Few-Shot Learning,当然不能太多,否则就是普通的Learning了)。一个训练样本,似乎不能再少了,但是还有Zero-Shot Learning。这似乎有点不可能,我没见过一个物体,怎么能认识它呢?

不见过不代表不认识,比如下图中的动物,大家都没有见过。但是我们是“认识”的,我们知道它不是马,也不是犀牛,这是一个新的我们每见过的动物。也许有人会反驳,我都不知道它的名字,怎么算”认识“它了?其实认识不认识和知不知道它的名字是两回事,名字只是一个符号而已,中国人叫它”独角兽”,美国人叫它”Unicorn”,泰国人叫它”ตัวยูนิคอน”。符号本身没有什么意义,只是作为语言用于交流才有意义。猴子不能用语言给物体起名字,不代表它们不能识别物体。

我们还是回到人脸识别的问题上来。前面介绍的Siamese网络是一种解决增加新类的方法。但是它有一个缺点——不能提前计算(或者说索引)。对于门禁系统,上面的方法问题不大。但是比如我们的摄像头拍摄到了小偷的人脸照片,我们需要从几百万甚至几千万张照片中搜索可能的嫌疑人,用神经网络两两计算是不可能的。如果有十张小偷的照片,我们的计算就需要十倍的时间。

另外一种我们即将介绍的方法——Face Embedding就能解决这个问题。Face Embedding指的是输入一张人脸照片,我们用一个深度神经网络提取特征,把它表示成一个d维空间的向量。而计算两张照片的距离就变成这两个向量的运算,比如最简单的计算欧式距离。

对于前面的嫌疑人搜索,我们利用提前把人类库中的所有照片都变成一个d维向量,然后搜索的时候就只需要计算欧式距离就行了,这样会快得多。而且欧式空间的点我们可以通过一些空间索引或者近似索引的方法来找近似的(approximate)近邻,从而实现Approximate KNN算法。

那怎么把一张人脸照片表示成一个向量呢?最常见的做法是用大量的人脸数据库(不只是你们公司员工的那一点点照片)训练一个人脸分类器,这通常是一个深度的神经网络。然后我们把softmax之前的某一个全连接隐层作为人脸的特征向量。这个向量可以认为是这张人脸照片最本质的特征。给定两张照片,我们可以分别计算它们的特征向量,然后简单的计算欧式距离(或者训练一个相似度模型,当然不能太复杂)。这里其实也是一种Transfer Learning,我们用其它人脸的数据学到了区分人脸的有效特征,然后把它用于区分公司员工的人脸。当然Transfer Learning要求两个数据集的Domain是匹配的,用欧洲的人脸数据库来Transfer到亚洲可能并不好用。

但是前面提到的方法有一个问题——全连接层的隐单元通常比较多(通常上千,太少了效果不好)。因此这个特征向量的维度太大,后续的计算很慢(当然和Siamese比是快的)。本文使用了Triple-based损失函数直接学习出一个128维向量,这里的神经网络的输出就是这个128维向量。和前面的方法不同,前面的方法的神经网络的输出是一个分类概率,表示这张照片属于某个人的可能性。而本文的输出就是一个128维的向量,并且这个向量使得同一个人的两张照片得到的向量的欧式距离很近;而不同人的两种照片的欧式距离很远。

人脸识别简介

识别方法

方法比较

方法 效果
opencv 最简单、速度最快的方法,但效果一般
基于dlib pip有发布的库,不用自己训练模型,可以直接拿来使用,比较方便,效果较好
mtcnn 需要训练自己的模型,github有开源的项目,效果较好
基于pytorch 需要训练自己的模型,github有开源的项目,效果最好

以上这些都是亲自试验过的人脸检测方法,RetinaFace(基于pytorch)方法效果最好,最终采用这种方法,进行了一些优化。

Package FPS (1080x1920) FPS (720x1280) FPS (540x960)
facenet-pytorch 12.97 20.32 25.50
facenet-pytorch (non-batched) 9.75 14.81 19.68
dlib 3.80 8.39 14.53
mtcnn 3.04 5.70 8.23

Comparison of face detection packages

黑科技

Teachable Machine

Teachable Machine

Author: ElaineXHZhong
Link: https://elainexhzhong.github.io/2021/06/03/人脸识别技术总结/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.