Skip to content

Commit

Permalink
Merge pull request #9 from dgburnette/prelu
Browse files Browse the repository at this point in the history
Prelu
  • Loading branch information
BLMartin99 authored Jun 29, 2023
2 parents 11dc2bb + be53c75 commit dc399e9
Show file tree
Hide file tree
Showing 13 changed files with 383 additions and 0 deletions.
6 changes: 6 additions & 0 deletions example-prjs/prelu/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
This is small conv2d 1 layer example. To run it:
1. Run the run_catapult.sh script.
2. Replace the prelu_test.cpp in the my-Catapult-test with the prelu_test.cpp a level up (if you would like the testbench to be self-checking).
3. Move tb_input_features.dat and tb_output_predictions.dat to my-Catapult-test/tb_data (if you want two pre-computed examples).

Note: You can create your own image matrix or filter and get the predictions by editing then running prelu.py.
43 changes: 43 additions & 0 deletions example-prjs/prelu/catapult.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

import hls4ml
# import pprint
import yaml
import numpy as np

print(hls4ml.__version__)

with open('config.yml', 'r') as ymlfile:
config = yaml.safe_load(ymlfile)

# try tweaking the reuse_factor on one layer to get different pipelining
# config['HLSConfig']['LayerName']['fc1']['ReuseFactor'] = 4

print('NETWORK')
print(config)

config['OutputDir'] = 'my-Catapult-test'
config['Backend'] = 'Catapult'
config['IOType'] = 'io_stream'

config['HLSConfig']['Model']['Strategy'] = 'Latency'
#config['HLSConfig']['Model']['Strategy'] = 'Resource'

# default threshold is infinity
config['HLSConfig']['Model']['BramFactor'] = np.inf
# set to zero to force all weights onto (external function) interface
config['HLSConfig']['Model']['BramFactor'] = 0

print('CURRENT CONFIGURATION')
print('Backend='+config['Backend'])
print('IOType='+config['IOType'])
print('BramFactor={bf}'.format(bf=config['HLSConfig']['Model']['BramFactor']))

# pprint.pprint(config)

#Convert it to a hls project
hls_model = hls4ml.converters.keras_to_hls(config)

hls_model.build(vsynth=False)

# URL for this info: https://fastmachinelearning.org/hls4ml/setup/QUICKSTART.html

15 changes: 15 additions & 0 deletions example-prjs/prelu/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Backend: Catapult
KerasJson: prelu.json
KerasH5: prelu_weights.h5
OutputDir: my-Catapult-test
ProjectName: prelu
XilinxPart: xcku115-flvb2104-2-i
Part: xcku115-flvb2104-2-i
ClockPeriod: 5

