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

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

全文约2700字,读完大概需要这首歌的时间:




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

作者 | Kagami Hiiragi

译者 | linstancy

编辑 | Jane

出品 | AI科技大本营

前言

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

最近,我用一个以 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 (自定义存储库),安装过程非常简单,如下:



sudo add-apt-repository ppa:kagamih/dlib
sudo apt-get update
sudo apt-get install libdlib-dev



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

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

sudo apt-get install libdlib-dev libopenblas-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 文档,主要包括以下几个内容:

  • 初始化识别器

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

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

  • 获取未知图像的描述符

  • 对其类别进行分类

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

package main
import (
  "fmt"
  "log"
  "path/filepath"
  "github.com/Kagami/go-face"
)
// Path to directory with models and test images. Here it's
// assumed it points to the
// <https://github.com/Kagami/go-face-testdata> clone.
const dataDir = "testdata"
// This example shows the basic usage of the package: create an
// recognizer, recognize faces, classify them using few known
// ones.
func main() {
  // Init the recognizer.
  rec, err := face.NewRecognizer(dataDir)
  if err != nil {
    log.Fatalf("Can't init face recognizer: %v", err)
  }
  // Free the resources when you're finished.
  defer rec.Close()
  // Test image with 10 faces.
  testImagePristin := filepath.Join(dataDir, "pristin.jpg")
  // Recognize faces on that image.
  faces, err := rec.RecognizeFile(testImagePristin)
  if err != nil {
    log.Fatalf("Can't recognize: %v", err)
  }
  if len(faces) != 10 {
    log.Fatalf("Wrong number of faces")
  }
  // Fill known samples. In the real world you would use a lot of
  // images for each person to get better classification results
  // but in our example we just get them from one big image.
  var samples []face.Descriptor
  var cats []int32
  for i, f := range faces {
    samples = append(samples, f.Descriptor)
    // Each face is unique on that image so goes to its own
    // category.
    cats = append(cats, int32(i))
  }
  // Name the categories, i.e. people on the image.
  labels := []string{
    "Sungyeon", "Yehana", "Roa", "Eunwoo", "Xiyeon",
    "Kyulkyung", "Nayoung", "Rena", "Kyla", "Yuha",
  }
  // Pass samples to the recognizer.
  rec.SetSamples(samples, cats)
  // Now let's try to classify some not yet known image.
  testImageNayoung := filepath.Join(dataDir, "nayoung.jpg")
  nayoungFace, err := rec.RecognizeSingleFile(testImageNayoung)
  if err != nil {
    log.Fatalf("Can't recognize: %v", err)
  }
  if nayoungFace == nil {
    log.Fatalf("Not a single face on the image")
  }
  catID := rec.Classify(nayoungFace.Descriptor)
  if catID < 0 {
    log.Fatalf("Can't classify")
  }
  // Finally print the classified label. It should be "Nayoung".
  fmt.Println(labels[catID])
}



运行下面命令:

mkdir -p ~/go && cd ~/go  # Or cd to your $GOPATH
mkdir -p src/go-face-example && cd src/go-face-example
git clone https://github.com/Kagami/go-face-testdata testdata
edit main.go  # Paste example code
go get .
../../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 仓库中下载它们:

mkdir models && cd models
wget https://github.com/davisking/dlib-models/raw/master/shape_predictor_5_face_landmarks.dat.bz2
bunzip2 shape_predictor_5_face_landmarks.dat.bz2
wget https://github.com/davisking/dlib-models/raw/master/dlib_face_recognition_resnet_model_v1.dat.bz2
bunzip2 dlib_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 万张人脸数据集),但为了获得更高的识别性能这可能也是无法避免的,因此值得为自己模型的训练提供相应的工具。

原文链接:

https://hackernoon.com/face-recognition-with-go-676a555b8a7e

BTA六折早鸟票倒计时进行中


扫码抢票

2018年9月13-14日,区块链技术及应用峰会(BTA)·中国将于上海再度乘势来袭!

汇集100+区块链技术领导人物、100+区块链投资大咖、100+技术&财经媒体、1000+区块链技术爱好者,深挖区块链前沿技术及落地实践。

六折早鸟票倒计时进行中,锁定申城,年中超豪华干货空投,等你来抢。

