FC2カウンター FPGAの部屋 2018年03月09日
FC2ブログ

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

FPGAの部屋

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

AXI4-Stream インターフェースの全結合層2層目1(指示子による性能差)

AXI4-Stream インターフェースの 全結合層後のReLU の後に続いて、AXI4-Stream インターフェースの全結合層2層目を作っていこう。

まずは、affine_layer2 のVivado HLS 2017.4 プロジェクトを作成し、affine_layer2.h , affine_layer2.cpp を作成した。affine_layer2_tb.cpp はまだ実装が間に合わず、途中までとなっている。
affine_layer2_1_180309.png

affine_layer2.cpp の一部分を示す。affine_layer1.cpp を全結合層2層目用に書き換えてある。
affine_layer2_2_180309.png

C コードの合成を行った。結果を示す。
affine_layer2_3_180309.png

Estmated は 10.38 ns と 10 ns をオーバーしてしまっている。
Latency は min が 1,002 クロック、max が 1,102 クロックだった。
リソース使用量は、BRAM_18K は1 個、DSP48E も 1 個、FF が 405 個、LUT が 1,057 個だった。

さて、Latency がもっと短くなると思われるので、Loop2 にPIPELINE指示子を入れてみた。II は合成結果を見ると、Loop2 が 10 ~ 11 クロックかかっているので、II = 8 としてみる。
affine_layer2_4_180309.png

これで、C コードの合成を行った。結果を示す。
affine_layer2_5_180309.png

Estmated は 6.38 ns になって、タイミング制約を満たしている。
Latency は 803 クロックになった。思い通りになった。
リソース使用量は、BRAM_18K は2 個、DSP48E は3 個で、前回よりもそれぞれ 1 個と 2 個増えている。FF は 405 個から 451 個で増えているが、LUT は 1,057 個から 882 個で減った。

次に、Loop2 のPIPELINE指示子の II を 5 にしてみよう。
affine_layer2_6_180309.png

C コードの合成を行った。結果を示す。
affine_layer2_7_180309.png

Estmated は6.38 ns でタイミング制約を満たしている。
Latency は 505 クロックで、予定通りだ。
BRAM_18K は2 個、DSP48E は3 個で変化なし。FF は II = 8 の時よりも 451 個から 452 個で 1 個増えた。LUTは 882 個から 969 個で増えている。

Loop2 のPIPELINE指示子の II を 3 にしてみよう。これが、Loop4 のTrip Count と一致していてちょうど良いはず。
affine_layer2_8_180309.png

C コードの合成を行った。結果を示す。
affine_layer2_9_180309.png

Estmated は6.38 ns でタイミング制約を満たしている。
Latency は 307 クロックで、予定通りだ。
BRAM_18K は2 個、DSP48E は3 個で変化なし。FF は II = 5 の時よりも 452 個から 451 個で 1 個減った。LUTは 969 個から 942個で減っている。これが良さそうだ。

それでは、無茶振りして、Loop2 のPIPELINE指示子の II を 2 にしてみよう。
affine_layer2_10_180309.png

C コードの合成を行った。結果を示す。
affine_layer2_11_180309.png

結果は、PIPELINE指示子の II が 3 の時と同様だった。
やはり、Lpop4 のTrip Count よりも短いので、Loop4 をUNROLL するしかなくなるので、とりあえず無理のようだ。(他に指示子を加えたり、コードを書き換えれば可能だと思う)

PIPELINE指示子の II は 3 に戻して、もう一度、合成を行った。
次に、Export RTL を行った。結果を示す。
なお、Vivado synthesis, place and route にチェックを入れてある。
affine_layer2_12_180309.png

LUT は308 個、FF は 366 個、DSP は 3 個、BRAM は 2 個使用している。
CP achieved post-implementation は 7.056 ns だった。問題なさそうだ。

affine_layer2.h を貼っておく。

// affine_layer2.h
// 2018/03/08 by marsee
//

#ifndef __AFFINE_LAYER2_H__
#define __AFFINE_LAYER2_H__
#include <ap_fixed.h>

template<int W, int I, int U, int TI, int TD>
    struct ap_fixed1_axis{
        struct data {
            ap_fixed<W,I,AP_TRN,AP_WRAP> data0;
        } data;
        ap_uint<(W+7)/8> keep;
        ap_uint<(W+7)/8> strb;
        ap_uint<U>       user;
        ap_uint<1>       last;
        ap_uint<TI>      id;
        ap_uint<TD>      dest;
    };

template<int U, int TI, int TD>
    struct float1_axis{
        struct data {
            float data0;
        } data;
        ap_uint<1> keep;
        ap_uint<1> strb;
        ap_uint<U>       user;
        ap_uint<1>       last;
        ap_uint<TI>      id;
        ap_uint<TD>      dest;
    };

#define NUMBER_OF_MIDDLE_LAYER    100

#define NUMBER_OF_OUTPUT_LAYER    3

typedef struct {
    ap_fixed<12,7,AP_TRN,AP_WRAP> data [NUMBER_OF_OUTPUT_LAYER];
} mdata_type;

typedef struct {
    float data [NUMBER_OF_OUTPUT_LAYER];
} fmdata_type;

typedef ap_fixed<12,7,AP_TRN,AP_WRAP> out_type;

#endif


affine_layer2.cpp を貼っておく。

// affine_layer2.cpp
// 2018/03/08 by marsee
//

#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>

#include "affine_layer2.h"
#include "af2_weight.h"
#include "af2_bias.h"

int affine_layer2(hls::stream<ap_fixed1_axis<19,7,1,1,1> >& ins,
        hls::stream<ap_fixed1_axis<12,7,1,1,1> >& outs){
#pragma HLS INTERFACE axis register both port=outs
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE axis register both port=ins

    ap_fixed1_axis<19,7,1,1,1> stdata;
    out_type dot[NUMBER_OF_OUTPUT_LAYER];
    ap_fixed1_axis<12,7,1,1,1> outd;

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

    Loop2: for (int i=0; i<NUMBER_OF_MIDDLE_LAYER; i++){
#pragma HLS PIPELINE II=3
        if (i != 0)    // 最初の入力はすでに入力されている
            ins >> stdata;    // AXI4-Stream からの入力

        Loop4: for (int col=0; col<NUMBER_OF_OUTPUT_LAYER; col++){
#pragma HLS PIPELINE II=1
            if (i == 0// 最初は 0 にクリアする
                dot[col] = 0;

            out_type dot_temp = stdata.data.data0 * af2_weight[i][col];
            dot[col] += dot_temp;

            if (i == NUMBER_OF_MIDDLE_LAYER-1){ // 最後はバイアスを加算する
                dot[col] += af2_bias[col];

                outd.data.data0 = dot[col];

                if(col == 0)
                    outd.user = 1;
                else
                    outd.user = 0;

                if(col == NUMBER_OF_OUTPUT_LAYER-1)
                    outd.last = 1;
                else
                    outd.last = 0;

                outs << outd;
            }
        }
    }

    return(0);
}

  1. 2018年03月09日 05:54 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0