2019-周报7

本周解决了之前编码丢帧的问题。将原来测试中的单路解码根据项目需求改为双路解码,但由于ffmpeg的解码方式,可能造成两路解码帧的不同步,便会造成后续拼接部分的错位。总体来说大的主框架已经完成,但还有很多细节的部分需要调试。目前拼接使用的上下分割的拼接方式,隔行拼接计算量更大,且 UV 数据的处理还未找到解决方法。

除此之外阅读了 Geoffrey Hinton 关于模型简化的论文 Distilling the knowledge in a neural network ,论文中使用复杂模型来训练简单模型,使简单模型具有复杂模型的性能,从而达到简化模型结构的目的。

1 视频编解码

上次实验之所以有丢帧的现象是因为没有没有清洗(flush the decoder/encoder) 编解码器。在解码的时候,将所有编码数据全部送到解码器之后,在结束前需要调用avcodec_send_packet(dec_ctx, NULL)往解码器输入 NULL 将解码器中剩余的帧”冲洗”出来,编码同理。

1.1 双路解码一路编码

前面说到,ffmpeg使用以下四个函数进行编解码:

  • avcodec_send_frame
  • avcodec_receive_packet
  • avcodec_send_packet
  • avcodec_receive_frame

但是这几个函数的使用并不是很有规律地进行。比如avcodec_send_packetavcodec_receive_frame配合使用完成解码功能。调试发现,两个函数并非严格地交替执行,执行情况根据具体的编码视频不同而不相同。所以在双路解码时不能仅仅通过对以上两个解码函数使用上的同步而达到对解码后帧的同步。实际操作中,通过对两路解码状态的监测实现双路解码的同步。

1.2 编解码工作计划

基本完成了deepwater.exe inputA inputB output形式的可执行程序的主要内容,内部调用NVIDIA的编解码器进行编解码操作。根据之前的测试结果,奇偶分割或者上下分割两种方式,在未加去隔行处理的情况下表现差异不大,且均达到肉眼不可分的清晰度。但是YUV420P格式在奇偶分割的处理中存在着 UV 分量不可分的情况。

除了以上提到的内容,对项目进一步的工作安排还不是太清楚。

2 提炼模型

提高模型性能的一个简单方法便是训练多个不同的模型,然后使用多个模型识别的平均值作为最总结果,但是这样会导致预测模型过于笨重,且耗费过多的计算资源。本篇文章通过特殊的训练方法从笨重的模型中提炼信息到简单模型中,从而简化模型。

2.1 实现方法

本篇文章中提到的训练方法其实比较简单。例如,当我们训练分类模型时使用的标签均为硬标签(hard targets),即所属类别处为1,其余为0。但我们实际训练模型的输出为该输入所属类别的概率(softmax)。

$$
q_i = \frac{exp(z_i/T)}{\sum_jexp(z_j/T)}
$$

而我们的标签(hard targets) 中却并没有体现出该图片像其它类别的概率,也就是说我们的硬标签中包含的信息不如softmax多。于是作者使用训练之后复杂模型的输出来作为图片的标签(soft targets) 来训练简单的模型。最后得出的结果表明,虽然大大简化了模型的结构,却可以得到接近复杂模型的正确率,如下图所示。

除此之外作者还针对不同的模型给出了多种训练方法,可通过调整上式子中的温度指数$T$ 来调节概率的分布情况。且使用不同的目标函数,不同的代价函数也均能使用这种方法来简化模型。使用软标签(soft targets)训练使得训练的速度更快,仅使用原训练数据 3% 的训练量即可达到

接近原模型的测试正确率,具体指标如下图所示。

2.2 总结

以上方法的核心便是通过对训练集标签的改进,将 hard targets 改进为 soft targets。使得标签能够提供更多的信息,从而可以达到简化模型的目的,在实际部署中非常有用。

2.3 参考文献

  • Hinton, Geoffrey, Oriol Vinyals, and Jeff Dean. “Distilling the knowledge in a neural network.” arXiv preprint arXiv:1503.02531 (2015). pdf (Godfather’s Work)
Share Comments

2019-周报6

上周实验了opencv 的视频编解码功能,实验与调研结果表明opencv 对视频的编解码支持不够友好。于是决定使用ffmpeg 负责解码与编码工作,opencv 负责对解码后的数据进行处理。

本周在参考ffmpeg官方例程的基础上完成了对H265视频的解码,处理,再编码的工作。解码使用hevc-cuvid解码器,编码使用hevc-nvenc编码器,实验过程存在丢帧的现象,目前正在调试中,下面是具体的实验记录。