你们都用 Python 做人脸识别,我就偏要用 Go!相关推荐

  1. 用python做人脸识别_用Python实现一个简单的人脸识别,原来我和这个明星如此相似...

    近几年来,兴起了一股人工智能热潮,让人们见到了AI的能力和强大,比如图像识别,语音识别,机器翻译,无人驾驶等等.总体来说,AI的门槛还是比较高,不仅要学会使用框架实现,更重要的是,需要有一定的数学基础 ...

  2. python人脸识别门禁_用Python做人脸识别

    之前用facenet做了一个人脸识别的Demo,所以在此记录一下. 但因为我的水平十分有限,疏漏之处请多见谅. 1,这个流程大致是先用mtcnn检测人脸位置,得到一个人脸的bounding box. ...

  3. python如何做考勤_python基础教程:face++与python实现人脸识别签到(考勤)功能

    @本文来源于公众号:csdn2299,喜欢可以关注公众号 程序员学府 这篇文章主要为大家详细介绍了face++与python实现人脸识别签到(考勤)功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一 ...

  4. python人脸识别训练模型_开源 | 基于Python的人脸识别:识别准确率高达99.38%!

    原标题:开源 | 基于Python的人脸识别:识别准确率高达99.38%! 该库使用 dlib 顶尖的深度学习人脸识别技术构建,在户外脸部检测数据库基准(Labeled Faces in the Wi ...

  5. python百度人脸识别_python 与 百度人脸识别api

    用python来做人脸识别代码量少 思路清晰, 在使用之前我们需要在我们的配置的编译器中通过pip       install baidu-aip  即可 from aip import AipFac ...

  6. 刷脸签到python代码_背景提升|“刷脸”时代,如何运用Python实现人脸识别?

    打开手机,不用输入任何密码,通过"刷脸"就可以轻松打开界面; 走进一家餐厅,即便没有手机和钱包,点餐后就能通过"刷脸"完成支付; 去银行取款,不带银行卡.身份证 ...

  7. 刷脸签到python代码_背景提升 | “刷脸”时代,如何运用Python实现人脸识别?

    打开手机,不用输入任何密码,通过"刷脸"就可以轻松打开界面; 走进一家餐厅,即便没有手机和钱包,点餐后就能通过"刷脸"完成支付; 去银行取款,不带银行卡.身份证 ...

  8. 基于Python的人脸识别课堂考勤系统(毕设)

    一个菜鸟搞毕业设计的过程分享,可能对迷茫的你起到一点点作用! 序言 在着手开发项目之前我们一定要对系统进行一个初步的规划,比如系统可以实现什么功能,是否需要开发GUI页面(大部分导师都会让你搞一个,仅 ...

  9. 基于python opencv人脸识别的签到系统

    基于python opencv人脸识别的签到系统 前言 先看下效果 实现的功能 开始准备 页面的构建 功能实现 代码部分 总结 前言 一个基于opencv人脸识别和TensorFlow进行模型训练的人 ...

最新文章

  1. JAVA用最简单的方法来构建一个高可用的服务端,提升系统可用性
  2. 2019微生物组—宏基因组分析技术研讨会第六期
  3. 一份邀请函引发的中国芯片新猜想
  4. Android应用程序键盘(Keyboard)消息处理机制分析(3)
  5. Variational Inference
  6. linux PCB数组,Linux中的系统IO函数
  7. C#中的命名空间和程序集
  8. DirectX12(D3D12)基础教程(五)——理解和使用捆绑包,加载并使用DDS Cube Map
  9. 隐私信息检索(隐匿查询)
  10. 网络嗅探器(影音神探) 4.73
  11. 解决transition与fadeIn,fadeOut冲突问题
  12. php设置个性域名,利用nginx泛域名解析配置二级域名和多域名,实现二级域名子站,用户个性独立子域名。...
  13. 【AAC 系列一】Android 应用架构新时代来临!
  14. 盘点8个高效方法提高睾酮水平
  15. 叮咚~ 你有一份令人心动的offer待查收【cv君独家内推】
  16. 如果不明白该用组合关系还是依赖关系,就来看这一篇!
  17. 一个小兔子的大数据见解2
  18. 快速扫盲 | 霍尔传感器的工作原理
  19. IPaddr和IPaddr2的区别
  20. STM32CubeIDE 利用LL库 SysTick简单实现hcsr04超声波测距

热门文章

  1. linux socket 混杂模式,设置混杂模式的例子
  2. 解决ajax在chrome中正常,在IE中不正常的问题
  3. 质量管理老大难,企业如何迅速提高品质保障能力?
  4. java String类型转化为Int类型
  5. 路飞学城项目-前期准备
  6. 【转】UIPopoverController的使用
  7. c#获取autocad安装位置_Robotstudio软件二次开发:基于C#语言的Smart组件开发基础
  8. 暖暖环游世界显示服务器异常502,暖暖环游世界连接服务器失败 连接不上网络怎么办...
  9. PHP—利用cookie实现七天免登录
  10. QVariant与自定义类型互转之奇巧淫技