Skip to content

Commit 236a67d

Browse files
author
Robert Muchsel
authored
Add softmax function to allow the last layer to use 4/2/1 bit weights (#104)
1 parent 965d7b8 commit 236a67d

File tree

6 files changed

+47
-5
lines changed

6 files changed

+47
-5
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# MAX78000 Model Training and Synthesis
22

3-
_January 28, 2021_
3+
_February 1, 2021_
44

55
The Maxim Integrated AI project is comprised of four repositories:
66

@@ -1442,6 +1442,8 @@ The 32-bit intermediate result is multiplied by $2^{totalshift}$, where the tota
14421442

14431443
Using `output_shift` can help normalize data, particularly when using small weights. By default, `output_shift` is generated by the training software, and it is used for batch normalization as well as quantization-aware training.
14441444

1445+
*Note:* When using 32-bit wide outputs in the final layer, no hardware shift is performed and `output_shift` is ignored.
1446+
14451447
Example:
14461448
`output_shift: 2`
14471449

@@ -1814,7 +1816,7 @@ To run another inference, ensure all groups are disabled (stopping the state mac
18141816

18151817
`ai8xize.py` can generate a call to a software Softmax function using the command line switch `--softmax`. That function is provided in the `assets/device-all` folder. To use the provided software Softmax on MAX78000/MAX78002, the last layer output should be 32-bit wide (`output_width: 32`).
18161818

1817-
The software Softmax function is optimized for processing time and it quantizes the input.
1819+
The software Softmax function is optimized for processing time and it quantizes the input. When the last layer uses weights that are not 8-bits, the software function used will shift the input values first.
18181820

18191821
![softmax](docs/softmax.png)
18201822

README.pdf

1.55 KB
Binary file not shown.

assets/device-all/softmax.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,38 @@ void softmax_q17p14_q15(const q31_t * vec_in, const uint16_t dim_vec, q15_t * p_
131131

132132
}
133133

134+
/**
135+
* @brief Q17.14 fixed point softmax function with input shift, returns Q15
136+
* @param[in] vec_in pointer to input vector
137+
* @param[in] dim_vec input vector dimension
138+
* @param[in] in_shift input vector shift count
139+
* @param[out] p_out pointer to output vector
140+
* @return none.
141+
*
142+
* @details
143+
*
144+
* Here, instead of typical e based softmax, we use
145+
* 2-based softmax, i.e.,:
146+
*
147+
* y_i = 2^(x_i/16384) / sum(2^(x_j/16384))
148+
*
149+
* The relative output will be different here.
150+
* But mathematically, the gradient will be the same
151+
* with a log(2) scaling factor.
152+
*/
153+
154+
void softmax_shift_q17p14_q15(q31_t * vec_in, const uint16_t dim_vec, uint8_t in_shift, q15_t * p_out)
155+
{
156+
int16_t i;
157+
158+
for (i = 0; i < dim_vec; i++)
159+
{
160+
vec_in[i] <<= in_shift;
161+
}
162+
163+
softmax_q17p14_q15(vec_in, dim_vec, p_out);
164+
}
165+
134166
/**
135167
* @} end of Softmax group
136168
*/

assets/device-all/templatecnn.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ typedef int16_t q15_t;
2929
#define SYS_START LED_On(0)
3030
#define SYS_COMPLETE LED_Off(0)
3131

32-
/* Unload data from accelerator and run software SoftMax */
32+
/* Run software SoftMax on unloaded data */
3333
void softmax_q17p14_q15(const q31_t * vec_in, const uint16_t dim_vec, q15_t * p_out);
34+
/* Shift the input, then calculate SoftMax */
35+
void softmax_shift_q17p14_q15(q31_t * vec_in, const uint16_t dim_vec, uint8_t in_shift, q15_t * p_out);
3436

3537
/* Stopwatch - holds the runtime when accelerator finishes */
3638
extern volatile uint32_t cnn_time;

izer/max7800x.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2265,6 +2265,7 @@ def run_eltwise(
22652265
if softmax:
22662266
apb.softmax_layer(
22672267
output_width=output_width[final_layer],
2268+
shift=8 - abs(quantization[final_layer]) if not bypass[final_layer] else 0,
22682269
)
22692270

22702271
summary_stats = '/*\n' + \

izer/toplevel.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,7 @@ def main(
772772
def softmax_layer(
773773
memfile,
774774
output_width=8,
775+
shift=0,
775776
):
776777
"""
777778
Write the call to the softmax layer to `memfile`.
@@ -786,8 +787,12 @@ def softmax_layer(
786787
memfile.write(f' cnn_unload((uint32_t *) ml_data{"32" if output_width != 32 else ""});\n')
787788

788789
if output_width == 32:
789-
memfile.write(' softmax_q17p14_q15((const q31_t *) ml_data, '
790-
'CNN_NUM_OUTPUTS, ml_softmax);\n')
790+
if shift == 0:
791+
memfile.write(' softmax_q17p14_q15((const q31_t *) ml_data, '
792+
'CNN_NUM_OUTPUTS, ml_softmax);\n')
793+
else:
794+
memfile.write(' softmax_shift_q17p14_q15((q31_t *) ml_data, '
795+
f'CNN_NUM_OUTPUTS, {shift}, ml_softmax);\n')
791796
else:
792797
memfile.write(' arm_softmax_q7_q15((const q7_t *) ml_data32, '
793798
'CNN_NUM_OUTPUTS, ml_softmax);\n')

0 commit comments

Comments
 (0)