本文的目的是在一個神經網絡已經通過python或者MATLAB訓練好的神經網絡模型,將訓練好的模型的權重和偏置文件以TXT文件格式導出,然后通過python程序將txt文件轉化為coe文件,(coe文件是為了將其寫入rom,網絡中的權重和偏置通過讀取ROM即可,后續需要修改輸入其他特征值,只需要修改input的rom里面的coe文件即可)。
設計思想
其中sigmoid函數是本次實驗最大的難點,因為sigmoid函數的值是在0-1之間的小數,其值越大,說明該模型的輸出是該結果的幾率越大。但是verilog硬件描述語言,其計算結果只有0或1兩種情況,所以要想直接通過verilog語言計算出sigmoid函數的值是比較復雜的,本次使用的方法為查找表法,通過外部其他語言計算出sigmoid函數的值,然后將其放入查找表,后續當需要使用sigmoid函數時,直接輸出結果。但是這個需要不斷地往里面加值,每更新一次輸入,那么就往sigmoid模塊里面的查找表添加上該輸入的sigmoid值。
由于FPGA的計算是基于數字邏輯和二進制運算,小數計算只能通過 固定點數(即帶有定點小數位的整數表示)來模擬某些浮點數計算。這需要使用額外的邏輯來實現浮點數的運算、舍入和特殊值處理。
但是本文選擇一個簡便的方法,選擇將輸入,權重 分別保留兩位小數(可自己選擇位數,保留越多精度越高,反之精度越低),然后分別將其乘以100,將數據全都變成帶符號整數,然后將其進行乘加運算。將偏置保留4位小數并乘以10000,得到的結果除以10000然后進行sigmoid計算,后續無論添加多少層,都可以以此方法來進行計算。以下為搭建神經網絡的步驟:
step1: 處理數據,將保存好的權重文件轉化為coe文件,然后添加一個ROM,并將coe文件加載進ROM里面;
module input_rom_ctr(
input sys_clk,//50MHz時鐘
input rst_n,//復位,低電平有效
input [5:0] data_deep,
output reg [31:0] rom_data_r, //ROM讀出數據
output reg viald,
output reg [6:0] rom_addr_rr //ROM輸入地址
);
reg [6:0] rom_addr;
//產生ROM地址讀取數據
always @ (posedge sys_clk or negedge rst_n)
begin
if(!rst_n)begin
rom_addr <= 7'd0;
viald <= 1'b1;
end
else if(rom_addr_rr >= (data_deep -1'd1))begin
viald <= 1'b0;
end
else if(rom_addr >= (data_deep - 1'd1))begin
rom_addr <= 7'd0;
end
else begin
rom_addr <= rom_addr+1'b1;
viald <= viald;
end
end
reg [6:0]rom_addr_r;
always @(posedge sys_clk or negedge rst_n) begin
if(!rst_n)begin
rom_addr_r <= 7'd0;
rom_addr_rr <= 7'd0;
end
else begin
rom_addr_r <= rom_addr;
rom_addr_rr <= rom_addr_r;
end
end
wire [31:0] rom_data;
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)begin
rom_data_r <= 32'd0;
end
else begin
rom_data_r <= #2 rom_data;
end
end
//實例化ROM
input_rom rom_ip_inst
(
.clka (sys_clk ), //inoput clka
.addra (rom_addr), //input [4:0] addra
.douta (rom_data) //output [7:0] douta
);
endmodule
step2:將ROM里的數據讀取出來,如果數據較少就直接使用二維數組保存數據,較多的話可以添加一個RAM,然后通過調用RAM里面的變量搭建第一層神經網絡(暫不添加sigmoid)。
input_rom_ctr input_rom( //取輸入層的數據存入ram
.sys_clk (clk),//50MHz時鐘
.rst_n (rst_n),//復位,低電平有效
.data_deep(5),
.rom_data_r (rom_data1), //ROM讀出數據
.viald (en_wr1),
.rom_addr_rr (input_index)
);
always @(posedge clk)begin
if(en_wr1) begin
input_layer[input_index] <= rom_data1; ? //從rom里面讀出數據,并將其寫入ram/寄存器里面,后面的神經網絡直接調用寄存器操作
end
else begin
input_data <= input_layer[input_index];//從ram里面讀出來的數據,加載地址就得到相應的數據。
end
end
Step3:通過仿真得到第一層神經網絡每個神經元的乘加結果,并加上偏置后,通過外部計算得到sigmoid值后將其添加到sigmoid模塊的lut查找模塊中,如此反復,最后就可以得到一個神經網絡框架。(sigmoid函數的結果也要乘以100,作為下一層的輸入),最后得到的輸入層的每個神經元的結果就代表其識別結果的概率。
module sigmoid (
input wire signed [31:0] input_value, // 輸入32位有符號整數
output reg signed [31:0] sigmoid_output // 輸出32位有符號整數
);
always @(*) begin //可以看做是一個查找表,將上一層的輸入進入sigmoid函數來進行查找值,然后將得到的值乘以100用于保留兩位小數,精度要求高的就多乘一點
case (input_value)
-2673 : sigmoid_output = 43; //上一層輸入3490,是原本輸入乘以100,保留兩位小數乘以權重乘以100,即改結果是原本結果的10000倍,所以進sigmoid函數的應該是0.349
17232 : sigmoid_output = 85; //建議以后有更多值后繼續添加,查找表越豐滿,后續能使用的輸入就越多。
36380 : sigmoid_output = 97;
124358 : sigmoid_output = 100;
-47650 : sigmoid_output = 1;
-5781 : sigmoid_output = 36;
3657 : sigmoid_output = 59;
-23082 : sigmoid_output = 9;
///上面是第一層隱層的結果,下面是輸出層的結果。
4816 : sigmoid_output = 62;
-3390 : sigmoid_output = 42;
20652 : sigmoid_output = 89;
-4386 : sigmoid_output = 39;
-2004 : sigmoid_output = 45;
-623 : sigmoid_output = 48;
default: sigmoid_output = 0;
endcase
end
endmodule
仿真結果
最后的output_layer就是輸出的最后結果。
來源:https://blog.csdn.net/qq_48434158/article/details/132426289
-
FPGA
+關注
關注
1643文章
21968瀏覽量
614295 -
matlab
+關注
關注
188文章
2998瀏覽量
233274 -
神經網絡
+關注
關注
42文章
4809瀏覽量
102826 -
函數
+關注
關注
3文章
4371瀏覽量
64229 -
python
+關注
關注
56文章
4825瀏覽量
86223
原文標題:基于FPGA的神經網絡的預測過程的實現
文章出處:【微信號:gh_9d70b445f494,微信公眾號:FPGA設計論壇】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
評論