Skip to content
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

Explicit pointwise Conv1D implementation for "Latency" strategy #811

5 changes: 3 additions & 2 deletions hls4ml/backends/vivado/vivado_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,9 @@ def _register_layer_attributes(self):

for layer in cnn_layers:
attrs = self.attribute_map.get(layer, [])
# attrs.append(ConfigurableAttribute('conv_implementation', value_type=str, default='LineBuffer'))
attrs.append(ChoiceAttribute('conv_implementation', choices=['LineBuffer', 'Encoded'], default='LineBuffer'))
attrs.append(
ChoiceAttribute('conv_implementation', choices=['LineBuffer', 'Encoded', 'Pointwise'], default='LineBuffer')
)
self.attribute_map[layer] = attrs

def _register_flows(self):
Expand Down
2 changes: 1 addition & 1 deletion hls4ml/templates/vivado/build_prj.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ if {$opt(reset)} {
} else {
open_solution "solution1"
}
catch {config_array_partition -maximum_size 4096}
catch {config_array_partition -maximum_size 8192}
config_compile -name_max_length 80
set_part $part
config_schedule -enable_dsp_full_reg=false
Expand Down
1 change: 1 addition & 0 deletions hls4ml/templates/vivado/nnet_utils/nnet_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ namespace nnet {
// Common type definitions
enum io_type { io_parallel = 0, io_stream };
enum strategy { latency, resource };
enum class conv_implementation { linebuffer = 0, encoded = 1, pointwise = 2 };

/* ---
* Balanced tree reduce implementation.
Expand Down
14 changes: 12 additions & 2 deletions hls4ml/templates/vivado/nnet_utils/nnet_conv1d.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,19 @@ void pointwise_conv_1d_cl(data_T data[CONFIG_T::in_width * CONFIG_T::n_chan],

#pragma HLS INLINE region

// Nothing special to be done for io_parallel implementation
if (CONFIG_T::strategy == nnet::latency) {
conv_1d_latency_cl<data_T, res_T, CONFIG_T>(data, res, weights, biases);
if (CONFIG_T::implementation == conv_implementation::pointwise) {
// Use pointwise unrolled implementation
if (CONFIG_T::reuse_factor > 1 && CONFIG_T::reuse_factor <= 120) {
pointwise_conv_1d_latency_cl_split_by_rf<data_T, res_T, CONFIG_T>(data, res, weights, biases);
} else {
assert(CONFIG_T::reuse_factor == 1);
pointwise_conv_1d_latency_cl<data_T, res_T, CONFIG_T>(data, res, weights, biases);
}
} else {
// Use standard unrolled implementation
conv_1d_latency_cl<data_T, res_T, CONFIG_T>(data, res, weights, biases);
}
} else {
conv_1d_resource_cl<data_T, res_T, CONFIG_T>(data, res, weights, biases);
}
Expand Down
351 changes: 351 additions & 0 deletions hls4ml/templates/vivado/nnet_utils/nnet_conv1d_latency.h

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions hls4ml/templates/vivado/nnet_utils/nnet_conv_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

namespace nnet {

enum class conv_implementation { linebuffer = 0, encoded = 1 };

// *************************************************
// Encoded Implementation (Vlad's)
// *************************************************
Expand Down
38 changes: 19 additions & 19 deletions test/pytest/test_pointwiseconv.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,22 @@
@pytest.mark.parametrize('padds', padds_options)
@pytest.mark.parametrize('strides', strides1d_options)
@pytest.mark.parametrize(
'backend, io_type, strategy',
'backend, io_type, strategy, conv_impl',
[
('Quartus', 'io_parallel', 'resource'),
('Vivado', 'io_parallel', 'resource'),
('Vitis', 'io_parallel', 'resource'),
('Vivado', 'io_parallel', 'latency'),
('Vitis', 'io_parallel', 'latency'),
('Vivado', 'io_stream', 'latency'),
('Vivado', 'io_stream', 'resource'),
('Vitis', 'io_stream', 'latency'),
('Vitis', 'io_stream', 'resource'),
('Quartus', 'io_parallel', 'resource', 'LineBuffer'),
('Vivado', 'io_parallel', 'resource', 'LineBuffer'),
('Vitis', 'io_parallel', 'resource', 'LineBuffer'),
('Vivado', 'io_parallel', 'latency', 'LineBuffer'),
('Vitis', 'io_parallel', 'latency', 'LineBuffer'),
('Vivado', 'io_parallel', 'latency', 'Pointwise'),
('Vitis', 'io_parallel', 'latency', 'Pointwise'),
('Vivado', 'io_stream', 'latency', 'LineBuffer'),
('Vivado', 'io_stream', 'resource', 'LineBuffer'),
('Vitis', 'io_stream', 'latency', 'LineBuffer'),
('Vitis', 'io_stream', 'resource', 'LineBuffer'),
],
)
def test_pointwiseconv1d(chans, padds, strides, backend, io_type, strategy):
def test_pointwiseconv1d(chans, padds, strides, backend, io_type, strategy, conv_impl):
model = tf.keras.models.Sequential()
input_shape = (28, 3)
model.add(
Expand All @@ -47,6 +49,7 @@ def test_pointwiseconv1d(chans, padds, strides, backend, io_type, strategy):
kernel_initializer='normal',
use_bias=False,
data_format=chans,
name='pointwise1d',
)
)
model.compile(optimizer='adam', loss='mse')
Expand All @@ -55,14 +58,13 @@ def test_pointwiseconv1d(chans, padds, strides, backend, io_type, strategy):
keras_prediction = model.predict(X_input)

default_precision = 'ac_fixed<32,16,true>' if backend == 'Quartus' else 'ap_fixed<32,16>'
config = hls4ml.utils.config_from_keras_model(model, default_precision=default_precision)
config = hls4ml.utils.config_from_keras_model(model, default_precision=default_precision, granularity='name')
config['Model']['Strategy'] = strategy
config['LayerName']['pointwise1d']['ConvImplementation'] = conv_impl

output_dir = str(
test_root_path
/ 'hls4mlprj_pointwise1d_{}_strides_{}_{}_padding_{}_{}_{}'.format(
chans, strides[0], padds, backend, io_type, strategy
)
/ f'hls4mlprj_pointwise1d_{chans}_strides_{strides[0]}_{padds}_padding_{backend}_{io_type}_{strategy}_{conv_impl}'
)
hls_model = hls4ml.converters.convert_from_keras_model(
model, hls_config=config, output_dir=output_dir, io_type=io_type, backend=backend
Expand Down Expand Up @@ -100,6 +102,7 @@ def test_pointwiseconv2d(chans, padds, strides, backend, io_type, strategy):
kernel_initializer='normal',
use_bias=False,
data_format=chans,
name='pointwise2d',
)
)

Expand All @@ -113,10 +116,7 @@ def test_pointwiseconv2d(chans, padds, strides, backend, io_type, strategy):
config['Model']['Strategy'] = strategy
stride_cfg = str(strides).replace(', ', '_').replace('(', '').replace(')', '')
output_dir = str(
test_root_path
/ 'hls4mlprj_pointwise2d_{}_strides_{}_{}_padding_{}_{}_{}'.format(
chans, stride_cfg, padds, backend, io_type, strategy
)
test_root_path / f'hls4mlprj_pointwise2d_{chans}_strides_{stride_cfg}_{padds}_padding_{backend}_{io_type}_{strategy}'
)

hls_model = hls4ml.converters.convert_from_keras_model(
Expand Down