正文系原创,转载请注明出处~

不久前好运阅读了陈希章花了一如既往年岁月为国内开发者贡献的《Office 365
开发入门指南》。
虽然前期接触过SharePoint的开销,2007年从此就再也为并未接触SharePoint的出,这次阅读这仍开被自己重新认识了Office的系开发技术,让自家发觉及今之Office
开发也是.NET Core
开发技术的新战场,而且更有心之是陈希章的范例都是使用.NET
Core写的,具体地址 https://github.com/chenxizhang/office365dev。

小喵的博客:https://www.miaoerduo.com

每当新CEO纳德拉之带领下,秉持“云为先”和“一个微软”的政策,微软比另外时刻都更开放以及谦虚,内部协作为更紧密。Office
365向上至现,在经各种用户看得见和扣留不显现之成形与提高后,已经化为同模仿于成熟之说话服务,而各种进步及换代还以继续。
Office
365凡是一个充分好之开销平台,有大量的用户,据不了统计,地球上1/7之众人在采取Office,Microsoft
Graph可以给你的工作系统格外轻地同Office 365 集成
起来,立即以Office 365之雄强服务提高工作应用能力。而Office
Add-in则是面向所有的Office 365 & Office
开发人员的庆功宴,它因此来扩展Office 365 &
Office的力量,用中国话说就是“插件”。

博客原文(排版更漂亮):https://www.miaoerduo.com/c/dlib人脸要点检测的型解析以及压缩.html

统计 1

github项目:https://github.com/miaoerduo/dlib-face-landmark-compression

本书的情不仅基本完好覆盖了Office 365开支的季充分方向(Microsoft
Graph,Office Add-in, SharePoint Add-in,Office 365
Connector),而且还连了另部分来含义的话题,例如有对人工智能的话题,有经贸利用平台的话题(Power
Apps,Microsoft Flow,Power BI等)。

 

