Skip to content

Commit a3cca72

Browse files
authored
Merge pull request #780 from vloncar/rnn_fixes
Fix RNN layers when strategy=resource
2 parents 09e5274 + 51c117b commit a3cca72

File tree

5 files changed

+17
-47
lines changed

5 files changed

+17
-47
lines changed

hls4ml/backends/quartus/quartus_backend.py

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import numpy as np
55

66
from hls4ml.backends import FPGABackend
7-
from hls4ml.model.attributes import ConfigurableAttribute
7+
from hls4ml.model.attributes import ConfigurableAttribute, TypeAttribute
88
from hls4ml.model.flow import register_flow
99
from hls4ml.model.layers import GRU, LSTM, Activation, Conv1D, Conv2D, Dense, Embedding, Layer, SimpleRNN, Softmax
1010
from hls4ml.model.optimizer import get_backend_passes, layer_optimizer
@@ -39,6 +39,8 @@ def _register_layer_attributes(self):
3939
for layer in rnn_layers:
4040
attrs = self.attribute_map.get(layer, [])
4141
attrs.append(ConfigurableAttribute('recurrent_reuse_factor', default=1))
42+
attrs.append(ConfigurableAttribute('table_size', default=1024))
43+
attrs.append(TypeAttribute('table', default=FixedPrecisionType(18, 8)))
4244
self.attribute_map[layer] = attrs
4345

4446
def _register_flows(self):
@@ -312,16 +314,6 @@ def init_lstm(self, layer):
312314
reuse_factor = layer.model.config.get_reuse_factor(layer)
313315
layer.set_attr('recurrent_reuse_factor', reuse_factor)
314316

315-
index_t = IntegerPrecisionType(width=1, signed=False)
316-
layer.set_attr('index_t', index_t)
317-
318-
if 'table_t' not in layer.attributes:
319-
layer.set_attr(
320-
'table_t', NamedType(name=layer.name + '_table_t', precision=FixedPrecisionType(width=18, integer=8))
321-
)
322-
if 'table_size' not in layer.attributes:
323-
layer.set_attr('table_size', 1024)
324-
325317
# We don't use RF yet
326318
if True: # layer.model.config.is_resource_strategy(layer): ... Quartus only supports Dense resource multiplication
327319
n_in, n_out, n_in_recr, n_out_recr = self.get_layer_mult_size(layer)
@@ -367,14 +359,4 @@ def init_simple_rnn(self, layer):
367359
reuse_factor = layer.model.config.get_reuse_factor(layer)
368360
layer.set_attr('recurrent_reuse_factor', reuse_factor)
369361

370-
index_t = IntegerPrecisionType(width=1, signed=False)
371-
layer.set_attr('index_t', index_t)
372-
373-
if 'table_t' not in layer.attributes:
374-
layer.set_attr(
375-
'table_t', NamedType(name=layer.name + '_table_t', precision=FixedPrecisionType(width=18, integer=8))
376-
)
377-
if 'table_size' not in layer.attributes:
378-
layer.set_attr('table_size', 1024)
379-
380362
# TODO - Consider setting and using RF

hls4ml/backends/vivado/passes/recurrent_templates.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
typedef {accum_t.name} accum_t;
1717
typedef {bias_t.name} bias_t;
1818
typedef {weight_t.name} weight_t;
19-
typedef ap_{index_t} index_t;
19+
typedef {index_t.name} index_t;
2020
template<class x_T, class y_T>
2121
using product = nnet::product::{product_type}<x_T, y_T>;
2222
}};\n"""
@@ -28,15 +28,15 @@
2828
static const unsigned table_size = {table_size};
2929
static const unsigned io_type = nnet::{iotype};
3030
static const unsigned reuse_factor = {reuse};
31-
typedef ap_{table_t} table_t;
31+
typedef {table_t.name} table_t;
3232
}};\n"""
3333

3434
recr_activ_config_template = """struct {type}_config{index}_recr : nnet::activ_config {{
3535
static const unsigned n_in = {n_in};
3636
static const unsigned table_size = {table_size};
3737
static const unsigned io_type = nnet::{iotype};
3838
static const unsigned reuse_factor = {reuse};
39-
typedef ap_{table_t} table_t;
39+
typedef {table_t.name} table_t;
4040
}};\n"""
4141

4242
# LSTM + GRU templates

