FC2カウンター FPGAの部屋 AXI4 Stream版白線追従走行用畳み込みニューラルネットワークIPその3(C シミュレーション、合成)

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

AXI4 Stream版白線追従走行用畳み込みニューラルネットワークIPその3(C シミュレーション、合成)

AXI4 Stream版白線追従走行用畳み込みニューラルネットワークIPその2(C シミュレーション2)”の続き。

前回は、AXI4 Stream のビットアサインがBGR になってしまっていて、RGB では無かったので書き直した。また、畳み込みニューラルネットワークの最後の全結合層の出力をIP の出力として返していたが、分かりにくいので、進行方向の番号を返すように変更した。ちなみに 0 - 左旋回、1 - 直進、2 - 右旋回ということだったが、右旋回の出力が15個の内の5個間違っていた。それで、”CNNのVivado HLS実装のstraight_conv_nn2 の演算精度を変更する”で演算のビット幅を変更した。今回はどの程度右旋回のエラーが直っているか?を見てみよう。

まずは、このプロジェクトでも演算のビット幅を 3 ビット増やした。

ap_fixed<13, 6, AP_TRN_ZERO, AP_SAT> conv_out[NUM_OF_KERNELS][ROW_PIXELS-4][COULMN_PIXELS-4];
ap_fixed<13, 6, AP_TRN_ZERO, AP_SAT> pool_out[NUM_OF_KERNELS][(ROW_PIXELS-4)/2][(COULMN_PIXELS-4)/2];
ap_fixed<16, 7, AP_TRN_ZERO, AP_SAT> dot1[100];
ap_fixed<16, 7, AP_TRN_ZERO, AP_SAT> dot2[NUM_OF_OUTPUT];


これで C シミュレーションを行った。
wlt_cnn_150_170913.png

右旋回のエラーは 1 個に減った。ログを貼っておく。

INFO: [SIM 2] *************** CSIM start ***************
INFO: [SIM 4] CSIM will launch GCC as the compiler.
make: 'csim.exe' は更新済みです.
*straight0.bmp
outs = 1
*straight1.bmp
outs = 1
*straight2.bmp
outs = 1
*straight3.bmp
outs = 1
*straight4.bmp
outs = 1
*straight5.bmp
outs = 1
*straight6.bmp
outs = 1
*straight7.bmp
outs = 1
*straight8.bmp
outs = 1
*straight9.bmp
outs = 1
*straight10.bmp
outs = 1
*left_turn0.bmp
outs = 0
*left_turn1.bmp
outs = 0
*left_turn2.bmp
outs = 0
*left_turn3.bmp
outs = 0
*left_turn4.bmp
outs = 0
*left_turn5.bmp
outs = 0
*left_turn6.bmp
outs = 0
*left_turn7.bmp
outs = 0
*left_turn8.bmp
outs = 0
*left_turn9.bmp
outs = 0
*left_turn10.bmp
outs = 0
*right_turn0.bmp
outs = 2
*right_turn1.bmp
outs = 2
*right_turn2.bmp
outs = 2
*right_turn3.bmp
outs = 2
*right_turn4.bmp
outs = 2
*right_turn5.bmp
outs = 2
*right_turn6.bmp
outs = 1
*right_turn7.bmp
outs = 2
*right_turn8.bmp
outs = 2
*right_turn9.bmp
outs = 2
*right_turn10.bmp
outs = 2
INFO: [SIM 1] CSim done with 0 errors.
INFO: [SIM 3] *************** CSIM finish ***************


これで、問題ないと思う。

次に、C コードの合成結果を貼っておく。
wlt_cnn_151_170913.png
wlt_cnn_152_170913.png

Latency は 194426 クロックで、100 MHz 動作では、1.94 ms ということになる。
リソース使用量も問題ないと思う。

C/RTL協調シミュレーションを行った。
wlt_cnn_153_170913.png

Latency は 194463 クロックだった。

C/RTL協調シミュレーションの波形を示す。全体波形から。
wlt_cnn_154_170913.png

最初のCNNの判定部分の波形を示す。
wlt_cnn_156_170913.png
カーソルの0x1c 番地のAXI4 Lite Read でCNN の出力が出ていることを確認した。0x18 番地を読んで出力が 1 だということが分かった。次に 0x00 番地を読んで、値が 6 なので、ap_done と ap_idle が立っていることが分かる。
レジスタのアドレス・マップを貼っておく。

//------------------------Address Info-------------------
// 0x00 : Control signals
//        bit 0  - ap_start (Read/Write/COH)
//        bit 1  - ap_done (Read/COR)
//        bit 2  - ap_idle (Read)
//        bit 3  - ap_ready (Read)
//        bit 7  - auto_restart (Read/Write)
//        others - reserved
// 0x04 : Global Interrupt Enable Register
//        bit 0  - Global Interrupt Enable (Read/Write)
//        others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x10 : Data signal of ap_return
//        bit 31~0 - ap_return[31:0] (Read)
// 0x18 : Data signal of outs_V
//        bit 1~0 - outs_V[1:0] (Read)
//        others  - reserved
// 0x1c : Control signal of outs_V
//        bit 0  - outs_V_ap_vld (Read/COR)
//        others - reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)


Export RTL を行った。
wlt_cnn_155_170913.png

これも問題ないようだ。
最後に、straight_conv_nn2_axis2.cpp を貼っておく。

// straight_conv_nn2_axis2.cpp
// 2017/09/09 by marsee
// 畳み込み層のカーネル数 2
// AXI4 Stream入力 番号出力
//

#include <ap_fixed.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

