0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

用Go语言实现人脸识别,怎么做到的

8g3K_AI_Thinker 来源:未知 作者:工程师曾玲 2018-08-26 09:56 次阅读

做人脸识别用 Python 比较多,但是今天碰上一个另类,他就跟别人不一样,就不用 Python 用 Go。其实不管是 P 还是 G,能认出脸来就是好样的。

光说不练假把式,我们来看看这哥们到底是怎么做到的。

这篇文章将教会你如何运用 Go 语言实现人脸识别

▌前言

如今,神经网络已经非常流行,人们将它用于各种任务,特别是人脸识别应用。

最近,我用一个以 Go 语言为后端的软件,实现了一个人脸识别项目。它能够识别出上传照片中的人像 (如流行歌手)是谁。这听起来不错,我决定试一下也给你们介绍一下项目的整个过程。

需要说明的是,我尽可能地将所需的系统配置控制在较低水平,以便更多用户可以通过使用便宜的服务器来进行安装,而这也是为什么实现过程不使用 CUDA 或 GPU 的原因——虽然你现在可以很容易地租用这样的服务器,但它需要很高的成本,从而也会将很多潜在的使用者拒之门外。如果它只需要 CPU 而不需要外部依赖就能工作,情况会好很多。

▌选择合适的语言

如果你询问数据科学家或者那些有神经网络实践经验的工作者,几乎所有人都会建议你使用 Python 语言来解决机器学习任务。考虑到语言社区,可用库的数量,语言的简单性等,Python 语言确实是一个明智的选择。此外,在 Python 中,你还可以通过一些精彩的实例说明和文档来找到一些受欢迎的人脸识别库。

然而,这一次,我决定选用 Go 语言,主要有几以下几个原因:

我的论坛是用 Go 语言编写的,我个人也真的很喜欢以 single-binary 为后端所带来的便捷性。因此,在后端部署并整合人脸识别过程,而不需要 Python 实现的一些依赖和 IPC,这是很棒的。

Go 语言通常比 Python 更快,消耗的内存更少。任何高性能 Python 库的关键部分都是用 C / C++ 语言编写的,因此,无论如何你都会有 Python VM 的开销。我偏爱于更快的语言,除非这种语言会严重影响开发时间。我不会用 C或C++ 作为 Web 应用程序编写的主要语言,但 Go语言很好,它几乎和 Python 一样简单。

我没有在 Go 语言中找到人脸识别的有关库,因此用 Go 语言实现这样一个应用,对于整个社区而言,都是一件有趣又有帮助的事。

▌选择合适的框架

如前所述,神经网络以及相应的实现框架如今正被广泛地使用。仅在计算机视觉领域,可用的框架就有 Caffe,Torch,TensorFlow 等。

但是,有一个非常酷的机器学习库 —— dlib 库,一下就吸引了我的注意力。首先,它是用 C ++ 语言编写的,因此你可以使用 cgo 轻松地创建 Go 语言绑定。其次,在 Wild benchmarks 基准的人脸识别任务上,据说它能实现 99.38% 的准确性,这听起来是很不可思议的。再者,现在一些流行的人脸识别库 face_recognition 和 openface 在底层都使用 dlib 库,因此它在该任务上会是一个非常好的选择。

▌安装依赖项

一旦框架确定下来,那么我们要如何在机器上开发并部署这个项目呢?首先,C++ 依赖项的安装将会有很大的困难,因为你无法通过简便的“go get”或“pip install”命令来实现。要么只能希望你的操作系统存储库中提供这些依赖库,要么你只能通过繁琐的编译过程来安装,这样的话,这个问题就更加令人讨厌,因为有许多人都在 dlib 编译过程碰到问题。

如果你不得不通过编译过程来安装,那么可以参考一下下面的教程,也许会有帮助

https://gist.github.com/ageitgey/629d75c1baac34dfa5ca2a1928a7aeaf

幸运的是,我们有更好的选择:如果用户的目标系统已知,我们可以构建 dlib 库的二进制安装包来大大简化整个过程。说到服务器软件,Ubuntu 几乎是系统标配,因此首先要保证你能支持这个系统。

Ubuntu的标准仓库中自带有 dlib库,但其版本太旧了:人脸识别仅支持 dlib19.3 版本,所以我们需要构建自己的包。我为 Ubuntu 16.04 和 18.04 创建了 PPA (自定义存储库),安装过程非常简单,如下:

