Skip to content

Commit aac3f1f

Browse files
committed
Fix missing packages; rename PyTests & pre-commit pt 2.
1 parent 82779ff commit aac3f1f

26 files changed

+231
-124
lines changed

docs/advanced/model_optimization.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ hls4ml Optimization API
33
========================
44

55
Pruning and weight sharing are effective techniques to reduce model footprint and computational requirements. The hls4ml Optimization API introduces hardware-aware pruning and weight sharing.
6-
By defining custom objectives, the algorithm solves a Knapsack optimization problem aimed at maximizing model performance, while keeping the target resource(s) at a minimum. Out-of-the box objectives include network sparsity, GPU FLOPs, Vivado DSPs, memory utilization etc.
6+
By defining custom objectives, the algorithm solves a Knapsack optimization problem aimed at maximizing model performance, while keeping the target resource(s) at a minimum. Out-of-the box objectives include network sparsity, GPU FLOPs, Vivado DSPs, memory utilization etc.
77

88
The code block below showcases three use cases of the hls4ml Optimization API - network sparsity (unstructured pruning), GPU FLOPs (structured pruning) and Vivado DSP utilization (pattern pruning). First, we start with unstructured pruning:
99

@@ -115,6 +115,6 @@ Finally, optimizing Vivado DSPs is possible, given a hls4ml config:
115115
There are two more Vivado "optimizers" - VivadoFFEstimator, aimed at reducing register utilisation and VivadoMultiObjectiveEstimator, aimed at optimising BRAM and DSP utilisation.
116116
Note, to ensure DSPs are optimized, "unrolled" Dense multiplication must be used before synthesing HLS, by modifying the config:
117117
.. code-block:: Python
118-
hls_config = config_from_keras_model(optimized_model)
118+
hls_config = config_from_keras_model(optimized_model)
119119
hls_config['Model']['DenseResourceImplementation'] = 'Unrolled'
120120
# Any addition hls4ml config, such as strategy, reuse factor etc...

hls4ml/optimization/__init__.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from hls4ml.optimization.attributes import get_attributes_from_keras_model_and_hls4ml_config
44
from hls4ml.optimization.keras import optimize_model
55

6+
default_regularization_range = np.logspace(-6, -2, num=16).tolist()
7+
68