hls4ml/backends/vivado/vivado_backend.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from hls4ml.backends import FPGABackend
77
from hls4ml.backends.fpga.fpga_types import APTypeConverter, HLSTypeConverter, VivadoArrayVariableConverter
8-
from hls4ml.model.attributes import ChoiceAttribute, ConfigurableAttribute
8+
from hls4ml.model.attributes import ChoiceAttribute, ConfigurableAttribute, TypeAttribute
99
from hls4ml.model.flow import register_flow
1010
from hls4ml.model.layers import (
1111
GRU,
@@ -51,6 +51,8 @@ def _register_layer_attributes(self):
5151
attrs = self.attribute_map.get(layer, [])
5252
attrs.append(ConfigurableAttribute('recurrent_reuse_factor', default=1))
5353
attrs.append(ConfigurableAttribute('static', value_type=bool, default=True))
54+
attrs.append(ConfigurableAttribute('table_size', default=1024))
55+
attrs.append(TypeAttribute('table', default=FixedPrecisionType(18, 8)))
5456
self.attribute_map[layer] = attrs
5557

5658
# Add ParallelizationFactor to Conv1D/2D
@@ -393,46 +395,30 @@ def init_lstm(self, layer):
393395
reuse_factor = layer.model.config.get_reuse_factor(layer)
394396
layer.set_attr('recurrent_reuse_factor', reuse_factor)
395397

396-
index_t = IntegerPrecisionType(width=1, signed=False)
397-
398-
if 'table_t' not in layer.attributes:
399-
layer.set_attr('table_t', FixedPrecisionType(width=18, integer=8))
400-
if 'table_size' not in layer.attributes:
401-
layer.set_attr('table_size', 1024)
402398
if layer.model.config.is_resource_strategy(layer):
403399
n_in, n_out, n_in_recr, n_out_recr = self.get_layer_mult_size(layer)
404400
self.set_closest_reuse_factor(layer, n_in, n_out)
405401
self.set_closest_reuse_factor(layer, n_in_recr, n_out_recr, attribute='recurrent_reuse_factor')
406-
layer.weights['weight'].data = np.transpose(layer.weights['weight'].data)
407-
layer.weights['recurrent_weight'].data = np.transpose(layer.weights['recurrent_weight'].data)
408402
layer.set_attr('strategy', 'resource')
409403
else:
410404
layer.set_attr('strategy', 'latency')
411405

412-
layer.set_attr('index_t', index_t)
406+
layer.set_attr('index_t', NamedType(f'layer{layer.index}_index', IntegerPrecisionType(width=1, signed=False)))
413407

414408
@layer_optimizer(GRU)
415409
def init_gru(self, layer):
416410
reuse_factor = layer.model.config.get_reuse_factor(layer)
417411
layer.set_attr('recurrent_reuse_factor', reuse_factor)
418412

419-
index_t = IntegerPrecisionType(width=1, signed=False)
420-
421-
if 'table_t' not in layer.attributes:
422-
layer.set_attr('table_t', FixedPrecisionType(width=18, integer=8))
423-
if 'table_size' not in layer.attributes:
424-
layer.set_attr('table_size', 1024)
425413
if layer.model.config.is_resource_strategy(layer):
426414
n_in, n_out, n_in_recr, n_out_recr = self.get_layer_mult_size(layer)
427415
self.set_closest_reuse_factor(layer, n_in, n_out)
428416
self.set_closest_reuse_factor(layer, n_in_recr, n_out_recr, attribute='recurrent_reuse_factor')
429-
layer.weights['weight'].data = np.transpose(layer.weights['weight'].data)
430-
layer.weights['recurrent_weight'].data = np.transpose(layer.weights['recurrent_weight'].data)
431417
layer.set_attr('strategy', 'resource')
432418
else:
433419
layer.set_attr('strategy', 'latency')
434420

435-
layer.set_attr('index_t', index_t)
421+
layer.set_attr('index_t', NamedType(f'layer{layer.index}_index', IntegerPrecisionType(width=1, signed=False)))
436422

437423
@layer_optimizer(GarNet)
438424
def init_garnet(self, layer):

hls4ml/model/layers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def __init__(self, model, name, attributes, inputs, outputs=None):
112112
config_value, str
113113
): # TODO maybe move this to __setitem__ of AttributeDict?
114114
precision = self.model.config.backend.convert_precision_string(config_value)
115-
config_value = NamedType(self.name + config_key, precision)
115+
config_value = NamedType(self.name + '_' + config_key, precision)
116116
self.attributes[config_key] = config_value
117117

118118
self.initialize()

test/pytest/test_rnn.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ def test_rnn_parsing(rnn_layer, return_sequences):
8484
)
8585
@pytest.mark.parametrize('return_sequences', [True, False])
8686
@pytest.mark.parametrize('static', [True, False])
87-
def test_rnn_accuracy(rnn_layer, return_sequences, backend, io_type, static):
87+
@pytest.mark.parametrize('strategy', ['latency', 'resource'])
88+
def test_rnn_accuracy(rnn_layer, return_sequences, backend, io_type, strategy, static):
8889
# Subtract 0.5 to include negative values
8990
input_shape = (12, 8)
9091
X = np.random.rand(50, *input_shape) - 0.5
@@ -109,8 +110,9 @@ def test_rnn_accuracy(rnn_layer, return_sequences, backend, io_type, static):
109110
keras_model, granularity='name', default_precision=default_precision, backend=backend
110111
)
111112
hls_config['LayerName'][layer_name]['static'] = static
112-
prj_name = 'hls4mlprj_rnn_accuracy_{}_static_{}_ret_seq_{}_{}_{}'.format(
113-
rnn_layer.__class__.__name__.lower(), int(static), int(return_sequences), backend, io_type
113+
hls_config['LayerName'][layer_name]['Strategy'] = strategy
114+
prj_name = 'hls4mlprj_rnn_accuracy_{}_static_{}_ret_seq_{}_{}_{}_{}'.format(
115+
rnn_layer.__class__.__name__.lower(), int(static), int(return_sequences), backend, io_type, strategy
114116
)
115117
output_dir = str(test_root_path / prj_name)
116118

0 commit comments

Comments
 (0)