基于ffmpeg的HEVC编解码实验

GPU型号:GeForce GTX 1080

CUDA版本:CUDA 9.0

FFmpeg版本:ffmpeg-20180818-de1b44c-win64

IDE:Visual Studio 2015

ffmpeg不同编解码器的使用方法大体相同,使用GPU进行编解码时需要保证已安装好编解码器需要调用的底层环境。比如使用h264_qsv编解码器需要安装Intel Media SDK ,调用hevc-nvenc需要安装CUDA环境以及NVIDIA CODEC SDK,下面依次介绍ffmpeg的编解码过程。

解码流程

解码部分初始化部分相对简单,不需要设置很多复杂得参数,只需要完成相应数据的内存分配,并正确指定解码器的种类便可。

ffmepg按帧进行解码,我们的实验中每次读取4096 Byte送进解析器av_parser_parse2(),解析器会自动解析出一帧压缩的数据。配合使用avcodec_send_packet(dec_ctx, pkt)avcodec_receive_frame(dec_ctx, frame) 来解压一帧数据,下图为解压流程。

图一.解码流程

解压完一帧数据便存储于ffmpeg自定义的数据结构 frame 中,我们可以将此帧数据转换为opencv中的 MAT 类型并调用opencv中的相应函数进行处理,再将处理完成之后的数据转为ffmepgframe数据进行编码。

编码流程

相对于解码而言,编码需要设置更多的参数,更多的是对编码器的配置。且不同的编码器对应的配置存在一些差别。比如,使用hevc_nvenc 编码时 max_b_frames 参数必须设置为 0,否则会导致编码器加载失败

图2.加载失败

在调试过程中,设置 av_log_set_level(64); 可以得到很多重要的提示信息,非常有利于找到问题的原因。

编码器的其它参数设置如下:

  • c->bit_rate = 400000;
  • c->width = 1920;
  • c->high = 1080;
  • c->time_base = (AVRational) {1, 25};
  • c->framerate = (AVRational) {25, 1};
  • c->max_b_frames = 0;
  • c->pix_fmt = AV_PIX_FMT_NV20LE ;

上面可以看出,我们设置的像素存储格式不是 AV_PIX_FMT_YUV420P ,那是因为调试的过程中发现使用hevc-cuvid后的数据格式为 AV_PIX_FMT_NV20LE ,这也是YUV420P的一种,只是在ffmpeg中数据的存储方法上有些变化。

编码流程总的来说于解码类似,使用avcodec_send_frame(enc_ctx, frame) 发送一帧数据到编码器,再配合使用avcodec_receive_packet(enc_ctx, pkt) 接收编码后的数据。

整体流程

整体流程即将上面的编解码流程结合,再加上对解码后得到的每帧图像进行处理。在完成对编解码的调试后,这个过程中最主要的便是对解码后数据的处理。现在主要的问题便是想整个过程都在GPU中进行处理,避免时间浪费在数据的转移过程中。目前了解到的信息是,opencv中的数据处理可以全程在gpu中进行,但ffmpeg到opencv数据类型的转换过程还没有深入了解。

图3.整体流程

参考资料

Share Comments

2019-周报5

本周测试了OpenCV使用GPU对视频的读写显示情况,结果显示仅使用OpenCV不能很好地完成视频编码工作,综合考虑可以使用 OpenCV + FFmpeg 的方法各自完成其擅长的工作。搭建了ffmpeg + opencv 的开发环境学习了ffmpeg 最新的编解码相关API。

1 OpenCV的硬编解码测试

OpenCV 的软编解码是在在ffmpeg 的基础上实现的,能够支持几乎所有视频的解码,H264 及之前的编码。OpenCV 硬编解码则是跳过ffmpeg 直接在NVIDIA 官方的编解码包Video Codec SDK 上实现的,所以硬编解码方面仅支持NVIDIA的显卡。

之前提到,opencv在视频编解码方面支持得不是很好,在硬编解码方面则更加脆弱,对底层环境得版本及其依赖,以下是试验得过程记录。

1.1 使用OpenGL进行显示

在代码调试过程中为了实时显示视频,查看编解码效果,使用OpenGL 进行加速显示,opencv 中使用OpenGL需要单独编译。要使opencv支持OpenGL,首先得安装QT 环境,使用QT中的OpenGL模块,并在使用CMake-GUI 时勾选 with_opengl = ON with_qt = ON

