蹲实验室搞了三个月终于把CNN塞进指甲盖大的FPGA里了。今天和大家唠唠这个麻雀虽五脏全的CNN加速器,从Python炼丹到Verilog炼钢的全流程
CNN FPGA加速器实现(小型)CNN FPGA加速器实现(小型) 通过本工程可以学习深度学习cnn算法从软件到硬件fpga的部署。 网络软件部分基于tf2实现,通过python导出权值,硬件部分verilog实现,纯手写代码,可读性高,高度参数化配置,可以针对速度或面积要求设置不同加速效果。 参数量化后存储在片上ram,基于vivado开发。 图一为工程结构图,提供基础的testbench,加速器输入存在ram上,图二为在artix7 fpga xc7a200t所占资源(资源和速度互相折中,可以用更多的资源换速度,也可以降速度减少资源消耗)。 图三为网络结构图,demo所实现输入为28*28*1,图四五为卷积层和池化层可配置部分。 单张图片推理时间50us左右 提供本项目实现中所用的所有软件( python)和硬件代码( verilog)。

先看硬件架构的核心——参数化卷积核。这个模块用Verilog写起来像搭乐高:
module conv_core #(
parameter K=3,
parameter STRIDE=1
)(
input clk,
input [7:0] ifmap [0:K-1][0:K-1],
input [7:0] weight [0:K-1][0:K-1],
output reg [15:0] ofmap
);
// 乘累加操作流水线
always @(posedge clk) begin
integer i,j;
reg [15:0] sum;
sum = 0;
for(i=0; i<K; i=i+1)
for(j=0; j<K; j=j+1)
sum += ifmap[i][j] * weight[i][j];
ofmap <= sum;
end
endmodule
这个魔改版卷积核支持3x3/5x5动态配置,STRIDE参数控制步长。重点看for循环展开——综合器会根据K值自动生成对应数量的乘法器,想要速度就多铺计算单元,想省资源就降并行度。

权重量化是软件端的骚操作:
def quantize_weights(weights, bits=8):
scale = np.max(np.abs(weights)) / (2**(bits-1)-1)
q_weights = np.round(weights / scale).astype(np.int8)
return q_weights, scale
把32位浮点压缩到8位定点,实测精度损失不到2%,但存储空间直接砍四分之三。导出的权重头文件长这样:

localparam conv1_weights = {8'h12, 8'hF3, 8'h0A, ...};

CNN FPGA加速器实现(小型)CNN FPGA加速器实现(小型) 通过本工程可以学习深度学习cnn算法从软件到硬件fpga的部署。 网络软件部分基于tf2实现,通过python导出权值,硬件部分verilog实现,纯手写代码,可读性高,高度参数化配置,可以针对速度或面积要求设置不同加速效果。 参数量化后存储在片上ram,基于vivado开发。 图一为工程结构图,提供基础的testbench,加速器输入存在ram上,图二为在artix7 fpga xc7a200t所占资源(资源和速度互相折中,可以用更多的资源换速度,也可以降速度减少资源消耗)。 图三为网络结构图,demo所实现输入为28*28*1,图四五为卷积层和池化层可配置部分。 单张图片推理时间50us左右 提供本项目实现中所用的所有软件( python)和硬件代码( verilog)。

数据通路的状态机才是灵魂画手:
- 从片内RAM加载输入特征图切片
- 卷积核滑动窗生成器生成坐标
- 乘累加阵列暴算
- ReLU激活(就一行代码:assign relu = (dout[15]==1'b1) ? 0 : dout)
- 池化层比较器链流水处理
池化层的极简实现:
always @(posedge clk) begin
// 四输入比较器链
max_temp1 <= (window[0] > window[1]) ? window[0] : window[1];
max_temp2 <= (window[2] > window[3]) ? window[2] : window[3];
pool_out <= (max_temp1 > max_temp2) ? max_temp1 : max_temp2;
end
这个设计妙在完全用组合逻辑搭成流水线,每个时钟周期都能吐出一个池化结果。
实测在ARTIX7上跑28x28的MNIST识别,只占用了12%的DSP和8%的LUT。最骚的是整个推理流程50微秒搞定,比树莓派快三个数量级,功耗还不到0.5瓦。
代码仓库里准备了祖传调试秘籍:用Verilog的$fdisplay搞了个实时特征图导出工具,配合Python可视化脚本,硬件计算结果直接叠到matplotlib上对比,调参效率直接拉满。
更多推荐



所有评论(0)