FPGA万花筒之(十):基于FPGA的卷积神经网络实现之框架

姓名:张俸玺 学号:20012100022 学院:竹园三号书院

转自https://blog.csdn.net/qq_38798425/article/details/106723877

【嵌牛导读】FPGA,可编程门阵列,作为一种较为新型的技术,为大多数人所陌生。如今,用FPGA实现神经网络成为一种热门技术话题。本文对基于FPGA的卷积神经网络实现框架进行了简要叙述。

【嵌牛鼻子】FPGA 卷积神经网络

【嵌牛提问】基于FPGA的卷积神经网络实现的基本框架是什么?

【嵌牛正文】

github

首先设计整体框架,再根据整体结构去设计每一个子模块,通过例化子模块来形成完整的工程程序。也就是基于FPGA卷积神经网络实现里面的top.v文件。

本项目要实现的神经网络结构如下图所示:


对于在FPGA当中实现神经网络而言,每一种功能的层都单独设计一个子模块。而使用这些子模块搭建一个完整的网络框架主要有两种方法:

1.每一层都单独进行例化,占用单独的硬件资源。

2.同样功能的层复用同一部分硬件资源,通过parameter来进行区分

本项目为了初学者放心食用选择比较简单的第一种方式,当然前提是硬件资源足够多的,如果实现一个较大型的网络这样的方式是不可能的,还是需要使用第二种方法,不过偶从入门来说,第一种方法是非常容易理解的。

在最开始先要设置一个时钟模块,调用片上PLL,也就是clocking Wizard IP核。我使用的片上输入时钟为50M,输出时钟设置为两路,一路为原本的50M时钟,用于和系统时钟相关的地方(当然这个不一定会的上),另一路先随意设置为200M,在后面实际使用的时候再进行调整。


设置好后在top文件中进行例化

clock_pll clock_control

  (

    .CLK_IN1 (clk_in) ,

    .CLK_OUT1 (clk_50) ,

    .CLK_OUT2 (clk_200) ,

    .RESET (~rst_n) ,

    .LOCKED ()

);

那么这样一来我们就拥有一个快速的时钟,能够让我们的卷积神经网络飞速运行起来了。

下面我们需要一些子模块了,根据整个网络的结构,我们需要设计输入数据存储层、参数存储层、卷积层、池化层、全连接层,当然,还需要层间的缓存层。对于一个卷积层参数与输入数据需要同时进入,因此可以将参数存储层和层间输入缓存层合并为同一个模块。

以卷积层为例,先写出大概的框架,后面再慢慢填补。

module Layer1_Conv_Top#(

parameter filter_size=5

)

(

input clk_in,

input rst_n,

input data_in,

input weight_in,

output reg data_out

    );

    data_out <= data_in*weight_in;

endmodule

各个子模块创建完毕后,再去top文件里面例化一下并串联在一起,一个完整的框架就搞定了。

pic_in layer0(

.clk_in (clk_200) ,

.rst_n (rst_n) ,

.map (l1d1) ,

.ready (l1r1) ,

.weight (l1w1)

    );

Layer1_Conv_Top layer1_conv(

.clk_in (clk_200) ,

.rst_n (rst_n) ,

.data_in (l1d1) ,

.weights (l1w1) ,

.data_out (l1d2)

    );

Layer1_Pool_Top layer1_pool

(

.clk_in (clk_200) ,

.rst_n (rst_n) ,

.data_in (l1d2) ,

.data_out (l1d3)

    );

pool1_out_buffer layer1_pool_buffer(

.clk_in (clk_200) ,

.rst_n (rst_n) ,

.data_in (l1d3) ,

.data_out (l2d1) ,

.weight (l2w1)

    );

//layer2

Layer2_Conv_Top layer2_conv(

.clk_in (clk_200) ,

.rst_n (rst_n) ,

.data_in (l2d1) ,

.weights (l2w1) ,

.data_out (l2d2)

    );

Layer2_Pool_Top layer2_pool

(

.clk_in (clk_200) ,

.rst_n (rst_n) ,

.data_in (l2d2) ,

.data_out (l2d3)

    );

pool2_out_buffer layer2_pool_buffer(

.clk_in (clk_200) ,

.rst_n (rst_n) ,

.data_in (l2d3) ,

.data_out (l3d1) ,,

.weight (l3w1)

    );

//layer3

Layer3_Conv_Top layer3_conv(

.clk_in (clk_200) ,

.rst_n (rst_n) ,

.data_in (l3d1) ,

.weights (l3w1) ,

.data_out (l3d2)

    );

conv3_out_buffer layer3_conv_buffer

(

.clk_in (clk_200) ,

.rst_n (rst_n) ,

.data_in (l3d2) ,

.data_out (l3d3)

    );

Layer3_Pool_Top layer3_pool

(

.clk_in (clk_200) ,

.rst_n (rst_n) ,

.data_in (l3d3) ,

.data_out (l4d1)

    );

//full_connection

ful_conn  layer4_full_connect(

.clk_in (clk_200),

.rst_n (rst_n),

.data_in (l4d1),

.data_out (Dout)

    );

程序中用来连接各个子模块的wire类型数据的命名规则是

l(layer)+第几层+d(data)+第几个模块

到现在一个整体的网络框架应该是搭建完毕了。这里有个很值得注意的地方在于,为了编写简单,我将同样功能的模块都单独写了子模块,这样对于他们的不同就可以一个一个去处理。但是事实上,他们的整体思路是一样的,只需要改一些参数,也就是说通过设置许多的parameter也可以达到同样的目的。在所有的子模块介绍完后我将针对这一问题单独进行讲解。

你可能感兴趣的:(FPGA万花筒之(十):基于FPGA的卷积神经网络实现之框架)