Skip to content

Commit 9ca7af2

Browse files
authored
Merge pull request #655 from bo3z/sofstign-stream-opt
Quartus Streaming Softsign (PR #585 contd.)
2 parents 40ae7f9 + 9271648 commit 9ca7af2

File tree

2 files changed

+27
-36
lines changed

2 files changed

+27
-36
lines changed

hls4ml/templates/quartus/firmware/nnet_utils/nnet_activation_stream.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ template<class data_T, class res_T, typename CONFIG_T>
223223
void softsign(stream<data_T> &data, stream<res_T> &res) {
224224
#include "activation_tables/softsign_table.tb"
225225

226+
static const int MAX_VALUE = 8;
227+
226228
SoftsignActLoop:
227229
#pragma ii 1
228230
for (int i = 0; i < CONFIG_T::n_in / res_T::size; i++) {
@@ -232,11 +234,21 @@ void softsign(stream<data_T> &data, stream<res_T> &res) {
232234
SoftsignPackLoop:
233235
#pragma unroll
234236
for (int j = 0; j < res_T::size; j++) {
235-
hls_register int data_round = (in_data[j]*CONFIG_T::table_size/16).to_int();
236-
hls_register int index = data_round + 8*CONFIG_T::table_size/16;
237-
if (index < 0) index = 0;
238-
else if (index > CONFIG_T::table_size-1) index = CONFIG_T::table_size-1;
239-
out_data[j] = softsign_table[index];
237+
hls_register typename data_T::value_type absValue;;
238+
if(in_data[j] < 0){
239+
absValue = -in_data[j];
240+
}
241+
else{
242+
absValue = in_data[j];
243+
}
244+
ac_int<16> index = (absValue * CONFIG_T::table_size / MAX_VALUE).to_int();
245+
if (absValue > MAX_VALUE) index = CONFIG_T::table_size - 1;
246+
if(in_data[j] < 0) {
247+
out_data[j] = -(typename res_T::value_type) softsign_table[index];
248+
}
249+
else {
250+
out_data[j] = (typename res_T::value_type) softsign_table[index];
251+
}
240252
}
241253

242254
res.write(out_data);

test/pytest/test_softsign.py

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,48 +7,27 @@
77

88
test_root_path = Path(__file__).parent
99

10-
def flat_distribution(shape):
11-
return np.random.rand(*shape)
12-
13-
14-
@pytest.fixture()
15-
def generate_data(function, input_shape):
16-
return function((1000, *input_shape))
17-
18-
19-
# TODO: include latency strategy with flat_distribution when it can be made to pass
20-
@pytest.mark.parametrize('backend,strategy,function,input_shape,io_type', [
21-
('Vivado', 'stable', flat_distribution, (4,), 'io_parallel'),
22-
('Quartus', 'stable', flat_distribution, (4,), 'io_parallel'),
23-
24-
# IO_stram avaliable just for VIVADO
25-
('Vivado', 'stable', flat_distribution, (4,), 'io_stream'),
26-
('Vivado', 'stable', flat_distribution, (4, 4, 3), 'io_stream')
10+
@pytest.mark.parametrize('backend', ['Vivado', 'Quartus'])
11+
@pytest.mark.parametrize('input_shape, io_type', [
12+
((8, ), 'io_parallel'),
13+
((8, ), 'io_stream'),
14+
((8, 8, 3), 'io_stream')
2715
])
28-
def test_softsign(backend, strategy, generate_data, input_shape, io_type):
29-
X = generate_data
16+
def test_softsign(backend, input_shape, io_type):
17+
X = np.random.rand(1000, *input_shape)
3018
model = tf.keras.models.Sequential()
3119
model.add(tf.keras.layers.Activation(input_shape=input_shape, activation='softsign', name='softsign'))
3220
model.compile()
3321

34-
f_type = 'ac_fixed<18,8,true,AC_RND,AC_SAT>' if backend == 'Quartus' else 'ap_fixed<18,8,AP_RND,AP_SAT>'
35-
cfg = hls4ml.utils.config_from_keras_model(model, granularity='name')
36-
cfg['LayerName']['softsign']['Strategy'] = strategy
37-
cfg['LayerName']['softsign']['inv_table_t'] = f_type
38-
cfg['LayerName']['softsign']['exp_table_t'] = f_type
39-
40-
odir = str(test_root_path / 'hls4mlprj_softsign_{}'.format(strategy))
22+
cfg = hls4ml.utils.config_from_keras_model(model, granularity='name')
23+
odir = str(test_root_path / 'hls4mlprj_softsign_{}_{}_{}'.format(backend, io_type, str(input_shape)))
4124
hls_model = hls4ml.converters.convert_from_keras_model(model, hls_config=cfg, io_type=io_type,
4225
output_dir=odir, backend=backend)
4326
hls_model.compile()
4427

4528
y_keras = model.predict(X)
4629
y_hls4ml = hls_model.predict(X).reshape(y_keras.shape)
47-
4830
acc_hls4ml = accuracy_score(np.argmax(y_keras, axis=-1).ravel(), np.argmax(y_hls4ml, axis=-1).ravel())
4931

5032
print('Accuracy hls4ml relative to keras: {}'.format(acc_hls4ml))
51-
52-
assert acc_hls4ml >= 0.98
53-
54-
33+
assert acc_hls4ml >= 0.97

0 commit comments

Comments
 (0)