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

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

FPGAの部屋

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

AXI4-Stream インターフェースの全結合層2層目2(C シミュレーション、C/RTL 協調シミュレーション)

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

前回は、AXI4-Stream インターフェースの全結合層2層目のC コードの合成とExport RTLを行った。今回は、C シミュレーションとC/RTL 協調シミュレーションを行う。

テストベンチの affine_layer2_tb.cpp を貼っておく。

// affine_layer2_tb.cpp
// 2018/03/09 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 "affine_layer2.h"
#include "relu_affine1_output.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);

int affine_layer2_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<ap_fixed1_axis<12,7,1,1,1> > outs;
    hls::stream<float1_axis<1,1,1> > ins_soft;
    hls::stream<float1_axis<1,1,1> > outs_soft;

    mdata_type dot;
    fmdata_type fdot;

    ap_fixed1_axis<19,7,1,1,1> pix;
    float1_axis<1,1,1> fpix;
    ap_fixed1_axis<12,7,1,1,1> pdata;
    float1_axis<1,1,1> fpdata;

    // 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 = relu_affine1_out[i];
        fpix.data.data0 = relu_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;
    }

    affine_layer2(ins, outs);
    affine_layer2_soft(ins_soft, outs_soft);

    // outs, outs_soft を dot[] と fdot[] に代入して比較する
    for(int i=0; i<NUMBER_OF_OUTPUT_LAYER; i++){
        outs >> pdata;
        outs_soft >> fpdata;

        dot.data[i] = pdata.data.data0;
        fdot.data[i] = fpdata.data.data0;

        printf("i = %d, HW = %f, SW = %f\n", i, (float)dot.data[i], fdot.data[i]);
        if((double)pow((double)dot.data[i]-(double)fdot.data[i], (double)2) > 4){ // 2乗誤差が4よりも大きい
            printf("ERROR HW and SW results mismatch i = %d, HW = %f, SW = %f\n", i, (float)dot.data[i], fdot.data[i]);
            //return(1);
        }
    }

    // max_pooling の結果をヘッダファイルに出力
    ofstream OH("affine_layer2_output.h");
    OH << "// affine_layer2_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 __AFFINE_LAYER2_OUTPUT_H__" << endl;
    OH << "#define __AFFINE_LAYER2_OUTPUT_H__" << endl;
    OH << endl;
    OH << "const float affine2_fout[" << NUMBER_OF_OUTPUT_LAYER  << "] = {" << endl;
    for (int i=0; i<NUMBER_OF_OUTPUT_LAYER ; i++){
        OH << "    " << fixed << setprecision(14) << fdot.data[i];
        if (i == NUMBER_OF_OUTPUT_LAYER-1)
            OH << endl;
        else
            OH << "," << endl;
    }
    OH << "};" << endl << endl;

    OH << "const ap_fixed<12,7,AP_TRN,AP_WRAP> affine2_out[" << NUMBER_OF_OUTPUT_LAYER << "] = {" << endl;
    for (int i=0; i<NUMBER_OF_OUTPUT_LAYER ; i++){
        OH << "    " << fixed << setprecision(14) << (float)dot.data[i];
        if (i == NUMBER_OF_OUTPUT_LAYER-1)
            OH << endl;
        else
            OH << "," << endl;
    }
    OH << "};" << endl << endl;
    OH << "#endif" << endl;

    return(0);
}

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

    float1_axis<1,1,1> stdata;
    float dot[NUMBER_OF_OUTPUT_LAYER];
    float1_axis<1,1,1> outd;

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

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

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

            float dot_temp = stdata.data.data0 * af2_fweight[i][col];
            dot[col] += dot_temp;

            if (i == NUMBER_OF_MIDDLE_LAYER-1){ // 最後はバイアスを加算する
                dot[col] += af2_fbias[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);
}


(2018/04/17:修正)
(2018/04/21 :修正)
(2018/04/25 : 修正)
このテストベンチを使用して、C シミュレーションを行った。結果を示す。
affine_layer2_13_180310.png

i = 0, HW = -5.937500, SW = -6.891395
i = 1, HW = 2.625000, SW = 1.106318
i = 2, HW = -4.031250, SW = 1.138750
ERROR HW and SW results mismatch i = 2, HW = -4.031250, SW = 1.138750

i = 0, HW = -3.875000, SW = -1.873318
ERROR HW and SW results mismatch i = 0, HW = -3.875000, SW = -1.873318
i = 1, HW = 1.218750, SW = 0.888713
i = 2, HW = -2.718750, SW = -1.423239
INFO: [SIM 1] CSim done with 0 errors.
INFO: [SIM 3] *************** CSIM finish ***************
う~ん。HW の方は i = 1 が最大だが、SW の方は i = 2 が微妙だが最大だ。
固定小数点と浮動小数点演算の差が 2 以上でエラーは出いているのだが、HW、SW共に i = 1 が最大で直進を示している。合っている。
最初の畳み込み層の画像は直進だったはず。画像に使用したstraight_RED_rect0_00_rgb.bmp を示す。
conv_layer_11_180215.png

かなり左寄りの直進なので、右旋回と言ってもおかしくない感じだ。この辺のデータの作り方が問題だと常々考えてきた。
縦 5 ピクセル、横 5 ピクセルを移動して学習画像、テスト用画像を作成しているので、左寄りよりの直進画像と右寄りの右旋回画像が同じ位置ということがあり得るのかもしれない?と思っていた。
各層を連結したシミュレーションの時に数百くらいの画像を流して、精度を確認してみよう。

次に、C/RTL 協調シミュレーションを行ったが、途中でまた進まなくなってしまった。全結合層の時は2層とも失敗というか完了しない。
affine_layer2_14_180310.png

INFO: [COSIM 212-302] Starting C TB testing ...

が終了しない。
  1. 2018年03月10日 07:49 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0