FC2カウンター FPGAの部屋 2018年03月07日

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

FPGAの部屋

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

AXI4-Stream インターフェースの全結合層後のReLU 1(C ソースコード)

AXI4-Stream インターフェースの全結合層後のReLU の第1回目で、今回はC ソースコードを貼っておく。

まずは、relu_affine1.h から貼っておく。

// relu_affine1.h
// 2018/03/06 by marsee
//

#ifndef __RELU_AFFINE1_H__
#define __RELU_AFFINE1_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

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

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

typedef ap_fixed<19,7,AP_TRN,AP_WRAP> affine_type;

#endif


次に、relu_affine1.cpp を貼っておく。

// relu_affine1.cpp
// 2018/03/06 by marsee
//

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

#include "relu_affine1.h"

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

    ap_fixed1_axis<19,7,1,1,1> af1;

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

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

        if (af1.data.data0 < affine_type(0.0)) // データが 0 以下だったら 0 にする
            af1.data.data0 = affine_type(0.0);

        outs << af1;
    }

    return(0);
}


relu_affine1_tb.cpp を貼っておく。

// relu_affine1.cpp
// 2018/03/07 by marsee
//

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <math.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>

#include "relu_affine1.h"
#include "affine_layer1_output.h"

int relu_affine1(hls::stream<ap_fixed1_axis<19,7,1,1,1> >& ins,
        hls::stream<ap_fixed1_axis<19,7,1,1,1> >& outs);

int relu_affine1_soft(hls::stream<float1_axis<1,1,1> >& ins,
        hls::stream<float1_axis<1,1,1> >& outs);

int main(){
    using namespace std;
    hls::stream<ap_fixed1_axis<19,7,1,1,1> > ins;
    hls::stream<float1_axis<1,1,1> > ins_soft;
    hls::stream<ap_fixed1_axis<19,7,1,1,1> > outs;
    hls::stream<float1_axis<1,1,1> > outs_soft;

    float relu_fout[100];
    affine_type relu_out[100];

    ap_fixed1_axis<19,7,1,1,1> pix;
    float1_axis<1,1,1> fpix;

    // ins に入力データを用意する
    for(int i=0; i<5; i++){    // dummy data
        pix.user = 0;
        pix.data.data0 = (affine_type)i;
        ins << pix;
        fpix.user = 0;
        fpix.data.data0 = (float)i;
        ins_soft << fpix;
    }

    // 1 画面分のデータを ins、ins_soft に入力する
    for(int i=0; i < NUMBER_OF_MIDDLE_LAYER; i++){
        pix.data.data0 = affine1_out[i];
        fpix.data.data0 = affine1_fout[i];

        if (i == 0){    // 最初のデータの時に TUSER を 1 にする
            pix.user = 1;
            fpix.user = 1;
        } else {
            pix.user = 0;
            fpix.user = 0;
        }

        if (i == NUMBER_OF_MIDDLE_LAYER-1){ // 行の最後でTLASTをアサートする
            pix.last = 1;
            fpix.last = 1;
        } else {
            pix.last = 0;
            fpix.last = 0;
        }

        ins << pix;
        ins_soft << fpix;
    }

    relu_affine1(ins, outs);
    relu_affine1_soft(ins_soft, outs_soft);

    // outs, outs_soft を relu_out[][], relu_fout[][] に出力する
    for(int i=0; i < NUMBER_OF_MIDDLE_LAYER; i++){
        outs >> pix;
        outs_soft >> fpix;

        relu_out[i] = pix.data.data0;
        relu_fout[i] = fpix.data.data0;

        printf("i = %d, HW = %f, SW = %f\n", i, (float)pix.data.data0, fpix.data.data0);
        if ((double)pow((double)pix.data.data0-(double)fpix.data.data0,(double)2) > 4){ // 2乗誤差が4よりも大きい
            printf("ERROR HW and SW results mismatch i = %d, HW = %f, SW = %f\n", i, (float)pix.data.data0, fpix.data.data0);
            //return(1);
        }
    }
    cout << "Success HW and SW results match" << endl;
    cout << endl;

    // ReLU の結果をヘッダファイルに出力
    ofstream OH("relu_affine1_output.h");
    OH << "// relu_affine1_output.h" << endl;
    time_t now = time(0);
    struct tm* localNow = localtime(&now);
    OH << "// " << localNow->tm_year+1900 << "/" << localNow->tm_mon+1 << "/" << localNow->tm_mday;
    OH << " " << setw(2) << setfill('0') << localNow->tm_hour << ":" << localNow->tm_min << ":" << localNow->tm_sec << " by marsee" << endl;
    OH << "//" << endl;
    OH << endl;
    OH << "#ifndef __RELU_AFFINE1_OUTPUT_H__" << endl;
    OH << "#define __RELU_AFFINE1_OUTPUT_H__" << endl;
    OH << endl;
    OH << "const float relu_affine1_fout[" << NUMBER_OF_MIDDLE_LAYER <<  "] = {" << endl;
    for (int i=0; i<NUMBER_OF_MIDDLE_LAYER ; i++){
        OH << "    " << fixed << setprecision(14) << relu_fout[i];
        if (i == NUMBER_OF_MIDDLE_LAYER-1)
            OH << endl;
        else
            OH << "," << endl;
    }
    OH << "};" << endl << endl;

    OH << "const ap_fixed<19, 7, AP_TRN, AP_WRAP> relu_affine1_out[" << NUMBER_OF_MIDDLE_LAYER <<  "] = {" << endl;
    for (int i=0; i<NUMBER_OF_MIDDLE_LAYER ; i++){
        OH << "    " << fixed << setprecision(14) << (float)relu_out[i];
        if (i == NUMBER_OF_MIDDLE_LAYER-1)
            OH << endl;
        else
            OH << "," << endl;
    }
    OH << "};" << endl << endl;
    OH << "#endif" << endl;

    return(0);
}

