FC2カウンター FPGAの部屋 全結合層のテンプレートの変更

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

FPGAの部屋

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

全結合層のテンプレートの変更

この前から畳み込みニューラルネットワーク(CNN)の層のテンプレートを作ってきた。今回、MNISTのCNN を層のテンプレートで実装したのだが、BRAMのリソース使用量をオーバーしてしまったので、BRAMを多量に使用している第1層目のチューニングを変更する必要が出てきた。そのため、全結合層のテンプレートを変更することにした。

変更点は、出力の演算をする for ループのPIPELINE指示子のII を指定できるようにしたことだ。具体的には

const size_t OUTPUT_PIPELINE_II

をテンプレートの変数に追加して、出力の演算をする for ループのPIPELINE指示子のII を指定できるようにした。

新しい affine_layers_template.h を貼っておく。

// affine_layer_template.h
// 2018/05/02 by marsee
// テンプレートを使用して汎用化した affine_layer
// #define LOOP3_PIPELINE_ENABLE を書くとLoop3にPIPELINE指示子が入る
// 2018/05/19:テンプレートにOUTPUT_PIPELINE_IIを追加
//

#ifndef __AFFINE_LAYER_TEMPLATE_H__
#define __AFFINE_LAYER_TEMPLATE_H__

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

#include "layer_general.h"

#define TO_LITERAL(x) #x
#define PRAGMA_HLS(tok) _Pragma(TO_LITERAL(HLS tok)) // @hiyuhさんから

template<
    const size_t IN_W,     // 入力のビット幅
    const size_t IN_I,     // 入力の小数点位置
    const size_t OUT_W, // 出力のビット長
    const size_t OUT_I, // 出力の小数点位置
    const size_t WB_W,     // 重みとバイアスのビット長
    const size_t WB_I,     // 重みとバイアスの小数点位置
    const size_t V_PRE_LAYER_HIGHT,
    const size_t H_PRE_LAYER_WIDTH,
    const size_t NUMBER_OF_CHANNELS,
    const size_t NUMBER_OF_OUTPUT,
    const size_t HORIZ_PIPELINE_II,
    const size_t OUTPUT_PIPELINE_II
>int affine_layer_template(hls::stream<ap_fixed_axis<IN_W,IN_I,NUMBER_OF_CHANNELS,1> >& ins,
        hls::stream<ap_fixed_axis<OUT_W,OUT_I,1,1> >& outs,
        const ap_fixed<WB_W,WB_I,AP_TRN,AP_WRAP> af_weight[V_PRE_LAYER_HIGHT*H_PRE_LAYER_WIDTH*NUMBER_OF_CHANNELS][NUMBER_OF_OUTPUT],
        const ap_fixed<WB_W,WB_I,AP_TRN,AP_WRAP> af_bias[NUMBER_OF_OUTPUT]
){
//#pragma HLS ARRAY_PARTITION variable=af_weight complete dim=1

    ap_fixed_axis<IN_W,IN_I,NUMBER_OF_CHANNELS,1> stdata;
    ap_fixed<OUT_W,OUT_I,AP_TRN,AP_WRAP> dot[NUMBER_OF_OUTPUT];
//#pragma HLS ARRAY_PARTITION variable=dot complete dim=1
    ap_fixed_axis<OUT_W,OUT_I,1,1> outd;

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

    Loop2: for (int y=0; y<V_PRE_LAYER_HIGHT; y++){
        Loop3: for (int x=0; x<H_PRE_LAYER_WIDTH; x++){
#ifdef LOOP3_PIPELINE_ENABLE
    PRAGMA_HLS(pipeline II=HORIZ_PIPELINE_II)
#endif
            if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> stdata;    // AXI4-Stream からの入力

            Loop4: for (int col=0; col<NUMBER_OF_OUTPUT; col++){
PRAGMA_HLS(pipeline II=OUTPUT_PIPELINE_II)
                if (x==0 && y==0// 最初は 0 にクリアする
                    dot[col] = 0;

                ap_fixed<OUT_W,OUT_I,AP_TRN,AP_WRAP> dot_temp = ap_fixed<OUT_W,OUT_I,AP_TRN,AP_WRAP>(0);
                for (int i=0; i<NUMBER_OF_CHANNELS; i++){
                    dot_temp += stdata.data[i] * af_weight[V_PRE_LAYER_HIGHT*H_PRE_LAYER_WIDTH*i+y*H_PRE_LAYER_WIDTH+x][col];
                }
                dot[col] += dot_temp;

                if (y==V_PRE_LAYER_HIGHT-1 && x==H_PRE_LAYER_WIDTH-1){ // 最後はバイアスを加算する
                    dot[col] += af_bias[col];

                    outd.data[0] = dot[col];

                    if(col == 0)
                        outd.user = 1;
                    else
                        outd.user = 0;

                    if(col == NUMBER_OF_OUTPUT-1)
                        outd.last = 1;
                    else
                        outd.last = 0;

                    outs << outd;
                }
            }
        }
    }

    return(0);
}

#endif


MNIST 用の新しい affine_layer1.cpp を貼っておく。

// affine_layer1.cpp
// 2018/05/02 by marsee
// affine layer1 by template
// 2018/05/19:テンプレートにOUTPUT_PIPELINE_IIを追加
//

#include "affine_layer_template.h"
#include "af1_weight.h"
#include "af1_bias.h"

int affine_layer1(hls::stream<ap_fixed_axis<10,3,10,1> >& ins,
        hls::stream<ap_fixed_axis<13,7,1,1> >& outs){
//#pragma HLS DATA_PACK variable=outs
//#pragma HLS DATA_PACK variable=ins
    return(affine_layer_template<10,3,13,7,9,1,12,12,10,100,0,1>(ins, outs, af1_weight, af1_bias));
}


新しい affine_layer2.cpp を貼っておく。

// affine_layer2.cpp
// 2018/05/03 by marsee
// affine layer2 by template
// 2018/05/19:テンプレートにOUTPUT_PIPELINE_IIを追加
//

#define LOOP3_PIPELINE_ENABLE

#include "affine_layer_template.h"
#include "af2_weight.h"
#include "af2_bias.h"

int affine_layer2(hls::stream<ap_fixed_axis<13,7,1,1> >& ins,
        hls::stream<ap_fixed_axis<12,7,1,1> >& outs){
//#pragma HLS DATA_PACK variable=outs
//#pragma HLS DATA_PACK variable=ins
    return(affine_layer_template<13,7,12,7,9,1,1,100,1,10,3,1>(ins, outs, af2_weight, af2_bias));
}

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

コメント

コメントの投稿


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

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