但是QT官方提供的windows安装包只有32位的,并没有64位的。而若要编译支持CUDA 的opencv 必须编译 64 位得opencv,刚开始没有注意到这一点浪费了很多时间。所以在Windows环境下,如果要编译同时支持OpenGL和CUDA的opencv就必须下载QT源码编译安装64位的QT环境,再按照以下路径选择设置即可完成安装。

1
2
3
4
5
6
7
Set QT_MAKE_EXECUTABLE to D:\Qt\5.9\mingw53_32\bin\qmake.exe
Set Qt5Concurrent_DIR to D:\Qt\5.9\mingw53_32\lib\cmake\Qt5Concurrent
Set Qt5Core_DIR to D:\Qt\5.9\mingw53_32\lib\cmake\Qt5Core
Set Qt5Gui_DIR to D:\Qt\5.9\mingw53_32\lib\cmake\Qt5Gui
Set Qt5Test_DIR to D:\Qt\5.9\mingw53_32\lib\cmake\Qt5Test
Set Qt5Widgets_DIR to D:\Qt\5.9\mingw53_32\lib\cmake\Qt5Widgets
Set Qt5OpenGL_DIR to D:\Qt\5.9\mingw53_32\lib\cmake\Qt5OpenGL

1.2 解码

使用cv::cudacodec::createVideoReader(fname) 进行硬解码,解码后的数据直接存储在GPU中进行处理。但实际上这个语句的兼容性极差,前面提到opencv的硬编解码直接在NVIDIA 官方的编解码包Video Codec SDK 上实现的,这块基本属于opencv的边缘部分,很少人使用,官方针对这部分的更新也很缓慢,每当 Video Codec SDK 有了更新就很可能导致各种 Segmentation fault 。比如在使用cv::cudacodec::createVideoReader(fname)解码数据前,必须调用以下 Video Codec SDK 的函数进行初始化

1
2
3
4
5
6
7
8
9
void* hHandleDriver = 0;
CUresult res = cuInit(0, __CUDA_API_VERSION, hHandleDriver);
if (res != CUDA_SUCCESS) {
throw exception();
}
res = cuvidInit(0);
if (res != CUDA_SUCCESS) {
throw exception();
}

而opencv没有对此进行任何封装,且比较依赖当前的CUDA版本,在 CUDA8.0 时支持较好(网上调查论坛结果,没有实践,实验室电脑CUDA版本为9.0)。

使用opencv封装之后的解码函数硬解码有各种意外发生,但使用NVIDIA 官方提供的编解码例程直接调用 Video Codec SDK 能正常完成编解码。可以排除底层环境导致的原因,相关问题在 opencv 的GitHub库中的issue中也有较多的讨论。

1.3 编码

硬解码部分的支持不是很完善,硬编码部分代码更不完善,目前只支持windows平台,且不支持HEVC的编码。

1.4 总结

目前为止在opencv中能够实现的有以下部分:

  • H264,H265的cpu解码
  • 复制解码后的数据到GPU,在GPU完成拼接工作
  • H264的软编码

CUDA9.0中默认的Video Codec SDK版本使用dynlink_nvcuvid.h代替了nvcuvid.h 导致 opencv中的硬解码出现段错误,目前试验了很多方法还没有解决问题,应该可以通过单独更新 Video Codec SDK到最新的 8.1 版本解决,但为了不影响计算机中的整体环境还没有实际操作。H264,H265的硬解码理论上也是可以实现的(没有实际)。

1.5 参考资料

2 ffmpeg中的数据结构

学习一个框架从他的数据结构入手可以很清晰地了解框架的操作对象,更好地把握数据处理过程,ffmpeg使用 C 语言构建,其中的数据结构均由结构体描述,目前为止已经有超过两千种的数据结构,下面是ffmpeg编解码常用的各种结构体,涉及到网络协议,封装格式,解码器信息,视频数据等重要的存储结构。

2.1 AVFormatContext

AVFormatContext可以说是贯穿ffmpeg始终的结构体,也是包含信息最多的一个结构体。包含了输入数据缓存,视音频流,视音频流个数,文件名,视频时长,比特率,元数据等重要信息。下面介绍的很多结构均是此结构体中的子结构。

2.2 AVIOContext

AVIOContext包含于AVFormatContext中,看名字便可知道主要和文件输入输出有关。主要包含了缓存开始的位置,缓存大小,当前指针读取位置,缓存结束位置,使用的网络协议等。

