From d3d06ebdd522db4bdb25847f8d71cf15a7f85242 Mon Sep 17 00:00:00 2001 From: Nitesh Kumar <166297874+niteshg97@users.noreply.github.com> Date: Sat, 23 May 2026 12:33:03 +0530 Subject: [PATCH 1/2] Fix stable softmax LUT indexing for nonnegative inputs Stable softmax computes x_max - x_i, which is guaranteed nonnegative. Skip the sign bit when generating exp_table lookup indices to avoid wasting half of the LUT address space. --- hls4ml/templates/vivado/nnet_utils/nnet_activation.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hls4ml/templates/vivado/nnet_utils/nnet_activation.h b/hls4ml/templates/vivado/nnet_utils/nnet_activation.h index ac85e0b2cc..1d8a3a8866 100644 --- a/hls4ml/templates/vivado/nnet_utils/nnet_activation.h +++ b/hls4ml/templates/vivado/nnet_utils/nnet_activation.h @@ -138,10 +138,12 @@ template inline float softmax_real_val_from_ return (float)x; } -template inline unsigned softmax_idx_from_real_val(data_T x) { +template inline unsigned softmax_idx_from_real_val_unsigned(data_T x) { // Slice the top N bits to get an index into the table static constexpr int N = ceillog2(table_size); // number of address bits for table - ap_uint y = x(x.width - 1, x.width - N); // slice the top N bits of input + + // skip sign bit because inputs are guaranteed nonnegative + ap_uint y = x(x.width - 2, x.width - N - 1); // slice the top N bits of input return (unsigned)y(N - 1, 0); } @@ -254,7 +256,7 @@ void softmax_stable(data_T data[CONFIG_T::n_slice], res_T res[CONFIG_T::n_slice] typename CONFIG_T::inv_inp_t exp_sum(0); for (unsigned i = 0; i < CONFIG_T::n_slice; i++) { #pragma HLS unroll - unsigned x = softmax_idx_from_real_val(d_xi_xmax[i]); + unsigned x = softmax_idx_from_real_val_unsigned(d_xi_xmax[i]); exp_res[i] = exp_table[x]; } From 55bd6dbb71f130a4441db4456deecb1f33083e2b Mon Sep 17 00:00:00 2001 From: Nitesh Kumar <166297874+niteshg97@users.noreply.github.com> Date: Sat, 23 May 2026 18:46:43 +0530 Subject: [PATCH 2/2] Fix formatting and remove unnecessary line in softmax function --- hls4ml/templates/vivado/nnet_utils/nnet_activation.h | 1 - 1 file changed, 1 deletion(-) diff --git a/hls4ml/templates/vivado/nnet_utils/nnet_activation.h b/hls4ml/templates/vivado/nnet_utils/nnet_activation.h index 1d8a3a8866..039e966056 100644 --- a/hls4ml/templates/vivado/nnet_utils/nnet_activation.h +++ b/hls4ml/templates/vivado/nnet_utils/nnet_activation.h @@ -141,7 +141,6 @@ template inline float softmax_real_val_from_ template inline unsigned softmax_idx_from_real_val_unsigned(data_T x) { // Slice the top N bits to get an index into the table static constexpr int N = ceillog2(table_size); // number of address bits for table - // skip sign bit because inputs are guaranteed nonnegative ap_uint y = x(x.width - 2, x.width - N - 1); // slice the top N bits of input return (unsigned)y(N - 1, 0);