int relu_affine1_soft(hls::stream<float1_axis<1,1,1> >& ins,
        hls::stream<float1_axis<1,1,1> >& outs){

    float1_axis<1,1,1> af1;

    do {
    // user が 1になった時にフレームがスタートする
        ins >> af1;
    } while(af1.user == 0);

    Loop1: for (int i=0; i<NUMBER_OF_MIDDLE_LAYER; i++){
        if (i != 0)    // 最初の入力はすでに入力されている
            ins >> af1;    // AXI4-Stream からの入力

        if (af1.data.data0 < float(0.0)) // データが 0 以下だったら 0 にする
            af1.data.data0 = float(0.0);

        outs << af1;
    }

    return(0);
}


短いので貼れると思うので、affine_layer1_output.h も貼っておく。

// affine_layer1_output.h
// 2018/4/25 20:40:49 by marsee
//

#ifndef __AFFINE_LAYER1_OUTPUT_H__
#define __AFFINE_LAYER1_OUTPUT_H__

const float affine1_fout[100] = {
    -1.07044434547424,
    2.02270197868347,
    -1.05823743343353,
    6.61475515365601,
    -0.41641759872437,
    -0.43186429142952,
    -0.59285295009613,
    1.61030292510986,
    -0.86417144536972,
    -1.58257913589478,
    -1.58896744251251,
    -1.18942570686340,
    -1.29751002788544,
    -0.29641613364220,
    0.99740755558014,
    -1.56636476516724,
    1.15804195404053,
    -0.32042244076729,
    -1.29172587394714,
    -1.32565450668335,
    0.52028149366379,
    -0.77872759103775,
    -1.42185449600220,
    -1.11953997612000,
    -0.52264106273651,
    -9.46636104583740,
    1.24318540096283,
    1.48950290679932,
    -0.81046527624130,
    -0.13629606366158,
    -0.97734153270721,
    -1.32893562316895,
    -0.01425859332085,
    1.30608248710632,
    0.66073369979858,
    -1.30899047851562,
    1.64479529857635,
    -8.37205600738525,
    -0.93879777193069,
    -0.23133431375027,
    -0.70119810104370,
    14.23405647277832,
    -1.07003355026245,
    -0.59557068347931,
    -1.27445268630981,
    -0.49398189783096,
    13.72099971771240,
    1.28452575206757,
    0.00934629142284,
    -0.96886688470840,
    -0.59863859415054,
    -1.30126535892487,
    2.04380607604980,
    -0.86902260780334,
    3.03090858459473,
    -1.28547608852386,
    2.02088475227356,
    -0.50959372520447,
    2.04253935813904,
    -0.87841814756393,
    1.49199974536896,
    3.59934496879578,
    -0.50308769941330,
    3.50621104240417,
    -1.47892177104950,
    -0.40191367268562,
    -1.44002544879913,
    2.27853059768677,
    -1.31562995910645,
    -2.41246962547302,
    0.74652028083801,
    3.59772849082947,
    -0.15781980752945,
    -0.73974257707596,
    -1.69656479358673,
    -0.83578699827194,
    1.48410618305206,
    -0.45701009035110,
    -1.51373767852783,
    -1.64361524581909,
    -1.52793812751770,
    0.05682089924812,
    -0.87240159511566,
    0.13656859099865,
    0.39985269308090,
    -1.70221209526062,
    -1.72491621971130,
    -0.40194845199585,
    -0.78374582529068,
    -0.47359892725945,
    -1.49441266059875,
    -0.55138188600540,
    1.75030672550201,
    2.03031945228577,
    -0.60934787988663,
    -0.40171664953232,
    1.81010317802429,
    1.34133112430573,
    -0.33451518416405,
    -0.36992445588112
};

