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

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

FPGAの部屋

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

AXI4-Stream インターフェースの最終出力層1(C ソースコード)

AXI4-Stream インターフェースの最終出力層を作っていく。この層は、全結合層2層目のAXI4-Stream 出力を受けて、最大値の出力の配列の値に1 をセットして、それ以外の配列の値は 0 にする。

まずは、AXI4-Stream インターフェースの最終出力層のC ソースコードを貼っておく。
output_layer1.h から貼っておく。

// output_layer.h
// 2018/03/11 by marsee
//

#ifndef __OUTPUT_LAYER_H__
#define __OUTPUT_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 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 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 struct {
    ap_uint<1> data [NUMBER_OF_OUTPUT_LAYER];
} out_data_type;


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

typedef ap_uint<1> output_type;
#endif


output_layer.cpp を貼っておく。

// output_layer.cpp
// 2018/03/11 by marsee
//

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

#include "output_layer.h"

int output_layer(hls::stream<ap_fixed1_axis<12,7,1,1,1> >& ins,
        out_data_type& output){
#pragma HLS DATA_PACK variable=output
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE axis register both port=ins

    ap_fixed1_axis<12,7,1,1,1> stdata;
    mdata_type af2;
    int max_num;
    out_affine_type max_val;

    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_OUTPUT_LAYER; i++){
#pragma HLS PIPELINE II=1
        if(i != 0)    // 最初の入力はすでに入力されている
            ins >> stdata;    // AXI4-Stream からの入力

        af2.data[i] = stdata.data.data0;
    }

    max_val = 0;
    Loop3: for(int i=0; i<NUMBER_OF_OUTPUT_LAYER; i++){
#pragma HLS UNROLL
        if(i == 0){
            max_val = af2.data[0];
            max_num = 0;
        } else if (max_val < af2.data[i]){
            max_val = af2.data[i];
            max_num = i;
        }
    }

    Loop4: for(int i=0; i<NUMBER_OF_OUTPUT_LAYER; i++){
#pragma HLS UNROLL
        if(i == max_num)
            output.data[i] = output_type(1);
        else
            output.data[i] = output_type(0);
    }

    return(0);
}


output_layer_tb.cpp を貼っておく。

// output_layer_tb.cpp
// 2018/03/12 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 "output_layer.h"
#include "affine_layer2_output.h"

int output_layer(hls::stream<ap_fixed1_axis<12,7,1,1,1> >& ins,
        out_data_type& output);

int output_layer_soft(hls::stream<float1_axis<1,1,1> >& ins,
        out_data_type& output);

int main(){
    using namespace std;

    hls::stream<ap_fixed1_axis<12,7,1,1,1> > ins;
    hls::stream<float1_axis<1,1,1> > ins_soft;

    ap_fixed1_axis<12,7,1,1,1> pix;
    float1_axis<1,1,1> fpix;
    out_data_type out, out_soft;

    // ins に入力データを用意する
    for(int i=0; i<5; i++){    // dummy data
        pix.user = 0;
        pix.data.data0 = (out_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_OUTPUT_LAYER; i++){
        pix.data.data0 = affine2_out[i];
        fpix.data.data0 = affine2_fout[i];

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

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

        ins << pix;
        ins_soft << fpix;
    }

    output_layer(ins, out);
    output_layer_soft(ins_soft, out_soft);

    // out と out_soft を比較する
    for(int i=0; i < NUMBER_OF_OUTPUT_LAYER; i++){
        cout << "out" << "[" << i << "] = " << int(out.data[i]) << " out_soft" << "[" << i << "] = " << int(out_soft.data[i]) << endl;
        if(out.data[i] != out_soft.data[i]){
            cerr << "Error: out" << "[" << i << "] = " << int(out.data[i]) << " out_soft" << "[" << i << "] = " << int(out_soft.data[i]) << endl;
            // return(1);
        }
    }

    return(0);
}

int output_layer_soft(hls::stream<float1_axis<1,1,1> >& ins,
        out_data_type& output){

    float1_axis<1,1,1> stdata;
    fmdata_type af2;
    int max_num;
    float max_val;

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

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

        af2.data[i] = stdata.data.data0;
    }

    max_val = 0;
    Loop3: for(int i=0; i<NUMBER_OF_OUTPUT_LAYER; i++){
        if(i == 0){
            max_val = af2.data[0];
            max_num = 0;
        } else if (max_val < af2.data[i]){
            max_val = af2.data[i];
            max_num = i;
        }
    }

    Loop4: for(int i=0; i<NUMBER_OF_OUTPUT_LAYER; i++){
        if(i == max_num)
            output.data[i] = output_type(1);
        else
            output.data[i] = output_type(0);
    }

    return(0);
}


最後に全結合層2層目の出力を記述した affine_layer2_output.h を貼っておく。

// affine_layer2_output.h
// 2018/4/25 21:25:42 by marsee
//

#ifndef __AFFINE_LAYER2_OUTPUT_H__
#define __AFFINE_LAYER2_OUTPUT_H__

const float affine2_fout[3] = {
    -1.87331771850586,
    0.88871324062347,
    -1.42323863506317
};

const ap_fixed<12,7,AP_TRN,AP_WRAP> affine2_out[3] = {
    -3.87500000000000,
    1.21875000000000,
    -2.71875000000000
};

#endif

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