FC2カウンター FPGAの部屋 「ゼロから作るDeep Learning」の畳み込みニューラルネットワークのハードウェア化4(Vivado HLS1)

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

FPGAの部屋

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

「ゼロから作るDeep Learning」の畳み込みニューラルネットワークのハードウェア化4(Vivado HLS1)

「ゼロから作るDeep Learning」の畳み込みニューラルネットワークのハードウェア化3”の続き。

前回は、重みやバイアスのパラメータをC の配列に出力した。今回は、畳み込みニューラルネットワークのC ソースコードを作成してVivado HLSでハードウェア化してみよう。

layer_int.py の量子化の倍率を示す。

AF_OUT_MAG = 2 ** 5 # 出力の小数部
AF_OUT_INT = 2 ** 6 # 出力の整数部(+符号1ビット)
AF_WB_MAG = 2 ** 8 # 重みとバイアスの小数部
AF_WB_INT = 2 ** 1 # 重みとバイアスの整数部(+符号1ビット)

COV_OUT_MAG = 2 ** 7 # 出力の小数部
COV_OUT_INT = 2 ** 2 # 出力の整数部(+符号1ビット)
COV_WB_MAG = 2 ** 8 # 重みとバイアスの小数部
COV_WB_INT = 2 ** 1 # 重みとバイアスの整数部(+符号1ビット)


これは、例えば全結合層の出力値の量子化の整数部は AF_OUT_INT = 2 ** 6 なので、1 ビットなのだが、正の場合と負の場合があるので、+1とする。そして小数部は 5 ビットなので、Vivado HLSの任意精度固定小数点デー タ型で表すと ap_fixed<12, 7, AP_TRN_ZERO, AP_SAT> になる。それよりもリソース使用量の関係でビット幅を縮小しているのもあるが、基本的にはそんなものだ。

さて、畳み込みニューラルネットワークのC ソースコードを下に示す。

// mnist_conv_nn.cpp
// 2017/06/12 by marsee
// 畳み込み層のカーネル数 30
//

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

int mnist_conv_nn(ap_ufixed<8, 0, AP_TRN_ZERO, AP_SAT> in[784], ap_fixed<12, 7, AP_TRN_ZERO, AP_SAT> out[10]){
    ap_ufixed<8, 0, AP_TRN_ZERO, AP_SAT> buf[28][28];
    ap_fixed<10, 3, AP_TRN_ZERO, AP_SAT> conv_out[10][24][24];
    ap_fixed<10, 3, AP_TRN_ZERO, AP_SAT> pool_out[10][12][12];
    ap_fixed<12, 7, AP_TRN_ZERO, AP_SAT> dot1[100];
    ap_fixed<12, 7, AP_TRN_ZERO, AP_SAT> dot2[10];

    buf_copy1: for(int i=0; i<28; i++)
        buf_copy2: for(int j=0; j<28; j++)
            buf[i][j] = in[i*28+j];

    // Convolutional Neural Network 5x5 kernel, Stride = 1, Padding = 0
    // + ReLU
    CONV1: for(int i=0; i<30; 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_weight[i][0][m][n];
                    }
                }
                conv_out[i][j][k] += conv1_bias[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<30; 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<30; 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_weight[i*12*12+j*12+k][col];
                }
            }
        }
        dot1[col] += af1_bias[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_weight[row][col];
        }
        dot2[col] += af2_bias[col];

        out[col] = dot2[col];
    }

    return(0);
}


C ソースコードとしてはこのくらいだ。そして畳み込みとプーリングは5 重のループになった。なお、Softmax は未実装となっている。Zynq ならばソフトウェアで実装しても良いと思っている。
Vivado HLS 2017.1 で、PYNQボード用のプロジェクト mnist_conv_nn を作成した。下の図はC コードの合成の途中だ。
nn_fpga_ch7_12_170618.png

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

レイテンシは、約 82.0 ms かかっている。30 fps の1フレームは33.3 ms なので、時間がかかりすぎる。
しかもBRAM_18Kが 106 % でリソースが足りなくなっている。
これでは問題なので、もう少しリソースを削減してみよう。
やはり元を少なくする必要があるということで、畳み込みニューラルネットワークの畳み込み層のカーネルが今は30個なのだが、10個程度に減らしてみようと思う。そうすれば全結合層1層目の入力数も減るので、リソースの削減ができるはずだ。
畳み込みニューラルネットワークの畳み込み層のカーネルを10個に減らして学習を行い、テストデータの精度を見てみよう。
  1. 2017年06月18日 05:35 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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