2.3 编解码器信息

AVCodecContext是其中复杂度很高的结构体,其中包含了很多编解码的具体属性,如编解码器的类型(视频或音频),具体的编解码器,平均码率,帧率,采样格式等等。

AVCodec包含于AVCodecContext中,存储着具体使用的编解码器信息。

2.4 AVPacket

AVPacket主要存储了解码前的一帧数据,相对来说比较简单,除此之外还存储了数据的大小,时间戳等信息。

2.5 AVFrame

AVFrame主要存储了解码后的一帧数据以及该帧数据的相关信息,类如是否为关键帧,原始数据类型,视频的宽,高等。

2.6 相关结构的关系

下图来自雷霄骅雷神的博客,清晰地表示以上结构体之间的依赖关系

图1.ffmpeg重要结构体关系

2.7 参考资料

Share Comments

2019-周报4

本周编译了支持GPU的opencv源码(编译时间挺长的),并分别测试了使用H264,H265编码的视频读写情况。除此之外翻译了一篇pytorch官方的教程。

1 OpenCV读写H264,H265编码视频

测试了opencv读,写,拼接 H264,H265视频,下面是详细过程与结果。

1.1 读取H264,H265编码视频

分别使用opencv中的cv::VideoCapture(source) 读取 H264,H265编码后的视频,读取H264的视频一切正常,读取H265的视频整体正常,但提示丢失帧:

图1.h265-read

使用100帧H265编码视频测试发现读取正常,并没有少帧。所以,读取部分没有问题。

测试还发现,使用cv::VideoCapture(source) 读取的视频都是在cpu中进行解码处理。且解码后的帧为 BGR 数据,而不是YUV420,但并不影响后续拼接操作。

1.2 拼接

视频读取后便可很容易地获取每一帧,拼接部分只需要对每一帧进行操作即可。 BGR 数据反而解决了 UV 数据不可分的问题。

1.3 写视频

在视频写入之前的操作都没有什么大的问题,视频写入使用 cv::VideoWriter Class 进行操作。该类可以通过 VideoWriter::fourcc('H', 'E', 'V', 'C')选择编码方式。

当我们选择 H264 (VideoWriter::fourcc('X', '2', '6', '4'))编码时,提示信息如下:

图2.opencv-h264-write

提示缺少 openh264-1.6.0-win64msvc.dll 文件,OpenCV默认情况下没有编译此文件,可通过下载 openh264-1.6.0-win64msvc.dll.bz2 文件解决此问题。

当我们选择 H265 编码时,提示信息如下:

图3.opencv-h265-write

表示根本找不到此编码方式,opencv目前还不支持 H265 编码。官方论坛上此问题也没得到解决官方论坛相关问题

实验表明 OpenCV 虽然支持 H264,265的解码,但是对编码的支持不够友好,官方文档对此问题专门做出了说明,如下:

图4.The structure of a video

1.4 GPU解决方案

以上操作均是在CPU中处理实现,在查询并阅读opencv官方文档之后发现

  • cv::cudacodec::VideoReader Class
  • cv::cudacodec::VideoWriter Class
  • cv::cuda::GpuMat Class

等GPU中的视频读写,帧操作方法。但是资料较少,暂时还没有使用代码实现相应的功能,具体编解码支持情况还没调查清楚。

1.5 总结

实验表明,解码,拼接 部分,在 cpu 中能够正常完成。并且容易推测,在GPU中也能完成 解码,拼接部分任务。目前问题主要出在编码部分,视频编码不是OpenCV的主要关注点,目前仅能支持 H264的编码。

1.6 参考资料

2 pytorch官方资料翻译

深入理解TORCH.NN

Share Comments

2019-周报3

开学以来主要学习了CUDA优化相关的内容,创建了VS2015的cuda工程熟悉其编程与调试过程。人脸识别方面,调研了目前开源的人脸识别数据集,阅读了VGGFace与VGGFace2两篇论文,下载了Visual Geometry Group在2018年公布的VGGFace2 数据集并跑了一些主流的人脸识别模型。

1 CUDA 程序的优化

CUDA编程中,优化是非常关键的一步,算法的好坏极大地影响到程序的运行效率,优化的关键主要在于其执行模型与内存模型。执行模型中,线程束的调度,SIMD(单指令多数据)的理解,线程块大小个数的分配标准。内存模型中,全局内存,共享内存,缓存,常量内存的区别与使用方法以及各种内存与线程之间的关系。

