FC2カウンター FPGAの部屋 2018年06月

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

FPGAの部屋

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

「ハン・ソロ」(スターウォーズの映画)を見てきました

今日、「ハン・ソロ」(スターウォーズの映画)を見てきました。USでは評判悪いようですが、私は楽しめました。
  1. 2018年06月30日 21:42 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Kerasを使用したMNIST CNNで手書き文字認識5(実機確認2)

”Kerasを使用したMNIST CNNで手書き文字認識4(実機確認)”の続き。

前回は、SDK でPYNQボードをコンフィギュレーションし、アプリケーションソフトの mnist_conv_soft_test.elf を起動してPYNQボードで動作を確認した。今回はアプリケーションソフトを動作させて、自分で書いた手書き数字を認識させてみよう。

SDK で Xilinx メニューから Program FPGA を選択して、FPGA をコンフィギュレーションして、mnist_conv_soft_test.elf を右クリックし、右クリックメニューからRun As -> 1 Launch on Hardware (System Debugger) を選択して、アプリケーションソフトをRun するとHMDI out にカメラ画像が出力された。
keras_minst_cnn_18_180629.jpg

一番下の段の手書き数字を認識させよう。
最初に 1 にピンクの四角枠を合わせて 1 を認識させる。
keras_minst_cnn_19_180629.png

ハードウェアのCNN の認識時間は約 1.03 ms でソフトウェアでは、35.00 ms だった。ハードウェアの方はVivado HLS 2018.2 でのレイテンシとほぼ同じだった。ただし、四角枠の位置を調整してもどうしても 1 のはずが 3 と誤認されてしまう。ソフトウェアは以前のCNN で特徴マップが 10 個のものを使用している。こちらは、きちんと 1 と認識されている。

次に 2 を認識させよう。
keras_minst_cnn_20_180629.png

こちらは 2 と認識した。

3 を認識させる。
keras_minst_cnn_21_180629.png

3 も認識できた。

4 を認識させた。
keras_minst_cnn_22_180629.png

4 もどう位置を調整しても 8 と誤認されてしまう。

5 を認識させた。
keras_minst_cnn_23_180629.png

5 は問題無く認識できている。

6 を認識させた。
keras_minst_cnn_24_180629.png

6 は 8 と誤認された。

7 を認識させた。
keras_minst_cnn_25_180629.png

7 は 3 と誤認された。

8 を認識させた。
keras_minst_cnn_26_180629.png

8 は問題無く認識された。

9 を認識させた。
keras_minst_cnn_27_180629.png

9 は問題無く認識された。

0 を認識させた。
keras_minst_cnn_28_180629.png

0 も問題なく認識できた。

1, 4, 6, 7 が誤認してしまう。以前の 10 個の特徴マップのCNN では、正常に認識しているので、手書き数字は大丈夫だと思うのだが。。。量子化の精度、および飽和演算に問題があるのか?はたまた過学習になっているのかを検証するために、今回の特徴マップが 3 個の時の float 演算のCNN を動作させてみよう。これが問題無く認識できているようならば、量子化の精度、および飽和演算に問題があるということになる。
  1. 2018年06月30日 05:19 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

Kerasを使用したMNIST CNNで手書き文字認識4(実機確認)

Kerasを使用したMNIST CNNで手書き文字認識3(ビットストリームの生成、SDK)”の続き。

前回は、 PYNQ_MNIST_CNN3_182 フォルダVivado 2018.2 プロジェクトの論理合成、インプリメンテーション、ビットストリームの生成を行い、SDK でアプリケーションソフトの mnist_conv_soft_test.c を今回のプロジェクトに合うように変更した。今回は、SDK でPYNQボードをコンフィギュレーションし、アプリケーションソフトの mnist_conv_soft_test.elf を起動してPYNQボードで動作を確認する。

まずは、SDK で Xilinx メニューから Program FPGA を選択して、FPGA をコンフィギュレーションした。
次に、mnist_conv_soft_test.elf を右クリックし、右クリックメニューからRun As -> 1 Launch on Hardware (System Debugger) を選択して、アプリケーションソフトをRun したが、全く反応がない。
そこで、Debug モードでどこまで行くのか試してみることにした。
すると、ビットマップ・ディスプレイ・コントローラにフレーム・バッファのアドレスを書くところで止まってしまうことが分かった。
keras_minst_cnn_12_180628.png
keras_minst_cnn_13_180628.png

これは、いつもの、AXI Interconnect のアップデート問題ではないだろうか?今回も、Vivado 2017.2 からVivado 2018.2 へアップグレードしている。(”Vivado 2016.2 からVivado 2016.4 へアップグレード”参照)
AXI4 Lite 用のAXI Interconnect つまり、IP のレジスタにアクセスする用のAXI Interconnect を削除して、Add IP することにした。

下のブロックデザインで、選択されたAXI Interconnect を削除する。
keras_minst_cnn_14_180628.png

削除したところ。
keras_minst_cnn_15_180628.png

これで、Run Connection Automation を行うと、AXI SmartConnect がAdd IP された。
keras_minst_cnn_16_180628.png

Address Editor を示す。
keras_minst_cnn_17_180628.png

SDK で Xilinx メニューから Program FPGA を選択して、FPGA をコンフィギュレーションして、mnist_conv_soft_test.elf を右クリックし、右クリックメニューからRun As -> 1 Launch on Hardware (System Debugger) を選択して、アプリケーションソフトをRun するとHMDI out にカメラ画像が出力された。
keras_minst_cnn_18_180629.jpg
  1. 2018年06月29日 05:02 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

Kerasを使用したMNIST CNNで手書き文字認識3(ビットストリームの生成、SDK)

Kerasを使用したMNIST CNNで手書き文字認識2(all_layers IP の挿入)”の続き。

前回は、”Kerasを使用したMNIST CNNで手書き文字認識1(以前のVivado プロジェクトをVivado 2017.4に変換)”のCNN IP を削除して、Windows版のVivado HLS 2018.2 で mnist_conv_nn3_hlss_ko_dma プロジェクトの all_layers IP を再度作成してAdd IP した。今回は PYNQ_MNIST_CNN3_182 フォルダVivado 2018.2 プロジェクトの論理合成、インプリメンテーション、ビットストリームの生成を行い、SDK でアプリケーションソフトの mnist_conv_soft_test.c を今回のプロジェクトに合うように変更した。

まずは、PYNQ_MNIST_CNN3_182 フォルダVivado 2018.2 プロジェクトの論理合成、インプリメンテーション、ビットストリームの生成を行った。エラーは無かった。
keras_minst_cnn_9_180627.png

Project Summary を示す。
keras_minst_cnn_10_180627.png

ビットストリームの生成が成功したので、ハードウェアをエクスポートし、SDK を起動した。
mnist_conv_soft_test.c を今回のプロジェクトに合うように変更した。mnist_conv_soft_test.c は、”手書き数字認識用畳み込みニューラルネットワーク回路の製作7(ハードとソフトの比較)”に書いてあるハードウェアのMNISTの手書き数字を認識する時間とソフトウェアでMNISTの手書き数字を認識する時間を比較できるアプリケーションソフトだ。うまく変更できて、実行形式ファイルの .elf ファイルが生成できた。なお、時間の計測には、XTime_GetTime()を使用している。
keras_minst_cnn_11_180628.png

下に、mnist_conv_soft_test.c を示す。

/* * mnist_conv_soft_test.c * *  Created on: 2017/07/06 *      Author: ono */
// 2018/06/27 : HLSストリームのテンプレートを使用した all_layers IP 対応

#include <stdio.h>
#include <stdlib.h>
#include "xaxivdma.h"
#include "xil_io.h"
#include "xparameters.h"
#include "sleep.h"
#include "xgpio.h"
#include "xtime_l.h"

#include "xall_layers.h"
#include "xsquare_frame_gen.h"
#include "af1_bias_float.h"
#include "af1_weight_float.h"
#include "af2_bias_float.h"
#include "af2_weight_float.h"
#include "conv1_bias_float.h"
#include "conv1_weight_float.h"

#define FRAME_BUFFER_ADDRESS 0x10000000
#define NUMBER_OF_WRITE_FRAMES    3 // Note: If not at least 3 or more, the image is not displayed in succession.

#define HORIZONTAL_PIXELS    800
#define VERTICAL_LINES        600
#define PIXEL_NUM_OF_BYTES    4

int max_int(int out[10]);
int max_float(float out[10]);
int mnist_conv_nn_float(int in[22400], int addr_offset, float out[10]);
float conv_rgb2y_soft(int rgb);

static XAxiVdma_DmaSetup Vdma0_WriteCfg;
float buf[28][28];
float conv_out[10][24][24];
float pool_out[10][12][12];
float dot1[100];
float dot2[10];

void cam_i2c_init(volatile unsigned *mt9d111_i2c_axi_lites) {
    mt9d111_i2c_axi_lites[64] = 0x2// reset tx fifo ,address is 0x100, i2c_control_reg
    mt9d111_i2c_axi_lites[64] = 0x1// enable i2c
}

void cam_i2x_write_sync(void) {
    // unsigned c;

    // c = *cam_i2c_rx_fifo;
    // while ((c & 0x84) != 0x80)
        // c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
    usleep(1000);
}

void cam_i2c_write(volatile unsigned *mt9d111_i2c_axi_lites, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
    mt9d111_i2c_axi_lites[66] = 0x100 | (device_addr & 0xfe);   // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    mt9d111_i2c_axi_lites[66] = write_addr;
    mt9d111_i2c_axi_lites[66] = (write_data >> 8)|0xff;         // first data
    mt9d111_i2c_axi_lites[66] = 0x200 | (write_data & 0xff);        // second data
    cam_i2x_write_sync();
}

