赞
踩
第一和第二篇日志已经详细阐述了"半精度浮点数"的加法和乘法模块了。需要注意,他们的输入和输出均是16bit的半精度浮点数。现在我们自下而上,向着更顶层进发,用floatMult16和floatAdd16模块搭建基本的卷积运算模块。
另外,对于卷积神经网络中基本的卷积运算方法、卷积核、卷积层结构和参数等基础知识这里不会赘述,默认读者已经掌握。
在进行Image与filter的完整卷积运算之前,我们需要更小的模块去支持这样的操作。首先最基本的是image的一格与filter的一格进行的乘法运算。在一个卷积窗口内,这样一次又一次的乘法操作结束后需要进行累加,得到最后的卷积结果。
`timescale 100 ns / 10 ps module processingElement16(clk,reset,floatA,floatB,result); parameter DATA_WIDTH = 16; input clk, reset; input [DATA_WIDTH-1:0] floatA, floatB; output reg [DATA_WIDTH-1:0] result; wire [DATA_WIDTH-1:0] multResult; wire [DATA_WIDTH-1:0] addResult; floatMult16 FM (floatA,floatB,multResult); floatAdd16 FADD (multResult,result,addResult); always @ (posedge clk or posedge reset) begin if (reset == 1'b1) begin result = 0; end else begin result = addResult; end end endmodule
值得注意的是,这里用到了latch的结构进行累加,即把输出addResult作为输入再次参与加运算。
① 每个时钟周期上升沿到来时,两个16bit数A和B输入进来。在很短的时间里(一个clk周期内)Mult模块计算出乘积结果AB,并交付于Add模块。
② 上一个时钟周期运算完的累加结果addResult输入到Add模块,在极短的时间内(一个clk周期内)与AB进行加运算,得到本次的累加结果sum+AB,交付给后方寄存器result。
③ 在下个时钟上升沿到来时,result内存储的累加结果更新为本次的运算结果。同时,result也作为本模块的输出。
④ 下一个时钟上升沿到来…
每一个时钟周期都必须输入新的两个数A和B,或者当没有新的卷积任务时将输入口置零。否则将会一直对同一格进行乘加造作,导致重复运算的错误。
CU是PE的上一层,负责完成一整个窗口卷积结果的输出。换言之,在每一个时钟上升沿到来时,CU需要将一个窗口内n*n个格的数依次输入给PE。
本工程中使用的filter大小是5*5单通道的,因此一个窗口的大小也是1*5*5=25格,也就是25*16=400bit。
`timescale 100 ns / 10 ps module convUnit(clk,reset,image,filter,result); parameter DATA_WIDTH = 16; parameter D = 1; //depth of the filter parameter F = 5; //size of the filter input clk, reset; input [0:D*F*F*DATA_WIDTH-1] image, filter; output [0:DATA_WIDTH-1] result; reg [DATA_WIDTH-1:0] selectedInput1, selectedInput2; integer i; processingElement16 PE ( .clk(clk), .reset(reset), .floatA(selectedInput1), .floatB(selectedInput2), .result(result) ); // The convolution is calculated in a sequential process to save hardware // The result of the element wise matrix multiplication is finished after (F*F+2) cycles (2 cycles to reset the processing element and F*F cycles to accumulate the result of the F*F multiplications) always @ (posedge clk, posedge reset) begin if (reset == 1'b1) begin // reset i = 0; selectedInput1 = 0; selectedInput2 = 0; end else if (i > D*F*F-1) begin selectedInput1 = 0; selectedInput2 = 0; end else begin selectedInput1 = image[DATA_WIDTH*i+:DATA_WIDTH]; selectedInput2 = filter[DATA_WIDTH*i+:DATA_WIDTH]; i = i + 1; end end endmodule
重要变量说明:
其实逻辑非常清晰易懂:
(图片和卷积核本是二维数据矩阵,但经过了RFselector后被展平为一维数据,可以通过单变量索引拿取)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。