IOType : io_parallel
HLSConfig:
Model:
Precision: ap_fixed<16, 6>
ReuseFactor: 1
Strategy: Latency
Binary file added example-prjs/prelu/prelu.h5
Binary file not shown.
1 change: 1 addition & 0 deletions example-prjs/prelu/prelu.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"class_name": "Sequential", "config": {"name": "sequential", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": [null, 25], "dtype": "float32", "sparse": false, "ragged": false, "name": "input_1"}}, {"class_name": "PReLU", "config": {"name": "p_re_lu", "trainable": true, "dtype": "float32", "alpha_initializer": {"class_name": "Constant", "config": {"value": 0.25}}, "alpha_regularizer": null, "alpha_constraint": null, "shared_axes": null}}]}, "keras_version": "2.11.0", "backend": "tensorflow"}
51 changes: 51 additions & 0 deletions example-prjs/prelu/prelu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import tensorflow as tf
import numpy as np

# Create a relu 1layer that takes in a 25 element array
def create_model():
# Create a model
model = tf.keras.Sequential()
model.add(tf.keras.layers.InputLayer(input_shape=(25,)))
model.add(tf.keras.layers.PReLU(alpha_initializer=tf.initializers.constant(0.25)))

return model

# Save model to forms for hls4ml
def save_model(model, name=None):
# Save as model.h5, model_weights.h5, and model.json
if name is None:
name = model.name
model.save(name + '.h5')
model.save_weights(name + '_weights.h5')
with open(name + '.json', 'w') as outfile:
outfile.write(model.to_json())
return

if __name__ == '__main__':
model = create_model()
save_model(model, name='prelu')

# Image Matrix
image_mat = np.array([
[ 1, -2, 3, -4, 5, -5, 1, -2, 3, -4, 4, -5, 1, -2, 3, -3, 4, -5, 1, -2, 2, -3, 4, -5, 1 ]
])

# Get prediction
prediction = model.predict(image_mat)
print("Image Matrix\n")
print(image_mat)
print("Prediction\n")
print(prediction)

image_mat2 = np.array([
[ -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 ]
])

# Get prediction
prediction = model.predict(image_mat2)
print("Image Matrix\n")
print(image_mat2)
print("Prediction\n")
print(prediction)


137 changes: 137 additions & 0 deletions example-prjs/prelu/prelu_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
//
// rfnoc-hls-neuralnet: Vivado HLS code for neural-net building blocks
//
// Copyright (C) 2017 EJ Kreinar
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include <fstream>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#include "firmware/prelu.h"
#include "firmware/nnet_utils/nnet_helpers.h"
// #include "firmware/parameters.h"

#include <mc_scverify.h>

//hls-fpga-machine-learning insert bram
#include "firmware/weights/a2.h"

//hls-fpga-machine-learning insert declare weights
model_default_t a2[25];

namespace nnet {
bool trace_enabled = true;
std::map<std::string, void *> *trace_outputs = NULL;
size_t trace_type_size = sizeof(double);
}

CCS_MAIN(int argc, char *argv[])
{
//load input data from text file
std::ifstream fin("tb_data/tb_input_features.dat");
//load predictions from text file
std::ifstream fpr("tb_data/tb_output_predictions.dat");

#ifdef RTL_SIM
std::string RESULTS_LOG = "tb_data/rtl_cosim_results.log";
#else
std::string RESULTS_LOG = "tb_data/csim_results.log";
#endif
std::ofstream fout(RESULTS_LOG);

#ifndef __SYNTHESIS__
static bool loaded_weights = false;
if (!loaded_weights) {
//hls-fpga-machine-learning insert load weights
nnet::load_weights_from_txt<model_default_t, 25>(a2, "a2.txt");
loaded_weights = true;
}
#endif
std::string iline;
std::string pline;

if (fin.is_open() && fpr.is_open()) {
while ( std::getline(fin,iline) && std::getline (fpr,pline) ) {
char* cstr=const_cast<char*>(iline.c_str());
char* current;
std::vector<float> in;
current=strtok(cstr," ");
while(current!=NULL) {
in.push_back(atof(current));
current=strtok(NULL," ");
}
cstr=const_cast<char*>(pline.c_str());
std::vector<float> pr;
current=strtok(cstr," ");
while(current!=NULL) {
pr.push_back(atof(current));
current=strtok(NULL," ");
}
// std::cout << " Input feature map size = " << in.size() << " Output predictions size = " << pr.size() << std::endl;

//hls-fpga-machine-learning insert data
ac_channel<input_t> input_1/*("input_1")*/;
nnet::copy_data<float, input_t, 0, N_INPUT_1_1>(in, input_1);
ac_channel<result_t> layer2_out/*("layer2_out")*/;

//hls-fpga-machine-learning insert top-level-function
prelu(input_1,layer2_out,a2);

result_t tmp = layer2_out[0];
for(int i = 0; i < N_INPUT_1_1; i++)
{
if(pr[i] != tmp[i].to_double())
{
std::cout << "FAILURE" << std::endl;
std::cout << "Expected: " << pr[i] << " Actual: " << tmp[i].to_double() << std::endl;
return 1;
}
}

//hls-fpga-machine-learning insert tb-output
nnet::print_result<result_t, N_INPUT_1_1>(layer2_out, fout);
}
fin.close();
fpr.close();
} else {
std::cout << "INFO: Unable to open input/predictions file, using default input." << std::endl;

//hls-fpga-machine-learning insert zero
ac_channel<input_t> input_1/*("input_1")*/;
nnet::fill_zero<input_t, N_INPUT_1_1>(input_1);
ac_channel<result_t> layer2_out/*("layer2_out")*/;

//hls-fpga-machine-learning insert top-level-function
prelu(input_1,layer2_out,a2);

//hls-fpga-machine-learning insert output

//hls-fpga-machine-learning insert tb-output
nnet::print_result<result_t, N_INPUT_1_1>(layer2_out, fout);

}

fout.close();
std::cout << "INFO: Saved inference results to file: " << RESULTS_LOG << std::endl;

return 0;
}
Binary file added example-prjs/prelu/prelu_weights.h5
Binary file not shown.
44 changes: 44 additions & 0 deletions example-prjs/prelu/run_catapult.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#! /bin/bash

# This script runs the Catapult flows to generate the HLS.

VENV=/wv/scratch-baimar9c/venv

MGC_HOME=/wv/hlsb/CATAPULT/TOT/CURRENT/aol/Mgc_home
export MGC_HOME

export PATH=/wv/hlstools/python/python37/bin:$PATH:$XILINX_VIVADO/bin:$MGC_HOME/bin
export LD_LIBRARY_PATH=/wv/hlstools/python/python37/lib:$XILINX_VIVADO/lib/lnx64.o:$MGC_HOME/lib
export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python

# needed for pytest
export OSTYPE=linux-gnu

echo "Activating Virtual Environment..."
# bash
source $VENV/bin/activate

rm -rf ./my-Catapult-test*

# to run catapult+vivado_rtl
sed -e 's/Vivado/Catapult/g' vivado.py >catapult.py
# to only run catapult
# sed -e 's/Vivado/Catapult/g' vivado.py | sed -e 's/vsynth=True/vsynth=False/g' >catapult.py

# actually run HLS4ML + Catapult (+ optional vivado RTL)
python3 catapult.py

# run just the C++ execution
echo ""
echo "====================================================="
echo "====================================================="
echo "C++ EXECUTION"
pushd my-Catapult-test; rm -f a.out; $MGC_HOME/bin/g++ -std=c++17 -I. -DWEIGHTS_DIR=\"firmware/weights\" -Ifirmware -I$MGC_HOME/shared/include firmware/prelu.cpp prelu_test.cpp; a.out; popd

# Using VSCode setup generated by Catapult
echo ""
echo "====================================================="
echo "====================================================="
echo "To launch VSCode on the C++ generated by hls4ml:"
echo "setenv LD_LIBRARY_PATH $MGC_HOME/lib:$MGC_HOME/shared/lib"
echo "pushd my-Catapult-test; /wv/hlstools/vscode/LATEST/code Catapult.code-workspace"
39 changes: 39 additions & 0 deletions example-prjs/prelu/run_vivado.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#! /bin/bash

# This script runs the Vivado flows to generate the HLS.

VENV=$HOME/venv

MGC_HOME=/wv/hlsb/CATAPULT/TOT/CURRENT/aol/Mgc_home
export MGC_HOME

export PATH=/wv/hlstools/python/python37/bin:$PATH:$XILINX_VIVADO/bin:$MGC_HOME/bin
export LD_LIBRARY_PATH=/wv/hlstools/python/python37/lib:$XILINX_VIVADO/lib/lnx64.o:$MGC_HOME/lib
export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python

# needed for pytest
export OSTYPE=linux-gnu

echo "Activating Virtual Environment..."
# bash
source $VENV/bin/activate

rm -rf ./my-Vivado-test*

mkdir -p tb_data

# to run catapult+vivado_rtl
sed -e 's/Vivado/Catapult/g' vivado.py >catapult.py
# to only run catapult
# sed -e 's/Vivado/Catapult/g' vivado.py | sed -e 's/vsynth=True/vsynth=False/g' >catapult.py

# actually run HLS4ML + Vivado HLS
python3 vivado.py

# run just the C++ execution
echo ""
echo "====================================================="
echo "====================================================="
echo "C++ EXECUTION"
pushd my-Vivado-test; rm -f a.out; $MGC_HOME/bin/g++ -g -std=c++11 -I. -DWEIGHTS_DIR=\"firmware/weights\" -Ifirmware -Ifirmware/ap_types -I$MGC_HOME/shared/include firmware/prelu.cpp prelu_test.cpp; a.out; popd

2 changes: 2 additions & 0 deletions example-prjs/prelu/tb_input_features.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1 -2 3 -4 5 -5 1 -2 3 -4 4 -5 1 -2 3 -3 4 -5 1 -2 2 -3 4 -5 1
-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
2 changes: 2 additions & 0 deletions example-prjs/prelu/tb_output_predictions.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1 -0.5 3 -1 5 -1.25 1 -0.5 3 -1 4 -1.25 1 -0.5 3 -0.75 4 -1.25 1 -0.5 2 -0.75 4 -1.25 1
-0.25 2 -0.75 4 -1.25 -1.5 7 -2 9 -2.5 -2.75 12 -3.25 14 -3.75 -4 17 -4.5 19 -5 -5.25 22 -5.75 24 -6.25
43 changes: 43 additions & 0 deletions example-prjs/prelu/vivado.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

import hls4ml
# import pprint
import yaml
import numpy as np

print(hls4ml.__version__)

with open('config.yml', 'r') as ymlfile:
config = yaml.safe_load(ymlfile)

# try tweaking the reuse_factor on one layer to get different pipelining
# config['HLSConfig']['LayerName']['fc1']['ReuseFactor'] = 4

print('NETWORK')
print(config)

config['OutputDir'] = 'my-Vivado-test'
config['Backend'] = 'Vivado'
config['IOType'] = 'io_stream'

config['HLSConfig']['Model']['Strategy'] = 'Latency'
#config['HLSConfig']['Model']['Strategy'] = 'Resource'

# default threshold is infinity
config['HLSConfig']['Model']['BramFactor'] = np.inf
# set to zero to force all weights onto (external function) interface
config['HLSConfig']['Model']['BramFactor'] = 0

print('CURRENT CONFIGURATION')
print('Backend='+config['Backend'])
print('IOType='+config['IOType'])
print('BramFactor={bf}'.format(bf=config['HLSConfig']['Model']['BramFactor']))

# pprint.pprint(config)

#Convert it to a hls project
hls_model = hls4ml.converters.keras_to_hls(config)

hls_model.build(vsynth=False)

# URL for this info: https://fastmachinelearning.org/hls4ml/setup/QUICKSTART.html

0 comments on commit dc399e9

Please sign in to comment.