1010import seaborn as sb
1111
1212from hls4ml .model .graph import ModelGraph
13- from hls4ml .model .layers import GRU , LSTM
13+ from hls4ml .model .layers import GRU , LSTM , SeparableConv1D , SeparableConv2D
1414
1515try :
1616 import qkeras
@@ -184,6 +184,8 @@ def types_hlsmodel(model):
184184 for layer in model .get_layers ():
185185 if isinstance (layer , GRU ) or isinstance (layer , LSTM ):
186186 suffix = ['w' , 'rw' , 'b' , 'rb' ]
187+ elif isinstance (layer , SeparableConv1D ) or isinstance (layer , SeparableConv2D ):
188+ suffix = ['dw' , 'pw' , 'db' , 'pb' ]
187189 else :
188190 suffix = ['w' , 'b' ]
189191 for iw , weight in enumerate (layer .get_weights ()):
@@ -225,6 +227,8 @@ def weights_hlsmodel(model, fmt='longform', plot='boxplot'):
225227 for layer in model .get_layers ():
226228 if isinstance (layer , GRU ) or isinstance (layer , LSTM ):
227229 suffix = ['w' , 'rw' , 'b' , 'rb' ]
230+ elif isinstance (layer , SeparableConv1D ) or isinstance (layer , SeparableConv2D ):
231+ suffix = ['dw' , 'pw' , 'db' , 'pb' ]
228232 else :
229233 suffix = ['w' , 'b' ]
230234 name = layer .name
@@ -343,21 +347,23 @@ def activations_keras(model, X, fmt='longform', plot='boxplot'):
343347 # return summary statistics for matplotlib.axes.Axes.bxp
344348 # or histogram bin edges and heights
345349 data = []
346-
347- for layer in model .layers :
348- print (f" { layer .name } " )
349- if not isinstance (layer , keras .layers .InputLayer ):
350- y = _get_output (layer , X , model .input ).flatten ()
351- y = abs (y [y != 0 ])
352- if len (y ) == 0 :
353- print (f'Activations for { layer .name } are only zeros, ignoring.' )
354- continue
355- if fmt == 'longform' :
356- data ['x' ].extend (y .tolist ())
357- data ['weight' ].extend ([layer .name for i in range (len (y ))])
358- elif fmt == 'summary' :
359- data .append (array_to_summary (y , fmt = plot ))
360- data [- 1 ]['weight' ] = layer .name
350+ outputs = _get_outputs (
351+ [layer for layer in model .layers if not isinstance (layer , keras .layers .InputLayer )], X , model .input
352+ )
353+ outputs = dict (zip ([layer .name for layer in model .layers if not isinstance (layer , keras .layers .InputLayer )], outputs ))
354+ for layer_name , y in outputs .items ():
355+ print (f" { layer_name } " )
356+ y = y .flatten ()
357+ y = abs (y [y != 0 ])
358+ if len (y ) == 0 :
359+ print (f'Activations for { layer_name } are only zeros, ignoring.' )
360+ continue
361+ if fmt == 'longform' :
362+ data ['x' ].extend (y .tolist ())
363+ data ['weight' ].extend ([layer_name for i in range (len (y ))])
364+ elif fmt == 'summary' :
365+ data .append (array_to_summary (y , fmt = plot ))
366+ data [- 1 ]['weight' ] = layer_name
361367
362368 if fmt == 'longform' :
363369 data = pandas .DataFrame (data )
@@ -544,10 +550,10 @@ def _is_ignored_layer(layer):
544550 return False
545551
546552
547- def _get_output ( layer , X , model_input ):
548- """Get output of partial model """
549- partial_model = keras .models .Model (inputs = model_input , outputs = layer .output )
550- y = partial_model .predict (X )
553+ def _get_outputs ( layers , X , model_input ):
554+ """Get outputs of intermediate layers """
555+ partial_models = keras .models .Model (inputs = model_input , outputs = [ layer .output for layer in layers ] )
556+ y = partial_models .predict (X )
551557 return y
552558
553559
@@ -562,37 +568,30 @@ def get_ymodel_keras(keras_model, X):
562568 Returns:
563569 dict: A dictionary in the form {"layer_name": ouput array of layer}.
564570 """
565-
566571 ymodel = {}
567-
572+ traced_layers = []
573+ layer_names = []
568574 for layer in keras_model .layers :
569- print (f"Processing { layer .name } in Keras model..." )
570- if not _is_ignored_layer (layer ):
571- # If the layer has activation integrated then separate them
572- # Note that if the layer is a standalone activation layer then skip this
573- if hasattr (layer , 'activation' ) and not (
574- isinstance (layer , keras .layers .Activation ) or isinstance (layer , qkeras .qlayers .QActivation )
575- ):
576- if layer .activation :
577- if layer .activation .__class__ .__name__ == "linear" :
578- ymodel [layer .name ] = _get_output (layer , X , keras_model .input )
579-
580- else :
581- temp_activation = layer .activation
582- layer .activation = None
583- # Get output for layer without activation
584- ymodel [layer .name ] = _get_output (layer , X , keras_model .input )
585-
586- # Add the activation back
587- layer .activation = temp_activation
588- # Get ouput for activation
589- ymodel [layer .name + f"_{ temp_activation .__class__ .__name__ } " ] = _get_output (
590- layer , X , keras_model .input
591- )
592- else :
593- ymodel [layer .name ] = _get_output (layer , X , keras_model .input )
594- else :
595- ymodel [layer .name ] = _get_output (layer , X , keras_model .input )
575+ if _is_ignored_layer (layer ):
576+ continue
577+ # If the layer has activation integrated then separate them
578+ # Note that if the layer is a standalone activation layer then skip this
579+ name = layer .name
580+ if (
581+ hasattr (layer , "activation" )
582+ and layer .activation .__name__ != "linear"
583+ and not isinstance (layer , (keras .layers .Activation , qkeras .qlayers .QActivation ))
584+ ):
585+ tmp_activation = layer .activation
586+ layer .activation = None
587+ ymodel .update ({layer .name : _get_outputs ([layer ], X , keras_model .input )})
588+ layer .activation = tmp_activation
589+ name = layer .name + f"_{ tmp_activation .__name__ } "
590+ traced_layers .append (layer )
591+ layer_names .append (name )
592+ outputs = _get_outputs (traced_layers , X , keras_model .input )
593+ for name , output in zip (layer_names , outputs ):
594+ ymodel [name ] = output
596595 print ("Done taking outputs for Keras model." )
597596 return ymodel
598597
0 commit comments