Microsoft
Graph是平等学RESTful的接口,所以它们的持有接口都是透过标准的http方法(GET,
POST, PUT, DELETE)可以直接看到,
而且还足以经改变Url的参数来展开筛选、排序、分页等操作,它回到的数据是正规的JSON格式,这种特点决定了Microsoft
Graph是跨越出平台支持的,我们可拿它们当做是微软Office 365
的API网关,对外提供统一接入口层,让自身回忆自家之开源项目Nanofabric(https://github.com/geffzhang/NanoFabric)的API网关Ocelot的角色,我们来拘禁下这张Microsoft
Graph的整体架构。

人脸要点检测的艺于重重天地及且发出以,首先是人脸识别,常见的丁脸算法其实都见面有一样步,就是拿食指脸的图像进行对同步,而以此对齐就是通过重大点实现之,因此关于人脸要点检测的舆论也时时于face
alignment,也便是满脸对合。另一方面,对于美颜,2D/3D建模等等为亟需一来人脸的机要点技术,而且一般也求来尽可能多的口脸要点。

统计 2

Dlib is a modern C++ toolkit containing machine learning algorithms
and tools for creating complex software in C++ to solve real world
problems. It is used in both industry and academia in a wide range of
domains including robotics, embedded devices, mobile phones, and large
high performance computing environments. Dlib’s open source
licensing allows you to use it in any
application, free of charge.

位置证明与授权使用的OpenID Connect和OAuth 2.0,不仅仅是Office
365,Azure上之API验证都是因此OpenID Connect和OAuth
2.0,他的贯彻服务是Azure活动目录(AAD),在Nanofabric
中运用IdentityServer4 来促成身份验证和授权,IdentityServer4
本身已帮助你完成了OpenID Connect和OAuth 2.0 ,而且IdentityServer4
的架非常出色,非常容易进行定制开发。

Dlib是一个含了大量的机器上与错综复杂软件开发工具的现世C++工具箱,被广泛的用来软件开发等领域。

Office add-ins,SharePoint Add-ins,Office 365 Connectors
这三有的是Office
的效能的开发了,包括客户端、服务端和表面系统的竞相集成。这是一个榜首的微服务的运用体系的架,值得我们统筹下体系参考。

本篇博客主要研究的尽管是Dlib中之食指脸要点检测的家伙。该工具的章程依据是
One Millisecond Face Alignment with an Ensemble of Regression Trees by
Vahid Kazemi and Josephine Sullivan, CVPR 2014
这篇论文,在快及精度达全都高达了最好的效能。

Office 的扩大开发具有长久的历史,相较前面的VBA(Visual Basic for
Application)和VSTO(Visual Studio Tools for
Office)开发,我们拿马上时期之Office Add-in开发技术称为“Web
Add-in”,顾名思义,就是运用最普遍的Web技术来展开Office
Add-in的开。如果您曾发生Web的支付经历,你用异常易地上手,无需特别学习。反过来说,这为长了技术之窍门,对于部分早期的Office
插件开发者来说,这是一个不顶熟悉的圈子,要学的新物不丢,可能会见大增大家的变换成本。无论如何,Web
Add-in是一个有利于之补给(使用其并无意味着如果丢此前之VBA和VSTO),也是跨越平台更是移动化的待。总的来说,Office
365之开发都到家向开源转型了,使用了豪门最好熟悉的Web技术,用到了累累始源框架和工具,特别是始源跨平台的.NET
技术.NET Core 在此间去了重在角色,这为是.NET Core应用之一个至关重要战场。

正文的本位在于人口脸要点模型的囤结构的分析和模型的抽策略分析,最终以性几乎未换的动静下,得到模型的起码10加倍之压缩比。项目最终的github地址为:https://github.com/miaoerduo/dlib-face-landmark-compression
欢迎fork、star和pr。

Office 365
不仅仅是活生生的便捷办公第一抉择,而且秉持一贯以来的优良传统,它是一个颇开放的而是扩大平台。除了延续支持VBA和VSTO的扩张方式,新一替代Web
Add-in
将全面实现“一软编写,处处运行”的对象,发挥您的创意,定制专属的作用,可以当台式机、网页、平板、手机中落一致性的施用体验,并且还可以与世界的数以十亿计的Office
365用户分享。Office
365看作一个新的阳台以及新的生态,它自身为足够复杂,
这个指南包括目前Office
365所支持的支出模式之面面俱到介绍,并且通过案例带领观众进行实践,这个指南是单入门的好手册,广大的Office开发人员转到我们的.NET
Core平台上来吧,让你的Office技能焕发第二肉欲。

注意:

  1. 正文假定了读者对拖欠论文有自然之问询,可以利用Dlib完成人脸关键点的训和配备,因此无做论文的相关方的分解。、
  2. 正文中分析的数额还是Dlib的shape_predictor类的私家成员,这里只能把他们的修饰符从private改化了public,但文中并不曾特意指出。
  3. 正文中颇具的代码都于本土的64员操作系统及运行,在变量数据存储的深浅描述的时吧统统以64各类来证明,即使是例外之编译器也会指向数码大小造成影响,但立刻不是本文的重要。
  4. 本文中的数据类型如果未以C++中看看的数据类型,则为底的typedef的数据类型

    typedef char int8;
    typedef short int16;
    typedef int int32;
    typedef long int64;
    typedef float float32;
    typedef double float64;
    typedef unsigned char uint8;
    typedef unsigned short uint16;
    typedef unsigned int uint32;
    typedef unsigned long uint64;

Dlib中人脸要点落实的切近是dlib::shape_predictor,源码为:https://github.com/davisking/dlib/blob/master/dlib/image_processing/shape_predictor.h

这边大概的抽取了数码有关的接口定义:

namespace dlib
{
// ----------------------------------------------------------------------------------------
    namespace impl
    {
        struct split_feature
        {
            unsigned long idx1;
            unsigned long idx2;
            float thresh;
        };

        struct regression_tree
        {
            std::vector<split_feature> splits;
            std::vector<matrix<float,0,1> > leaf_values;
        };
    } // end namespace impl

// ----------------------------------------------------------------------------------------
    class shape_predictor
    {
    private:
        matrix<float,0,1> initial_shape;
        std::vector<std::vector<impl::regression_tree> > forests;
        std::vector<std::vector<unsigned long> > anchor_idx; 
        std::vector<std::vector<dlib::vector<float,2> > > deltas;
    };
}

 

下面,我们挨个对每个片的参数进行剖析。

Dlib内置了多底数据类型,像vector、metrix等等,每种数据类又可独立序列化成二进制的数额。对于shape_predictor的序列化,本质上虽是连连的调用成员变量数据的序列化方法,由此大地简化代码,提高了代码的复用率。

inline void serialize (const shape_predictor& item, std::ostream& out)
    {
        int version = 1;
        dlib::serialize(version, out);
        dlib::serialize(item.initial_shape, out);
        dlib::serialize(item.forests, out);
        dlib::serialize(item.anchor_idx, out);
        dlib::serialize(item.deltas, out);
    }

唯独,对于移动端等用场景,需要模型占用尽可能少的储存空间,这样一来,这些标准的贮存方就会招致数的老大要命程度的冗余。我们的任务便是一点点底滑坡这些冗余,只抱来因此之数据。

同一、常量部分

第一,我们用明白有些常量的数码。这些数量就了针对范的叙说。

变量名 数据类型 作用
version uint64 记录模型版本号
cascade_depth uint64 回归树的级数
num_trees_per_cascade_level uint64 每一级中的树的个数
tree_depth uint64 树的深度
feature_pool_size uint64 特征池的大小
landmark_num uint64 特征点的数目
quantization_num uint64 量化的级数
prune_thresh float32 剪枝的阈值

 

仲、初始形状 initial_shape

matrix<float,0,1> initial_shape;
表示的凡初始化人脸关键点的坐标,存储类型是float型,个数为 landmark_num
* 2
(不要遗忘了一个接触是鲜单数组成 :P)。

三、锚点 anchor_idx

std::vector<std::vector<unsigned long> > anchor_idx;
是一个二维的高频组,存放的凡landmark点的下标。在周边的68碰及192碰的职责中,使用一个uint8即使得存放下标,而此以的凡unsigned
long
,显然过于冗余,这里可以简化成uint8囤。这个二维数组的尺寸为 cascade_depth
* feature_pool_size 
。每一级回归树下相同模仿锚点。

四、deltas

std::vector<std::vector<dlib::vector<float,2> > > deltas;和anchor_idx类似,是一个二维数组,不同的是,数组的每个值都是dlib::vector<float,2>的构造。这个数组的深浅为 cascade_depth
* feature_pool_size *
,存放的内容是float数值。考虑到此的参数量很少,没有减掉的画龙点睛,这里我们直接存储原数。

五、森林 forests

这有凡是范参数量最可怜的一些,一个模子大概2/3底仓储都耗在了是地方。这里才是咱们减少的根本!

std::vector<std::vector<impl::regression_tree> > forests;一个shape_predictor中,有cascade_depth级,每一级有num_trees_per_cascade_level棵树。对于各棵树,它要存放在了少数独片的多寡:分割的阈值splits和叶子的价leaf_values。为了有利于阅读,再把数据结构的概念附上。

namespace dlib
{
    namespace impl
    {
        struct split_feature
        {
            unsigned long idx1;
            unsigned long idx2;
            float thresh;
        };

        struct regression_tree
        {
            std::vector<split_feature> splits;
            std::vector<matrix<float,0,1> > leaf_values;
        };
    } // end namespace impl
}

5.1 splits

splits存放的数额是阈值和特点像素值的下标,这个下标的限量是[0,
feature_pool_size)
,在普通情况下,feature_pool_size不见面极其可怜,论文中极其酷吗便假设到了2000。这里我们得动用一个uint16来存储。thresh就直接存储。对于一棵树,树之深度为tree_depth,则有
2^tree_depth – 1 个split_node。(这里当只有根节点的培养深度为0)。

5.2 leaf_values

std::vector<matrix<float,0,1> > leaf_values;对深度也tree_depth的树,有 2^tree_depth
个叶子节点。对于每个叶子节点,需要仓储整个关键点的偏移量,也就是说每个节点存放了
landmark_num * 2 单float的数值。那么这有的参数量到底有多杀啊?

举个例,在cascade_num为10,num_trees_per_cascade_level为500,tree_depth为5,landmark_num为68的时候。leaf_values的值有cascade_num
* num_trees_per_cascade_level * (2 ^ tree_depth) * landmark_num
* 2 = 21760000 = 20.8M

的参数量,由于采用float存储,通常一个float是4单字节,因此总的存储量达到了逆天的80MB!远很让任何的参数的总和。

那么如何才能够管用的降这一部分底存储量呢?

当即就要使用到传说被的型压缩三宗套:剪枝,量化编码

5.2.1 参数分布分析

第一笔者统计了参数的布,大致的动静是这样的,(具体的结果招来不顶了)。

叶子节点里的参数的限定以[-0.11, 0.11]之间,其中[-0.0001,
0.0001]的参数占了50%以上。说明模型中生大量底百般接近0的数字。

5.2.2 剪枝

剪枝的方针十分粗犷,选择一个剪枝的阈值prune_thresh,将模小于阈值的往往周置0。

5.2.3 量化

量化的进程,首先获取数据中之太小值和最好充分价值,记否:leaf_min_value 和
leaf_max_value。之后因量化的级数
quantization_num,计算产生各个一级的升幅:quantization_precision =
(leaf_max_value – leaf_min_value)
/ quantization_num
。之后于随意数值x,那么她说到底也 x
/ quantization_precision

进行四放弃五抱的结果。这样即便可管float的数字转换成整形来代表。量化级数更是强,则量化之后的价值损失就一发聊。

5.3.3 编码

假设我们无做任何的编码操作,直接存储量化之后的结果,也是得得水平及展开模型的减少的。比如以256级量化,则量化的结果运用一个uint8就得储存,从而把存储量降呢原本的1/4。但是这么有个别独问题:1,依赖量化的级数;2,存储量减少非死。

当信息论中出只信息熵的定义。为了证实存储上之足重优化,这里选择了一个68沾之模子,经过256层量化之后,计算出信息熵(信息熵的乘除请查阅其他的材料),其数值为1.53313,也就是说,理想图景下,一个数值仅需要不顶2
bits就算可储存了。如果无编码则要8 bits。压缩比也 1.53313 / 8 = 19.2
%,前者只为后人的1/5休顶!

此,我下的凡经典的huffman编码,使用了github上的
https://github.com/ningke/huffman-codes 项目蒙之代码,感谢作者的献!

本来项目被不得不对char类型的数量进行编码,因此此吧召开了对应的改动,以适应被int类型的编码,同时删除了有些于是非顶之函数。

动huffman对上述的256层的数值进行编码,最终之每个数字的平分长也1.75313,已经生类似美状态。

采用huffman编码时,同时要拿码表进行仓储,这一部分细节较为麻烦,读者可活动阅读源码。

 

至此,Dlib的范的分析和压缩虽合介绍了了。对代码感兴趣之同室可以以:https://github.com/miaoerduo/dlib-face-landmark-compression
,也就是是我的github上clone到最新的代码,代码我眼前呢于时时刻刻的测试,如果出题目,也会及时更新的。

当当地的试行被,原模的轻重也127M,压缩后就发生5.9M,且性能几乎不移(这里prune_thresh设为0.0001,
quantization_num设为256,quantization_num设置更怪,则精度越来越接近原模,同时prune_thresh的深浅很多时分是尚未因此之)。

 

当下将毕业了,希望写博客的惯会一直维持下去。

末了,再同涂鸦,希望多少喵能和大家一块学学及升华~~