FC2カウンター FPGAの部屋 AXI4-Stream インターフェースの畳み込みニューラルネットワーク1(概要説明)
FC2ブログ

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

FPGAの部屋

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

AXI4-Stream インターフェースの畳み込みニューラルネットワーク1(概要説明)

いよいよ今まで作ってきたAXI4-Stream インターフェースの各層をつないで、AXI4-Stream インターフェースの畳み込みニューラルネットワークをテストしていこう。

まずは、Vivado HLS 2017.4 で all_layers というプロジェクトを作成した。
all_layers_1_180315.png

プロジェクトにはファイルがたくさん入っている。
all_layers プロジェクトのフォルダを示す。
all_layers_2_180315.png

all_layers.cpp が今までのハードウェア化する各層の C ソースコードを接続するファイルで、all_layers_soft.cpp は、float で実装した各層の C ソースコードを接続するファイルだ。all_layers_soft.cpp はテストベンチでの比較用となる。
all_layers_tb.cpp がテストベンチだ。
curve_data_0_100.h, curve_data_2500_2600.h, curve_data_5000_5100.h は、”カーブ、直線用白線間走行用畳み込みニューラルネットワーク11(画像データをCのヘッダファイルに変換)”で作成された白線間走行用のテスト画像を数値化したヘッダファイルになる。名前では100 個のデータの様に見えるが、実は300 個の画像データが保存されている。今回は、これらのヘッダの 8 ビットの画像データの int t_train_256[300][560] を使用する。
all_layers_6_180315.png

さて、all_layers フォルダの下の hw_ip フォルダには、各層のハードウェア化する C ソースファイルがある。
all_layers_3_180315.png

これらの C ソースファイルは今までやってきたファイルと同じものだが、ブロック・レベルのインターフェースの指示子はコメントアウトしてある。こうしないと、最後のExport RTLで回路が無くなってしまうためだ。conv_layer.cpp を例として示しておく。
all_layers_5_180315.png

all_layers フォルダにある all_layers.cpp が各層の C ソースコードを接続するファイルとなる。

all_layers フォルダの下の sw_ip フォルダは、各層で、テストベンチに含まれていた float で演算する各層の C ソースコードを独立させた C ソースファイルがある。それらが、****_soft.c ファイルだ。
all_layers_4_180315.png

all_layers フォルダにある all_layers_soft.cpp が float で実装した各層の C ソースコードを接続するファイルとなる。

all_layers.h を示す。

// all_layers.h
// 2018/03/13 by marsee
//

