Skip to content

fix conv1d io_parallel resource #403

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 11 additions & 12 deletions hls4ml/templates/vivado/nnet_utils/nnet_conv1d_resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ void conv_1d_full(
data_T data_conv[CONFIG_T::filt_width * CONFIG_T::n_chan * CONFIG_T::out_width];
data_T data_col[CONFIG_T::filt_width * CONFIG_T::n_chan];
res_T res_col[CONFIG_T::n_filt];

//#pragma HLS ARRAY_PARTITION variable=data_conv complete
#pragma HLS ARRAY_PARTITION variable=data_col complete
#pragma HLS ARRAY_PARTITION variable=res_col complete
Expand Down Expand Up @@ -142,17 +142,17 @@ void conv_1d_resource_cf(
template<class data_T, typename CONFIG_T>
void im2col_1d_cl(data_T data[CONFIG_T::in_width * CONFIG_T::n_chan], data_T data_col[CONFIG_T::filt_width * CONFIG_T::n_chan], const int col) {
int index = 0;
ChannelLoop:
for (int channel = CONFIG_T::n_chan; channel--; data++) {
#pragma HLS UNROLL
KernelLoop:
for (int kernel_col = 0; kernel_col < CONFIG_T::filt_width; kernel_col++) {
int input_col = -CONFIG_T::pad_left + kernel_col * CONFIG_T::dilation + col * CONFIG_T::stride_width;
if (input_col >= 0 && input_col < CONFIG_T::in_width) {
//*(data_col++) = data[input_col * CONFIG_T::n_chan];
data_col[index] = data[input_col * CONFIG_T::n_chan];
KernelLoop:
for (int kernel_col = 0; kernel_col < CONFIG_T::filt_width; kernel_col++) {
#pragma HLS UNROLL

ChannelLoop:
for (int channel = 0; channel < CONFIG_T::n_chan; channel++) {
int index_data = (col*CONFIG_T::stride_width+kernel_col-CONFIG_T::pad_left) * CONFIG_T::n_chan + channel;

if (index_data >= 0 && index_data < CONFIG_T::in_width*CONFIG_T::n_chan) {
data_col[index] = data[index_data];
} else {
//*(data_col++) = 0;
data_col[index] = 0;
}
index++;
Expand Down Expand Up @@ -191,7 +191,6 @@ void conv_1d_resource_cl(
dense_resource<data_T, res_T, typename CONFIG_T::mult_config>(data_col, res_col, weights, biases);
for (int j = 0; j < CONFIG_T::n_filt; j++) {
res[i * CONFIG_T::n_filt + j] = res_col[j];
//res[j * CONFIG_T::out_width + i] = res_col[j]; // Transposed order
}
}
}
Expand Down
64 changes: 64 additions & 0 deletions test/pytest/test_conv1d.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from hls4ml.converters.keras_to_hls import keras_to_hls
import pytest
import hls4ml
import numpy as np
from sklearn.metrics import accuracy_score
import tensorflow as tf
from tensorflow.keras.models import model_from_json
import yaml

@pytest.fixture(scope='module')
def data():
X = np.random.rand(100,100,7)
return X

@pytest.fixture(scope='module')
def keras_model():
jsons = open('../../example-models/keras/KERAS_conv1d.json','r').read()
model = model_from_json(jsons)
model.load_weights('../../example-models/keras/KERAS_conv1d_weights.h5')
return model

@pytest.fixture
@pytest.mark.parametrize('settings', [('io_parallel', 'latency'),
('io_parallel', 'resource'),
('io_stream', 'latency'),
('io_stream', 'resource')])
def hls_model(settings):
io_type = settings[0]
strategy = settings[1]
config = hls4ml.converters.create_config(output_dir = 'hls4mlprj_conv1d_{}_{}'.format(io_type, strategy))
config['KerasJson'] = '../../example-models/keras/KERAS_conv1d.json'
config['KerasH5'] = '../../example-models/keras/KERAS_conv1d_weights.h5'
config['OutputDir'] = 'hls4mlprj_conv1d_{}_{}'.format(io_type, strategy)
config['IOType'] = io_type

hls_config = {'Model' : {'Strategy' : strategy,
'ReuseFactor' : 1,
'Precision' : 'ap_fixed<16,3,AP_RND_CONV,AP_SAT>'}}
# Some model specific precision tuning
config['LayerName'] = {}
config['LayerName']['fc1_relu'] = {'Precision':{'weight' : 'ap_fixed<16,3>', 'result' : 'ap_fixed<16,6,AP_RND_CONV,AP_SAT>'}}
config['LayerName']['output_softmax'] = {'Precision':{'weight' : 'ap_fixed<16,6>', 'result' : 'ap_fixed<16,6,AP_RND_CONV,AP_SAT>'}}
config['LayerName']['output_softmax_softmax'] = {'Strategy':'Stable'}
config['HLSConfig'] = hls_config
hls_model = keras_to_hls(config)
hls_model.compile()
return hls_model

@pytest.mark.parametrize('settings', [('io_parallel', 'latency'),
('io_parallel', 'resource'),
('io_stream', 'latency'),
('io_stream', 'resource')])
def test_accuracy(data, keras_model, hls_model):
X = data
model = keras_model
# model under test predictions and accuracy
y_keras = model.predict(X)
y_hls4ml = hls_model.predict(X)
# "accuracy" of hls4ml predictions vs keras
rel_acc = accuracy_score(np.argmax(y_keras, axis=1), np.argmax(y_hls4ml, axis=1))

print('hls4ml accuracy relative to keras: {}'.format(rel_acc))

assert rel_acc > 0.98