FC2カウンター FPGAの部屋 DMA付きテンプレートを使用したMNISTのCNN3(C シミュレーション2)
FC2ブログ

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

FPGAの部屋

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

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

コメント

コメントの投稿


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

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