FC2カウンター FPGAの部屋 2018年05月11日

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

FPGAの部屋

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

テンプレートで書いた畳み込み層の入力層(ソースコード)

テンプレートで書いた畳み込み層では、汎用化するために入力のフォーマットを ap_fixed_axis にしている。このため、以前のフォーマットを ap_fixed_axis に変換する入力層が必要となった。その入力層を作っていこう。

入力層はテンプレートとしなかった。それは、やることが少なく、決まったこと(フォーマットの変換)をするだけなので、テンプレートにするメリットを見いだせなかったためだ。
それでは、input_layer.h から貼っておく。

// input_layer.h
// 2018/05/08 by marsee
//

#ifndef __INPUT_LAYER_H__
#define __INPUT_LAYER_H__

static const size_t IN_W = 32;
static const size_t OUT_W = 9;
static const size_t OUT_I = 1;

static const size_t VERTICAL_PIXEL_HIGHT = 10;
static const size_t HORIZONTAL_PIXEL_WIDTH = 56;

#endif


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

// input_layer.cpp
// 2018/05/08 by marsee
//

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

#include "layer_general.h"

#include <ap_axi_sdata.h>

#include "input_layer.h"

int input_layer(hls::stream<ap_axiu<IN_W,1,1,1> >&ins,
    hls::stream<ap_fixed_axis<OUT_W,OUT_I,1,1> >&outs){
#pragma HLS DATA_PACK variable=outs
#pragma HLS INTERFACE axis register both port=ins

    ap_axiu<IN_W,1,1,1> pix;
    ap_fixed_axis<OUT_W,OUT_I,1,1> out;

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

    Loop2: for (int y=0; y<VERTICAL_PIXEL_HIGHT; y++){
        Loop3: for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE II=1
            if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix;    // AXI4-Stream からの入力

            out.data[0] = (ap_fixed<OUT_W,OUT_I,AP_TRN,AP_WRAP>)((ap_ufixed<168, AP_TRN, AP_WRAP>)(pix.data & 0xff) / 256);
            out.user = pix.user;
            out.last = pix.last;

            outs << out;
        }
    }
    return(0);
}


テストベンチの input_layer_tb.cpp を貼っておく。なおテストベンチは、フォーマットの変換という性格上、float との値の違いを比較するということではなく、BMPファイルを読み込んでデータをフォーマット変換して、input_layer_output.h に書き込む動作となっている。

// input_layer_tb.cpp
// 2018/05/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 "layer_general.h"
#include "input_layer.h"
#include "bmp_header.h"

int input_layer(hls::stream<ap_axiu<IN_W,1,1,1> >&ins,
    hls::stream<ap_fixed_axis<OUT_W,OUT_I,1,1> >&outs);

#define BMP_FILE_NAME   "straight_RED_rect0_00_rgb.bmp"

int main(){
    using namespace std;

    hls::stream<ap_axiu<IN_W,1,1,1> > ins;
    hls::stream<ap_fixed_axis<OUT_W,OUT_I,1,1> > outs;
    ap_axiu<IN_W,1,1,1> pix;
    ap_fixed_axis<9,1,1,1> pixf;

    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr;
    int *rd_bmp;
    ap_fixed<OUT_W,OUT_I,AP_TRN,AP_WRAP> *out_vals;
    int blue, green, red;
    ap_fixed_axis<OUT_W,OUT_I,1,1> val;

    if ((fbmpr = fopen(BMP_FILE_NAME, "rb")) == NULL){ // test.bmp をオープン
        fprintf(stderr, "Can't open straight_RED_rect0_00.bmp by binary read mode\n");
        exit(1);
    }
    // bmpヘッダの読み出し
    fread(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpr);
    fread(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpr);
    fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);

    // ピクセルを入れるメモリをアロケートする
    if ((rd_bmp =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate rd_bmp memory\n");
        exit(1);
    }
    if ((out_vals =(ap_fixed<OUT_W,OUT_I,AP_TRN,AP_WRAP> *)malloc(sizeof(ap_fixed<OUT_W,OUT_I,AP_TRN,AP_WRAP>) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate hw_conv memory\n");
        exit(1);
    }

    // rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            blue = fgetc(fbmpr);
            green = fgetc(fbmpr);
            red = fgetc(fbmpr);
            rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
        }
    }
    fclose(fbmpr);

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

    // 1 画面分のデータを ins、ins_soft に入力する
    for(int j=0; j < bmpihr.biHeight; j++){
        for(int i=0; i < bmpihr.biWidth; i++){
            pix.data = (ap_uint<32>)rd_bmp[(j*bmpihr.biWidth)+i];

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

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

            ins << pix;
        }
    }

    input_layer(ins, outs);

    // 出力の outs を out_vals[] に入れる
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            outs >> val;
            out_vals[y*bmpihr.biWidth+x] = val.data[0];
        }
    }

    // ヘッダ出力
    ofstream OH("input_layer_output.h");
    OH << "// input_layer_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 __INPUT_LAYER_OUTPUT_H__" << endl;
    OH << "#define __INPUT_LAYER_OUTPUT_H__" << endl;
    OH << endl;

    OH << "const ap_fixed<9, 1, AP_TRN, AP_WRAP> conv_layer_out[" << bmpihr.biHeight*bmpihr.biWidth << "] = {" << endl;
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            OH << "    " << fixed << setprecision(12) << out_vals[bmpihr.biWidth*y+x];
            if (y==bmpihr.biHeight-1 && x==bmpihr.biWidth-1)
                OH << endl;
            else
                OH << "," << endl;
        }
    }
    OH << "};" << endl << endl;
    OH << "#endif" << endl;

    free(rd_bmp);
    free(out_vals);

    return(0);
}

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