Skip to content

Commit fe8519f

Browse files
jmitrevsthesps
andcommitted
fix conv1d io_parallel resource (#403)
* fix conv1d io_parallel resource * replace tabs with spaces in modified code * Add test for Conv1D example model Co-authored-by: Sioni Summers <[email protected]>
1 parent da2c46a commit fe8519f

File tree

2 files changed

+75
-12
lines changed

2 files changed

+75
-12
lines changed

hls4ml/templates/vivado/nnet_utils/nnet_conv1d_resource.h

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void conv_1d_full(
4141
data_T data_conv[CONFIG_T::filt_width * CONFIG_T::n_chan * CONFIG_T::out_width];
4242
data_T data_col[CONFIG_T::filt_width * CONFIG_T::n_chan];
4343
res_T res_col[CONFIG_T::n_filt];
44-
44+
4545
//#pragma HLS ARRAY_PARTITION variable=data_conv complete
4646
#pragma HLS ARRAY_PARTITION variable=data_col complete
4747
#pragma HLS ARRAY_PARTITION variable=res_col complete
@@ -142,17 +142,17 @@ void conv_1d_resource_cf(
142142
template<class data_T, typename CONFIG_T>
143143
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) {
144144
int index = 0;
145-
ChannelLoop:
146-
for (int channel = CONFIG_T::n_chan; channel--; data++) {
147-
#pragma HLS UNROLL
148-
KernelLoop:
149-
for (int kernel_col = 0; kernel_col < CONFIG_T::filt_width; kernel_col++) {
150-
int input_col = -CONFIG_T::pad_left + kernel_col * CONFIG_T::dilation + col * CONFIG_T::stride_width;
151-
if (input_col >= 0 && input_col < CONFIG_T::in_width) {
152-
//*(data_col++) = data[input_col * CONFIG_T::n_chan];
153-
data_col[index] = data[input_col * CONFIG_T::n_chan];
145+
KernelLoop:
146+
for (int kernel_col = 0; kernel_col < CONFIG_T::filt_width; kernel_col++) {
147+
#pragma HLS UNROLL
148+
149+
ChannelLoop:
150+
for (int channel = 0; channel < CONFIG_T::n_chan; channel++) {
151+
int index_data = (col*CONFIG_T::stride_width+kernel_col-CONFIG_T::pad_left) * CONFIG_T::n_chan + channel;
152+
153+
if (index_data >= 0 && index_data < CONFIG_T::in_width*CONFIG_T::n_chan) {
154+
data_col[index] = data[index_data];
154155
} else {
155-
//*(data_col++) = 0;
156156
data_col[index] = 0;
157157
}
158158
index++;
@@ -191,7 +191,6 @@ void conv_1d_resource_cl(
191191
dense_resource<data_T, res_T, typename CONFIG_T::mult_config>(data_col, res_col, weights, biases);
192192
for (int j = 0; j < CONFIG_T::n_filt; j++) {
193193
res[i * CONFIG_T::n_filt + j] = res_col[j];
194-
//res[j * CONFIG_T::out_width + i] = res_col[j]; // Transposed order
195194
}
196195
}
197196
}

test/pytest/test_conv1d.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from hls4ml.converters.keras_to_hls import keras_to_hls
2+
import pytest
3+
import hls4ml
4+
import numpy as np
5+
from sklearn.metrics import accuracy_score
6+
import tensorflow as tf
7+
from tensorflow.keras.models import model_from_json
8+
import yaml
9+
10+
@pytest.fixture(scope='module')
11+
def data():
12+
X = np.random.rand(100,100,7)
13+
return X
14+
15+
@pytest.fixture(scope='module')
16+
def keras_model():
17+
jsons = open('../../example-models/keras/KERAS_conv1d.json','r').read()
18+
model = model_from_json(jsons)
19+
model.load_weights('../../example-models/keras/KERAS_conv1d_weights.h5')
20+
return model
21+
22+
@pytest.fixture
23+
@pytest.mark.parametrize('settings', [('io_parallel', 'latency'),
24+
('io_parallel', 'resource'),
25+
('io_stream', 'latency'),
26+
('io_stream', 'resource')])
27+
def hls_model(settings):
28+
io_type = settings[0]
29+
strategy = settings[1]
30+
config = hls4ml.converters.create_config(output_dir = 'hls4mlprj_conv1d_{}_{}'.format(io_type, strategy))
31+
config['KerasJson'] = '../../example-models/keras/KERAS_conv1d.json'
32+
config['KerasH5'] = '../../example-models/keras/KERAS_conv1d_weights.h5'
33+
config['OutputDir'] = 'hls4mlprj_conv1d_{}_{}'.format(io_type, strategy)
34+
config['IOType'] = io_type
35+
36+
hls_config = {'Model' : {'Strategy' : strategy,
37+
'ReuseFactor' : 1,
38+
'Precision' : 'ap_fixed<16,3,AP_RND_CONV,AP_SAT>'}}
39+
# Some model specific precision tuning
40+
config['LayerName'] = {}
41+
config['LayerName']['fc1_relu'] = {'Precision':{'weight' : 'ap_fixed<16,3>', 'result' : 'ap_fixed<16,6,AP_RND_CONV,AP_SAT>'}}
42+
config['LayerName']['output_softmax'] = {'Precision':{'weight' : 'ap_fixed<16,6>', 'result' : 'ap_fixed<16,6,AP_RND_CONV,AP_SAT>'}}
43+
config['LayerName']['output_softmax_softmax'] = {'Strategy':'Stable'}
44+
config['HLSConfig'] = hls_config
45+
hls_model = keras_to_hls(config)
46+
hls_model.compile()
47+
return hls_model
48+
49+
@pytest.mark.parametrize('settings', [('io_parallel', 'latency'),
50+
('io_parallel', 'resource'),
51+
('io_stream', 'latency'),
52+
('io_stream', 'resource')])
53+
def test_accuracy(data, keras_model, hls_model):
54+
X = data
55+
model = keras_model
56+
# model under test predictions and accuracy
57+
y_keras = model.predict(X)
58+
y_hls4ml = hls_model.predict(X)
59+
# "accuracy" of hls4ml predictions vs keras
60+
rel_acc = accuracy_score(np.argmax(y_keras, axis=1), np.argmax(y_hls4ml, axis=1))
61+
62+
print('hls4ml accuracy relative to keras: {}'.format(rel_acc))
63+
64+
assert rel_acc > 0.98

0 commit comments

Comments
 (0)