前言

基于深度学习的人脸识别系统,一共用到了5个开源库:OpenCV(计算机视觉库)、Caffe(深度学习库)、Dlib(机器学习库)、libfacedetection(人脸检测库)、cudnn(gpu加速库)。

用到了一个开源的深度学习模型:VGG model。

最终的效果是很赞的,识别一张人脸的速度是0.039秒,而且最重要的是:精度高啊!!!

CPU:intel i5-4590

GPU:GTX 980

系统:Win 10

OpenCV版本:3.1(这个无所谓)

Caffe版本:Microsoft caffe (微软编译的Caffe,安装方便,在这里安利一波)

Dlib版本:19.0(也无所谓

CUDA版本:7.5

cudnn版本:4

libfacedetection:6月份之后的(这个有所谓,6月后出了64位版本的)

这个系列纯C++构成,有问题的各位朋同学可以直接在博客下留言,我们互相交流学习。

====================================================================

本篇是该系列的第四篇博客,介绍如何使用CUBLAS加速进行两个向量间余弦距离的计算。

思路

我们先来温习一下两个向量之间余弦距离的数学公式,大家自己可以回忆一下:



x,y均为同维度的向量,如果为6400维,那么我们可以将式子进行展开:



为什么这里我们要用余弦距离,而不用欧式距离?

余弦距离使用两个向量夹角的余弦值作为衡量两个个体间差异的大小。相比欧氏距离,余弦距离更加注重两个向量在方向上的差异。(摘自http://www.cnblogs.com/chaosimple/archive/2013/06/28/3160839.html

我们使用余弦距离能够更好的反映两个人脸向量之间的相似度。

实现

这里我们可以先实现一个,不使用CUDA加速的版本。

ComputeDistance.h:

  1. #include <vector>
  2. #include <assert.h>
  3. float cosine(const vector<float>& v1, const vector<float>& v2);

ComputeDistance.cpp:(提供一个总的接口)

  1. #include <ComputeDistance.h>
  2. using namespace std;
  3. float dotProduct(const vector<float>& v1, const vector<float>& v2)
  4. {
  5. assert(v1.size() == v2.size());
  6. float ret = 0.0;
  7. for (vector<float>::size_type i = 0; i != v1.size(); ++i)
  8. {
  9. ret += v1[i] * v2[i];
  10. }
  11. return ret;
  12. }
  13. float module(const vector<float>& v)
  14. {
  15. float ret = 0.0;
  16. for (vector<float>::size_type i = 0; i != v.size(); ++i)
  17. {
  18. ret += v[i] * v[i];
  19. }
  20. return sqrt(ret);
  21. }
  22. float cosine(const vector<float>& v1, const vector<float>& v2)
  23. {
  24. assert(v1.size() == v2.size());
  25. return dotProduct(v1, v2) / (module(v1) * module(v2));
  26. }

这里的目的是输入vector< float> x, vector< float> y 进行计算,我们使用上一篇博客中提取人脸向量的代码来进行测试,看其运行时间。

main函数:

  1. Caffe_Predefine();
  2. Mat lena = imread("lena.jpg");
  3. Mat test = imread("test.jpg");
  4. resize(lena, lena, Size(224, 224));
  5. resize(test, test, Size(224, 224));
  6. if (!lena.empty()&&!test.empty())
  7. {
  8. vector<float> lena_vector = ExtractFeature(lena);
  9. vector<float> test_vector = ExtractFeature(test);
  10. clock_t t1, t2;
  11. t1 = clock();
  12. cout << "余弦距离为:" << cosine(lena_vector, test_vector) << endl;
  13. t2 = clock();
  14. cout << "计算耗时" << t2 - t1 << "ms" << endl;
  15. }
  16. imshow("LENA", lena);
  17. imshow("TEST", test);
  18. waitKey(0);

运行结果:



但是在真实应用中,我们必须要求计算的高速度。这里可以这样来考虑:其一是通过多线程,当有很多人需要进行匹配时,每个线程都进行与测试向量的距离计算。其二是本身人脸向量计算的时候就需要先加速,这里我们先使用CUBLAS来尝试对cosine函数进行加速。

CUBLAS

cublas是一个开源的矩阵加速运算库,它使用更为优秀的浮点运算设备GPU来对线性运算进行加速。因为余弦公式(上面有),我们需要做的核心数学公式及为向量点乘(向量的模可以看成是向量自己对自己的点乘然后再开方):



值得一提的是,CUBLAS为我们提供好了这样一个函数:cublasSdot(即为cublasSdot_v2)

  1. cublasSdot_v2 (cublasHandle_t handle,int n,const float *x,int incx,const float *y,int incy,float *result);

n代表的是输入向量的维度,x是第一个向量,y是第二个向量,incx 与incy 取1,result 是点积结果。

我们在配置Caffe的过程中,早已经把cublas的库添加了。所以我们新建一个cpp,在文件里包含

  1. #include <stdlib.h>
  2. #include <time.h>
  3. #include <iostream>
  4. #include "cuda_runtime.h"
  5. #include "cublas_v2.h"
  6. using namespace std;
  7. cublasStatus_t ret;
  8. cublasHandle_t handle_cos;

即可,做一个小测试。

如何撰写这个求余弦的公式?一个直观的感受即为:

  1. float Cosine(float* a, float* b, float *result,float *a_result,float *b_result,int channel)
  2. {
  3. cublasSdot(handle_cos, channel, a, 1, b, 1, result);
  4. cublasSdot(handle_cos, channel, a, 1, a, 1, a_result);
  5. cublasSdot(handle_cos, channel, b, 1, b, 1, b_result);
  6. return *result/(sqrt(*b_result)*sqrt(*a_result));
  7. }

我们的主函数:

  1. int main()
  2. {
  3. int arraySize = 10000;
  4. float* a = (float*)malloc(sizeof(float) * arraySize);
  5. float* d_a;
  6. cudaMalloc((void**)&d_a, sizeof(float) * arraySize);
  7. for (int i = 0; i<arraySize; i++)
  8. a[i] = 1.0f;
  9. cudaMemcpy(d_a, a, sizeof(float) * arraySize, cudaMemcpyHostToDevice);
  10. float* result = (float*)malloc(sizeof(float));
  11. float* a_result = (float*)malloc(sizeof(float));
  12. float* b_result = (float*)malloc(sizeof(float));
  13. ret = cublasCreate(&handle_cos);
  14. clock_t t1, t2;
  15. t1 = clock();
  16. cout << Cosine(d_a, d_a, result, a_result, b_result, arraySize) << endl;
  17. t2 = clock();
  18. cout << t2 - t1<<"ms"<<endl;
  19. //printf("\n\nCUBLAS: %.3f", *cb_result);
  20. cublasDestroy(handle_cos);
  21. cin.get();
  22. }

这里我们算了一个10000维向量的点积(自己乘自己),计算速度为0ms(应该是可以看比毫秒精度更高的时间单位的,大家可以自己试试):



使用CUBLAS,我们可以获得很快速的两个向量之间求点积的解决方案。其实事实上,比起两个向量之间求点积的速度,我们更为重要的,是如何求解一个向量与多个向量求余弦距离的优化方法。在之后的几章会对这个问题进行讨论。

=================================================================

基于深度学习的人脸识别系统系列(Caffe+OpenCV+Dlib)——【四】使用CUBLAS加速计算人脸向量的余弦距离 完结,如果在代码过程中出现了任何问题,直接在博客下留言即可,共同交流学习。

基于深度学习的人脸识别系统系列(Caffe+OpenCV+Dlib)——【四】使用CUBLAS加速计算人脸向量的余弦距离的更多相关文章

  1. 基于深度学习的人脸识别系统(Caffe+OpenCV+Dlib)【一】如何配置caffe属性表

    前言 基于深度学习的人脸识别系统,一共用到了5个开源库:OpenCV(计算机视觉库).Caffe(深度学习库).Dlib(机器学习库).libfacedetection(人脸检测库).cudnn(gp ...

  2. 基于深度学习的人脸识别系统(Caffe+OpenCV+Dlib)【三】VGG网络进行特征提取

    前言 基于深度学习的人脸识别系统,一共用到了5个开源库:OpenCV(计算机视觉库).Caffe(深度学习库).Dlib(机器学习库).libfacedetection(人脸检测库).cudnn(gp ...

  3. 基于深度学习的人脸识别系统(Caffe+OpenCV+Dlib)【二】人脸预处理

    前言 基于深度学习的人脸识别系统,一共用到了5个开源库:OpenCV(计算机视觉库).Caffe(深度学习库).Dlib(机器学习库).libfacedetection(人脸检测库).cudnn(gp ...

  4. 基于深度学习的中文语音识别系统框架(pluse)

    目录 声学模型 GRU-CTC DFCNN DFSMN 语言模型 n-gram CBHG 数据集 本文搭建一个完整的中文语音识别系统,包括声学模型和语言模型,能够将输入的音频信号识别为汉字. 声学模型 ...

  5. 【原创 深度学习与TensorFlow 动手实践系列 - 4】第四课:卷积神经网络 - 高级篇

    [原创 深度学习与TensorFlow 动手实践系列 - 4]第四课:卷积神经网络 - 高级篇 提纲: 1. AlexNet:现代神经网络起源 2. VGG:AlexNet增强版 3. GoogleN ...

  6. 【OCR技术系列之四】基于深度学习的文字识别(3755个汉字)

    上一篇提到文字数据集的合成,现在我们手头上已经得到了3755个汉字(一级字库)的印刷体图像数据集,我们可以利用它们进行接下来的3755个汉字的识别系统的搭建.用深度学习做文字识别,用的网络当然是CNN ...

  7. 【OCR技术系列之四】基于深度学习的文字识别

    上一篇提到文字数据集的合成,现在我们手头上已经得到了3755个汉字(一级字库)的印刷体图像数据集,我们可以利用它们进行接下来的3755个汉字的识别系统的搭建.用深度学习做文字识别,用的网络当然是CNN ...

  8. 基于深度学习的回声消除系统与Pytorch实现

    文章作者:凌逆战 文章代码(pytorch实现):https://github.com/LXP-Never/AEC_DeepModel 文章地址(转载请指明出处):https://www.cnblog ...

  9. VulDeePecker:基于深度学习的脆弱性检测系统

    最近的两款软件,VUDDY和VulPecker,假阴性率高而假阳性率低,用于检测由代码克隆引发的漏洞.而如果用于非代码克隆引起的漏洞则会出现高误报率. 本文使用深度学习处理程序中的代码片段,不应由专家 ...

随机推荐

  1. 网站平台的favicon.ico的logo

        <link rel="shortcut icon" href="http://www.uuop.com/icotemp/2017061703035984/f ...

  2. 【hdu 6038】Function

    [Link]:http://codeforces.com/contest/834/problem/C [Description] 给你两个排列a和b; a排列的长度为n,b排列的长度为m; a∈[0. ...

  3. 玩转阿里云server——安装WebserverTomcat7

    1. 以root用户身份登录阿里云server 2. 使用apt-get install安装Tomcat7 sudo apt-get install tomcat7 3.安装后.Tomcat在启动时报 ...

  4. Android模拟、实现、触发系统按键事件的方法

     Android模拟.实现.触发系统按键事件的方法 /** * 模拟系统按键. * * @param keyCode */ public static void onKeyEvent(final ...

  5. nyist oj 1058 部分和问题 (DFS搜索)

    部分和问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描写叙述 给定整数a1.a2........an.推断能否够从中选出若干数,使它们的和恰好为K. 输入 首先,n和k ...

  6. 记号(notation)的学习

    数学的记号(notation) 记号具体代表什么含义,取决于你的定义: 比如这样的 d⃗  一个向量,每个分量 d(i) 表示的是从初始结点 v 到当前节点 vi 的最短路径:也即这样的一个向量的每一 ...

  7. DTU(用于将串口数据转换为IP数据或将IP数据转换为串口数据通过无线通信网络进行传送的无线终端设备)

    DTU (Data Transfer unit),是专门用于将串口数据转换为IP数据或将IP数据转换为串口数据通过无线通信网络进行传送的无线终端设备.DTU广泛应用于气象.水文水利.地质等行业.

  8. 洛谷 P1598 垂直柱状图

    P1598 垂直柱状图 题目描述 写一个程序从输入文件中去读取四行大写字母(全都是大写的,每行不超过72个字符),然后用柱状图输出每个字符在输入文件中出现的次数.严格地按照输出样例来安排你的输出格式. ...

  9. C 字符/字符串经常使用函数

    string.h中经常使用函数 char * strchr(char * str ,char ch); 从字符串str中查找首次出现字符ch的位置,若存在返回查找后的地址.若不存在则返回NULL vo ...

  10. linux又一次编译安装gd,添加freetype支持,解决验证码不显示问题,Fatal error: Call to undefined function imagettftext()

    问题: Fatal error: Call to undefined function Think\imagettftext() in /var/www/webreg/ThinkPHP/Library ...