sudoadd-apt-repositoryppa:kagamih/dlibsudoapt-getupdatesudoapt-getinstalllibdlib-dev

以上命令将安装最新的 dlib19.15 版本及 Intel 的数学核心库,对于 Intel 处理器而言,这似乎是标准 BLAS 和 LAPACK 接口的最快实现。

对于 Debian sid 和 Ubuntu 18.10 (尚未发布) 而言,标准仓库中同样提供了 dlib 的安装过程,你只需要如下命令:

sudoapt-getinstalllibdlib-devlibopenblas-dev

这将使用 OpenBLAS 来代替 MKL,实现的速度同样非常快。或者,你也可以通过 enable non-free package 并安装 libmkl-dev 来实现。

我们还需要 libjpeg 来加载 JPEG 图像:在 Ubuntu 上安装 libjpeg-turbo8-dev 包,或在 Debian 上安装 libjpeg62-turbo-dev。

到目前为止,我没有给出其他系统的安装说明,如果你在安装 dlib 过程中碰到问题,可以访问我的 github 希望能为你提供合理有效的安装建议。

GitHub 地址:

https://github.com/Kagami/go-face

此外,我还考虑为 dlib 库提供 Docker 镜像 (其中有少部分内容已存在),许多具有复杂依赖关系的项目都倾向于使用这种分布式方法。但在我看来,一个本机包能够为用户提供更好的体验,你不需要在控制台编写长命令,也不需要处理 sandbox 环境中的内容。

▌写入依赖库

当前人脸识别库地工作原理通常是:通过为照片上的每张人脸返回一组数字 (矢量嵌入或描述符) 来比较区分它们,并通过比较这些数字来找到图像中人的名字 (通常是通过计算欧几里德距离向量,得到属于同一个人的两张人脸的最小距离)。这个概念这次就不在这里赘述了。

创建图像中人脸的原始代码并不是个重要的问题,这个过程几乎是遵循官方的例子就可以了。你可以查看 facerec.cc 及其相应的头文件 facerec.h,其中定义了 5 个函数和几个在 Go 语言和 dlib 库之间的交互结构。

在这里,虽然 dlib 库支持所有流行的图像格式,但它只能从文件中加载它们。这将导致混乱,因为我们通常只会将图像保存在内存中并将其写入临时文件。因此,在这里我使用 libjpeg 来编写自己的图像加载器。由于大多数照片都以该格式存储的,因此这种格式的加载器足以胜任大部分的需要,以后有需要我还会添加其他格式的图像加载器。

我把 C++ 和 Go 语言的连接层放在 face.go 中。它提供了 Face 结构,用于保存图像中人脸的坐标及其描述符,并通过 Recognizer 为所有操作提供接口,如初始化和实际识别。

一旦我们有了描述符,我们能做什么呢?在最简单的情况下,你可以通过比较未知描述符与所有已知描述符之间的欧几里德距离。但这并不完美,即使是当前最先进的人脸识别技术也会得到错误的答案。如果想稍微改善一下结果,我们需要使用每个人的许多图像,并检查这些图像中是否有非常接近于所提供的人脸。

这也正是分类器 classify.cc 所做的工作。首先,计算距离,然后对这些距离进行排序,计算同一个人在前 10 个最小距离中的点击数。)

诸如支持向量机,将会在这个任务上提供更好的算法性能。 dlib 甚至为训练此类模型提供了便捷的 API。很少有文章会提到 SVM 在大型数据集上的性能,因此我打算先在大型集合上测试它。

▌使用

下面得到的结果你可以在 github 中查看:

import"github.com/Kagami/go-face"

GitHub 地址:

https://github.com/Kagami/go-face

相关的所有结构和方法概述,请参阅 GoDoc 文档,主要包括以下几个内容:

初始化识别器

识别所有的已知图像并收集描述符

将具有相应类别的已知描述符传递给识别器

获取未知图像的描述符

对其类别进行分类

以下是一个工作示例,来说明了上述的所有步骤:

