// affine_layer1.h
// 2018/04/27 by marsee (HLS stream)
//
#ifndef __AFFINE_LAYER1_H__
#define __AFFINE_LAYER1_H__
#include <ap_fixed.h>#include "af1_weight.h"#include "af1_bias.h"static const size_t V_PRE_LAYER_HIGHT = 3;
static const size_t H_PRE_LAYER_WIDTH = 26;
static const size_t NUMBER_OF_MIDDLE_LAYER = 100;
static const size_t NUMBER_OF_KERNEL = 2;
static const size_t ARRAY_SIZE = 5;
static const size_t CW = 16;
static const size_t CI = 6;
static const size_t NW = 19;
static const size_t NI = 7;
typedef struct {
ap_fixed<NW,NI,AP_TRN,AP_WRAP> data [NUMBER_OF_MIDDLE_LAYER];
} mdata_type;
typedef struct {
float data [NUMBER_OF_MIDDLE_LAYER];
} fmdata_type;
typedef ap_fixed<NW,NI,AP_TRN,AP_WRAP> affine_type;
typedef ap_fixed<CW,CI,AP_TRN,AP_WRAP> conv_type;
#endif
// affine_layer1.cpp
// 2018/04/27 by marsee (HLS stream)
//
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>
#include "layer_general.h"
#include "affine_layer1.h"
int affine_layer1(hls::stream<ap_fixed_axis<CW,CI,NUMBER_OF_KERNEL,1> >& ins,
hls::stream<ap_fixed_axis<NW,NI,1,1> >& outs){
//#pragma HLS ARRAY_PARTITION variable=af1_weight complete dim=1
#pragma HLS DATA_PACK variable=outs
#pragma HLS DATA_PACK variable=ins
ap_fixed_axis<CW,CI,NUMBER_OF_KERNEL,1> stdata;
affine_type dot[NUMBER_OF_MIDDLE_LAYER];
//#pragma HLS ARRAY_PARTITION variable=dot complete dim=1
ap_fixed_axis<NW,NI,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++){
//#pragma HLS PIPELINE II=1
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> stdata; // AXI4-Stream からの入力
Loop4: for (int col=0; col<NUMBER_OF_MIDDLE_LAYER; col++){
#pragma HLS PIPELINE II=1
if (x==0 && y==0) // 最初は 0 にクリアする
dot[col] = 0;
affine_type dot_temp = (affine_type)0;
for (int i=0; i<NUMBER_OF_KERNEL; i++){
dot_temp += stdata.data[i] * af1_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] += af1_bias[col];
outd.data[0] = dot[col];
if(col == 0)
outd.user = 1;
else
outd.user = 0;
if(col == NUMBER_OF_MIDDLE_LAYER-1)
outd.last = 1;
else
outd.last = 0;
outs << outd;
}
}
}
}
return(0);
}
// affine_layer1_tb.cpp
// 2018/04/27 by marsee (HLS stream)
//
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <math.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>
#include "layer_general.h"
#include "affine_layer1.h"
#include "max_pooling_output.h"
int affine_layer1(hls::stream<ap_fixed_axis<CW,CI,NUMBER_OF_KERNEL,1> >& ins,
hls::stream<ap_fixed_axis<NW,NI,1,1> >& outs);
int affine_layer1_2(hls::stream<ap_fixed_axis<CW,CI,NUMBER_OF_KERNEL,1> >& ins,
hls::stream<ap_fixed_axis<NW,NI,1,1> >& outs);
int affine_layer1_soft(hls::stream<float_axis<NUMBER_OF_KERNEL,1> >& ins,
hls::stream<float_axis<1,1> >& outs);
int main(){
using namespace std;
hls::stream<ap_fixed_axis<CW,CI,NUMBER_OF_KERNEL,1> > ins;
hls::stream<ap_fixed_axis<CW,CI,NUMBER_OF_KERNEL,1> > ins2;
hls::stream<ap_fixed_axis<NW,NI,1,1> > outs;
hls::stream<ap_fixed_axis<NW,NI,1,1> > outs2;
hls::stream<float_axis<NUMBER_OF_KERNEL,1> > ins_soft;
hls::stream<float_axis<1,1> > outs_soft;
mdata_type dot;
mdata_type dot2;
fmdata_type fdot;
ap_fixed_axis<CW,CI,NUMBER_OF_KERNEL,1> pix;
ap_fixed_axis<CW,CI,NUMBER_OF_KERNEL,1> pix2;
float_axis<NUMBER_OF_KERNEL,1> fpix;
ap_fixed_axis<NW,NI,1,1> pdata;
ap_fixed_axis<NW,NI,1,1> pdata2;
float_axis<1,1> fpdata;
// ins に入力データを用意する
for(int i=0; i<5; i++){ // dummy data
pix.user = 0;
for(int k=0; k<NUMBER_OF_KERNEL; k++){
pix.data[k] = (affine_type)i;
}
ins << pix;
ins2 << pix;
fpix.user = 0;
for(int k=0; k<NUMBER_OF_KERNEL; k++){
fpix.data[k] = (float)i;
}
ins_soft << fpix;
}
// 1 画面分のデータを ins、ins_soft に入力する
for(int j=0; j < V_PRE_LAYER_HIGHT; j++){
for(int i=0; i < H_PRE_LAYER_WIDTH; i++){
for(int k=0; k<NUMBER_OF_KERNEL; k++){
pix.data[k] = mp_out[j*H_PRE_LAYER_WIDTH+i][k];
fpix.data[k] = mp_fout[j*H_PRE_LAYER_WIDTH+i][k];
}
if (j==0 && i==0){ // 最初のデータの時に TUSER を 1 にする
pix.user = 1;
fpix.user = 1;
} else {
pix.user = 0;
fpix.user = 0;
}
if (i == H_PRE_LAYER_WIDTH-1){ // 行の最後でTLASTをアサートする
pix.last = 1;
fpix.last = 1;
} else {
pix.last = 0;
fpix.last = 0;
}
ins << pix;
ins2 << pix;
ins_soft << fpix;
}
}
affine_layer1(ins, outs);
affine_layer1_2(ins2, outs2);
affine_layer1_soft(ins_soft, outs_soft);
// outs, outs2 を dot[] と dot2[] に代入して比較する
int errcnt = 0;
for(int i=0; i<NUMBER_OF_MIDDLE_LAYER; i++){
outs >> pdata;
outs2 >> pdata2;
outs_soft >> fpdata;
dot.data[i] = pdata.data[0];
dot2.data[i] = pdata2.data[0];
fdot.data[i] = fpdata.data[0];
printf("i = %d, HW = %f, HW2 = %f, SW = %f\n", i, (float)dot.data[i], (float)dot2.data[i], fdot.data[i]);
if(dot.data[i] != dot2.data[i]){ // 2つの実装の値が合わない
printf("ERROR HW and SW results mismatch i = %d, HW = %f, HW2 = %f, SW = %f\n", i, (float)dot.data[i], (float)dot2.data[i], fdot.data[i]);
errcnt++;
//return(1);
}
}
cout << "Error Count = " << errcnt << endl;
cout << endl;
// max_pooling の結果をヘッダファイルに出力
ofstream OH("affine_layer1_output.h");
OH << "// affine_layer1_output.h" << endl;
time_t now = time(0);
struct tm* localNow = localtime(&now);
OH << "// " << localNow->tm_year+1900 << "/" << localNow->tm_mon+1 << "/" << localNow->tm_mday;
OH << " " << setw(2) << setfill('0') << localNow->tm_hour << ":" << localNow->tm_min << ":" << localNow->tm_sec << " by marsee" << endl;
OH << "//" << endl;
OH << endl;
OH << "#ifndef __AFFINE_LAYER1_OUTPUT_H__" << endl;
OH << "#define __AFFINE_LAYER1_OUTPUT_H__" << endl;
OH << endl;
OH << "const float affine1_fout[" << NUMBER_OF_MIDDLE_LAYER << "] = {" << endl;
for (int i=0; i<NUMBER_OF_MIDDLE_LAYER ; i++){
OH << " " << fixed << setprecision(14) << fdot.data[i];
if (i == NUMBER_OF_MIDDLE_LAYER-1)
OH << endl;
else
OH << "," << endl;
}
OH << "};" << endl << endl;
OH << "const ap_fixed<19,7,AP_TRN,AP_WRAP> affine1_out[" << NUMBER_OF_MIDDLE_LAYER << "] = {" << endl;
for (int i=0; i<NUMBER_OF_MIDDLE_LAYER ; i++){
OH << " " << fixed << setprecision(14) << (float)dot.data[i];
if (i == NUMBER_OF_MIDDLE_LAYER-1)
OH << endl;
else
OH << "," << endl;
}
OH << "};" << endl << endl;
OH << "#endif" << endl;
return(0);
}
int affine_layer1_soft(hls::stream<float_axis<NUMBER_OF_KERNEL,1> >& ins,
hls::stream<float_axis<1,1> >& outs){
float_axis<NUMBER_OF_KERNEL,1> stdata;
float dot[100];
float_axis<1,1> outd;
Loop1: do {
// 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++){
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> stdata; // AXI4-Stream からの入力
Loop4: for (int col=0; col<100; col++){
if (x==0 && y==0) // 最初は 0 にクリアする
dot[col] = 0;
for (int i=0; i<NUMBER_OF_KERNEL; i++){
dot[col] += stdata.data[i] * af1_fweight[V_PRE_LAYER_HIGHT*H_PRE_LAYER_WIDTH*i+y*H_PRE_LAYER_WIDTH+x][col];
}
if (y==V_PRE_LAYER_HIGHT-1 && x==H_PRE_LAYER_WIDTH-1){ // 最後はバイアスを加算する
dot[col] += af1_fbias[col];
outd.data[0] = dot[col];
if(col == 0)
outd.user = 1;
else
outd.user = 0;
if(col == NUMBER_OF_MIDDLE_LAYER-1)
outd.last = 1;
else
outd.last = 0;
outs << outd;
}
}
}
}
return(0);
}
// 検証用 affine_layer1_2()
// 検証用に affine_layer1() とは異なる実装でコーディング
int affine_layer1_2(hls::stream<ap_fixed_axis<CW,CI,NUMBER_OF_KERNEL,1> >& ins,
hls::stream<ap_fixed_axis<NW,NI,1,1> >& outs){
ap_fixed_axis<CW,CI,NUMBER_OF_KERNEL,1> stdata;
conv_type aff_in[NUMBER_OF_KERNEL][V_PRE_LAYER_HIGHT][H_PRE_LAYER_WIDTH];
affine_type dot1[NUMBER_OF_MIDDLE_LAYER];
ap_fixed_axis<NW,NI,1,1> outd;
do {
// user が 1になった時にフレームがスタートする
ins >> stdata;
} while(stdata.user == 0);
for (int y=0; y<V_PRE_LAYER_HIGHT; y++){
for (int x=0; x<H_PRE_LAYER_WIDTH; x++){
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> stdata; // AXI4-Stream からの入力
for (int i=0; i<NUMBER_OF_KERNEL; i++){
aff_in[i][y][x] = stdata.data[i];
}
}
}
for(int col=0; col<NUMBER_OF_MIDDLE_LAYER; col++){
dot1[col] = 0;
for(int i=0; i<NUMBER_OF_KERNEL; i++){
for(int j=0; j<V_PRE_LAYER_HIGHT; j++){
for(int k=0; k<H_PRE_LAYER_WIDTH; k++){
dot1[col] += aff_in[i][j][k]*af1_weight[i*V_PRE_LAYER_HIGHT*H_PRE_LAYER_WIDTH+j*H_PRE_LAYER_WIDTH+k][col];
}
}
}
dot1[col] += af1_bias[col];
outd.data[0] = dot1[col];
if(col == 0)
outd.user = 1;
else
outd.user = 0;
if(col == NUMBER_OF_MIDDLE_LAYER-1)
outd.last = 1;
else
outd.last = 0;
outs << outd;
}
return(0);
}
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | - | - | - | - | - |