近期,在如今所在的公司从事人脸识别的工做。使用的深度学习工具是caffe。后须要将算法布置到项目中去甚至是ARM上去。即使caffe有本身的libcaffe库能使用,可是这个库自己带有反向学习功能,而实际上deploy并不须要,故deploy时明显能够对caffe进行瘦身。另caffe有众多的依赖项,尤为是依赖protobuf使得我在工做中有诸多不便(protobuf不但2和3版本兼容很差,某些老的protobuf也没法被更新的protobuf使用,这样会致使以前的网络可能没法被更新的caffe识别到)。算法
简化caffe实际上并不复杂。咱们能够理一理须要作的事情:网络
我命名个人Net是 XYZNet,那么XYZNet可以计算,最少须要两类资源:框架
1:每一层的类型和其参数 2:每一层的权值(weights)和偏移值(bias),注意偏移值也能够是没有的。函数
以上两类资源都来自于你定义的caffe模型和训练好的model。能够简单将caffe的这些参数导出成二进制文件而后加载到XYZNet中。工具
因为层来源于文件,获得是每个层的类型,故须要有一个能动态生成层对象的运行时结构。这样就能在读取文件时,建立每个层的实例化对象,并将其指针保存至XYZNet的vector中。学习
为了能执行forward的计算,每个层须要知道其输入的数据信息和输出的数据的大小,这些资源须要提早分配好或计算获得,以方便forward的计算,这里把能预处理的操做放在这里会比较合适。故每个层都对应一个SetUp函数,来处理这些工做。spa
剩下的就是每个层的forward的工做了。这部分的处理,便可以将caffe的对应代码COPY过来,也能够在掌握原理的状况下本身适当编写,由于有些层的caffe代码,实在是对于仅仅保留forward计算的时候,是能够简化许多的。设计
在分析以上须要作的事情后,就能够简单设计其forwrad框架了:指针
设计一个父类:baselayer,全部的具体层都继承于它。它须要最少3个函数:InitLayer 从文件中读取模型参数和训练好的权值model;SetUp 根据输入的数据的尺寸信息,计算出输出的尺寸信息并分配资源,这里也许会计算出中间的临时变量的值;Forward 函数,计算结果。在XYZNet中将有一个vector<baselayer* >,用来保存各类层的实例化对象。对象
创建一个链表,链表中包含层的类型名称和每个层的构造函数,这样查找链表就能根据类型名建立层的实例化对象(caffe用的是map<string,func>,func是构造函数,这样来建立层的实例对象的)。
关于资源分配,为了能有效利用内存空间,创建一个内存管理类,每一次一个层须要分配输出数据空间时,将向这个管理类申请内存,并告诉管理类本身输出数据的名称,这段内存将由这个管理类管理,层自己将并不关心这个数据空间。而一个层须要输入数据时,将也像这个管理类提出申请,它须要提供本身输入数据的名称字符串,管理类将返回字符串对应的数据交给这个层,当层计算结束时,管理类将会知道本层输入数据已经计算完毕,它会作一些工做,以保障这个数据块能被其余层做为输出数据占用。
在forward的时候,首先须要申请获得输入输出数据存储空间,完成后将告诉内存管理器输入数据能够被释放。由于在forward计算中,输入的数据也就是caffe的bottom数据不少时候其数据是能够释放掉的,这样实际上能节约内存空间。
以上分析,大体能有一个清晰的forward设计思路。
一下是框架示意图: