// relu.h
// 2018/02/20 by marsee
//
#ifndef __RELU_H__
#define __RELU_H__
#include <ap_fixed.h>
template<int W, int I, int U, int TI, int TD>
struct ap_fixed2_axis{
struct data {
ap_fixed<W,I,AP_TRN,AP_WRAP> data0;
ap_fixed<W,I,AP_TRN,AP_WRAP> data1;
} data;
ap_uint<(W+7)/8> keep;
ap_uint<(W+7)/8> strb;
ap_uint<U> user;
ap_uint<1> last;
ap_uint<TI> id;
ap_uint<TD> dest;
};
template<int U, int TI, int TD>
struct float2_axis{
struct data {
float data0;
float data1;
} data;
ap_uint<1> keep;
ap_uint<1> strb;
ap_uint<U> user;
ap_uint<1> last;
ap_uint<TI> id;
ap_uint<TD> dest;
};
#define HORIZONTAL_PIXEL_WIDTH 52
#define VERTICAL_PIXEL_WIDTH 6
#define ARRAY_SIZE 2
#define NUMBER_OF_KERNEL 2
typedef ap_fixed<16, 6, AP_TRN, AP_WRAP> conv_type;
#endif
// relu.cpp
// 2018/02/20 by marsee
// 2018/02/23 : 0 を conv_type(0.0) に変更
//
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include "relu.h"
int relu(hls::stream<ap_fixed2_axis<16,6,1,1,1> >& ins,
hls::stream<ap_fixed2_axis<16,6,1,1,1> >& outs){
#pragma HLS INTERFACE axis port=ins
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE s_axilite port=return
ap_fixed2_axis<16,6,1,1,1> pix;
do {
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
// user が 1になった時にフレームがスタートする
ins >> pix;
} while(pix.user == 0);
Loop1: for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
Loop2: for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE II=1
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
if (pix.data.data0 < conv_type(0.0)) // データが 0 以下だったら 0 にする
pix.data.data0 = conv_type(0.0);
if (pix.data.data1 < conv_type(0.0)) // データが 0 以下だったら 0 にする
pix.data.data1 = conv_type(0.0);
outs << pix;
}
}
return(0);
}
// relu_tb.cpp
// 2018/02/20 by marsee
//
#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 "relu.h"
#include "conv_layer_output.h"
int relu(hls::stream<ap_fixed2_axis<16,6,1,1,1> >& ins,
hls::stream<ap_fixed2_axis<16,6,1,1,1> >& outs);
int relu_soft(hls::stream<float2_axis<1,1,1> >& ins,
hls::stream<float2_axis<1,1,1> >& outs);
int main(){
using namespace std;
hls::stream<ap_fixed2_axis<16,6,1,1,1> > ins;
hls::stream<float2_axis<1,1,1> > ins_soft;
hls::stream<ap_fixed2_axis<16,6,1,1,1> > outs;
hls::stream<float2_axis<1,1,1> > outs_soft;
float relu_fout[312][2];
conv_type relu_out[312][2];
ap_fixed2_axis<16,6,1,1,1> pix;
float2_axis<1,1,1> fpix;
// ins に入力データを用意する
for(int i=0; i<5; i++){ // dummy data
pix.user = 0;
pix.data.data0 = (conv_type)i;
pix.data.data1 = (conv_type)i;
ins << pix;
fpix.user = 0;
fpix.data.data0 = (float)i;
fpix.data.data1 = (float)i;
ins_soft << fpix;
}
// 1 画面分のデータを ins、ins_soft に入力する
for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
for(int i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
pix.data.data0 = conv_layer_out[j*HORIZONTAL_PIXEL_WIDTH+i][0];
pix.data.data1 = conv_layer_out[j*HORIZONTAL_PIXEL_WIDTH+i][1];
fpix.data.data0 = conv_layer_fout[j*HORIZONTAL_PIXEL_WIDTH+i][0];
fpix.data.data1 = conv_layer_fout[j*HORIZONTAL_PIXEL_WIDTH+i][1];
if (j==0 && i==0){ // 最初のデータの時に TUSER を 1 にする
pix.user = 1;
fpix.user = 1;
} else {
pix.user = 0;
fpix.user = 0;
}
if (i == HORIZONTAL_PIXEL_WIDTH-1){ // 行の最後でTLASTをアサートする
pix.last = 1;
fpix.last = 1;
} else {
pix.last = 0;
fpix.last = 0;
}
ins << pix;
ins_soft << fpix;
}
}
relu(ins, outs);
relu_soft(ins_soft, outs_soft);
// outs, outs_soft を relu_out[][], relu_fout[][] に出力する
for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
for(int i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
outs >> pix;
outs_soft >> fpix;
relu_out[j*HORIZONTAL_PIXEL_WIDTH+i][0] = pix.data.data0;
relu_out[j*HORIZONTAL_PIXEL_WIDTH+i][1] = pix.data.data1;
relu_fout[j*HORIZONTAL_PIXEL_WIDTH+i][0] = fpix.data.data0;
relu_fout[j*HORIZONTAL_PIXEL_WIDTH+i][1] = fpix.data.data1;
if ((double)pow((double)pix.data.data0-(double)fpix.data.data0,(double)2) > 4 ||
(double)pow((double)pix.data.data1-(double)fpix.data.data1,(double)2) > 4){ // 2乗誤差が4よりも大きい
printf("ERROR HW and SW results mismatch i = %ld, j = %ld, HW = %f, %f, SW = %f, %f\n", i, j, (float)pix.data.data0, (float)pix.data.data1, fpix.data.data0, fpix.data.data1);
return(1);
}
}
}
cout << "Success HW and SW results match" << endl;
cout << endl;
// ReLU の結果をヘッダファイルに出力
ofstream OH("relu_output.h");
OH << "// relu_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 __RELU_OUTPUT_H__" << endl;
OH << "#define __RELU_OUTPUT_H__" << endl;
OH << endl;
OH << "const float relu_fout[" << VERTICAL_PIXEL_WIDTH*HORIZONTAL_PIXEL_WIDTH << "][" << NUMBER_OF_KERNEL << "] = {" << endl;
for (int y=0; y<VERTICAL_PIXEL_WIDTH ; y++){
for (int x=0; x<HORIZONTAL_PIXEL_WIDTH ; x++){
OH << " {" << fixed << setprecision(12) << relu_fout[HORIZONTAL_PIXEL_WIDTH*y+x][0] << ", "
<< relu_fout[HORIZONTAL_PIXEL_WIDTH*y+x][1] << "}";
if (y==VERTICAL_PIXEL_WIDTH-1 && x==HORIZONTAL_PIXEL_WIDTH-1)
OH << endl;
else
OH << "," << endl;
}
}
OH << "};" << endl << endl;
OH << "const ap_fixed<16, 6, AP_TRN, AP_WRAP> relu_out[" << VERTICAL_PIXEL_WIDTH*HORIZONTAL_PIXEL_WIDTH << "][" << NUMBER_OF_KERNEL << "] = {" << endl;
for (int y=0; y<VERTICAL_PIXEL_WIDTH ; y++){
for (int x=0; x<HORIZONTAL_PIXEL_WIDTH ; x++){
OH << " {" << fixed << setprecision(12) << (float)relu_out[HORIZONTAL_PIXEL_WIDTH*y+x][0] << ", "
<< (float)relu_out[HORIZONTAL_PIXEL_WIDTH*y+x][1] << "}";
if (y==VERTICAL_PIXEL_WIDTH -1 && x==HORIZONTAL_PIXEL_WIDTH -1)
OH << endl;
else
OH << "," << endl;
}
}
OH << "};" << endl << endl;
OH << "#endif" << endl;
return(0);
}
int relu_soft(hls::stream<float2_axis<1,1,1> >& ins,
hls::stream<float2_axis<1,1,1> >& outs){
float2_axis<1,1,1> fpix;
do {
// user が 1になった時にフレームがスタートする
ins >> fpix;
} while(fpix.user == 0);
Loop1: for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
Loop2: for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> fpix; // AXI4-Stream からの入力
if (fpix.data.data0 < 0.0) // データが 0 以下だったら 0 にする
fpix.data.data0 = 0.0;
if (fpix.data.data1 < 0.0) // データが 0 以下だったら 0 にする
fpix.data.data1 = 0.0;
outs << fpix;
}
}
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 |
31 | - | - | - | - | - | - |