1.1 执行模型

弄懂执行模型就是要知道成千上万的线程是如何在GPU中调度的,从硬件层面探讨内核的执行问题,首先要了解以下GPU硬件中的概念:

  • cuda核
  • 线程束(warp)
  • SIMD(single instruction multi data)
  • SM(stream multi processer)

1.1.1 cuda核

cuda核是为了适应GPU的大规模运算专门精简设计的算术逻辑单元(ALU),我们程序设计的线程便是在cuda核中计算处理。

1.1.2 线程束(warp)

线程束是一个重要的概念,每个线程束包含32个线程,32是cuda编程的一个重要数字。线程的执行都是按照线程束调度的而不是单个线程调度。

1.1.3 单指令多数据(SIMD)

前面讲到线程束之所以重要,就是(SIMD)架构决定的。顾名思义,单指令多数据,就是多个(32个)数据同时执行一个指令。也就是一个线程束(warp)中的32个线程同时执行一条指令(或者某些线程等待不执行任何操作,这样会浪费资源,需要优化),这也是考虑到并行处理时大量的重复指令设计的。

1.1.4 流式多处理器(SM)

流式多处理器(SM)是GPU架构的核心,一个SM由大量的cuda核,特殊功能单元,加载/存储单元组成。一个SM可以管理上千个线程束(不同型号GPU不同),SM个数便是常说的GPU核心数。

1.1.5 相互关系

以上几个概念的关系可以简单描述为:32个cuda核组成一个线程束,同一个线程束(32个cuda核)执行相同的指令即为SIMD(一个warp中的32个线程执行相同的指令),多个(不同型号GPU数目不同)warp组成一个SM,一块GPU包含多个SM (SM的个数便是常说的GPU核心数)。下图较好得描述了逻辑视图和硬件视图:

图1.硬件结构

在了解了gpu的执行模型之后,将编程模型与执行模型结合,便能很好得理解block,grid的设计原则,以及block中线程的数量与性能之间的关系,是算法优化的一大因素。

1.2 内存模型

GPU中的内存主要分为两个部分,全局内存共享内存,全局内存通过PCIE总线与CPU相连,可以直接通过CPU操作,即我们通常说的显存,容量大,速度相对较慢。共享内存只能在GPU内分配使用,即二级缓存,容量有限,速度快。共享内存是珍贵的资源,共享内存与全局内存的不同使用方法都会极大得影响到程序的性能,对于读写频繁的数据,转移到共享内存再操作会极大地提高运行速度。

1.2.1 常用内存

下面是常用内存地存取速度:

  • Register – dedicated HW – single cycle
  • Shared Memory – dedicated HW – single cycle
  • Local Memory – DRAM, no cache – slow
  • Global Memory – DRAM, no cache – slow
  • Constant Memory – DRAM, cached – depending on cache locality
  • Texture Memory – DRAM, cached – depending on cache locality
  • Instruction Memory ( invisible ) – DRAM

实用关键字 __shared__在共享内存中创建变量,关键字__device__在全局内存中创建变量,以下是常用的变量声明方式

变量声明 存储器 作用域 生命期
单独声明的自动变量(非数组) register thread kernel
自动变量数组 local thread kernel
__shared__ int sharedVar shared block kernel
__device__ int sharedVar global grid application
__constant__ int sharedVar constant grid application

1.2.2 内存与线程的关系

每个线程私有的为 Local Memory,local memory存储于全局内存中。共享内存(shared memory)为每个block共享,不同block之间不能相互访问。全局内存为整个设备共有。

1.3 参考资料

2 人脸识别

本次仅仅是训练的人脸识别,不包括人脸检测,使用的数据集也都是经过人脸检测切割之后的人脸图像。

2.1 人脸识别数据集介绍

深度学习在人脸识别领域取得了巨大的成功,但在2015年之前,都没有一个适用于深度学习的人脸识别开源数据集,比较大的超过百万张图片的数据集例如Google,Facebook的数据库都是公司私有并不公开。传统的人脸识别数据库如 LFW(Labelled Faces in the Wild),数据量都很有限。由于制作数据集成本高昂,所以人脸识别在学术届的发展较为缓慢,直到2015年牛津大学Visual Geometry Group实验室公布了VGGFace人脸识别数据集才得已改善,我们使用的是Visual Geometry Group实验室在2018年发布的VGGFace2数据集进行训练,下面是一些人脸识别数据集的介绍。