int main(){
    XAll_layers mcnn;
    XSquare_frame_gen sf_gen;
    int inbyte_in;
    int xval, yval;
    int i, res;
    int result[10];
    float result_float[10];
    static XGpio GPIOInstance_Ptr;
    int XGpio_Status;
    int max_id;
    XAxiVdma_Config *XAxiVdma0_Config;
    XAxiVdma XAxiVdma0;
    int XAxiVdma0_Status;
    int result_disp = 0;
    int conv_addr;
    int max_id_float;
    XTime start_time, end_time;

    // AXI VDMA Initialization sequence
    XAxiVdma0_Config = XAxiVdma_LookupConfig(XPAR_CAMERA_INTERFACE_AXI_VDMA_0_DEVICE_ID); // Look up the hardware configuration for a device instance
    if (XAxiVdma0_Config == NULL){
        fprintf(stderr, "No AXI VDMA found\n");
        return(-1);
    }

    XAxiVdma0_Status = XAxiVdma_CfgInitialize(&XAxiVdma0, XAxiVdma0_Config, XAxiVdma0_Config->BaseAddress); // Initialize the driver with hardware configuration
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_CfgInitialize() failed\n");
        return(-1);
    }

    XAxiVdma_Reset(&XAxiVdma0, XAXIVDMA_WRITE);
    while(XAxiVdma_ResetNotDone(&XAxiVdma0, XAXIVDMA_WRITE)) ;

    XAxiVdma0_Status = XAxiVdma_SetFrmStore(&XAxiVdma0, NUMBER_OF_WRITE_FRAMES, XAXIVDMA_WRITE); // Set the number of frame store buffers to use.

    Vdma0_WriteCfg.VertSizeInput = VERTICAL_LINES;
    Vdma0_WriteCfg.HoriSizeInput = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES;
    Vdma0_WriteCfg.Stride = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES; // Indicates the number of address bytes between the first pixels of each video line.
    Vdma0_WriteCfg.FrameDelay = 0// Indicates the minimum number of frame buffers the Genlock slave is to be behind the locked master. This field is only used if the channel is enabled for Genlock Slave operations. This field has no meaning in other Genlock modes.
    Vdma0_WriteCfg.EnableCircularBuf = 1// Indicates frame buffer Circular mode or frame buffer Park mode.  1 = Circular Mode Engine continuously circles through frame buffers.
    Vdma0_WriteCfg.EnableSync = 0// Enables Genlock or Dynamic Genlock Synchronization. 0 = Genlock or Dynamic Genlock Synchronization disabled.
    Vdma0_WriteCfg.PointNum = 0// No Gen-Lock
    Vdma0_WriteCfg.EnableFrameCounter = 0// Endless transfers
    Vdma0_WriteCfg.FixedFrameStoreAddr = 0// We are not doing parking

    XAxiVdma0_Status = XAxiVdma_DmaConfig(&XAxiVdma0, XAXIVDMA_WRITE, &Vdma0_WriteCfg);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaConfig() failed\n");
        return(-1);
    }

    // Frame buffer address set
    unsigned int frame_addr = (unsigned int)FRAME_BUFFER_ADDRESS;
    for (i=0; i<NUMBER_OF_WRITE_FRAMES; i++){
        Vdma0_WriteCfg.FrameStoreStartAddr[i] = frame_addr;
        //frame_addr += HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES * VERTICAL_LINES;
    }

    XAxiVdma0_Status = XAxiVdma_DmaSetBufferAddr(&XAxiVdma0, XAXIVDMA_WRITE, Vdma0_WriteCfg.FrameStoreStartAddr);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaSetBufferAddr() failed\n");
        return(-1);
    }

    // Mnist_conv_nn, Square_frame_gen Initialize
    XAll_layers_Initialize(&mcnn, 0);
    XSquare_frame_gen_Initialize(&sf_gen, 0);

    // square_frame_gen initialize
    XSquare_frame_gen_Set_x_pos(&sf_gen, HORIZONTAL_PIXELS/2);
    xval = HORIZONTAL_PIXELS/2;
    XSquare_frame_gen_Set_y_pos(&sf_gen, VERTICAL_LINES/2);
    yval = VERTICAL_LINES/2;
    XSquare_frame_gen_Set_width(&sf_gen, 28);
    XSquare_frame_gen_Set_height(&sf_gen, 28);
    XSquare_frame_gen_Set_off_on(&sf_gen, 1); // on

    // XSquare_frame_gen start
    XSquare_frame_gen_DisableAutoRestart(&sf_gen);
    while(!XSquare_frame_gen_IsIdle(&sf_gen)) ;
    XSquare_frame_gen_Start(&sf_gen);
    XSquare_frame_gen_EnableAutoRestart(&sf_gen);

    // mnist_conv_nn initialize
    XAll_layers_Set_addr_offset(&mcnn, HORIZONTAL_PIXELS/2);
    XAll_layers_Set_in_r(&mcnn, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*(VERTICAL_LINES/2)*sizeof(int));

    // axis_switch_1, 1to2 ,Select M00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x40), 0x80000000); // disable
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x44), 0x0); // square_frame_gen enable
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR), 0x2); // Commit registers

    // axis_switch_0, 2to1, Select S00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR+0x40), 0x1);
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR), 0x2); // Commit registers

    // VDMA start
    XAxiVdma0_Status = XAxiVdma_DmaStart(&XAxiVdma0, XAXIVDMA_WRITE);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaStart() failed\n");
        return(-1);
    }

    // mt9d111_inf_axis_0, axi_iic_0, bitmap_disp_cntrler_axi_master_0
    volatile unsigned int *bmdc_axi_lites;
    volatile unsigned int *mt9d111_axi_lites;
    volatile unsigned int *mt9d111_i2c_axi_lites;

    bmdc_axi_lites = (volatile unsigned *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_0_BASEADDR;
    mt9d111_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_MT9D111_INF_AXIS_0_BASEADDR;
    mt9d111_i2c_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_AXI_IIC_0_BASEADDR;

    bmdc_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Bitmap Display Controller start
    mt9d111_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Camera Interface start (Address is dummy)

    // CMOS Camera initialize, MT9D111
    cam_i2c_init(mt9d111_i2c_axi_lites);

    cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0xf00x1);      // Changed regster map to IFP page 1
    cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0x970x20);        // RGB Mode, RGB565

    mt9d111_axi_lites[1] = 0// One_shot_mode is disabled

    // AXI GPIO Initialization
    XGpio_Status = XGpio_Initialize(&GPIOInstance_Ptr,XPAR_AXI_GPIO_0_DEVICE_ID);
    if(XST_SUCCESS != XGpio_Status)
        print("GPIO INIT FAILED\n\r");
    // AXI GPIO Set the Direction(output setting)
    XGpio_SetDataDirection(&GPIOInstance_Ptr, 10);

    while(1){
        printf("mnist_conv_nn_test, <h> : left, <k> : up, <j> : down, <l> : right, <q> : exit\n");
        inbyte_in = inbyte();
        switch(inbyte_in) {
            case 'h' : // left
            case 'H' : // left -5
                if(inbyte_in == 'h' && xval > 0)
                    --xval;
                else if(inbyte_in == 'H' && xval >= 5)
                    xval -= 5;
                XSquare_frame_gen_Set_x_pos(&sf_gen, xval);
                XAll_layers_Set_addr_offset(&mcnn, xval);
                printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                break;
            case 'l' : // right
            case 'L' : // right +5
                if(inbyte_in == 'l' && xval < HORIZONTAL_PIXELS-28)
                    xval++;
                else if(inbyte_in == 'L' && xval <= HORIZONTAL_PIXELS-28-5)
                    xval += 5;
                XSquare_frame_gen_Set_x_pos(&sf_gen, xval);
                XAll_layers_Set_addr_offset(&mcnn, xval);
                printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                break;
            case 'k' : // up
            case 'K' : // up -5
                if(inbyte_in == 'k' && yval > 0)
                    --yval;
                else if(inbyte_in == 'K' && yval >= 5)
                    yval -= 5;
                XSquare_frame_gen_Set_y_pos(&sf_gen, yval);
                XAll_layers_Set_in_r(&mcnn, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*yval*sizeof(int));
                printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                break;
            case 'j' : // down
            case 'J' : // down +5
                if(inbyte_in == 'j' && xval < VERTICAL_LINES-28)
                    yval++;
                else if(inbyte_in == 'J' && xval <= VERTICAL_LINES-28-5)
                    yval += 5;
                XSquare_frame_gen_Set_y_pos(&sf_gen, yval);
                XAll_layers_Set_in_r(&mcnn, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*yval*sizeof(int));
                printf("X_POS = %d, Y_POS = %d\n", xval, yval);
                break;
            case 'r' : // result check
                result_disp = 1;
                break;
            case 'q' : // exit
                return(0);
        }

        if(result_disp){
            printf("\nHardware\n");
            // XMnist_conv_nn start
            XAll_layers_DisableAutoRestart(&mcnn);
            while(!XAll_layers_IsIdle(&mcnn));
            XTime_GetTime(&start_time);
            XAll_layers_Start(&mcnn);
            while(!XAll_layers_IsIdle(&mcnn));
            XTime_GetTime(&end_time);
            printf("conv_time = %f ms\n", (float)((long)end_time-(long)start_time)/325000.0);

            // mnist cnn result check
            res = XAll_layers_Get_dot2_0_V(&mcnn);
            result[0] = res & 0x0fff;
            if(result[0] & 0x800// minus
                result[0] = 0xfffff000 | result[0]; // Sign extension

            res = XAll_layers_Get_dot2_1_V(&mcnn);
            result[1] = res & 0x0fff;
            if(result[1] & 0x800// minus
                result[1] = 0xfffff000 | result[1]; // Sign extension

            res = XAll_layers_Get_dot2_2_V(&mcnn);
            result[2] = res & 0x0fff;
            if(result[2] & 0x800// minus
                result[2] = 0xfffff000 | result[2]; // Sign extension

            res = XAll_layers_Get_dot2_3_V(&mcnn);
            result[3] = res & 0x0fff;
            if(result[3] & 0x800// minus
                result[3] = 0xfffff000 | result[3]; // Sign extension

            res = XAll_layers_Get_dot2_4_V(&mcnn);
            result[4] = res & 0x0fff;
            if(result[4] & 0x800// minus
                result[4] = 0xfffff000 | result[4]; // Sign extension

            res = XAll_layers_Get_dot2_5_V(&mcnn);
            result[5] = res & 0x0fff;
            if(result[5] & 0x800// minus
                result[5] = 0xfffff000 | result[5]; // Sign extension

            res = XAll_layers_Get_dot2_6_V(&mcnn);
            result[6] = res & 0x0fff;
            if(result[6] & 0x800// minus
                result[6] = 0xfffff000 | result[6]; // Sign extension

            res = XAll_layers_Get_dot2_7_V(&mcnn);
            result[7] = res & 0x0fff;
            if(result[7] & 0x800// minus
                result[7] = 0xfffff000 | result[7]; // Sign extension

            res = XAll_layers_Get_dot2_8_V(&mcnn);
            result[8] = res & 0x0fff;
            if(result[8] & 0x800// minus
                result[8] = 0xfffff000 | result[8]; // Sign extension

            res = XAll_layers_Get_dot2_9_V(&mcnn);
            result[9] = res & 0x0fff;
            if(result[9] & 0x800// minus
                result[9] = 0xfffff000 | result[9]; // Sign extension

            max_id = XAll_layers_Get_output_V(&mcnn) & 0xf;
            XGpio_DiscreteWrite(&GPIOInstance_Ptr, 1, max_id);

            for(i=0; i<10; i++){
                printf("result[%d] = %x\n", i, result[i]);
            }
            printf("max_id = %d\n", max_id);

            printf("\nSoftware\n");
            conv_addr = FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*yval*sizeof(int);
            XTime_GetTime(&start_time);
            mnist_conv_nn_float((int *)conv_addr, xval, result_float);
            XTime_GetTime(&end_time);
            max_id_float = max_float(result_float);
            printf("conv_time = %f ms\n", (float)((long)end_time-(long)start_time)/325000.0);
            for(i=0; i<10; i++){
                printf("result_float[%d] = %f\n", i, result_float[i]);
            }
            printf("max_id_float = %d\n", max_id_float);

            result_disp = 0;
        }
    }
}

int max_int(int out[10]){
    int max_id;
    int max, i;

    for(i=0; i<10; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    return(max_id);
}

int mnist_conv_nn_float(int in[22400], int addr_offset, float out[10]){

    // 手書き数字の値を表示
    /*for (int i=0; i<28; i++){        for (int j=0; j<800; j++){            if (j>=addr_offset && j<addr_offset+28)                printf("%2x, ", (int)(conv_rgb2y_soft(in[i*800+j])*256.0));        }        printf("\n");    } */

    buf_copy1: for(int i=0; i<28; i++){
        buf_copy2: for(int j=0; j<800; j++){
            if (j>=addr_offset && j<addr_offset+28)
                buf[i][j-addr_offset] = (float)0.99609375 - (float)conv_rgb2y_soft(in[i*800+j]);
        }
    }

    // Convolutional Neural Network 5x5 kernel, Stride = 1, Padding = 0
    // + ReLU
    CONV1: for(int i=0; i<10; i++){    // カーネルの個数
        CONV2: for(int j=0; j<24; j++){
            CONV3: for(int k=0; k<24; k++){
                conv_out[i][j][k] = 0;
                CONV4: for(int m=0; m<5; m++){
                    CONV5: for(int n=0; n<5; n++){
                        conv_out[i][j][k] += buf[j+m][k+n] * conv1_fweight[i][0][m][n];
                    }
                }
                conv_out[i][j][k] += conv1_fbias[i];

                if(conv_out[i][j][k]<0)    // ReLU
                    conv_out[i][j][k] = 0;
            }
        }
    }

    // Pooling Kernel = 2 x 2, Stride = 2
    POOL1: for(int i=0; i<10; i++){
        POOL2: for(int j=0; j<24; j += 2){
            POOL3: for(int k=0; k<24; k += 2){
                POOL4: for(int m=0; m<2; m++){
                    POOL5: for(int n=0; n<2; n++){
                        if(m==0 && n==0){
                            pool_out[i][j/2][k/2] = conv_out[i][j][k];
                        } else if(pool_out[i][j/2][k/2] < conv_out[i][j+m][k+n]){
                            pool_out[i][j/2][k/2] = conv_out[i][j+m][k+n];
                        }
                    }
                }
            }
        }
    }

    af1_dot1: for(int col=0; col<100; col++){
        dot1[col] = 0;
        af1_dot2: for(int i=0; i<10; i++){
            af1_dot3: for(int j=0; j<12; j++){
                af1_dot4: for(int k=0; k<12; k++){
                    dot1[col] += pool_out[i][j][k]*af1_fweight[i*12*12+j*12+k][col];
                }
            }
        }
        dot1[col] += af1_fbias[col];

        if(dot1[col] < 0)    // ReLU
            dot1[col] = 0;
    }

    af2_dot1: for(int col=0; col<10; col++){
        dot2[col] = 0;
        af2_dot2: for(int row=0; row<100; row++){
            dot2[col] += dot1[row]*af2_fweight[row][col];
        }
        dot2[col] += af2_fbias[col];

        out[col] = dot2[col];
    }

    return(0);
}

int max_float(float out[10]){
    int max_id;
    float max;

    for(int i=0; i<10; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    return(max_id);
}


// 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 にした
// 2017/06/30 : retval を float にした
float conv_rgb2y_soft(int rgb){
    int r, g, b, y_f;
    int y;
    float y_float;

    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;

    y_float = (float)y/256.0;

    return(y_float);
}


今日、PYNQボードを出して、ソフトウェア実行してみたいとは思ったのだが、昨日が蒸し暑くて、ばて気味だったので、明日に回すことにした。
  1. 2018年06月28日 05:24 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

Kerasを使用したMNIST CNNで手書き文字認識2(all_layers IP の挿入)

Kerasを使用したMNIST CNNで手書き文字認識1(以前のVivado プロジェクトをVivado 2017.4に変換)”の続き。

Kerasを使用したMNIST CNNで手書き文字認識1(以前のVivado プロジェクトをVivado 2017.4に変換)”のCNN IP を削除して、”DMA付きテンプレートを使用したMNISTのCNN4(Cコードの合成、Export RTL)”で作成したIP をAdd IP したのだが、Add IPのリストに出てこなかった。そこで、Windows版のVivado HLS 2018.2 で再度IP化して、Vivado 2018.2 のVivado プロジェクトにAdd IP した。

Windows版のPYNQ_MNIST_CNN3_182 フォルダのPYNQ_FASTX_164 プロジェクトの CNN IP を削除して、Linux 版Vivado HLS 2018.2 で作成した mnist_conv_nn3_hlss_ko_dma プロジェクトの all_layers IP をAdd IP しようと思ったのだが、IP Catalog には登録できてもAdd IPのリストに出てこなかった。そこで、Windows版のVivado HLS 2018.2 で mnist_conv_nn3_hlss_ko_dma プロジェクトの all_layers IP を再度作成した。
Windows版のVivado HLS 2018.2 で mnist_conv_nn3_hlss_ko_dma プロジェクトを作成した。
keras_minst_cnn_6_180627.png

C コードの合成を行った。結果を示す。
keras_minst_cnn_7_180627.png

結果はLinux 版と同一だった。

Export RTLを行った。結果を示す。
keras_minst_cnn_8_180627.png

こちらもLinux 版と同じだ。

Vivado プロジェクトのある PYNQ_MNIST_CNN3_182 フォルダに hls _all_layers フォルダを作って、Windows版のVivado HLS 2018.2 の mnist_conv_nn3_hlss_ko_dma プロジェクトの all_layers IP をコピーして、IP Catalog に登録した。
今度は、Add IPのリストに出てきたので、Add IPできた。
Vivado 2018.2 のプロジェクトを示す。
keras_minst_cnn_3_180627.png

ブロックデザインを示す。all_layers IP が Add IP されている。
keras_minst_cnn_4_180627.png

Address Editor を示す。
keras_minst_cnn_5_180627.png
  1. 2018年06月27日 05:41 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

DMA付きテンプレートを使用したMNISTのCNN4(Cコードの合成、Export RTL)

DMA付きテンプレートを使用したMNISTのCNN3(C シミュレーション2)”の続き。

前回は、28 x 28 ピクセルの手書き数字の真ん中のエリアの0x80 より大きいピクセル数の数で手書き数字の位置を検出するというテストベンチを土日で書いていたが、失敗した。今回は、位置を検出するのは諦めて、C コードの合成とExport RTL を行った。

C コードの合成を行った。結果を示す。
mnist_conv_nn3_ko_dma_5_180625.png
mnist_conv_nn3_ko_dma_6_180625.png

Estimated は 9.400 ns だった。
Latency は min が 102506 クロックで、max が 102938 クロックだった。max で 100 MHz クロック動作の場合に、約 1.03 ms で実行できる。
リソース使用量は、BRAM_18K で 36 個、DSP48E で 66 個、FF が 6615 個、LUT が 10096 個だった。
DMA を付ける前は、BRAM_18K が 34 個、DSP48E が 62 個、FF が 5284 個、LUT が 9137 個だったので、当たり前だが少しリソース使用量が増えた。

次に、Exprot RTL を行った。なお、Vivado synthesis, place and route にチェックを入れてある。結果を示す。
mnist_conv_nn3_ko_dma_7_180625.png

LUT は 3536 個、FF は 3757 個、DSP は 67 個、BRAM 35 個、SRL 116 個使用している。
DMA を付ける前は、LUT は 2794 個、FF は 3195 個、DSP は 62 個、BRAM 34 個、SRL 73 個使用していたので、結構増えている。

CP achieved post-implementation は 9.757 ns で 10 ns に収まるかどうか不安なところだ。
  1. 2018年06月26日 04:48 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

DMA付きテンプレートを使用したMNISTのCNN3(C シミュレーション2)

DMA付きテンプレートを使用したMNISTのCNN2(C シミュレーション1)”の続き。

DMA 付きテンプレートを使用したMNIST のCNN のC シミュレーションを行った。今回は、28 x 28 ピクセルの手書き数字の真ん中のエリアの0x80 より大きいピクセル数の数で手書き数字の位置を検出するというテストベンチを土日で書いていたが、失敗した。

テストベンチの mnist_conv_nn_hlss_dma_tb.cpp を示す。

// mnist_conv_nn_hlss_dma_tb.cpp
// 2017/06/14 by marsee
// 畳み込み層のカーネル数 10
// 2017/06/29 : ストライドDMAのためのテストベンチ
// 2018/06/25 : mnist_conv_nn_hlss_dma_tb.cppに変更
//

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

#include "conv1_weight.h"
#include "conv1_bias.h"
#include "af1_weight.h"
#include "af1_bias.h"
#include "af2_weight.h"
#include "af2_bias.h"

#include "bmp_header.h"
#include "mnist_conv_nn3_hlss.h"

int all_layers(int in[22400], int addr_offset, output_type& output, out_affine_type dot2[NUMBER_OF_OUTPUT_LAYER]);
int mnist_conv_nn_float(int in[22400], int addr_offset, float out[10]);
int max_ap_fixed(ap_fixed<12, 7, AP_TRN, AP_WRAP> out[10]);
int max_float(float out[10]);
float conv_rgb2y_soft(int rgb);
int conv_rgb2y_tb(int rgb);
int image_center_count(int *y_addr, int x_pos, int x_size, int& around_count, int& center_count);
int max_arg(int arg0, int arg1, int arg2, int arg3);
int same_num(int a, int b, int c, int d, int e);

#define READ_BMP_FILE_NAME    "bmp_file0.bmp"

#define PIXEL_INCREMENT_STEP    14
#define IMAGE_SERCH_INC_STEP    2
#define IMAGE_SERCH_LIMIT       7
#define IMAGE_THRESHOLD         20
#define IMAGE_SERCH_COUNT       20

// 8
//#define X_POS    560 // 8 の位置
//#define Y_POS    183 // 8 の位置
//#define X_POS    502 // 7, 8, 9サーチ
//#define Y_POS    185 // 7, 8, 9サーチ
// 7
//#define X_POS    504
//#define Y_POS    184
// 5
//#define X_POS    390 // org
//#define Y_POS    138 // org
//#define X_POS    390
//#define Y_POS    136
// 0
#define X_POS    390
#define Y_POS    72
#define WIDTH    28
#define HEIGHT    28

int main(){
    ap_fixed<12, 7, AP_TRN, AP_WRAP> result_ap_fixed[10];
    float result_float[10];
    int max_id_hw, max_id_sw, max_id_ref;
    int *in;
    int *inf;
    output_type result_out;

    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr;
    int *rd_bmp;
    int blue, green, red;

    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);
    }

    if ((inf =(int *)malloc(sizeof(int) * (800 * 28))) == NULL){
        fprintf(stderr, "Can't allocate (float)inf 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);

    int x_pos_p = X_POS;
    int cur_x_pos = X_POS;
    int cur_y_pos = Y_POS;
    int cur_center_count;
    int next_center_count_x, next_center_count_y;
    int pre_center_count_x, pre_center_count_y;
    int cur_around_count;
    int pre_around_count_x, pre_around_count_y;
    int next_around_count_x, next_around_count_y;
    int sucess;

    for(int i=0; i<IMAGE_SERCH_COUNT; i++){

        int *cur_y_addr = &rd_bmp[cur_y_pos*bmpihr.biWidth];
        image_center_count(cur_y_addr, cur_x_pos, bmpihr.biWidth, cur_around_count, cur_center_count);
        if(cur_center_count >= IMAGE_THRESHOLD){
            sucess = 0;
            for(int j=0; j<=IMAGE_SERCH_LIMIT; j++){
                cur_y_addr = &rd_bmp[cur_y_pos*bmpihr.biWidth];
                int *next_y_addr = &rd_bmp[(cur_y_pos+IMAGE_SERCH_INC_STEP)*bmpihr.biWidth];
                int *pre_y_addr = &rd_bmp[(cur_y_pos-IMAGE_SERCH_INC_STEP)*bmpihr.biWidth];
                image_center_count(cur_y_addr, cur_x_pos, bmpihr.biWidth, cur_around_count, cur_center_count);
                image_center_count(cur_y_addr, cur_x_pos+IMAGE_SERCH_INC_STEP, bmpihr.biWidth, next_around_count_x, next_center_count_x);
                image_center_count(next_y_addr, cur_x_pos, bmpihr.biWidth, next_around_count_y, next_center_count_y);
                image_center_count(cur_y_addr, cur_x_pos-IMAGE_SERCH_INC_STEP, bmpihr.biWidth, pre_around_count_x, pre_center_count_x);
                image_center_count(pre_y_addr, cur_x_pos, bmpihr.biWidth, pre_around_count_y, pre_center_count_y);
                if(cur_center_count > next_center_count_x && cur_center_count > next_center_count_y &&
                    cur_center_count > pre_center_count_x && cur_center_count > pre_center_count_y){
                    sucess = 1;
                    break;
                }
                int snum = same_num(cur_center_count,next_center_count_x, pre_center_count_x, next_center_count_y, pre_center_count_y);
                if(snum >= 3){
                    sucess = 1;
                    break;
                }

                int num = max_arg(next_center_count_x, pre_center_count_x, next_center_count_y, pre_center_count_y);
                switch(num){
                case 0:
                    cur_x_pos += IMAGE_SERCH_INC_STEP;
                    break;
                case 1:
                    cur_x_pos -= IMAGE_SERCH_INC_STEP;
                    break;
                case 2:
                    cur_y_pos += IMAGE_SERCH_INC_STEP;
                    break;
                case 3:
                    cur_y_pos -= IMAGE_SERCH_INC_STEP;
                    break;
                default:
                    break;
                }
            }
            if(sucess == 0){
                x_pos_p += PIXEL_INCREMENT_STEP;
                cur_x_pos = x_pos_p;
                cur_y_pos = Y_POS;
                continue;
            }

        } else {
            x_pos_p += PIXEL_INCREMENT_STEP;
            cur_x_pos = x_pos_p;
            cur_y_pos = Y_POS;
            continue;
        }

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

        printf("\ncur_x_pos = %d, cur_y_pos = %d\n", cur_x_pos, cur_y_pos);

        all_layers(in, cur_x_pos, result_out, result_ap_fixed);
        mnist_conv_nn_float(inf, cur_x_pos, result_float);

        printf("result_out = %d\n", (int)result_out);

        max_id_hw = max_ap_fixed(result_ap_fixed);
        max_id_sw = max_float(result_float);

        printf("max_id_hw = %d\n", max_id_hw);
        printf("max_id_sw = %d\n", max_id_sw);

        for(int k=0; k<10; k++){
            printf("result_ap_fixed[%d] = %f", k, (float)result_ap_fixed[k]);
            printf(", result_float[%d] = %f\n", k, result_float[k]);
        }

        x_pos_p += PIXEL_INCREMENT_STEP;
        cur_x_pos = x_pos_p;
        cur_y_pos = Y_POS;
    }

    return(0);
}

int mnist_conv_nn_float(int in[22400], int addr_offset, float out[10]){
    float buf[28][28];
    float conv_out[CONV_CHANNELS][24][24];
    float pool_out[CONV_CHANNELS][12][12];
    float dot1[100];
    float dot2[10];

    // 手書き数字の値を表示
    /*for (int i=0; i<28; i++){
        for (int j=0; j<800; j++){
            if (j>=addr_offset && j<addr_offset+28)
                printf("%2x, ", (int)(conv_rgb2y_soft(in[i*800+j])*256.0));
        }
        printf("\n");
    }*/

    buf_copy1: for(int i=0; i<28; i++){
        buf_copy2: for(int j=0; j<800; j++){
            if (j>=addr_offset && j<addr_offset+28)
                buf[i][j-addr_offset] = (float)0.99609375 - (float)conv_rgb2y_soft(in[i*800+j]);
        }
    }

    // Convolutional Neural Network 5x5 kernel, Stride = 1, Padding = 0
    // + ReLU
    CONV1: for(int i=0; i<CONV_CHANNELS; i++){    // カーネルの個数
        CONV2: for(int j=0; j<24; j++){
            CONV3: for(int k=0; k<24; k++){
                conv_out[i][j][k] = 0;
                CONV4: for(int m=0; m<5; m++){
                    CONV5: for(int n=0; n<5; n++){
                        conv_out[i][j][k] += buf[j+m][k+n] * conv1_fweight[i][0][m][n];
                    }
                }
                conv_out[i][j][k] += conv1_fbias[i];

                if(conv_out[i][j][k]<0)    // ReLU
                    conv_out[i][j][k] = 0;
            }
        }
    }

    // Pooling Kernel = 2 x 2, Stride = 2
    POOL1: for(int i=0; i<CONV_CHANNELS; i++){
        POOL2: for(int j=0; j<24; j += 2){
            POOL3: for(int k=0; k<24; k += 2){
                POOL4: for(int m=0; m<2; m++){
                    POOL5: for(int n=0; n<2; n++){
                        if(m==0 && n==0){
                            pool_out[i][j/2][k/2] = conv_out[i][j][k];
                        } else if(pool_out[i][j/2][k/2] < conv_out[i][j+m][k+n]){
                            pool_out[i][j/2][k/2] = conv_out[i][j+m][k+n];
                        }
                    }
                }
            }
        }
    }

    af1_dot1: for(int col=0; col<100; col++){
        dot1[col] = 0;
        af1_dot2: for(int i=0; i<CONV_CHANNELS; i++){
            af1_dot3: for(int j=0; j<12; j++){
                af1_dot4: for(int k=0; k<12; k++){
                    dot1[col] += pool_out[i][j][k]*af1_fweight[i*12*12+j*12+k][col];
                }
            }
        }
        dot1[col] += af1_fbias[col];

        if(dot1[col] < 0)    // ReLU
            dot1[col] = 0;
    }

    af2_dot1: for(int col=0; col<10; col++){
        dot2[col] = 0;
        af2_dot2: for(int row=0; row<100; row++){
            dot2[col] += dot1[row]*af2_fweight[row][col];
        }
        dot2[col] += af2_fbias[col];

        out[col] = dot2[col];
    }

    return(0);
}

int max_ap_fixed(ap_fixed<12, 7, AP_TRN, AP_WRAP> out[10]){
    int max_id;
    ap_fixed<12, 7, AP_TRN, AP_WRAP> max;

    for(int i=0; i<10; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    return(max_id);
}

int max_float(float out[10]){
    int max_id;
    float max;

    for(int i=0; i<10; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    return(max_id);
}


// 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 にした
// 2017/06/30 : retval を float にした
float conv_rgb2y_soft(int rgb){
    int r, g, b, y_f;
    int y;
    float y_float;

    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;

    y_float = (float)y/256.0;

    return(y_float);
}

// 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_tb(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);
}

// 最初の行と行の先頭からの位置を指定して、真ん中の300ピクセル中で
// THRESHOLDよりも大きな数のピクセルを検索
#define THRESHOLD 0x80

int image_center_count(int *y_addr, int x_pos, int x_size, int& around_count, int& center_count){
    around_count = 0;
    center_count = 0;

    row_count: for(int i=0; i<28; i++){
        column_count: for(int j=0; j<28; j++){
            int pixel = 255 - conv_rgb2y_tb(y_addr[x_pos+i*x_size+j]);

            if(i<3 || i>24 || j<3 || j>24){
                if(pixel >= THRESHOLD)
                    around_count++;
            /*}else if((i>6 && i<22)&&(j>3 && j<24)){
                if(pixel >= THRESHOLD)
                    center_count++; */
            }else if((i>2 && i<25)&&(j>2 && j<25)){
                if(pixel >= THRESHOLD)
                    center_count++;
            }
        }
    }
    return(0);
}

// 4つの引数のうちの最大値の引数の番号を返す
int max_arg(int arg0, int arg1, int arg2, int arg3){
    int num;

    if(arg0 >= arg1 && arg0 >= arg2 && arg0 >= arg3)
        num = 0;
    else if(arg1 >= arg0 && arg1 >= arg2 && arg1 >= arg3)
        num = 1;
    else if(arg2 >= arg0 && arg2 >= arg1 && arg2 >= arg3)
        num = 2;
    else if(arg3 >= arg0 && arg3 >= arg1 && arg3 >= arg2)
        num = 3;
    else
        num = 4;

    return(num);
}

// 引数a に値が同じ引数が何個あるかを返す
int same_num(int a, int b, int c, int d, int e){
    int num = 0;

    if(a == b)
        num++;
    if(a == c)
        num++;
    if(a == d)
        num++;
    if(a == e)
        num++;

    return(num);
}


C シミュレーションを行った。結果を示す。
mnist_conv_nn3_ko_dma_4_180625.png

INFO: [SIM 2] *************** CSIM start ***************
INFO: [SIM 4] CSIM will launch CLANG as the compiler.
   Compiling ../../../mnist_conv_nn_hlss_dma_tb.cpp in debug mode
   Generating csim.exe

cur_x_pos = 390, cur_y_pos = 72
            *********       
         ****     ****      
         ****       ***     
        **           ***    
       ***           ***    
      ****            **    
      ***             **    
      **              **    
      **              **    
     ***              **    
     ***              **    
    ***               **    
    ***              ***    
    ***             ****    
    **              ***     
    **              **      
    **              **      
    ***            ***      
     **           ****      
     ***          **        
      **         ***        
      **        ****        
      ***      ****         
       **********           
        *********           
          ***               
                            
                            
around_count = 27, center_count = 77, center/around = 2.851852
result_out = 0
max_id_hw = 0
max_id_sw = 0
result_ap_fixed[0] = 3.062500, result_float[0] = 3.609492
result_ap_fixed[1] = -5.125000, result_float[1] = -5.091571
result_ap_fixed[2] = -6.593750, result_float[2] = -6.368342
result_ap_fixed[3] = -3.593750, result_float[3] = -3.126124
result_ap_fixed[4] = -1.093750, result_float[4] = -1.202655
result_ap_fixed[5] = -2.593750, result_float[5] = -2.427429
result_ap_fixed[6] = -1.812500, result_float[6] = -1.711420
result_ap_fixed[7] = -6.437500, result_float[7] = -6.372975
result_ap_fixed[8] = -4.906250, result_float[8] = -4.710299
result_ap_fixed[9] = -6.187500, result_float[9] = -6.375507

cur_x_pos = 390, cur_y_pos = 72
            *********       
         ****     ****      
         ****       ***     
        **           ***    
       ***           ***    
      ****            **    
      ***             **    
      **              **    
      **              **    
     ***              **    
     ***              **    
    ***               **    
    ***              ***    
    ***             ****    
    **              ***     
    **              **      
    **              **      
    ***            ***      
     **           ****      
     ***          **        
      **         ***        
      **        ****        
      ***      ****         
       **********           
        *********           
          ***               
                            
                            
around_count = 27, center_count = 77, center/around = 2.851852
result_out = 0
max_id_hw = 0
max_id_sw = 0
result_ap_fixed[0] = 3.062500, result_float[0] = 3.609492
result_ap_fixed[1] = -5.125000, result_float[1] = -5.091571
result_ap_fixed[2] = -6.593750, result_float[2] = -6.368342
result_ap_fixed[3] = -3.593750, result_float[3] = -3.126124
result_ap_fixed[4] = -1.093750, result_float[4] = -1.202655
result_ap_fixed[5] = -2.593750, result_float[5] = -2.427429
result_ap_fixed[6] = -1.812500, result_float[6] = -1.711420
result_ap_fixed[7] = -6.437500, result_float[7] = -6.372975
result_ap_fixed[8] = -4.906250, result_float[8] = -4.710299
result_ap_fixed[9] = -6.187500, result_float[9] = -6.375507

cur_x_pos = 506, cur_y_pos = 74
          ********          
      *************         
      ******     ***        
      **          **        
      **          ***       
                  ***       
                  **        
                  **        
                  **        
                ****        
                ***         
               ***          
              ****          
              **            
             ***            
            ***             
           ***              
          ***               
         ***                
       ****                 
      ****                  
    ******                  
    ******* **********      
  **************************
  *************      *******
                            
                            
                            
around_count = 38, center_count = 49, center/around = 1.289474
result_out = 2
max_id_hw = 2
max_id_sw = 2
result_ap_fixed[0] = -10.781250, result_float[0] = -10.776622
result_ap_fixed[1] = 5.843750, result_float[1] = 6.291816
result_ap_fixed[2] = 9.187500, result_float[2] = 9.915581
result_ap_fixed[3] = 1.000000, result_float[3] = 1.670637
result_ap_fixed[4] = -8.531250, result_float[4] = -8.459249
result_ap_fixed[5] = -12.875000, result_float[5] = -13.018033
result_ap_fixed[6] = -10.656250, result_float[6] = -10.853217
result_ap_fixed[7] = -9.156250, result_float[7] = -9.043528
result_ap_fixed[8] = -0.281250, result_float[8] = 0.021258
result_ap_fixed[9] = -7.093750, result_float[9] = -7.039160

cur_x_pos = 506, cur_y_pos = 74
          ********          
      *************         
      ******     ***        
      **          **        
      **          ***       
                  ***       
                  **        
                  **        
                  **        
                ****        
                ***         
               ***          
              ****          
              **            
             ***            
            ***             
           ***              
          ***               
         ***                
       ****                 
      ****                  
    ******                  
    ******* **********      
  **************************
  *************      *******
                            
                            
                            
around_count = 38, center_count = 49, center/around = 1.289474
result_out = 2
max_id_hw = 2
max_id_sw = 2
result_ap_fixed[0] = -10.781250, result_float[0] = -10.776622
result_ap_fixed[1] = 5.843750, result_float[1] = 6.291816
result_ap_fixed[2] = 9.187500, result_float[2] = 9.915581
result_ap_fixed[3] = 1.000000, result_float[3] = 1.670637
result_ap_fixed[4] = -8.531250, result_float[4] = -8.459249
result_ap_fixed[5] = -12.875000, result_float[5] = -13.018033
result_ap_fixed[6] = -10.656250, result_float[6] = -10.853217
result_ap_fixed[7] = -9.156250, result_float[7] = -9.043528
result_ap_fixed[8] = -0.281250, result_float[8] = 0.021258
result_ap_fixed[9] = -7.093750, result_float[9] = -7.039160
INFO: [SIM 1] CSim done with 0 errors.
INFO: [SIM 3] *************** CSIM finish ***************


0 と 2 が 2 回検出されているが、1, 3, 4 が検出されていない。パラメータを変更してもうまく行かなかった。残念。。。
  1. 2018年06月25日 05:26 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

DMA付きテンプレートを使用したMNISTのCNN2(C シミュレーション1)

DMA付きテンプレートを使用したMNISTのCNN1(C ソースコード)”の続き。

前回は、DMA 付きテンプレートを使用したMNIST のCNN のC ソースコードを貼った。今回は、その C ソースコードを利用してC シミュレーションをしてみよう。

まずは、数に示したように一番下の 7, 8, 9 をCNN に入力してみよう。
mnist_conv_nn3_ko_dma_2_180624.jpg

DMA付きテンプレートを使用したMNISTのCNN1(C ソースコード)”に書いたように、1回毎に 5 ピクセルずつ 28 x 28 ピクセルに切り取る画像の x 軸を右にずらしていく。もう一度書いておくと、around_count と center_count は、28 x 28 ピクセルのMNIST の手書き文字の周り 3 ピクセル分、(3+3)x28 + (3+3) x 26 = 300 ピクセルと真ん中の 300 ピクセルの 0x80 より大きなピクセルを数えて、その比を求めようと思う。これは、手書き文字がどこにあるのか?をサーチするのに使用したい。とりあえず、どのような結果になるかを検証してみよう。

mnist_conv_nn3_ko_dma プロジェクトのC シミュレーションを行った。
mnist_conv_nn3_ko_dma_3_180624.png

結果を示す。

INFO: [SIM 2] *************** CSIM start ***************
INFO: [SIM 4] CSIM will launch CLANG as the compiler.
   Compiling ../../../mnist_square_dma.cpp in debug mode
   Generating csim.exe

X_POS = 502, Y_POS = 185
                            
                            
          ************      
          ************      
          **       ***      
         ***        **      
        ***        ***      
        **         ***      
        **        ***       
         *        ***       
                  **        
                  **        
                  **        
                  **        
                 ***        
                 ***        
                ***         
                **          
                **          
                **          
                **          
               ***          
              ****          
              ***           
              ***           
                            
                            
                            
around_count = 12, center_count = 42, center/around = 3.500000
result_out = 3
max_id_hw = 3
max_id_sw = 3
result_ap_fixed[0] = -6.687500, result_float[0] = -6.598463
result_ap_fixed[1] = -1.187500, result_float[1] = -0.928407
result_ap_fixed[2] = -2.437500, result_float[2] = -1.751157
result_ap_fixed[3] = -0.031250, result_float[3] = 0.870602
result_ap_fixed[4] = -2.406250, result_float[4] = -2.517686
result_ap_fixed[5] = -6.562500, result_float[5] = -6.144890
result_ap_fixed[6] = -9.875000, result_float[6] = -9.862177
result_ap_fixed[7] = -2.781250, result_float[7] = -2.362119
result_ap_fixed[8] = -3.250000, result_float[8] = -3.122242
result_ap_fixed[9] = -2.343750, result_float[9] = -2.650363

X_POS = 507, Y_POS = 185
                            
                            
     ************           
     ************           
     **       ***           
    ***        **           
   ***        ***           
   **         ***           
   **        ***            
    *        ***            
             **             
             **             
             **             
             **             
            ***             
            ***             
           ***              
           **               
           **               
           **               
           **               
          ***               
         ****               
         ***                
         ***                
                            
                            
                            
around_count = 12, center_count = 40, center/around = 3.333333
result_out = 1
max_id_hw = 1
max_id_sw = 1
result_ap_fixed[0] = -4.093750, result_float[0] = -3.944167
result_ap_fixed[1] = 0.843750, result_float[1] = 1.401140
result_ap_fixed[2] = 0.562500, result_float[2] = 1.179666
result_ap_fixed[3] = 0.125000, result_float[3] = 0.740295
result_ap_fixed[4] = -7.281250, result_float[4] = -8.019794
result_ap_fixed[5] = -8.343750, result_float[5] = -8.311672
result_ap_fixed[6] = -4.906250, result_float[6] = -4.912206
result_ap_fixed[7] = -5.781250, result_float[7] = -5.561728
result_ap_fixed[8] = -0.593750, result_float[8] = -0.508428
result_ap_fixed[9] = -10.031250, result_float[9] = -10.652685

X_POS = 512, Y_POS = 185
                            
                            
************                
************                
**       ***                
**        **                
*        ***                
         ***                
        ***                 
        ***                 
        **                  
        **                  
        **                  
        **                  
       ***                  
       ***                  
      ***                   
      **                    
      **                    
      **                    
      **                    
     ***                    
    ****                    
    ***                     
    ***                     
                            
                            
                            
around_count = 20, center_count = 37, center/around = 1.850000
result_out = 6
max_id_hw = 6
max_id_sw = 6
result_ap_fixed[0] = 1.375000, result_float[0] = 1.538496
result_ap_fixed[1] = -3.125000, result_float[1] = -3.003051
result_ap_fixed[2] = -3.593750, result_float[2] = -3.063903
result_ap_fixed[3] = -7.656250, result_float[3] = -7.790153
result_ap_fixed[4] = -3.968750, result_float[4] = -3.929864
result_ap_fixed[5] = -4.937500, result_float[5] = -5.745523
result_ap_fixed[6] = 1.812500, result_float[6] = 2.254609
result_ap_fixed[7] = -3.093750, result_float[7] = -2.851094
result_ap_fixed[8] = -0.343750, result_float[8] = -0.149853
result_ap_fixed[9] = -2.781250, result_float[9] = -3.073567

X_POS = 517, Y_POS = 185
                            
                            
*******                     
*******                     
    ***                     
     **                     
    ***                     
    ***                     
   ***                      
   ***                      
   **                       
   **                       
   **                       
   **                       
  ***                       
  ***                       
 ***                        
 **                         
 **                         
 **                         
 **                         
***                         
***                         
**                          
**                          
                            
                            
                            
around_count = 32, center_count = 13, center/around = 0.406250
result_out = 6
max_id_hw = 6
max_id_sw = 6
result_ap_fixed[0] = -0.593750, result_float[0] = -0.710496
result_ap_fixed[1] = -1.406250, result_float[1] = -1.237631
result_ap_fixed[2] = -2.312500, result_float[2] = -2.128094
result_ap_fixed[3] = -1.312500, result_float[3] = -0.931199
result_ap_fixed[4] = -0.812500, result_float[4] = -0.698710
result_ap_fixed[5] = -1.937500, result_float[5] = -2.167314
result_ap_fixed[6] = 0.062500, result_float[6] = 0.688496
result_ap_fixed[7] = -1.968750, result_float[7] = -1.845435
result_ap_fixed[8] = -0.750000, result_float[8] = -0.674898
result_ap_fixed[9] = -0.843750, result_float[9] = -1.345316

X_POS = 522, Y_POS = 185
                            
                            
**                          
**                          
**                          
**                          
**                          
**                          
*                           
*                           
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
around_count = 14, center_count = 0, center/around = 0.000000
result_out = 3
max_id_hw = 3
max_id_sw = 3
result_ap_fixed[0] = -1.125000, result_float[0] = -1.619331
result_ap_fixed[1] = -1.875000, result_float[1] = -2.359333
result_ap_fixed[2] = -0.406250, result_float[2] = 0.069491
result_ap_fixed[3] = 0.375000, result_float[3] = 1.420542
result_ap_fixed[4] = -1.687500, result_float[4] = -2.624235
result_ap_fixed[5] = -0.718750, result_float[5] = -0.753983
result_ap_fixed[6] = -2.250000, result_float[6] = -3.265238
result_ap_fixed[7] = -1.687500, result_float[7] = -1.984813
result_ap_fixed[8] = 0.343750, result_float[8] = 0.805721
result_ap_fixed[9] = -0.250000, result_float[9] = -0.241826

X_POS = 527, Y_POS = 185
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
around_count = 0, center_count = 0, 
result_out = 8
max_id_hw = 8
max_id_sw = 3
result_ap_fixed[0] = -0.906250, result_float[0] = -1.296470
result_ap_fixed[1] = -1.468750, result_float[1] = -1.965718
result_ap_fixed[2] = -0.156250, result_float[2] = 0.285129
result_ap_fixed[3] = 0.437500, result_float[3] = 1.279455
result_ap_fixed[4] = -1.687500, result_float[4] = -2.641459
result_ap_fixed[5] = -0.281250, result_float[5] = -0.265089
result_ap_fixed[6] = -1.812500, result_float[6] = -2.805036
result_ap_fixed[7] = -1.812500, result_float[7] = -2.567419
result_ap_fixed[8] = 0.593750, result_float[8] = 0.916473
result_ap_fixed[9] = -0.468750, result_float[9] = -0.466774

X_POS = 532, Y_POS = 185
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
around_count = 0, center_count = 0, 
result_out = 8
max_id_hw = 8
max_id_sw = 3
result_ap_fixed[0] = -0.937500, result_float[0] = -1.329478
result_ap_fixed[1] = -1.437500, result_float[1] = -1.938128
result_ap_fixed[2] = -0.156250, result_float[2] = 0.330411
result_ap_fixed[3] = 0.375000, result_float[3] = 1.262094
result_ap_fixed[4] = -1.593750, result_float[4] = -2.625525
result_ap_fixed[5] = -0.218750, result_float[5] = -0.105831
result_ap_fixed[6] = -1.781250, result_float[6] = -2.788874
result_ap_fixed[7] = -1.625000, result_float[7] = -2.566367
result_ap_fixed[8] = 0.531250, result_float[8] = 0.966137
result_ap_fixed[9] = -0.437500, result_float[9] = -0.442092

X_POS = 537, Y_POS = 185
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
around_count = 0, center_count = 0, 
result_out = 8
max_id_hw = 8
max_id_sw = 3
result_ap_fixed[0] = -0.906250, result_float[0] = -1.390456
result_ap_fixed[1] = -1.281250, result_float[1] = -1.837113
result_ap_fixed[2] = -0.218750, result_float[2] = 0.437072
result_ap_fixed[3] = 0.312500, result_float[3] = 1.242732
result_ap_fixed[4] = -1.500000, result_float[4] = -2.527295
result_ap_fixed[5] = -0.312500, result_float[5] = -0.236968
result_ap_fixed[6] = -1.687500, result_float[6] = -2.775196
result_ap_fixed[7] = -1.593750, result_float[7] = -2.510123
result_ap_fixed[8] = 0.500000, result_float[8] = 0.975650
result_ap_fixed[9] = -0.406250, result_float[9] = -0.408239

X_POS = 542, Y_POS = 185
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                          **
                          **
                        ****
                        *** 
                        **  
                        **  
                        **  
                        *** 
                          **
                          **
                           *
                            
                            
                            
                            
                            
around_count = 19, center_count = 0, center/around = 0.000000
result_out = 2
max_id_hw = 2
max_id_sw = 2
result_ap_fixed[0] = -0.531250, result_float[0] = -0.738625
result_ap_fixed[1] = -0.781250, result_float[1] = -0.758915
result_ap_fixed[2] = 0.437500, result_float[2] = 2.021734
result_ap_fixed[3] = -0.312500, result_float[3] = 0.229120
result_ap_fixed[4] = -2.500000, result_float[4] = -3.328397
result_ap_fixed[5] = -0.468750, result_float[5] = -1.405289
result_ap_fixed[6] = -1.062500, result_float[6] = -1.902044
result_ap_fixed[7] = -2.093750, result_float[7] = -2.454546
result_ap_fixed[8] = -0.781250, result_float[8] = -1.369310
result_ap_fixed[9] = -2.125000, result_float[9] = -3.382636

X_POS = 547, Y_POS = 185
                            
                          **
                        ****
                       **** 
                       **   
                       **   
                       **   
                       **   
                        ****
                         ***
                        ****
                       *****
                     ****   
                     ****   
                   ****     
                   ***      
                   **       
                   **       
                   **       
                   ***      
                     **     
                     ***    
                      ******
                       *****
                            
                            
                            
                            
around_count = 26, center_count = 29, center/around = 1.115385
result_out = 4
max_id_hw = 4
max_id_sw = 4
result_ap_fixed[0] = -1.593750, result_float[0] = -2.247005
result_ap_fixed[1] = -3.812500, result_float[1] = -3.951203
result_ap_fixed[2] = -2.000000, result_float[2] = -1.570028
result_ap_fixed[3] = -5.031250, result_float[3] = -4.849737
result_ap_fixed[4] = 3.718750, result_float[4] = 4.487070
result_ap_fixed[5] = -0.406250, result_float[5] = 0.060456
result_ap_fixed[6] = -1.718750, result_float[6] = -1.914177
result_ap_fixed[7] = -3.406250, result_float[7] = -3.879769
result_ap_fixed[8] = -0.750000, result_float[8] = -0.644624
result_ap_fixed[9] = -0.625000, result_float[9] = -0.510215

X_POS = 552, Y_POS = 185
                            
                     ****** 
                   *********
                  ****    **
                  **      **
                  **      **
                  **    ****
                  **   **** 
                   ******   
                    ****    
                   *****    
                  ******    
                ****   ***  
                ****    **  
              ****      *** 
              ***        ***
              **          **
              **          **
              **           *
              ***         **
                **        **
                ***       **
                 ***********
                  ********  
                            
                            
                            
                            
around_count = 48, center_count = 53, center/around = 1.104167
result_out = 2
max_id_hw = 2
max_id_sw = 2
result_ap_fixed[0] = -16.593750, result_float[0] = -17.208761
result_ap_fixed[1] = 1.531250, result_float[1] = 2.165034
result_ap_fixed[2] = 5.437500, result_float[2] = 6.572360
result_ap_fixed[3] = 0.031250, result_float[3] = 0.297143
result_ap_fixed[4] = -1.937500, result_float[4] = -1.676362
result_ap_fixed[5] = -12.156250, result_float[5] = -12.265809
result_ap_fixed[6] = -5.937500, result_float[6] = -5.896308
result_ap_fixed[7] = -10.000000, result_float[7] = -9.892697
result_ap_fixed[8] = 2.125000, result_float[8] = 2.661707
result_ap_fixed[9] = -5.031250, result_float[9] = -5.242616

X_POS = 557, Y_POS = 185
                            
                ******      
              *********     
             ****    ***    
             **      **     
             **      **     
             **    ****     
             **   ****      
              ******        
               ****         
              *****         
             ******         
           ****   ***       
           ****    **       
         ****      ***      
         ***        ***     
         **          **     
         **          **     
         **           **    
         ***         ***    
           **        **     
           ***       **     
            ***********     
             ********       
                            
                            
                            
                            
around_count = 15, center_count = 80, center/around = 5.333333
result_out = 8
max_id_hw = 8
max_id_sw = 8
result_ap_fixed[0] = -1.687500, result_float[0] = -1.081046
result_ap_fixed[1] = -4.875000, result_float[1] = -4.630392
result_ap_fixed[2] = -3.250000, result_float[2] = -2.767578
result_ap_fixed[3] = -4.218750, result_float[3] = -3.703644
result_ap_fixed[4] = -5.031250, result_float[4] = -4.921146
result_ap_fixed[5] = -1.687500, result_float[5] = -1.303151
result_ap_fixed[6] = 0.937500, result_float[6] = 1.242822
result_ap_fixed[7] = -9.625000, result_float[7] = -9.519215
result_ap_fixed[8] = 4.593750, result_float[8] = 5.101025
result_ap_fixed[9] = -10.000000, result_float[9] = -9.979488

X_POS = 562, Y_POS = 185
                            
           ******           
         *********          
        ****    ***         
        **      **          
        **      **          
        **    ****          
        **   ****           
         ******             
          ****              
         *****              
        ******              
      ****   ***            
      ****    **            
    ****      ***           
    ***        ***          
    **          **          
    **          **          
    **           **         
    ***         ***         
      **        **          
      ***       **          
       ***********          
        ********            
                            
                            
                            
                            
around_count = 15, center_count = 80, center/around = 5.333333
result_out = 5
max_id_hw = 5
max_id_sw = 5
result_ap_fixed[0] = -5.781250, result_float[0] = -5.452863
result_ap_fixed[1] = -5.843750, result_float[1] = -5.953544
result_ap_fixed[2] = -8.468750, result_float[2] = -8.320899
result_ap_fixed[3] = 1.250000, result_float[3] = 1.922730
result_ap_fixed[4] = -9.593750, result_float[4] = -9.907320
result_ap_fixed[5] = 2.531250, result_float[5] = 3.078276
result_ap_fixed[6] = -5.437500, result_float[6] = -5.247157
result_ap_fixed[7] = -14.062500, result_float[7] = -14.017766
result_ap_fixed[8] = -0.843750, result_float[8] = -0.499992
result_ap_fixed[9] = -8.000000, result_float[9] = -7.772581

X_POS = 567, Y_POS = 185
                            
      ******                
    *********               
   ****    ***              
   **      **               
   **      **               
   **    ****               
   **   ****                
    ******                  
     ****                   
    *****                   
   ******                   
 ****   ***                 
 ****    **                 
***      ***                
**        ***               
*          **               
*          **               
*           **              
**         ***              
 **        **               
 ***       **               
  ***********               
   ********                 
                            
                            
                            
                            
around_count = 34, center_count = 51, center/around = 1.500000
result_out = 3
max_id_hw = 3
max_id_sw = 3
result_ap_fixed[0] = -5.812500, result_float[0] = -5.792901
result_ap_fixed[1] = -4.656250, result_float[1] = -4.453804
result_ap_fixed[2] = -7.750000, result_float[2] = -7.388370
result_ap_fixed[3] = -0.406250, result_float[3] = 0.467601
result_ap_fixed[4] = -7.093750, result_float[4] = -7.120575
result_ap_fixed[5] = -1.031250, result_float[5] = -0.734315
result_ap_fixed[6] = -5.156250, result_float[6] = -5.283511
result_ap_fixed[7] = -8.562500, result_float[7] = -8.129398
result_ap_fixed[8] = -3.375000, result_float[8] = -2.987090
result_ap_fixed[9] = -1.250000, result_float[9] = -0.776801

X_POS = 572, Y_POS = 185
                            
 ******                     
********                    
**    ***                   
      **                    
      **                    
    ****                    
   ****                     
*****                       
****                        
****                        
****                        
   ***                      
    **                      
    ***                     
     ***                    
      **                    
      **                    
       **                   
      ***                   
      **                    
      **                    
********                    
******                      
                            
                            
                            
                            
around_count = 34, center_count = 27, center/around = 0.794118
result_out = 2
max_id_hw = 2
max_id_sw = 2
result_ap_fixed[0] = -2.468750, result_float[0] = -2.650382
result_ap_fixed[1] = 0.250000, result_float[1] = 0.538665
result_ap_fixed[2] = 0.375000, result_float[2] = 1.258284
result_ap_fixed[3] = -0.375000, result_float[3] = 0.272008
result_ap_fixed[4] = -2.406250, result_float[4] = -2.322924
result_ap_fixed[5] = -5.187500, result_float[5] = -5.700843
result_ap_fixed[6] = -3.531250, result_float[6] = -3.706063
result_ap_fixed[7] = -0.500000, result_float[7] = 0.025969
result_ap_fixed[8] = -2.031250, result_float[8] = -1.912965
result_ap_fixed[9] = -3.031250, result_float[9] = -3.784628

X_POS = 577, Y_POS = 185
                            
**                          
***                         
 ***                        
 **                         
 **                         
***                         
**                          
                            
                            
                            
                            
*                           
*                           
**                          
***                         
 **                         
 **                         
  **                        
 ***                        
 **                         
 **                         
***                         
*                           
                            
                            
                            
                            
around_count = 38, center_count = 0, center/around = 0.000000
result_out = 2
max_id_hw = 2
max_id_sw = 3
result_ap_fixed[0] = -1.718750, result_float[0] = -2.488659
result_ap_fixed[1] = -1.875000, result_float[1] = -2.093781
result_ap_fixed[2] = 0.812500, result_float[2] = 1.519924
result_ap_fixed[3] = 0.562500, result_float[3] = 1.925102
result_ap_fixed[4] = -2.687500, result_float[4] = -3.053965
result_ap_fixed[5] = -1.375000, result_float[5] = -1.572820
result_ap_fixed[6] = -3.250000, result_float[6] = -3.985408
result_ap_fixed[7] = -1.687500, result_float[7] = -1.889108
result_ap_fixed[8] = 0.312500, result_float[8] = 0.334581
result_ap_fixed[9] = -0.875000, result_float[9] = -1.184953

X_POS = 582, Y_POS = 185
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
around_count = 0, center_count = 0, 
result_out = 8
max_id_hw = 8
max_id_sw = 3
result_ap_fixed[0] = -0.781250, result_float[0] = -1.287772
result_ap_fixed[1] = -1.281250, result_float[1] = -1.798043
result_ap_fixed[2] = -0.156250, result_float[2] = 0.356295
result_ap_fixed[3] = 0.312500, result_float[3] = 1.086336
result_ap_fixed[4] = -1.343750, result_float[4] = -2.392095
result_ap_fixed[5] = -0.281250, result_float[5] = -0.224637
result_ap_fixed[6] = -1.500000, result_float[6] = -2.600045
result_ap_fixed[7] = -1.468750, result_float[7] = -2.357529
result_ap_fixed[8] = 0.468750, result_float[8] = 0.972850
result_ap_fixed[9] = -0.468750, result_float[9] = -0.335838

X_POS = 587, Y_POS = 185
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
around_count = 0, center_count = 0, 
result_out = 8
max_id_hw = 8
max_id_sw = 3
result_ap_fixed[0] = -0.781250, result_float[0] = -1.220394
result_ap_fixed[1] = -1.281250, result_float[1] = -1.839818
result_ap_fixed[2] = -0.187500, result_float[2] = 0.401741
result_ap_fixed[3] = 0.250000, result_float[3] = 1.110537
result_ap_fixed[4] = -1.375000, result_float[4] = -2.384243
result_ap_fixed[5] = -0.281250, result_float[5] = -0.168204
result_ap_fixed[6] = -1.531250, result_float[6] = -2.608488
result_ap_fixed[7] = -1.500000, result_float[7] = -2.379575
result_ap_fixed[8] = 0.468750, result_float[8] = 0.984628
result_ap_fixed[9] = -0.375000, result_float[9] = -0.316269

X_POS = 592, Y_POS = 185
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
around_count = 0, center_count = 0, 
result_out = 8
max_id_hw = 8
max_id_sw = 3
result_ap_fixed[0] = -0.812500, result_float[0] = -1.300202
result_ap_fixed[1] = -1.312500, result_float[1] = -1.806584
result_ap_fixed[2] = -0.218750, result_float[2] = 0.371900
result_ap_fixed[3] = 0.312500, result_float[3] = 1.214317
result_ap_fixed[4] = -1.375000, result_float[4] = -2.446056
result_ap_fixed[5] = -0.218750, result_float[5] = -0.112995
result_ap_fixed[6] = -1.625000, result_float[6] = -2.746831
result_ap_fixed[7] = -1.562500, result_float[7] = -2.425787
result_ap_fixed[8] = 0.468750, result_float[8] = 1.018132
result_ap_fixed[9] = -0.437500, result_float[9] = -0.380261

X_POS = 597, Y_POS = 185
                            
                            
                            
                            
                            
                            
                            
                           *
                           *
                           *
                           *
                           *
                           *
                           *
                           *
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
around_count = 8, center_count = 0, center/around = 0.000000
result_out = 8
max_id_hw = 8
max_id_sw = 8
result_ap_fixed[0] = -0.875000, result_float[0] = -1.595969
result_ap_fixed[1] = -1.031250, result_float[1] = -1.375270
result_ap_fixed[2] = 0.031250, result_float[2] = 0.657372
result_ap_fixed[3] = 0.156250, result_float[3] = 0.948161
result_ap_fixed[4] = -1.750000, result_float[4] = -2.468961
result_ap_fixed[5] = -0.031250, result_float[5] = 0.506728
result_ap_fixed[6] = -1.812500, result_float[6] = -3.221714
result_ap_fixed[7] = -1.687500, result_float[7] = -2.368360
result_ap_fixed[8] = 0.437500, result_float[8] = 1.243422
result_ap_fixed[9] = -0.531250, result_float[9] = -0.634587

X_POS = 602, Y_POS = 185
                            
                            
                            
                            
                        ****
                        ****
                       ***  
                      ***   
                      **    
                      **    
                      **    
                      **    
                      **    
                      **    
                      ******
                       *****
                            
                            
                            
                            
                            
                            
                           *
                          **
                          **
                          **
                          **
                          **
around_count = 24, center_count = 17, center/around = 0.708333
result_out = 4
max_id_hw = 4
max_id_sw = 4
result_ap_fixed[0] = -0.937500, result_float[0] = -1.223027
result_ap_fixed[1] = -2.156250, result_float[1] = -2.179262
result_ap_fixed[2] = -2.187500, result_float[2] = -2.192808
result_ap_fixed[3] = -2.125000, result_float[3] = -2.247617
result_ap_fixed[4] = -0.093750, result_float[4] = -0.292071
result_ap_fixed[5] = -2.125000, result_float[5] = -2.427494
result_ap_fixed[6] = -1.375000, result_float[6] = -2.113518
result_ap_fixed[7] = -1.375000, result_float[7] = -1.207759
result_ap_fixed[8] = -1.500000, result_float[8] = -1.335060
result_ap_fixed[9] = -4.406250, result_float[9] = -5.568094

X_POS = 607, Y_POS = 185
                            
                            
                            
                            
                   *******  
                   ******** 
                  ***     **
                 ***      **
                 **       **
                 **      ***
                 **      ** 
                 **      ** 
                 **    **** 
                 **    **** 
                 ********** 
                  ********* 
                        **  
                        *   
                       **   
                       **   
                       **   
                       **   
                      ***   
                     ***    
                     **     
                     **     
                     **     
                     **     
around_count = 31, center_count = 34, center/around = 1.096774
result_out = 4
max_id_hw = 4
max_id_sw = 4
result_ap_fixed[0] = -4.031250, result_float[0] = -4.133974
result_ap_fixed[1] = -2.625000, result_float[1] = -2.239853
result_ap_fixed[2] = -4.968750, result_float[2] = -4.674777
result_ap_fixed[3] = -1.968750, result_float[3] = -1.642591
result_ap_fixed[4] = 4.281250, result_float[4] = 5.110765
result_ap_fixed[5] = -2.531250, result_float[5] = -2.270406
result_ap_fixed[6] = -3.500000, result_float[6] = -3.630763
result_ap_fixed[7] = -3.843750, result_float[7] = -3.728224
result_ap_fixed[8] = -0.656250, result_float[8] = -0.452520
result_ap_fixed[9] = -2.781250, result_float[9] = -2.926447

X_POS = 612, Y_POS = 185
                            
                            
                            
                            
              *******       
              ********      
             ***     **     
            ***      ***    
            **       ***    
            **      ***     
            **      **      
            **      **      
            **    ****      
            **    ****      
            **********      
             *********      
                   **       
                   *        
                  **        
                  **        
                  **        
                  **        
                 ***        
                ***         
                **          
                **          
                **          
                **          
around_count = 6, center_count = 66, center/around = 11.000000
result_out = 8
max_id_hw = 8
max_id_sw = 8
result_ap_fixed[0] = -12.968750, result_float[0] = -13.174346
result_ap_fixed[1] = -6.468750, result_float[1] = -6.281274
result_ap_fixed[2] = -6.843750, result_float[2] = -6.845981
result_ap_fixed[3] = 2.218750, result_float[3] = 2.776402
result_ap_fixed[4] = -2.718750, result_float[4] = -2.315293
result_ap_fixed[5] = -6.250000, result_float[5] = -6.071845
result_ap_fixed[6] = -10.843750, result_float[6] = -11.015667
result_ap_fixed[7] = -7.000000, result_float[7] = -6.841413
result_ap_fixed[8] = 3.750000, result_float[8] = 4.229207
result_ap_fixed[9] = -0.437500, result_float[9] = -0.011891

X_POS = 617, Y_POS = 185
                            
                            
                            
                            
         *******            
         ********           
        ***     **          
       ***      ***         
       **       ***         
       **      ***          
       **      **           
       **      **           
       **    ****           
       **    ****           
       **********           
        *********           
              **            
              *             
             **             
             **             
             **             
             **             
            ***             
           ***              
           **               
           **               
           **               
           **               
around_count = 6, center_count = 66, center/around = 11.000000
result_out = 8
max_id_hw = 8
max_id_sw = 8
result_ap_fixed[0] = -9.687500, result_float[0] = -9.947154
result_ap_fixed[1] = -9.187500, result_float[1] = -9.279012
result_ap_fixed[2] = -7.531250, result_float[2] = -7.597316
result_ap_fixed[3] = 1.875000, result_float[3] = 2.737737
result_ap_fixed[4] = -4.656250, result_float[4] = -4.532206
result_ap_fixed[5] = -3.656250, result_float[5] = -3.266784
result_ap_fixed[6] = -12.343750, result_float[6] = -12.734062
result_ap_fixed[7] = -3.125000, result_float[7] = -2.826399
result_ap_fixed[8] = 4.875000, result_float[8] = 5.315073
result_ap_fixed[9] = 2.281250, result_float[9] = 2.924442

X_POS = 622, Y_POS = 185
                            
                            
                            
                            
    *******                 
    ********                
   ***     **               
  ***      ***              
  **       ***              
  **      ***               
  **      **                
  **      **                
  **    ****                
  **    ****                
  **********                
   *********                
         **                 
         *                  
        **                  
        **                  
        **                  
        **                  
       ***                  
      ***                   
      **                    
      **                    
      **                    
      **                    
around_count = 14, center_count = 49, center/around = 3.500000
result_out = 7
max_id_hw = 7
max_id_sw = 7
result_ap_fixed[0] = -2.625000, result_float[0] = -2.513616
result_ap_fixed[1] = -1.531250, result_float[1] = -1.173316
result_ap_fixed[2] = -0.718750, result_float[2] = 0.351554
result_ap_fixed[3] = -1.343750, result_float[3] = -1.153538
result_ap_fixed[4] = 0.281250, result_float[4] = 0.777785
result_ap_fixed[5] = -10.000000, result_float[5] = -10.576931
result_ap_fixed[6] = -6.250000, result_float[6] = -6.237439
result_ap_fixed[7] = 0.687500, result_float[7] = 1.322895
result_ap_fixed[8] = -5.281250, result_float[8] = -4.995121
result_ap_fixed[9] = -5.562500, result_float[9] = -5.764553

X_POS = 627, Y_POS = 185
                            
                            
                            
                            
******                      
*******                     
*     **                    
      ***                   
      ***                   
     ***                    
     **                     
     **                     
   ****                     
   ****                     
*******                     
*******                     
    **                      
    *                       
   **                       
   **                       
   **                       
   **                       
  ***                       
 ***                        
 **                         
 **                         
 **                         
 **                         
around_count = 24, center_count = 32, center/around = 1.333333
result_out = 0
max_id_hw = 0
max_id_sw = 0
result_ap_fixed[0] = 0.687500, result_float[0] = 0.791694
result_ap_fixed[1] = -2.156250, result_float[1] = -2.344940
result_ap_fixed[2] = -4.187500, result_float[2] = -4.291689
result_ap_fixed[3] = -4.375000, result_float[3] = -4.177928
result_ap_fixed[4] = -0.062500, result_float[4] = -0.151814
result_ap_fixed[5] = -2.593750, result_float[5] = -3.096778
result_ap_fixed[6] = 0.031250, result_float[6] = 0.079751
result_ap_fixed[7] = -2.468750, result_float[7] = -2.334525
result_ap_fixed[8] = -1.500000, result_float[8] = -1.337001
result_ap_fixed[9] = -0.312500, result_float[9] = -0.457717

X_POS = 632, Y_POS = 185
                            
                            
                            
                            
*                           
**                          
 **                         
 ***                        
 ***                        
***                         
**                          
**                          
**                          
**                          
**                          
**                          
*                           
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
around_count = 25, center_count = 0, center/around = 0.000000
result_out = 3
max_id_hw = 3
max_id_sw = 3
result_ap_fixed[0] = -0.562500, result_float[0] = -1.318965
result_ap_fixed[1] = -2.125000, result_float[1] = -2.567228
result_ap_fixed[2] = -0.843750, result_float[2] = -0.476693
result_ap_fixed[3] = 0.156250, result_float[3] = 1.306376
result_ap_fixed[4] = -1.281250, result_float[4] = -1.726599
result_ap_fixed[5] = -0.906250, result_float[5] = -1.148492
result_ap_fixed[6] = -2.125000, result_float[6] = -2.973163
result_ap_fixed[7] = -0.718750, result_float[7] = -0.478881
result_ap_fixed[8] = -0.093750, result_float[8] = 0.278913
result_ap_fixed[9] = -0.187500, result_float[9] = -0.585260

X_POS = 637, Y_POS = 185
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
around_count = 0, center_count = 0, 
result_out = 8
max_id_hw = 8
max_id_sw = 3
result_ap_fixed[0] = -0.750000, result_float[0] = -1.350178
result_ap_fixed[1] = -1.125000, result_float[1] = -1.817338
result_ap_fixed[2] = -0.125000, result_float[2] = 0.408225
result_ap_fixed[3] = 0.312500, result_float[3] = 1.204863
result_ap_fixed[4] = -1.312500, result_float[4] = -2.470115
result_ap_fixed[5] = -0.093750, result_float[5] = -0.141706
result_ap_fixed[6] = -1.343750, result_float[6] = -2.660645
result_ap_fixed[7] = -1.250000, result_float[7] = -2.317636
result_ap_fixed[8] = 0.468750, result_float[8] = 0.968406
result_ap_fixed[9] = -0.437500, result_float[9] = -0.434542

X_POS = 642, Y_POS = 185
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
around_count = 0, center_count = 0, 
result_out = 8
max_id_hw = 8
max_id_sw = 3
result_ap_fixed[0] = -0.687500, result_float[0] = -1.279108
result_ap_fixed[1] = -1.093750, result_float[1] = -1.801685
result_ap_fixed[2] = -0.156250, result_float[2] = 0.382397
result_ap_fixed[3] = 0.312500, result_float[3] = 1.128036
result_ap_fixed[4] = -1.250000, result_float[4] = -2.419693
result_ap_fixed[5] = -0.062500, result_float[5] = -0.134422
result_ap_fixed[6] = -1.312500, result_float[6] = -2.609115
result_ap_fixed[7] = -1.343750, result_float[7] = -2.328017
result_ap_fixed[8] = 0.437500, result_float[8] = 0.966102
result_ap_fixed[9] = -0.406250, result_float[9] = -0.377428

X_POS = 647, Y_POS = 185
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
                            
around_count = 0, center_count = 0, 
result_out = 8
max_id_hw = 8
max_id_sw = 3
result_ap_fixed[0] = -0.718750, result_float[0] = -1.336163
result_ap_fixed[1] = -1.093750, result_float[1] = -1.808135
result_ap_fixed[2] = -0.250000, result_float[2] = 0.418296
result_ap_fixed[3] = 0.343750, result_float[3] = 1.161598
result_ap_fixed[4] = -1.343750, result_float[4] = -2.456500
result_ap_fixed[5] = -0.125000, result_float[5] = -0.176320
result_ap_fixed[6] = -1.312500, result_float[6] = -2.647960
result_ap_fixed[7] = -1.281250, result_float[7] = -2.320159
result_ap_fixed[8] = 0.437500, result_float[8] = 0.986491
result_ap_fixed[9] = -0.437500, result_float[9] = -0.386770
INFO: [SIM 1] CSim done with 0 errors.
INFO: [SIM 3] *************** CSIM finish ***************


center/around の値で手書き数字のセンタリングをしても良いのかな?とおもう。もう少しデータを収集したい。
なお、7 は認識できなかった。8, 9 は認識できた。
  1. 2018年06月24日 07:59 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

DMA付きテンプレートを使用したMNISTのCNN1(C ソースコード)

MNISTのCNN 用のDMA IP を”TensorFlow + Kerasを使ってみた20(特徴マップ3個のMNIST用CNNをVivado HLSで実装)”のテンプレートを使用した特徴マップ3個のMNIST のCNN に付けた。これで、PYNQ に搭載した”手書き数字認識用畳み込みニューラルネットワーク回路の製作3(畳み込みNN)”の入出力フォーマットと同じになったので、”Kerasを使用したMNIST CNNで手書き文字認識1(以前のVivado プロジェクトをVivado 2017.4に変換)”のmnist_conv_nn10_sDMA IP と入れ替えれば、DMA 付きテンプレートを使用したMNIST のCNN を試してみることができる。

DMA 付きテンプレートを使用したMNIST のCNN として作成したmnist_conv_nn3_ko_dma プロジェクトを示す。
mnist_conv_nn3_ko_dma_1_180624.png

ここで、”MNISTのCNN 用DMA IP 1(C シミュレーション)”のmnist_square_dma.cpp を変更したので、貼っておく。

// mnist_square_dma.cpp
// 2018/06/19 by marsee
// 2018/06/23 : 表示を追加
//

#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;

#ifndef __SYNTHESIS__
    int around_count = 0;
    int center_count = 0;
#endif

    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]);
            // 白地に黒数字から黒地に白数字に変換
#ifndef __SYNTHESIS__
            if(i<3 || i>24 || j<3 || j>24){
                if(pixel.data >= 0x80)
                    around_count++;
            }else if((i>6 && i<22)&&(j>3 && j<24)){
                if(pixel.data >= 0x80)
                    center_count++;
            }

            if(pixel.data >= 0x80)
                printf("*");
            else
                printf(" ");
#endif
            if(i==0 && j==0)
                pixel.user = 1;
            else
                pixel.user = 0;
            if(j == 27)
                pixel.last = 1;
            else
                pixel.last = 0;

            outs << pixel;
        }
#ifndef __SYNTHESIS__
        printf("\n");
#endif
    }
#ifndef __SYNTHESIS__
    printf("around_count = %d, center_count = %d, ", around_count, center_count);
    if(around_count != 0)
        printf("center/around = %f\n", (float)center_count/(float)around_count);
    else
        printf("\n");
#endif

    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);
}


なお、around_count と center_count は、28 x 28 ピクセルのMNIST の手書き文字の周り 3 ピクセル分、(3+3)x28 + (3+3) x 26 = 300 ピクセルと真ん中の 300 ピクセルの 0x80 より大きなピクセルを数えて、その比を求めようと思う。これは、手書き文字がどこにあるのか?をサーチするのに使用したい。とりあえず、どのような結果になるかを検証してみよう。

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

// mnist_conv_nn3_hlss_dma.cpp
// 2018/06/23 by marsee
//

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

#include "layer_general.h"
#include "mnist_conv_nn3_hlss.h"

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

int input_layer(hls::stream<ap_axiu<8,1,INPUT_CHANNELS,1> >&ins,
    hls::stream<ap_fixed_axis<INPUT_BIT_LENGTH,INPUT_INTEGER_LEN,INPUT_CHANNELS,1> >&outs);

int conv_layer1(hls::stream<ap_fixed_axis<INPUT_BIT_LENGTH,INPUT_INTEGER_LEN,INPUT_CHANNELS,1> >& ins,
    hls::stream<ap_fixed_axis<CONV_BIT_LENGTH,CONV_INTEGER_LEN,CONV_CHANNELS,1> >& outs);

int relu_conv1(hls::stream<ap_fixed_axis<CONV_BIT_LENGTH,CONV_INTEGER_LEN,CONV_CHANNELS,1> >& ins,
    hls::stream<ap_fixed_axis<CONV_BIT_LENGTH,CONV_INTEGER_LEN,CONV_CHANNELS,1> >& outs);

int max_pooling(hls::stream<ap_fixed_axis<CONV_BIT_LENGTH,CONV_INTEGER_LEN,CONV_CHANNELS,1> >& ins,
    hls::stream<ap_fixed_axis<CONV_BIT_LENGTH,CONV_INTEGER_LEN,CONV_CHANNELS,1> >& outs);

int affine_layer1(hls::stream<ap_fixed_axis<CONV_BIT_LENGTH,CONV_INTEGER_LEN,CONV_CHANNELS,1> >& ins,
    hls::stream<ap_fixed_axis<AFFINE_BIT_LENGTH,AFFINE_INTEGER_LEN,1,1> >& outs);

int relu_affine1(hls::stream<ap_fixed_axis<AFFINE_BIT_LENGTH,AFFINE_INTEGER_LEN,1,1> >& ins,
    hls::stream<ap_fixed_axis<AFFINE_BIT_LENGTH,AFFINE_INTEGER_LEN,1,1> >& outs);

int affine_layer2(hls::stream<ap_fixed_axis<AFFINE_BIT_LENGTH,AFFINE_INTEGER_LEN,1,1> >& ins,
    hls::stream<ap_fixed_axis<OUTPUT_BIT_LENGTH,OUTPUT_INTEGER_LEN,1,1> >& outs);

int output_layer(hls::stream<ap_fixed_axis<OUTPUT_BIT_LENGTH,OUTPUT_INTEGER_LEN,1,1> >& ins, output_type& output,
    out_affine_type dot2[NUMBER_OF_OUTPUT_LAYER]);

int all_layers(int in[22400], int addr_offset, output_type& output, out_affine_type dot2[NUMBER_OF_OUTPUT_LAYER]){
#pragma HLS INTERFACE s_axilite port=addr_offset
#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 m_axi depth=22400 port=in offset=slave

    hls::stream<ap_axiu<8,1,1,1> > dma_outs;
// #pragma HLS STREAM variable=dma_outs depth=784 dim=1
    hls::stream<ap_fixed_axis<INPUT_BIT_LENGTH,INPUT_INTEGER_LEN,INPUT_CHANNELS,1> > outs_input_layer;
// #pragma HLS STREAM variable=outs_input_layer depth=560 dim=1
    hls::stream<ap_fixed_axis<CONV_BIT_LENGTH,CONV_INTEGER_LEN,CONV_CHANNELS,1> > outs_conv_layer;
// #pragma HLS STREAM variable=outs_conv_layer depth=312 dim=1
    hls::stream<ap_fixed_axis<CONV_BIT_LENGTH,CONV_INTEGER_LEN,CONV_CHANNELS,1> > outs_relu_conv1;
// #pragma HLS STREAM variable=outs_relu depth=312 dim=1
    hls::stream<ap_fixed_axis<CONV_BIT_LENGTH,CONV_INTEGER_LEN,CONV_CHANNELS,1> > outs_max_pooling;
// #pragma HLS STREAM variable=outs_max_pooling depth=78 dim=1
    hls::stream<ap_fixed_axis<AFFINE_BIT_LENGTH,AFFINE_INTEGER_LEN,1,1> > outs_affine_layer1;
// #pragma HLS STREAM variable=outs_affine_layer1 depth=100 dim=1
    hls::stream<ap_fixed_axis<AFFINE_BIT_LENGTH,AFFINE_INTEGER_LEN,1,1> > outs_relu_affine1;
// #pragma HLS STREAM variable=outs_relu_affine1 depth=100 dim=1
    hls::stream<ap_fixed_axis<OUTPUT_BIT_LENGTH,OUTPUT_INTEGER_LEN,1,1> > outs_affine_layer2;
// #pragma HLS STREAM variable=outs_affine_layer2 depth=3 dim=1

    mnist_square_dma(in, addr_offset, dma_outs);
    input_layer(dma_outs, outs_input_layer);
    conv_layer1(outs_input_layer, outs_conv_layer);
    relu_conv1(outs_conv_layer, outs_relu_conv1);
    max_pooling(outs_relu_conv1, 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);
}


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

// mnist_conv_nn_hlss_dma_tb.cpp
// 2017/06/14 by marsee
// 畳み込み層のカーネル数 10
// 2017/06/29 : ストライドDMAのためのテストベンチ
// 2018/06/25 : mnist_conv_nn_hlss_dma_tb.cppに変更
//

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

#include "conv1_weight.h"
#include "conv1_bias.h"
#include "af1_weight.h"
#include "af1_bias.h"
#include "af2_weight.h"
#include "af2_bias.h"

#include "bmp_header.h"
#include "mnist_conv_nn3_hlss.h"

int all_layers(int in[22400], int addr_offset, output_type& output, out_affine_type dot2[NUMBER_OF_OUTPUT_LAYER]);
int mnist_conv_nn_float(int in[22400], int addr_offset, float out[10]);
int max_ap_fixed(ap_fixed<12, 7, AP_TRN, AP_WRAP> out[10]);
int max_float(float out[10]);
float conv_rgb2y_soft(int rgb);

#define READ_BMP_FILE_NAME    "bmp_file0.bmp"

// 8
//#define X_POS    560
//#define Y_POS    183
#define X_POS    502
#define Y_POS    185
// 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 main(){
    ap_fixed<12, 7, AP_TRN, AP_WRAP> result_ap_fixed[10];
    float result_float[10];
    int max_id_hw, max_id_sw, max_id_ref;
    int *in;
    int *inf;
    output_type result_out;

    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr;
    int *rd_bmp;
    int blue, green, red;

    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);
    }

    if ((inf =(int *)malloc(sizeof(int) * (800 * 28))) == NULL){
        fprintf(stderr, "Can't allocate (float)inf 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);

    int x_pos_p = X_POS;
    for(int i=0; i<30; i++){
        // rd_bmp を in と inf に入力
        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];
                inf[(y-Y_POS)*bmpihr.biWidth+x] = rd_bmp[y*bmpihr.biWidth+x];
            }
        }

        printf("\nX_POS = %d, Y_POS = %d\n", x_pos_p, Y_POS);

        all_layers(in, x_pos_p, result_out, result_ap_fixed);
        mnist_conv_nn_float(inf, x_pos_p, result_float);

        printf("result_out = %d\n", (int)result_out);

        max_id_hw = max_ap_fixed(result_ap_fixed);
        max_id_sw = max_float(result_float);

        printf("max_id_hw = %d\n", max_id_hw);
        printf("max_id_sw = %d\n", max_id_sw);

        for(int i=0; i<10; i++){
            printf("result_ap_fixed[%d] = %f", i, (float)result_ap_fixed[i]);
            printf(", result_float[%d] = %f\n", i, result_float[i]);
        }

        x_pos_p += 5;
    }

    return(0);
}

int mnist_conv_nn_float(int in[22400], int addr_offset, float out[10]){
    float buf[28][28];
    float conv_out[CONV_CHANNELS][24][24];
    float pool_out[CONV_CHANNELS][12][12];
    float dot1[100];
    float dot2[10];

    // 手書き数字の値を表示
    /*for (int i=0; i<28; i++){
        for (int j=0; j<800; j++){
            if (j>=addr_offset && j<addr_offset+28)
                printf("%2x, ", (int)(conv_rgb2y_soft(in[i*800+j])*256.0));
        }
        printf("\n");
    }*/

    buf_copy1: for(int i=0; i<28; i++){
        buf_copy2: for(int j=0; j<800; j++){
            if (j>=addr_offset && j<addr_offset+28)
                buf[i][j-addr_offset] = (float)0.99609375 - (float)conv_rgb2y_soft(in[i*800+j]);
        }
    }

    // Convolutional Neural Network 5x5 kernel, Stride = 1, Padding = 0
    // + ReLU
    CONV1: for(int i=0; i<CONV_CHANNELS; i++){    // カーネルの個数
        CONV2: for(int j=0; j<24; j++){
            CONV3: for(int k=0; k<24; k++){
                conv_out[i][j][k] = 0;
                CONV4: for(int m=0; m<5; m++){
                    CONV5: for(int n=0; n<5; n++){
                        conv_out[i][j][k] += buf[j+m][k+n] * conv1_fweight[i][0][m][n];
                    }
                }
                conv_out[i][j][k] += conv1_fbias[i];

                if(conv_out[i][j][k]<0)    // ReLU
                    conv_out[i][j][k] = 0;
            }
        }
    }

    // Pooling Kernel = 2 x 2, Stride = 2
    POOL1: for(int i=0; i<CONV_CHANNELS; i++){
        POOL2: for(int j=0; j<24; j += 2){
            POOL3: for(int k=0; k<24; k += 2){
                POOL4: for(int m=0; m<2; m++){
                    POOL5: for(int n=0; n<2; n++){
                        if(m==0 && n==0){
                            pool_out[i][j/2][k/2] = conv_out[i][j][k];
                        } else if(pool_out[i][j/2][k/2] < conv_out[i][j+m][k+n]){
                            pool_out[i][j/2][k/2] = conv_out[i][j+m][k+n];
                        }
                    }
                }
            }
        }
    }

    af1_dot1: for(int col=0; col<100; col++){
        dot1[col] = 0;
        af1_dot2: for(int i=0; i<CONV_CHANNELS; i++){
            af1_dot3: for(int j=0; j<12; j++){
                af1_dot4: for(int k=0; k<12; k++){
                    dot1[col] += pool_out[i][j][k]*af1_fweight[i*12*12+j*12+k][col];
                }
            }
        }
        dot1[col] += af1_fbias[col];

        if(dot1[col] < 0)    // ReLU
            dot1[col] = 0;
    }

    af2_dot1: for(int col=0; col<10; col++){
        dot2[col] = 0;
        af2_dot2: for(int row=0; row<100; row++){
            dot2[col] += dot1[row]*af2_fweight[row][col];
        }
        dot2[col] += af2_fbias[col];

        out[col] = dot2[col];
    }

    return(0);
}

int max_ap_fixed(ap_fixed<12, 7, AP_TRN, AP_WRAP> out[10]){
    int max_id;
    ap_fixed<12, 7, AP_TRN, AP_WRAP> max;

    for(int i=0; i<10; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    return(max_id);
}

int max_float(float out[10]){
    int max_id;
    float max;

    for(int i=0; i<10; i++){
        if(i == 0){
            max = out[0];
            max_id = 0;
        }else if(out[i]>max){
            max = out[i];
            max_id = i;
        }
    }
    return(max_id);
}


// 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 にした
// 2017/06/30 : retval を float にした
float conv_rgb2y_soft(int rgb){
    int r, g, b, y_f;
    int y;
    float y_float;

    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;

    y_float = (float)y/256.0;

    return(y_float);
}


X_POS、Y_POS の値を初期値として、X_POS の値を +5 ピクセルしながら X 軸方向にCNN をかけていく。
  1. 2018年06月24日 05:42 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

MNISTのCNN 用DMA IP 2(C コードの合成、C/RTL 協調シミュレーション、Export RTL)

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

前回は、MNISTのCNN 用のDMA IP を作成し、C シミュレーションを行った。今回は、C コードの合成、C/RTL 協調シミュレーション、Export RTLを行った。

まずは、Vivado HLS 2018.2 の新機能の Schedule Viewer の機能を見るために、PIPELINE指示子をコメントアウトして、C コードの合成を行った。
mnist_square_dma_7_180621.png

C コードの合成結果を示す。
mnist_square_dma_8_180621.png

Latency は 3389 クロックだった。column_count ループの Iteration Latency が 4 クロックだったので、それでクロック数が増えているようだ。
リソース使用量は、BRAM_18K が 2 個、DSP48E が 2 個、FF が 830 個、LUT が 1270 個だった。

Analysis ボタンをクリックして、Schedule Viewer を表示させた。
mnist_square_dma_9_180621.png

row_count と column_count があるのが分かる。
Operation\Control Step の数は 12 だった。

次に、PIPELINE指示子を戻した。
mnist_square_dma_10_180621.png

これで C コードの合成を行った。結果を示す。
mnist_square_dma_11_180621.png

Latency は 3389 クロックから 809 クロックに下がった。
リソース使用量は、BRAM_18K が 2 個、DSP48E が 3 個、FF が 1378 個、LUT が 1583 個だった。PIPELINE指示子が無い時よりも大分増えている。

Analysis ボタンをクリックして、Schedule Viewer を表示させた。
mnist_square_dma_12_180621.png

row_count と column_count が合わさって、row_count_column_count になっていた。
Operation\Control Step の数は 25 だった。

C/RTL 協調シミュレーションを行った。結果を示す。
mnist_square_dma_13_180621.png

Latency は 1014 クロックだった。

C/RTL 協調シミュレーションの波形を示す。
まずは波形全体から。
mnist_square_dma_14_180621.png

AXI4-Stream の TLAST をアサートしている辺りで、TVALID が 0 にディアサートされているのが気になるが、スループットは出ているようだ。

次に最初の部分を拡大してみよう。
mnist_square_dma_15_180621.png

28 個のピクセルの DMA を行う。ARLENを見ると最初は 0x0f なので 16 バーストで、次は 0x0B なので 12 バーストの計 28 個バーストしている。
アドレス転送とデータ転送がもう少しオーバーラップしている方が良いと思う。

Export RTLを行った。
Vivado HLS 2018.2 では、Wave Debug 項目が増えている。これは、Verilog/VHDL Simulator Selection が AUTO だとハイドされている。これが有効になるのは、Vivado Simulator の時だけのようだ。このオプションにチェックすると、C/RTL 協調シミュレーションが終了する前にVivado が起動して、波形を表示する。
mnist_square_dma_16_180621.png

Export RTLを行った。なお、Vivado synthesis, place and route にチェックを入れてある。
mnist_square_dma_17_180622.png

LUT が 575 個、FF が 807 個、DSP が 4 個、BRAM が 1 個、SRLが 39 個使用していた。
  1. 2018年06月22日 04:51 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

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

Vivado 2018.2 が出た

昨日、Vivado 2018.2 が出ていた。

Vivado HLS のAnalysis にSchedule Viewer が追加されたということでやってみることにした。

MNISTのCNNの特徴マップが 3 個の場合で確かめてみた。
Vivado 2018.2 で mnist_conv_nn3_hlss_k_org82 フォルダのVivado HLS プロジェクトをC コードの合成を行った。結果を示す。
下に 2018.1 の結果も示す。
vivado_2018_1_1_180620.pngtensorflow_keras_111_180618.png

同じ結果だった。

Analysis モードにすると、Schedule Viewer が起動した。新しいモードだ。
vivado_2018_1_2_180620.png

conv_layer1 > conv_layer_template を選択した。
赤い部分があるが、これはタイミング違反のブロックということだ。
どこからデータが来て、どこに行くのかが矢印で示されているのだと思う。
vivado_2018_1_3_180620.png

affine_layer1 > affine_layer_templat_1 を示す。
vivado_2018_1_4_180620.png

見やすくなった気がするが、どこの演算をしているのかがいまいち分からない?

Export RTLの結果を示す。2018.1 の結果も示す。
vivado_2018_1_5_180620.pngtensorflow_keras_112_180618.png

特に FF と SLICE の使用量が 2018.2 の方が少なくなっている。
CP achieved post-implementation が 9.525 ns から 8.846 ns に改善されているが、これはVivado の改善のようだ。


次に、Vivado 2018.2 を”Kerasを使用したMNIST CNNで手書き文字認識1(以前のVivado プロジェクトをVivado 2017.4に変換)”のVivado 2017.4 と比較してみよう。

Vivado 2018.2 の PYNQ ボードのMNIST のCNN プロジェクトを示す。
vivado_2018_1_6_180620.png

Vivado 2018.2 の結果を示す。 2017.4 の結果も示す。
vivado_2018_1_7_180620.pngvivado_2018_1_8_180620.png

LUT は少し 2018.2 の方が少なく、LUT RAM と FF がやはり、2018.2 の方が少なくなった。
今度から 2018.2 を使ってみようか?
  1. 2018年06月20日 04:50 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

Kerasを使用したMNIST CNNで手書き文字認識1(以前のVivado プロジェクトをVivado 2017.4に変換)

TensorFlow + Kerasを使ってみた22(Linux版とWindows版のVivado HLSでの違い)”までで作ってきたMNISTのCNNをVivado に組み込んで実機で動作させてみようと思う。とりあえずは、従来のフレームワークに入れて、HLSストリーム版のCNN が実際にうまく行くかを確認したい。

以前の「手書き数字認識用畳み込みニューラルネットワーク回路」のVivado プロジェクトは、”手書き数字認識用畳み込みニューラルネットワーク回路の製作4(Vivadoプロジェクト)”のVivado 2017.2 のプロジェクトだった。
これをVivado 2017.4 に変換した。
keras_minst_cnn_1_180619.png

次に、論理合成、インプリメンテーション、ビットストリームの生成を行った。
結果を示す。
keras_minst_cnn_2_180619.png

タイミングも満たされてうまく行っている。
次は、HLSストリームを使用したMNISTのCNNは、ストリーム入力になっているので、ストリームを作成するDMA をVivado HLS で作っていこう。
  1. 2018年06月19日 05:24 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた22(Linux版とWindows版のVivado HLSでの違い)

TensorFlow + Kerasを使ってみた21(特徴マップ数が3個、5個、10個のMNIST用CNNをC/RTLコシムとIP化)”の続き。

前回は、特徴マップ数が 3 個、 5 個、10 個のMNIST用CNNをC/RTL 強調シミュレーションと、Export RTL を行って、結果を比較した。今回は、前回はLinux 版のVivado HLS 2017.4 の結果だったが、Windows版のVivado HLS 2017.4 の結果も比較した。また、Vivado HLS 2018.1 で特徴マップが 3 個の場合をやってみたので比較した。

Windows版のVivado HLS 2017.4 の特徴マップ 3 個、5 個、10 個のC コードの合成とExport RTLを行った。結果は下表に示す。

特徴マップが 3 個の場合のWindows版Vivado HLS 2018.1 の C コードの合成の結果を示す。
tensorflow_keras_111_180618.png

特徴マップが 3 個の場合のWindows版Vivado HLS 2018.1 の Export RTLの結果を示す。
tensorflow_keras_112_180618.png

Vivado HLSの特徴マップ 3 個、5 個、10 個のC コードの合成とExport RTLの結果を下表に示す。
tensorflow_keras_113_180618.png

Vivado HLS 2017.4 のLinux 版とWindows版のC コードの合成結果は同じだったが、Export RTLの結果は異なっている。これは、Vivado 2017.4 が Linux 版とWindows版で異なっているのかもしれない?
Vivado HLS 2018.1 のC コードの合成結果は、2017.4 の結果よりも FF と LUT のリソース使用量が少なった。Export RTLの結果は、FF は Vivado HLS 2018.1 の方がリソース使用量が少なかったが、LUT は Vivado HLS 2017.4 の方がリソース使用量が少なかった。
  1. 2018年06月18日 05:30 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた21(特徴マップ数が3個、5個、10個のMNIST用CNNをC/RTLコシムとIP化)

TensorFlow + Kerasを使ってみた20(特徴マップ3個のMNIST用CNNをVivado HLSで実装)”の続き。

前回は、MNIST 用のCNN で特徴マップ数が 3 個の場合をVivado HLS で実装した。今回は、特徴マップ数が 3 個、 5 個、10 個のMNIST用CNNをC/RTL 強調シミュレーションと、Export RTL を行う。

まずは、特徴マップ数が 3 個の時のMNIST 用CNN をC/RTL 強調シミュレーションと、Export RTL を行ってみよう。
最初に、テストベンチの mnist_conv_nn_hlss_tb.cpp の 「#define NUM_ITERATIONS 1000」をコメントアウトして、「#define NUM_ITERATIONS 2」のコメントアウトを削除した。これは、C/RTL 強調シミュレーションを行うにあたって、1000 個推論を実行するのは時間がかかりすぎると思ったからだ。波形を見るだけなので、少ない推論数でも十分なわけだ。
tensorflow_keras_104_180616.png

これで、C/RTL 強調シミュレーションを行ったところ、エラーだった。
tensorflow_keras_105_180616.png

次に、Export RTL を行った。なお、Vivado synthesis, place and route にチェックを入れてある。結果を示す。
tensorflow_keras_103_180616.png

LUT は 2794 個、FF は 3195 個、DSP は 62 個、BRAM 34 個、SRL 73 個使用している。
合成時のリソース使用量はBRAM_18K が 34 個、DSP48E が 62 個、FF が 5284 個、LUT が 9137 個だった。DSP と BRAM の個数は同じで、FF は約 60.5 % 、LUT は約 31.4 % になった(LUT はLUT とSRL をLUT として計算した)。


次に、特徴マップ数が 5 個の時のMNIST 用CNN をC/RTL 強調シミュレーションと、Export RTL を行ってみよう。
同様に、テストベンチの mnist_conv_nn_hlss_tb.cpp の 「#define NUM_ITERATIONS 1000」をコメントアウトして、「#define NUM_ITERATIONS 2」のコメントアウトを削除した。
C/RTL 強調シミュレーションを実行したところ、同様にエラーだった。
tensorflow_keras_106_180616.png

Export RTL を行った。なお、Vivado synthesis, place and route にチェックを入れてある。結果を示す。
tensorflow_keras_107_180617.png

LUT は 3605 個、FF は 3811 個、DSP は 93 個、BRAM 66 個、SRL 63 個使用している。
合成時のリソース使用量はBRAM_18K が 66 個、DSP48E が 93 個、FF が 6215 個、LUT が 11144 個だった。DSP と BRAM の個数は同じで、FF は約 61.3 % 、LUT は約 32.9 % になった(LUT はLUT とSRL をLUT として計算した)。


最後に、特徴マップ数が 5 個の時のMNIST 用CNN をC/RTL 強調シミュレーションと、Export RTL を行ってみよう。
同様に、テストベンチの mnist_conv_nn_hlss_tb.cpp の 「#define NUM_ITERATIONS 1000」をコメントアウトして、「#define NUM_ITERATIONS 2」のコメントアウトを削除した。
C/RTL 強調シミュレーションを実行したところ、同様にエラーだった。
tensorflow_keras_109_180617.png

Export RTL を行った。なお、Vivado synthesis, place and route にチェックを入れてある。結果を示す。
tensorflow_keras_108_180617.png

LUT は 5708 個、FF は 5681 個、DSP は 175 個、BRAM 130 個、SRL 73 個使用している。
合成時のリソース使用量はBRAM_18K が 130 個、DSP48E が 175 個、FF が 9005 個、LUT が 16391 個だった。DSP と BRAM の個数は同じで、FF は約 63.1 % 、LUT は約 35.3 % になった(LUT はLUT とSRL をLUT として計算した)。

Export RTL 時の特徴マップ数によるリソース使用量の違いを表に追加した。
tensorflow_keras_110_180617.png
  1. 2018年06月17日 05:36 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

「空飛ぶタイヤ」(映画)を見てきました

「空飛ぶタイヤ」(映画)(音注意)を見てきました。
池井戸潤の原作は3回読んだんですが、やはり映画は、時間が足りないですね。「64」の様に前後編に分けたほうが良かったのでは?と思いました。はるな銀行に銀行を変えたのか?の経緯が全く飛んでましたね。。。
ちょうど、ハリーポッターの最後から2、3作前のような感じです。本のボリュームは多くなっても、映画の時間はそれほど増えないので、映画が良く分からなくなった感じがしました。。。
  1. 2018年06月16日 19:37 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた20(特徴マップ3個のMNIST用CNNをVivado HLSで実装)

TensorFlow + Kerasを使ってみた19(特徴マップ3個と2個のMNIST用CNNをテスト)”の続き。

前回は、MNIST 用のCNN で特徴マップが 3 個と 2 個の時について学習を行ったところ、3 個の場合の精度が 98.54 % で使い物になるようだった。特徴マップが 2 個の場合は、98.02 % で少し低くなっていた。今回は、MNIST 用のCNN で特徴マップが 3 個の場合をVivado HLS で実装してみよう。

まずは、畳み込み層と全結合層の重みとバイアスをKeras からC のヘッダファイルとして取得した。
そして、MNIST のデータの1000 個分をC のヘッダファイルとして出力した mnist_data.h を使用する。
これらのヘッダファイルの取得方法は、”TensorFlow + Kerasを使ってみた18(特徴マップ5個のMNIST用CNNをVivado HLSで実装)”をご覧あれ。。。

Vivado HLS 2017.4 の mnist_conv_nn5_hlss_org を作成した。
各層の演算精度が書いてある mnist_conv_nn5_hlss.h を示す。ここの値を変更すると演算精度を変更することができる。
tensorflow_keras_99_180615.png

幾度と無く mnist_conv_nn5_hlss.h のパラメータを変更して、C シミュレーションを行った結果、「特徴マップが 5 個の時」のパラメータの中で、 CONV_BIT_LENGTH を 10 から 11 ビットに変更したところ、ハードウェア化する固定小数点演算の精度が改善した。これで行くことにする。

C シミュレーションを行った。結果を示す。
tensorflow_keras_98_180615.png

1000 個のMNIST のデータのうちでハードウェアの固定小数点演算ではエラーが 15 個、ソフトウェアの浮動小数点演算ではエラーが 16 個だった。
よって、ハードウェアの固定小数点演算での精度は、98.5 % となった。
ソフトウェアの浮動小数点演算での精度は、98.4 % となった。

C コードの合成を行った。結果を示す。
tensorflow_keras_100_180615.png
tensorflow_keras_101_180615.png

Latency は min が 101701 クロックで、max は 102133 クロックだった。100 MHz 動作だと約 1.02 ms だった。fpsにすると約 979 fps となった。
リソース使用量はBRAM_18K が 34 個、DSP48E が 62 個、FF が 5284 個、LUT が 9137 個だった。

特徴マップ数が 10 個の場合と 5 個の場合と 3 個の場合のリソース使用量を表にした。
tensorflow_keras_102_180615.png

この表を見ると、特に BRAM_18K の減りが激しいようだ。BRAM_18K の特徴マップ数が 10 個の時を基準とした時の 3 個の時のパーセンテージは 26.15 % だったが、DSP48E は 35.43 % で、FF は 58.68 % 、 LUT は 55.74 % だった。

なお、あくまで C コードの合成でのリソース使用量の見積もりであることに注意してほしい。
特に、パラメータ数が多いテンプレートを使っていると C コードの合成時のレポートと実際にExport RTL した時のVivado での概算とのリソース使用量の違いが多い気がする。
  1. 2018年06月15日 05:33 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた19(特徴マップ3個と2個のMNIST用CNNをテスト)

TensorFlow + Kerasを使ってみた18(特徴マップ5個のMNIST用CNNをVivado HLSで実装)”の続き。

特徴マップ5個のMNIST 用 CNN がうまく行ったようなので、特徴マップ 3 個と 2 個のMNIST 用CNN をKeras で学習させてみることにした。

まずは、Keras でSequentialモデルを作って学習する。以前使用していたCNN から畳み込み層の特徴マップの数を 5 個から 3 個に変更した。他のコードは変えていない。
tensorflow_keras_90_180614.png
tensorflow_keras_91_180614.png
tensorflow_keras_92_180614.png
tensorflow_keras_93_180614.png

Epoch 10 まで学習して val_acc: 0.9854 だった。やはり、特徴マップが多いものよりも精度は少し落ちている。ちなみに特徴マップが 10 個の時は、Epoch 12 で val_acc: 0.9898 、特徴マップが 5 個の時は、Epoch 10 まで学習して val_acc: 0.9864 だった。
学習も特徴マップが 10 個の時や 5 個の時よりも、3 個の時の方がより過学習になっていないようだ。


次に、Keras でSequentialモデルを作って学習する。以前使用していたCNN から畳み込み層の特徴マップの数を 5 個から 2 個に変更した。他のコードは変えていない。
tensorflow_keras_94_180614.png
tensorflow_keras_95_180614.png
tensorflow_keras_96_180614.png
tensorflow_keras_97_180614.png

Epoch 10 の時の精度が 0.9802 であまり上がらない。特徴マップ 2 個を使うという選択肢は厳しいようだ。
  1. 2018年06月14日 05:19 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた18(特徴マップ5個のMNIST用CNNをVivado HLSで実装)

TensorFlow + Kerasを使ってみた17(特徴マップを10個から5個へ)”の続き。

前回は、今までは畳み込み層で 10 個の特徴マップを使用していたが、5 個ではどうだろうということでやってみたところ、98.64 % の精度が確保できた。今回は、特徴マップ5 個のMNIST 用 CNN を使用して、Vivado HLS で実装してみた。

まずは、畳み込み層と全結合層の重みとバイアスをKeras からC のヘッダファイルとして取得した。
TensorFlow + Kerasを使ってみた9(畳み込み層の重みをC のヘッダに変換)
TensorFlow + Kerasを使ってみた10(バイアスをC のヘッダに変換)
TensorFlow + Kerasを使ってみた11(全結合層の重みをC のヘッダに変換)"

そして、MNIST のデータの1000 個分をC のヘッダファイルとして出力した mnist_data.h を使用する。
TensorFlow + Kerasを使ってみた12(MNISTのデータの一部をC のヘッダに変換)

そうして、作成したVivado HLS 2017.4 の mnist_conv_nn5_hlss_org を作成した。
Keras で重みやバイアス、各層の出力の最大値、最小値をみたところ、畳み込み層の整数部のビット数を 1 ビット増やして、4 ビットとすることにした。総ビット数は 10 ビットで変更無しなので、小数部が 1 ビット減って 6 ビットとした。
各層の演算精度が書いてある mnist_conv_nn5_hlss.h を示す。ここの値を変更すると演算精度を変更することができる。
tensorflow_keras_89_180613.png

C シミュレーションを行った。結果を示す。
tensorflow_keras_86_180612.png

1000 個のMNIST のデータのうちでハードウェアの固定小数点演算ではエラーが 7 個、ソフトウェアの浮動小数点演算ではエラーが 9 個だった。
よって、ハードウェアの固定小数点演算での精度は、99.3 % となった。
ソフトウェアの浮動小数点演算での精度は、99.1 % となった。
だいぶ精度が良いが、10000 個のテストデータの内の最初の 1000 個のデータで評価しているので、他のところのデータの精度が悪かったのか?

C コードの合成を行った。結果を示す。
tensorflow_keras_87_180613.png
tensorflow_keras_88_180613.png

Latency は min が 130646 クロックで、max は 131366 クロックだった。100 MHz 動作だと約 1.31 ms となる。fpsにすると約 763 fps となる。
前回の特徴マップが 10 個の飽和演算なしの時の Latency の max は 204376 クロックだったので、 204376 / 131366 x 100 ≒ 155.58 % の性能ということになる。
リソース使用量はBRAM_18K が 66 個、DSP48E が 93 個、FF が 6215 個、LUT が 11144 個だった。
前回の特徴マップが 10 個の飽和演算なしの時のリソース使用量は、BRAM_18K が 130 個、DSP48E が 175 個、FF が 9005 個、LUT が 16391 個だったので、BRAM_18K については、半分以下のリソース使用量となった。
  1. 2018年06月13日 04:46 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた17(特徴マップを10個から5個へ)

TensorFlow + Kerasを使ってみた16(C コードの合成、ビット幅の削減)”の続き。

前回は、各層の演算のビット幅をチェックしたが、ビット幅を小さくしても、思ったようにリソース使用量が少なくならなかった。今回は、IP のレイテンシとリソース使用量に効くのはなんと言っても、畳み込み層の特徴マップの数じゃないか?と思う。今までは畳み込み層で 10 個の特徴マップを使用していたが、5 個ではどうだろうということでやってみた。

まずは、Keras でSequentialモデルを作って学習する。以前使用していたCNN から畳み込み層の特徴マップの数を 10 個から 5 個に変更した。他のコードは変えていない。
tensorflow_keras_82_180612.png
tensorflow_keras_83_180612.png
tensorflow_keras_84_180612.png
tensorflow_keras_85_180612.png

Epoch 10 まで学習したが val_acc: 0.9864 なので、良さそうだ。ちなみに特徴マップが 10 個の時は、Epoch 12 で val_acc: 0.9898 だった。
演算のビット幅を落として精度が落ちるならば、特徴マップを減らして、演算のビット幅をあまり落とさないほう精度的には同じで、よりリソース使用量が小さくなるのではないか?と思っている。つまり、精度を考えた特徴マップの数と演算のビット幅の最適化を図っていきたい。
学習も特徴マップが 10 個の時よりも、5 個の時の方がより過学習になっていないようだ。
  1. 2018年06月12日 05:29 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた16(C コードの合成、ビット幅の削減)

TensorFlow + Kerasを使ってみた15(飽和演算と通常の演算)”の続き。

前回は、畳み込み層に”Vivado HLS の任意精度固定小数点データ型の飽和演算”でテストした演算後の値を飽和演算し、また全結合層では内積の演算に飽和演算を用いる実装と、今まで通りにすべての演算に飽和演算を用いない場合について検証した。今回は、その飽和演算ありと飽和演算なしの2つの実装を合成して、リソース使用量を比較して見た後で、演算のビット幅を小さくして、C シミュレーション結果とC コードの合成結果を見ていこう。

最初に飽和演算なしの実装(mnist_conv_nn10_hlss_k_org)のC コードの合成結果を見る。
tensorflow_keras_73_180610.png
tensorflow_keras_74_180610.png

Latency は min が 202936 クロックで、 max が 204376 クロックだった。これは、100 MHz クロックを使用すると max の場合では、約 2.04 ms となった。
リソース使用量は、BRAM_18K が 130 個、DSP48E が 175 個、FF が 9005 個、LUT が 16391 個だった。

次に、飽和演算あり(mnist_conv_nn10_hlss_k)の実装のC コードの合成結果を見る。
tensorflow_keras_75_180610.png
tensorflow_keras_76_180610.png

こちらのLatency の min は 217336 クロックで max は 218776 クロックだった。100 MHz クロックだと max で 2.19 ms となった。飽和演算なしと比較すると、max 値で 217336 / 204376 ≒ 1.063 倍だった。
リソース使用量は、BRAM_18K が 130 個、DSP48E が 175 個は飽和演算なしと変化がないが、FF の 9168 個と LUT の 19109 個は飽和演算なしよりもリソース使用量が多かった。

次に演算のビット幅を縮小してみよう。
次に示す演算のビット幅でCNN の演算を行った。

#define INPUT_CHANNELS 1
#define INPUT_BIT_LENGTH 9
#define INPUT_INTEGER_LEN 1

#define CONV_BIT_LENGTH 8
#define CONV_INTEGER_LEN 3
#define CONV_CHANNELS 10
#define CONV_MID_BIT_LENGTH 13
#define CONV_MID_BIT_INTGER_LEN 3

#define AFFINE_BIT_LENGTH 11
#define AFFINE_INTEGER_LEN 5

#define OUTPUT_BIT_LENGTH 12
#define OUTPUT_INTEGER_LEN 7


演算のビット幅を 2 ビット減らしてみた。ただし整数部のビット幅はいじっていないので、飽和演算あり、飽和演算なしで同様のエラーになるはずである。
飽和演算ありと飽和演算なしの実装の C シミュレーション結果を示す。
tensorflow_keras_77_180610.png

飽和演算ありと飽和演算なしどちらも、HW_ERROR_COUNT = 23, SW_ERROR_COUNT = 15 だった。
エラー内容を示す。なおこのエラー内容も、飽和演算ありと飽和演算なしで同一だった。

id = 18, max_id_ref = 3, max_id_sw = 8
id = 115, max_id_ref = 4, max_id_sw = 9
id = 151, max_id_ref = 9, max_id_hw = 8
id = 184, max_id_ref = 8, max_id_hw = 3
id = 217, max_id_ref = 6, max_id_hw = 5
id = 247, max_id_ref = 4, max_id_sw = 2
id = 321, max_id_ref = 2, max_id_sw = 7
id = 324, max_id_ref = 0, max_id_hw = 6
id = 340, max_id_ref = 5, max_id_hw = 3
id = 340, max_id_ref = 5, max_id_sw = 3
id = 406, max_id_ref = 5, max_id_hw = 9
id = 445, max_id_ref = 6, max_id_sw = 0
id = 448, max_id_ref = 9, max_id_hw = 8
id = 449, max_id_ref = 3, max_id_sw = 5
id = 508, max_id_ref = 6, max_id_hw = 5
id = 547, max_id_ref = 2, max_id_hw = 3
id = 551, max_id_ref = 7, max_id_hw = 3
id = 582, max_id_ref = 8, max_id_hw = 2
id = 582, max_id_ref = 8, max_id_sw = 2
id = 619, max_id_ref = 1, max_id_hw = 8
id = 619, max_id_ref = 1, max_id_sw = 8
id = 625, max_id_ref = 6, max_id_hw = 4
id = 655, max_id_ref = 8, max_id_hw = 3
id = 658, max_id_ref = 7, max_id_hw = 4
id = 659, max_id_ref = 2, max_id_hw = 1
id = 659, max_id_ref = 2, max_id_sw = 1
id = 674, max_id_ref = 5, max_id_hw = 3
id = 684, max_id_ref = 7, max_id_hw = 3
id = 684, max_id_ref = 7, max_id_sw = 3
id = 685, max_id_ref = 8, max_id_hw = 2
id = 723, max_id_ref = 0, max_id_hw = 4
id = 738, max_id_ref = 2, max_id_hw = 8
id = 813, max_id_ref = 9, max_id_sw = 8
id = 846, max_id_ref = 7, max_id_hw = 9
id = 870, max_id_ref = 6, max_id_hw = 5
id = 883, max_id_ref = 3, max_id_sw = 5
id = 947, max_id_ref = 8, max_id_sw = 9
id = 965, max_id_ref = 6, max_id_sw = 0
HW_ERROR_COUNT = 23, SW_ERROR_COUNT = 15


次に、演算ビット幅を縮小したままC コードの合成を行った。
まずは、飽和演算なしからC コードの合成結果を示す。
tensorflow_keras_78_180611.png
tensorflow_keras_79_180611.png

Latency は min が 202936 クロックで、 max が 204376 クロックだった。これは、100 MHz クロックを使用すると max の場合では、約 2.04 ms となる。これはビット幅を変更する前と同じだった。
リソース使用量は、BRAM_18K が 130 個、DSP48E が 175 個、FF が 9005 個、LUT が 16391 個だった。これはビット幅を変更する前からすると、FF が約 88.2 % 、LUT が約 91.4 % に減少している。

次に飽和演算ありの C コードの合成結果を示す。
tensorflow_keras_80_180611.png
tensorflow_keras_81_180611.png

Latency の min は 217336 クロックで max は 218776 クロックだった。100 MHz クロックだと max で 2.19 ms となった。やはり、こちらもビット幅を変更する前と同一だった。
リソース使用量は、BRAM_18K が 130 個、DSP48E が 175 個は飽和演算なしと変化がないが、FF の 8107 個と LUT の 17641 個だった。これはビット幅を変更する前からすると、FF が約 88.4 % 、LUT が約 92.3 % に減少している。

ビット幅を縮小しても思ったよりリソース使用量の縮小がなかったので、以前の下に示す演算ビット幅で行こうと思う。

#define INPUT_CHANNELS 1
#define INPUT_BIT_LENGTH 9
#define INPUT_INTEGER_LEN 1

#define CONV_BIT_LENGTH 10
#define CONV_INTEGER_LEN 3
#define CONV_CHANNELS 10
#define CONV_MID_BIT_LENGTH 16
#define CONV_MID_BIT_INTGER_LEN 3

#define AFFINE_BIT_LENGTH 13
#define AFFINE_INTEGER_LEN 5

#define OUTPUT_BIT_LENGTH 12
#define OUTPUT_INTEGER_LEN 7


また、飽和演算ありと飽和演算なしだが、現在の整数ビット幅を維持できれば、飽和演算ありと飽和演算なしとエラー数も変化がないので、リソース使用量の少ない飽和演算なしで行くことにする。
  1. 2018年06月11日 05:04 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた15(飽和演算と通常の演算)

TensorFlow + Kerasを使ってみた14(Vivado HLSで実装2)”の続き。

前回は、Keras から重みやバイアスを取り出して、Vivado HLS 2017.4 に実装したCNN をC シミュレーションしたところ、ソフトウェアのfloat 演算では精度 99 %、ハードウェアの固定小数点演算では、精度 98 % を確認することが出来た。今回は、畳み込み層に”Vivado HLS の任意精度固定小数点データ型の飽和演算”でテストした演算後の値を飽和演算し、また全結合層では内積の演算に飽和演算を用いる実装と、今まで通りにすべての演算に飽和演算を用いない場合について検証してみよう。

まずは、今まで通りに飽和演算を用いない場合について現在のパラメータで実力を確認しよう。
現在のMNIST のデータ数は 500 個を使用してる。
固定小数点のビット長のパラメータを次に示す。

#define INPUT_CHANNELS 1
#define INPUT_BIT_LENGTH 9
#define INPUT_INTEGER_LEN 1

#define CONV_BIT_LENGTH 10
#define CONV_INTEGER_LEN 3
#define CONV_CHANNELS 10

#define AFFINE_BIT_LENGTH 13
#define AFFINE_INTEGER_LEN 7

#define OUTPUT_BIT_LENGTH 12
#define OUTPUT_INTEGER_LEN 7


入力層の出力のビット長は 9 ビットで、そのうちの 1 ビットが整数のビット長である。つまり +1-0.00390625 〜 -1 までだ。
畳み込み層の出力のビット長は 10 ビットで、そのうちの 3 ビットが整数のビット長である。
全結合層の出力のビット数は 13 ビットで、そのうちの 7 ビットが整数のビット長である。
C シミュレーションの結果を示す。
tensorflow_keras_68_180609.png

500 個のMNIST データに対して、ソフトウェアのfloat 演算は 7 個、ハードウェアの固定小数点演算は 12 個のエラーが出た。
精度を計算してみよう。
ソフトウェアのfloat 演算のエラー数は 3 個なので、 (500 - 7) / 500 x 100 = 98.6 %
ハードウェアの固定小数点演算は 6 個なので、 (500 - 12) / 500 x 100 = 97.6 %
ソフトウェアのfloat 演算とハードウェアの固定小数点演算との差は 1 % となった。

さて、ここから、飽和演算をする実装に変更した mnist_conv10_hlss_k プロジェクトと今までの飽和演算をしない実装の mnist_conv10_hlss_k_org プロジェクトを比較してみよう。

飽和演算をする実装に変更した mnist_conv10_hlss_k プロジェクトの畳み込み層の飽和演算を紹介しよう。
tensorflow_keras_70_180610.png

演算結果の val を飽和演算して out_sat に代入する。 out_sat を conv_out.data[k] に代入している。

次に、mnist_conv10_hlss_k プロジェクトの飽和演算を紹介する。
tensorflow_keras_71_180610.png

飽和演算するように宣言した dot配列を使用して演算するので、飽和演算が実行できる。

さて、今までのKeras パラメータを見ると、第1層目の全結合層の値域が小さいので、整数値のビット長の 7 ビットはいらないことが分かった。そこで 5 ビットとする。そして、精度方向に 3 ビット拡張することにした。整数部を 2 ビット削除して、小数部を 3 ビット追加した。つまり、ビット長を 14 ビット、整数部のビット長を 5 ビットとした。
変更した固定小数点のビット長のパラメータを示す。

#define INPUT_CHANNELS 1
#define INPUT_BIT_LENGTH 9
#define INPUT_INTEGER_LEN 1

#define CONV_BIT_LENGTH 10
#define CONV_INTEGER_LEN 3
#define CONV_CHANNELS 10
#define CONV_MID_BIT_LENGTH 16
#define CONV_MID_BIT_INTGER_LEN 3

#define AFFINE_BIT_LENGTH 14
#define AFFINE_INTEGER_LEN 5
//#define AFFINE_BIT_LENGTH 13
//#define AFFINE_INTEGER_LEN 7

#define OUTPUT_BIT_LENGTH 12
#define OUTPUT_INTEGER_LEN 7


このパラメータでMNIST データ数を 1000 個として C シミュレーションを行った。
tensorflow_keras_69_180610.png

飽和演算をする実装に変更した mnist_conv10_hlss_k プロジェクトと今までの飽和演算をしない実装の mnist_conv10_hlss_k_org プロジェクト共に、1000 個のMNIST データに対して、ソフトウェアのfloat 演算は 15 個、ハードウェアの固定小数点演算は 15 個のエラーが出た。
という訳で、ソフトウェアのfloat 演算とハードウェアの固定小数点演算のエラー個数が同一になった。

次に、

#define AFFINE_BIT_LENGTH 13

に変更して、全結合層の演算のビット長を 13 ビットにした。 C シミュレーションの結果を示す。
tensorflow_keras_72_180610.png

飽和演算をする実装に変更した mnist_conv10_hlss_k プロジェクトと今までの飽和演算をしない実装の mnist_conv10_hlss_k_org プロジェクト共に、1000 個のMNIST データに対して、ソフトウェアのfloat 演算は 15 個、ハードウェアの固定小数点演算は 14 個のエラーが出た。
全結合層第1層目の演算のビット幅を 1 ビット減らしたのに、ハードウェアの固定小数点演算での精度が増えてしまった。良い具合に間違ったようだ。
現在のソフトウェアのfloat 演算の精度は 98.5 % だった。
  1. 2018年06月10日 05:03 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

FPGAの部屋のまとめサイトの更新(2018年6月9日)

FPGAの部屋のまとめサイトを更新しました。
2018年6月8日までの記事のエントリを追加しました。Ultra96TensorFlow, Keras のエントリを追加しました。
  1. 2018年06月09日 07:25 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS の任意精度固定小数点データ型の飽和演算

Kerasを勉強して、Keras でMNISTのCNNのパラメータを抽出して、Vivado HLS で自作テンプレートを使ってCNN を実装しているが、現在の自作テンプレートは飽和演算をサポートしていない。これは、飽和演算をサポートするよりは、演算によって取りうる値域すべてをカバーする演算用のビット長を与えたほうが、リソース使用量が小さいという実証データに基づいていた。ただし、特に、全結合層に言えることだが、演算結果の値域をカバーするような演算ビット幅を与えても、途中の計算でオーバーフローしてしまう可能性がある。つまり、整数部4ビットでは、+7.XXX ~ -8.XXX の数を表せるが、最終的に +4.XXX でもそれは、+36.XXX から +32.XXX を引いた結果かもしれない?その場合には、整数部4ビットで演算させる場合は、途中の演算で破綻している訳である。それでもたま~にであれば、それも量子化による誤差の一部として認めても良いと思っている。あくまでもリソース使用量との兼ね合いで。。。(ちなみに、Vivado HLSでは自由にビット長を選べるので、各層ごとに演算ビット長を変更している)
今度、飽和演算をサポートしたCNN とサポートしていないCNN の精度の差を比べてみようと思っている。

さて、全結合層は演算自体が多いので、演算自体に飽和演算をサポートするが、畳み込み層は1回の演算数が今のところ25個なので、重みの最大値、最小値から演算の途中の最大値を導出することができる。よって、正しい値になるような演算ビット長を推測しやすい。そのような演算ビット長で演算はするのだが、次の層に送る場合に飽和演算をサポートするとよりリソース使用量が削減される可能性がある。そのような演算をサポートするために飽和演算をサポートしない演算の結果を飽和演算しながら、丸めたい。
と言う訳で今日のブログにつながる訳である。

さて、まずは、sat_test1.h を示す。

// sat_test1.h
// 2018/06/07 by marsee
//

#ifndef __SAT_TEST1_H__
#define __SAT_TEST1_H__

#include <ap_fixed.h>

typedef ap_fixed<53, AP_TRN, AP_WRAP> ap_fixed_inout_def;
typedef ap_fixed<53, AP_TRN, AP_SAT> ap_fixed_sat_def; // 飽和演算
typedef ap_fixed<75, AP_TRN, AP_WRAP> ap_fixed_mid_def;

#endif


次に、sat_test1.cpp を示す。合成する気はさらさらないので、途中で printf() を使用している。

// sat_test1.cpp
// 2018/06/07 by marsee
//

#include "sat_test1.h"

int sat_test1(ap_fixed_inout_def in0, ap_fixed_inout_def in1,
        ap_fixed_inout_def &out){
    ap_fixed_mid_def calc;

    calc = ap_fixed_mid_def(in0) * ap_fixed_mid_def(in1);
    printf("calc = %f\n"float(calc));
    out = ap_fixed_inout_def(ap_fixed_sat_def(calc));

    return(0);
}


最後にテストベンチの sat_test1_tb.cpp を示す。

// sat_test1_tb.cpp
// 2018/06/07 by marsee
//

#include "sat_test1.h"

int sat_test1(ap_fixed_inout_def in0, ap_fixed_inout_def in1,
        ap_fixed_inout_def &out);

int main(){
    ap_fixed_inout_def in0_0, in1_0;
    ap_fixed_inout_def in0_1, in1_1;
    ap_fixed_inout_def out0, out1;

    in0_0 = 1.5;
    in1_0 = 1.5;
    sat_test1(in0_0, in1_0, out0);
    printf("in0_0 = %f, in1_0 = %f, out = %f\n",
        float(in0_0), float(in1_0), float(out0));

    in0_1 = 3.0;
    in1_1 = 3.0;
    sat_test1(in0_1, in1_1, out1);
    printf("in0_1 = %f, in1_1 = %f, out = %f\n",
        float(in0_1), float(in1_1), float(out1));

    in0_1 = -3.0;
    in1_1 = 3.0;
    sat_test1(in0_1, in1_1, out1);
    printf("in0_1 = %f, in1_1 = %f, out = %f\n",
        float(in0_1), float(in1_1), float(out1));

    return(0);
}


C シミュレーションの結果を示す。
sat_test1_1_180608.png

1.5 x 1.5 = 2.25 は演算後のビット長が定義したビット長に収まっているので、これは正しい。
3.0 x 3.0 = 3.75 は途中の結果は 9.0 だけど、飽和演算して、3.75 に丸められているので、問題無い様だ。
-3.0 x 3.0 = -4.00 は途中の結果は -9.0 だけど、飽和演算して、-4.00 に丸められているので、問題無い様だ。
  1. 2018年06月08日 04:35 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた14(Vivado HLSで実装2)

TensorFlow + Kerasを使ってみた13(Vivado HLSで実装1)”の続き。

前回は、今ままでの重みやバイアス、そして、MNISTのデータの一部を記述した C ヘッダを使用して、”今まで作ってきた層のテンプレートをMNIST のCNN に適用する3(Export RTL まで)”のVivado HLS プロジェクトに適用してみたが、C シミュレーションをした時に、ほとんどのデータがエラーになってしまった。今回は、その原因を追求して原因を突き止めた。そして、もう一度、C シミュレーションを行ったところNo Error だった。成功した。

まず、前回のエラーはどこが原因なのか考えたところ、flatten 層でフラット化してるのだが、MaxPooling層のどこが全結合層のどこに接続されているか?ということだった。Keras では下の図を見ると、MaxPooling層の (None, 12, 12, 10) がFlatten 層で (None, 1440) に変換されている。つまり、MaxPooling 層では、処理された画像の高さ (12)、画像の幅 (12) 、チャネル数 (10) の配列ということになる。そうなると前結合層の重みを取り出したの配列数の (1440, 100) の 1440 の内訳は処理された画像の高さ (12)、画像の幅 (12) 、チャネル数 (10) の配列のはずである。それじゃまずい。想定してる配列の順番は、チャネル数 (10) 、画像の高さ (12)、画像の幅 (12) なので、重みの配列の順番を入れ替える必要があるということが分かった。
tensorflow_keras_64_180606.png

そこで、”TensorFlow + Kerasを使ってみた11(全結合層の重みをC のヘッダに変換)”の全結合層1層目の重みをC ヘッダにする部分のPython コードを以下の様に変更した。

fwrite_af_weight(dence_layer1_weight, 'af1_weight10.h', 'af1_fweight', 'af1_weight', MAGNIFICATION_AF)
MAGNIFICATION_AF = 2 ** (9-1)
print(dence_layer1_weight.shape)
dence_Layer1_w12_12_10_100 = np.reshape(dence_layer1_weight,(12,12,10,100))
dence_Layer1_w201 = dence_Layer1_w12_12_10_100.transpose(2,0,1,3)
dence_Layer1_w1440_100 = np.reshape(dence_Layer1_w201,(1440,100))
fwrite_af_weight(dence_Layer1_w1440_100, 'af1_weight10.h', 'af1_fweight', 'af1_weight', MAGNIFICATION_AF)



これで作成された全結合層1層目の重みをC ヘッダにした af1_weight10.h を示す。
tensorflow_keras_51_180601.png
tensorflow_keras_52_180601.png

この全結合層1層目の重みを Vivado HLS の mnist_conv_nn10_hlss_k プロジェクトに適用した。
(2018/06/07 : 修正、デバックのために、NUM_ITERATIONS に 1 を設定していたので、エラーが 0 だった。 300 を設定するとエラーが出るようになった)
C シミュレーションを行ったところ、300 個の テストデータに対して、ソフトウェアのfloat 演算は 3 個、ハードウェアの固定小数点演算は 6 個のエラーが出た。ちなみに、ハードウェアの量子化ビット幅は以前使用したものをそのまま使用している。
tensorflow_keras_65_180606.png

精度を計算してみよう。
ソフトウェアのfloat 演算のエラー数は 3 個なので、 (300 - 3) / 300 x 100 = 99 %
ハードウェアの固定小数点演算は 6 個なので、 (300 - 6) / 300 x 100 = 98 %

これで、Keras から重みやバイアスをVivado HLS のCNN に移すことが出来たと思うが、ビット幅の検討をする必要がある。
  1. 2018年06月06日 04:56 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた13(Vivado HLSで実装1)

TensorFlow + Kerasを使ってみた12(MNISTのデータの一部をC のヘッダに変換)”の続き。

前回は、MNISTのデータの一部をC のヘッダに変換した。今回は、今ままでの重みやバイアス、そして、MNISTのデータの一部を記述した C ヘッダを使用して、”今まで作ってきた層のテンプレートをMNIST のCNN に適用する3(Export RTL まで)”のVivado HLS プロジェクトに適用してみよう。

まずは、Vivado HLS 2017.4 で mnist_conv_nn10_hlss_k プロジェクトを作成した。
tensorflow_keras_59_180605.png

mnist_conv_nn10_hlss_k プロジェクトでは、”今まで作ってきた層のテンプレートをMNIST のCNN に適用する3(Export RTL まで)”で使用した mnist_conv_nn1_hlss プロジェクトの重みやバイアス、そして、MNISTのデータの一部を記述した C ヘッダをKeras で出力した重みやバイアス、そして、MNISTのデータの一部を記述した C ヘッダに変更した。

C シミュレーションを行った。コンパイラは gcc で実行するとエラーだった。
tensorflow_keras_60_180605.png

エラーログを示す。

INFO: [SIM 2] *************** CSIM start ***************
INFO: [SIM 4] CSIM will launch GCC as the compiler.
Compiling ../../../mnist_conv_nn_hlss_tb.cpp in debug mode
csim.mk:76: ターゲット 'obj/mnist_conv_nn_hlss_tb.o' のレシピで失敗しました
gcc: internal compiler error: Segmentation fault (program cc1plus)
Please submit a full bug report,
with preprocessed source if appropriate.
See for instructions.
make: *** [obj/mnist_conv_nn_hlss_tb.o] エラー 4
CRITICAL WARNING: [SIM 100] 'csim_design' failed: compilation error(s).
INFO: [SIM 3] *************** CSIM finish ***************


gcc: internal compiler error ということでどうしようもない。

次に、clang でコンパイルしてみた。
tensorflow_keras_61_180605.png

今度はコンパイルできたが、300 個のデータの殆どでエラーになってしまった。。。
tensorflow_keras_62_180605.png

ちなみに、元の mnist_conv_nn1_hlss プロジェクトで C シミュレーションをやってみた。
こちらのデータ数は 100 個だが、1 個の間違いだけなので、Keras の重みやバイアスのデータがおかしいのだと思う。
tensorflow_keras_63_180605.png

これから原因を追求していこう。
  1. 2018年06月05日 04:57 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた12(MNISTのデータの一部をC のヘッダに変換)

TensorFlow + Kerasを使ってみた11(全結合層の重みをC のヘッダに変換)”の続き。

前回は全結合層1層目、2層目の重みをC のヘッダに変換した。今回は、MNISTのデータの一部をC のヘッダに変換してみよう。これは、Vivado HLS のC シミュレーション時に精度を確認するためのデータとなる。

MNISTのデータの一部をC のヘッダに変換するPython コードを示す。
(2018/06/05:修正 MNIST のデータを見ると 1.0 つまり 256 のデータが存在する。これは 8 ビット長のビット表現では、 0 になってしまうことが考えられるので、Python コードを修正した)

# MNISTのデータをCの配列に出力し、ファイルに書き込み

# coding: utf-8
import sys, os
sys.path.append(os.pardir)

import numpy as np
import datetime

OUTPUT_DATA_NUM = 300 # 出力するMNISTのテストデータ数 10000までの数
OFFSET = 0 # MNISTデータセットのオフセット、100だったら100番目からOUTPUT_DATA_NUM個を出力する

# データの読み込み
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 256
x_test /= 256

print(x_test.shape)

f = open("mnist_data.h", 'w')
todaytime = datetime.datetime.today()
f.write('// mnist_data.h\n')
strdtime = todaytime.strftime("%Y/%m/%d %H:%M:%S")
f.write('// {0} by marsee\n'.format(strdtime))
f.write("\n")

f.write('ap_ufixed<8, 0, AP_TRN, AP_WRAP> x_test['+str(OUTPUT_DATA_NUM)+']['+str(x_test.shape[1]*x_test.shape[2])+'] = {\n')
for i in range(OFFSET, OFFSET+OUTPUT_DATA_NUM):
    f.write("\t{")
    for j in range(x_test.shape[1]):
        for k in range(x_test.shape[2]):
            if (x_test[i][j][k] == 1.0):
                x_test[i][j][k] = x_test[i][j][k] * 256
                x_test[i][j][k] = (x_test[i][j][k]-1)/256
            f.write(str(x_test[i][j][k]))
            if (j==x_test.shape[1]-1 and k==x_test.shape[2]-1):
                if (i==OFFSET+OUTPUT_DATA_NUM-1):
                    f.write("}\n")
                else:
                    f.write("},\n")
            else:
                f.write(", ")
f.write("};\n")

f.write('int x_test_256['+str(OUTPUT_DATA_NUM)+']['+str(x_test.shape[1]*x_test.shape[2])+'] = {\n')
for i in range(OFFSET, OFFSET+OUTPUT_DATA_NUM):
    f.write("\t{")
    for j in range(x_test.shape[1]):
        for k in range(x_test.shape[2]):
            f.write(str(int(x_test[i][j][k]*256)))
            if (j==x_test.shape[1]-1 and k==x_test.shape[2]-1):
                if (i==OFFSET+OUTPUT_DATA_NUM-1):
                    f.write("}\n")
                else:
                    f.write("},\n")
            else:
                f.write(", ")
f.write("};\n")

f.write("\n")
f.write('int y_test['+str(OUTPUT_DATA_NUM)+'] = {\n')
for i in range(OFFSET, OFFSET+OUTPUT_DATA_NUM):
    f.write(str(y_test[i]))
    if (i==OFFSET+OUTPUT_DATA_NUM-1):
        f.write("};\n")
    else:
        f.write(", ")
        
f.close() 


このPython コードを実行すると mnist_data.h が生成される。
mnist_data.h の一部を示す。
tensorflow_keras_55_180604.png
tensorflow_keras_56_180604.png
tensorflow_keras_57_180604.png

出力されたMNIST のデータが正しいかどうか?を確かめてみた。
x_test256[300][784] のデータをLibreOffice Calc で 28 x 28 に並べみた。
tensorflow_keras_58_180605.png

少しデータが余ってしまったが、7 に見える。
y_test[300] を見ても、最初の数は 7 なので、mnist_data.h は正しいようだ。
  1. 2018年06月04日 05:26 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

ふすま張り替え、家の農作物

今日は午前中は筑波大学に行って、クロスカントリーコースと北ループを走ってきました。
約7kmでした。10km走りたかったんですが、疲れてきたので止めました。

午後からは親の家屋のふすまの張替えをやりました。
今は粘着シートのふすま紙があるんですね。。。これです。”リンテックコマース シールタイプの粘着ふすま紙 94cmX2m HF-K04
大きな模様の入っていないほうが合わせる手間がいらなくて便利ですね。。。
道具は、”シールタイプのふすま紙 道具6点セット DO-26”と”リンテックコマース ふすま用引き手取替え2点セット T-526”とふすまの穴を塞ぐのに”リンテックコマース ふすまの穴3点セット 20X20cm FF-301”を使いました。ふすまの穴はこのふすまの穴3点セットの紫色の紙をテープのりで貼って終わりにしました。どのみち、ふすま紙をべったり上から貼るのですし、液体のりだと乾くまで待つ必要がありますね。これでも十分でした。
張り方はこの辺りのを見てやりました。結構綺麗に貼れましたよ。
diary1806_1_180603.jpg
diary1806_2_180603.jpg

家の畑はおふくろが作物作っています。
じゃがいもの出来は良さそうです。火山灰地質なので、じゃがいもの出来が良いです。
diary1806_3_180603.jpg

diary1806_4_180603.jpg

これはトマトかな?

ブロッコリーと奥はまめかな?
diary1806_5_180603.jpg

ネギも食いきれないほど植わっています。。。

ブルーベリーも今年も豊作のようです。。。
diary1806_6_180603.jpg
  1. 2018年06月03日 16:51 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた11(全結合層の重みをC のヘッダに変換)

TensorFlow + Kerasを使ってみた10(バイアスをC のヘッダに変換)”の続き。

前回は、畳み込み層、全結合層1層目、全結合層2層目のバイアスをC のヘッダファイルに変換した。今回は全結合層1層目、2層目の重みをC のヘッダに変換しよう。

まずは、全結合層1層目、2層目の重みをC のヘッダに変換する fwrite_af_weight() を示す。

# 全結合層の重みをCヘッダファイルに書き出す
# 2018/05/31 by marsee

def fwrite_af_weight(weight, wfile_name, float_wt_name, fixed_wt_name, MAGNIFICATION):
    import datetime
    import numpy as np
    
    f = open(wfile_name, 'w')
    todaytime = datetime.datetime.today()
    f.write('// '+wfile_name+'\n')
    strdtime = todaytime.strftime("%Y/%m/%d %H:%M:%S")
    f.write('// {0} by marsee\n'.format(strdtime))
    f.write("\n")
    
    f.write('const float '+float_wt_name+'['+str(weight.shape[0])+']['+str(weight.shape[1])+'] = {\n')
    for i in range(weight.shape[0]):
        f.write("\t{")
        for j in range(weight.shape[1]):
            f.write(str(weight[i][j]))
            if (j==weight.shape[1]-1):
                if (i==weight.shape[0]-1):
                    f.write("}\n")
                else:
                    f.write("},\n")
            else:
                f.write(", ")
    f.write("};\n")

    f.write("\n")
    f.write('const ap_fixed<'+str(int(np.log2(MAGNIFICATION))+1)+', 1, AP_TRN_ZERO, AP_SAT> '+fixed_wt_name+'['+str(weight.shape[0])+']['+str(weight.shape[1])+'] = {\n')
    for i in range(weight.shape[0]):
        f.write("\t{")
        for j in range(weight.shape[1]):
            w_int = int(weight[i][j]*MAGNIFICATION+0.5)
            if (w_int > MAGNIFICATION-1):
                w_int = MAGNIFICATION-1
            elif (w_int < -MAGNIFICATION):
                w_int = -MAGNIFICATION
            f.write(str(float(w_int)/float(MAGNIFICATION)))
            if (j==weight.shape[1]-1):
                if(i==weight.shape[0]-1):
                    f.write("}\n")
                else:
                    f.write("},\n")
            else:
                f.write(", ")
    f.write("};\n")

    f.close()


全結合層1層目の重みを af1_weight10.h に出力する。
(2018/06/06 :修正 全結合層の1層目の重みの配列数は (1440, 100) だが、1440 の内訳は処理された画像の高さ (12)、画像の幅 (12) 、チャネル数 (10) の配列だった。想定してる配列の順番は、チャネル数 (10) 、画像の高さ (12)、画像の幅 (12) なので、重みの配列の順番を入れ替える必要がある)

fwrite_af_weight(dence_layer1_weight, 'af1_weight10.h', 'af1_fweight', 'af1_weight', MAGNIFICATION_AF)
MAGNIFICATION_AF = 2 ** (9-1)
print(dence_layer1_weight.shape)
dence_Layer1_w12_12_10_100 = np.reshape(dence_layer1_weight,(12,12,10,100))
dence_Layer1_w201 = dence_Layer1_w12_12_10_100.transpose(2,0,1,3)
dence_Layer1_w1440_100 = np.reshape(dence_Layer1_w201,(1440,100))
fwrite_af_weight(dence_Layer1_w1440_100, 'af1_weight10.h', 'af1_fweight', 'af1_weight', MAGNIFICATION_AF)


af1_weight10.h の一部を画像を貼っておく。とても大きいので、全部ブログに貼れないからだ。
tensorflow_keras_51_180601.png
tensorflow_keras_52_180601.png

全結合層2層目の重みを af2_weight10.h に出力する。

fwrite_af_weight(dence_layer2_weight, 'af2_weight10.h', 'af2_fweight', 'af2_weight', MAGNIFICATION_AF)


af2_weight10.h の一部を画像を貼っておく。
tensorflow_keras_53_180601.png
tensorflow_keras_54_180601.png
  1. 2018年06月02日 04:50 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0

TensorFlow + Kerasを使ってみた10(バイアスをC のヘッダに変換)

TensorFlow + Kerasを使ってみた9(畳み込み層の重みをC のヘッダに変換)”の続き。

前回は、畳み込み層の重みをC のヘッダに変換した。今回は、畳み込み層、全結合層1層目、全結合層2層目のバイアスをC のヘッダファイルに変換する。
なお、量子化の精度の評価はまだできていないので、以前に使用した量子化ビット幅を使ってやってみよう。

最初に、バイアスをC のヘッダファイルに変換する関数の fwrite_bias() を示す。

# 畳み込み層と全結合層のバイアスをCヘッダファイルに書き出す
# 2018/05/31 by marsee

def fwrite_bias(bias, wfile_name, float_b_name, fixed_wt_name, MAGNIFICATION):
    import datetime
    import numpy as np
    
    f = open(wfile_name, 'w')
    todaytime = datetime.datetime.today()
    f.write('// '+wfile_name+'\n')
    strdtime = todaytime.strftime("%Y/%m/%d %H:%M:%S")
    f.write('// {0} by marsee\n'.format(strdtime))
    f.write("\n")

    f.write('const float '+float_b_name+'['+str(bias.shape[0])+'] = {\n\t')
    for i in range(bias.shape[0]):
        f.write(str(bias[i]))
        if (i < bias.shape[0]-1):
            f.write(", ")
    f.write("\n};\n")

    f.write("\n")
    f.write('const ap_fixed<'+str(int(np.log2(MAGNIFICATION))+1)+', 1, AP_TRN_ZERO, AP_SAT> '+fixed_wt_name+'['+str(bias.shape[0])+'] = {\n\t')
    for i in range(bias.shape[0]):
        b_int = int(bias[i]*MAGNIFICATION+0.5)
        if (b_int > MAGNIFICATION-1):
            b_int = MAGNIFICATION-1
        elif (b_int < -MAGNIFICATION):
            b_int = -MAGNIFICATION
        f.write(str(float(b_int)/float(MAGNIFICATION)))
        if (i < bias.shape[0]-1):
            f.write(", ")
    f.write("\n};\n")

    f.close()


バイアスをC のヘッダファイルに出力する。

fwrite_bias(conv_layer_bias, 'conv1_bias10.h', 'conv1_fbias', 'conv1_bias', MAGNIFICATION_CONV)


MAGNIFICATION_AF = 2 ** (9-1)
fwrite_bias(dence_layer1_bias, 'af1_bias10.h', 'af1_fbias', 'af1_bias', MAGNIFICATION_AF)


fwrite_bias(dence_layer2_bias, 'af2_bias10.h', 'af2_fbias', 'af2_bias', MAGNIFICATION_AF)


畳み込み層のC ヘッダファイル conv1_bias10.h を示す。

// conv1_bias10.h
// 2018/05/30 05:00:50 by marsee

const float conv1_fbias[10] = {
 -0.007222185, 0.0038653917, -0.10034832, -0.102261335, -0.007837055, -0.0026648666, -0.15441592, -0.17244887, 0.0006733343, -0.17412803
};

const ap_fixed<9, 1, AP_TRN_ZERO, AP_SAT> conv1_bias[10] = {
 -0.00390625, 0.00390625, -0.09765625, -0.09765625, -0.00390625, 0.0, -0.15234375, -0.16796875, 0.0, -0.171875
};


全結合層1層目のC ヘッダファイル af1_bias10.h を示す。

// af1_bias10.h
// 2018/06/01 04:44:24 by marsee

const float af1_fbias[100] = {
 0.019238321, -0.01771137, -0.026059965, -0.010412146, 0.016551534, 0.07084589, -0.020174462, -0.03186624, 0.009918453, -0.0005349776, -0.03642758, 0.005985915, -0.02327196, -0.0062365746, -0.04722478, -0.015795827, 0.031737898, 0.033591818, 0.039311368, 0.062911175, -0.033230793, -0.015483118, 0.010640073, -0.008249342, 0.03172312, -0.057140794, -0.061525248, -0.0142213, 0.04127987, -0.020516558, 0.04062112, -0.00087091, -0.0095176855, 0.0044661723, -0.012458612, -0.0047280258, 0.035344347, 0.0032061578, 0.05681947, -0.0026758113, 0.02949447, -0.004827402, 0.03566772, 0.04697614, 0.04577419, -0.020583214, 0.013479586, -0.054213677, 0.066026285, -0.006469002, 0.015176552, 0.003240489, -0.033093527, -0.043891124, 0.016665407, -0.003594259, 0.030643634, 0.08290552, 0.0020669047, -0.015035913, 0.05790131, 0.053463947, 0.10505945, 0.0014302151, 0.022453506, 0.016916182, -0.034298472, -0.017455893, -0.03765105, -0.039369643, -0.0095089385, -0.04399201, -0.021653317, -0.043070063, 0.062387593, 0.02000768, 0.06076118, 0.008908279, -0.052377164, 0.036777783, -0.0069501484, -0.04945799, 0.066166185, -0.049473558, -0.0031864739, 0.06794129, 0.0066950982, -0.04975326, 0.030130928, 0.011892647, 0.029019792, 0.0011624178, -0.00398671, -0.0360224, 0.013510628, -0.014131005, -0.007958779, -0.0017996833, 0.026189724, 0.009352577
};

const ap_fixed<9, 1, AP_TRN_ZERO, AP_SAT> af1_bias[100] = {
 0.01953125, -0.015625, -0.0234375, -0.0078125, 0.015625, 0.0703125, -0.015625, -0.02734375, 0.01171875, 0.0, -0.03125, 0.0078125, -0.01953125, -0.00390625, -0.04296875, -0.01171875, 0.03125, 0.03515625, 0.0390625, 0.0625, -0.03125, -0.01171875, 0.01171875, -0.00390625, 0.03125, -0.0546875, -0.05859375, -0.01171875, 0.04296875, -0.015625, 0.0390625, 0.0, -0.00390625, 0.00390625, -0.0078125, 0.0, 0.03515625, 0.00390625, 0.05859375, 0.0, 0.03125, 0.0, 0.03515625, 0.046875, 0.046875, -0.015625, 0.01171875, -0.05078125, 0.06640625, -0.00390625, 0.015625, 0.00390625, -0.02734375, -0.0390625, 0.015625, 0.0, 0.03125, 0.08203125, 0.00390625, -0.01171875, 0.05859375, 0.0546875, 0.10546875, 0.0, 0.0234375, 0.015625, -0.03125, -0.01171875, -0.03515625, -0.03515625, -0.00390625, -0.0390625, -0.01953125, -0.0390625, 0.0625, 0.01953125, 0.0625, 0.0078125, -0.046875, 0.03515625, -0.00390625, -0.046875, 0.06640625, -0.046875, 0.0, 0.06640625, 0.0078125, -0.046875, 0.03125, 0.01171875, 0.02734375, 0.0, 0.0, -0.03125, 0.01171875, -0.01171875, -0.00390625, 0.0, 0.02734375, 0.0078125
};


全結合層2層目のC ヘッダファイル af2_bias10.h を示す。

// af2_bias10.h
// 2018/06/01 04:43:44 by marsee

const float af2_fbias[10] = {
 -0.055489913, 0.074969545, -0.014903568, 0.0025154892, -0.031464603, 0.041022513, -0.0558837, -0.027120732, -0.034348655, -0.001718868
};

const ap_fixed<9, 1, AP_TRN_ZERO, AP_SAT> af2_bias[10] = {
 -0.05078125, 0.07421875, -0.01171875, 0.00390625, -0.02734375, 0.04296875, -0.05078125, -0.0234375, -0.03125, 0.0
};

  1. 2018年06月01日 05:53 |
  2. TensorFlow, Keras
  3. | トラックバック:0
  4. | コメント:0