1010test_root_path = Path (__file__ ).parent
1111
1212
13- def flat_distribution (shape ):
14- return np .random .rand (* shape )
15-
16-
17- def high_accuracy_distribution (shape ):
18- '''Start with a flat distribution, then pick a random member of each row to amplify'''
19- x = np .random .rand (* shape )
20- imax = np .random .randint (0 , shape [1 ], size = shape [0 ])
21- x [:, imax ] *= 10
22- return x
23-
24-
2513@pytest .fixture ()
26- def generate_data (function , input_shape ):
27- return function ((1000 , * input_shape ))
14+ def generate_data (input_shape ):
15+ shape = (5000 , * input_shape )
16+ d = np .random .normal (0 , 2 , shape )
17+ modify_entries = np .random .randint (0 , 1 , shape ) < 0.05
18+ d [modify_entries ] = d [modify_entries ] * 5 + 10
19+ return np .clip (d , - 32 , 31 )
2820
2921
3022@pytest .mark .parametrize ('backend' , ['Vivado' , 'Vitis' , 'Quartus' ])
31- @pytest .mark .parametrize ('strategy' , ['stable' , 'argmax' ])
23+ @pytest .mark .parametrize ('strategy' , ['stable' , 'latency' , ' argmax' ])
3224@pytest .mark .parametrize (
33- 'function ,input_shape,io_type' ,
25+ 'input_bits ,input_shape,table_bits ,io_type' ,
3426 [
35- (flat_distribution , (8 ,), 'io_parallel' ),
36- (high_accuracy_distribution , (8 ,), 'io_parallel' ),
37- (flat_distribution , (8 ,), 'io_stream' ),
38- (high_accuracy_distribution , (8 ,), 'io_stream' ),
39- (flat_distribution , (8 , 8 , 3 ), 'io_stream' ),
40- (high_accuracy_distribution , (8 , 8 , 3 ), 'io_stream' ),
27+ ('16,6' , (8 ,), '18,8' , 'io_parallel' ),
28+ ('16,6' , (8 ,), '18,8' , 'io_stream' ),
29+ ('16,6' , (8 ,), '9,6' , 'io_parallel' ),
30+ ('16,6' , (8 ,), '9,6' , 'io_stream' ),
31+ ('9,6' , (8 ,), '18,8' , 'io_parallel' ),
32+ ('9,6' , (8 ,), '18,8' , 'io_stream' ),
33+ ('16,6' , (8 , 8 , 3 ), '18,8' , 'io_stream' ),
4134 ],
4235)
43- def test_softmax (backend , strategy , generate_data , input_shape , io_type , function ):
36+ def test_softmax (backend , strategy , generate_data , input_bits , input_shape , table_bits , io_type ):
4437 X = generate_data
4538 model = tf .keras .models .Sequential ()
4639 model .add (tf .keras .layers .Activation (input_shape = input_shape , activation = 'softmax' , name = 'softmax' ))
4740 model .compile ()
4841
49- f_type = 'ac_fixed<18,8,true,AC_RND,AC_SAT>' if backend == 'Quartus' else 'ap_fixed<18,8,AP_RND,AP_SAT>'
42+ table_type = f'fixed<{ table_bits } , RND, SAT>'
43+
5044 cfg = hls4ml .utils .config_from_keras_model (model , granularity = 'name' )
5145 cfg ['LayerName' ]['softmax' ]['Strategy' ] = strategy
52- cfg ['LayerName' ]['softmax' ]['inv_table_t' ] = f_type
53- cfg ['LayerName' ]['softmax' ]['exp_table_t' ] = f_type
46+ cfg ['LayerName' ]['softmax' ]['inv_table_t' ] = table_type
47+ cfg ['LayerName' ]['softmax' ]['exp_table_t' ] = table_type
48+ cfg ['LayerName' ]['softmax_input' ]['Precision' ]['result' ] = f'fixed<{ input_bits } >'
5449
55- odir = str (test_root_path / 'hls4mlprj_softmax_{}_{}_{}_{}_{}' ).format (
56- backend , io_type , strategy , function .__name__ , str (input_shape )
50+ odir = str (
51+ test_root_path
52+ / f'hls4mlprj_softmax_{ backend } _{ io_type } _{ strategy } _{ input_shape } _input-bits={ input_bits } _table-bits={ table_bits } '
5753 )
5854 hls_model = hls4ml .converters .convert_from_keras_model (
5955 model , hls_config = cfg , io_type = io_type , output_dir = odir , backend = backend
@@ -73,9 +69,9 @@ def test_softmax(backend, strategy, generate_data, input_shape, io_type, functio
7369@pytest .mark .parametrize ('io_type' , ['io_parallel' , 'io_stream' ])
7470def test_softmax_skipped (backend , io_type ):
7571 X = np .random .rand (100 , 10 )
76- model = tf .keras .models . Sequential ( )
77- model . add ( tf .keras .layers .Dense ( 14 , input_shape = ( 10 ,), name = 'dense' ) )
78- model . add ( tf .keras .layers . Activation ( activation = 'softmax' , name = ' softmax' ) )
72+ dense = tf .keras .layers . Dense ( 14 , input_shape = ( 10 ,), name = 'dense' )
73+ softmax = tf .keras .layers .Activation ( activation = 'softmax' , name = 'softmax' )
74+ model = tf .keras .models . Sequential ([ dense , softmax ] )
7975 model .compile ()
8076
8177 cfg = hls4ml .utils .config_from_keras_model (model , granularity = 'name' )
@@ -92,7 +88,6 @@ def test_softmax_skipped(backend, io_type):
9288 assert len (hls_layers ) == 2
9389
9490 # Verify hls4ml output is equal to Dense output
95- y_keras = model .predict (X )
96- y_hls4ml = hls_model .predict (X ).reshape (y_keras .shape )
97- keras_trace = hls4ml .model .profiling .get_ymodel_keras (model , X )
98- np .testing .assert_allclose (y_hls4ml , keras_trace ['dense' ], rtol = 0 , atol = 2e-2 )
91+ y_keras_dense = dense (X ).numpy () # type: ignore
92+ y_hls4ml = hls_model .predict (X ).reshape (y_keras_dense .shape ) # type: ignore
93+ np .testing .assert_allclose (y_hls4ml , y_keras_dense , rtol = 0 , atol = 2e-2 )
0 commit comments