#ifndef __ALL_LAYER_H__
#define __ALL_LAYER_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 W, int I, int U, int TI, int TD>
    struct ap_fixed2_axis{
        struct data {
            ap_fixed<W,I,AP_TRN,AP_WRAP> data0;
            ap_fixed<W,I,AP_TRN,AP_WRAP> data1;
        } 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 float2_axis{
        struct data {
            float data0;
            float data1;
        } 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;
    };

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_OUTPUT_LAYER    3

typedef ap_uint<2> output_type;

typedef ap_fixed<12,7,AP_TRN,AP_WRAP> out_affine_type;
#endif


all_layers.cpp を示す。

// all_layers.cpp
// 2018/03/12 by marsee
//

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

#include "all_layers.h"

int conv_layer(hls::stream<ap_axiu<32,1,1,1> >& ins,
        hls::stream<ap_fixed2_axis<16,6,1,1,1> >& outs);

int relu(hls::stream<ap_fixed2_axis<16,6,1,1,1> >& ins,
        hls::stream<ap_fixed2_axis<16,6,1,1,1> >& outs);

int max_pooling(hls::stream<ap_fixed2_axis<16,6,1,1,1> >& ins,
        hls::stream<ap_fixed2_axis<16,6,1,1,1> >& outs);

int affine_layer1(hls::stream<ap_fixed2_axis<16,6,1,1,1> >& ins,
        hls::stream<ap_fixed1_axis<19,7,1,1,1> >& outs);

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 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 output_layer(hls::stream<ap_fixed1_axis<12,7,1,1,1> >& ins, output_type& output,
        out_affine_type dot2[NUMBER_OF_OUTPUT_LAYER]);

int all_layers(hls::stream<ap_axiu<32,1,1,1> >& ins, output_type& output,
        out_affine_type dot2[NUMBER_OF_OUTPUT_LAYER]){
#pragma HLS INTERFACE s_axilite port=output
#pragma HLS INTERFACE s_axilite port=dot2
#pragma HLS ARRAY_PARTITION variable=dot2 complete dim=1
#pragma HLS DATAFLOW
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE axis register both port=ins

    hls::stream<ap_fixed2_axis<16,6,1,1,1> > outs_conv_layer;
//#pragma HLS STREAM variable=outs_conv_layer depth=312 dim=1
    hls::stream<ap_fixed2_axis<16,6,1,1,1> > outs_relu;
//#pragma HLS STREAM variable=outs_relu depth=312 dim=1
    hls::stream<ap_fixed2_axis<16,6,1,1,1> > outs_max_pooling;
//#pragma HLS STREAM variable=outs_max_pooling depth=78 dim=1
    hls::stream<ap_fixed1_axis<19,7,1,1,1> > outs_affine_layer1;
//#pragma HLS STREAM variable=outs_affine_layer1 depth=100 dim=1
    hls::stream<ap_fixed1_axis<19,7,1,1,1> > outs_relu_affine1;
//#pragma HLS STREAM variable=outs_relu_affine1 depth=100 dim=1
    hls::stream<ap_fixed1_axis<12,7,1,1,1> > outs_affine_layer2;
//#pragma HLS STREAM variable=outs_affine_layer2 depth=3 dim=1

    conv_layer(ins, outs_conv_layer);
    relu(outs_conv_layer, outs_relu);
    max_pooling(outs_relu, outs_max_pooling);
    affine_layer1(outs_max_pooling, outs_affine_layer1);
    relu_affine1(outs_affine_layer1, outs_relu_affine1);
    affine_layer2(outs_relu_affine1, outs_affine_layer2);
    output_layer(outs_affine_layer2, output, dot2);

    return(0);
}


all_layers_tb.cpp を示す。

// all_layers_tb.cpp
// 2018/03/14 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 "all_layers.h"

#include "curve_data_0_100.h"
//#include "curve_data_2500_2600.h"
//#include "curve_data_5000_5100.h"

#define ALL_DATA_NUM   300
#define NUM_OF_KERNELS 2
#define COULMN_PIXELS 56
#define ROW_PIXELS 10
#define ALL_PIXELS 560
#define NUM_OF_OUTPUT 3

#define NUM_ITERATIONS    300 // C Simulation
//#define NUM_ITERATIONS    1 // C/RTL CoSimulation

int all_layers(hls::stream<ap_axiu<32,1,1,1> >& ins, output_type& output,
        out_affine_type dot2[NUMBER_OF_OUTPUT_LAYER]);

int all_layers_soft(hls::stream<ap_axiu<32,1,1,1> >& ins, output_type& output,
        float dot2[NUMBER_OF_OUTPUT_LAYER]);

int main(){
    using namespace std;

    hls::stream<ap_axiu<32,1,1,1> > ins;
    hls::stream<ap_axiu<32,1,1,1> > ins_soft;
    output_type output, output_soft;
    out_affine_type dot2[NUMBER_OF_OUTPUT_LAYER];
    float dot2_soft[NUMBER_OF_OUTPUT_LAYER];
    ap_axiu<32,1,1,1> pix;
    int hw_err_cnt = 0;
    int sw_err_cnt = 0;

    for(int i=0; i<NUM_ITERATIONS; i++){
        // ins に入力データを用意する
        for(int m=0; m<5; m++){    // dummy data
            pix.user = 0;
            pix.data = ap_uint<32>(m);
            ins << pix;
        }

        for(int y=0; y<ROW_PIXELS; y++){
            for(int x=0; x<COULMN_PIXELS; x++){
                // 1 画面分のデータを ins、ins_soft に入力する
                pix.data = ap_uint<32>(t_train_256[i][y*COULMN_PIXELS+x]);

                if (x==0 && y==0)    // 最初のデータの時に TUSER を 1 にする
                    pix.user = 1;
                else
                    pix.user = 0;

                if (x == COULMN_PIXELS-1// 行の最後でTLASTをアサートする
                    pix.last = 1;
                else
                    pix.last = 0;

                ins << pix;
                ins_soft << pix;
            }
        }

        all_layers(ins, output, dot2);
        all_layers_soft(ins_soft, output_soft, dot2_soft);

        int t_test_num = 0;
        for(int m=0; m<NUMBER_OF_OUTPUT_LAYER; m++){
            if(t_test[i][m] == 1.0f){
                t_test_num = m;
                break;
            }
        }
        // out と out_soft を比較する
        /* cout << "output" << " = " << int(output) << " output_soft = " << int(output_soft) << endl;        for(int j=0; j<NUMBER_OF_OUTPUT_LAYER; j++){            cout << "dot2[" << j << "] = " << float(dot2[j]) << " dot2_soft[" << j << "] = " << dot2_soft[j] << endl;        } */
        if(int(output) != t_test_num){
            cout << "hw_error: i = " << i << " output = " << int(output) << " t_test_num = " << t_test_num << endl;
            hw_err_cnt++;
            //return(1);
        }
        if(int(output_soft) != t_test_num){
            cout << "sw_error: i = "<< i << " output_soft = " << int(output_soft) << " t_test_num" " = " << t_test_num << endl;
            sw_err_cnt++;
            //return(1);
        }
        if(int(output) != t_test_num || int(output_soft) != t_test_num){
            for(int j=0; j<NUMBER_OF_OUTPUT_LAYER; j++){
                cout << "dot2[" << j << "] = " << fixed << setprecision(8) << float(dot2[j]) << "    dot2_soft[" << j << "] = " << dot2_soft[j] << endl;
            }
            cout << endl;
        }
    }
    cout << "hw_err_cnt = " << hw_err_cnt << " sw_err_cnt = " << sw_err_cnt << endl;

    return(0);
}

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

コメント

コメントの投稿


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

トラックバック URL
https://marsee101.blog.fc2.com/tb.php/4107-0b471817
この記事にトラックバックする(FC2ブログユーザー)