FC2カウンター FPGAの部屋 MNISTのCNN 用DMA IP 1(C シミュレーション)
FC2ブログ

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

FPGAの部屋

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

MNISTのCNN 用DMA IP 1(C シミュレーション)

MNISTのCNN 用のDMA IP を作成した。
MNISTのCNN は、ap_uint<8> のHLS ストリーム・データを入力する。よって、MNISTのCNN に手書き数字データを供給するために画像を切り取り 28 x 28 ピクセルのHLSストリーム・データを供給する mnist_square_dma IP を作成する。

Vivado HLS 2018.2 の mnist_square_dma プロジェクトを示す。
mnist_square_dma_1_180621.png

mnist_square_dma.cpp を示す。

// mnist_square_dma.cpp
// 2018/06/19 by marsee
//

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

int conv_rgb2y(int rgb);

int mnist_square_dma(int in[22400], int addr_offset, hls::stream<ap_axiu<8,1,1,1> >&outs){
#pragma HLS INTERFACE axis register both port=outs
#pragma HLS INTERFACE m_axi depth=22400 port=in offset=slave
#pragma HLS INTERFACE s_axilite port=return

    ap_axiu<8,1,1,1> pixel;

    row_count: for(int i=0; i<28; i++){
        column_count: for(int j=0; j<28; j++){
#pragma HLS PIPELINE II=1
            pixel.data = 255 - conv_rgb2y(in[addr_offset+i*800+j]);
            // 白地に黒数字から黒地に白数字に変換

            if(i==0 && j==0)
                pixel.user = 1;
            else
                pixel.user = 0;
            if(j == 27)
                pixel.last = 1;
            else
                pixel.last = 0;

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

// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
    int r, g, b, y_f;
    int y;

    b = rgb & 0xff;
    g = (rgb>>8) & 0xff;
    r = (rgb>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
    y = y_f >> 8// 256で割る

    if (y >= 256)
        y = 255;

    return(y);
}


mnist_square_dma_tb.cpp を示す。

// mnist_square_dma_tb.cpp
// 2018/06/21 by marsee
//

#include <stdio.h>
#include <ap_fixed.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

#include "bmp_header.h"

#define READ_BMP_FILE_NAME    "bmp_file0.bmp"

// 8
#define X_POS    560
#define Y_POS    183
// 7
//#define X_POS    504
//#define Y_POS    184
// 5
//#define X_POS    390
//#define Y_POS    138
// 0
//#define X_POS    390
//#define Y_POS    70
#define WIDTH    28
#define HEIGHT    28

int mnist_square_dma(int in[22400], int addr_offset, hls::stream<ap_axiu<8,1,1,1> >&outs);

int main(){
    int *in;
    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr;
    int *rd_bmp;
    int blue, green, red;
    hls::stream<ap_axiu<8,1,1,1> > outs;
    ap_axiu<8,1,1,1> pixel;

    if ((fbmpr = fopen(READ_BMP_FILE_NAME, "rb")) == NULL){ // test.bmp をオープン
        fprintf(stderr, "Can't open ");
        fprintf(stderr, READ_BMP_FILE_NAME);
        fprintf(stderr, " 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 ((in =(int *)malloc(sizeof(int) * (800 * 28))) == NULL){
        fprintf(stderr, "Can't allocate (ap_ufixed<8, 0, AP_TRN_ZERO, AP_SAT>)in 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);

    // rd_bmp を in に入力
    for (int y=Y_POS; y<Y_POS+HEIGHT; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            in[(y-Y_POS)*bmpihr.biWidth+x] = rd_bmp[y*bmpihr.biWidth+x];
        }
    }

    mnist_square_dma(in, X_POS, outs);

    for (int y=0; y<HEIGHT; y++){
        for (int x=0; x<WIDTH; x++){
            outs >> pixel;
            if(pixel.data >= 0x80)
                printf("*");
            else
                printf(" ");
        }
        printf("\n");
    }

    free(rd_bmp);
    free(in);

    return(0);
}


mnist_square_dma_tb.cpp で 下の画像の手書き数字を切り取る。
mnist_square_dma_3_180621.jpg

現在の mnist_square_dma_tb.cpp は 8 を切り取るようになっている。C シミュレーションをしてみよう。
mnist_square_dma_2_180621.png

ご覧の通りに 8 が切り取られている。

7 の切り取り。
mnist_square_dma_4_180621.png

5 の切り取り。
mnist_square_dma_5_180621.png

0 の切り取り。
mnist_square_dma_6_180621.png
  1. 2018年06月21日 05:29 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

トラックバック URL
http://marsee101.blog19.fc2.com/tb.php/4204-bc9bec69
この記事にトラックバックする(FC2ブログユーザー)