#include "conv1_weight.h"
#include "conv1_bias.h"
#include "af1_weight.h"
#include "af1_bias.h"
#include "af2_weight.h"
#include "af2_bias.h"

#define REDUSED_ROW        45
#define REDUSED_COULMN    60
#define NUM_OF_KERNELS    2
#define COULMN_PIXELS    56
#define ROW_PIXELS        10
#define ALL_PIXELS        560
#define NUM_OF_OUTPUT    3

int max_ap_fixed(ap_fixed<167, AP_TRN_ZERO, AP_SAT> out[NUM_OF_OUTPUT], ap_uint<2> &out_num);

int straight_conv_nn2_axis2(hls::stream<ap_axiu<32,1,1,1> >& ins, ap_uint<2> &outs){
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE s_axilite port=outs
#pragma HLS INTERFACE axis register both port=ins
    ap_ufixed<80, AP_TRN_ZERO, AP_SAT> buf[ROW_PIXELS][COULMN_PIXELS];
    ap_fixed<136, AP_TRN_ZERO, AP_SAT> conv_out[NUM_OF_KERNELS][ROW_PIXELS-4][COULMN_PIXELS-4];
    ap_fixed<136, AP_TRN_ZERO, AP_SAT> pool_out[NUM_OF_KERNELS][(ROW_PIXELS-4)/2][(COULMN_PIXELS-4)/2];
    ap_fixed<167, AP_TRN_ZERO, AP_SAT> dot1[100];
    ap_fixed<167, AP_TRN_ZERO, AP_SAT> dot2[NUM_OF_OUTPUT];
    ap_axiu<32,1,1,1> pix;

    do {
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
    // user が 1になった時にフレームがスタートする
        ins >> pix;
    } while(pix.user == 0);

    // 10 x 56 に整形
    buf_copy1: for(int i=0; i<REDUSED_ROW; i++){
        buf_copy2: for(int j=0; j<REDUSED_COULMN; j++){
            if (!(i==0 && j==0))    // 最初の入力はすでに入力されている
                ins >> pix;    // AXI4-Stream からの入力

            if((i>=33 && i<33+ROW_PIXELS) && (j>=2 && j<2+COULMN_PIXELS)){
                buf[i-33][j-2] = (ap_ufixed<80, AP_TRN_ZERO, AP_SAT>)((ap_ufixed<168, AP_TRN_ZERO, AP_SAT>)(pix.data & 0xff) / 256);
            }
        }
    }

    // Convolutional Neural Network 5x5 kernel, Stride = 1, Padding = 0
    // + ReLU
    CONV1: for(int i=0; i<NUM_OF_KERNELS; i++){    // カーネルの個数
        CONV2: for(int j=0; j<ROW_PIXELS-4; j++){
            CONV3: for(int k=0; k<COULMN_PIXELS-4; k++){
                conv_out[i][j][k] = 0;
                CONV4: for(int m=0; m<5; m++){
                    CONV5: for(int n=0; n<5; n++){
                        conv_out[i][j][k] += buf[j+m][k+n] * conv1_weight[i][0][m][n];
                    }
                }
                conv_out[i][j][k] += conv1_bias[i];

                if(conv_out[i][j][k]<0)    // ReLU
                    conv_out[i][j][k] = 0;
            }
        }
    }

    // Pooling Kernel = 2 x 2, Stride = 2
    POOL1: for(int i=0; i<NUM_OF_KERNELS; i++){
        POOL2: for(int j=0; j<ROW_PIXELS-4; j += 2){
            POOL3: for(int k=0; k<COULMN_PIXELS-4; k += 2){
                POOL4: for(int m=0; m<2; m++){
                    POOL5: for(int n=0; n<2; n++){
                        if(m==0 && n==0){
                            pool_out[i][j/2][k/2] = conv_out[i][j][k];
                        } else if(pool_out[i][j/2][k/2] < conv_out[i][j+m][k+n]){
                            pool_out[i][j/2][k/2] = conv_out[i][j+m][k+n];
                        }
                    }
                }
            }
        }
    }

    af1_dot1: for(int col=0; col<100; col++){
        dot1[col] = 0;
        af1_dot2: for(int i=0; i<NUM_OF_KERNELS; i++){
            af1_dot3: for(int j=0; j<(ROW_PIXELS-4)/2; j++){
                af1_dot4: for(int k=0; k<(COULMN_PIXELS-4)/2; k++){
                    dot1[col] += pool_out[i][j][k]*af1_weight[i*((ROW_PIXELS-4)/2)*((COULMN_PIXELS-4)/2)+j*((COULMN_PIXELS-4)/2)+k][col];
                }
            }
        }
        dot1[col] += af1_bias[col];

        if(dot1[col] < 0)    // ReLU
            dot1[col] = 0;
    }

    af2_dot1: for(int col=0; col<NUM_OF_OUTPUT; col++){
        dot2[col] = 0;
        af2_dot2: for(int row=0; row<100; row++){
            dot2[col] += dot1[row]*af2_weight[row][col];
        }
        dot2[col] += af2_bias[col];
    }

    max_ap_fixed(dot2, outs);

    return(0);
}

int max_ap_fixed(ap_fixed<167, AP_TRN_ZERO, AP_SAT> out[NUM_OF_OUTPUT], ap_uint<2> &out_num){
    int max_id;
    ap_fixed<167, AP_TRN_ZERO, AP_SAT> max;

    for(int i=0; i<NUM_OF_OUTPUT; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    out_num = (ap_uint<2>)max_id;

    return(0);
}


  1. 2017年09月13日 04:23 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog19.fc2.com/tb.php/3913-d43c1112
この記事にトラックバックする(FC2ブログユーザー)