如何用DL4J构建起一个人脸识别系统

一、概述
人脸识别本质上是一个求相似度的问题,相同的人脸映射到同一个空间,他们的距离比较近,这个距离的度量可以是余弦距离,也可以是欧几里得距离,或者其他的距离 。下面有三个头像 。
 

如何用DL4J构建起一个人脸识别系统

文章插图
 
 
如何用DL4J构建起一个人脸识别系统

文章插图
 
 
如何用DL4J构建起一个人脸识别系统

文章插图
 
A B C
显然A和C是相同人脸,A和B是不同人脸,用数学怎么描述呢?假设有个距离函数d(x1,x2),那么 d(A,B) > d(A,C) 。在真实的人脸识别应用中,函数d(x1,x2)小到一个什么范围才认定为同一张人脸呢?这个值和训练模型时的参数有关,这个将在下文中给出 。值得注意的是,如果函数d为cosine,则值越大表示越相似 。一个通用的人脸识别模型应该包含特征提取(也就是特征映射)和距离计算两个单元 。
二、构造模型
那么有什么办法可以特征映射呢?对于图像的处理,卷积神经网络无疑是目前最优的办法 。DeepLearning4J已经内置了训练好的VggFace模型,是基于vgg16训练的 。vggFace的下载地址:https://dl4jdata.blob.core.windows.net/models/vgg16_dl4j_vggface_inference.v1.zip,这个地址是怎么获取到的呢?直接跟一下源码VGG16,pretrainedUrl方法里的DL4JResources.getURLString方法便有相关模型的下载地址,VGG19、ResNet50等等pretrained的模型下载地址,都可以这样找到 。源码如下
public class VGG16 extends ZooModel {@Builder.Default private long seed = 1234;@Builder.Default private int[] inputShape = new int[] {3, 224, 224};@Builder.Default private int numClasses = 0;@Builder.Default private IUpdater updater = new Nesterovs();@Builder.Default private CacheMode cacheMode = CacheMode.NONE;@Builder.Default private WorkspaceMode workspaceMode = WorkspaceMode.ENABLED;@Builder.Default private ConvolutionLayer.AlgoMode cudnnAlgoMode = ConvolutionLayer.AlgoMode.PREFER_FASTEST;private VGG16() {}@Overridepublic String pretrainedUrl(PretrainedType pretrainedType) {if (pretrainedType == PretrainedType.IMAGENET)return DL4JResources.getURLString("models/vgg16_dl4j_inference.zip");else if (pretrainedType == PretrainedType.CIFAR10)return DL4JResources.getURLString("models/vgg16_dl4j_cifar10_inference.v1.zip");else if (pretrainedType == PretrainedType.VGGFACE)return DL4JResources.getURLString("models/vgg16_dl4j_vggface_inference.v1.zip");elsereturn null;}vgg16的模型结构如下:
====================================================================================================VertexName (VertexType)nIn,nOutTotalParamsParamsShapeVertex Inputs====================================================================================================input_1 (InputVertex)-,----conv1_1 (ConvolutionLayer)3,641,792W:{64,3,3,3}, b:{1,64}[input_1]conv1_2 (ConvolutionLayer)64,6436,928W:{64,64,3,3}, b:{1,64}[conv1_1]pool1 (SubsamplingLayer)-,-0-[conv1_2]conv2_1 (ConvolutionLayer)64,12873,856W:{128,64,3,3}, b:{1,128}[pool1]conv2_2 (ConvolutionLayer)128,128147,584W:{128,128,3,3}, b:{1,128}[conv2_1]pool2 (SubsamplingLayer)-,-0-[conv2_2]conv3_1 (ConvolutionLayer)128,256295,168W:{256,128,3,3}, b:{1,256}[pool2]conv3_2 (ConvolutionLayer)256,256590,080W:{256,256,3,3}, b:{1,256}[conv3_1]conv3_3 (ConvolutionLayer)256,256590,080W:{256,256,3,3}, b:{1,256}[conv3_2]pool3 (SubsamplingLayer)-,-0-[conv3_3]conv4_1 (ConvolutionLayer)256,5121,180,160W:{512,256,3,3}, b:{1,512}[pool3]conv4_2 (ConvolutionLayer)512,5122,359,808W:{512,512,3,3}, b:{1,512}[conv4_1]conv4_3 (ConvolutionLayer)512,5122,359,808W:{512,512,3,3}, b:{1,512}[conv4_2]pool4 (SubsamplingLayer)-,-0-[conv4_3]conv5_1 (ConvolutionLayer)512,5122,359,808W:{512,512,3,3}, b:{1,512}[pool4]conv5_2 (ConvolutionLayer)512,5122,359,808W:{512,512,3,3}, b:{1,512}[conv5_1]conv5_3 (ConvolutionLayer)512,5122,359,808W:{512,512,3,3}, b:{1,512}[conv5_2]pool5 (SubsamplingLayer)-,-0-[conv5_3]flatten (PreprocessorVertex)-,---[pool5]fc6 (DenseLayer)25088,4096102,764,544W:{25088,4096}, b:{1,4096}[flatten]fc7 (DenseLayer)4096,409616,781,312W:{4096,4096}, b:{1,4096}[fc6]fc8 (DenseLayer)4096,262210,742,334W:{4096,2622}, b:{1,2622}[fc7]----------------------------------------------------------------------------------------------------Total Parameters:145,002,878Trainable Parameters:145,002,878Frozen Parameters:0对于VggFace我们只需要前面的卷积层和池化层来提取特征,其他的全连接层可以丢弃掉,那么我们的模型可以设置成如下的样子 。
如何用DL4J构建起一个人脸识别系统

文章插图
 
说明:这里用StackVertex和UnStackVertex的原因是,dl4j中默认情况下有都给输入时是把张量Merge在一起输入的,达不到多个输入共享权重的目的,所以这里先用StackVertex沿着第0维堆叠张量,共享卷积和池化提取特征,再用UnStackVertex拆开张量,给后面用于计算距离用 。


推荐阅读