packagemainimport("fmt""log""path/filepath""github.com/Kagami/go-face")//Pathtodirectorywithmodelsandtestimages.Hereit's//assumeditpointstothe//clone.constdataDir="testdata"//Thisexampleshowsthebasicusageofthepackage:createan//recognizer,recognizefaces,classifythemusingfewknown//ones.funcmain(){//Inittherecognizer.rec,err:=face.NewRecognizer(dataDir)iferr!=nil{log.Fatalf("Can'tinitfacerecognizer:%v",err)}//Freetheresourceswhenyou'refinished.deferrec.Close()//Testimagewith10faces.testImagePristin:=filepath.Join(dataDir,"pristin.jpg")//Recognizefacesonthatimage.faces,err:=rec.RecognizeFile(testImagePristin)iferr!=nil{log.Fatalf("Can'trecognize:%v",err)}iflen(faces)!=10{log.Fatalf("Wrongnumberoffaces")}//Fillknownsamples.Intherealworldyouwouldusealotof//imagesforeachpersontogetbetterclassificationresults//butinourexamplewejustgetthemfromonebigimage.varsamples[]face.Descriptorvarcats[]int32fori,f:=rangefaces{samples=append(samples,f.Descriptor)//Eachfaceisuniqueonthatimagesogoestoitsown//category.cats=append(cats,int32(i))}//Namethecategories,i.e.peopleontheimage.labels:=[]string{"Sungyeon","Yehana","Roa","Eunwoo","Xiyeon","Kyulkyung","Nayoung","Rena","Kyla","Yuha",}//Passsamplestotherecognizer.rec.SetSamples(samples,cats)//Nowlet'strytoclassifysomenotyetknownimage.testImageNayoung:=filepath.Join(dataDir,"nayoung.jpg")nayoungFace,err:=rec.RecognizeSingleFile(testImageNayoung)iferr!=nil{log.Fatalf("Can'trecognize:%v",err)}ifnayoungFace==nil{log.Fatalf("Notasinglefaceontheimage")}catID:=rec.Classify(nayoungFace.Descriptor)ifcatID< 0 {    log.Fatalf("Can't classify")  }  // Finally print the classified label. It should be "Nayoung".  fmt.Println(labels[catID])}

运行下面命令:

mkdir-p~/go&&cd~/go#Orcdtoyour$GOPATHmkdir-psrc/go-face-example&&cdsrc/go-face-examplegitclonehttps://github.com/Kagami/go-face-testdatatestdataeditmain.go#Pasteexamplecodegoget.../../bin/go-face-example

由于在 dlib 的代码中大量使用了 C++ 模板,因此需要一些时间来编译 go-face (在我的 i7 上大约需要运行 1 分钟)。 幸运的是,Go 语言能够构建输出缓存,这样可以在今后构建的时候速度更快。

上面的示例输出应打印“Nayoung”,表示能够正确识别出未知图像。

▌模型

go-face 需要 shape_predictor_5_face_landmarks.dat 和

dlib_face_recognition_resnet_model_v1.dat 模型才能开始工作。你可以从 dlib-models 仓库中下载它们:

mkdirmodels&&cdmodelswgethttps://github.com/davisking/dlib-models/raw/master/shape_predictor_5_face_landmarks.dat.bz2bunzip2shape_predictor_5_face_landmarks.dat.bz2wgethttps://github.com/davisking/dlib-models/raw/master/dlib_face_recognition_resnet_model_v1.dat.bz2bunzip2dlib_face_recognition_resnet_model_v1.dat.bz2

此外,当你要运行示例代码时,还可以通过 go-face-testdata 仓库来访问这些模型。

▌未来的工作

我对结果非常满意,通过简单的 API,得到不错的识别结果,还可以轻松嵌入到 Go 的应用程序中。当然,还有需要改进的地方:

为了追求简单性和速度,在创建描述符时,go-face 无法对图像进行一些预处理,如抖动。但是,增加图像预处理操作是很有必要的,因为它可能会提高识别的性能。

Dlib 库支持很多图像格式 (如 JPEG,PNG,GIF,BMP,DNG),但是 go-face 目前只能实现 JPEG 格式,未来的工作我们希望可以支持更多的格式。

正如 dlib 的作者 Davis 所建议的,相比于搜索最小距离,采用多类 SVM 可能会得到更好的分类结果,因此还需要进行额外的测试验证。

在 go-face 中,除非真的需要,不然我尽量不复制值,但实际上它还测试过大样本 (10,000+人脸数据集) 的测试性能,可能存在一些瓶颈,有待日后完善。

