一起学习用Verilog在FPGA上实现CNN----SoftMax层设计

Posted 鲁棒最小二乘支持向量机

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一起学习用Verilog在FPGA上实现CNN----SoftMax层设计相关的知识,希望对你有一定的参考价值。

1 SoftMax层设计

1.1 softmax

SoftMax函数的作用是输入归一化,计算各种类的概率,即计算0-9数字的概率,SoftMax层的原理图如图所示,输入和输出均为32位宽的10个分类,即32x10=320

本项目softmax实现逻辑为:

  • 指数计算(通过exponent实现)
  • 计算指数和(通过floatAdd实现)
  • 求指数和倒数(通过floatReciprocal实现)
  • 计算每个元素的softmax值(通过floatMult实现)

1.2 exponent

每个输入分别输入到各自的exponent模块,计算指数,该模块的输入和输出位宽均为32位,输入1个数,计算输出1个指数

exponent模块展开原理图,如图所示,包含2个乘法器和1个加法器

1.3 floatAdd

加法器计算所有指数的和

1.4 floatReciprocal

floatReciprocal模块计算指数和的倒数

floatReciprocal模块展开原理图,如图所示

1.5 floatMult

乘法器计算各输入的softmax值,然后输出

2 代码实现

2.1 floatAdd

2.1.1 设计输入

创建floatAdd文件,操作如图:

输入文件名:

双击打开,输入代码:

module floatAdd (floatA,floatB,sum);
	
input [31:0] floatA, floatB;
output reg [31:0] sum;

reg sign;
reg [7:0] exponent;
reg [22:0] mantissa;
reg [7:0] exponentA, exponentB;
reg [23:0] fractionA, fractionB, fraction;	//fraction = 1,mantissa
reg [7:0] shiftAmount;
reg cout;

