基于FPGA的GoogleNet加速器-前言

版权声明:本文为博主原创文章,欢迎转载,但请注明出处 https://blog.csdn.net/lulugay/article/details/53483188
这是我的第一篇技术博文,语言表达能力有限,望见谅。
《基于FPGA的GoogleNet加速器》是我的本科毕业设计,现在这方面资料比较少,学习的过程中遇到困难几乎没有资料可以参考,所以在这里分享自己的学习经历,以帮助初学者快速入门。由于老师要求,我不能把源代码放出来,但是授人以鱼不如授人以渔嘛。
《基于FPGA的GoogleNet加速器》 由三部分任务组成
1、将Caffe上的GoogleNet转化为C代码
2、用VivadoHLS工具将C代码转化为IP核
3、将IP核组织起来
一、GoogleNet工程概述
这部分任务在做之前我还是很打怵的,毕竟GoogLeNet号称22层,各个计算模块加在一起124个,做完以后发现真正需要从零开写的代码也就200行。
文件源代码解压以后有两个文件夹,gnnc和share。gnnc文件夹用来存放VS工程,share用来存放由caffe产生的数据,用于检查自己写的GoogleNet,后面会详细说。
(1)GNet的结构
.../gnnc/gnnc/gnnc文件夹存放的就是GNet的核心文件,包括
common.cpp:从share文件夹调用数据,检查等函数
conv.cpp:卷积
googlenet.cpp:将所有的基本函数连接起来形成Googlenet
inception.cpp:“盗梦空间”模型是GoogleNet的灵魂,用稠密组件代替稀疏计算,以提高计算资源利用率,需要调用conv,pool
lrn.cpp:局部归一化,据说没啥大用
sigmoid.cpp:sigmoid函数
pooling.cpp:汇聚
...\gnnc\share\deploy.prototxt文件就是定义GNet架构的文件,后面详细说
(2)GNet数据
GNet从输入到输出经过22层,每一层有包括若干基础函数,每一层都有输入输出,会产生大量的临时数据,因此我们每写完一层就可以检查一层。
.../gnnc/share/datas_cpu是我们将要调用的数据,下面有包括两个文件夹
blob文件夹存放每一层产生的临时数据,总共124个文件,可能你会问:不是只有22层么?
每一层都包含若干函数,像Inception层包括6个卷积,1个汇聚,1个连接层(将计算出的结果连接起来,讲Inception时候细说),就会产生8个临时数据。
blob.c记录.bb文件与GNet中函数的对应关系,3(行数)  conv1/7x7_s2意思是2.bb存放的是conv1/7x7_s2的输出,4 pool1/3x3_s2意思是3.bb存放的是 pool1/3x3_s2的输出,至于为啥串一个看代码就知道怎么回事儿了。
weights文件夹下.bs文件记录卷积层的偏置,.wt文件记录卷积层的权重。1(行数)  conv1/7x7_s2意思是0.bs存放的是conv1/7x7_s2的偏置,0.wt存放的是conv1/7x7_s2的权重。
(3)common.cpp详解
common.cpp里面的函数包括读取权重偏置数据,检查我们写的函数的输出与caffe的输出是否一致,加载数据(免去调试时从头开始算)
a.layer_read_wb()函数的的第一个传入参数是id,就是上面提到的文件的名称,要计算conv1/7x7_s2那么id就是0
b.showdata()这里顺带说一句调试的流程,如果发现结果错误,先别瞎猜,把正确数据错误数据都打印出来对比,再进到函数里面单步执行看到哪步出问题。
c.checkdata()检查输出是否正确,传入参数id就是跟哪个文件比较,想检查conv1/7x7_s2那么id=2,具体怎么对应看那个文件
(4)deploy.prototxt
layer {
  name: "conv1/7x7_s2"
  type: "Convolution"
  bottom: "transformed_data"
  top: "conv1/7x7_s2"
  param {
    lr_mult: 1.0
    decay_mult: 1.0
                 }
  param {
    lr_mult: 2.0
    decay_mult: 0.0
                 }
  convolution_param {
    num_output: 64
    pad: 3
    kernel_size: 7
    stride: 2
    weight_filler {
      type: "xavier"
      std: 0.1
    }
    bias_filler {
      type: "constant"
      value: 0.2
    }
  }
}


这层的名称是conv1/7x7_s2,调用卷积函数,输出是conv1/7x7_s2。lr_mult、decay_mult、weight_filler、bias_filler这些参数我们并不需要关注。
num_output是输出层数,pad是填充的大小,默认值是0,通常设置为kernel大小的一半取整;
stride:一次移动2格,默认值为2
kernel_size:卷积核的大小
需要关注的是层与层之间的连接关系,  bottom: "conv1/7x7_s2"   top: "pool1/3x3_s2"表示该层输入是conv1/7x7_s2,输出是pool1/3x3_s2
这些都是从caffe框架中找到的,与googlenet论文中的稍有不同。
(5)gnnc.h
struct layer_param
{
       struct input
       {
              int width;
              int hight;
              int depth;
       } in;
       struct output
       {
              int width;
              int hight;
              int depth;
       } out;
};


每层最基本的参数就是输入输出,其他层的定义会分别说。
前言到此为止

猜你喜欢

转载自blog.csdn.net/lulugay/article/details/53483188
今日推荐