const ap_fixed<19,7,AP_TRN,AP_WRAP> affine1_out[100] = {
    -1.22485351562500,
    2.79467773437500,
    -1.23950195312500,
    9.45532226562500,
    -0.39111328125000,
    -0.36645507812500,
    -0.56665039062500,
    2.11010742187500,
    -0.92529296875000,
    -1.86206054687500,
    -1.90454101562500,
    -1.38159179687500,
    -1.51977539062500,
    0.04516601562500,
    1.44580078125000,
    -1.82397460937500,
    1.67358398437500,
    0.02636718750000,
    -1.50488281250000,
    -1.54272460937500,
    0.99658203125000,
    -0.83862304687500,
    -1.65795898437500,
    -1.28344726562500,
    -0.54541015625000,
    -12.42919921875000,
    2.00537109375000,
    2.03759765625000,
    -0.84692382812500,
    0.27978515625000,
    -1.04248046875000,
    -1.56860351562500,
    0.30810546875000,
    1.99609375000000,
    1.28930664062500,
    -1.57373046875000,
    2.31689453125000,
    -10.94824218750000,
    -1.01269531250000,
    -0.13574218750000,
    -0.75708007812500,
    19.37792968750000,
    -1.22167968750000,
    -0.62182617187500,
    -1.48803710937500,
    -0.42578125000000,
    18.65820312500000,
    1.73413085937500,
    0.23950195312500,
    -1.07177734375000,
    -0.56103515625000,
    -1.52734375000000,
    2.82861328125000,
    -0.97363281250000,
    4.35302734375000,
    -1.52099609375000,
    2.71801757812500,
    -0.51782226562500,
    2.75024414062500,
    -0.91528320312500,
    2.07055664062500,
    5.08178710937500,
    -0.45678710937500,
    5.00292968750000,
    -1.72045898437500,
    -0.33129882812500,
    -1.07739257812500,
    3.32397460937500,
    -1.51245117187500,
    -2.93920898437500,
    1.01025390625000,
    5.14819335937500,
    0.18505859375000,
    -0.82324218750000,
    -2.02026367187500,
    -0.84716796875000,
    2.06396484375000,
    -0.40454101562500,
    -1.78906250000000,
    -1.94873046875000,
    -1.20434570312500,
    0.45068359375000,
    -0.93212890625000,
    0.40722656250000,
    0.64453125000000,
    -2.00488281250000,
    -2.01147460937500,
    -0.34863281250000,
    -0.85351562500000,
    -0.40234375000000,
    -1.76367187500000,
    -0.55029296875000,
    2.29492187500000,
    2.72192382812500,
    -0.56152343750000,
    -0.37280273437500,
    2.56713867187500,
    1.82861328125000,
    -0.26318359375000,
    -0.34667968750000
};

#endif

  1. 2018年03月07日 04:51 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0