always @ (floatA or floatB) begin
	exponentA = floatA[30:23];
	exponentB = floatB[30:23];
	fractionA = 1'b1,floatA[22:0];
	fractionB = 1'b1,floatB[22:0]; 
	
	exponent = exponentA;

	if (floatA == 0) begin						//special case (floatA = 0)
		sum = floatB;
	end else if (floatB == 0) begin					//special case (floatB = 0)
		sum = floatA;
	end else if (floatA[30:0] == floatB[30:0] && floatA[31]^floatB[31]==1'b1) begin
		sum=0;
	end else begin
		if (exponentB > exponentA) begin
			shiftAmount = exponentB - exponentA;
			fractionA = fractionA >> (shiftAmount);
			exponent = exponentB;
		end else if (exponentA > exponentB) begin 
			shiftAmount = exponentA - exponentB;
			fractionB = fractionB >> (shiftAmount);
			exponent = exponentA;
		end
		if (floatA[31] == floatB[31]) begin			//same sign
			cout,fraction = fractionA + fractionB;
			if (cout == 1'b1) begin
				cout,fraction = cout,fraction >> 1;
				exponent = exponent + 1;
			end
			sign = floatA[31];
		end else begin						//different signs
			if (floatA[31] == 1'b1) begin
				cout,fraction = fractionB - fractionA;
			end else begin
				cout,fraction = fractionA - fractionB;
			end
			sign = cout;
			if (cout == 1'b1) begin
				fraction = -fraction;
			end else begin
			end
			if (fraction [23] == 0) begin
				if (fraction[22] == 1'b1) begin
					fraction = fraction << 1;
					exponent = exponent - 1;
				end else if (fraction[21] == 1'b1) begin
					fraction = fraction << 2;
					exponent = exponent - 2;
				end else if (fraction[20] == 1'b1) begin
					fraction = fraction << 3;
					exponent = exponent - 3;
				end else if (fraction[19] == 1'b1) begin
					fraction = fraction << 4;
					exponent = exponent - 4;
				end else if (fraction[18] == 1'b1) begin
					fraction = fraction << 5;
					exponent = exponent - 5;
				end else if (fraction[17] == 1'b1) begin
					fraction = fraction << 6;
					exponent = exponent - 6;
				end else if (fraction[16] == 1'b1) begin
					fraction = fraction << 7;
					exponent = exponent - 7;
				end else if (fraction[15] == 1'b1) begin
					fraction = fraction << 8;
					exponent = exponent - 8;
				end else if (fraction[14] == 1'b1) begin
					fraction = fraction << 9;
					exponent = exponent - 9;
				end else if (fraction[13] == 1'b1) begin
					fraction = fraction << 10;
					exponent = exponent - 10;
				end else if (fraction[12] == 1'b1) begin
					fraction = fraction << 11;
					exponent = exponent - 11;
				end else if (fraction[11] == 1'b1) begin
					fraction = fraction << 12;
					exponent = exponent - 12;
				end else if (fraction[10] == 1'b1) begin
					fraction = fraction << 13;
					exponent = exponent - 13;
				end else if (fraction[9] == 1'b1) begin
					fraction = fraction << 14;
					exponent = exponent - 14;
				end else if (fraction[8] == 1'b1) begin
					fraction = fraction << 15;
					exponent = exponent - 15;
				end else if (fraction[7] == 1'b1) begin
					fraction = fraction << 16;
					exponent = exponent - 16;
				end else if (fraction[6] == 1'b1) begin
					fraction = fraction << 17;
					exponent = exponent - 17;
				end else if (fraction[5] == 1'b1) begin
					fraction = fraction << 18;
					exponent = exponent - 18;
				end else if (fraction[4] == 1'b1) begin
					fraction = fraction << 19;
					exponent = exponent - 19;
				end else if (fraction[3] == 1'b1) begin
					fraction = fraction << 20;
					exponent = exponent - 20;
				end else if (fraction[2] == 1'b1) begin
					fraction = fraction << 21;
					exponent = exponent - 21;
				end else if (fraction[1] == 1'b1) begin
					fraction = fraction << 22;
					exponent = exponent - 22;
				end else if (fraction[0] == 1'b1) begin
					fraction = fraction << 23;
					exponent = exponent - 23;
				end
			end
		end
		mantissa = fraction[22:0];
		sum = sign,exponent,mantissa;			
	end		
end

endmodule

如图所示:

2.1.2 分析与综合

将floatAdd设置为顶层:

对设计进行分析,操作如图:

分析后的设计,Vivado自动生成原理图,如图:

对设计进行综合,操作如图:

综合完成,关闭即可:

2.1.3 功能仿真

创建仿真激励文件,操作如图:

输入激励文件名:

确认创建:

双击打开,输入激励代码:

`timescale 1ns / 1ps

module tb_floatAdd();
reg [31:0] floatA;
reg [31:0] floatB;
wire [31:0] sum;

initial begin
	
	// 0.0004125 + 0.000000525
	#0
	floatA = 32'hbab1cf4b;
	floatB = 32'h3aaaad74;

	// 0.0004125 + 0
	#10
	floatA = 32'b00111001110110000100010011010000;
	floatB = 32'b00000000000000000000000000000000;

	#10
	$stop;
end

floatAdd FADD
(
	.floatA(floatA),
	.floatB(floatB),
	.sum(sum)
);

endmodule

如图所示:

将tb_floatAdd设置为顶层:

开始进行仿真,操作如下:

仿真波形,如图:


仿真结束,关闭仿真:

2.2 floatMult

2.2.1 设计输入

创建floatMult文件,操作如图:


双击打开,输入代码:

module floatMult (floatA,floatB,product);

input [31:0] floatA, floatB;
output reg [31:0] product;

reg sign;
reg [7:0] exponent;
reg [22:0] mantissa;
reg [23:0] fractionA, fractionB;	//fraction = 1,mantissa
reg [47:0] fraction;

always @ (floatA or floatB) begin
	if (floatA == 0 || floatB == 0) begin
		product = 0;
	end else begin
		sign = floatA[31] ^ floatB[31];
		exponent = floatA[30:23] + floatB[30:23] - 8'd127 + 8'd2;
	
		fractionA = 1'b1,floatA[22:0];
		fractionB = 1'b1,floatB[22:0];
		fraction = fractionA * fractionB;
		
		if (fraction[47] == 1'b1) begin
			fraction = fraction << 1;
			exponent = exponent - 1; 
		end else if (fraction[46] == 1'b1) begin
			fraction = fraction << 2;
			exponent = exponent - 2;
		end else if (fraction[45] == 1'b1) begin
			fraction = fraction << 3;
			exponent = exponent - 3;
		end else if (fraction[44] == 1'b1) begin
			fraction = fraction << 4;
			exponent = exponent - 4;
		end else if (fraction[43] == 1'b1) begin
			fraction = fraction << 5;
			exponent = exponent - 5;
		end else if (fraction[42] == 1'b1) begin
			fraction = fraction << 6;
			exponent = exponent - 6;
		end else if (fraction[41] == 1'b1) begin
			fraction = fraction << 7;
			exponent = exponent - 7;
		end else if (fraction[40] == 1'b1) begin
			fraction = fraction << 8;
			exponent = exponent - 8;
		end else if (fraction[39] == 1'b1) begin
			fraction = fraction << 9;
			exponent = exponent - 9;
		end else if (fraction[38] == 1'b0) begin
			fraction = fraction << 10;
			exponent = exponent - 10;
		end else if (fraction[37] == 1'b1) begin
			fraction = fraction << 11;
			exponent = exponent - 11;
		end else if (fraction[36] == 1'b1) begin
			fraction = fraction << 12;
			exponent = exponent - 12;
		end else if (fraction[35] == 1'b1) begin
			fraction = fraction << 13;
			exponent = exponent - 13;
		end else if (fraction[34] == 1'b1) begin
			fraction = fraction << 14;
			exponent = exponent - 14;
		end else if (fraction[33] == 1'b1) begin
			fraction = fraction << 15;
			exponent = exponent - 15;
		end else if (fraction[32] == 1'b1) begin
			fraction = fraction << 16;
			exponent = exponent - 16;
		end else if (fraction[31] == 1'b1) begin
			fraction = fraction << 17;
			exponent = exponent - 17;
		end else if (fraction[30] == 1'b1) begin
			fraction = fraction << 18;
			exponent = exponent - 18;
		end else if (fraction[29] == 1'b0) begin
			fraction = fraction << 19;
			exponent = exponent - 19;
		end else if (fraction[28] == 1'b1) begin
			fraction = fraction << 20;
			exponent = exponent - 20;
		end else if (fraction[27] == 1'b1) begin
			fraction = fraction << 21;
			exponent = exponent - 21;
		end else if (fraction[26] == 1'b1) begin
			fraction = fraction << 22;
			exponent = exponent - 22;
		end else if (fraction[27] == 1'b1) begin
			fraction = fraction << 23;
			exponent = exponent - 23;
		end
	
		mantissa = fraction[47:25];
		product = sign,exponent,mantissa;
	end
end

endmodule

如图所示:

2.2.2 分析与综合

将floatMult设置为顶层:

关闭上次的分析文件:

对设计进行分析,操作如图:

分析后的设计,Vivado自动生成原理图,如图:

对设计进行综合,综合完成,关闭即可:

2.2.3 功能仿真

创建激励文件tb_floatMult:

双击打开,输入激励:

`timescale 1ns / 1ps

module tb_floatMult();
reg [31:0] floatA;
reg [31:0] floatB;
wire [31:0] product;

initial begin
	
	// 0.0004125 * 0.000000525
	#0
	floatA = 32'b00111001110110000100010011010000;
	floatB = 32'b00110101000011001110110110111010;

	// 0.0004125 * 0
	#10
	floatA = 32'b00111001110110000100010011010000;
	floatB = 32'b00000000000000000000000000000000;

	#10
	$stop;
end

floatMult FM
(
	.floatA(floatA),
	.floatB(floatB),
	.product(product)
);

endmodule

如图所示:

将tb_floatMult设置为顶层:

开始进行仿真:

仿真波形如图:

仿真结束,关闭仿真:

2.3 exponent

2.3.1 设计输入

创建exponent文件,如图:

一起学习用Verilog在FPGA上实现CNN----integrationFC设计

一起学习用Verilog在FPGA上实现CNN----池化层设计

一起学习用Verilog在FPGA上实现CNN----integrationConv设计

一起学习用Verilog在FPGA上实现CNN----SoftMax层设计

一起学习用Verilog在FPGA上实现CNN----全连接层设计

一起学习用Verilog在FPGA上实现CNN----卷积层设计