79
def optimize_keras_for_hls4ml(
810
keras_model,
@@ -20,7 +22,7 @@ def optimize_keras_for_hls4ml(
2022
validation_metric,
2123
increasing,
2224
rtol,
23-
callbacks=[],
25+
callbacks=None,
2426
ranking_metric='l1',
2527
local=False,
2628
verbose=False,
@@ -29,16 +31,18 @@ def optimize_keras_for_hls4ml(
2931
directory='hls4ml-optimization',
3032
tuner='Bayesian',
3133
knapsack_solver='CBC_MIP',
32-
regularization_range=np.logspace(-6, -2, num=16).tolist(),
34+
regularization_range=default_regularization_range,
3335
):
3436
'''
3537
Top-level function for optimizing a Keras model, given hls4ml config and a hardware objective(s)
3638
3739
Args:
3840
- keras_model (keras.Model): Model to be optimized
3941
- hls_config (dict): hls4ml configuration, obtained from hls4ml.utils.config.config_from_keras_model(...)
40-
- objective (hls4ml.optimization.objectives.ObjectiveEstimator): Parameter, hardware or user-defined objective of optimization
41-
- scheduler (hls4ml.optimization.schduler.OptimizationScheduler): Sparsity scheduler, choose between constant, polynomial and binary
42+
- objective (hls4ml.optimization.objectives.ObjectiveEstimator):
43+
Parameter, hardware or user-defined objective of optimization
44+
- scheduler (hls4ml.optimization.schduler.OptimizationScheduler):
45+
Sparsity scheduler, choose between constant, polynomial and binary
4246
- X_train (np.array): Training inputs
4347
- y_train (np.array): Training labels
4448
- X_val (np.array): Validation inputs
@@ -48,19 +52,25 @@ def optimize_keras_for_hls4ml(
4852
- optimizer (keras.optimizers.Optimizer or equivalent-string description): Optimizer used during training
4953
- loss_fn (keras.losses.Loss or equivalent loss description): Loss function used during training
5054
- validation_metric (keras.metrics.Metric or equivalent loss description): Validation metric, used as a baseline
51-
- increasing (boolean): If the metric improves with increased values; e.g. accuracy -> increasing = True, MSE -> increasing = False
52-
- rtol (float): Relative tolerance; pruning stops when pruned_validation_metric < (or >) rtol * baseline_validation_metric
55+
- increasing (boolean): If the metric improves with increased values;
56+
e.g. accuracy -> increasing = True, MSE -> increasing = False
57+
- rtol (float): Relative tolerance;
58+
pruning stops when pruned_validation_metric < (or >) rtol * baseline_validation_metric
5359
5460
Kwargs:
5561
- callbacks (list of keras.callbacks.Callback) Currently not supported, developed in future versions
56-
- ranking_metric (string): Metric used for rannking weights and structures; currently supported l1, l2, saliency and Oracle
62+
- ranking_metric (string): Metric used for rannking weights and structures;
63+
currently supported l1, l2, saliency and Oracle
5764
- local (boolean): Layer-wise or global pruning
5865
- verbose (boolean): Display debug logs during model optimization
59-
- rewinding_epochs (int): Number of epochs to retrain model without weight freezing, allows regrowth of previously pruned weights
60-
- cutoff_bad_trials (int): After how many bad trials (performance below threshold), should model pruning / weight sharing stop
66+
- rewinding_epochs (int): Number of epochs to retrain model without weight freezing,
67+
allows regrowth of previously pruned weights
68+
- cutoff_bad_trials (int): After how many bad trials (performance below threshold),
69+
should model pruning / weight sharing stop
6170
- directory (string): Directory to store temporary results
6271
- tuner (str): Tuning alogorithm, choose between Bayesian, Hyperband and None
63-
- knapsack_solver (str): Algorithm to solve Knapsack problem when optimizing; default usually works well; for very large networks, greedy algorithm might be more suitable
72+
- knapsack_solver (str): Algorithm to solve Knapsack problem when optimizing;
73+
default usually works well; for very large networks, greedy algorithm might be more suitable
6474
- regularization_range (list): List of suitable hyperparameters for weight decay
6575
'''
6676

hls4ml/optimization/attributes.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ def __init__(
3030
if not isinstance(output_precision, (FixedPrecisionType, IntegerPrecisionType)):
3131
raise Exception('Layer weight precision is not in valid format')
3232

33-
if not strategy in ('Latency', 'latency', 'Resource', 'resource'):
33+
if strategy not in ('Latency', 'latency', 'Resource', 'resource'):
3434
raise Exception('Unknown layer strategy')
3535

36-
if not io_type in ('io_parallel', 'io_stream'):
36+
if io_type not in ('io_parallel', 'io_stream'):
3737
raise Exception('Unknown IO type')
3838

3939
self.n_in = n_in
@@ -95,8 +95,10 @@ class LayerAttributes:
9595
- input_shape (tuple): Layer input shape
9696
- output_shape (tuple): Layer output shape
9797
- optimizable (bool): Should optimizations (pruning, weight sharing) be applied to this layer
98-
- optimization_attributes (OptimizationAttributes): Type of optimization, optimization vs weight sharing, block shape and pattern offset
99-
- args (dict): Additional information, e.g. hls4mlAttributes; dictionary so it can be generic enough for different platforms
98+
- optimization_attributes (OptimizationAttributes): Type of optimization,
99+
pruning or weight sharing, block shape and pattern offset
100+
- args (dict): Additional information,
101+
e.g. hls4mlAttributes; dictionary so it can be generic enough for different platforms
100102
'''
101103

102104
def __init__(

hls4ml/optimization/config.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,17 @@
1717
- Dense: Neurons, determined by their outgoing connections (columns in Keras weight tensors)
1818
- Conv2D: Filters (structures of size filt_width x filt_height x n_chan)
1919
- Notes:
20-
- For Dense, it was also possible optimize by incoming connections (rows); however, removing zero neurons becomes harder
20+
- For Dense, it was also possible optimize by incoming connections (rows);
21+
However, removing zero neurons becomes harder because of Keras Surgeon
2122
- For Conv2D, significant literature explored pruning channels; currently not supported
2223
- Supports: All layers in SUPPORTED_LAYERS (hls4ml.optimization.keras)
2324
2425
3. Pattern:
2526
- Pruning: Y
2627
- Weight sharing: Y
27-
- Description: Zeroes out or quantizes all the weights in a group.
28-
Groups are determined by a variable, n, and every n-th weight in the flattened, transposed (Resource) weight tensor is collected and stored in the same group
28+
- Description: Zeroes out or quantizes all the weights in a group
29+
Groups are determined by a variable, n, and every n-th weight in the flattened,
30+
Transposed (Resource) weight tensor is collected and stored in the same group
2931
Equivalent to pruning/quantizing weight processed by the same DSP in hls4ml
3032
- Supports: All layers in SUPPORTED_LAYERS (hls4ml.optimization.keras)
3133

hls4ml/optimization/keras/__init__.py

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from hls4ml.optimization.scheduler import OptimizationScheduler
1717

1818
np_config.enable_numpy_behavior()
19+
default_regularization_range = np.logspace(-6, -2, num=16).tolist()
1920

2021

2122
def optimize_model(
@@ -34,7 +35,7 @@ def optimize_model(
3435
validation_metric,
3536
increasing,
3637
rtol,
37-
callbacks=[],
38+
callbacks=None,
3839
ranking_metric='l1',
3940
local=False,
4041
verbose=False,
@@ -43,46 +44,59 @@ def optimize_model(
4344
directory=TMP_DIRECTORY,
4445
tuner='Bayesian',
4546
knapsack_solver='CBC_MIP',
46-
regularization_range=np.logspace(-6, -2, num=16).tolist(),
47+
regularization_range=default_regularization_range,
4748
):
4849
'''
4950
Top-level function for optimizing a Keras model, given objectives
5051
5152
Args:
5253
- model (keras.Model): Model to be optimized
53-
- model_attributes (dict): Layer-wise model attributes, obtained from hls4ml.optimization.get_attributes_from_keras_model(...)
54-
- objective (hls4ml.optimization.objectives.ObjectiveEstimator): Parameter, hardware or user-defined objective of optimization
55-
- scheduler (hls4ml.optimization.schduler.OptimizationScheduler): Sparsity scheduler, choose between constant, polynomial and binary
54+
- model_attributes (dict): Layer-wise model attributes,
55+
obtained from hls4ml.optimization.get_attributes_from_keras_model(...)
56+
- objective (hls4ml.optimization.objectives.ObjectiveEstimator):
57+
Parameter, hardware or user-defined objective of optimization
58+
- scheduler (hls4ml.optimization.schduler.OptimizationScheduler):
59+
Sparsity scheduler, choose between constant, polynomial and binary
5660
- X_train (np.array): Training inputs
5761
- y_train (np.array): Training labels
5862
- X_val (np.array): Validation inputs
5963
- y_val (np.array): Validation labels
6064
- batch_size (int): Batch size during training
6165
- epochs (int): Maximum number of epochs to fine-tune model, in one iteration of pruning
62-
- optimizer (keras.optimizers.Optimizer or equivalent-string description): Optimizer used during training
63-
- loss_fn (keras.losses.Loss or equivalent loss description): Loss function used during training
64-
- validation_metric (keras.metrics.Metric or equivalent loss description): Validation metric, used as a baseline
65-
- increasing (boolean): If the metric improves with increased values; e.g. accuracy -> increasing = True, MSE -> increasing = False
66-
- rtol (float): Relative tolerance; pruning stops when pruned_validation_metric < (or >) rtol * baseline_validation_metric
66+
- optimizer (keras.optimizers.Optimizer or equivalent-string description):
67+
Optimizer used during training
68+
- loss_fn (keras.losses.Loss or equivalent loss description):
69+
Loss function used during training
70+
- validation_metric (keras.metrics.Metric or equivalent loss description):
71+
Validation metric, used as a baseline
72+
- increasing (boolean): If the metric improves with increased values;
73+
e.g. accuracy -> increasing = True, MSE -> increasing = False
74+
- rtol (float): Relative tolerance;
75+
pruning stops when pruned_validation_metric < (or >) rtol * baseline_validation_metric
6776
6877
Kwargs:
6978
- callbacks (list of keras.callbacks.Callback) Currently not supported, developed in future versions
70-
- ranking_metric (string): Metric used for rannking weights and structures; currently supported l1, l2, saliency and Oracle
79+
- ranking_metric (string): Metric used for rannking weights and structures;
80+
currently supported l1, l2, saliency and Oracle
7181
- local (boolean): Layer-wise or global pruning
7282
- verbose (boolean): Display debug logs during model optimization
73-
- rewinding_epochs (int): Number of epochs to retrain model without weight freezing, allows regrowth of previously pruned weights
74-
- cutoff_bad_trials (int): After how many bad trials (performance below threshold), should model pruning / weight sharing stop
83+
- rewinding_epochs (int): Number of epochs to retrain model without weight freezing,
84+
allows regrowth of previously pruned weights
85+
- cutoff_bad_trials (int): After how many bad trials (performance below threshold),
86+
should model pruning / weight sharing stop
7587
- directory (string): Directory to store temporary results
7688
- tuner (str): Tuning alogorithm, choose between Bayesian, Hyperband and None
77-
- knapsack_solver (str): Algorithm to solve Knapsack problem when optimizing; default usually works well; for very large networks, greedy algorithm might be more suitable
89+
- knapsack_solver (str): Algorithm to solve Knapsack problem when optimizing;
90+
default usually works well; for very large networks, greedy algorithm might be more suitable
7891
- regularization_range (list): List of suitable hyperparameters for weight decay
7992
'''
8093

8194
if not isinstance(scheduler, OptimizationScheduler):
8295
raise Exception(
8396
'Scheduler must be an instance of from hls4ml.optimization.scheduler.OptimizationScheduler'
84-
+ 'If you provided string description (e.g. \'constant\'), please use an object instance (i.e. ConstantScheduler())'
85-
'For a full list of supported schedulers and their description, refer to hls4ml.optimization.scheduler.'
97+
'If you provided string description (e.g. \'constant\')'
98+
'Please use an object instance (i.e. ConstantScheduler()).'
99+
'For a full list of supported schedulers, refer to hls4ml.optimization.scheduler.'
86100
)
87101

88102
if epochs <= rewinding_epochs:
@@ -164,7 +178,8 @@ def optimize_model(
164178
masked_backprop = MaskedBackprop(optimizable_model, loss_fn, model_attributes)
165179

166180
# In certain cases, the model might underperform at the current sparsity level, but perform better at a higher sparsity
167-
# Therefore, monitor the models performance over several sparsity levels and only stop pruning after high loss over several trials
181+
# Therefore, monitor the models performance over several sparsity levels and
182+
# Only stop pruning after high loss over several trials
168183
bad_trials = 0
169184
sparsity_conditions = True
170185
target_sparsity = scheduler.get_sparsity()
@@ -222,13 +237,11 @@ def optimize_model(
222237
# Evaluate on validation set and print epoch summary
223238
if verbose:
224239
val_res = optimizable_model.evaluate(validation_dataset, verbose=0, return_dict=False)
225-
print(
226-
f'Epoch: {epoch + 1} - Time: {time.time() - start_time}s - Average training loss: {round(epoch_loss_avg.result(), 3)}'
227-
)
240+
t = time.time() - start_time
241+
avg_loss = round(epoch_loss_avg.result(), 3)
242+
print(f'Epoch: {epoch + 1} - Time: {t}s - Average training loss: {avg_loss}')
228243
print(f'Epoch: {epoch + 1} - learning_rate: {optimizable_model.optimizer.learning_rate.numpy()}')
229-
print(
230-
f'Epoch: {epoch + 1} - Loss on validation set: {val_res[0]} - Performance on validation set: {val_res[1]}'
231-
)
244+
print(f'Epoch: {epoch + 1} - Validation loss: {val_res[0]} - Performance on validation set: {val_res[1]}')
232245

233246
# Check if model works after pruning
234247
pruned_performance = optimizable_model.evaluate(validation_dataset, verbose=0, return_dict=False)[-1]

hls4ml/optimization/keras/builder.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ def build(self, hp):
9090
return model_to_prune
9191

9292

93+
default_regularization_range = np.logspace(-6, -2, num=16).tolist()
94+
95+
9396
def build_optimizable_model(
9497
model,
9598
attributes,
@@ -104,7 +107,7 @@ def build_optimizable_model(
104107
verbose=False,
105108
directory=TMP_DIRECTORY,
106109
tuner='Bayesian',
107-
regularization_range=np.logspace(-6, -2, num=15).tolist(),
110+
regularization_range=default_regularization_range,
108111
):
109112
'''
110113
Function identifying optimizable layers and adding a regularization loss
@@ -128,10 +131,13 @@ def build_optimizable_model(
128131
- learning_rate_range (list): List of suitable hyperparameters for learning rate
129132
130133
Notes:
131-
- In general, the regularization and learning rate ranges do not need to be provided, as the implementation sets a generic enough range.
132-
However, if the user has an idea on the possible range on hyperparameter ranges (eg. VGG-16 weight decay ~10^-5), the tuning will complete faster
133-
- The default tuner is Bayesian & when coupled with the correct ranges of hyperparameters, it performs quite well, fast. However, older version of Keras Tuner had a crashing bug with Bayesian Tuner
134-
- In general, the directory does not need to be specified. However, if pruning several models simultaneously, to avoid conflicting intermediate results, it is useful to specify directory
134+
- In general, the regularization and learning rate ranges do not need to be provided,
135+
as the implementation sets a generic enough range. if the user has an idea on the
136+
possible range on hyperparameter ranges, the tuning will complete faster.
137+
- The default tuner is Bayesian & when coupled with the correct ranges of hyperparameters,
138+
it performs quite well, fast. However, older version of Keras Tuner had a crashing bug with it.
139+
- In general, the directory does not need to be specified. However, if pruning several models simultaneously,
140+
to avoid conflicting intermediate results, it is useful to specify directory.
135141
'''
136142
# User provided manual hyper-parameters for regularisation loss
137143
# TODO - Maybe we could extend this to be hyper-parameters per layer? or layer-type?

hls4ml/optimization/keras/config.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
1515
1. l1 - groups of weights are ranked by their l1 norm
1616
2. l2 - groups of weights are ranked by their l2 norm
17-
3. oracle - abs(dL / dw * w), introduced by Molchanov et al. (2016) Pruning Convolutional Neural Networks for Resource Efficient Inference
17+
3. oracle - abs(dL / dw * w), introduced by Molchanov et al. (2016)
18+
Pruning Convolutional Neural Networks for Resource Efficient Inference
1819
4. saliency - (d^2L / dw^2 * w)^2, introduced by Lecun et al. (1989) Optimal Brain Damage
1920
'''
2021
SUPPORTED_METRICS = ('l1', 'l2', 'oracle', 'saliency')

0 commit comments

Comments
 (0)