2.2 参考资料

  1. ZQ. Cao, L. Shen, W. Xie, O. M. Parkhi, A. Zisserman, VGGFace2: A dataset for recognising faces across pose and age, 2018. site, arXiv
  2. Parkhi, O. M. and Vedaldi, A. and Zisserman, A., Deep Face Recognition, British Machine Vision Conference, 2015.site
  3. K. Zhang and Z. Zhang and Z. Li and Y. Qiao, Joint Face Detection and Alignment Using Multitask Cascaded Convolutional Networks, IEEE Signal Processing Letters, 2016. arXiv
Share Comments

2019-周报2

本周主要学习了cuda编程,简单地了解了几种基于深度学习的人脸识别算法(DeepFace, DeepID, FaceNet, VGGFace)

1 CUDA编程

CPU+GPU的异构编程架构是高性能计算的主流,以高吞吐量与高效率完成复杂任务。其代码分为两部分,由主机端(CPU)运行代码与设备端(GPU)运行代码(核函数)组成。

CUDA编程中,内存管理线程管理设备管理是非常重要的概念,也是构成程序逻辑与影响程序效率的重要因素。除此之外CUDA编程需要了解GPU的架构,资源。CUDA程序流程大致分为以下几个部分:

  1. 主机端(CPU)内存分配,设备端(GPU)内存分配
  2. 把数据从CPU内存拷贝到GPU内存
  3. 调用核函数对存储在GPU内存的数据进行操作
  4. 将数据从GPU内存传回到CPU内存

1.1 内存管理

CUDA编程模型是由主机和设备组成,各自拥有独立的内存。为了使操作者拥有充分的控制权并使系统达到最佳性能,CUDA运行时负责分配与释放内存,并且在主机与设备内存之间传输数据。内存管理函数如下:

图一.内存管理函数

设备端的内存只有核函数能够读取,使用udaMemcpy()函数在主机与设备之间进行数据转移,如上面的4个步骤提到的,通常都是将主机端的数据拷贝到设备端,调用核函数对设备端的数据进行计算,再将计算之后的结果拷贝回主机端进行存储。

1.2 线程管理

线程管理是CUDA编程很重要的一个概念,从逻辑层的角度来看,GPU中各个线程并行进行(硬件层不一定都是并行)。CUDA的特点之一就是通过编程模型揭示了一个两层线程层次结构(grid+block),充分熟悉与理解线程层次结构对DUDA编程十分重要。

每启动一个核函数就会在设备中产生大量的线程,并且每个线程都执行由核函数指定的语句,产生的大量线程便是两层的线程结构进行管理,由线程块(block)与线程网格(grid)构成

图二.线程结构

每启动一个核函数,就同时启动了一个网格(grid),网格最多可以为三维,维度值的最大值由硬件决定,我们服务器上的 GeForce GTX 1080 Ti 支持的最大网格维数为1D=(131072), 2D=(131072,65536), 3D=(16384,16384,16384) ,网格由块组成,这便是线程结构的第一层。块由线程组成,这便是第二层。他们的层次结构为: 网格(grid)–>块(block)–>线程(thread)

1.3 设备管理

前面说到了在逻辑层来说,各个线程都是并行运行的,但是在硬件层并不一定,并没有那么多的硬件资源供所有线程并行运行。设备管理需要清楚当前硬件的资源情况,对于程序的优化十分重要,设备管理需要对GPU的架构有一定了解,NVIDIA目前推出的最新架构为Turing,实验室服务器使用的 GeForce GTX 1080 Ti为Pascal架构,其资源如下图所示:

图3.设备资源

参数中

  • Warp size: 32
  • Maximum number of threads per multiprocessor: 2048
  • Maximum number of threads per block: 1024
  • Maximum sizes of each dimension of a block: 1024 x 1024 x 64
  • Maximum sizes of each dimension of a grid: 2147483647 x 65535 x 65535

几个参数,对于编程时资源的分配十分重要

1.4 参考资料

  • CUDA C编程权威指南(John Cheng)

2 基于深度学习的人脸识别算法

深度学习的人脸识别算法准确度大大地高于传统算法,准确度早已超过了人工识别准确率(DeepFace: 92.5%, DeepID: 99.15%, FaceNet-NN3: 99.65% , LFW数据集测试结果),所以现在深度学习在人脸识别方面的研究除了提高准确率之外还致力于裁剪网络结构,减小参数(VGGFace)

2.1 DeepFace

