基于FPGA的卷积并行加速其实有很多方法,例如脉动阵列、加法树等操作。本篇博客将介绍一下基于加法树的并行化设计。
其实总体原理也是很简单的。如下图所示,九个叶子节点是乘法器节点,分别代表九次乘法运算(卷积核是3*3的)。在得到乘法运算结果之后,将结果传送给加法节点。
为了进一步增加并行性,加法树结构采用三叉树。即,对每三个子节点进行求和。最终得到一个部分和。
实现方式是写一个加法器模块,再写一个乘法器模块,之后再写一个总体的模块将这些乘法器和加法器进行结合。
PS:加法器和乘法器都是自己写的,并没有调用 IP 核,如果想实现浮点数运算,可以调用赛灵思的浮点数运算 IP 核。
// 加法器模块
module adder(
input clk,
input rst_n,
input [15 : 0] a,
input [15 : 0] b,
input [15 : 0] c,
output [15 : 0] result
);
reg [15 : 0] result_reg;
assign result = result_reg;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
result_reg <= 16'b0;
else
begin
result_reg <= a + b + c;
end
end
endmodule
// 乘法器模块
module mult(
input clk,
input rst_n,
input [15 : 0] a,
input [15 : 0] b,
output [15 : 0] result
);
reg [15:0]result_reg;
assign result = result_reg;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
result_reg <= 16'b0;
end
else
begin
result_reg <= a * b;
end
end
endmodule
module tree(
input clk,
input rst_n,
output [15 : 0]result
);
reg [15 : 0] result_reg;
wire [15:0] mult_w [8:0];
wire [15 : 0] adder_w [2 : 0];
reg [15:0] num_reg [8:0];
genvar i;
generate
for(i = 0; i < 9; i = i + 1)
begin: mults
mult
u_mult(
.clk(clk),
.rst_n(rst_n),
.a(num_reg[i]),
.b(num_reg[i]),
.result(mult_w[i])
);
end
endgenerate
genvar j;
generate
for(j = 0; j < 3; j = j + 1)
begin: adders
adder
u_adder(
.clk(clk),
.rst_n(rst_n),
.a(mult_w[j * 3 + 0]),
.b(mult_w[j * 3 + 1]),
.c(mult_w[j * 3 + 2]),
.result(adder_w[j])
);
end
endgenerate
adder
fin_adder(
.clk(clk),
.rst_n(rst_n),
.a(adder_w[0]),
.b(adder_w[1]),
.c(adder_w[2]),
.result(result)
);
integer s;
always@(posedge clk)
begin
if(!rst_n)
begin
result_reg <= 16'b0;
for(s = 0; s < 8; s = s + 1)
begin
num_reg[s] <= 16'd0;
end
end
else
begin
end
end
genvar l;
generate
for(l = 0; l < 9; l = l + 1)
begin:nums
always@(posedge clk or posedge rst_n)
begin
if(rst_n)
num_reg[l] <= l + 1;
end
end
endgenerate
endmodule
RTL 分析:
仿真结果:
至于实现效率方面的话,其实是没有脉动阵列效率高的,并且基于加法树其实本质上还是串行操作。基于脉动阵列的仿真结果如下:
本人实现了基于脉动阵列的 Eyeriss 项目,并在 AX7020 开发板上调试通过,有需要的可以私信我。