-
Notifications
You must be signed in to change notification settings - Fork 571
Softmax update #1494
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
base: main
Are you sure you want to change the base?
Softmax update #1494
Changes from 48 commits
3d463b3
d678573
77258bc
59bd96f
dbb207b
0c59255
51efff0
6067bea
06fda4e
bf38a6b
e27fd11
9f4a448
16ca197
564b692
974e75a
060c398
f78558c
772b93a
d2b8921
a1ad891
d65544d
2d6a5cc
c3a4584
9b1cf17
31b7ad6
70b19d1
091cd8e
6c9f9a7
7a004b2
9d588f2
d5e3493
a56a8d6
29bdbb3
cab4cbc
42ece34
7e2798a
bd4778e
3946858
be76917
189f64a
e0aba71
584c4f7
711083a
6309fdb
b91a330
f990dbd
5bee49a
134787b
a90b79a
07ad4a4
aa5af6b
49d6ccd
3d7979a
aa678e0
5dadf1a
d8abde4
55e7454
947f195
10532da
232b2a3
84e0710
01d70a4
8d8bc8a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -194,12 +194,42 @@ def format(self, node): | |
|
|
||
| softmax_config_template = """struct {type}_config{index} : nnet::activ_config {{ | ||
| static constexpr unsigned n_in = {n_in}; | ||
|
|
||
| // For multi-dim softmax | ||
| static const unsigned n_slice = {n_slice}; | ||
| static const unsigned n_outer = {n_outer}; | ||
| static const unsigned n_inner = {n_inner}; | ||
|
|
||
| // For legacy softmax | ||
| typedef {table_t.name} table_t; | ||
| static constexpr unsigned table_size = {table_size}; | ||
|
|
||
| static constexpr unsigned exp_table_size = {exp_table_size}; | ||
| static constexpr unsigned inv_table_size = {inv_table_size}; | ||
| static constexpr unsigned io_type = nnet::{iotype}; | ||
| static constexpr unsigned reuse_factor = {reuse}; | ||
|
|
||
| static constexpr nnet::softmax_implementation implementation = nnet::softmax_implementation::{implementation}; | ||
| typedef {smax_accum_t} accum_t; | ||
| typedef {exp_table_t.name} exp_table_t; | ||
| typedef {inv_table_t.name} inv_table_t; | ||
| typedef {inv_table_t.name} inv_table_t;""" | ||
|
|
||
| softmax_config_table_template = """ | ||
|
|
||
| using {exp_table_name}_arr_t = nnet::array<exp_table_t, exp_table_size>; | ||
| using {inv_table_name}_arr_t = nnet::array<inv_table_t, inv_table_size>; | ||
| static constexpr const {exp_table_name}_arr_t exp_table = {exp_table_name}; | ||
| static constexpr const {inv_table_name}_arr_t invert_table = {inv_table_name}; | ||
|
jmitrevs marked this conversation as resolved.
|
||
| }};\n""" | ||
|
|
||
| softmax_config_table_template_stable = """ | ||
| typedef {inv_inp_t.name} inv_inp_t; | ||
| typedef {inp_norm_t.name} inp_norm_t; | ||
|
|
||
| using {exp_table_name}_arr_t = nnet::array<exp_table_t, exp_table_size>; | ||
| using {inv_table_name}_arr_t = nnet::array<inv_table_t, inv_table_size>; | ||
| static constexpr const {exp_table_name}_arr_t exp_table = {exp_table_name}; | ||
| static constexpr const {inv_table_name}_arr_t invert_table = {inv_table_name}; | ||
| }};\n""" | ||
|
|
||
| activ_function_template = 'nnet::{activation}<{input_t}, {output_t}, {config}>({input}, {output});' | ||
|
|
@@ -221,6 +251,36 @@ def format(self, node): | |
| params = self._default_config_params(node) | ||
| params['type'] = node.get_attr('activation') | ||
|
|
||
| if (params['type'] == 'softmax') or (params['type'] == 'softmax_multidim'): | ||
| params.setdefault('n_inner', 1) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These options have a default value, so there's no reason to set it here. See the default value in fpga_backend.py
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed n_inner and n_outer |
||
| params.setdefault('n_outer', 1) | ||
| n_slice = params['n_in'] // params['n_inner'] // params['n_outer'] | ||
| params['n_slice'] = n_slice | ||
|
|
||
| params['exp_table_name'] = node.name + '_exp_table' | ||
| params['inv_table_name'] = node.name + '_inv_table' | ||
|
|
||
| if params['implementation'] == 'stable': | ||
| self.template = softmax_config_template + softmax_config_table_template_stable | ||
|
|
||
| if 'exp_table_size' not in params: | ||
| params['exp_table_size'] = 2 ** params['inp_norm_t'].precision.width | ||
| node.set_attr('exp_table_size', params['exp_table_size']) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would not make the default different for oneAPI vs Vitis/Vivado. Note that the setting there is:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One could argue for a different default, but let's not diverge.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest just copying https://github.com/fastmachinelearning/hls4ml/blob/main/hls4ml/backends/vivado/passes/core_templates.py#L298-L309 for the default setting
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed this to use the default size of 1024 bits, but I would suggest something around 4096, perhaps, since at 1e-3 tolerance, I get around 60% of the values wrong. This is with a non-quantised layer too, since we don't have defined exp_table and inv_table sizes for a non-quantised layer, we default to 1024, leading to very coarse table values. |
||
|
|
||
| if 'inv_table_size' not in params: | ||
| params['inv_table_size'] = 2 ** params['inv_inp_t'].precision.width | ||
| node.set_attr('inv_table_size', params['inv_table_size']) | ||
|
|
||
| params['smax_accum_t'] = params['accum_t'].name | ||
| # params.setdefault('table_size', params['exp_table_size']) # Not sure if necessary | ||
|
|
||
| else: | ||
| # TODO: For latency check the table sizes correctly, match them | ||
| if 'exp_table_size' not in params: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is re-implementing set_default.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got rid of it :) |
||
| params['exp_table_size'] = params['table_size'] | ||
| if 'inv_table_size' not in params: | ||
| params['inv_table_size'] = params['table_size'] | ||
|
|
||
| return self.template.format(**params) | ||
|
|
||
|
|
||
|
|
@@ -251,7 +311,7 @@ def format(self, node): | |
| class SoftmaxConfigTemplate(ActivationConfigTemplate): | ||
| def __init__(self): | ||
| super(ActivationConfigTemplate, self).__init__(Softmax) # Skip ActivationConfigTemplate's __init__ | ||
| self.template = softmax_config_template | ||
| self.template = softmax_config_template + softmax_config_table_template | ||
|
|
||
|
|
||
| class ActivationFunctionTemplate(FunctionCallTemplate): | ||
|
|
@@ -304,6 +364,7 @@ def format(self, node): | |
| params = self._default_function_params(node) | ||
| params['activation'] = node.get_attr('activation').lower() | ||
| params['config'] = f'{node.get_attr("activation")}_config{node.index}' | ||
|
|
||
| return self.template.format(**params) | ||
|
|
||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.