人脸识别可分为 detect-> align-> represent-> classify 几个部分,DeepFace在align部分使用了3D对齐技术,将检测到的人脸进行3D-aligned处理之后再放入网络中进行识别。网络结构如下图所示

图4.DeepFace网络结构

从图中可以看出,检测到的是侧脸,经过3D-aligned处理之后面部调整为正面,讲调整后的图像输入网络。网络C1, C3表示卷积层,M2为max pooling层,L4, L5, L6为局部卷积层,F7, F8为全连接层。

2.2 DeepID

DeepID是在GoogleNet和VGGNet上的基础上进行改进,使之适应于人脸识别,网络有一代和二代两种,两种网络的区别主要在于损失函数的定义。常用的为DeepID2的损失函数,除了采用softmax训练构建分类器时产生的交叉熵函数之外,还添加了关于两张图片是不是一个人的损失函数,两个损失函数按权重组合,最终生成了对应的总损失函数用来进行训练,网络结构如下:

图5.DeepID网络机构

相比DeepFace,DeepID3的网络结构更深,且没有使用3D对齐技术,直接输入检测到的人脸图像进行识别。

2.3 FaceNet

FaceNetFaceNet是谷歌提出的网络结构, 网络在使用的过程中通过三元对来构造损失函数,直接根据学习到的特征向量,计算在一类的图片距离和不在一类的图片距离,训练的结果是一类之间的距离尽量小,不一类之间的距离尽量大。

2.4 VGGFace

VGGFace的网络在LFW数据集上的准确率为98.95%,虽然不及FaceID和FaceNet,但是网络结构更加简单,有更强的鲁棒性

2.5 参考资料

Share Comments

2019-周报1

本周对视频编解码的几种框架进行了比较,给出了初步的方案设计,人脸识别方面,查阅了相关论文,对二十世纪七十年代至今的各种人脸识别算法做了总结,具体情况如下。

1 视频编解码方案设计

​ 视频编解码部分,现已确定编码使用hevc-nvenc编码器,解码使用hevc-cuvid解码器,拼接使用CUDA编程在GPU内实现。关键在于使用哪个框架使得编程实现最方便,以下是几种编解码方案的介绍及对比情况。

1.1 Video Codec SDK

Video Codec SDK 是NVIDIA官方推出的开发工具包,使用该工具包可以直接调用NVIDIA支持的编解码器,目前最新版本是8.2.

图1.NVIDIA CODEC

其它所有支持NVIDIA硬编码的框架都是在这基础上进行的二次开发,如ffmpeg。直接使用该开发包进行编解码效率最高,但是参数众多,学习成本高。

1.2 使用opencv编解码

​ opencv编程简单,有类似matlab一般便利的函数接口使用起来非常方便,且内置视频编解码模块cudacodec。

图2.OpenCV CUDA accelerated

但是进一步调查发现opencv对视频编解码的支持比较老旧,模块中包含的视频编解码器十分有限且不具备hevc-nvenc与hevc-cuvid,具体包含的编解器如下图。

图3.OpenCV CODEC

若要使其支持,需要自己手动添加ffmpeg最新库使其支持,既麻烦也没有必要,所以编解码放弃使用opencv实现。

1.3 FFmpeg / libav

ffmpeg/libav库为NVIDIA官方推荐的视频编解码框架,支持所有NVIDIA最新的编解码器。在安装NVIDIA最新的视频编解码开发包Video Codec SDK 8.2之后便可以使用ffmpeg/libav调用NVIDIA的编码器/解码器。

1.4 总结

​ 从上面的介绍可以看出,以上三个框架从底层到高层的顺序为:Video Codec SDK–>FFmpeg / libav–>OpenCV。其中OpenCV的封装最高级,使用起来最为方便,但是其最新版本不支持英伟达的HEVC编解码器,FFmpeg很好地支持英伟达最新编解码器,其使用起来相比Video Codec SDK方便,所以目前确定开放方案如下

  • 编解码框架:ffmpeg
  • 拼接:CUDA
  • 开发环境:VisualStudio2015

疑问: ffmpeg在windows上使用MinGW编译器编译,CUDA程序使用NVCC编译器编译,目前还不清楚将FFmpeg与CUDA结合使用的具体方法???

1.5 参考资料

NVIDIA VIDEO CODEC SDK

NVIDIA-FFmpeg/libav

OpenCV 4.0 docs

OpenCV Video Encoding/Decoding

FFmpeg/libav


