0.模型訓練:暫時跳過
CNN有監督,可以用BP訓練:http://www.mamicode.com/info-detail-2288678.html
1.參數:
1.1一開始混亂的點
(1)每個核有一個bias,每個核出一個通道的結果(一個特征)。
(2)fcweight1:500行;fcweight1:10行;
(3)一組核:所求特征(輸出)由多個子特征(輸入)組成,每個子特征有一個核
1.2過程
(1)卷積一:輸入28*28,20個核(5*5),20個bias(1*20),輸出20通道24*24,算步長:28=5+(24-1)*步長,所以步長=1;
(2)卷積一池化:每2*2選一個最大值,無重合,規模橫縱減半;
(3)卷積二:輸入20通道12*12,20*50個核(50組核,一組核對應一個bias,得一個通道結果)(每個通道輸入*對應組對應通道的核),50個bias,輸出50通道8*8,12=5+7*1,步長=1;
(4)卷積二池化:減半
(5)全連接層一:輸入50通道4*4,展開1*800,映射到1*500(全連接->每個輸入都要乘weightN+biasN=iN,所以有500*800個參數,500個bias,:(500*800)* (800*1)=(500*1)+bias(500*1))
(6)全連接層一過濾:輸入1*500,負數取正,輸出1*500
(7)全連接層二:輸入1*500,輸出1*10:(10*500)*(500*1)=10*1+bias(10*1)
(8)輸出:找到1*10向量中最大值,輸出下標為識別結果
weight=20*25+20*50*25+500*800+10*500=500+25000+400000+5000=430500 開440000空間
bias=20+50+500+10=580 開600
2.設計:看指導書
數據通路不要和控制寫一起,控制單獨寫狀態機!
(1)定點數問題:
參數和數據處理:轉為8位二進制數(有符號,參數有負數)。運算后要移位?
教程:https://jingyan.baidu.com/article/f71d6037b3b43f1ab641d10d.html
處理成1符號+2整數+5小數,相當於一個數放大了2^5倍
原始數據*32=輸入數據,還要看數據會不會溢出(大於3)
錯誤和經驗:
1.clock design生成.v文件后,再把里面的模塊設成top,單獨寫仿真或綜合時是找不到這個模塊的,要把block design生成的.v文件刪了之后才能找到。。。但是重啟vivado后又可以直接改top了?妙
2.lia:https://blog.csdn.net/qq_34322603/article/details/72854621:
然后常規方法進入軟件調試界面,設置斷點。(這里提醒一下,聯合調試一定要在SDK下將比特流下載到FPGA中,而不要在vivado中下載比特流。Xilinx官方給出的解釋是:由於使用PS端的時鍾來接入ILA,所以要現在SDK中將比特流進行下載)
3.verliog:一個信號只能有一個驅動,多個改變位置要加選擇器。
4.加完debug后布線報錯:
[Chipscope 16-213] The debug port 'dbg_hub/clk' has 1 unconnected channels (bits). This will cause errors during implementation.
原因:綜合之后沒有選debug的設置,有的線還沒有連時鍾。給clk加debug好像有個buff報錯解決不了,就把clk的debug刪了
5.lia的wave出不來:要用sdk燒一遍才行。先用vivado 的hardware燒板子作為啟動,然后用sdk燒,就能彈出來了。
6.#include "xil_io.h"報錯:clean一遍編譯
7.ila的wave圖點運行就走一點點:一次只能抓1000個,要選好時間。令人做藕
8.初始化的使能是必須加的,因為pl初始化好了之后ps可能還沒開始傳東西。。。要用axi-lite告訴初始化模塊我要開始傳有效數據了。
9.可以直接在netlist里面mark debug,要是寫(**)沒加進去的話
選上線右鍵mark debug就行。
10.ila彈不出來:用sdk導完之后再用vivado燒一次就有了。
11.我放棄了,我還是寫仿真測吧。上板子弄單元測試太麻煩了。而且我發現wrapper會自動生成一個仿真文件。。。可以先不加系統,把輸入輸出都引出來然后寫仿真,最后再把輸入輸出都換成axi。我愛中間輸出。
12.用自帶的wrapper的test,改block的代碼的話,要重新生成一邊wrapper。但是生成完之后自己加的測試代碼也沒有了。所以還是手動搭一個吧,可以把自動的那個文件頂層粘過去
13.我愛子狀態機。for循環拆成狀態機:每個條件判斷一個狀態,執行內容一個狀態,跟編譯插標簽似的
每層:判斷本層邊界,符合則初始化下一層計數,跳出則上層計數加一
14.系統命令錯誤:參數不存在等,准確錯誤報不出來,形如下圖就是$display后面參數不存在的報錯
15.XXX右移還是XXX
16.綜合時不自動保存,綜合前一定要把文件都保存了。
狀態機套路 以cov為例
將for循環改寫,每個循環變量拆分成以下子狀態:
父狀態:循環變量初始化
判條件,轉移
在葉節點自加(不能在當前狀態自加,因為后面可能還要用i的當前值)
always@(posedge clk)begin case(s1) 0: begin if(state==1||state==3)begin s1<=1; s1_cha_count<=0; cov_en<=0; //若復用,需要初始化計數 end end 1://讀1個通道bias,開始計數 begin //計數:如果>1,finish //讀入bias if(s1_cha_count>=s1_cha_num) s1<=7; else begin read_bias<=1; read_bias_finish<=0; s1<=10; s1_wei_count<=0; end end 10://等待讀bias begin if(read_bias_finish==1)begin s1<=2; end end 2://每個通道,讀20個weight矩陣 begin //計數,若為21轉到1 if(s1_wei_count>=s1_wei_num)begin s1<=1; s1_cha_count<=s1_cha_count+1; end else begin read_weight<=1; read_weight_finish<=0; s1<=8; s1_i<=0; end end 8://等待讀weight begin if(read_weight_finish==1)begin s1<=3; end end 3://讀從data讀i行 begin //計數,如果行數>24,跳到2,否則到4 if(s1_i>=s1_result_num)begin s1<=2; s1_wei_count<=s1_wei_count+1; end else begin s1<=4; s1_j<=0; end end 4://列計數 begin ans_wen<=0; //列計數,如果列數>24,跳到3,否則到5 if(s1_j>=s1_result_num) begin s1<=3; s1_i<=s1_i+1; end else begin s1<=5; end end 5://執行體 begin read_data<=1;//子模塊讀完后置0 read_data_finish<=0; s1<=9; end 9://等讀data begin if(read_data_finish==1)begin s1<=6; cov_en<=1; end end 6://等待計算結果寫回 begin //寫回,跳到4 if(COVFINISH==1)begin//測試,待改正COVFINISH==1 //寫回,待 s1<=4; s1_j<=s1_j+1; ans_addr<=s1_cha_count*s1_wei_num*s1_result_num*s1_result_num +s1_wei_count*s1_result_num*s1_result_num +s1_result_num*s1_i +s1_j; ans_in<=COVRESULT; ans_wen<=1; $display("cov%d channel=%d weight=%d i=%d j=%d result=%d addr=%d",state,s1_cha_count,s1_wei_count,s1_i,s1_j,COVRESULT,s1_cha_count*s1_wei_num*s1_result_num*s1_result_num +s1_wei_count*s1_result_num*s1_result_num +s1_result_num*s1_i +s1_j); end end 7://結束狀態,置finish為1 begin finish<=1; s1<=0; end default:; endcase end