从人脸提取特征向量是一个强大的概念,因为你不需要收集自己的训练数据,这也是一项非常艰巨的任务 (Davis 曾提到创建 dlib 中 ResNet 模型所用到的 300 万张人脸数据集),但为了获得更高的识别性能这可能也是无法避免的,因此值得为自己模型的训练提供相应的工具。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 人脸识别
    +关注

    关注

    76

    文章

    4002

    浏览量

    81626
  • python
    +关注

    关注

    54

    文章

    4763

    浏览量

    84338

原文标题:你们都用 Python 做人脸识别,我就偏要用 Go!

文章出处:【微信号:AI_Thinker,微信公众号:人工智能头条】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何运用Go语言实现人脸识别

    但是,有一个非常酷的机器学习库 —— dlib 库,一下就吸引了我的注意力。首先,它是 C ++ 语言编写的,因此你可以使用 cgo 轻松地创建 Go 语言绑定。其次,在 Wild
    的头像 发表于 08-23 09:41 1.3w次阅读

    C语言实现:见缝插针游戏!代码思路+源码分享

    见缝插圆我们昨天已经C语言实现了,今天将实现一个见缝插针的游戏。
    发表于 12-05 11:02 688次阅读

    verilog语言实现电子钟

    各位大神求救啊verilog语言实现电子钟
    发表于 05-04 16:37

    基于FPGA的图像边缘检测系统设计,VHDL语言实现怎么做

    不知道有没有大神做过:基于FPGA的图像边缘检测系统设计,VHDL语言实现
    发表于 05-10 00:22

    如何用C语言实现OOP编程?

    老大看到OOP编程很好,就让我学,怎么C语言实现OOP编程的,请大侠指点
    发表于 10-30 03:45

    【AI技能解析】人脸识别怎么做到的?

    识别支付场景】人脸识别这么火,那么它到底是怎么实现的呢?看大牛为您解锁人脸识别技术中的黑科技!中
    发表于 03-16 11:25

    JAVA语言实现RSA公钥密码算法

    JAVA语言实现RSA公钥密码算法:本文阐述了公开密钥密码体制RSA算法的原理及实现技术。并在此基础上,给出了JAVA语言实现的RSA算法源代码。关键词:ILSA体制;公钥;密钥
    发表于 02-10 10:27 58次下载

    VHDL语言实现3分频电路

    VHDL语言实现3分频电路 标签/分类: 众所周知,分频器是FPGA设计中使用频率非常高的基本设计之一,尽管在目前大部分设计中,广泛使用芯片厂家集成的锁相
    发表于 08-21 15:28 5670次阅读

    C语言实现DES算法

    C语言实现DES算法 本DES算法,使用了效率很高的C完成。目前,国内知名企业的POS终端中,单DES算法,均是采用这个函数完成。函数经本站验证过,可以
    发表于 01-16 10:09 3257次阅读

    C语言实现FFT算法

    C语言实现FFT算法 /*****************fft programe*********************/#include "typedef.h" #include "math.h" struct compx EE(struct compx
    发表于 10-30 13:39 6320次阅读

    C语言实现数字滤波

    C语言实现数字滤波 。对数值进行精度调整,下面给出几种常用的数字滤波方法的C语言函数,这些函数有一定的通用性,Turbo C 2.0编制而成,在研华IPC-610/386机上均编译
    发表于 07-26 15:44 10次下载

    go语言枚举类型怎么

    go 语言枚举类型是这么的?在什么场景下会用到枚举?本文对 go 语言枚举做了详细讲解。 枚举,是一种重要的数据类型,由一组键值对组成,通
    的头像 发表于 09-02 09:43 5129次阅读

    go语言实现的简单im即时通信系统

      本文介绍了一个 go 语言实现的简单 im 即时通信系统。 简介 纯go实现的im即时通讯系统,各层可单独部署,之间通过rpc通讯,支持集群,github地址 https
    的头像 发表于 10-20 16:02 3598次阅读

    累加校验和C语言实现

    累加校验和C语言实现
    发表于 11-29 18:06 10次下载
    累加校验和C<b class='flag-5'>语言实现</b>

    怎么C语言实现多态

    这里我想主要介绍下在C语言中是如何实现的面向对象。知道了C语言实现面向对象的方式,我们再联想下,C++中的class的运行原理是什么?
    的头像 发表于 10-12 09:12 1968次阅读