2 人脸识别算法调研

​ 最早的关于人脸识别的研究出现在20世纪50年代的心理学领域[Bruner and Tagiuri 1954],到20世纪60年代才逐渐有了一些工程上的文献出现[Bledsoe 1964]. 但真正关于机器自动识别的研究开始于20世纪70年代[Kelly 1970] ,Kanade [1973]。20世纪50年代以来,心理学家和神经科学家的研究对此领域影响重大,并出现了一系列重要的成果与算法。

2.1 人脸识别的主要步骤与影响因素

​ 相比与指纹识别,虹膜,视网膜识别之类的技术。人脸识别不需要被识别者的主动配合,因此具有很大的商业价值,所以一直受到学者的重视。在这个领域中很难说哪一种算法比另一种更好,这取决于应用场景,背景简单或复杂,图像识别或者是视频识别,图像质量的好坏,数据集的多少都对算法有着很大地影响。通常来说,一个人脸识别系统包括人脸检测,特征提取,人脸识别/匹配三个部分,如下图所示。

图4.face recognition steps

影响人脸识别算法性能的问题有很多,其中最重要的两个问题为:

  1. 光照问题
  2. 姿势问题

2.2 人脸识别主要算法介绍

​ 下面主要介绍近四十年来人脸识别领域的各种经典算法,关于人脸识别算法的分类方法很多,下面按照年代顺序介绍最为主要的一些算法

2.2.1 基于几何特征的人脸识别算法

​ 作为最早的人脸识别方法,人们最先想到的便是对人脸的几何特征进行提取识别,使用眼睛、鼻子、嘴巴、下巴等重要特征的几何关系来描述人脸的轮廓。但实际效果并不乐观,识别能力与速度以及算法的鲁棒性都不够高,通常需要与其它方法结合使用。

2.2.2 主成分分析法(Principle-component-analysis,PCA)

​ 主成分分析法是应用极为广泛的经典传统算法,包括Eigenface,fisherface,LBP(Local Binary Patterns)等经典方法。

2.2.2.1 EigenFace

​ EigenFace又称特征脸或者本征脸方法,是90年代初期由Turk和Pentland提出的目前最流行的算法之一,具有简单有效的特。

​ 特征子脸技术的基本思想是:从统计的观点,寻找人脸图像分布的基本元素,即人脸图像样本集协方差矩阵的特征向量,以此近似地表征人脸图像。这些特征向量称为特征脸(Eigenface)。

图5.EigenFace

2.2.2.2 FisherFace

​ FisherFace是另一种特征子空间的构建方法,和EigenFace的思想一致,在PCA的基础上加入了LDA(Linear Discriminant Analysis)构建的子空间

2.2.3 神经网络

​ 在神经网络方法之前,都是采取人工提取特征+分类器分类的方式。如上面提到的EigenFace,FisherFace,LBP等特征提取,除此之外还HOG,SIFT,Gabor等特征提取方法。而神经网络不需要认为提取特征,通过在大量数据中模型自动学习特征,也是目前人脸识别中正确率最高的方法,但缺点是所需数据量大,在缺少数据的场合通常使用人工提取特征的方法。

2.2.4 其它算法

图6.categories

2.3 参考资料

  1. Zhao, Wenyi, et al. “Face recognition: A literature survey.” ACM computing surveys (CSUR) 35.4 (2003): 399-458.
  2. Pandya, Jigar M., Devang Rathod, and Jigna J. Jadav. “A survey of face recognition approach.” International Journal of Engineering Research and Applications (IJERA) 3.1 (2013): 632-635.
  3. Vijayakumari, V. “Face recognition techniques: A survey.” World journal of computer application and technology 1.2 (2013): 41-50.
Share Comments

Hello World

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

Share Comments

学习报告-第二周

本周学习主要学习了FFmpeg的基本使用以及卷积神经网络的基本概念,具体内容如下:

  • FFmpeg库的安装以及VS2012的配置
  • 音视频编解码基本知识,H.264 MPEG4 VP8等编解码标准
  • FFmpeg编解码常用函数学习:
    • libavcodec 库的基本使用
    • libavformat库的基本使用
  • 常用结构体的熟悉:
    • 解协议:AVIOContext,URLProtocol,URLContext
    • 解封装:AVFormatContext,AVInputFormat
    • 解码:AVStream,AVCodecContext,AVCodec
    • 存数据:AVPacket,AVFrame

  • CNN的构建,滤波器的选择
Share Comments