From 860176e62319eebaeca0a70f717e26e0c9e93aee Mon Sep 17 00:00:00 2001 From: Bharath Ramaswamy Date: Tue, 14 Jan 2025 02:37:58 +0000 Subject: [PATCH] Added documentation for release 2.0.0 Signed-off-by: Bharath Ramaswamy --- releases/2.0.0/_images/accuracy_list.png | Bin 0 -> 242664 bytes releases/2.0.0/_images/adaround.png | Bin 0 -> 11474 bytes releases/2.0.0/_images/channel_pruning_1.png | Bin 0 -> 27278 bytes releases/2.0.0/_images/compression_flow.png | Bin 0 -> 55762 bytes .../2.0.0/_images/compression_use_case.PNG | Bin 0 -> 46589 bytes releases/2.0.0/_images/cp_2.png | Bin 0 -> 58390 bytes releases/2.0.0/_images/cp_3.jpg | Bin 0 -> 68184 bytes releases/2.0.0/_images/cp_4.jpg | Bin 0 -> 70953 bytes .../2.0.0/_images/cross_layer_scaling.png | Bin 0 -> 88402 bytes releases/2.0.0/_images/greedy_2.png | Bin 0 -> 17884 bytes releases/2.0.0/_images/greedy_3.png | Bin 0 -> 8253 bytes releases/2.0.0/_images/greedy_4.jpg | Bin 0 -> 50524 bytes releases/2.0.0/_images/greedy_5.jpg | Bin 0 -> 31976 bytes .../2.0.0/_images/keras_min_max_ranges.PNG | Bin 0 -> 46462 bytes .../_images/keras_per_layer_mse_loss.PNG | Bin 0 -> 103129 bytes .../_images/keras_per_layer_quant_enabled.PNG | Bin 0 -> 53609 bytes .../2.0.0/_images/keras_post_quant_layer.png | Bin 0 -> 9544 bytes .../2.0.0/_images/keras_pre_quant_layer.png | Bin 0 -> 7062 bytes .../2.0.0/_images/keras_quantsim_callflow.png | Bin 0 -> 9628 bytes releases/2.0.0/_images/keras_weights_pdf.PNG | Bin 0 -> 19691 bytes .../_images/overall_quantization_workflow.png | Bin 0 -> 17785 bytes releases/2.0.0/_images/pareto.png | Bin 0 -> 21364 bytes releases/2.0.0/_images/pareto_curve.png | Bin 0 -> 73478 bytes releases/2.0.0/_images/quant_2.png | Bin 0 -> 301491 bytes releases/2.0.0/_images/quant_3.png | Bin 0 -> 148644 bytes .../_images/quant_analyzer_min_max_ranges.PNG | Bin 0 -> 40000 bytes .../quant_analyzer_per_layer_mse_loss.PNG | Bin 0 -> 72108 bytes ...quant_analyzer_per_layer_quant_enabled.PNG | Bin 0 -> 45404 bytes .../_images/quant_analyzer_weights_pdf.PNG | Bin 0 -> 16257 bytes releases/2.0.0/_images/quant_use_case_1.PNG | Bin 0 -> 19720 bytes releases/2.0.0/_images/quant_use_case_2.PNG | Bin 0 -> 35277 bytes releases/2.0.0/_images/quant_use_case_3.PNG | Bin 0 -> 17060 bytes .../quantization_debugging_flow_chart.png | Bin 0 -> 97284 bytes .../2.0.0/_images/quantization_workflow.png | Bin 0 -> 36946 bytes releases/2.0.0/_images/quantizer_groups.png | Bin 0 -> 27568 bytes releases/2.0.0/_images/quantsim2.0.png | Bin 0 -> 108216 bytes .../2.0.0/_images/quantsim_config_file.png | Bin 0 -> 23721 bytes releases/2.0.0/_images/spatial_svd.png | Bin 0 -> 43692 bytes releases/2.0.0/_images/stages.png | Bin 0 -> 13789 bytes releases/2.0.0/_images/vis_1.png | Bin 0 -> 14614 bytes releases/2.0.0/_images/vis_4.png | Bin 0 -> 144633 bytes releases/2.0.0/_images/vis_5.png | Bin 0 -> 15286 bytes releases/2.0.0/_images/vis_6.png | Bin 0 -> 14581 bytes releases/2.0.0/_images/vis_7.png | Bin 0 -> 50987 bytes releases/2.0.0/_images/weight_svd.png | Bin 0 -> 58733 bytes releases/2.0.0/_images/winnow_1.png | Bin 0 -> 26858 bytes releases/2.0.0/_images/winnow_2.png | Bin 0 -> 38602 bytes releases/2.0.0/_images/work_flow_amp.png | Bin 0 -> 25147 bytes .../2.0.0/_modules/aimet_common/defs.html | 753 +++++ .../aimet_onnx/adaround/adaround_weight.html | 703 +++++ .../aimet_onnx/amp/mixed_precision_algo.html | 887 ++++++ .../aimet_onnx/amp/quantizer_groups.html | 731 +++++ .../_modules/aimet_onnx/auto_quant_v2.html | 2041 ++++++++++++ .../_modules/aimet_onnx/batch_norm_fold.html | 817 +++++ .../aimet_onnx/cross_layer_equalization.html | 709 +++++ .../aimet_onnx/layer_output_utils.html | 512 +++ .../_modules/aimet_onnx/mixed_precision.html | 457 +++ .../_modules/aimet_onnx/quant_analyzer.html | 998 ++++++ .../2.0.0/_modules/aimet_onnx/quantsim.html | 1601 ++++++++++ .../aimet_onnx/sequential_mse/seq_mse.html | 979 ++++++ .../keras/adaround_weight.html | 698 +++++ .../keras/amp/quantizer_groups.html | 749 +++++ .../aimet_tensorflow/keras/auto_quant_v2.html | 2018 ++++++++++++ .../keras/batch_norm_fold.html | 1363 ++++++++ .../keras/bn_reestimation.html | 463 +++ .../aimet_tensorflow/keras/compress.html | 445 +++ .../keras/cross_layer_equalization.html | 828 +++++ .../_modules/aimet_tensorflow/keras/defs.html | 462 +++ .../keras/layer_output_utils.html | 493 +++ .../keras/mixed_precision.html | 520 +++ .../keras/model_preparer.html | 1302 ++++++++ .../keras/quant_analyzer.html | 965 ++++++ .../aimet_tensorflow/keras/quantsim.html | 1203 +++++++ .../_base/adaround/adaround_weight.html | 921 ++++++ .../_base/amp/mixed_precision_algo.html | 924 ++++++ .../_base/amp/quantizer_groups.html | 838 +++++ .../aimet_torch/_base/mixed_precision.html | 464 +++ .../_modules/aimet_torch/_base/seq_mse.html | 904 ++++++ .../_modules/aimet_torch/bn_reestimation.html | 517 +++ .../2.0.0/_modules/aimet_torch/compress.html | 448 +++ .../aimet_torch/cross_layer_equalization.html | 1079 +++++++ releases/2.0.0/_modules/aimet_torch/defs.html | 599 ++++ .../aimet_torch/layer_output_utils.html | 746 +++++ .../_modules/aimet_torch/model_preparer.html | 1114 +++++++ .../model_validator/model_validator.html | 434 +++ releases/2.0.0/_modules/aimet_torch/peft.html | 840 +++++ .../_modules/aimet_torch/v1/auto_quant.html | 995 ++++++ .../aimet_torch/v1/quant_analyzer.html | 488 +++ .../_modules/aimet_torch/v1/quantsim.html | 1049 +++++++ .../_modules/aimet_torch/v2/auto_quant.html | 1035 ++++++ .../aimet_torch/v2/mixed_precision.html | 383 +++ .../manual_mixed_precision.html | 533 ++++ .../aimet_torch/v2/nn/true_quant.html | 2791 +++++++++++++++++ .../aimet_torch/v2/quant_analyzer.html | 503 +++ .../v2/quantization/affine/backends.html | 730 +++++ .../v2/quantization/affine/quantizer.html | 1183 +++++++ .../v2/quantization/float/quantizer.html | 690 ++++ .../aimet_torch/v2/quantization/tensor.html | 873 ++++++ .../aimet_torch/v2/quantsim/config_utils.html | 790 +++++ .../aimet_torch/v2/quantsim/quantsim.html | 938 ++++++ .../quant_stats_visualization.html | 1173 +++++++ releases/2.0.0/_modules/index.html | 382 +++ .../_sphinx_design_static/design-tabs.js | 101 + .../sphinx-design.min.css | 1 + releases/2.0.0/_static/aimet-furo.css | 98 + releases/2.0.0/_static/basic.css | 914 ++++++ releases/2.0.0/_static/check-solid.svg | 4 + releases/2.0.0/_static/clipboard.min.js | 7 + releases/2.0.0/_static/copy-button.svg | 5 + releases/2.0.0/_static/copybutton.css | 94 + releases/2.0.0/_static/copybutton.js | 248 ++ releases/2.0.0/_static/copybutton_funcs.js | 73 + releases/2.0.0/_static/debug.css | 69 + releases/2.0.0/_static/design-tabs.js | 101 + releases/2.0.0/_static/doctools.js | 149 + .../2.0.0/_static/documentation_options.js | 13 + releases/2.0.0/_static/file.png | Bin 0 -> 286 bytes releases/2.0.0/_static/language_data.js | 192 ++ releases/2.0.0/_static/minus.png | Bin 0 -> 90 bytes .../_static/nbsphinx-broken-thumbnail.svg | 9 + .../2.0.0/_static/nbsphinx-code-cells.css | 259 ++ releases/2.0.0/_static/nbsphinx-gallery.css | 31 + .../2.0.0/_static/nbsphinx-no-thumbnail.svg | 9 + releases/2.0.0/_static/plus.png | Bin 0 -> 90 bytes releases/2.0.0/_static/pygments.css | 249 ++ .../2.0.0/_static/scripts/furo-extensions.js | 0 releases/2.0.0/_static/scripts/furo.js | 3 + .../2.0.0/_static/scripts/furo.js.LICENSE.txt | 7 + releases/2.0.0/_static/scripts/furo.js.map | 1 + releases/2.0.0/_static/searchtools.js | 632 ++++ releases/2.0.0/_static/skeleton.css | 296 ++ releases/2.0.0/_static/sphinx-design.min.css | 1 + releases/2.0.0/_static/sphinx_highlight.js | 154 + .../2.0.0/_static/styles/furo-extensions.css | 2 + .../_static/styles/furo-extensions.css.map | 1 + releases/2.0.0/_static/styles/furo.css | 2 + releases/2.0.0/_static/styles/furo.css.map | 1 + releases/2.0.0/apiref/index.html | 387 +++ releases/2.0.0/apiref/onnx/adaround.html | 438 +++ releases/2.0.0/apiref/onnx/amp.html | 594 ++++ releases/2.0.0/apiref/onnx/autoquant.html | 512 +++ releases/2.0.0/apiref/onnx/bnf.html | 387 +++ releases/2.0.0/apiref/onnx/cle.html | 381 +++ releases/2.0.0/apiref/onnx/index.html | 365 +++ .../apiref/onnx/layer_output_generation.html | 401 +++ releases/2.0.0/apiref/onnx/lpbq.html | 398 +++ .../2.0.0/apiref/onnx/quant_analyzer.html | 648 ++++ releases/2.0.0/apiref/onnx/quantsim.html | 495 +++ releases/2.0.0/apiref/onnx/seq_mse.html | 406 +++ .../2.0.0/apiref/tensorflow/adaround.html | 420 +++ releases/2.0.0/apiref/tensorflow/amp.html | 587 ++++ .../2.0.0/apiref/tensorflow/autoquant.html | 512 +++ releases/2.0.0/apiref/tensorflow/bn.html | 392 +++ releases/2.0.0/apiref/tensorflow/bnf.html | 388 +++ releases/2.0.0/apiref/tensorflow/cle.html | 387 +++ .../2.0.0/apiref/tensorflow/compress.html | 503 +++ releases/2.0.0/apiref/tensorflow/index.html | 365 +++ .../tensorflow/layer_output_generation.html | 400 +++ .../apiref/tensorflow/model_preparer.html | 607 ++++ .../apiref/tensorflow/quant_analyzer.html | 597 ++++ .../2.0.0/apiref/tensorflow/quantsim.html | 491 +++ releases/2.0.0/apiref/torch/adaround.html | 431 +++ releases/2.0.0/apiref/torch/autoquant.html | 524 ++++ releases/2.0.0/apiref/torch/bn.html | 393 +++ releases/2.0.0/apiref/torch/bnf.html | 391 +++ releases/2.0.0/apiref/torch/cle.html | 386 +++ releases/2.0.0/apiref/torch/compress.html | 645 ++++ .../aimet_torch.nn.QuantizationMixin.html | 660 ++++ ...t_torch.nn.QuantizedAdaptiveAvgPool1d.html | 384 +++ ...t_torch.nn.QuantizedAdaptiveAvgPool2d.html | 384 +++ ...t_torch.nn.QuantizedAdaptiveAvgPool3d.html | 384 +++ ...t_torch.nn.QuantizedAdaptiveMaxPool1d.html | 384 +++ ...t_torch.nn.QuantizedAdaptiveMaxPool2d.html | 384 +++ ...t_torch.nn.QuantizedAdaptiveMaxPool3d.html | 384 +++ .../aimet_torch.nn.QuantizedAlphaDropout.html | 384 +++ .../aimet_torch.nn.QuantizedAvgPool1d.html | 384 +++ .../aimet_torch.nn.QuantizedAvgPool2d.html | 384 +++ .../aimet_torch.nn.QuantizedAvgPool3d.html | 384 +++ .../aimet_torch.nn.QuantizedBCELoss.html | 384 +++ ...t_torch.nn.QuantizedBCEWithLogitsLoss.html | 384 +++ .../aimet_torch.nn.QuantizedBatchNorm1d.html | 384 +++ .../aimet_torch.nn.QuantizedBatchNorm2d.html | 384 +++ .../aimet_torch.nn.QuantizedBatchNorm3d.html | 384 +++ .../aimet_torch.nn.QuantizedBilinear.html | 384 +++ .../aimet_torch.nn.QuantizedCELU.html | 384 +++ .../aimet_torch.nn.QuantizedCTCLoss.html | 384 +++ ...imet_torch.nn.QuantizedChannelShuffle.html | 384 +++ ...aimet_torch.nn.QuantizedCircularPad1d.html | 384 +++ ...aimet_torch.nn.QuantizedCircularPad2d.html | 384 +++ ...aimet_torch.nn.QuantizedCircularPad3d.html | 384 +++ ...aimet_torch.nn.QuantizedConstantPad1d.html | 384 +++ ...aimet_torch.nn.QuantizedConstantPad2d.html | 384 +++ ...aimet_torch.nn.QuantizedConstantPad3d.html | 384 +++ .../aimet_torch.nn.QuantizedConv1d.html | 384 +++ .../aimet_torch.nn.QuantizedConv2d.html | 384 +++ .../aimet_torch.nn.QuantizedConv3d.html | 384 +++ ...met_torch.nn.QuantizedConvTranspose1d.html | 384 +++ ...met_torch.nn.QuantizedConvTranspose2d.html | 384 +++ ...met_torch.nn.QuantizedConvTranspose3d.html | 384 +++ ...torch.nn.QuantizedCosineEmbeddingLoss.html | 384 +++ ...et_torch.nn.QuantizedCosineSimilarity.html | 384 +++ ...et_torch.nn.QuantizedCrossEntropyLoss.html | 384 +++ .../aimet_torch.nn.QuantizedDropout.html | 384 +++ .../aimet_torch.nn.QuantizedDropout1d.html | 384 +++ .../aimet_torch.nn.QuantizedDropout2d.html | 384 +++ .../aimet_torch.nn.QuantizedDropout3d.html | 384 +++ .../aimet_torch.nn.QuantizedELU.html | 384 +++ .../aimet_torch.nn.QuantizedEmbedding.html | 384 +++ .../aimet_torch.nn.QuantizedEmbeddingBag.html | 384 +++ ...torch.nn.QuantizedFeatureAlphaDropout.html | 384 +++ .../aimet_torch.nn.QuantizedFlatten.html | 384 +++ .../aimet_torch.nn.QuantizedFold.html | 384 +++ ...torch.nn.QuantizedFractionalMaxPool2d.html | 384 +++ ...torch.nn.QuantizedFractionalMaxPool3d.html | 384 +++ .../aimet_torch.nn.QuantizedGELU.html | 384 +++ .../aimet_torch.nn.QuantizedGLU.html | 384 +++ .../aimet_torch.nn.QuantizedGRU.html | 384 +++ .../aimet_torch.nn.QuantizedGRUCell.html | 384 +++ ...met_torch.nn.QuantizedGaussianNLLLoss.html | 384 +++ .../aimet_torch.nn.QuantizedGroupNorm.html | 384 +++ .../aimet_torch.nn.QuantizedHardshrink.html | 384 +++ .../aimet_torch.nn.QuantizedHardsigmoid.html | 384 +++ .../aimet_torch.nn.QuantizedHardswish.html | 384 +++ .../aimet_torch.nn.QuantizedHardtanh.html | 384 +++ ..._torch.nn.QuantizedHingeEmbeddingLoss.html | 384 +++ .../aimet_torch.nn.QuantizedHuberLoss.html | 384 +++ ...imet_torch.nn.QuantizedInstanceNorm1d.html | 384 +++ ...imet_torch.nn.QuantizedInstanceNorm2d.html | 384 +++ ...imet_torch.nn.QuantizedInstanceNorm3d.html | 384 +++ .../aimet_torch.nn.QuantizedKLDivLoss.html | 384 +++ .../aimet_torch.nn.QuantizedL1Loss.html | 384 +++ .../aimet_torch.nn.QuantizedLPPool1d.html | 384 +++ .../aimet_torch.nn.QuantizedLPPool2d.html | 384 +++ .../aimet_torch.nn.QuantizedLSTM.html | 384 +++ .../aimet_torch.nn.QuantizedLSTMCell.html | 384 +++ .../aimet_torch.nn.QuantizedLayerNorm.html | 384 +++ .../aimet_torch.nn.QuantizedLeakyReLU.html | 384 +++ .../aimet_torch.nn.QuantizedLinear.html | 404 +++ ...t_torch.nn.QuantizedLocalResponseNorm.html | 384 +++ .../aimet_torch.nn.QuantizedLogSigmoid.html | 384 +++ .../aimet_torch.nn.QuantizedLogSoftmax.html | 384 +++ .../aimet_torch.nn.QuantizedMSELoss.html | 384 +++ ...t_torch.nn.QuantizedMarginRankingLoss.html | 384 +++ .../aimet_torch.nn.QuantizedMaxPool1d.html | 384 +++ .../aimet_torch.nn.QuantizedMaxPool2d.html | 384 +++ .../aimet_torch.nn.QuantizedMaxPool3d.html | 384 +++ .../aimet_torch.nn.QuantizedMaxUnpool1d.html | 384 +++ .../aimet_torch.nn.QuantizedMaxUnpool2d.html | 384 +++ .../aimet_torch.nn.QuantizedMaxUnpool3d.html | 384 +++ .../aimet_torch.nn.QuantizedMish.html | 384 +++ ...orch.nn.QuantizedMultiLabelMarginLoss.html | 384 +++ ....nn.QuantizedMultiLabelSoftMarginLoss.html | 384 +++ ...met_torch.nn.QuantizedMultiMarginLoss.html | 384 +++ .../aimet_torch.nn.QuantizedNLLLoss.html | 384 +++ .../aimet_torch.nn.QuantizedNLLLoss2d.html | 384 +++ .../aimet_torch.nn.QuantizedPReLU.html | 384 +++ ...et_torch.nn.QuantizedPairwiseDistance.html | 384 +++ .../aimet_torch.nn.QuantizedPixelShuffle.html | 384 +++ ...imet_torch.nn.QuantizedPixelUnshuffle.html | 384 +++ ...imet_torch.nn.QuantizedPoissonNLLLoss.html | 384 +++ .../aimet_torch.nn.QuantizedRNN.html | 384 +++ .../aimet_torch.nn.QuantizedRNNCell.html | 384 +++ .../aimet_torch.nn.QuantizedRReLU.html | 384 +++ .../aimet_torch.nn.QuantizedReLU.html | 384 +++ .../aimet_torch.nn.QuantizedReLU6.html | 384 +++ ...met_torch.nn.QuantizedReflectionPad1d.html | 384 +++ ...met_torch.nn.QuantizedReflectionPad2d.html | 384 +++ ...met_torch.nn.QuantizedReflectionPad3d.html | 384 +++ ...et_torch.nn.QuantizedReplicationPad1d.html | 384 +++ ...et_torch.nn.QuantizedReplicationPad2d.html | 384 +++ ...et_torch.nn.QuantizedReplicationPad3d.html | 384 +++ .../aimet_torch.nn.QuantizedSELU.html | 384 +++ .../aimet_torch.nn.QuantizedSiLU.html | 384 +++ .../aimet_torch.nn.QuantizedSigmoid.html | 384 +++ .../aimet_torch.nn.QuantizedSmoothL1Loss.html | 384 +++ ...imet_torch.nn.QuantizedSoftMarginLoss.html | 384 +++ .../aimet_torch.nn.QuantizedSoftmax.html | 384 +++ .../aimet_torch.nn.QuantizedSoftmax2d.html | 384 +++ .../aimet_torch.nn.QuantizedSoftmin.html | 384 +++ .../aimet_torch.nn.QuantizedSoftplus.html | 384 +++ .../aimet_torch.nn.QuantizedSoftshrink.html | 384 +++ .../aimet_torch.nn.QuantizedSoftsign.html | 384 +++ .../aimet_torch.nn.QuantizedTanh.html | 384 +++ .../aimet_torch.nn.QuantizedTanhshrink.html | 384 +++ .../aimet_torch.nn.QuantizedThreshold.html | 384 +++ ...t_torch.nn.QuantizedTripletMarginLoss.html | 384 +++ ...uantizedTripletMarginWithDistanceLoss.html | 384 +++ .../aimet_torch.nn.QuantizedUnflatten.html | 384 +++ .../aimet_torch.nn.QuantizedUnfold.html | 384 +++ .../aimet_torch.nn.QuantizedUpsample.html | 384 +++ ...orch.nn.QuantizedUpsamplingBilinear2d.html | 384 +++ ...torch.nn.QuantizedUpsamplingNearest2d.html | 384 +++ .../aimet_torch.nn.QuantizedZeroPad1d.html | 384 +++ .../aimet_torch.nn.QuantizedZeroPad2d.html | 384 +++ .../aimet_torch.nn.QuantizedZeroPad3d.html | 384 +++ ..._torch.quantization.DequantizedTensor.html | 442 +++ ...et_torch.quantization.QuantizedTensor.html | 445 +++ ...orch.quantization.QuantizedTensorBase.html | 518 +++ ...et_torch.quantization.affine.Quantize.html | 476 +++ ...uantization.affine.QuantizeDequantize.html | 492 +++ ..._torch.quantization.affine.dequantize.html | 398 +++ ...et_torch.quantization.affine.quantize.html | 499 +++ ...antization.affine.quantize_dequantize.html | 508 +++ ...ization.float.FloatQuantizeDequantize.html | 561 ++++ releases/2.0.0/apiref/torch/index.html | 419 +++ .../torch/interactive_visualization.html | 420 +++ .../apiref/torch/layer_output_generation.html | 437 +++ releases/2.0.0/apiref/torch/lpbq.html | 531 ++++ .../2.0.0/apiref/torch/migration_guide.html | 676 ++++ .../2.0.0/apiref/torch/model_preparer.html | 673 ++++ .../2.0.0/apiref/torch/model_validator.html | 566 ++++ releases/2.0.0/apiref/torch/mp.html | 588 ++++ releases/2.0.0/apiref/torch/nn.html | 957 ++++++ releases/2.0.0/apiref/torch/peft_lora.html | 659 ++++ .../2.0.0/apiref/torch/quant_analyzer.html | 623 ++++ releases/2.0.0/apiref/torch/quantization.html | 734 +++++ releases/2.0.0/apiref/torch/quantsim.html | 623 ++++ releases/2.0.0/apiref/torch/seq_mse.html | 437 +++ releases/2.0.0/apiref/torch/v1/adaround.html | 436 +++ releases/2.0.0/apiref/torch/v1/amp.html | 560 ++++ releases/2.0.0/apiref/torch/v1/autoquant.html | 529 ++++ .../2.0.0/apiref/torch/v1/quant_analyzer.html | 628 ++++ releases/2.0.0/apiref/torch/v1/quantsim.html | 561 ++++ releases/2.0.0/apiref/torch/v1/seq_mse.html | 442 +++ releases/2.0.0/examples/index.html | 546 ++++ .../2.0.0/examples/onnx/quantization/AMP.html | 774 +++++ .../examples/onnx/quantization/AMP.ipynb | 705 +++++ .../examples/onnx/quantization/adaround.html | 754 +++++ .../examples/onnx/quantization/adaround.ipynb | 578 ++++ .../2.0.0/examples/onnx/quantization/cle.html | 725 +++++ .../examples/onnx/quantization/cle.ipynb | 603 ++++ .../examples/onnx/quantization/quantsim.html | 640 ++++ .../examples/onnx/quantization/quantsim.ipynb | 488 +++ .../quantization/keras/KerasAMP.html | 716 +++++ .../quantization/keras/KerasAMP.ipynb | 468 +++ .../quantization/keras/adaround.html | 692 ++++ .../quantization/keras/adaround.ipynb | 522 +++ .../quantization/keras/autoquant.html | 595 ++++ .../quantization/keras/autoquant.ipynb | 378 +++ .../quantization/keras/bn_reestimation.html | 773 +++++ .../quantization/keras/bn_reestimation.ipynb | 624 ++++ .../keras/keras_transformer_qat.html | 569 ++++ .../keras/keras_transformer_qat.ipynb | 461 +++ .../quantization/keras/model_preparer.html | 589 ++++ .../quantization/keras/model_preparer.ipynb | 326 ++ .../tensorflow/quantization/keras/qat.html | 629 ++++ .../tensorflow/quantization/keras/qat.ipynb | 511 +++ .../keras/qat_range_learning.html | 629 ++++ .../keras/qat_range_learning.ipynb | 491 +++ .../quantization/keras/quant_analyzer.html | 658 ++++ .../quantization/keras/quant_analyzer.ipynb | 459 +++ .../keras/quantsim_adaround_pcq.html | 668 ++++ .../keras/quantsim_adaround_pcq.ipynb | 498 +++ .../quantization/keras/quantsim_cle.html | 670 ++++ .../quantization/keras/quantsim_cle.ipynb | 504 +++ .../torch/compression/channel_pruning.html | 642 ++++ .../torch/compression/channel_pruning.ipynb | 434 +++ .../torch/compression/spatial_svd.html | 621 ++++ .../torch/compression/spatial_svd.ipynb | 413 +++ .../spatial_svd_channel_pruning.html | 737 +++++ .../spatial_svd_channel_pruning.ipynb | 587 ++++ .../examples/torch/quantization/AMP.html | 799 +++++ .../examples/torch/quantization/AMP.ipynb | 765 +++++ .../examples/torch/quantization/adaround.html | 747 +++++ .../torch/quantization/adaround.ipynb | 593 ++++ .../torch/quantization/autoquant.html | 594 ++++ .../torch/quantization/autoquant.ipynb | 371 +++ .../torch/quantization/bn_reestimation.html | 653 ++++ .../torch/quantization/bn_reestimation.ipynb | 409 +++ .../examples/torch/quantization/cle_bc.html | 808 +++++ .../examples/torch/quantization/cle_bc.ipynb | 665 ++++ .../examples/torch/quantization/qat.html | 722 +++++ .../examples/torch/quantization/qat.ipynb | 565 ++++ .../quantization/qat_range_learning.html | 723 +++++ .../quantization/qat_range_learning.ipynb | 563 ++++ .../torch/quantization/quant_analyzer.html | 720 +++++ .../torch/quantization/quant_analyzer.ipynb | 574 ++++ releases/2.0.0/featureguide/adaround.html | 1057 +++++++ .../featureguide/analysis tools/index.html | 390 +++ .../interactive_visualization.html | 442 +++ .../layer_output_generation.html | 709 +++++ .../analysis tools/quant_analyzer.html | 1649 ++++++++++ releases/2.0.0/featureguide/autoquant.html | 1480 +++++++++ releases/2.0.0/featureguide/bn.html | 675 ++++ releases/2.0.0/featureguide/bnf.html | 823 +++++ releases/2.0.0/featureguide/cle.html | 760 +++++ .../compression/channel_pruning.html | 727 +++++ .../compression/feature_guidebook.html | 408 +++ .../greedy_compression_ratio_selection.html | 421 +++ .../2.0.0/featureguide/compression/index.html | 487 +++ .../featureguide/compression/spatial_svd.html | 964 ++++++ .../visualization_compression.html | 451 +++ .../featureguide/compression/weight_svd.html | 693 ++++ .../featureguide/compression/winnowing.html | 415 +++ releases/2.0.0/featureguide/index.html | 420 +++ .../featureguide/mixed precision/amp.html | 1537 +++++++++ .../featureguide/mixed precision/index.html | 398 +++ .../featureguide/mixed precision/mmp.html | 628 ++++ releases/2.0.0/featureguide/seq_mse.html | 612 ++++ releases/2.0.0/genindex.html | 1392 ++++++++ releases/2.0.0/glossary.html | 444 +++ releases/2.0.0/index.html | 417 +++ releases/2.0.0/install/basic_install.html | 329 ++ releases/2.0.0/install/index.html | 544 ++++ releases/2.0.0/install/install_docker.html | 583 ++++ releases/2.0.0/install/install_host.html | 597 ++++ releases/2.0.0/install/quick-start.html | 506 +++ releases/2.0.0/objects.inv | Bin 0 -> 50211 bytes releases/2.0.0/quantsim/advanced.html | 745 +++++ releases/2.0.0/quantsim/calibration.html | 1330 ++++++++ releases/2.0.0/quantsim/encoding_spec.html | 686 ++++ releases/2.0.0/quantsim/index.html | 590 ++++ releases/2.0.0/quantsim/qat.html | 1038 ++++++ releases/2.0.0/quantsim/runtime_config.html | 668 ++++ .../quantsim/tensorflow/model_guidelines.html | 389 +++ .../quantsim/torch/model_guidelines.html | 465 +++ releases/2.0.0/release_notes.html | 1099 +++++++ releases/2.0.0/search.html | 343 ++ releases/2.0.0/searchindex.js | 1 + .../2.0.0/userguide/debugging_guidelines.html | 447 +++ releases/2.0.0/userguide/index.html | 386 +++ .../2.0.0/userguide/on_target_inference.html | 519 +++ .../userguide/quantization_workflow.html | 523 +++ releases/2.0.0/versions.html | 358 +++ releases/latest | 2 +- 425 files changed, 192398 insertions(+), 1 deletion(-) create mode 100644 releases/2.0.0/_images/accuracy_list.png create mode 100644 releases/2.0.0/_images/adaround.png create mode 100644 releases/2.0.0/_images/channel_pruning_1.png create mode 100644 releases/2.0.0/_images/compression_flow.png create mode 100644 releases/2.0.0/_images/compression_use_case.PNG create mode 100644 releases/2.0.0/_images/cp_2.png create mode 100644 releases/2.0.0/_images/cp_3.jpg create mode 100644 releases/2.0.0/_images/cp_4.jpg create mode 100644 releases/2.0.0/_images/cross_layer_scaling.png create mode 100644 releases/2.0.0/_images/greedy_2.png create mode 100644 releases/2.0.0/_images/greedy_3.png create mode 100644 releases/2.0.0/_images/greedy_4.jpg create mode 100644 releases/2.0.0/_images/greedy_5.jpg create mode 100644 releases/2.0.0/_images/keras_min_max_ranges.PNG create mode 100644 releases/2.0.0/_images/keras_per_layer_mse_loss.PNG create mode 100644 releases/2.0.0/_images/keras_per_layer_quant_enabled.PNG create mode 100644 releases/2.0.0/_images/keras_post_quant_layer.png create mode 100644 releases/2.0.0/_images/keras_pre_quant_layer.png create mode 100644 releases/2.0.0/_images/keras_quantsim_callflow.png create mode 100644 releases/2.0.0/_images/keras_weights_pdf.PNG create mode 100644 releases/2.0.0/_images/overall_quantization_workflow.png create mode 100644 releases/2.0.0/_images/pareto.png create mode 100644 releases/2.0.0/_images/pareto_curve.png create mode 100644 releases/2.0.0/_images/quant_2.png create mode 100644 releases/2.0.0/_images/quant_3.png create mode 100644 releases/2.0.0/_images/quant_analyzer_min_max_ranges.PNG create mode 100644 releases/2.0.0/_images/quant_analyzer_per_layer_mse_loss.PNG create mode 100644 releases/2.0.0/_images/quant_analyzer_per_layer_quant_enabled.PNG create mode 100644 releases/2.0.0/_images/quant_analyzer_weights_pdf.PNG create mode 100644 releases/2.0.0/_images/quant_use_case_1.PNG create mode 100644 releases/2.0.0/_images/quant_use_case_2.PNG create mode 100644 releases/2.0.0/_images/quant_use_case_3.PNG create mode 100644 releases/2.0.0/_images/quantization_debugging_flow_chart.png create mode 100644 releases/2.0.0/_images/quantization_workflow.png create mode 100644 releases/2.0.0/_images/quantizer_groups.png create mode 100644 releases/2.0.0/_images/quantsim2.0.png create mode 100644 releases/2.0.0/_images/quantsim_config_file.png create mode 100644 releases/2.0.0/_images/spatial_svd.png create mode 100644 releases/2.0.0/_images/stages.png create mode 100644 releases/2.0.0/_images/vis_1.png create mode 100644 releases/2.0.0/_images/vis_4.png create mode 100644 releases/2.0.0/_images/vis_5.png create mode 100644 releases/2.0.0/_images/vis_6.png create mode 100644 releases/2.0.0/_images/vis_7.png create mode 100644 releases/2.0.0/_images/weight_svd.png create mode 100644 releases/2.0.0/_images/winnow_1.png create mode 100644 releases/2.0.0/_images/winnow_2.png create mode 100644 releases/2.0.0/_images/work_flow_amp.png create mode 100644 releases/2.0.0/_modules/aimet_common/defs.html create mode 100644 releases/2.0.0/_modules/aimet_onnx/adaround/adaround_weight.html create mode 100644 releases/2.0.0/_modules/aimet_onnx/amp/mixed_precision_algo.html create mode 100644 releases/2.0.0/_modules/aimet_onnx/amp/quantizer_groups.html create mode 100644 releases/2.0.0/_modules/aimet_onnx/auto_quant_v2.html create mode 100644 releases/2.0.0/_modules/aimet_onnx/batch_norm_fold.html create mode 100644 releases/2.0.0/_modules/aimet_onnx/cross_layer_equalization.html create mode 100644 releases/2.0.0/_modules/aimet_onnx/layer_output_utils.html create mode 100644 releases/2.0.0/_modules/aimet_onnx/mixed_precision.html create mode 100644 releases/2.0.0/_modules/aimet_onnx/quant_analyzer.html create mode 100644 releases/2.0.0/_modules/aimet_onnx/quantsim.html create mode 100644 releases/2.0.0/_modules/aimet_onnx/sequential_mse/seq_mse.html create mode 100644 releases/2.0.0/_modules/aimet_tensorflow/keras/adaround_weight.html create mode 100644 releases/2.0.0/_modules/aimet_tensorflow/keras/amp/quantizer_groups.html create mode 100644 releases/2.0.0/_modules/aimet_tensorflow/keras/auto_quant_v2.html create mode 100644 releases/2.0.0/_modules/aimet_tensorflow/keras/batch_norm_fold.html create mode 100644 releases/2.0.0/_modules/aimet_tensorflow/keras/bn_reestimation.html create mode 100644 releases/2.0.0/_modules/aimet_tensorflow/keras/compress.html create mode 100644 releases/2.0.0/_modules/aimet_tensorflow/keras/cross_layer_equalization.html create mode 100644 releases/2.0.0/_modules/aimet_tensorflow/keras/defs.html create mode 100644 releases/2.0.0/_modules/aimet_tensorflow/keras/layer_output_utils.html create mode 100644 releases/2.0.0/_modules/aimet_tensorflow/keras/mixed_precision.html create mode 100644 releases/2.0.0/_modules/aimet_tensorflow/keras/model_preparer.html create mode 100644 releases/2.0.0/_modules/aimet_tensorflow/keras/quant_analyzer.html create mode 100644 releases/2.0.0/_modules/aimet_tensorflow/keras/quantsim.html create mode 100644 releases/2.0.0/_modules/aimet_torch/_base/adaround/adaround_weight.html create mode 100644 releases/2.0.0/_modules/aimet_torch/_base/amp/mixed_precision_algo.html create mode 100644 releases/2.0.0/_modules/aimet_torch/_base/amp/quantizer_groups.html create mode 100644 releases/2.0.0/_modules/aimet_torch/_base/mixed_precision.html create mode 100644 releases/2.0.0/_modules/aimet_torch/_base/seq_mse.html create mode 100644 releases/2.0.0/_modules/aimet_torch/bn_reestimation.html create mode 100644 releases/2.0.0/_modules/aimet_torch/compress.html create mode 100644 releases/2.0.0/_modules/aimet_torch/cross_layer_equalization.html create mode 100644 releases/2.0.0/_modules/aimet_torch/defs.html create mode 100644 releases/2.0.0/_modules/aimet_torch/layer_output_utils.html create mode 100644 releases/2.0.0/_modules/aimet_torch/model_preparer.html create mode 100644 releases/2.0.0/_modules/aimet_torch/model_validator/model_validator.html create mode 100644 releases/2.0.0/_modules/aimet_torch/peft.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v1/auto_quant.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v1/quant_analyzer.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v1/quantsim.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v2/auto_quant.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v2/mixed_precision.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v2/mixed_precision/manual_mixed_precision.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v2/nn/true_quant.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v2/quant_analyzer.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v2/quantization/affine/backends.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v2/quantization/affine/quantizer.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v2/quantization/float/quantizer.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v2/quantization/tensor.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v2/quantsim/config_utils.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v2/quantsim/quantsim.html create mode 100644 releases/2.0.0/_modules/aimet_torch/v2/visualization_tools/quant_stats_visualization.html create mode 100644 releases/2.0.0/_modules/index.html create mode 100644 releases/2.0.0/_sphinx_design_static/design-tabs.js create mode 100644 releases/2.0.0/_sphinx_design_static/sphinx-design.min.css create mode 100644 releases/2.0.0/_static/aimet-furo.css create mode 100644 releases/2.0.0/_static/basic.css create mode 100644 releases/2.0.0/_static/check-solid.svg create mode 100644 releases/2.0.0/_static/clipboard.min.js create mode 100644 releases/2.0.0/_static/copy-button.svg create mode 100644 releases/2.0.0/_static/copybutton.css create mode 100644 releases/2.0.0/_static/copybutton.js create mode 100644 releases/2.0.0/_static/copybutton_funcs.js create mode 100644 releases/2.0.0/_static/debug.css create mode 100644 releases/2.0.0/_static/design-tabs.js create mode 100644 releases/2.0.0/_static/doctools.js create mode 100644 releases/2.0.0/_static/documentation_options.js create mode 100644 releases/2.0.0/_static/file.png create mode 100644 releases/2.0.0/_static/language_data.js create mode 100644 releases/2.0.0/_static/minus.png create mode 100644 releases/2.0.0/_static/nbsphinx-broken-thumbnail.svg create mode 100644 releases/2.0.0/_static/nbsphinx-code-cells.css create mode 100644 releases/2.0.0/_static/nbsphinx-gallery.css create mode 100644 releases/2.0.0/_static/nbsphinx-no-thumbnail.svg create mode 100644 releases/2.0.0/_static/plus.png create mode 100644 releases/2.0.0/_static/pygments.css create mode 100644 releases/2.0.0/_static/scripts/furo-extensions.js create mode 100644 releases/2.0.0/_static/scripts/furo.js create mode 100644 releases/2.0.0/_static/scripts/furo.js.LICENSE.txt create mode 100644 releases/2.0.0/_static/scripts/furo.js.map create mode 100644 releases/2.0.0/_static/searchtools.js create mode 100644 releases/2.0.0/_static/skeleton.css create mode 100644 releases/2.0.0/_static/sphinx-design.min.css create mode 100644 releases/2.0.0/_static/sphinx_highlight.js create mode 100644 releases/2.0.0/_static/styles/furo-extensions.css create mode 100644 releases/2.0.0/_static/styles/furo-extensions.css.map create mode 100644 releases/2.0.0/_static/styles/furo.css create mode 100644 releases/2.0.0/_static/styles/furo.css.map create mode 100644 releases/2.0.0/apiref/index.html create mode 100644 releases/2.0.0/apiref/onnx/adaround.html create mode 100644 releases/2.0.0/apiref/onnx/amp.html create mode 100644 releases/2.0.0/apiref/onnx/autoquant.html create mode 100644 releases/2.0.0/apiref/onnx/bnf.html create mode 100644 releases/2.0.0/apiref/onnx/cle.html create mode 100644 releases/2.0.0/apiref/onnx/index.html create mode 100644 releases/2.0.0/apiref/onnx/layer_output_generation.html create mode 100644 releases/2.0.0/apiref/onnx/lpbq.html create mode 100644 releases/2.0.0/apiref/onnx/quant_analyzer.html create mode 100644 releases/2.0.0/apiref/onnx/quantsim.html create mode 100644 releases/2.0.0/apiref/onnx/seq_mse.html create mode 100644 releases/2.0.0/apiref/tensorflow/adaround.html create mode 100644 releases/2.0.0/apiref/tensorflow/amp.html create mode 100644 releases/2.0.0/apiref/tensorflow/autoquant.html create mode 100644 releases/2.0.0/apiref/tensorflow/bn.html create mode 100644 releases/2.0.0/apiref/tensorflow/bnf.html create mode 100644 releases/2.0.0/apiref/tensorflow/cle.html create mode 100644 releases/2.0.0/apiref/tensorflow/compress.html create mode 100644 releases/2.0.0/apiref/tensorflow/index.html create mode 100644 releases/2.0.0/apiref/tensorflow/layer_output_generation.html create mode 100644 releases/2.0.0/apiref/tensorflow/model_preparer.html create mode 100644 releases/2.0.0/apiref/tensorflow/quant_analyzer.html create mode 100644 releases/2.0.0/apiref/tensorflow/quantsim.html create mode 100644 releases/2.0.0/apiref/torch/adaround.html create mode 100644 releases/2.0.0/apiref/torch/autoquant.html create mode 100644 releases/2.0.0/apiref/torch/bn.html create mode 100644 releases/2.0.0/apiref/torch/bnf.html create mode 100644 releases/2.0.0/apiref/torch/cle.html create mode 100644 releases/2.0.0/apiref/torch/compress.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizationMixin.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedAdaptiveAvgPool1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedAdaptiveAvgPool2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedAdaptiveAvgPool3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedAdaptiveMaxPool1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedAdaptiveMaxPool2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedAdaptiveMaxPool3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedAlphaDropout.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedAvgPool1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedAvgPool2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedAvgPool3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedBCELoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedBCEWithLogitsLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedBatchNorm1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedBatchNorm2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedBatchNorm3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedBilinear.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedCELU.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedCTCLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedChannelShuffle.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedCircularPad1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedCircularPad2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedCircularPad3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedConstantPad1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedConstantPad2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedConstantPad3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedConv1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedConv2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedConv3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedConvTranspose1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedConvTranspose2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedConvTranspose3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedCosineEmbeddingLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedCosineSimilarity.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedCrossEntropyLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedDropout.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedDropout1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedDropout2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedDropout3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedELU.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedEmbedding.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedEmbeddingBag.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedFeatureAlphaDropout.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedFlatten.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedFold.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedFractionalMaxPool2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedFractionalMaxPool3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedGELU.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedGLU.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedGRU.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedGRUCell.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedGaussianNLLLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedGroupNorm.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedHardshrink.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedHardsigmoid.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedHardswish.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedHardtanh.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedHingeEmbeddingLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedHuberLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedInstanceNorm1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedInstanceNorm2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedInstanceNorm3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedKLDivLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedL1Loss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedLPPool1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedLPPool2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedLSTM.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedLSTMCell.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedLayerNorm.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedLeakyReLU.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedLinear.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedLocalResponseNorm.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedLogSigmoid.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedLogSoftmax.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedMSELoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedMarginRankingLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedMaxPool1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedMaxPool2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedMaxPool3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedMaxUnpool1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedMaxUnpool2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedMaxUnpool3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedMish.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedMultiLabelMarginLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedMultiLabelSoftMarginLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedMultiMarginLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedNLLLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedNLLLoss2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedPReLU.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedPairwiseDistance.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedPixelShuffle.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedPixelUnshuffle.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedPoissonNLLLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedRNN.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedRNNCell.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedRReLU.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedReLU.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedReLU6.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedReflectionPad1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedReflectionPad2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedReflectionPad3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedReplicationPad1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedReplicationPad2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedReplicationPad3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedSELU.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedSiLU.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedSigmoid.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedSmoothL1Loss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedSoftMarginLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedSoftmax.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedSoftmax2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedSoftmin.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedSoftplus.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedSoftshrink.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedSoftsign.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedTanh.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedTanhshrink.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedThreshold.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedTripletMarginLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedTripletMarginWithDistanceLoss.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedUnflatten.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedUnfold.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedUpsample.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedUpsamplingBilinear2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedUpsamplingNearest2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedZeroPad1d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedZeroPad2d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.nn.QuantizedZeroPad3d.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.quantization.DequantizedTensor.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.quantization.QuantizedTensor.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.quantization.QuantizedTensorBase.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.quantization.affine.Quantize.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.quantization.affine.QuantizeDequantize.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.quantization.affine.dequantize.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.quantization.affine.quantize.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.quantization.affine.quantize_dequantize.html create mode 100644 releases/2.0.0/apiref/torch/generated/aimet_torch.quantization.float.FloatQuantizeDequantize.html create mode 100644 releases/2.0.0/apiref/torch/index.html create mode 100644 releases/2.0.0/apiref/torch/interactive_visualization.html create mode 100644 releases/2.0.0/apiref/torch/layer_output_generation.html create mode 100644 releases/2.0.0/apiref/torch/lpbq.html create mode 100644 releases/2.0.0/apiref/torch/migration_guide.html create mode 100644 releases/2.0.0/apiref/torch/model_preparer.html create mode 100644 releases/2.0.0/apiref/torch/model_validator.html create mode 100644 releases/2.0.0/apiref/torch/mp.html create mode 100644 releases/2.0.0/apiref/torch/nn.html create mode 100644 releases/2.0.0/apiref/torch/peft_lora.html create mode 100644 releases/2.0.0/apiref/torch/quant_analyzer.html create mode 100644 releases/2.0.0/apiref/torch/quantization.html create mode 100644 releases/2.0.0/apiref/torch/quantsim.html create mode 100644 releases/2.0.0/apiref/torch/seq_mse.html create mode 100644 releases/2.0.0/apiref/torch/v1/adaround.html create mode 100644 releases/2.0.0/apiref/torch/v1/amp.html create mode 100644 releases/2.0.0/apiref/torch/v1/autoquant.html create mode 100644 releases/2.0.0/apiref/torch/v1/quant_analyzer.html create mode 100644 releases/2.0.0/apiref/torch/v1/quantsim.html create mode 100644 releases/2.0.0/apiref/torch/v1/seq_mse.html create mode 100644 releases/2.0.0/examples/index.html create mode 100644 releases/2.0.0/examples/onnx/quantization/AMP.html create mode 100644 releases/2.0.0/examples/onnx/quantization/AMP.ipynb create mode 100644 releases/2.0.0/examples/onnx/quantization/adaround.html create mode 100644 releases/2.0.0/examples/onnx/quantization/adaround.ipynb create mode 100644 releases/2.0.0/examples/onnx/quantization/cle.html create mode 100644 releases/2.0.0/examples/onnx/quantization/cle.ipynb create mode 100644 releases/2.0.0/examples/onnx/quantization/quantsim.html create mode 100644 releases/2.0.0/examples/onnx/quantization/quantsim.ipynb create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/KerasAMP.html create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/KerasAMP.ipynb create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/adaround.html create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/adaround.ipynb create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/autoquant.html create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/autoquant.ipynb create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/bn_reestimation.html create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/bn_reestimation.ipynb create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/keras_transformer_qat.html create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/keras_transformer_qat.ipynb create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/model_preparer.html create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/model_preparer.ipynb create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/qat.html create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/qat.ipynb create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/qat_range_learning.html create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/qat_range_learning.ipynb create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/quant_analyzer.html create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/quant_analyzer.ipynb create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/quantsim_adaround_pcq.html create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/quantsim_adaround_pcq.ipynb create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/quantsim_cle.html create mode 100644 releases/2.0.0/examples/tensorflow/quantization/keras/quantsim_cle.ipynb create mode 100644 releases/2.0.0/examples/torch/compression/channel_pruning.html create mode 100644 releases/2.0.0/examples/torch/compression/channel_pruning.ipynb create mode 100644 releases/2.0.0/examples/torch/compression/spatial_svd.html create mode 100644 releases/2.0.0/examples/torch/compression/spatial_svd.ipynb create mode 100644 releases/2.0.0/examples/torch/compression/spatial_svd_channel_pruning.html create mode 100644 releases/2.0.0/examples/torch/compression/spatial_svd_channel_pruning.ipynb create mode 100644 releases/2.0.0/examples/torch/quantization/AMP.html create mode 100644 releases/2.0.0/examples/torch/quantization/AMP.ipynb create mode 100644 releases/2.0.0/examples/torch/quantization/adaround.html create mode 100644 releases/2.0.0/examples/torch/quantization/adaround.ipynb create mode 100644 releases/2.0.0/examples/torch/quantization/autoquant.html create mode 100644 releases/2.0.0/examples/torch/quantization/autoquant.ipynb create mode 100644 releases/2.0.0/examples/torch/quantization/bn_reestimation.html create mode 100644 releases/2.0.0/examples/torch/quantization/bn_reestimation.ipynb create mode 100644 releases/2.0.0/examples/torch/quantization/cle_bc.html create mode 100644 releases/2.0.0/examples/torch/quantization/cle_bc.ipynb create mode 100644 releases/2.0.0/examples/torch/quantization/qat.html create mode 100644 releases/2.0.0/examples/torch/quantization/qat.ipynb create mode 100644 releases/2.0.0/examples/torch/quantization/qat_range_learning.html create mode 100644 releases/2.0.0/examples/torch/quantization/qat_range_learning.ipynb create mode 100644 releases/2.0.0/examples/torch/quantization/quant_analyzer.html create mode 100644 releases/2.0.0/examples/torch/quantization/quant_analyzer.ipynb create mode 100644 releases/2.0.0/featureguide/adaround.html create mode 100644 releases/2.0.0/featureguide/analysis tools/index.html create mode 100644 releases/2.0.0/featureguide/analysis tools/interactive_visualization.html create mode 100644 releases/2.0.0/featureguide/analysis tools/layer_output_generation.html create mode 100644 releases/2.0.0/featureguide/analysis tools/quant_analyzer.html create mode 100644 releases/2.0.0/featureguide/autoquant.html create mode 100644 releases/2.0.0/featureguide/bn.html create mode 100644 releases/2.0.0/featureguide/bnf.html create mode 100644 releases/2.0.0/featureguide/cle.html create mode 100644 releases/2.0.0/featureguide/compression/channel_pruning.html create mode 100644 releases/2.0.0/featureguide/compression/feature_guidebook.html create mode 100644 releases/2.0.0/featureguide/compression/greedy_compression_ratio_selection.html create mode 100644 releases/2.0.0/featureguide/compression/index.html create mode 100644 releases/2.0.0/featureguide/compression/spatial_svd.html create mode 100644 releases/2.0.0/featureguide/compression/visualization_compression.html create mode 100644 releases/2.0.0/featureguide/compression/weight_svd.html create mode 100644 releases/2.0.0/featureguide/compression/winnowing.html create mode 100644 releases/2.0.0/featureguide/index.html create mode 100644 releases/2.0.0/featureguide/mixed precision/amp.html create mode 100644 releases/2.0.0/featureguide/mixed precision/index.html create mode 100644 releases/2.0.0/featureguide/mixed precision/mmp.html create mode 100644 releases/2.0.0/featureguide/seq_mse.html create mode 100644 releases/2.0.0/genindex.html create mode 100644 releases/2.0.0/glossary.html create mode 100644 releases/2.0.0/index.html create mode 100644 releases/2.0.0/install/basic_install.html create mode 100644 releases/2.0.0/install/index.html create mode 100644 releases/2.0.0/install/install_docker.html create mode 100644 releases/2.0.0/install/install_host.html create mode 100644 releases/2.0.0/install/quick-start.html create mode 100644 releases/2.0.0/objects.inv create mode 100644 releases/2.0.0/quantsim/advanced.html create mode 100644 releases/2.0.0/quantsim/calibration.html create mode 100644 releases/2.0.0/quantsim/encoding_spec.html create mode 100644 releases/2.0.0/quantsim/index.html create mode 100644 releases/2.0.0/quantsim/qat.html create mode 100644 releases/2.0.0/quantsim/runtime_config.html create mode 100644 releases/2.0.0/quantsim/tensorflow/model_guidelines.html create mode 100644 releases/2.0.0/quantsim/torch/model_guidelines.html create mode 100644 releases/2.0.0/release_notes.html create mode 100644 releases/2.0.0/search.html create mode 100644 releases/2.0.0/searchindex.js create mode 100644 releases/2.0.0/userguide/debugging_guidelines.html create mode 100644 releases/2.0.0/userguide/index.html create mode 100644 releases/2.0.0/userguide/on_target_inference.html create mode 100644 releases/2.0.0/userguide/quantization_workflow.html create mode 100644 releases/2.0.0/versions.html diff --git a/releases/2.0.0/_images/accuracy_list.png b/releases/2.0.0/_images/accuracy_list.png new file mode 100644 index 0000000000000000000000000000000000000000..779748676ee5ec13d3e5805ba5f33fd5e63514f9 GIT binary patch literal 242664 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
  • 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

    +LfrkqN=dY0?NG^URh6*oZLk% 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 G*Z%|W3+L+q literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/channel_pruning_1.png b/releases/2.0.0/_images/channel_pruning_1.png new file mode 100644 index 0000000000000000000000000000000000000000..68953c8787d746c183985e7fc11e8c079588af92 GIT binary patch literal 27278 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%0D?J2}|cWlyT(ThVnhd+!!2rdXR)I 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/compression_use_case.PNG b/releases/2.0.0/_images/compression_use_case.PNG new file mode 100644 index 0000000000000000000000000000000000000000..bc42909990b44a64ba901fc8cbafaeb15dbdae79 GIT binary patch literal 46589 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 MSFc|wRkaHKA4m8`f&c&j literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/cp_2.png b/releases/2.0.0/_images/cp_2.png new file mode 100644 index 0000000000000000000000000000000000000000..d25a132b3099a551090a0f6f27cff26a53d12290 GIT binary patch literal 58390 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 F{vYm5BGv!^ literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/cp_3.jpg b/releases/2.0.0/_images/cp_3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8c02570c59e54904f5ab955b708ee0fed6df9c09 GIT binary patch literal 68184 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

    a#dPr9Rxf?K1vr!5qMOK3bsOe^mR> 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/cross_layer_scaling.png b/releases/2.0.0/_images/cross_layer_scaling.png new file mode 100644 index 0000000000000000000000000000000000000000..56c09217fec9d370a3789b4b028cc2296f041c3a GIT binary patch literal 88402 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/greedy_4.jpg b/releases/2.0.0/_images/greedy_4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..653fc39f2c5e60466a9d1b9648d978e68bb931b6 GIT binary patch literal 50524 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%0Da{}%!xE^}z z#|AxhoiJ0KaV?c&|0D4L6z%`BTI;{@8<`w&yi7xAIv&}rff=xmmFIOrgi&+cQI>MpvcuH>AHCH5Spx={)xw(*FzvlWFe<@&giR)1EgB>R9 zjWLcJRfoT-jOel~MZI75-mcc6H7vPcz!MwJgBYtG5j7^RVkqjUTA~Hsuxr76l-%Zr z5|+HPaCUG-QU$&~jk^O$@NWRM9MIJ`AYEZ#2j!NaPScg?SVn8TeH$J27NBL0CaiS9 z9cP-CI)$ttwXZz5w@zW7+$cBBW5VHx8KAIe><&Z@t}KLZoG%~{C70t?@W%+i6238n z-(CSul4c2ZeeaI~q)7d^M)$eA3+Tj;VZ?CR9Vm4MdUFk1QMXEz9ew+7PWO9nA(i~> zN8@*c1y4|Dtj%G++=z&%%TM%)8M2aHmRUq=Qe~8Me!&@25Y=9hUma%#aLafLzWd&! z?voGNgzBD6FnsL=2Y#)7b1RoE7VFEH$&cD(RmCYy{^b)=gzN(v3OVGpPNA)r)rSM0 z4=l!)Clp4Qd{3%nGc;a@3DE@wn2KXTPTp1vOE&5&)?%#V@Lsr{W|>S8ITV*%UnQna zYk*H~tnNTiO}Oc=l4!vW{V%N$pJKrmtH73u4)p`}0Stgh@st8P2fyCG1C_*Q-DUy* z00X&)i!*3v1??ysY{~4B$DpcZEkpkR%Jt69Qle*o@RvJjm|rTi4ZF)8#`u_?ryA8m zVB(KSF&QT@Iczpv3U};mMUsVHDOpe$T+7q~S$H#pQ-X>+5Nrp*2mPhNKLBj`#fRWq zOkwEl4Ujf=@&X2@HF5_!n6plq8vN~CX@g5ClQG&cMnq?{a=?3$n&Xh%r;ATl9mH-D z0Ho=ww+Ou^26D|e7cy{`17rY%R^$L0t_L+aq4^x_0a*-Ue>=2ST?Wn|&Ou#e7x&>ZS|iol*Hj4y=#9y+snXxds5| zzbF^To@Pc{^A-gtEIa@>gHUT>%bc9>FyYnC>&X|>q7Nv4G{`NCJl)Y*I4o$yy#qb# z2QZQ6PT&X}ZAnX<8$zzLsbOJ=6Ngpy{q>qAySK#IH(U+G^e}9b$pp~;1fcz28W7;( z|9WON!PS)|*BDd4G@Stk^V1I(ZH9kElGvX>-~V$X2OS;6UHV`uNM!i$#`zB188lc{zch`@SaNsYXc`3!Kyb?k~k-)UBVyWNsk9 z%WL0~Q*VJC=_up3Rx$Li=EibEW$=JKv%0=TN#QF2#2*~ZW{vKBfoAU8X#4khTwN~Z1asDra zyQf5Me*G~8<>&!phH3w_akskGXq0>QqMhQQcu98GA})>$W14ALyX`l#Bgf4A zu3Ou4)Q0Wj63R=G)@jC=9DTETs^p^XvBE()^0$jWzJ<4I=Kl+o!|$BSwcZcEI}YvC z-$!A!dJ;OP@JUTTnn!4xB_#&R9x~l-oAu*8kz86;QytExueEOPk2bSMcObk@++3nU zv!~DFp*qm`FZstmpDm2TRvq{>Nx;EYmLWD~J2{O*Kxty={ewh;!q1DS$Cpef)I36T zPm5+kHBR+!{f1kg>}PnHB=NVrco}uCz=9$0as4Nuy;o{XR2`Hr7;4T&PWd;B<=Zss zN(DL2k#}v)Los_lAdMxrhCD)fhyjAPH6tCksT^Vd{8AqnuBc^Ed8V17Q9CUkgXLH} z5{2qaj|-I?Ox}eR!F~{#p53|wD0v~hv=}Zas_4OxkKOg;lOe z+sr-SPh*d-l2RGkeU+FwGhK$wQoQvBN*Lnw6#gb!v*0OxqUlDbiC|+#FjBR{Od89@j`ckM2QIqLdzP``b_SWlFe8ekh;^T(P-~D)_#>2=|U$ z1GZFC@O2J6EQRI{RICZ@Vf|Jj)Noi?zB6s{ebgb4Hjoj&*Wn5BdbUC@m2|BpM3?x;V>i33KK&qBQxP+a{~V4QEcPf^nHklMN8bx zP>qbfj3{1Y1P`lz{GSVNer=Tx?A$wk@usXfK$}&YhxA>LbY!|5Zm(YOy8uzI;RaX;P8pnST(6&y zln1)kXwM!^SYz6eUYC0LMw|%n8|?;vWFP@D<+o-Nhx3KF-Q*}j^MZ>19c1B{Xb|P= z&C@24Hv73X@d3D7PBTjloQ>uIfMwou-kjfomQ-{vS6XUf_pBUpXOu8k>}|jQ$e}!b zupIrxKs7@?9g2Aq?E3OhXM1|e%rFRpGm>t$<+;3}UW>;oH`nz<+lcLij;iDkn*jTp zlFHd11)s`o9XSi|r>rDgR>$a%!o60!N%4<+-g)_Skk33UE8SGH_%50vr3oZsf|nMi zn@5s4_bA{4g1ZLdyBm&^+)MVasG5iXx~jG1u;dn%7I0fu2movU z(jwA5+Be)ahqB&;C6q4%p-S0e>O~3cGzq}xzlo_vcQoOrxyJQ&BeL_P!IK|K|C9tH#mg;5V-^C!MgVbW2N3_$&o!e&nl)tkl=oT zZW{U^;C(>l)DTdR>Hi&k%H0CsMS#9sHbrqF+L$(h$Avl}z7Ik-9ZY_|V1n%35nU^u zyZ+c&Ab)P0QtC@T^o`>Mtfg{kf%Q*f#X$fh`fVaqyhL5$-rPwUPl@V{j(DkL;9i86?@gGO64c-}mpP}Ui z7l?<8XB9LJOeJ=pDSzIQ@v(p3?y2Pui@WIghq|)2O7kzbdnp))IQh}fFatRqC@5Ml zKHQ_f;!tMl{q}Y6-m0-CatQXopC%ub4>~e1>?B`9q~b1e>D^0f$KelgyE&90j@Sg`}28C zg6{Rl1fy^#n=I);OnVKqTPBc2g65(#4U|C`Z)rjKCo0C76tO)I?tM3A|a7kD+r z*#yy|0lR(zi8wOoFhDV<#+hI%a=0|AtsU72qQ{fP6p{XpqgltdfDTtXlull3deC`b z;K!P1Av{lJ$So^h-}xxN?2jl~$+F8ejek_(@Ze=d)0eO6MJeYLez(h$@iz79U@pZBEG1Ixlry`(oeqXu2iVyv zE)WWO-CDlYopd%o?*(!XuCc!FmL{v18LA<*QHtVPFJ1`K9!Sweyc!AZbz5%;N7cm) z$J8#@n%3?tqLr?;zEYMA+9j5qC>KKNV)EN|O|tsCRd4FG{m-h=KkXX-K`ls3?F&~V ze?-<;0A;dyRy^Do-U-8NWLU-)d{sJpmRoEYR`6k&KeP*zC(1=xShM(V-$=X9{#sE{ zb?mK6mcLORiyZM>Z?CQRAzki1%a;`L>RP{5Jv}{LCF_S2@ek0H{cU|8q)DKqHVn9r zj}h7AF&8kt$m@KyN2;{s%wU!kr`#O1t`UeB{7JoL+QTA&QR&dh9p1%QIJ=p?yu_gj z6f>_rUzOuyK#FmNf6oJLFtH$!@#kqJ6ld8O+Zb9wAcQA+-9sgb+@YEebm)BzXNL1$ z**dbf4)r4{5xkr+Hg6bU&su9z8+PA0 z>%OPS16jI9D#3@= z8pts+f@RxmP$rLJb(Wrsy;d?bO_KhtVF}+zuA#1;VDHU%=gN<{%@&&wx3iz*j%nu? zO$MxeH~f7%x4Zk_(ZqyyhNB(GCm_)8 zOQa9PQeq3i=TrUBehAt&8ymP>3%X=dSC++ZTjQpR=~ji(nj#Cznej^t?+us6?%7#T zK>IN5ybHqGKan-{3o~~XJwlQIfzUt?w0~^L_qG6)h&(A-@2xESW1e{L)2-|1BK=TB zYPp~a*vCNg(IF?!yDiIn?mTq$+BhSH4fxg_(t?s&EF4@LAGPh0&;37Nw?~AZy}zZW z4$__nzH0<{z0gbjMQ{4>hLRMaI@y1krv<)+f|Oc7L;S(mno3+v4I~EnW(aZUS)kL~ zyIGjS()K89xnNsh$0=)WMyU5EW~WRpijI9JcIQ9%9OPJ@-M-SI>*ldn2KDm%}^idGR~Wv|8@LDNX; zQ}v17XZ%Yw`RLIc&C7cLp>enYXYj;NlpApfuaOib_fG7YaU)Vp7Q~+vy0sZdbJyEg z@+>>^xdX{`>2iLC3oiH7o<6a3C;MhL+~UbpKWbD_6Xq1E7ihpHEs$i0#pR49I^l5S zgpl(r`R7%d5Gl@`G@i>uM2!jfTnBo!L~?t`e8Ucd9|j{XiP(v@Xm}l^{;h*0B||JF znegLzihWc!Z4haO>M{2&uh$^H+#?XS={RE(WuQyuHYVY4hl%Y^o@c(3tkONT%soPE z!uM2bq|{;~R>@9LwZCeFLa7tQ!)pFJidAn$ zwO^b$KSI<~14(Kip63}rz&S5fe)(H{oAuL05O}g)^A?#6pa5He?N&Ly@rgxVNA@fG zH&qxC+|#fx<+V>cA0E3>&lNZ}-lztx2=7N+8}CkB`(+Vz6!w_!;YrX=ufG*w{ORxa z2;PVs8EN&_O?T^z@USzI(01D_Q%ijY&Gv80`=s&CzwWyva)JylHaGfs{$w&Ka`3p z%UPVFj1Zna1J!DO0_^n3DPo->~-l+K;pt43rR+eD`>Db3^h6S!SGi zduec(@oS?%nNG@z@?*!;!zYHbUgMc*`|@Li&@%gyYgFKk>II+@_Q9h49Iq0X(xF>1 zv@Foxne?%*qYtc@d%TIK@#ZBEG8_RZj!AOdTO6Ai=ac9I-yFi0WPWXE=6-wd zr#UXSdSI?;H$9n5yuCgf$;ajL>L|kI1gU!?45Gis5Y=n%RsCbAG-QMHqs{dMcDmfn z04`GIHt}Bi*0GH1@tfX6PpQ}B?y#ml4yaQt)wc^W;ychp>e{uB@KfOJh+y?_h3FeH zelk?mp~f^;oLA2r#BeRg-hH$uX>{YS8qwb7!xyC$y2wxZ)ZzL`R`iB^-67kpQiA7N7gQvf__*vzk*~&=V%5PdMUvUYuBc zcyBaSdK8{0B*yz}>jVzVx-}Iq895OI>WF`xN$_v2CMl2#q646b$pD(zlLXG{e+kLj zI+0l(5NI7cca8--Jd0zl@pnr566rrDazPHT-xe&*Z!P`wPrMxVdpP~m3W)_`!kErq z8l(E~S<=HYqqy!%<+Lm{X^-lem6>VAuEyZcu-QJQ%k5oNqvi;5;R~P-!r-8*X{xDB zA&qw9lcTM8C&MPq>($dmCaSK7zu{O=u+6Qd*J72cgs*co9@S~&5RA3!>qL70g(-YF#yHvT5I8*2v1<{y=%mPN6NlM=(w|3*nkWB#aokRvOF)lHAbjD4Xmo-Ry) zyPDSzIjsc^wf2_t<&j59iTh8(tn4)L1i5As+aAI=hOgds=-)R5R`-;fAg^0oJqxn8 zwHpPeEt(4H+f`+YQ>^&Uv47U3E4C*^K^v9EeQVCpX}}10=novRTwOC%`E}bumW~_(@!Axb# z9p+mZc22S;n@yJb!;%cy-x+VRr@(M!f%dD~|M~gBeleqtOdMyhv3nzx~ksDnw>#Q4GUpe?y4Q<;T44sMTo zSf6}bUL8E)AEB>`FlFjgJ6ew6CH?3?jYqN8^AXKfG4jc}uyCG2&KzJS>}J=j3$NzN zf8@lVrD99fO5AP4{&u6WOPF{czv$AyYd#ii6j{-c5eXqp`^+WoF2BfStLxa_7raD4n z)Yo7q)^8rk5NW>h`{}Jb=Wpb9iNL#5GQWSCPffdwP$0vEi=l|$ghE#Nyw*qgYF>R5 ztA8(69|BuXE@~@VXuk3s+ltZ{wzVl^7<2yP?H9!WH_IBXG+&4dvmY%4&z=kd=*l!c zj}=#vxGy9ScA~20H14xQ_vv2*ud0qkEHeywhO##9Ugf5srJk;_(Dw_HM7Mv1= zF~vL%Vvg5({(nd()h(OwtD~KJBV-EKQw9`aXF9D}|RXL=e$Cc;LKK_Z>nAHUZC{MWOVE}h3Lxb z4qw|SC8WkEl7&)bB;Oa6c7a@ImbKR_Zi8^nErAX1KDJXFHuV`|NQpfUZJOJn0>aic7K7uK(}{Q>27zUlW%j8u_-a_;SJ4( ziT3Ic_T&8B@Fp*tcpJp+JH!{?AOv|Xis5>AM z)Bw;~m*>wa>SG7+SCPtEC_)DS$9BGh!VLjP9vnd*yo4Eea$iictWcMK{Dpvayuo1H zIjN)oZ|nwJeW{ZMkY2zd{#lvivC@lojuH2tTvEAHD=gh3Dsd_UZeI%s(n$q}OTslJ z5p^JBsRJF%SjI;ZN1-_LG8-gIdq1B*)uJ5n5&9%X$1Lt`pd8TT2P7;DMS3IQ3Y+=? z$jAft@uf|!{TCw@mtoWXj|C1YA|G})lkQV z6!^qcuY(u^@jgd{%HPak%aip@J!kusta#V2f~XZ2T*8%G>L@AdT#O?8R&E(BeQHs$ zJCaKw`ccq6?{lB4OYFkHIeX&zmH!J6sol0BOHkJ@A=7GORb6{J0i>KMxgmQ1L){$s znJJ3oxD8}37yKfkm*d;z*>5p{990bBz70kGVz1~%Sf=wQS$D6LIHvDS|p zhw6l2V&Vj10nl7%sfm884bKb?h0!T zIAblsV0H3;8-jsy#uAQ_sOF~;(@0BBE*gu&54Q<~+k_d6?_iO23yIk~sB@7__ZG<5 zT&2B-`Vz5-Nr2J1f{p`{n0kiU~5mDaN`g-_PC zChLq|?O8IFfXMN)lZ+>fNp+|J2`@^euquEOOw!?Nv72qoO{A(=4k zH4F3)ziI978)qZqfO(3qs=j*YOVaY8n^jqu=9_|CWmDAIt{-34!Cl=&?AP&dsZwylDfX9}vyM4jksok};LR@jxQ9 zRwKkS<$$jj;vaaohNks9?T5c6HV)!GXPS9)6mELl;WeR^SjH;U=S#7(w=6y~w_2Con(Z#` z&G>FTq|fbFnmew|7jrGUGoa?6I@RmJw&BOAhUrC9T}acx^$X$g@Ne)=q0xmyWR3=% z&_vXtk)cCXBXi|*WIb0`T)hw#{t{=#l4yw8Fp?&}H@nYar8NCWHmpKm_)?)CQ!-BF z&ygp6%%I@FU2iQLn-@#?G}6{gnZ38ZmR}z!-9tBvWrYbWVTs`$8Ju-o>xGx=u+;xS z_JB7Wg%Tlc{bTij@8yvG!0A9JY(qT^q>qEd^{+!$@WVjB_Qd&8FXcP$c+Jej%;ni;0rvnQFx- z)39lkjl}rFPrZDm1H8Tua&$grS+0IQ3nn({Lj;0>o!;PCx>D`52DzwI-IiRJ2x2bDi zUOT#%?xn+A6DjY@B&ca?FdE~U>~KO?b`B$eZKQFb@X|q?No+pE=vXBIlwGPq1J$#1 zbceprUyLRghBdAZPeYpp(xY?y7~Bm>%(^3`auOzY8O%476tpGmzH(hK1GqIHACS!b zSt@ELRv?{XjAl)+h`A;0P=|lu@;Y$YGRB~P{$JXjcm>N;qDzq_3~#Urx47~if6;+j zeQnaUT|8UH6zA4k%pZNb&)~FFG?L6g;?+mo3|wffpYl!w@rmjgT|| z=>0n3v7XZR?b_C`wJQUAewX|f54V2l$1G4PS25(8XqS*R)gaKM)V8*HdR^1I^D@J) zi{jk2!ATl*2L|T<(?i0916~d2Zy(vdxNL^yBSiMLwZooOO>h~TH->I4%|EEH{w%PF z^H>kgO!;{sQIQL8`+<0B61{c=Q~!C{okd0`vGj70jPTsCHc58M6|P6AEPpfp!3tEP zWEVATqU=27RWj_E4~`SDYE{fG=uQY?J0p3Vs=_1&El|;M8#i*%tGk^J`bwkjl4L zL{s<(sB7+ij|+I>o!v2;N5e*wQcH!G5M;xjbkDo4q~tA~bwW+})NI4N_e#O+9TQ5Y zexDo0zpvr16CA8S!c;x~BN;#X3nyiQbg7KceG7_ZZ9j_?)6=tLXVx)CO$Q>gxj%7K zaO$BmqnF-qx^o~HnGUxNzLnQDR#z3JQmt((S+%Ibf8C1sG_GgGc;UDY;#v9k%Z-65 z$=fO@o!-9t*j0;=5zx}znAyeNeWi&@rFMS9A);YDzw<#mxc)wYH;+`b<@NbcqMNmU zEe$a-^8RTk3nXfvsQMl-jFjC^;2;5aecqt;7xfEu@R450EtkTs9Im zQ}rBKgNg%GsS9c6M8%zFx*C`hcWV0nS;t7cHh<>?c5BvhMBBhUt|IJ;?qbS8s6562 z_bYD)c3_)-MwC7-?gfoP86zS(Z)=XK>h6jm_ryX)npy-WiNG!5WX^eB2&s@-^BG<2 ztT&8L{d)q6*w8W&T;xOe<;9*|!3qt;I6UaI8;c!Si`b3X&{EOXC(TFCJVBtuqR7I9 zB8tIKKPQ`pUf|qFRBIKJyk+G;pSiVBT}kfw0jo@zmB`*lJNEn5KF)76&u_Y@RXE;U zIi|N8y)d#WI6i*N@%?D-o!g=?|1PO?KxQ^T=W!=2BoJW5;2FEv)Dx*Y>Q zM$=)FT2WrpgHXQ5P+0otmA6%wJr18`{Gd5#z|ov~pDNopA`T7PHyeI)#_M3k80txGpmNLCo_7?KS}rQq z?v>F6Ysgn5UB=bcRS8VzunVj()HiF`guPdb;_&BrzyVThw`;^J_{5|Eb%)G{gsON~ z!s$nZz4m8rWoQpE+;Ir^_BRpZ9P1IKuTPXjl@cf9%j@dOLl;L>$C~=3>xsGZ_L9CC z%T-&=j5>RqSkU?(?n%;#w%0_{y)8=&abqxF6DPaJoMl6gE+)OiL7_HblRJ_%%E58m zoBvdhyYgeqE6pyOsI?o<0y@+_d93H)4E*FqfNfu(ss$~wWw1g6gw*_E6(7FWO0!Hm zG~}PZM1KTaiHY=yU!Dgs(}zIMi*8f-mma1z`Jp;d=~UJ!!(xg)J|4yibx&QZ>OR~O z|L}R1T-z7@Mzkx7EUQz?ix%?D)F5~Dr8#+1as{F+h}Z1^{qdB=2<5(A+^KJbr75rB zmfNRvNjw?SO7A4yrF;yXAbUd;>0!en1nQ^D`{_FP_2P_FKdYR9X8E$SEI)XKW}wq?!d`d-AEd zeCHG~70PQ~?-(Po?(w|Fr~jmJ?)gtR2EMc2BwkW*4)iH#YE%8qg{ zf__({HhZ@FjGA?3m8Rhx`Og`w*X{&2E$J03M+cUqK@oNcN!l&*4Qf7Wx|qe{tP!Sn z_bg5PZz-8Jh#@oOT?3;e_8i{hds|r~Hm+W^U!`W4+$x!k&8(@evm%ICwNfCOODoUg4=mI-Ih7gCPBUrRPRdZpTE6sn1t5SwHd*6%iNr2#0H0D?6DNZej{38+oOC>p36hR$pr_STHEMG_%i213 zc&eT1suz}Zjlt@08BLnI z3Jhm`a+h@2$y&~?y`a0}-@qE9Sf#Au5O#t0o=@q%jo7}3Y`ntid!}|C`PFGFaMjo| z@r(5vjqTG?0br%GnhdQF>>cco6J+zBl6?je-Zsc_fD%Gi3`RiW7dMFUW{uZB`Crkd zn||rM&c!#(;6NAe=GvN1rNEqCs=3_pMW5RMU(u`U(m=oa)LrEgcHfnH(cbHBe-p68 zZxat@n{1fo)T<5vMQ>X{OI+h~0;$Mk+jX{3!nrxa83pSctPhW;nd(0((h0g~T(^5M z{~oiptArk}*z&g3-GO)W?IL^;SMOuk-6)9U=y6~0#@2Y5M2c^x2eeO>6yfhGkuwA% zaz}D`Zts~G<6j+WUup?52j!-&Q4~~OJ)LPKqfZZ%+Uu}yG8DzDEqFSW8Ywu}Q+>*I zwyu4uL~vq8DRjb$Mjez!M-?SIQpqN++h@CDOJboNUF(QNpHF*;wTDkvGLcG}*b3c^ zV8E=I!i~OvZaauy=VjYDYuh>b-m4yG+viE^+{Mt@^Z;3mKnD-jo+yp&*qw-XW}z&Z z+1LK3z6oF-pdT$Xf|CP={}E7#-+`9c#SkknLvRyY;1B4Vsj0f!1d?pOdi^n)w*HXf z7!XqtcX%ruP-iTb;YvH@DOuVvw(n>T>(54XUlSH~gtdn|uZO3OeV-sakU;9VyY}!8 z9rvkw^+{1^(~mA4(MHO3;k8Xica}VbX`Dwu(^ixg^m>cp8Wf{QHtG&L2w!f#yBoq= zFIvUDJ-uQ5X%~P>0op#Y>$=qma`3ej_S;jncR4bG?W4(konm8n!(By-MhBkM7Tu|~ zI1m?nS{JKZ5r5WR_x$WaHpkA=)?_q^HG;k(sbw+ey?2uEW!`YTWH`k@YoF;ov~rA_ zl+d!shNG6I>tpyR)lboi@iw%E=g;k~>~$;C2;;@A^I>7j@_o z_f&UKtXWp8w&tq&c8MPW+u+Rsw`MkI1kHMIOq81jbQL5VoY+G;631x{_>*LbHJ zIv+K3hCV!)Awr9e5kk)~o3_r}e;%W7!d9=X4xg66b*&9Nt(s4LMvnH;Z-ECc=c%dn zaDKrmsLR^BcPN6tvmcgrOa-4np(}vA zdUJ2!aHsEslH0o~@G{xV8kN^aX@B`&N+mA8ihOgj(i#tH-t@GY(o?cy;C%JLJMg>d z9I*q;SEIZ-e*jYtQ=0iwbZPwx(;Hl4e21ZdG~ee*B{xI?ofk$dlFhthjybLE<=33P zl4Qd3oIUf3nC%;+_G(10OSorMl~ghmM?cDzB8t-%Z$7Vdm4(EHf-9j7RBJ8 zymRwfxJ}0bO~Ox<`un@9lmjPJK+|0yHA@gr`Sb9JH|%?u{Dq$rP)S2P!$W;;=}A4S zs}o!Qb!-l&0!Fu0+I=*IDs6DBmX$*K*rZU;Wa?KTCc=GQl^&;Hw=yn+!0RVInhPp) zI#fRb?Bz%Ex1bArX&`6Ft$pAE4*~A{XxYF}A6v1Y_e0B@IH7}XZAOS&%pi5^mk~B% zFPT+U#k=))4c40s;!bd9S?kVBcq(qmw(RnIxh4`-1rF`@4=(C_?227wFuk$jyzXa( z!Tj52B>(&cjajV@t#LzsC340u4<|?t2Skl_crqZ zJx4P6sS<3$vaBDGPL*=fRr!9)&TNPzb%H#iHBG+88*XaOkN3`}pwFeiaw7FDDgD($HQzcg*fBmkeffU8&z37tf0wUiPU#&b~Uh~&9SBq|=#8^iUMK?+P z^|k*_U%HTLFAikH7)$t3m5ZC~?QhqdLucD6-sst4J4}$bGY7Iuu)qS2Wk*iR@a0U$ z2`HT7XM2m^=pkx-I_nPe(~8fBVDpRuqgiIBx58f$C7=cZT&Xw)60X;jZc}67M(iXgTl?-G|4F22U)VJ{dW3&x ztR1NYd{j3Tu(8{tP*J+O{}HPKI+sCxYXA7y?!1Zk%5CmuVNH9i^~tfK-pM1JQed$+@xm2%og;6J~Mzm`wK z!cK-u*b_&KBI~zO;9q%${pf|4lh}KlAb(oFOz9EVHFV*wW(K%5_Ht{yaDf zJ)8{kQbl^7d3YXBLgZB?DK$&W7V|4PWbEQz>#C8)bbGzxB!sLG2;P6zy+4p+u`DBg zJb}WTdzGV8QmKh*dc3(r;jy>7yUS5(o9KRLQI}seQ-HxVo}R2zxykqFol8QD5WP!7 zLzU8`iMi!^S0^RzYi~SQ+h*6^GzX>5e9552bDYOjhZ(`Wk1E5=WR)?+C3Qc0-9koC zXwOMw3`!S|uW7tq#tc%&x>!z)i(OgMuZJ3qcZ8+I9obz$_1+`iY4uh3JZ{83KnO3oZP=9-(OY}5I2GdKN1 zH8x9T`ln(Q(z(7ogxvGmYM+E_voXx5?dqPqBf6?>ns!%0t5l*f_T2=RukkxCjI=28 zkFH}c#F4ipA@W71nhuty4|E@5MG|4v3Nur6@2RL;^J>`b zM%}FJ3;n1opH*M2Hr5jtEjRl9hP9r4yNC6yZ+O(?@8!cq3&=6*a2P@RO}~f?XqHNW zrOA~+_PH_s{@M%eud4aEbPD zNffpNvKF=`YCFI0eVGM8>|VN_0tSO!*R{$>!e5!d%e2R6_k>Zu}6h zBu!%D-9pO}2fbF*;_7TwoLeD|kED)`x*Ug)Q$+=14aJ8O28a0^&}Qhri#0tWld?9Z z_A&qiT^ga;=Swd#yB9J1m67Tzd_{rhvWj<_&0`JLzbesgfK-}F4n8Z9z|HVBRGg1s z67Q=;{BM)w9ri*SH`EcNCzH$vuGuX?RL0h@=p@U;ZD2IPmVg30@VE$1K z(O%AZLdkJhz5Q@$=8e%aMe)%v$TX`jsj<59kS~U#3iXLL!b<&6FKqR$X*JZ^LM(00 zc812nXA-Bud~cncJpZr9sdn{Nv3<+Go8}A`)1u( zhE$(oT#+>^_D(wEcF`Noi}b|00?@IjOqNo76oDiGbm;MfNN!|Wr=9I_p_n48(bJpY%X0?p?up}B)*b}WB<`Bm=JY<9P*V#S zq!%tMyHUof!rs!_h|DW0JyQ!)2t`Am%#!=!LgiK~&D=M*>(KrZfL54G_!lf7t>_YX zJ@2x99X!rM(dGvaMAY7tkjBOCp!_X%e+U-68-MNK{3ReI9 zy`=(et-5VU{jp-w4&6e1xm;;_!|PGsq806f!;MujtN(*9xG-3<+fas*QxcnrWAP76 zB4pV>tAVk~`)>x&rzhVfGLcv{~vbN1r>4$xo6_`Cdk1#HEr?3~>Aq6)UI zjW4`p8#^D|`6qWlJI!zJ zP#Z*&cdh54lfiyl;h#!||CQ!g4Irauq(7mslPjn$+T4FIM~{CA?WrIhB0)%0h7eqW zU=9G{2boQ+B7KMM?^~9YbO*X7N*AH`=_Q;B$fLhV9JzH8q3!Z%0sQS3Rf+oTC46WT zR#VSK+WjgM6<*#O*Io{uEQ z1{q}6u?sPT9_B?hBp*TlZq^T}9*Yn+HpXYz5uM#V1ooB=tuGs;PMziF*0y_b>Gk6t(mz&3dnL}})Gb7|_M4*p%OZ;QumQm7H+lc2 ztdP0CNG`VyKhW~8>@~vNcDsW((y57LyE(fMO+QV0`!lOOZ@_SDt0DFTX9IbLzVveA zt0`gUOE-CX`O~ksR#M@hVHA=Dee7@dyajsBm^1Nc=|V$*YU4=RJ=qX_U9vMi8~^9; zZhr{(bqWu+msM7m#N8~)?ab-Jp0%{ZmSr!^QZQju5ba-O_$;o#;E;?St3UtS#C{Xb zAja1>*dy%6*1Nn4=EIpyaoHbtG6J=Ox>$J0DeUcqx~Oiw-i+tS-5i_}Uu|FiAn>mA z8YcZGQDQB>&L_*TzuqoU+k5B@nKhEXs}l5A1CowI^Lv2r5T6{OqBVTHE3mfTAyS$} zF!p+4=jMepH$`u=jXEStl=o_lHnOdz8ZUOq{D5)q1AoN*z{Z@$&P3-;%!|&C4%PkZ z)LQx5(@kHgu@fEfK9|fGFdyhm$#T53E5%Vj*mag#)ei2N>giTx&rjA#?!5@X0+&Y` zjzW{Yg3UFP^xfpt=CjlIPukzxEUoXh+g-P&v}h!L*h~}0n37VJW=U0&(x7>I5YC`R zt6`K*EN*^Z|2^>F{wLHFZ2*yUMYsKE(Nv%ZqD`nPK&MUNCAaP0zQ9S<4C)eu2e- zIg46Y4`m1PJ5;VUN-ymrW3G(0F;P*GH4zk@D26oEp-Rh>OVKbNEiD23#gocM9EBui z_%+_=WYu1?KH=iPNO zZ{J~Y9PUs1KPly&SR|AJO4C78?`g1w9mLGxw(rt8dYm2fw5 z-Eu90PBf&Ib;Y;AGe$*M)6*!!dsATIjg~q9cY|p*+9*4-9&QY0@~=s=RUqT ztrZ*8vf?>+v{A>Q++FcI!V4Cz^m%#Nri)R6mp^`X_W9B3q_k}yXZA~+_&J=n-(wHs zSa}r0(1zy_PAa1&w`ZEtpE-SgJZgJe&!ZccxY_LZ*?UX~n(CapqFiHR=s{M!zq>KX zP?G5RuK!m&DL=ye4xf7bC!}d7HN1|YnCJlG`o*0v4EW{oA$0(N!LAEF3)2(c!`{0s z+b>s&VI4EX<>K5hXx=ck(io;)X=z#=Ll$l96GnS@%3_nnXx|>C?Bhj;cK!By&j9VJ zH+P0A&Z2jXYa&va0-+;J5>IW$UiP9^>?Ox`H^gt?K)1h<_gNd#j`Qt0zVbL>@vgsg z=O`gm=F!!ExO+F=@~gS^>O4(@Dt7)9G_*anph(_%*QV0)?$p^cFU^rumbVJjXEIYQ zZu=C{ceDeJ?1egI=O{80ym#i6pPakoCJP$~JRtURquW~|E~P~#j43;YruhC3UuF|HVi`ZuynYRf)}M#9 zBq6wBSK=PkmzlEthO_9>RZB*nddIzQIvql7cZ8?|aI%ah9&S0_rLHdlK-VeHoRyuM zN1hTNd~Wm2lPTq-2lp5Wjm(FuSWY|@=ZbE9F8_O;k zQ|qYrIQYxA47|`f!!f>0`6~O z(t^r4b1FHA#%PqGLUkb1?^(wYrJ{!Kdm-X4iXh8c_FQ$oV@l zbHA>2{x|cbTSoZwbt98apL&X#CS`Hr-m`tVDe>@05Un8P_;^wJ=0&g6**l?lf>vRh zJ=5y<7?-_G0-96yJiLH2{61d5i&M!jkE;bvmx%mKD(mA3Lh|TsJ1A5N$QbMuDAhOZ zw)0(Td-+lIZW-ryO{b2wNa{jDub32X)JO6peQLnMI)CraW3M8-;EbYx8OTWoz2Kke zFFtr;cZdHE`AChpuf|M|u6s8)ba;+hFZyusEt?TEh6*I~d(e$CD`b0{aIrYhANU<{ zFQ84DNUMzOI@h!8>}1@2L~UQo5TmTXaQIE(XFur}1%9K6g&T&kuae6^ZvV%&SCye<@OHP2c5;O zbH?&wre&LI0;_t78zLjZ7Xlfmt-}#2rB>A32>0q#+K*hh@s=;&H?R=Dr!+3~#X_=7 zqz{EHaj3My-3Qu8=SY0+ZtFIUj&Z)}q~sNQ|LNY!E6A7V343~AP3maEvA%e-kE;be z|AV(*a<#z)mV;1ft79B7u=J!(Gq-OJU?%rBFR5sykf9h3ZcwayC=g&&YM$)iOs6b1-awvTF2W5MIHZ;AJP z4kB93j=9j#xQIcNmVT<-KgZs<_S7eNE@iRK_At#HB|b7wl>D-e_--WyB5h8s3a;|j z4se2w&ky{h1TD)k6I%ACA;w42y}5Y_o#ZB+hOW5<;~WOKoK-+Rw;5&kE^u_BpXO}2GOFoFa)_E zs0ISVCV@hw!rKUnw!Q<>);fnTu{+ff zuFNWxO7Y)snw?jhI&H{$O<3zVK)bc!Dwh-U7s}QmL!kj*MC{|tS%;Khn^bN{RvL6r z(Zd8qlFfjqNsr{BDgyL$22x$wS)Go*j+~*!xKUJn zGV~_>wAT8!-=~4+d*g#LbATklO@OuQWL*!-fO*whz8NUcx8!cQ|B-L{z>-xlZfd7P z{?O0upq_jspoOw3Ysp8cfg{W3(>8&~_o>-F7aMc#%g5n80;KPrl###E506*n;lTp^ zaX|c^9C&ot!OeiosDqU?=b{k%dTE1@+xz(&QUiyCgc^jZ7NQCzj_M*p~rT82Bs>9cDg`ulWb zEpu$NwcU30c>utlC!mKMzt8wzl!!b~ zZ%XYc65vr>j}i2I85sf63?;vbO!oag2*9HI>jun7&&>l_(zi-u^V>@Fx}9>LTtwH5 zBEQBz9P(peWaJ>28HmW_4j5T&o`suz*&98<@d`WplnP}U;@p2#b575w7{JC&k>sX~ z9muzP<-K!*=08!qhaSP9C=z#(ww9^Y)v5#@6}!9v_SbfMWEk3$0Ri_gqX!R^;8Cpu zm{!y{gJrfA-Kk5<%GL3jq-WUViTn%;@{pBdbmH%zo#kVi+u-!$1hzwlU$8mtP(=*b z65}GHE20XtsDD}8f8BpGY7Z#^gXgb8`Q0jM233-cBDKu2XJ%)or+k8}lXYjiUk?j8 z8|v~DO9e5LclN~y5$n#0YZ)OdZR6d(O^nDUaq7DH_7u^chlk*BuF$ySFXjAHOS?gl z$$-Dz6PZ*`)>2NasEmf|rc|a@GnC8Y-W%+6V#_in1xw(;)P%7o}D+( zml=v6947}#rZt%umHTF955MIE5MT(}3U@d-)63h90(8%p`W{qNrlV*Ji2VGs{{daEMi(-mn*Rkma~=LfoR|gM14qJS*8zAeopBIoj7j4dl27y zQE!w{M)|pitdmY+oON1Hh(2H9_+ok2?u0`~U;pLEPDBxzX_z(N+Xg>{TkkP&@C1_m zM$N-KbIS{-n#%ZV$}a^H!|2&V+E*#0iLXDvna9N3-15To;@Y-5l0MzmE88|YG*^^y zO7I-dZhKzyg`~(X*W_EI>B}Pme_1p?Gzm=zr69lLY0A}jHE~KtRp`u=obx{W>-{5c ziifzEk0z=!1_*a@tii7C+|3%f7@z-GE8{2t8j-jrDnh^3V&s+*c_@3wWQj)g9hssZ zB5N2Nt+uvDz%k0kkBrWnzCHI{ll!otRr>A%b^GT|am${!%Xz)WS2yk+07mn

    Vb% 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 WOj2#5D*u zhvBrZq4zoaan?EI)kE7>v1-L~v#=buEj3Wur5_X5 zf=`dKSLRtY?s4hG*Rz-H)P7Z>{OU*zbp3e-Tp8>CzlHvfH0QtS*n+<5rLHG7$~lQW zjX_F=S#SpK8V-!6O3QxXRm{ldEt?9BSYz$&M(qCQRb6uug5VX-JBv|-q!V>XJcha} zFtx}$wQiK(IMBXJ8hzdkEUaE}foOQvF5+fNk0tk`>xz2|a89y(FyVT&2h5Z67v9%nENyFS48Kh0T1ktQL|w_%JOe)8E(;gH4!yAGUm&9ZB~pmD_t9 zZS33afp1cTQN*q^Bezzall-G^Oq7^?7jIN{oeI)$BIFVxwTvwpZs~gX#%8{p^5GlmW9Gl!OMX) zK_Xt>fn$lK<2(ao_RQWcoSTy$e#e8KW;r~{9LRF3l9l8y+|AiYG&tg`CbxY6r#|7n z0PQKBytC8?B(wSeP5IJ5&pc81R(+$(Fx71Q50Kj>V&+~g z_=KAK?q^& z!KNP1s#L0E=&m4}4o3{CYMxlSa4JHQqqCOI3YSEhr0+kIQ?ZgbH_nyX5B zMQrBn-vJkuPr4G1-}eyv=9j1$qS^(SYfU_P)!b2gMC8t%vU?RUd@OdE(zB+EAy0aYJ8SF!Oj)Ijov#+ zew!^$7lwZ{Fhv$|h6ddO50I9)r_qn(j<|}zGMW)JF<1xpl&9<|m_f&^^VE*-3f7yL zQUTUXw}cm1%R52S>~%aYkv1IXwuAhifP@1j<3{zh;}7X96fWtW2W;8@6PN41+xV4( UhsO+boAH2<|LF*7z>m-W0e~bxEdT%j literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/greedy_5.jpg b/releases/2.0.0/_images/greedy_5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..39b02ebe6c0f3e47c47f8cfde8fda73f30a75dd6 GIT binary patch literal 31976 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 I8kQIS9~9VPTL1t6 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/keras_per_layer_mse_loss.PNG b/releases/2.0.0/_images/keras_per_layer_mse_loss.PNG new file mode 100644 index 0000000000000000000000000000000000000000..3b8cfde4f6ab9f57e33dddd97dfd503629cc7556 GIT binary patch literal 103129 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/keras_per_layer_quant_enabled.PNG b/releases/2.0.0/_images/keras_per_layer_quant_enabled.PNG new file mode 100644 index 0000000000000000000000000000000000000000..896279a60dc83e45c424ae98b370aee6f6d27476 GIT binary patch literal 53609 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 F{vEQ6eH8!z literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/keras_post_quant_layer.png b/releases/2.0.0/_images/keras_post_quant_layer.png new file mode 100644 index 0000000000000000000000000000000000000000..1f2dba9c658d3df3e4ca330e0ae6bb19a479db27 GIT binary patch literal 9544 zcmaiaWmFtpvo4ZAaCg_i2@Zn=nBWY-Jp}h)gIn<67M#Ihg1ZNI*I+?{GidM-Al!N1 z^WA&b`El0y(XzXHRd-j_uG;lH74;6RfP+biiG+lNqofGZL>xB}+v+P6#J)@yX#{aV zcGpypMXH{nh9d?qY-H4AkdW#UupZ4`BE}dliU#gTNVxs~Y{4;abg;P5h^VjF$| zcy3vZshpRGjtAf=(^SV}337bq;##JY1LnDjo*ylF?+R>N-~zxwR%gtrc z5xT9M_t}2AeG|RRKaVL2l|uX@gaKEgAyPxn~PLhX!7fdsg8<$ z$iQ0`#zNEl1n1C9G{D875t77 z`jKkd<7hS?oJB@Ky0#Cz#&BYlS4LGOqunpKkIyRMx+}LlXYc-C%#Mw=b5Us_ryJWB z&&QMgz#vYB3-d)DV~146^m#h4YFtuQ-v6pW!nYa;a{=sq(PM$7FmIW*6A;cNVkBu+ zE*g?74vbZ;yud(zL)J!JJeIa@E{pY9OPNylRWCM-RIR~#KW^kL6J}J&yGvhk z?3pM%qgR-=C4NJ6X1Kj7>&Y8M(sR%XNBS`M2Vr{Af(VDE zTQe{SjH(#kVS;Sn)UzUVVd4bYKF|M|6`L$^_Whpni?ZVcbi6xqcHx~R*N<}EWqYoQ z+BIS#$9sREYLNhO&OQe8p{uRKY)N)pQ-FKGu^iiet zm`q<;$eXg>xEQ>YVwFY9VzYd+J&9?i!}ZbrYtgQOJx5qZf}<={#EE2^sbGAyyrvhN z)OLnz&(;Gdes#ZsN-y4Yx*jD8?d9QwqS&a3$e_N%C*rnxOByA8j8gEcv`JeoX(JxY zhsUm{l?28_5poD`o(_EqX+TZ%JTlIi`j8$cfT=)aw>=0V;O{d}dP$+E-2l^)$K!8+ zm^&Ci-?H&k%owJv#5ADN7y6OuoeaXUJ(Z~GZ3({3tga4%QK1c^0|vm7T5*G{Tc6cJ~e=t-W(7f41Hu` zSc*#LHpHz=FK0?zfs3wh8#6s?0RAmSPZv3c)7YL6mNH+4hznxSBa;7|hUQJ>{r&!T z2hV9cx^w`JZ3ql{RQPe@P@>04wsi9B)Bm6{sI3+?PvHpp>(X)aV;ZabtM_F}-$O7f zl9Omd<&Aw^tAW-w1Pudvx+&CRJX#^nxAj=Cu{2fHeqUm+=5jDKC}Q#Pxl_Y<_KPTV zwUlUCXvx|{N~-!k@JMN$y%?n}NG8_% z^%+46JAQ=1rPSBv0k}3h^pMv)KTbx3#@B*^eOp*PY(|5Mnzpea1J4r9VU*;xwfKGj9fITZ@!(DxO!IU+kQeiq5OCaj+ukt}T&u)B!i$BxRE!X}& zZ@U3D@#g%$*XVZt{%9xKc*C)Z)FMe) zrPvhwke#7)nJWD^!LOifJ_pYMr1ewcf%w*h0eg9?JjTy?CVHHuL2mSqSXT?qyiR|% z{!p+cvAY?(JF4?(bW_S!p;3a6jN$PEGaO>YtW=_?=ZWo}g20 zkcn*1#Kh$8?mpP}aS(ou1(p6=)!xK|CAxTWjwXoArkNq}S6B*TX==iT&}2m%NWi;P zT0nw&9?kJm7!rq& ze-iaEx7U+F78e(BX$38xR#o+S=Q=kfeR#y|{`9?!S-VyigG%LJd8*ute2F?DFCBriiC^&d3z&f9HBU~|KV=_786 z?=W%sXgL4&T98iX<2Kck85f%Z1CqP~%0;#k#3JEP)wIEL_OWCmTvZ{RT1?2?yK;V3 zQ*qwFui5)e_vc@<>u8`&Dgk=xpvb|9;%3qV8c*caIrL!zDQDA%DJ zY%TMgU(s5X)`FuInk8P2hJ3B2zmI&{EBAz{XxknNzM3usjmgX88#v7cc%E!sq5ExB z7P&|9u%;;J3=N}gxld@ySnD+L1aaD^s;Y~nC!6Z$A8)qkJ;Y&YT1T_`Z@HY`E@HBqO#bbY z_+G@9NeHB(q8g5kuW2^6?zv2DvDxSHJF;`N2{E2A$dh3kP>1$1!UOZ^95KQUWka4{xQt?R^KY5(vUVQeuA(nR9 z_5KV^N`7COLsEgLvvme&Q&UsX&Jh3W`!#ZgxY#%%FL(%eu2Q8AKdyu3Gjo1&m1ben zrcyrf)$;dJptHBDft!R1^UlcoJK<-8?~*Da^4ale2!}eyg})Gd6B#^82L@;Hn3Q-) za$vr%;p53j8rdEZJ?cG+%PVtzT|J;i$7NS$GR)lG;s-<}5-sDCpiECxyrYVSq|vUE zJiBj=WjE$#kIBg4>)guTOpFX@SU7U_1HbW z!r|6j_CgXrK_R7js(%cHjzc|xw5xaSQ$>%^=yH=0@c6q_7d%$$;K}WAgw}Ro&sIv@ zNQA!qzz^V_IYC*kpq0YhQP9xd4s=}uq0u`V8(Q&rC_=0U>_84Dt0d6-ArKVYdbiU{ z{!J=0evRAiI!&`n<6BGEOSkm}o(4>R%jf-|?&l5U**kFjL(2fcofPqR3y5RTDQ?79 z$*e5q6&xrcmLbB-2PDni^~`%WYA+b2r%}3!fPis|p;Mc`>GVUb!vSQK2OEQIS4|8p zgyyFT(MOFmn?#k|K9b+8j*KFS+p)W{lJ;{9F#T_9^nG#4BUbDTHilg>+iX@wq*AoE zK4BfYQeFrbu4u8GP!b|0vliRvSt$I^`&U+0?9{6)kqC`b^O7^4FNEBEIb^B?=M&$D z55#`qbCm@iPAEr&{!;+yaeuOYVMdPQM~kMU*@AAti;8|!g6qS_5#C%e)qoe z+g4LS$-F`H)#@~8*8{Z{WRKxoPXSEcqFKbZzHv`hfmKJROn-7(`Hb45TOjKr6SN$8 zCEl@?3sy@$i2xT<%`d*beurgDNZrd~^`$g}y{v~%H=>4I9FIa1cV$q+CO-b?$J$!u zYtPkLJLF2cd)E5^&vvCkE!(l)#AD~^ z3ak!eRl4Qyob!%C@?m3QArcPq=avqiGYGc|1{3n)z#|o{)ej+L;^7gg*Wz^;%mgR3 zZ?X)7!9P*<2?xcLU(hH6WHJXN7Cs$T5NXJ3{FwBuAMFxt`wqHeG-B;UF{6yG%Il#m zn5I^R_yQ4L*YY$~jx9LDY#ATLG}+$6ndL#RlI>PtfSzBB$^lEURGIWbwncveXDSh? z246+)?cQh0>fy2iC87Vi#(oRu0W+^PlBTubpE6l=;w`NYdYR(X4d`PxwjEGz^qF1| z42Ez~@sftEu_bgb9paPU7JXlpu-_=hAJi)zYQAUZJyu7}G_Of(qX#PVgnS}9OFU_2Dpxiq=bg8nypJ!#?>JhjxF&qf@|e<- ze?Lxr@;%skdLpZ_bo7_Z9xWva+B8N1N>bLgn09+tpFqwcEK;3yEuD-{?I*w`xosB= zW|UGCKp{%evhI5bPRjNeVfyd;r{}*Snrp@y$;D~sB;lVkf0eEGl&yUrNV@bo-guGz zL0ef*7G~d-LP2TW2P;LjiTwDmkJ1YI2I3_OP_wQe1Tv)h=SgaFg{z;UP2EzFm8+8x zd=sWnNjP(Rtfy@iq?6c-R40!9CBoy~Uk zo31=Mv^OPus^+GUO^%Te9K`I#Dx`}CLXy#>2JzVpM!hie=5Y#cW6sChs(xpR z0D}*uIR~Q`eAZ;5;7@;*n#~y&o`s901d~R~Q0pi5!!alDDf{9`PF^;#o z;DHz8Bzy1l)yj10N%guZ(TIyuL+Q#Qa3|r{LkhT#LAEnUjTsYdONo3Nbk{BuoCffT zntj{hAF&@ULg()Ac{7!$7RafPXDEpJc0=!MtdCxQSgo^rnX=L;2F<0ouvYb7`_hJn zGpM2`PYrD{-|Oi`wVx&x=q}xjxU$KvSx~Hi@DsE?E<3vJYVtE4wtp{M5A@Vq2wjIe z$gvLK-E0@I=78~H6+^un&f?tm1sztipS`V@ziLqMmWp|zI|up%9$XEkZvgK8q^hpE z2ue*r+ZqPp+Lk$OnGMPKcKFU24OG;*EuK%_0U`b%ycc&?w41kUvqfTn5+$m!w(BS{ zC=JyCw#`(A-zTvm8S6$2SBstEvXAtHwuH}rY<29GzPU!suLK8MZx6W2EM|4^8{XFu z4I#f1++@rO;d`wxKJ{pY@&ODJFOtcV;!#Uuv)!;oBI|w4jP16p};yT#F({h;dTELIu9Q}MaTQq-{{$6 zY4s|DQldM;*M7V>w!zYD)7)e&&FO36Be5{Upwad^d7NKMZMDAu0P&7~zleuGOhP0# z`Z-E04@)8$&pLA4@SF;49$Qj9E68F%8@I&?(pa_ndXY_QUgfS7${Zl(`yBMHCmZo;`SW+~Nz~@B96-IJ zzC;fi=O8f@xpC{gJN3Gep=!-y1aPIn@CF-HGD_0h`s-w!U2&aoGV z8gdTkr@mCAfLeardk6%qh1(z_6narbLh2pc+au}FgrV2YhNNs^rQJ=sUr(sHaCw% zouG%$=3$^RtsD#!_`})wGX=qXxcbo%N4KGlIK&&fa{}YdY?c=A*)<$y6~W zaBE+>TinuH6<n~q;wzASrMtZm}Elc|YLsJqub;1s{&6+JRet7gn6HjJSn$l}t{a6EYwE{j|?S=Xv-Wz?_d9&B*CEB;F*rP)9`X01>v zP8bo*BtgFg!7cd|aA%VD)ZZS??~2Y}76T?%o2w<@n|}Vw<}M#PbiBc)KsPjrnhF$T zJRY`I$@~0D4==wco&vx6aYYCd4hp5E%lnz&)g=8eQLbkiptcsLQ(i>$(V-0Nt4&8e zeV0sCbze!sIXv(q7iGI?^tw84eembV@ARVcv5o5M$xKXmj__&SlOLYIhx@TnC4mi} z0~%NLkOf76P=K)c%nOY$)$nO0ZS(6{asQ8xYoqNfSjm|o)s<$A|WW0`Tae+ z?iR14ZGYm!zdKXr6UnQ8>6)Nt@X2Cb^=;fqIiNf|#(5NkwO&F4XyR9bzIoh_t(4C_ zN}nk|%MH#xCrfvx)%gJlM2m_Z{u~WvoI#t|AK+Hoezi?9FiZDQ+QypzbX;RZmi3r& zH0&A|bX;I-+(E3ZCVC&%#%jEp5z9;Xlfa-Dz&$*ju~9gX!>Q0y-Nx1RVoeN-JoeG@ zT8fE@5w2n>C=U<P*$<*eR;AuM1mt zOU6;x4vX${bDK5)wu}7iqc%f|#X}w1zm^g=bPvB<>18>5QAAJj&Du%T>n)&9e>(T> zWvKyd<4fJTEwfibqZ(`%F%7fR8*t;K0?7m`iL57ct&Fks1ITp==;!fh)8Ai3(-hoK zZFCJqGF|ZS8TvHd{Lm$}uHyN2tzq$SO80`*NtRshwFQ#f*&K&^nOxxk503;N4+B95 zE+KGFo{L?w9ZQYm!(08-E9JOq2GJt<$D&_mGRhz{_J#pQlwD8&N_k1mh_z?AM@rh$ z-br)|&xxU5W#i8iM0s(4k@rma^P85TA<)4W6E)HO94vH_mL_o3$#S!va`5NoRAGeq z8J!FopXOa6zl5LDy8~0DPEL+CrIV#Ej(W|nm>HVR zvThD8E@NB$KBV2X4y}I+)nUs|v+J4HFa|4CW93o`BNYLhIty&Ljw8Dbt7^n6X!Y8h zv82z9FDsuQH!KCSj>r~e#%ZX(LeKHTq3cIJPhBe{1taPzei+R9%ljhf)5{J|5XjQO zffIo$E1f99iYu$cW9=NseRF;UgYoT_0~8rkxr(XlIk)@BBN4ERD=;*1>O4E(zFK73 z@OF72_KWtMzY3((#yVeSGk}|}PKyFcCiN)6#f9Cm4?&}Xwit~$;N9JqO*S|feLNJ* zo*Y%0r}*@EG($|XEYqIxiZ zTSjqRKB%64etwo9OGJ1^U?e$R92Pqfamzw5fv<;;XBFG+$w|)vg6;57(*VEGP+pt% z0wTj!m)Yt{;|PXlih`^_y_9*1u%f~WlKGnFX&%eU5d(S~Ff<`Hw)kNWg2n(v zfK?ev5a&Bcb5qk>5D0Bwx5FQWA13e$?pQT$F9AhBm-X`ZsHYC;ZOgKzyaQ^IpKPT9IyZt9hZxr%gXz*AXrKY39`Yb!#20Fs43|&H*&$`Cn0W> zquS*f#dD*vj;L+WuSEDWg^myyl0-XwO&HjAE9C9Uk1O(WfAdB-BC%M~RuD%+r0#!% z5P*})rhDQypUjV{s?(P(ZW)h;*MlN|Ha}kEv%gaWp#0cX(u&4Xf9>e8kua^u&dyHY zWuY@N>vJ+Q6-L0*&6So^PPNvZp4SB>jF=Fo~CG$!eXNSam+nVMMwGcWR03#t4-fG}3tfOpu*K=;T7w&yCoqMc0G z{0NC5#9U(G={>--E|sdEDR#4jk=)4NEY~oIk+xbGZg~9oSMo#N?|m{qm*s!NC<933 zF9M1ls!X%t@bEvE7O4m~gsJAvEibbz?x`}6iKAb~=u0LbN}^rw^$4=`(U?XP&cZ7W zDRHUC$m7++dw#IJbncwvP`>6C+9=V z?R85K%>qCc6e`It%)`j&R$vyz=Y*qbYM0o=o?Q*j6ujxmz2i1+{o2^5&9#^$8xM{h zez(3&E%K5^7`pV;&G%@y=-#iEbm3r)#_Y`il6)8kV(EkK$DVKvE!HBGzYY%% z|B6{y6YAr;G7o90uh*O?)<;;tA7N{=rw*IqdRt1`HowCjbdvXA+2QJHOXk>@)+x%d z7FvJrFG!$W2$#etIt^qyBC{|*gC;5Fo?VXEuFGjil2Rp01jqrw(jjcJ>?q|5ch)E$ z682|Zf#0n@>DM|tTz{R_0>llp!6#ynW^vxy5XTBHk$)F(ytJjIfoXZ%o?-)CFen%P z|Apa4@C|mhM3%xZTpRiXd}tkyRHL0N+JTf$A!kr+HubaaT^))-%iWO4I|4PMu4P6MP7G}@;S4c+~codoZ|BceX_T9MIJ(3(YgwU+{GGIk8 z*dFKz4603cj#L{vm@Uf!ySWq`#HPpAAs|J0F`pL1y610{aC=i2yGzo&sse*vJ}T$BD>xw0)z+!+zh=zV7~pX|p)%d8*BTwzCIo z&9H+w{{Tr#c})#W^{YbIRHDv!T(=r{npkfEmTj7KJPuogX1F|M&B5E_WiQSRPrI0_ z84$Wu0gx=W8@9C~NH}L{-bc7;^MNHB@t7ytSv3hv>lC8d6tv`jx>kM_=_|5i{p9lF z7VQc*{PDlIwk8?C_k?F#RQu0GaXRC@6&XjmReCW=2LBRxhJ`7Zr{Wo?MW)&kN~~8M zB>eeT9M!gJIpEV-cBRo;jCG`I^Z}BpsQEH8U>T5F`1?usaLm>h$^rO-1XTNDgc{jq zY}=EUSHjx6D%tp{pvSAc^W1Jw`W__E>)|$Yyu5?@v@8cV`!B?Pzp6&^FHajKadh2$ zYm3WTc{=I&TF0KE(pvOpHLpMFcz;@znECy?i2_%?{!#?nXjHu$^+T}aUGde?QqXC) zH;cuu=vt2bSERFMTBoy-lpCfTtai!_tLLEKmWS9`J@BvH&o`mROBenbLEQ@3gB8#MLyseoh z3kCBC#UL6IKx*6F!6Yz&&)@%dvO8i*woE|C`*qCbKcsZ^|44Qh79|F=Vp1e}H^}Of z#AH(*vH7HBVPYxC2^UOdH)CET%~&~oU-|$WG4?_iBK}FF8TNRBoCsaLJp=tiTBm}8 z8%neDk=Z^+rPVXW4CHwPzw@3qEH6-WR)A$h5*L>#0$v7ZHOc-s=nd>$K~@y^-~rpz zjt^0U7extPm>0gHFsmC0!DcRBnP)FT&oltmHC0YA5~u6fa*v-3t{~&jcE)fbs5P_> zW?cNnSMP0|PR#+x@s}DlvJIRd86!s~pBX2XCq0wk8GJINdd7e>5P$=J5Sw$0Rfhw-HRsL$(X3=P; zRw!=lqX-*=b)j9DjRTZz-buyqa$DhJA~(E2x8irrevZ>}~!92E_(h~g7R|^-A_nL MZ^58y*$*NA2kwB3{r~^~ literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/keras_pre_quant_layer.png b/releases/2.0.0/_images/keras_pre_quant_layer.png new file mode 100644 index 0000000000000000000000000000000000000000..8fe929c501ec1446e18e27b495b9f477df4612a8 GIT binary patch literal 7062 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/keras_weights_pdf.PNG b/releases/2.0.0/_images/keras_weights_pdf.PNG new file mode 100644 index 0000000000000000000000000000000000000000..6b6dd360b73564f3f4994707e7412f87f1072131 GIT binary patch literal 19691 zcmcJ%cT`i|_63RxVl1Em0pX)4AfhxuK)R^(CLq$mNbd@SUKE3f^dh|p3Q`25O4leg z2tvRhRZ0j&dJXmM1W~?we|Nk;-gu7T5W~qn`|Q2ensd#y_6fYBDtGEQ{c#c!l2Z!u zw>3ye4#P-D4hbAP3O;ey@45{BIpm}vcatQ)?Vm~TA5sfx6=@QZ_hBctU}WI`kcaZR zP9!80p9y~tH9EXCB_UCMtZ-ZUuA9+JG9-z*zNT>@I}jsa9cgi`!%dF;%)-rU3namE z-@fEsti7F@5Bb9SAtB_pcDfta;3Gk%jxV>>XU!s%>Q5}hXsLfnlp(7ijWK~0%*O8~ z`hM-QcTjWH`np_#mRQIj z|DQe(x3ssJ3*j@xnVHXe zdwcmcyC3S0Z#WIF9R|}_zkxKEm%hi8#{&BVQ@F4DQ~W&4|GYND>3E^-kh&W)3CW$= z8_0i}j&L*oTu&o|oOl*Z)}|qO6X_QfgiwIQpdLiil8~g|Vq;fknm2vKv_2+%yUmH| zc@lXRxL4jvjqIWI`)t_9#<3@Mlfw|%Q{3g8IFWM3l0nhC@mF&^Q0^uT!IL?421DMD zEs}mLOfQQ2w7#i@8rHZcI;ME`fh$B8`JolnOEqGT+G1BmkiG(o0wW{&L0)r<#aO%S zDUL_AQaEw^#w@lb9JN?RXOw~w&;@h4@!_^AvY-4G?o*%ld;~eQJ74tDcFdY559J-G zd$^05_N$z7PfwqfV|os}{nM4xBl+dgkd(G2ybsD#B6jX`pa3P6^NNc@dx4SB%J|HJ zi~Hu5=wgKzH}BX6Z}q&NP8+^=wsl<)TZVPQdC6)?HQ;ypQ_IB|&d&Dt&oP1tEIf}! zOj4X)yw5>-H`pm*^XFKp1n$#U8_(d)k8f^iJ4k*MrR)uM(t9;E<8SbtlLU$vU4++U zR$xEYNLbu6>WjKQ?ckR)$j^(zjizMgmOIsYQ5qGnN1#v_%26MN61})9f-#=j-R%QR zbc4@qDUFu4ANoiJZv~H)0mGsWlUInF{W&7}@M_M}Sj?eD_m6O?y2BOX@-x(1n zv>bS=`J>#r`?h;$SCZY8OugMw@-i3-PTqYxHM4^MFcg$O=;%IpR1Mv&Vy{MnvsoHy zb1!PbEPBl4Y&2Jjl-JAHf1Y+)`iz%6hsP)6ogg7$F=(-8YZdwG%@XUzIHol*H3JWK zRlRbzrsg42|3H&n3uYxDGm0ea>v*x~A=b04zeyY#;|$4jurVlPZ{ zl{bdXuBCfA7%ge7IF*wNSK?LsQ?s;P2o7^=tQ|6nTO=8mTyHvZQf<_|5)Z}G`;e=q zG%Pua+{vDr8BD24@y{uz^(kN{Y^&x`x&bd)`>3okOV~q0)LJ!IA*?vA46LivZ_{?9ms)g6nMDkRc^YyUT}TIej!!V? z?-R-{@2?fJ;O*~Q>Z|2)6dhd|RGGqg`L>C+c;GrIlKLELL4bQaaz+7igb*Vx!C64q z1Ak;lpyrP^b8ovo@>yBd8r@20Hgw$XUCd?6UkRn3Es#!T#}xR2S$mcKzektbipXb_ z%&JPUJTlUpxf;8&HJ6N*?%b(uDe`Eg(-X8yz==~wUys$wy=SJ(D%|F^K-25g%WOFn zi4o8|uJoEMPrIO#K5mqf>8-TvZB~mgY8f)e&ZohxcgCH6nBDf>)E`&C`<0o>CONj0 z=1=SCTh41@zWIjivair@p4eC&+s)uqGD5X-{}Wz#T3YV=(_j{u|KW4-uUa9{i#PQ7 zSye?Qr+TdlGSu!3%Fl7(CAil|T%E^mWoZ_WlWP_%WH&}50{Lg}(hIr@g}Cpsdbrfb zcE!t^es5!z*Lj}CIxQ_5UU>5fVLqe~sxiC52p}ZfZJdrW($7s5kQ5qZS1%%(zNH=d!COT%o7me|w?_5(^J`y#4BZsBG;b zzun4x#oCLinMP6c2*e{iN^D6$znL-^;eYIZjYg@hngt1|v6PklB5AZCM$czPYA3l9 zyWEu3-YKATPrX3y;&M2zuFr~M;nEit*m=LuJo0mAzV0}eUAi0|#bj#wj6aJbmCa+N zyEST&%&s~3I`(zW^k!3(-(Fu>@cPe(Ds0ndiZ9VHeg=n9YTdR}vo=sIVE^{^?AE#jBy8SI; zg@sjsIN75_>v^uJY6Mrw_wpBQoKgLLtM829a)!3#KME#86EfU0bEYv(uI_-+znNa@CdLs&AIvaK7Z=*@H6c6Xz`#8Q~t}eGy&&~StUHFHJNK@Du{fS*IHuU@Kr!*2fJRw{6 zO%%U$vOX}NkXO)^bkkG2b?e9}`fKvh4Gj&gUA75{iPYp8 zZYA&jC{t>Pv>9yU3jg{H%kBJ`(jom>VkX+EAU|V!idHkVIcTz(-JE~oBFaPOtxlfK zYn^mJ72dw%-ZVF@Hjt6=zhn=|&CNw0PofPkTs(4ac&h2<`_WJ#LvKMg<$xmY;VJn; z7Nig~l_x|g!q!l2#+C8rjBnpl(Z(%A-Xw>{$jmg@bG+^BgGzj1)x?xULHd=Q^-GM` z?9NFPmk0_7yB6gI$bEY4mMvSUQ$oX~!y;Rqw4_^YZDUg}!~(niaO#Ha2Q{5nJuvdb z{3;4)=B*zw4^#Pw_tZQNZ72z;jrdL}60Mgn86>oALRzY}$)W2Yp%iGQ65aoeD@K89 zD>9Fv0nI=)-VqYe9|3(YHrY9+jYg0gpI%z3*F@?R(hXoEBzwtc6c&qBza~#dk#v!TRUSN*eHH0| zGnFjT`BER0P5I+FY2CsPjUGr8=q1JyXsv%>unUZ^&srny8+lGL1uRz ziH(53Yg6HsCC}e5(bmS*zOt!xQ;eIPmJifKzAkL0+R)-y^)x&?$<^K6eSwcU+VN61 zI#*^PA>e^gS?^_O-));>5X_5<9yOiTi|v*2{CcGkd7&Zw33LFdZRz3dVpJbC)&TF) zaLNfUEVY=G&Q%?ZPw?HmqUXEJ&3Q(gIpH!r-M+v z9t>L9vFX~el_-^5;{LaERfijcfJedk$+hdLM9*<#o7PN2^V0CheT>OQHPc zxfk*rDc@Ng)Q77VBbf0B&#Z81WY^D++2lksT`=CQ-ywmZU)d^s5Y^aQ+h{~Z;keh0 z>D4*|d7ULy+Hbv4a*;LSbqqy0&!boN-Ap4&{`K|NV@Y6 z$T4@6WEj;GljHSt2mv-Z8AR2ijvB?VTajfw7Xqo4PTkP&{7l@)N`&{>8z4f8iGi>P z;)Qwr3pVfVX@$z+qw;YSCF~MOXV{b}*|@IDlrn9(>_rwq6%|OYOCPDB(_M zwqwvtawyF|1Xyr!A;hjGg|Az9A@5NJq3*65f9D72`jg++oXHR6A}y#(NptW)XAXZp z4-<{HgJ{bgzn<|{A#SMVdUAOLzwWaL*BjrsvyOnV0X*)lnk3BsX9do-*WDtBr|RTi zXQS4FI1O$n3{ohrToHCWmvvvnp@j)?U7^Q^N{W`dg_f?{WCV-CrmSYbrrh#!YFZw`%Nn~R%Ax$i zfaeC%PxJ2dC+^E6{CGl;`$Y*(-YajnS zG>B*)rTV>pKABn0HHPg+HEAAb0~0bJ|K`~pJU8!MKlTOvqsDSKk-?71`&bIz!mXts78&s|kr&QsK z?PO6mkgZlfK157qsb&QkpZ)Pko^JtU^jJHlmTb@pehW^h=6U=KY z%8p*#%|x+b@A5SW6?l|OGLX>%`TqiBJH;M@%bYJ7c!US zRG=I3xoJe!jPrT_u(^}ZJ2S2=tZj19;HnYtP@nceD-M+!%oJ$1eRYI#&x)TQ;?)(Q z4Qq!?UbU3ZZ{Y6$Q|pc(0d9W$knvgkv~l@2pG|3`^9|%Oc$|;&bh5|`r-{_JeEmX_9tYc`$Hz5K>HP4=wB!;mXd zM0Z!&-4RN5YCGC%C;WG7RFHA$#*ED)Umn!^)oWna&_@@^rQg_A_y@~``bs`I@byze z3F$?SN4#-j;e3pMH4wHZ9pOIA0rO`;c_h_wVri~G)Nn)TdWH9&oaSEhdX}XSFF*#p z=d))Rw|*XoSbhBodkP##w&w^N{GYYoa6E`iI4d)aN$@GZv*EslF>0y|^U z@%*N4vH2-O$7XitL3dn7e}$80>!?Y7bm8~!_tak_7PkCP&>mMG85MMp%jYO>Ucz3h zL-siq%n2qlzbUMkZZ7z|BJ3`KF0$^v+}_@1xcHLqnS<1)wL_>iA?nLTY{CADDX2FL z9gbju=nNM9$?~Fq5|b)Ggw9|8`IywuV^Xx&5!FiiGYBv+N!a1GOD|YqUbgw~-pyS7 z_Nmb#r9pz%9k|x&|3r-qsC5%Jfm#>RrB(T%uh}Jc$W8aylKHAYw16%V%9I&kk10Gt4iJReIDD@3o8Qoy0=4tHn zxG%b4HxEIsu>2V)#q;6>udlA0@h1JQgSfyMx5LB`A9bO=USx5M`oc?u2o8H0=F=B3 zKh%aZ;ML`5sPK997;*Nrybk^eA+@}}HbCW!eK~EJXct-HBat6|7oY^tu-G+sJwkrH z)DmKt+#YbtM=2#C*|5*#>c^U>P+`cjFnB=biGNzM(Iv!3|GQ^lr19sn=dUiE_0uqpe44J&6QtB~)}_SZy?4Yfrr zJAvK7jG8${@X6MOF8y<@L1K!17!v_s&XK#r0wW{ccZY;zSJiLN&rDl3GDej=AY)S| z>y1o#t3>zt!RS9`En3L2rk6{H#i`tM-Or@-OMYH?BpLf~dmX;MQayEsS`!jvT@`SE zL!8<*=rG=`46WUsVdK{I8w$G%U?M=^MI}N6`>a_DNtcqE3;bxw!wb$fTJ9~|!c<4o z9(x$a<@lP5`QOuWQS21N90I+r;ge~NsiWrvx zL1||1{cHUYlTQ$2fa6@~`LUNp3hr(XDO9fZmX`F{LpVserck-FQCiZ-1W6F4gl66ZX#)K9V*w-qF?1gC?E?zIg?=*6)($^| zm$XYltZfm9Y(Pi*Irhjm81@L{#F>AtgCtZQTq%YPqc4r|nLms z1_n&$6Y}0`78E|>8o(r^k)#AJsK%)nN6R2=mwrx7k~_xTbc-!P-0rA~WnAydR&hJ6 zMNBK>K9&-E$vpAQfHPXJ*V7?!wi?}{OlEW-i$Gx_G(MWQc_fI6iq&89nOho+=asE@ z8=MlH+$_Z&|2rXR1-4G8%hFeyY!IVUyr8VG%YZFHFa9Ku-WC{}?PL-5!62eJEaIye z18uRfmu_q7lA{l8$$mckL6rZ}7BiZ=OkSx67VzVm$Y;2npTrwB*tB<< zz@~pJ!n6jzDi+TvVWn1jCZ!$s4117Y?UabXV1xP4NB4Cq|*JV)LFfL*78Gl-% ziSznUqZk}&W+B6=Pt;Af0OMR6lUJTJOPzm7f$qdhs-0hrYN{uCOaz!{XI_<-sszU^ z;7tkyYZXx1d97T@QXq}$Pe07U+RwptNhyYHqHjo5spnCnuJe$0IN#ZpGQ=iGIy2rX z_T=dnf60jcXD26&%(gY|s_xA%kzX?IT>cSZe3pVis8zG;Zfmlb@N}+HdDDVTi$?`c zMgi&eS_z5s4k<{zKpM=f<Zk>z{Mw#kDCKry_xRj z-Jp~M$_QSAwVEs$Y_P4q@Wn?D#yJAl?bo-WWG;S?>r}p4#$@4kxp}0prZ!RN5D_Be zb?zi2K$nx}UbFu~P;pg`0=E43#&pa<`0FVDu=g5G>lI5MQ0SyiEDcLw|54`hH(c>Z z?PH>H(W)fB4Y}v)Ji74>!1Ged0dBwIu|csumab^s=V^BCR|}J6y7^B zxh6lr^4NDoPA|BdRD?czj}WOxahjfV=*y)jN>PvIYfub~n>?m-MXBSKc5=%^hDpJb2UrH3MnGbX6cA{*i@gUhJ%}@WTF&Pc$j{k=+r}x`iy# zRdXpZg`b{sSMGQa7ZQ99h*k@QP@0Ex~7u>b8i{|f& zc&d3Eo(^N?q0+eNDFYI}slhppPo+$3l& z7p!c*FbFVHRvoQNZcp}~Zh;$=SVp*w!ISHAjeN|ybF@-YleGgcG(g8o^vdp0G^-Uk zL&wQa=y0Ctrj$@5CInIrwee{+tBPTWWS`2Hy=(W0OoXZJk~J$#9l`##=Qeh_$*Z~9 zLnpsSBbj4v;Tn%B3(RUi4c=)@PE7M&RZ!BA@t64=a3Hz@1tajU2(yUm)}|^M@+k{1 zG~RAWpR(Q$ofS%SlqK_zgEn(->aH_f1?YZ2h*`wFiG@0UJY)qCo8}72$zk~o0(1~G z0Cs}FOq|Cn6csc52cDaDg= zQi@7FA~>CE&X@MCB@k}{6`*Ff-Pyv+zPWS%0IIrgSS4;OD=76;;Pjk#@WcQF$__+C z1Gq<+$?t4c+I>+Wabs0QiS7irIMeqzty{*PEdyQk_oVkPjTb>@ex^`T>Y4L(=qT_F zi6F$a{b9okfBwy3X`-_=xkX2wgLuzqjc)g)_~Rk}F)Cpx=;>`m7n@2DhHkG^q&Cmh zhTc6OnjN58@lTSr;;%JlW`u&JsHg37?oxnN&Hh>{41@JMeY>4by%7fudC!y&`@+VE^zV|SI{$N9QwF4?LEjM}TvHq{N= z1?bhfg?Hti!J!M7C=(9BZvw@}P0Gz7>3Wp*>W6^P#&v0J(57RdF-s1aUwQewj~sM; z&k#2f3B@dJOryD^w5FziMC3{b#|eKoZo^u?K@XhaRsM!f?07aVg_hM6|2X1L@lG1Q zImAtWosS!)ZJeAoSX1m8nZ`gw!f!*ZpsZ6_S!64*JAxXiE@;-Y_{O0URGGOn`>jRImf>aGZBb}-E zONV~1uXaqf2ydO@v~bBc#IweU5cj#~PM_DW$m6@&!h%DRuj_K5{MGt>7bkI+Doc7- zr9c|CSK%Z2kYG!?rYi8E5aElKP|JvQb9M1rs+^)LH5+ z9l=v^E?C>yy(wE=Wztq0zXc+mw%lQYp1p_z;wHWLb#9pOP*U2Q7dbTZFwlMY_lmF^ zJtu2L7n_+h>er5#OzM@1dkcJbrLE>j@vR*@u~2>bKZ{x^Zrtepe&v@hUp~;2ks%Wl z6bziq+!xyyalJO&qBA8WhyfRUzuJ{|_jd)j;efgCPu`(j?Zo#hP7L)G_op!qX;-PH z>m@#lii$QD*`Bwix+oQ+o55$QOBtl8rS1Bz86 zaC;y$6GIHI@B6pu7r0@r1213Ol|3O^ya6NUo>h{)%QfpOSwv~YTli<(2e}rCH>l$( zr}5VF0@jWQ_#Peh-6@u_NQsXr^qf`b#MJG9!3VY9UPIko>7l42X)M>4C|uB3wAJJ| zZWOyvdAU;;G!e<%zjO(ECnrlgXhe`w#&~BwU)rrNSy$GTHE;nnXP`<)J;8R#>X{q7O@zRqgXoG0&)gz7)>dpkJJrcyd z@znvOu)Ev06CG4d`{LtSP8^6b>hEk`=aKI-WS$Qn(~H|@V+sqrL*CX%2vC{s@kXKx za^}GOL98WI-x0a2Px(!s%j~ZC4nWIRzAIQ;eQL)0fCM`~lsc`B&^wT>rwu@i*jGT< z`ZlSdbf@;27$8L`b@rBq^GWURJ*Z0@{~fMaOgNsWhWa#%RW;m=#?G^1Pc^; zObLw<{O_i>@Jk_zuP)`R{3NeFM5wIemr%xfBUcnSVMANykukgh2t3eO0CMilVZUF1 z=(Sy%c9lO5S1BQPaK6wIw?`KQXg^5n6PhqUyj6d91;F8cfnACt*%Vz*>#EcPBr3~} z3-WPCx{9A5b=~k5h!JWJdi%1jWBtAYiT93KXCQr)W&=dCh9Dd?uEW*39M7}kVfBTWV&ObK@%`F5*@~hU(3n3`xRlsj>*4R*FhV5(0ilB|9r+uL^;cMC%Uw?Gn=y^49{0F7o*-mS6V{t((%0<2Xa-qe8cTr_tXOXZr;ROFw`@juq>t9Clu zpLLdmNy}e!uamx6`x>$R%YtU$;gNq^79c<8VVwIJ_^XVkmMCsd#U5TCSjY1-|F)LN zsr@wr0R;B>8Jk_PN>KnJ`O!0(SYryv66i4iGT*ZB9(aNxHc+0W2>jq!t~N(~cZ4cr zb7;5JvWM^A_Ua4|iAD%syY?+j`sr;eTiaIUnZO}_I2_&!-zHWK0eeB1p(2;RI;=() zI<>vGoVfE}BLpJ=JgRGHofQ-oJ`tFcoqZ8I| z?Q7>}hG;vnMnZd1 z1&A*0OAC#VUN|NND&+i@TeXdR@W9Tqvcnv&1(D?z74c8o$P}0v`QXjY!wlx(ru6$; z4{Fh6>xUe&5QbjwRX9?EBmTxc0`X9nR+6MvMw+*$a5K3xeVztoM~6Rf=`iReAniHR zt%=OZ;iA8O`amFjVQnbE&NWoP>YhL?WE8;OIz6pWps#sd2@Wqkc9M*YOh(JRRYw6- zg*i!;V@~kssBLeQy7Pqj`DxU$zc5vxQ;NbUtf_9rJPHkmv7Ova}}E_cMejAro@|5MWE+et*h5f0Ph45pqoLCwokQAJ~<@@ohQwJG0ym-1Yka7GB6A zzMdv?~?VWzW60-VFm;-o!fXAAT$p@*5aqA;p`mZWn(Z2bw3$G9=*}wbO+%+{# zI(U8KxnW{+NonnppKA_WitiGPSJtqxVc<5dh?F$0zAX;AIE^mt^KSqGEL-??nq+tL zGQ>=2tV*%@@EU6kz>hyH4XcL%!trFiwowMC*Ed}jPsY)LLeU<507Z$@drW9CvXHc9 zg+>-xy;qdj+x(U{`P>Y`ovfoA9iK-pc8+DECr2}7N?@OlE;O~fi?$mNbw=v4`tDB$ z7|6q^Y?|bUH_H%=ZfPpK)sG|icn{!T{CBvfjg8*N2GumPEBDMZR}r8;!w6IlxdjBJ z4vsSDPNQ|tT&d@LK+p0Qs__39L@+}Bj;CC}C7rZoXxzjpEFKUb?F7azFWdIu_ zfD#C>!^>!HdeLk8zh!yo_+G(dFJnbl<_{H~Uy79~vkP)UHgv0c_lJeP^RPeI-hIXzWo3we?dfjR5Y-D`7S@)h0elL2hF> zVCqYb(hDUi&z>Enzh)VJDI{d@mR*h+q0_ObsMFODm>iJJ39{=?=BZk2j4h<<=i$Vo zl+O_Edot8-FDT8I*_>(0%)FSBlLNg_57pAtjDl0~4-g<$@yXH=BF6{f|1q&&;jjA~ z)XYJ@N1304@u4DMDWJmldzh?zuUT5(fhJ=qpIWy-Fu@$p=UByAi2c_h%I*=yEBxOv7hsqhThPL$UWdcEokXn7 zk0P`1Lh9eL!ZCeYY3I2bs|82J9xZM5w`$B_kN-_{{S@icM&+2!KSjJ^O?(VWZ}BUnQLE<)axWymsjSo^ zeMabM@bD-lba8K?I8wPX-jyjH$2-O*B)~zLKqqDT)p~5mt!LjVyLNuqFdbLySE6o? zEWDW%7Zy=??RS#a9f2>h)`|qB+hzRy*@(irZEjB0Uh*FYJqBb#YSY6JJWTaDZ{JSP zla0zr4jZ+^VECc(I{QQ+`s+wNWFvKVA*QfuPW6R4fB30=M*-NzY9>Lf>;s4{!mp2# z&J-zaFv090qeVZ=Z$px3V*Ys50U#t??2bz&_1@jwfi{#E=+rS~!0Zp$Fs?n-;qGy= zze$g#kP|Mm;PG-)q4!#;|Jx@i2k?b}nnNJh0DLz3Ym$f%h@3N5U{y0Q^4no&*N!_q z{XcRpKnIr0zH=o4;%|)fSSy>vk^53pK*-nOm_Oh{39H=+ zP}hGaESf?XBb$!wtPQ1}`C*}zX>!Ql?NOd;xmo&in-XD4kWgcI^m#J-%2Z}%W}=(6 zD0(}wsCq9W`%mP|M?s_8pY%P;mZ!2Q-FORWjLfeQlHQyN5F4-hlQ>_5Vqc;FBJjmyzr{b}`<`-Z^G-j!dR&>uoN$W{IssIqcV z#Axd*YuLl)h<87DtGn2ZN2ju!x4#;z@K^uC+dhr;45d5xm`}<3oIjE6Xv+;cQFhSi zo6;OL+&5W}@8C^6X}Iub*#yi-Ot0E?PYI6T$(g|=*sFsG?D7b(v`M^-ADH3u?&b-6w`PvLaX&CyUU-aknKTK$zHyGuRx|pKmCQ)n6 z&%EC+XuufHyE&V98t1Jr3@D4Ci^4Y~zz>dt+X|+)O69eZ!K_rPqX^{YV-S<8PRMC6 zt3ML)!_-2rAFu$n0UysIr4Q9?!7?)|nDa1I;6R`+a8CqqhGRD$H#^nz=UEwDY1<@d z@t_HyDn5H)-lN**Kn9OJV$50l!(752rG%uA=*o;2c$9b?%!qK-gQ(Xy!?i*XHH#h@ zbfA%u7j%TE6Rk;JN0LiF=5?~m6cgF#2s>=6SeB4CCxHOBPrf_5U$##=rcjL|9F!Ki zirdjeXRioodO-V}ko`m%6S!4C`Jm#r6i=5_%7%I+4Kqyk>hqeX;FqZ+YU**u%0%ovop6{ip{SBZLp{7Ng z0ALfdV&h6+opAv!javucm?Pbt`*WD%e~YtI&2M7$oJRsZAPk~inP{~DgvcLbz6dva z?=kn3(qCucSS&_6O8IRa=tsP(r6u$A>(`q(#A5`2Q3{7(_)(fKN31lebvi-ALp}c= z>36D`z&zSSJRnuS_!C1#j&h8P{TV(JZuV*eko8^%=Ue1#C`+4b;R$8wfQ6ptYpl;btYlwq!#T zzpd4Ri1TO2bUn-+Hf0}~$sKx4^50T$mVJtQL*^06U+!jXw7ih2r8YLZD!amh6N;zy zsnVY68eYJvBKxsA|AlkR)RgrZy5ou>(Hp{3gkJqf!#43^|JA;NTk^3Aljy8u$*qSK zxUxGQF@O3IU!{GixgEg;aY{j9h10R+Cr{ADdch7|VNc(9B?mDD9S_)+@bfVrRuGgezL z;%!cg0n%rYDu~JJba{680slAv;KWPwCn~2sjLtRJt06C6=E})`hEO<=ef%ryttbMW zfNT9x-1U=ytP?yiAAfP8UiRyn`4?^!aGEWyI z>rvjG$H5mG%(9XrqaO!Az-;RF^>Z*CLjV0^VZzCttZTSrj6#j4MQU`r3_DS9tzAD% z)36^Y2^s5tUIOSxr-4reyK2cAl=~%O!R|6W!+F@r1FU90V<%j>wS^Np#h9>(i3ngc zM=wua7fJnN>IX=IK)7bYQ_3=+bUKM$O+_s<>Mwsh@`fY}e0|$Fu}uQA`JKAxE!(e+X{wUx{0}l@d(>rB38;?;6oNBst%#X& zwNCExb>FkiU~}Mbg^gj#ndsKxYCfXgUuaAyPaSw_&|*IO;dA;Ciuql74VssT=EWHY z4y&E5#T`8jqQv(r_CIuS1IFyp1_o}?NwyX32m@ud;Bo;+Q}?iEoW%U_&oh9Ne|vrN zEh1T;o^H=Y&T(CYHgHTZJ06ooKBgy1`QTB3#7e9zMx4VYp@GW&w(Op_BpodkWYlqe zSjf=B%EEjaOTLk`moFYzn|Sq5k?!w$U3GObeReqCr}r$bzAVhmSNt|x)i)CG5p`x+ zWKUo{z}NUQ`W+L5zGf1-M9*31Tzi1U(o-EH+VO{%<|Br8pf=&saP5tfW z^|r`dM6yeQR!jzL!s-921q|5s%MC^B^YZ8T#O?IGP1Km#VA;bj#VErnlfbBdX(S9-59bxPhk;bmHY}_odKsw|; zm|kjA#g32*)+yV;s|C$gqSE#4-+y@-%4MkUkW9U{GZMkeDek+K0XnTLU6}a{IinHH z{LXJ>eAl1KfZX;$SE$^y&z4EhY^@l#i9?MU8srNj$5B$-*-_6B~nT9xWz2|D;(@^Y7E@--)Oa+QQG=?uAYwD;PI zfl*ANgHiWrh11Rv%94(_t215SzD0<}!N29{GG2pQbA&MVsZvVD)l@H4Y^ulj?p7r? zggInQqS0`#tp$pl0yWG6^X^1NUUOMRXqaTLY7|G-bW>lF(7UG%Axi}r+K=p`rkkeK z62Ef}F7>>>@@19T{j~)AC(6jk{&PXUudlxK!1AUtt|#7Om+=DmPHXk|h$Zaj%?v=xIfp+C0&boIT_E+~xC3M@0%(+sfRB3<>rl zHuWxJB_N;P-eL0jzzXkIj^)%8t;f~F$7XhBT^T_&YE4L0?45vCC;IXgv5D2bJ^%}S znnfKEk%1JV(|Ht+0z6`l$GmxUOH9+dl69q*aYX#xEsFOVP-Nf4Yu2z|$`W(0pHj}g zp7X(EnuN`~&Ip@TZjO=hoU=nSdFm{e7O>a9#T3G}5*V{L^qp6KFoJX1jMQE(T>{9TYwbC4_jcFQA z59-ZUOH~C?nH!)$5QSK4`u1vZwyQ%TXw^f6w@a)R`agFR0^gI?HtbgANczUPIKHAP zSrO&4Jxw8sOQOihwaJp&t&m`U%jmq)J@a5gfdl@c-Lj{!ExN?z+bv4?+!gzpQWff* zB(o}Y2_x?n>yFjg+Qh!oYdDJcjJR54P0CQ&Sca$Z`85lp&Exn9!4PJ%N3-o8jF(*C zo5w5iG2#W@{{5*7HqG#g`P#mkT8vQgW^qjy?h~%r84k!Q=P2ileOd6eZ?>;og$sq6 z7ors7s_}7UbjPLm7*-_JhT5gT$FS>g&+qSXLfcbK=w$d9<|X(W19!F$TZ)E{;fq2i z&CqaVUYud$Q%Y4#mS=^^h{NDTOknInE^D0wzOp*0ICMZ{5r-}gt(NdnD+(14D{n+C zt%?Zi${Dp)g(g^Sq+(e#xUZmJt52J)UxO9QacM57wCZ*+&p`B+NvphJlZlZ6JxZQ zw6lTf=Dce8YBaP@J}ar{e7A*mhd*t;Lg1%_XoQ`7U>ALY*qW2a^t*PArCQ~{Pc6|U zf(2qhl~`9ZT>3FJ~E~uy41SD*m)YZ?k}~= z8rC0u`Q37mab8vsue~a^>Yi!)G|HQdc4y0sVb(ru>qq8pj9pS6S-HSYqLgonPwQ0% znZ$2%?WPQBy8}+TyWV64?JJIRSKJaEJ!gF`t(~p*j`EgqVMODb&G4mK@aO_mpGJ2C zVUxG{YHZgeV`H&1PRU8|yK`4O#+%?S-#cu48&D$PixRG(6I0ly>6TX^(`Qi5qc1wB>nl#eviYkI!4_~ppT#>39wEQ;!6e& z&=e%&(g`wt{#)@>gfbZMtqunm_K z@3lT3Y;`+GXHt?po)@35AB-`*V=VEu;2d_*NZnWf{Ond>{^eb*I@`Uu%q02~Q@P|T zf*A&bSEg)^f}iKQgFkc&zxXmW5Upt5feK_W1r_KxYp$B>T!NGAKut6Y!1#9W$borilPy{bwk~T`}Y`ZZ>OGqc1u!sNk z4u+Fs)c>&2U3g>u3-*}MXh5KHO@#KXBO>6S4dGQuBzH*vzCq-Fe{cwtv0sB%1_gEk z5)|J{mBJG{jAd_wPftzpYbu4YoKv`-s?qkmSvYHa+#Im3u6+HRlG0Lj6_pUTxuhdF z_5AC7hb@plJ}g*Uw4JPob~Hu_vvP=kbr{e%FR!YiqHuf-X!On{Z5G&}pU>EL zaWj}Z6=zUwQ?^OsHFsSdRsBrAfa3I8J7|@fW>J4Z`c+}1+&=rlP{A*yty(i#?9pF8Rha2A|XHoZ*sJHBfXnHnb$%py8rex-DXsF}8R? zltD-h*TxlKt5n)?wE6k)B!7X%Y>%{4)SJ&LA0Q;Mxilqa!A>nyV3oIE4!6d!c9 z_4jeI`GKuAcI$Ri;mi_hbei;wjbPnCwBTi9^aZ?lUz?B5zVOgQ_Cg18P1x0-^* z@LlbHW?J=V)`Ts`W!zp9Od!}z7gzgSDZ8wcMdZ<=apZIbh726jI{dTW3eQNIj7|ta0>8G*o| zj@V^Ks;N41aA2GYj47@QTv|DjK_N-9=sR)!#1CUPdK@w=SX*q=40}yi5uO_DAgk)8 zmt79#Es_0v14u^d<;W1nIpgASk^z0Y!T6gc6#C-g^rIQbGsmA%K)fmo7C3 zgh(%;g%J2h{k`uy|21pPhgmaUX3Yn}y~!=-?0e4M&wloEZj`p>i+i`}Z{y+N-BVLl z(#69g;KpskiErUP7d)ffasO_3>ArY|S3SzOiQ6HtQ`Atz!>dcUbNPl4w@>1(YT|{5 z_u$c=zZ+`090z!K%A{&aiu(Q*yGwUkIBWnbhxFeH%s*`>(%I5JEnsCQrJ;-JRiLUT z|L|T^s->4;j#}fP#gBV!O3KFXl&OfsdD`)FdOwVF>^!^c%1Tg3%cw+4V*k*BHYn(X!dap1Y8#>sB(o)@_Nx)WJm+P-ZujrBRh%$x;_BC`ZPaHu77s7>%K6dpeQ zvz07Tp{}d?XQSBksT$kguN=EM{v8G;OriSo6G!=j|K|?ckP$99G{;?*{-xKM?AJqe z$Gy#VHy4={5wptwZa_Bfz9&&eu0$XsgHJC~VW5t!Z^w@jO_!H+o8vYw(-YT&JRZ3 zM4+sdZfh0eD*rUQ1LG2+41~+MG4ph^4e;;Ye=a1Ue=#) zGGgdRET}|}`T9tH$0#@G_g%g_+jD4M;OTSa@4agdZ-dgHx7zXS( zbY5K3!WN!?a+B51t=$@31?y!zfC(&p5wxkV*uT`tCUU->LfnbQr*X}(xc<$hMPqrj z%-*+Y1Z+1x`=K@20yM6l^omL2+S7wL?=wZeZpzE)U#dIg>H~}BM5kFUCR!jZ{C>Fh zZHYr_TYx*~7U%(Kdh3`~vwhjhpMK3%3^kmA3)g60L>u^zO*-o$hW^-CZ9;^xbu7N` zf<@jWx7K^MKl6f>oU6Or{a4)CgPNc#O>RX+iiiCvsV$gKTI!H^fdw_$| zz99jNoD%F@hWG;_f%)o|&0`yfeBc|b^QYaq*G*%vvylEwk1_fE z^r*E}TFDvzC5P~5x*eH+A4>Mh?W@s+;U~*JCw{sv_>Oo})QvK(P~@+-*GtU~u@1Yj z>@-?a;PVMT7R@zd*nQsF66=y%YVx%fGh@Dmwzn7TZFN5{fUH$s8V!@utuw zfBd9&`_IrNsa}ECZPu+eG+#e`JrFXh6GN}pKfV}RfZ5)c6A|q^9|*xTuC7v^IjA$a zX&!d9c4qetmS%$Qk{QD-q@Ii33+`=;~AOF=h$oj{a*#?`-4;(}0Gv_zF&h4as# zE#^$eS;=FmQ#LjK8Xf{DINzmlSzcf3#rJy^%>AQxMKn1z7BnH zq4GV#nGra?%T3a)@T|zhF2QKgH^gHle3vuao#Mfil>J9J#zGbR5st#OVc=&@l1BQs z42)wT(2Mp>|07iWuU}j-a18ufY8S{RLB{b&RWp=B#USp1T2IekccdT2dp;E&$a?QSQ+67;K20f5=Yp_|HZc*i1ghByv35?rcOkNs4%QL zPyx!Y$Xx+8{j*QpbbMz-&x%hP^6YhcPUpx@Kbe*HOE_wnd!kB?rIb<<#F?N4f+`bF z1^>9^VkkO>_qyrOx%NkH0gs{r%UwU`OSQvO%aA55f^7Lp)5Gv7sxUc@G8dg{Y;BKM zv%23^!2mIe1v?-;;XmVtZDxKM{EEC7CUNnZb?$z!;4yxl$AtO2nmmy7c|QK*my?XlJzV$Rs! zsUc^(P>}96y^w3yFOsh%wK~t{7Ij4;7VlbT{6cina+n7*@&J zFbs{^kS#S1IyIuV?)SL!d?#Q=z7*!ZkFm_Y+Cdtrn-EPemK(lSAy=-!EuHG*iV6#m7B;b&$$TB=hoph+Lu9vYJyiwV96}tw8GLC2F$J0 zTpH5ZCxnXkNGQk+5araaaCA6&!Pzh!6BUg8;U+7v^tqTtL*4Y3%+>G1(irNHtC7^+ zOow!IdDh6$?)66ZbTz~z#2`g%bD$(xsz3UGu~lT=pW(Rmos$EW{ep zCOKVALS-Lg@nQXj%OQysaf_;}yLgyq`w{!uoZurGP2)Cn75yAdGOL@p#cPfBNf-Ot z+(S!w)1b@xA%>bMQkxVxh8D!8`a{9)B}G+z?RGXt-{JT2*l%aJaFdneXj|)Yk94Rx zV1(m?%Dn8h_ygYS3`_9DQ-(%QW>Hej;7x(j7m%$F?No5!N>r+Z|8BkA!Z=FC&Fi`% za5u4vpO|*elGWpjpA+ytPZc_7>UE6^V?5E6H$&iD~ni5#O zX4B{H<7(91cT$RPLrcg~O|q?rMI7I2Z~T6G%q|{#c2AJcMdka|6fgU>hbDi0|t*`XPVrSY63Z>osc}Ch5;{)&~9#+V^q_F*XM- z1oz3cyXN&8L4D{+_OCBBp91iwR zR2*8A(5Lc^0dM-9bidwF3HU(TO6*t?<6FDDY%g;D#gxpv@$)2KbxHm~;p>T(jJ?L- zx&>deFU!5+GMDe@Go*dc;j6sc%vog*hNx-5;DAReHbuIlt*|Lh{KZ37RnFaiNVJoDQNHp`u{l_F-9`||QUtow zq`b=R_^Q8(q&3b;+|=cH1Tw2XZhd2zJ9?J}`d#URh!P)s>(l&+nj(sqIj14B^(Z#Mn%t+f?i)tA`fku%+dY(xX zdSRD$VW^@O`tI;Fjyqceu~QQjy&NNS|9OKPdy8q?#o3tvbI2A=pTV^d5EkaE>b=*2 z^3nsmTN=5j`eBcoZcyJI>+&&@Y;W`6*#?`174(fv{XlzB*#`$Q`JsD5<4B^0# zHtPG;fkR<^Yg*Sqt7K%x)pSx%+b%{~G(?^ZNDE6Le|G2vp8T%L++h5gWg{0rxiPlb z3KMn1ylgbMI%e|x<>GLa*F0Bm3|N(mE3Z0BTeAuLgJd1%_ss*0+B9;u*sgU&b;bjA zINyFBvf-ej`#qj(mN@>kD2Er4`Uom+Ebhlypmm!fTGuso5G@Z!skWs(Ze||IkyEC; zy9c@7%)Cq0%qfGYwaov$|KS~L=Pwbu&k@6ynrvaaI_-s%SEaZo*VCh5TbuZPI7AP? zM1wA@6q49J;!fX{lXtl7i5~tEmIRzTL5hp=`BW z_Mfk#f4|9;m#Tmte4~mL>1jHJ2j`^L5(g!DzA8Fz=%?WxQC}6ctmk5q>1??kFXd_i z?UPN)UrA%s=Ut(BzL>!b@oo4?Wr*gacH`*g{C}cR{*uLKqHZE1V4DPT^;&1A_WZ}& z<@`^@9tp0O8LKcjLr8+$(X!tIH)+JlCR+XXi`E>MUAZ*_o5r*wKY~FUhT#_=@kM1T zW8jO_D>WtX}%Ma>2$zEpyJ=jY8GkYQmU{-u@mUlt>&hI)+%QarGOBmb|%B#3-@zgBpb_&(50XB*a@8XxWmd1tk zERPkve)=vhSbFZUlyy&!9X$ZW=;%@RT9r^x`v@c~T``ZA0C%>ZKH^rXiyc!zSHH?C zkx3QkO|dF%0(x&P^Nu8AB5YSusC1;mN~o9gvDNd2XpOk+dm>AbJ`Ic|$;I}~H4(Zg zZ>btO5i5iZNo8dima_89C=SAfb6otcY4IK@IkqNWVEia>XfANAU@{6jY0o9I&SIt( zPAbmqJf7b4NR_c${?^|xVEa%77HMAd8^5S(j;*m;3%CmR6hy>sD7=Hr$(Aaa9 zo#9A3{&i~%3h`Lgl)6kG#bMXO6s{0C!Lbu~fW2;E{yZs*r*p~cG~s8_f_qtJ1VE0k_*Y)0=T+W4e-9TK<34|uNX1}GRr&-Ke!;Ke`o{s z%G-Q*uB5d%xL1d=Ow}h8 z$lO#?ehqaFEC(;HOQ9{k8w9^#z4qz@HS@Z*cOvJu=VlV*wTs?~4Wgf>Z|VqAszvt+ zFjU#H>>f-1HJ4@{dzNP6RiiMeX7kTD>7QROWMknIE#&=f%-CGSh(Jqn&Nb{(-c818 zRsP8Wrawy{>nk=#(^Aaii}(!7b&56mXXlX{U>dq{-Hu@RU7{#-Z7owR(4xqaLy1sX6`#g z##s+DSRG0WeFQxibmQ6XxRB@9$or(MBH4S|uA%#NVOA#bVTJnGRuK2BpxT>LzeROU zo~l_BcK|v)TG)FfN@4t> zvc_>P$lSoif&zaCc2y&k*FOGvjvDToLbcdk9aI;}agWJNJZE|5VXwNN+IUC@Kimf$ z=VIWyi66ZX`l71jag2w~lbZX=l7Vo+SGseNfJmAIX0!BnEa25SnbTpXCrNjUKk7m) z4d8?gpAFS+kHlI$;=X(vJfr@I=MUW>uZ^8f@N~^$Hs|EF)#{|6Zg|bSa1t@Y^FxtC ztc8-vZ+9TaN#vETc6)g5GZ_K)f;U;dB;mN`$AnaTLpMd9d$--Rc<#v$wd#}g_+y?`TO=10Ll)k@kHMZP=j4Y<|k%%0w>=_pX zNKW@z1H$RRX7`t z;FJmxJ5Mh7V^@Kz(0PN@^y}+@SW}9yc~cQo7yNoVf)Xz3CKaUk(lixW!=6H=OLNz% z_?Mkz#@3t6n^_Ijt))K?4)pr|B;DaBGy;qKgh#Cji|%f>?TO9HUu=qsrnjVMw0_j#(#Sn3(P2wYOWL`E%eE0pZ#gc4*#raD<)llB`&etWqS@Yo zsIap&a(_qkX}xd-4I+qqP{hcvb&%db8S@3cJ7U&Il7AahT$VrtMW6LilEo7ZO*-_* z4R_XcTwNwS46(L@c@O%%9`tU#Ov?2iSl!iwlcS%g(t*y@6gAlQ>b-EesLUq6lt)H> zrY4B8&ec&O2`?6|3p7&$_U^`_9Y8LF`x$)X^)l%U}2q2 zFAgU5k}Xb&WCWl-0vKCg;*7#@;pwI)+bl)10?Zeu<4GG%kdFEUh{w3NFASM%7IO`z z`P0N2D~?Up(88(w(2s)#yWjfV{aea{$0!SBE1oe%2Vv0h69->kx%#So!iPj z!d!lf&~9muq9NM(-0ft!n2Pe(4l5`%q~A!1USA3V<&!EOa+uczF~>%E1SM!!r5;K) z!L%P>zSZC5Gvm)#aBWoHDofbh(Q0)@U#%vSp8V;D;Ia#5eQZ|2Z&JlL z4Ox-Ld~ji>>1brB^j0D(9hGo$@k)ZqrNh9d^EExuJb4;4OH5h#pvYB$z6NqkRbAkk zB{w_MhNdQxv3HC}@;B5p91#U0d^3kp=5B5aXCld+m2P2YKabzxi zO-U)lb##{@@T;r#m;Hl|4VRgLq^(j?L@w(!^%$JH@d@Jg04Nw>?a`k!whWFPLly$Y zvNEqexXDR4NErkF&~m&2f0(CD9|PS4)=z;o?A86+RU)1EH#*yi_ zx1&?YmVz6UZk;D|0VLld=0~cv%dh^-e$mz-&>Qrg@LOwOAbNz6L)b7SoH-J$mqa%H zi|AK@uEqBu&KDVM~~fc zfT48Z6Jqb@d5X7L(It4Rwm?d1dII0z7j3|2h^rL;!3tD}i%p{QW8U#? z|B`MY$d>+fAIm zhiV4pB%cJ?4v~Bu3URwW&N6FUC1m1ak?M2fQ4@7_ip;nkjL%sTyFaowy?hS}D>J!o z6T_y}@)WyAWC|}#T&UKWjL4tR(7u~LKytgL_GM3T{Pkx8%SLtG)U<||=5@cK2e%er zHH=0!dG=?6yQW}~JK;xGae$+(p8)rMZC6)aQgd*2PHj9y?Ip8B`PJ41BA|B}mA!11 z+q?Af6UcdfCnEGhE5Rfg9IErN?2Gq-aqaj{13GCf#HLV%(x9Gf$?Gy6Z>hkcAD4&9 zxFm#m4z@6k@Pfhbkv4fnTBF=etc7z z@_mp=Vhby4X#{_^-MT1MAVS^}yR`b{m9Hx1*)CrIiGY)D&8h1Ti__eGKOH%xo9UaF zz4AaEdzoBL6II% zjUFimG1wJ@fS%9TSclE(X-HqQ8W*&}{*X}pnIj$skIBM`qj7|t)1h?6vgmz%B_HRR z7v$ftOIe`J?>R+3*hoV1Er5sfB4oQEDCP-kCVd+lsT<7QR_1Jm9nZHydnGA>soiBkF;$epqxBQuB(( z(clq8FI95B#|u+hMhf-V31sgS7aftBxjr9I8<95s#h6<0wIM`5q?A60-w`P2j*zUG zqaGrCMlSkt%XrkX-MKk6as?HwdW#_YIl%^-$?}~#*@KR*eL+#t#{ve8kKX2My~DgL zP3KsbR+jwLET4|Vgdy13dc2_x5AQ!i50nyJG5nz_bkPD@6*-vw%Y`I*;Ke~nf0C9h zo^ar~TVlqUVOy5b8hEg~mNeb%Wa9tC{N|E6vXZZew}0z7mMI_#qYP8O%o;l+`XK)b z&XRLFxC5zuUBNfyk!xRUKU!*6_fn%QhHF9&B6X)oYZYw$tBmUbA|F^hW`j@0JKsLk}_$1&M*9G*i91X_G;igN%&1_DEukJAq4_~7ZA ze^~5kPBq*G)4&P^DFlRr3r;lp`q+WzS4c3=%J=3TsWJ`S2O&3eT&#Hl(u!#x8CX_k zZtm>s55AtZD+Q|yk`k~Sn#5I90|4bO%Rc93-a*@efk4XKO2)FMUfCnWr| zetTVU+F=d_-^{sWB%kug2n~|&I-JmF-+z~~8@yU_Ph&POL|#Oi2#{Q#!a)c(ID@zW zz-b0)kuD`HYSB7E42U4(D}`~!7DnG`=fabA!0D8+q{u#=M&M_`R`N2GJ z4Ze*8A0e`Z9|sLVPHndeISDQ8^#w71$beILQ0qjFq(L9aQI_T>U>@h=!G*OuU#HWw zpaq>C8?SWX)Xtz;eTR{XGL-V@lQH60;&;U6zguG3d292GiFVhDz|KH}3<2N0Zwi*w zlUPc7&K55gbM)qFZp<~T(sGGJkJ~S(Y0wCflU9Ciz9C9@zJvWW^q^#Gm0R+8noLgo;_Il$cMR`l&?MjF9e6>-cUtyfs7>}B^uCMkyeaG~3ctyA*S)+1>L zhn6KbJ0Epwnb#J%mHUqzpT9=>co#Eu%A@yrJ3-^A*?`T!xY5r=Ze>9hxa_Jk8oGFH zVRgMp^l>zJ?JO0I+9##pKp#%U*#I4F8-mPI-u_WK;7=|_C`6Ms67wgXnIsWW+W-p4 z2N$+E%DzVkr(%Y`<7W^b8_U5p0Ze}?cpl60m9M%rE@{^d4oe3G=0*(&1sbxjd5*1X zpFr_%a~i4lOFeHY?s^z-yH&us|Ml~XY-*(*a-x~q4G3g59Y%kty0s_n%c+m0d6K|; zy=*8t#zDf2%@cKkW(~~_gpfFrqAwkKjq#>+LgR-19Mr_01O0`(u3Q^Jz;oxmeo^lC) z)*)PmFsJv{k_!OYxZNh+tI&RxWSYo<|F)p%ot0FclHb<(HNdXzi=gP;^3Q5qCkWeY zHlGfNLOs>RZ(BOlG@G=oH!C;`(knuXekMl zzN!a9e{Q(Ri!T|xDjGPdvJg^Zivu_k*LUi-=Ej|_&RlJhiasv9m1aBhG}Wuza#Rkp zvzn@>=>XYc8M1H^nZ+9kg$GZqP7x^!d;f%>#Juzx;uTWvWV?iJdhe)H+SZN+1}bu7yXeLQwN9#zeav^i!r&t`tCah{rS>KBd*L#uP656;jg%g>&EjDtZ%;kp5mvS zW50B*(gcx`I^1398ZYA)?O=mGY2&%*rjrEf>;13zlMoIGe#oJPfNAVgTyfDsMQU_v zxPA>Zs%$4;){{|z(5(7LbGPEWZJaJZdaJBRH~HpJ`V(H)&W`40&(gDNz=E3*j-|fp z7t=e_eDtFGaVok@d7R@iCm9!fuKG!Sy#U!8S! zw*30YFhRb00+Tzf>!(#qwoUgtqkXn~!^+*{UvV0zM4By2YX%-)Sc>Z~e=&r#!&VN& zecc-|aiVI1@9)05mGRdgL zrl_zQn}cy?vGx*ce9_18LFAGTNl(Se{V@@DiV%CHrg77wlkD!8 zf8V>LP|=&?PJnrq{_j8FPRI<4 z=)$3F)^8e^m+K$xkIzg>(SK_yL`C6C~8y+8`qaNYdMa)oWP>rzC+%c1(zg8 z+^zpztmv?!vkR&?MJI~$7N{wR-1}atL;28>b7M%kfpTNy@S?&Bz)r|1k)@nz_aZvvMJK*!Vl}CluI!Lsn8i+^*1oX(i!A zzfQ#ZYNH#_%{ty=7}ctkmr*jA%64$ z)nyT-hIY1SE32A&?<)(Lx;W)KNb!QM~;sN~KX`|N}O#_0dbyqd~0SUpw+iwBPh*;m}C z{e}a$B$3w4{ghUnyHm4YW(&w-`|kL;LFjX?7i07&9#W7K%o9`+)aKzn`geLZ=fsYz zn0A}G<=%|A_?5iquN$RIkml(aRjyyrLxQrHyAPF4lLofU^*VUFl$ zS8{^20y}!ST&HO+wfnohXy{61vsiy@XDMF@LR7qXmc##O?8Z;#fegl|G;&Z3Z|74e zsT$ViuiwFs3r)ex;N8QetnF#U7iK=U)!fGtYceVhA`xb-HoLF6TSo9#al#YDw<|Ra zieh0x+m-Wf$%F*!k{dAuquvRn@V6{KOM_UfI~N>$q2*~FlSZBSa_k&}s;o}Ud; zNF7TTFB|9NUrapyE2b?DQ@M8&eC(wx1OAOP`c}$rX(y*-wQy&*NwJC~+&kRa@n)sO zuiqj-9@|y_k_yM`!p%q=`Tno9PaMhDN66uD!R43F+v9=ozckBm3)f@R(RXRXIv2d{F^@t5Q7t{I_@AVrh3r z&Yqi04qx&e-Ub&XuJq57F4}?NSM)!To?aix)v_U!s__Epo8D#}O`iwQ+}12VX->K0 z!{VRLAt9hB+tnZ>$vp~YK9*qrUcfLVopS=GXzQg{x0LClPaG%d|3;IDlnDnp*Li%H zRWsAxXq_vzB+5qBmwf$JxNSE552f%;k;WCDWi-NxUPCa`!oWH_o@Fytut^6>4<8UC zzag~X^ueZei)8^H7Nyxd&Fh?S_JKn|QgZSx=9^s7`5P8Bo`Y;3pNCR}acg!9BGgf) z6qTU0Qh@ewkKLnvXQ~*QVYo9>-d;rUW)^BVv)>CR9E~fG^x7zXas42ksF|Q{NrY+q zfOTByW`vxEspvJWQo7f@+fIL#)7JJ^c$8GhB7uK3(hlqHeKKGaOu>?HS@~JAZN`W! zE*z@lPIrC5RaIsSYB~S!X{#ZGm@j}>3k|GDr) zWcy)1!{l1h3+625M{3zm{yV(>Tzrmu;{R`k-l?QNPCv8x+U+YNKV}CmwvnF?zrf;j z405Q;e%@aUejx&R*2|xK+p?O?kkyc{#uw2k^flSm%p1E(fDjXYIX!g-gS>nvhsIkuDMf!$;4-_ZJp=s^4Ip(>idbs#tYW?kO0U~)D6%9(2JF@JEVOMmDz@DrZ@IQ!I-CM^_B=8!ytTmKDobYYFa-Vdwd(; zl-w>VxdlA?dZr#=iE>FD6Ga_b^af_{`9c-ax|%Gl_NY8Q1n*tTZ%;0yQfkjjK#kr@z) zxE?yUfZ*Hjd!9J$zf5p)WeFjev^Kj>#SHvD@wNJnK&wp0XvB+JnaLbc$yQvb+7vu> z7$_u633r5G@mX>*3XcZbA!0=;m7 zW&&kx0hQThm++O7-d(=#LT}Zj-l={<5S^hJaD4Z6tB!q zaXuChLrH^{^O_e(N+50x%QMUOhKbP$Iw}*E98*jS0&E~JGsYrBemAw8%$PA~J;K5D z<<>uOC7-&_q_k5|R^@;?K@gh8+v)!Nwl@mE?$H&H&H@pUO|VK5yCldE4?fx6^x8-?H-Yzb!4dYLbx_}LXS!sh6` z4*zn4@{?@euYuS2B%$DS0;ynl)@Trf1!CmE$2ZnGa>hpSG>Pi@RaT@|9_S1~#FRLb zV;!&~j`CpSI3JWSf>?5h6gu3+^ok7)a5^Nq)CHVutwwR>+e7|f_X~D1sQtC!u`TS(?@GP7)y(?a!iE-VNuuVouI0E<<1a5j=9sDDzOtL$a zxXX@$gsN$5IyfnHDfP1tKKfcIu&s3RZ zSo~QdgMGFd${NGlouvAkAedPHH8eYXqjxHI3-?~PkX!e zS4vTew+uEOA9Ck!Nrqcyi?}!Dqmsp0@GvvgQu1Mr1Ph4l`y(?9jd!GiSxl!Rt(bQ3 z8_6X4&0BA&@MlM-j;U3roOR~mY%(e=N~zlR5Gy1TVDaYkd&8{&ww z45*r6^@a0Vn#lRT5Y+$Um*v$@l09-o_Xk)p*6>sN9F{P#FeeeG$X>#s{vd)Kk(7cN z#mWfQ1a#Xy1rs;sV_*=UHb+Zr$qkzw{K;~cE>D6Dj>oF3N|r<%#`ccnih&KLTsUBf zRh7~|+1IuZkRZwvYrR2o!zu7^Jpb*VLw15g|-G6NM)@KA|8<{PJR^TgwBgf|=rMkG(u4lB8u#=QCsm|g%n?h^c3B4~#A5%ead zuE@S)LQ9d9(gC zo@Ih57Gx5w7lm%z7wKdT-B;q;7bm&tN+jioq?p=ZHJR8%r>ZD|)#~02B>yu4SM^6P zxDCk7KJodZI?QlFSxfUy&FNw_cimqy2ZWDa@7YaCRxYWJvyN$yxe}I9*%*cO5 zT^x?6RKsywxbJs=)Ujb-ref|z9{vsEnRep>H~iic57Rua0N%^&m+@#HvMsEM;n~rG zc4+o_+6Y1yyV)_{{Z9#VK|eX4PXiSBX18Qg6WB(B`J@?wC2F+}^L^V{(DljsI2roqPqXh@RajRHn7J)|eA$d}gg zq&fNn!-Ta7!S2YOh~m@XtKO#HwG9SBtbPI3Awywj8kX1qsnJfT?U7tn>+b0BcNY%H z4Y=&CY@cQD#dFF9+g4Sp_0^veGhkMbjj`BFkCch{LV@s0i%!%|487MG872wTu9X*J z3u{h%BEYM*`!|)-h2d6mTs9sS$dIdo4ohZBk$_sJZfRTtdwbptk*coMUKZd-=eU~W zgzqh;%`R#)di<&tH27 z^5Ss#X{ofz))_&9tlW~Ig$dU4!OZ);)9>NvGls>s2A&%a)glJ}ne9Q;2l8&rQA9?G zl{DE7Y9)9)9KBih68#{JgVw@pQRgq5@OaBcGjQJ#NYJFHTQm(^9~_{aQCodDleJH& zmW@j;v-9`sFs_?*vG1PoCyOz%!%V9`gdYj9!EX(Ty;?5-b3T`gKNHAyQre~ZXg~1{ zGG+M2l5XrWPi(HtRP5=KCIf@Xho>>0^MaOXjYFzs$Y6IjQ%B)=A(*O4XaUK6ND2X~_82}!#@|k=@z&7>iQ9D- zOss^BJ5IZgKS+{fJ2;S;>h3V*_&r6Cporj?&hz(J+W>;@ zTrLW7n%t8a+}ahF`=?wKEC{?*+@l>8-F}xPgZ_r;K1Hzx@Yt&)&uaeaxS?U}50?O` zZy#TNo~!q;unzo=?;nosNsw>+gCfh-?(Dy=C?-bL=NYpMB{4>!`q@$L=7MBM(WZem zl&xrG47$DhRPL-CHF1PXw1ZbWMso=Jy!&5x6eMI_q&97yRv(jDV154696H5;FuB+Gn1Bf`IHRF#fX+FKs3`}_B ziOOzL`DzC-!g^nH*;4KfTTLS_aGmjw(jn8lx{%=9-W#Ah8zZwuSFtM39$!}`DHPng zJ=Cz50KMLg<6Z;l>ATd>&Cu*Cb76Xsxo0wR;_67zH54*z?3GA)^2fZte#hs7(sP0| z0)H-M@%%{Em51c)EkjPm?}@*XtkB9qw;EEw7caWLcR}uYD0i9=Wg9$rk_!sgmGZxP z2$}3k!P+trq}{K4k@#x$L-4y06#WA$i_@IZXKNCGJaK`@;FUoDBbVaiZa_Y*Rn{yN z-9fp{ruGejSigbHnrH7}l{50Npe;1SN4D|FSx$ZYp7G24BSb}uHOw7(Vx-RDcf>&{ z0oSW){4p*U7Yuy3Nqt1B#;tcq7c&;q_*jJJADZXYv3?kikm+K#;>zSB+Baw8${elX zFQq544l^TolN1?QAakplr+Lfo^I+Ra4*gjEw98W#QBGC;^+svpXC^c^_;0u~J16@O z)Feij-UhfNmOasx)10BxFw4xaIpVz}D6h=3RqeV-%Dn1fVRNuSW#+<<>p$o>Pz z%jwHlrjycm<+!OHN5XqZRJ8N1GJ~oQvG+i>4e4deKs^qAJz_6nV-ywux!W7KQzGH z$NITjtY(^s!P@3jBIoJQt)t4{I5*a0GR|r!E3Lt8Ch6H?jN)oHPt(FSm?0noBww-w z;AX^`6x=rG^r-lGF3f%=CB(4sxkeKWC@ctje1GC47ltahN(m5|Eetr~ab&6ssbl#s zKBijPvyc(;LXY@ng^WMf_rkg7-ZuvnLMXkXzXweXMk+vGP6-M`-JW(!`jN%n-EH}K4d%A`Aa%y6HkQ%nc?NY0v(o%PARsgL%Ke{|%ORB4kVO|sxM3w9yF8PGY zocRZWac7Ymbe|ztkd$$ryd6rCM2O76Rjs<@{T}3J@JyV@@c%5Hrqi!-dvHm5J3j2a zPJYV|_X1zSff&_wwW4qT*7f2Q8j@i3G7D%mMNU3Hh$XolNB@^Ga9ICw97-xpB-)iw zu_HofKcl1)!M$v@KB8Hy^X9+l`M;#a{}pvV(k2c90Ne65oL61xP^Z^%Qy#x+*UY^} zMQPKatHrB}X&GV`jWA>;+u*b}+-XMHu3Xx4#?FTctt0hp# z*Yhc~otVYFcpWv4G|D@E79q+oze2XGI{#mLn+?N(GG+UX|3N%z^c36T%a(j5UkeUj z(#!m1IHstpk5qg-Z-EPuv@fRJ`(ZK&@D?QA;civ$wAai4`$A1yp#?LI!8!^XS1~#4 zb$(b{g6s^O51a_f;~SF^WWk>td>ep<=)ZwV@P9PVm7g(67wGAN)XAQ9Ld*e-7$)Sy zQ*rrDwsh;qIa}yW-#j$%$Rg}49;+-TfIlRj;@0kXB|&tUIcpoa7L8hbIgLr--S?8q za}ZyuZ)#ZuJ8|{H03?vnjIlAop*oqhIlF!YZfy@Nxuz3RIpsI@2Wv4&?P|##58vpl zD?D^u^lmtmt4_5_k-m9gEzM-7;5rmeV^td(XHG=NV4Iv7GpO+zOfr{2NHkwCCL17!VtVc zV($o@ux2+029$UL+g{rNI<4vYi!K4Nn}Q*9lRw9_EkYX3Vm2YM z$`0O+JtgQRbNhZeGYTt#V+8uL7htn6YUJ-bcz;Uwgj1WccH3T~K86yAr07N_-PBCke8MG9U~@pnC@xD@ zsEQ+A&Y3oULx1Gr1zp%Y4gOL>Fj**ff-%$yzhaAy^oZv-HqxcM%iGI}@e2othPu{dAJ=d8_Kjf)uZx zd&aA%S%+`Ww}}38+uiG;c{yVDwsLShH5a3-105Ke5i#pqI2JDRG{$jzDO!%8BnEi5 zkVjUL8P+GK6Uchn%=Blp#5i77CY-3qlhjD=m3c!SCh~O>8AKKQ!5ndRd7oKs&U81K z$m5UDs3wy8YbguN(hb~57T0-xBbRd2;5Z>EM(*L!*xeza5Z)zd4a99Yr)XFSPM4R? zcCk?Qt!=I0Mmmg{8tb0gDE;8pa*=9e*oNSQI5BVBc45N535&+2a`}UJ$!%ni=-^-lQ&io0{ z4Oyhjg^WLrMsqo34m!rVf$VQ}b#1$Pq~&vxKwx)ekXTUsX0>p*efp#Bu8YDbB7Ed~ zFP*gG6)b;3l_RQ=2<{C@!nGP>OW literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/pareto.png b/releases/2.0.0/_images/pareto.png new file mode 100644 index 0000000000000000000000000000000000000000..5c14e8c91e70bee03ec6244d22ccf3eb923a8101 GIT binary patch literal 21364 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/pareto_curve.png b/releases/2.0.0/_images/pareto_curve.png new file mode 100644 index 0000000000000000000000000000000000000000..60a08471496fe8dd3a0699bbb9416790720ebd29 GIT binary patch literal 73478 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

    v+x2S>C=cBz_tDs@d*p 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/quant_2.png b/releases/2.0.0/_images/quant_2.png new file mode 100644 index 0000000000000000000000000000000000000000..5c81db4fde911ea9a3a0b76826f88e5c66a06a72 GIT binary patch literal 301491 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

    2tE)_%dUx)^CyRM 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

    am)%8>zPUN(AxKphHbAZL$&)&9GVQ;MA*6WoeP= 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 z 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/quant_analyzer_per_layer_quant_enabled.PNG b/releases/2.0.0/_images/quant_analyzer_per_layer_quant_enabled.PNG new file mode 100644 index 0000000000000000000000000000000000000000..d8e2ad0669e1b9196ec881ca0ed5ac918efde05e GIT binary patch literal 45404 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≫b; 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/quant_analyzer_weights_pdf.PNG b/releases/2.0.0/_images/quant_analyzer_weights_pdf.PNG new file mode 100644 index 0000000000000000000000000000000000000000..cb932964823b13ae1ef2b1b26722e30f6d6deea1 GIT binary patch literal 16257 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 NF~>h}M=t*Pe*q@H0JZ=C literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/quant_use_case_2.PNG b/releases/2.0.0/_images/quant_use_case_2.PNG new file mode 100644 index 0000000000000000000000000000000000000000..075ec7ee9e62d7aac74cda3c991c14cb15930e97 GIT binary patch literal 35277 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�i7M@hax=$!{$XJCwsYo)e>D!WT0g8x5-j@_<~%+<2+RcrV`2XvK(s z%fVsyJ~2mI1zfVRPnF9!G0#*D&HJcWc%YlHs84dMxsQ@co+A!60h^p*ABTh!<5!=p ztMYdTr_-YD3NPh{s#x45WKWjAiE0L}bZGrf^4WgT$`ot53Dk_tR;7aP)738PVz_~# z5NgHi#0{U%!iHiBiaraum(bU?b35}tvNcxeL>C~8#&CVQ6O^S<69VaR#?u^Q+$JP@ z$ep-(xIz&Y8xa5Rsr7#Lf_Qn!lprC}`X;oG>)=XZbU8*NhE5p3fu^iKAkC8M4jK#1 z;T}Ds_rnki)qw-sS;g?k78`b)*k3iT^HRbB77@q(bT64($KSU4bC*7UrYQC)R?$y( zaJN3&(@MFPs62>D*inT zR_mpp%@{;rWAz_3vC^{W1kbp<@Z_0)2BG03->Ov#7LB{XWYY@nXObbGk`0BP=8j#M zx0rGb!{0GIuDmJ6-MfatA)w=ceonU63&-!Enaf+r#;pBr?l-R#>Kpm9FR%8HMJ}3< z*nobw8P`8`#868jFvi8L4L!pYt8(^Y?Eb2qm1vCzbQyl$aFmG0d(~XDtJ`)1b$!*c z*Pce6JPiwl4AagZB^w3FiylysJaI#FKtFs=u_(27PQasu8F{NfvqSeY@~$#hfDHOr zpwp+xwWA^+W-0C4orw2O8S~C;?_3*2{aL!L8G+L6zx-SuPVf5u0~$&z!1s}`a0dly zm29{ZT;MEpAsUEgJ4G1_*V@UIG}M|wdj=v>a+3_M1#~c-Bl0Q`4JI@2Fk?poAz%t7 zbGen?d%JiV>Bo;)xlWx&EC4%4PV;IYU+a%P;$J}38j1+H@b+6|+=Ri5Wh2DHJmJBz z8ag53rz#Ztx5K$JJu-g{)1b=^wYEK8N;1W0yNhW`YIBSJK`hbM7=Wycnk|uxheUtj zKna9Fi;)zjKmi^<7VBw5eEf4DVsXZj{@Jo@c@{G6TnbyCRfLz-QF&Gx(MbT9D1WrL~>l$?akw@u&G5Pts9PdwA zWzXCmwz60D!2L-<&jnQLEibR5ELf7Dq*Z#6pxYKwMLXhWYfh|b=p2o$^3DmJUAx#n zVmBPiwHIME2ecpew8V!=;}A5Za&e%W;~Rf_>voanyyN}4SDAJlJaG_QqQ&5RsP394 z&BgYU5MA;9h@%X#kcr3Ulp&KKZ{7zQN(({J;vg%HjHfYrlN-BuN)7IMKXUL7s)Qs}-iL{H?fo)_BFxpM zKM=DK%i7ZB$ge_WCMa!$J*L1AHb zhh26*e-0(w|H&+sj}ENhNER@IFax=R=C++9N406($Ne-gB~8K}WipJy7PWsymTpd2 z2eg0WYx2=?NKJnMx}9Ha5M#=I0!({I9nBo6tHGyuGu*$GpJJ3^R*VC>X)~1LILUWO zor(_pVs(M8n9&HU?NZcqffSL>GV@2?(gS>HniZ$+hpN07DpUC4eojng3X&8SQ~cpX zibx=Rl423A2P(M=7C@z>eDq?82@{rp!5SLrmEet=^uLx6aYn^g=^&B{sjTKdnR$8t zJ>nmwNmWUNQ>NQkeDTOPr|WR-?Wc<(6ga>$5=!P(I%iP~XvxB8QjJb}hq#D{i2vOI zx8n@~kxhc6@C^k}d4-Uv{^9iu*FRUf@b3#+?qB>TE9pP}-7k3jzX;OOH&(M>n-W#5SM=I6MOeZ;xy#{lg5}EpKn->y z9ZtFsjjzKGRQT9*WmjF>?Ll#9M!U*| zf0TX8n9NE5!zOudv+5SnXL-Nboxl|`i;aY2__muuissO{rU6c9o2yV>ZMKw+ytZ}s$!TU!0#pN$VW*{aa z{_7E;k`Xh=gwU-kdfCA7nb>6eg|KvL8-!ezJvyNzFHmC&B$Ipn_gWYr2<1_9Ntg&1 z$4r^^zV#eT7H=56+^jIBw>>Q)LmS>qqala74)T2KHap_3-Pv$_u$WYaO?$wwS@)vW z@duU&A5mwx|N6DaNm>6Z%vZ^Z*+hCEh1-k1$XWBK z(hth_eY`J!hGViJ0g3AOMNeFSsruk7`LsQAJMACg$&|X}c0D%Qhm+0pCic{u2kf!y zCUG_C?=PVKRSwtQr#!Ccoc^wuE0?%e zSQ?&8J$)o@-aetopa>aSOOr@>SBFRw2vT#q>*NZ`zGKAw`ZG0)COk@$-Vr$U5X*jj zv8)f!&ID6AW;>*2OWZc*Ar2`C^t_spwjS02)k6r$9HvANs!)Baw0wGzx__~YUd}=J zUYLz3n!WkJweB+OajW5><-7@%zD12ZQmY3Czr{W{_HCE}cO`nolC^mtiKHao3p@0} z5=XouJFxO_IX#ef6BFeF)+K)uAPfx7(jJUYX&-Qet}c3Y?OIRCBmV4}KPnEN&g9w! zLKkUEXi_GM@Y-^~y3p+esfpB<#A0C07zxIb`ZL_6;qnhAA*611#lomvg zpK`g+A=CHdN@vaauWI%RJ%SLrb9?0U{2lu;_4^)7I;{f;Y_Q@J5-+t2dkH11c;u+ENaD^4% zTy!&(Ck)L1hc{5?lkm7Q< zVe!f7M3s9)ZQb>J4S?Qa+=At;7ar}M;zY@l&pn)zSTGs;_fwmDLVlzOl1i{>m4hN+i>isy7_egs`B z$+z_o?wTvYW+r0$Qevbcn1^pWcN+_Rr9EE@)Crc|JoFK>Un@rP*5!u&F{8m|b$kPH z`gp;dSiTW_Ifx0+K-o1@c8|1-`u3B9o2S|Q=cg&uc)YbhO$Xq~0xJ}%_LQHz>0$?dM{bd4=$5s3{at#ZYHy`KIm48} z`ECTt@+KuJBCJ1AN36|xA}E$3}IuMg5Q0(b*)o#~K40C4z1|Po$&j{`GA>T~R)=>Y6U0ysB+MG&)mghpnm`M znc0#dwW`gksreaTwv_a-u>SAJ(JdeQWHaYFz7O#Z)rBBfaQ`U$)ExKMH>2-ukDtO9 z&b#(b?ve1Vh2!U~j>v`Hloo7>qx zMM;GE6u~E}MBt1hFKEh1h(4T`K6Vjz4F9f>SFv&Zq2@M7sPJx>sxNMmTxaq}pIl^^ z{fOhd?#d-x6VMTElj|^3zBQ!a5FRBB(G8 z>y0X+mWNx~jl|p~{7u0Tup5p45_y6uR(HRu+IrqHh&z+*;Gc?lqXM4qaSRg==ANVXGD0(gz3V~oM>wvnh^n4qt9+M* zt)4XxgtCSvO7mjRJxH(PGzg{U8d8yHBsT+Bl>X~&wjGs{;#zdx!`07{|%bK`C|GR+1eAyI((1{~5Nr3HVr z-hD+ycqP{JL(YknV192Lg@Oyd6FLc&n*8x-cu45)vB#>u&iOg7eZ_Y$vF%FiZpV!2 zjoEM1Vb?q@8Ah}nwo=U7&lWJldtsYj zMHI_qBR=h-N%usJI~3w5E=ZIn`vS+wS`oFZBFSG~f8Mk#EIi*2cxNaNuFSw~{IK+! za}3H;3NH~q$nlL%gC6c(Cc^w|_hj+S0b>Nba8eI=UILr+@T4zvp;PipTNAnnOe+Sm zUQ)WvWm!ezRI9D z4O1KH1@Sh9wguBckC3E`@5WHbYNd<|MRG5-GUU5Rm8CMl!dWI5172c4<1ZSYC-J{! z2bEHdjp^%jat=FZ2mXP5mP(s-@tbpHg!ZHKn0Xy*j_AwlLwl1s(lUmG?uez=Dyyfj zFLT2n?>6kAI2YC&b341o<%_>desa`28TOTVKQzgI-KS-b`a&>uTmsV?Oe3Y1`+PaJ zh!P96ChF;b5#Ih5d}L>^0p7@F5j?eqqqnJ+pfL4(jgTIGznPr~RZ#$40R3dJijYxd zcFeC#t0fLuzj~@z_Tz-D=OU%!BPID*(%G31NlgDk`FH2Ccpze;24&M{7<*sHkp;&! zU`#I`ZC+sbT}C(4fv--x_lTiIlF11oJvIg3?K#`2S|Z_Jzo&7h48xzp^9!rPI%QRf zpo-D_#~eWHN|0l!3BYg%yYc&OOn}Fv7{o^tMS;7juH0d%Tm9zwYXsgZ772`rsHRIn z!H@HqWl^XPYMZ%AsU6eV%C+!6ILfr}xDQ(DKU>I?wl|1?dX+uF9RV*wc~`{b zU@zY0T4HZx;D4?OpTT@dT8QT=pZY7dlX#_vu9BcD)n_s=!fB zy!e$y{#|snT@-?^M@(?49SWnxi8@<;gKCXt5Z?10g-9oo7v zLwM7y#}mUZj%D$IV25d#dd%oe?MT!g8}DJiUks_`sP5zm#4|?YsyDuuu|0x~Berzs zzDD>dK>+GM1tw%L&T2#gfQ4#e;Hv=z?t$HyZ#rBfTlThcnPOy7M4KJ;d=@gU5zvw0 zJtNb~NI`i1IJswZY%xv7EW5Ry?R|MLI#aGWNVg|@{xez*O|G-qGHEn+);efQ8&9Al zckP-s4kBsC8i5zu!wPkhB(Co6|1?5qfQDqQE5knxNlEg*m+q%AbNttT3#M{&aPG>M z1AjJVBRj(yrZ#kLo_Wi2V%pi;xG=xy(`E9u2653vgt$6kVc?5yc5TcscrJl=(qa#o z!u9v!(FN$_@w=d3dt>@rBcL_5Ws_mUFGZ0_y11@98lFt59zHF23G>Oi>MGFltojcT zt8J#Mx;_x2OyyreTHPvjfA>JDX<-&fB54TJ$(C>(HOHJRWol2gM`AcO!+kBsX&!5) zco7Ju&vmnAL4^YY-O3IlPc98ODM21aTeAa%|)7(2Qq9^3#l3)A#=M%P_O=12}(ABk9ez zv|sKF32xr?arEmbx?m_$(%{0)D2rhatm2PBW{-5y(ZpZERbVmlX5$;O0U>ie#n(n2Bn zx{3|H?v5)H+B$|qJh8O4h==LVwDKNUZ=y8or1Vv*I5&nMJ%W}-Gh4O|9kX(a!6|4_ zXAKAIeEUg<1Ug|bdNDYur^QIY$jcswjk=tZk({S(%lHU`$UiTyt+HoEAhv+Fxk1@b zC#`x=sRWAiy&1<%%QExF(Z@>u9MG$P;d z+WR^?WTg-+L~o`j4sVwg{MDibxd(g|tf#D}Xgb&6s&S|$^Nt`-#fyUxL#%*_SR|mN z-0Rg)V$*EM&JQw^t>(ncw(}sMoap^Mk(PGM(3LexLIijVf3NgWHE^;uaz+;0t?BAd zL67Un5yWO-tne3+@@V%&-Z`i$Ef3sBt+UQ}4!q3uDj2>}KJDeD{TIP-@eD*wnev<_ z)n;#ikqVvV z1%EG_DdrjqO}?k+_nxScjIo3aqxKfI#Rog^qC%|jvZ_tZp12vV2i>{fWcgFpNAIXn z0F&hh6uNgD4pel}`@4caOa*?RSy6wWl()EA4qp3XJ)P*dW>^Qtt#Fl*CuG;ul&|B4 zQrLi8W5SQKRgmxBxgVd={(q7U!QIl3tBi;RmeQRJgwLTuqrzZccHYOGeie%J?DyFj z&x4&-mWC%51n@*1G0^HD_}eZWlW)_+6JKl(y1hSKx2(JB{tq<6-iT7^D?If^;Frgd z>g6)sBhTnl`a&)&b)AoQu)FD8aKU zZyaB&h=vxV&3~17rXX4VKllQYHTo#r^}4j&YC^~(Y&HS?sxHa@8rDw<7BD$WRGxve`ZXcmg&Oi};CX4U{K?<3n3{dRtX^g&VBh?|TY_&n&pf?{u`g z)WKmk2IX9os)JG2&*(cHr5p-XzY2}N7@Ai2>P(%hx0+zhYb2^HI@%HJ*Wbxjf+`A@ zGea(2y|+AjvV&JM<3+Cl<4rbm1%N1OL>D-!a)CENoG zX9c3`;d^LWj?}^hl)e$dpAENwOLF4eS`*LXehES&aW%36lE(Qzil42q)qJBDxKgu@ zh_URv4TP9euRk?)Z20NCI%;}9cJ@?b&!r`2wZZZUJaB>Ucv4*X)EftHVNC4Z zPnMorJ+MOak5IdtB?ID&eEAp;Ec-J|ynm@-kv`bnsCk6b*1@G#(s=SQ^Jlq4mYybE z?CiZZ-bVHc-^-eb5RV$ooMB&5*UCTOtez^+anp32KE!Crt9taAw;It{kpVF{ZeV=M z@914U(fZy(&x?f_qc>0WeD3$hQGVcmfkqz%f);am*+wU!>qCr^yf9l0fXyZLGkMIU3205)uz~!&$zZbZ5c%&(h zF|gbnxKYN4u77GQiJ4dOj~b&ioJ-$&I4}JTn-VG;+KMLCwGxkyM)}lF5Grp{@$;{_ z%q4{qep5ko3s9I&Uf1yz8KcTk1|%hlrksA*-r?hc$le6n@}`rB@h!~A3B$9(N2$bi zqr2Z)?=L*AQE&q>FJa5M4hD`0EOMnIA;@*x5#EO8Fg8@>G6|IcnYNIynBy^nR}lfO5r;P)S43yZ0%~ zVfvJV1cA9xU58xQapR=W)AcmxBqg_Nl0vb9} zU?k9l@vl7mr%t>B6ul54Js?45X4bHDv=#&lronUMJ-=JBwP~rVCszhY74+r~JRW6C z9k_zroNMCa6Bbq(yeaHr)?xCgI3@nMKGFtkbxwD`CH#u^xF`4;8I6F8`^&bJYU;pX zQkq0@m?Jgby$>+5y1k(IXs>N4OeOY|Y|kdGEzgQhedbtf8jzg-vk^cdr6yh=Y&1>u zu*B3FGTBA0)-^;-GwrrWGW@8+)8ZnO7jz3WSv5XH6QRMO36ceKE@7~#@rsy{qMq+P zaz$zltjDuOmHaW23-F`lmX`fzpg_5FfwBN89D=NHR+Q;$O!>)73zw%C(?2rU13>G` z4HPwh70;MtJC|dBNS>9ivGWM(M>RuR`dV^y-R>84XZs5mnLPkx&P5oHfFojp&hYWq z*rFT9C(Xhea-BkO_qj2U2Iaf!6(dFgTk*c@+;(5d;?3E7;m`m9rUY?X0i{B=&d!Ww zs#9jl^I6_sn9P=QWl?|{Sc0X3L3?1)WMlJwa9O?H2J+YgvZCS~TC^?|>R`jfAbSMq z=G}t!<>aorG6=9Ias>(h{T66Q60Cpi5_tItdi>3&D+lSpamg8%+k1);6h%%fgyb9< zt^2-8Gmz+TDW~1o`z_yLvqLCR!BH#~^nsr*{2g*xp{Xn-ZCqyc*wK!eqN{S(G;df+ z`1nDM*^gY5)`wBw8D8z|l%aYf|Cm9q2FjK@XWwj_AD*ODZ+t12jb0aeuY`q}YgRyG z=d%C&7SM~>?zD!_eFxK9%g{#C#YAD(>HHx?FQ;Z1huuAR|GW{I9?2?GlB-&*HBAaA~VkpZoR*cb<{ldnNwP;|`Md#o0h=Un``gAB1m0 zf_)r6aym7HYFy@QMNsG?zyM9x~UbE9S_1 zB}z1UY~9EBZzTjim_KosYW@{~_X_P7TYuMz8-gwHBdEKtI-L#p#80r9r@5^y|N3mJ za6ao$=0@4xK3=rY44qk?9xWrctx1<>@3tpsRap@(+c&F-r!ejQ_5xn338)YxQyT9Z zsx=(C2KTg6@b>DyX(=_MI@M+N7 zNPa;z8TTaX85_fV-obr&exczDi;%mzznH1onOYG|qTikxH^*eQgKWo01R41{E=f5ps8W$Fn+$6px3KOBl5qKSNHK#`H1P{az zu=qjx9iszLI1+VfZa64@6Xku27ww{@^BGgtlTKFc=(Od}?9Ec84DMSL!cxYPnio6` z@+n`4*+zRNwe1hUMz$1wK+>jX1$Qm=3H9F%Zg`U4*``H;^WF9CYQWfAm=iD$4?2cy z$b{EeqU+sH-6q!@#Uf&DbmIDrJm2j&T&{RSB_lZ*^FJ9)+$k zSeaHjW%L@uH-)u5{{dv$)qvu^n%9w@_TBMwbNB63nYj?NwK6CP?!%Trc=7)2g~ z*`Vv_qBp1kA8k+hS~8h-J$L>QM^yRu@H`Mw%=6Q}7aB4&J zv`AZD56#uEv*NsU8QW21wL^#-($e~fOms5^8O_>h)flb=)39|YaaB)zb)EH2cxNuj zwXM&m|DwB6Y5s^kBKwOM&O^#4v#3b?XnFwZ(FG>zpv=G77(35*jkb&ze;A^8kyP&OfRlea;D~1q&{p=ODV8wgl>>$}K!P2H3?uLQ|VEr+&6`eT2qE_D03F zIqSaBC$8MICyl4m?~Wqq*Ei&c9e;U)3&M5cPmy%X>2Ly(Gt5$~uC^NTM5R##D$4&T zkLG{>fN_QDFi_&D0nwkphvdT27jt}WM%p*FBe~+!vkATzW7bLdtpi{M#AtCtUOAA{7#*^NI6NUMgLl*+PnCM48c% zsdfq57xo_%^|%Pa=kTDDjM2!;*G!X-En|~tWl<&V2n^SyzKC}}DjjS674;D?$i6HN z=+^sdEG~_$IYBW5tt?&*ki%*`fVJ<1_0&3IidsW^HWAb6;Jf9$b=~MDX*mCaN*N;+ z7WLNrBp%5Qc3IfuaEtwx&VaS0f3?Hog}D_xe=buPTcBLGPusG8gXDu&5 zKUKS38Zxr`P{&f5;GVN2jAEs8{(!(R_?v4yS0>+kQ6}x`>yJ^H)h zJOpJprQs{!z*1?`V^SRSoh)iOhQ(AsI)fEuOsih3UOUk4{6)l^rY#(EuZqu>Aa2W&ryx(&8-9}L?1yMP@Ao&y~{>; zQ?@^1>XAqf#{6tfHtLX>wlALtw^Zt2QaN5CRo+GT6Nt$e*Z3k)roC3V+(5Q890=q5 z@n(_qA<;VS=+3v_w777fP}>Jn?~rJ9k>!#Zh&K0iTE&Bc$Fq1~e#&CF2vYq+OzCE> zqNud6`1M59u_NZZc4ov0C+tOXp{ks>4uY`7AF;slMdSNklr|Hg%GyQSipL9~IDPhc zX-3A_mRo1;(v$C8nnP>4HU?dl%(*W@>OOnUEz!a>8n=-r-<3bSr4M=T3`p9L0A`x3 zB6UdO^0zEBcwNpMUb$WoB}7YKqVu$$e@+6Uu}7nd7g=H~$VYCAT$Efd-1usAd)v3^ z`tj@71uVt^@`)OCj;%#>Oxr5cxciuWRd*_My;jIPxlJYyu z94JPvQVYDvf zjU9pNG{VQqovZ8Nxcd0x?A(#>^LE-eLni8?S+@agndcf zOeuSD>gxyq_%0)$G3#pnrqL{BFDKNnjiw%UVt@0JPQ1b!R}u)N!S}q4@>IH7pi^5TdANNap*pP3VZNJi z?g?XGdr>9tlQAqX-SS(l>`AVSa2ldie48B5_2Etz4j~x_~C>=!{f0HS8T8zkeUDG<(X7 z-uex~XgnGHwuHn$92lZH^=ij%It1AOb|8c;n6;VNfwjK$z1$}&8E~TD6AyJ-V(er& zcV?ioyQo6X)R^hn0}X}5z;)7H^5 zy&oQ86Q+RnH=&Fz^V|ROaG9Y5_U8zP-e?_y(Df5U(|c= zm`EqHgSWU?1p%_Y0$K?_6X;sfP+*jdMJFH#-t5J6EH_|FT>W%-JP+Q@i<1{Z-2=U&>CCUwg6)u%~=m zx~B_*#S0Yra@XoOJe`J63kfR`M3zNTb&JDFY`ebtPpTc~ZZwiD%2|P6nZ@53H0_tz+S5TQWX5l+4je`HC zwEtCzRgSvZ$mlYf-Qlp{0RE`_zT6UZ40GKV+feB~Wx-;ZzsOU@NHj7%aj#F2qcVIx z`-|DcQ^unGso)uc@+te6Mj&4-ecI^G)BXsL#hBkCM;xpc)*@L)CnDOH{k&ORq?-qe zJx2|baI7@0C*5RF%UQN|M-Y|O6vjt(8!VZ^TmcxN7C?Nkp%wa$F91yEa4=3Wr#_Gb zn~IPHw)vd3pDh;rR3zX074`4#;`+m0K!Awe-FCS=B^u_f*Oy|}`C%2yD!VDg)Ac3| z_4niPC;_J1$Czw$W^5WmW0UcCq&U*31dI2qtaq3fULRthf@+lV^Jhl2VJKH`<)t|4 za1!2zi!FrQeKd~kjp6BvPv>7^#`9H;-1rcnbn@^^K*{NLA9Pf^7F;ecBdu-iz^PP1 zqqjmA(8SFRV~AA9!ey&=xMON-Z`6u#%>tVKHg|8DxqhHp<;DBWEX?qBz10oJQkC|t zgMiEy85`Z)d@DaGJ>9_cohWw#V9O;vkFv4Ea3OUn7Nkg!o7lO!Wr^XgZy;RG*M%~k zWU6fMS&hciB}$AZr6bodnBM_O>@@~$*Et@JE|zWlufmL$yKLdB+{>#d9-Sa^k`LS? zDx+nmP(dh`*n<^Vr+-OJ=F2fzKT+fIcu!ADlEj&aeSEofH0C~gMh~xN9%q}4pVaLs z1)7rMu2I0n;MN!)KId`mq!>8N^IB>70^n@=J-=xb;ijb6Y}Z65)?X{_-l&6svBj!@ zQH#}2$%1OwP2S_eD@bVQM2k?pNAB8_Nw_>Q_&uj|*59&c*r$-f6!<`)jYf-`V5!;! zP&^R)0h$kHtBt&(uiW2Da%N?@Ij5Vn}e5Cb#k)E+&xxO2@veq`$Aux$$k;VONU-RU={XZxZy6_4NS?iPjVQ zj#)=ZNl*v`|KQ*+qOi{b05M4fUqXO}M)TivF70K-X{5n#oME)_}?QMrBt|EA{;ztR05{}@9R@)mG*v$8eE>hlb30w(5OJ; z5X-}x!E*i<1IAryl2so$G#QNT9g8dw}BZ?(S}P_uO+|ZXWV|$wRW&-b>~jbIdW6 zKtst)UVA$C;^O)QA>7r~(>!ogRDy3m{~Nka_#^kpp0BX>yQMDE4M*eB-#{(>1N&K8 zRT-=%RUR(YVEy!iN`VMWPapNo>jAuH^z7c*1sVQK%m9+NE;i%{KvN_O$KpH@f@l_# zW~V?W*!%gjf!|UdzZ^(G6FKkO`;+g-apj*Rd~KIh^xYESelOF=!-76?PweP1 zmF^cm#HE)1+zRrK zRlnhbw4e?7$r;2aakKqm^i-K7z~dEMyOm0~i=%D&x84}FU9*jX8~`DLWS}_#Xo%8m zb%G04m=85$@|EVCrTQ=uA~aw)*?|(di$Kv_H)|;Auhbxdyln~T8f`YULP~(7WudAT zq@gF+4N<_2RPz}r*=FKX=M)c0dCEL#dFc5 z9r_vl>6n#YI3kx1o98}+NVXZwI;E(wm)EI3^nF|*TqNuB0WarV*Mphobz6bNLKAhU z`$R!KK|#w)Ok2x;;Nqj6|6acw{KCZU6SnHJIX(qm-T&TzmyLu3#{2hq$!Bd_*@d+G z5y`Bt9d|8R&ts=tTn3&lrviK6iRMJi9P221$_At$_`-EY9K&8Vv8#k%>Oii+&Nt#KvuMy(@QudN+D5WwMm?C1q{9svUfXikTkc+ew{x9& zVBI9fP#_%%lLwL21Pfp^Bc%nKO(x)L)LsY*rZJi@cFS1BP?K_yVHl2!8b{WtL+ttB zqMzsepz!ica;Dm(VY6mNY1MTc-7`jjhC#MSKlU0^JRn><>W0BjNLLwiL*HD_)}2Uh z(a4NpI9JMZHw4$`7ZItv^Bv1VFm{veO@LE5=lzI$>mp2PFF|HtkX`wer~9?; zsRaAyee%mH1umIceI$6La8gk=>yOK`$AxE%E;MdxuF7Lp*uw|mfpnip-jA5i2Z@Y~ ztdxBFOsCx;>S?`_7)SG|66eMAmu~ptL9H7N4#ZqpIrr4V<58B zX$a?%lmr>~uCtUE8J&ROuZvX1lVYor<*_SRFG}<~KP4t2!7OcnQ*?c!UFI3r8+Teg zIAp2etU4UMM_lBa!6$0P9(dB%6cRGukhknf$lZU#nF7Q{?npePX5`R9G99+%GT|9G zf`ns6F-sa3O&uLtr$Opq&MeW9UhsF7KzLWqd;9&2%Q^z}Zc4D`xA))5aTY=+a!L{I zn!Fz}Xn%#ra;Kl}8l-*;Cot!1w9D$ChD@$s6Ej{W$9B@wn*JAGABz$qITXvtipZ17 z+nmtfC#%lta&1Q>SczPr*9OWl`te3<=keqv8f`Vop(XH+SC@TrB}B1Q#)FJZKU?L^ zj^`&jte8lAEY_d5?2SU@G9-G{Fa28Ac*(}aPRS66R*;A`=eb}>?>@Yd9MKmE7sMqR z)B*>Gl#ckm;Q{3hfLa!&@q*+!X{P{Yc{B{&Dy1H;(kZ`2?I{fEV?oO z0ywf|it1dupm&mVw1B@s#!te6F4~428uby{IIR%4LYUAP53_njtn>E}HIrGh851}w zyEcOy+dn9@hdACY2g1_$b|+}aF~1>hWKl!~k1|ngzhygez;PK)ayWtK2o9zSj2XLu zZ$9=w<(DdrX0(Wes&N7Nq$Yw6=#=Y+%0S&?-ZVn;iK`rhQIJ;a`7ANj8z+7&6$Am4 zqs9Lecm_+CoHNNAVL*`EH?%fPZMs7%3i{Of)P~a~I`;5@d#}7#ClkDW7_AjM_@mK& zXW11NS-;gQXu%O@{d(bQe>NW$koiGIj>y_`{c5*K|GUE{=J&~Ab<%y|hPT_h-OR@U zZz_Kc@{k{k$Fxh?WPe*IClX}BL*{vQKInwhO0ssDnyak8?&3ElS^xJH_vIziX2}f&^n-}n`{#X*a@xyWg_p%b^(k2Qd|a05 zoA()V#Z$waf{iZcNP0B)Jqj{fUX3nzxcZJA!h?~d0}^EMcwdpyV6JYS^0c#3VuiW@ zGRna$VNWoM@a=JV>C8`XZKIP$Sb(jjyiW;W!B<&VHzU7DvSxUBT)t50bkS<-SEHdh zoY}C?3{!vrRcKN!cA`tTC=C4|;E@x(z?tDbfOatVdHq&lm`DId49eWsW%g`ca(*~Z zaNOpEP55WDcXZGGQ!9ZFcfH}`00thHJEuZ>w62G8z&QN#No059kG*q+yURk6@c{1> zq0vvU!I6E}Bi!o+yEZQ~h^6zcALr`FdImP)tF9v(PGJWt7IP4L8QZNxX`qaP{skUf zy0pH5M-LInrR2RV6FH84`MZcqFV6vXuZP}&l9XqYVUN(&QGy+r?U2-iin&fwb{ovr z)>WgI#hp?r({O?SUMB_2AR#Bc1}iLRZJ6-YEU{9aoydx%bcdk8JjumY&v5Aivfb@7 z+)Ay~fsRA>ld%Cz$f#-~H-zj1ZU5!~g6qm(Y5Ftk{b@VyaI1w#g&gFG?75E#hf5@< z7zHf05}&nfe+O{X{59--(%N5YqL;yDfKg9Rd5tVgXIE}G({;PH41w9`XEDoU1s&4| ztn7qr+FZEoe-rvd!j$UQz<6t9U6;PE>rEHwc_U(7z|6yH#wA$45)ot?uk5z&ov=So z{E>Xeb_XLKu8H287zf+xN&5|)F<)yJCFDX zaZcC!dhNGrjeNipn*AgZffa84x%WTi7;237LZrG4IgS^j{aI(Nlk%KmgllmHeK&lH z6ZL0KE4+>uysoe0x5s>;O*I8oIKLK~nwmt5z8_Ls>(_g6l9L;G!f*B8*)eIep~2r; z^#G0mtWHY$@8RL9Wql>1?plJg)#?@tRr2ZiwXB0Q8#ch1s!@ENXyh#Fn%k_Z!q)02 zKc-fozm40M&+1Sf2=2sMEc)7md(~b(${_7`REHP&hGX$NN4clxLKf@R=&NE+W9=@>d-+n`C5~re4x< zXd7jJ#kTU4f8+|686Y_r?JqXLE-@G~a34$9HDb0czS%hEq>zlf#!*z7DG3fxIi%qA zz1o1bG~OKWPP9p8mhYwixEb*zn7>PYVXS&7SQYho3)jfBrKzt~d@2i}IOOq2UI_a| zlMHD}L{i-4kjN@j=9!QTc+iDzsRUmZrYw;d;;L)u$--AfviMk}oxhvIO;>p1 z6}UKGw1W4+udRc<_HyZ56OQ2UJe^Js&ah8x?kbHte_=FmC1NHhSZ%Cq6B=G&;(~6N zSHI`kjr@M6$8GaD_Dm_VIU-SPZ^Ojy`Gsi0_15SpIUJ9>h`G78DCoJ~_d<W97dK+yiE7-h#^r+}n>cef^7 zsa6e%k53kh*S_$q=m0m#5818B9m|2lDS6l5yR#=P^Hid-o%w)ReT-J%W8G4=L;y9O zGb1rl^NU6EXT<8-{g^*~HOdV(+8jkfcrBDR1J>BS^NBm>!cF@p`;)B#Y11b^AGm#e zEreSs@h2SIEX7A`g9#WHAvP};jcM(j4Xg43m7ZfhUe`Cq*kr+BsF}#6hVg1CZ01(Q zU!4SPcSua6fJ_BDq6!By%RHjK8zL^a(wSYLm<0i#@aC|_8q>ky+j|n?uZrHABwzPb z%hlkGK_BPj*W+a8!!EyDpqj+K`O&Dv`}EA!pUP3?xi^KvZnTj{4bfhHiBH z9#_(l$>%kg{{2~-pvX}y{-_$F&>#IxoBk(GSH4^PxQX4dKX6N+06&C>HCiyz7tZLf zZzb799)6iqv)u*L|6S9Y5h~8L5RgVQb>qmxq7-9gY{v^qcJPJNF}QAYUyT7CL_v~Q z3Sf0=f$hUP9u8Z0j;P0M7pSdmyu}$LrEML>YqR_d#V-oqA!RV2U^yqRVKx5c^b`sg z+PuG7M*%b^b~C+bT8&4l?2qLL=YVrp#VG5ht&75Ria{GX(0LBlw({Tn&eYQcA3;%g z{y>*l?vIE+;KfG2)9N+p=4|u%dgXD-ZC^+>9Sc%g*e7peHj9t^K?6>VRfgZ-O>5N(^JWgXggK$;o-ysXR-s_TxJ3Mjwk+%K{_uGc}RPfHD)BARgv2VB5hV`m#l`k;HI{u@ zW=o3gY)4_oX|qyKZy&@wlO^W@3!IQpW0?HsQ74(rObt7ux;1z|k1z+Aj`+#Q336Zs zyA8y#@!>&=z& zK?2vO6WGoca|WKhXXgh;jc@mykIps&T2fwIr(Y3M<^1cTN-A+g2eNXzgkc<=?9lm5 z{_v3PRX%BPO_%Bc4P5pDtC#xrJf;$t^SY+Y^{B`WQaSVp Tfr_BR)eXyfTU$eKEGPSiH)|mOnBcdH; zI?oKLq9{ z8QQ!~y=txil#~mRQ)v`_Pt0^|Zf4*FU9}iJAAdaexWkaiN0Py|ZjSO~61@Ll@VIGR zSye5Z)B0vJI4AfLa!5T+(;NFQkelF5LmY4IKU9mVqW(&wGyK4kBQa1SS-IZ~&p>1f zIevWRsma!o6IDUzff88R`(`au%)#&7N9pTil}sD5ko z98MIAt(b3~<_z9T;+CBoSkQ}biXf6Wv)IVC33h(`@5T`gYu%VNk*{&Up+wK?LC)2@ z@*W`n^+mf#+o#Gd$G?>7=F;N|2M{3chCIzVzwUKX|H0-^P_!63BwHu&Cu7`a z+xBdTv&<}2Mr&-SYmx8U5m+{|wfLjq-KQD}bMM>hiDpkXi#hFURE)qwyFQ^X0oldZ*x>;ou23JrS5HM+!}yA1>HVIrI(Ti zg(po2dR=SW)yd>f;xK6Hd7eH~>B?WLpZNrIye=cKes|i}F@Ok!ka>TlQHwh(I=36c zc%M`jHd$rt$iszwlpVR|bBs_H@;m>`Q2b>V{JjH>tK+GPT`#zMW@uxoS^+#;O6OtY zS;80cEsdA(i((XL1)4ctyr4v+xQ2J*nBGmNXj6E1Em?p)W>j8I5iCCwm!ds}_UUj= zWb0OUyw-&x@=1yC+apfYg2W4nw&$Ga!lkN{_Jf+Ny*?bc)iu{_CZ#^5?CaN3pDqFV zU(@^J4|ntlcb%ytyLTP%8b1JYmRF!S|zwMtt33NjIq^d;s;#NLFX zID)j=zrf7<32ozQ@3UH*5KT~>V`Le|EpTz45?~{La0P?o2riR96pw86@kV-7y zrEyyahMYFzr27jq*O0ct2xn6CBC}vYNPi- zyZN)k=G}23_iEc)AWTzDHO?g;`Ki!ln*+%Y``zV+>_N+^Vz_d>7C*Bwy-J*1#oM!m z@a`fnX9lBtFd*p=ml5E1uV0mz9<%;D^Hiu@glA>_g^rfx*>P*_GTnH2kr9ejDOU*j30?`Uh`ijJdT zYf*LIIMPuxQ>cM5dT?w^Ankvjoyx3Fq9t(vpV@K)0xG=|)e_%kVZ0tL;ex^w`z|P+ zVi$In9KzG@GN7xF(Wgb1=_bpCaWKa}vz;jb|rR=X&Kv#L9 zUKM$JATF~G-N@~KqPubwaVZt;Du*(gb7Z)YGeD%BxL`D+r+6nqLpE~on_2go(0`7m z@-s8ct%9A7hXlj;bGoj9e$U6JkmQs$D;h3F0@T#&rA0&OFtrclMei~p(g@OV`|Ouv zfHri5;~w)NDx`m=&Jq4t$PJHF@P7Z0J^A#|gN@GQRm*RAVI6E6@D!t8103aR+1YfJ zUznI;hrZqO^9NG0r%AH=C@7c%8o@t3??@_>@PN=@yxRTS7oBPy^{YLTL)7H>wd#%E zkn>Pq*W$75Fyr+k0m2dlRyiyVxO$%x2a}=4v(X2#-dJKDxA(^ViqMpK>t*0@^@-P& zal`)W4!}ugl37}q_@Hrm{kCXw5tlGQGueCv$nT#a}6@aL;+x>Z!P3=RB$K7%G$Mkw~Hgf+u1d%9L zz7M&5dGG_%UOc8_cz!skq()wribT(Oeq8&k3Pheif0FwDDSruvfwPzs33#+BQAh4$ zdrtS`9W?BrW&%HY{m;e*OjOaH?(Es;^Kcmi>Drut$Aec+R#wp1sjicLyzTv7zTJj@ zqul|LR1J*n^|(I%_(5JH`m|?nYxbKjQQJ9!^`l&WuY0=FM!Z)~1xF8B$|kNwsA820 ziIg#eoNXmX8+%6gYBz&MkCvOo{W5>FY=tkWi-dW2?n`JK9(R)UZ+T^Sp+L;*GVw`1e4*V~PlT!qj)pp#8=t6$Q zR-^|M+4YTpNCt%nPTmiYm4Y+e*Z}^nSF&gmW_uwWJmX0~J-ih8G$yoZ9E&+2M8vf- z_W>zp_ON@eZ>gfOvPl$I=E3f7$nGinyHj8%Yz@gGS08P;^!DyB7GEhy@1 z{6)^``)g*Kyd{aPwod{jY9b4l&uYYsI0FB@L0;PhcB@fK^!J%40`pL6XPY{~Wsagg zjO1(t@CrJ8v)*Rt`AS#~6h3^oeKu`r0dJ>mlZz;cYA4{C3v@;KIfQW+mQI{E;; zs7k?J#hP*N^vpg7m<9;?0g5t6r86PJIX28`yr@k9XEF}NLz5*LqQjU+!kCcwc+pf@K@Hg z-Bf2swrT6WDV+oDz!pe`U|#*Y2GZkaCuxA{1CZiDx`Zj~luKrKTyNgZ+6YB=W-G1y zmqjWWLxcN?*Wd@WSW=|krI>A6}t;H1L&CwhP*poG7BdwptjP|;&3cvqB zpPbha?tPKGN2Angy}0d5)Q(~GQCjjP0ElSTk*ttldr}0XDjZQ1G+_2K>NUfBY{Y%8 zjYch%z{BDQ8_&(f=5cuZz;z-B2)HZ zBLQ@d`@7xQHHWw>)_i(XhwjiZ@cXn7#=1rcRR7}mM{#B`Uy(;v2=_-bn3SYKx~|G5Y+&rLcJW? z$Za+k^S`}sCv!z}@6k^6*c(^1L_=R8K$+)uA5a=bsD-jjFdKQgHp-$I_0GfI7b5Es zcnPu+_i!=9HdIo;kY;q}?|T)lRgw_Ylqt96+9eflw3+|cd>otedr$65`V2g_s9KJE zhwiblwX`r2o>)rVli11JS}`iK8%>|1gr zLcQeQ_ywv@+aL#i@5hWfbngk@b(R%R7_#6xVqnXyWd=*l~X~)kpN$>B2i6rLiyAm%O zknt64gvkK(y_-`C=%`kV%ZsVeSs0;CnbMg6RMkXUp%FXJJJQcU!;oU1~{J(VKpmcM-lu zrUQW?7ntbw(u3Wz(%+jjmf*V{mkQF7JqM!kb676 z?csbl1S}|*)%q-jTmBI1{Wf@n#k%2=I!R@}1!WYU%qDGPbDjOZJ$wMA7e)E>5zqt& zv&8y@&98iPcXeBbChbZ=ER{D#6Pot{orEa}@@7k75vLDN!z&ggXIf6Jm>m7gJ*nv3 zAw!(;mBRJd>zSk^LjrvUk1O(#>u+(eIF?`tZT9#S# zuTaZe;R<@dhij3bOOnzcbkSFV!wE|9wXi63H+M4X(zcii%O4MIHdvz6*2lw499u5v4dNCFfaF-VUo-*Ebbdz8~|t@qNqC+rkPV72Ya^k1Ce!2zdMZuIesCXeKK57jiJNPqKeqBN-as3(?5KI2u+T&-5W{e7lf zw6S;tA`fO9BJZU6#f2)1PRl6NAGOI4>LM@WC!$|z{l-hQ84xcMvCg9Ut5nElAP@6% zR1gu=fi-RVR(PeD%D}W(s9^A44BGaD2F-V*apHWN9INngeAqQ^``AC&_qQ7*aR^8J z4@z|D&RU^b%{yq!jrasPhan%U4iFZD7+~W%3c8cgY}WzM-1^V3lx5O2JY}o*bCuzq z^on~*oD8EV#p}r9RCruykp`m;e&er(L?@ z1A~_3M#iBMg&;<>Ou-oxrA+DH9pr9egkfM#?^h)kIN5iZ?c5_{r(ib5Bu_%zaxLC> zNiq=EPkg0*(sx|7VqhUk#xD3g3`6m!v>O`KV|W|me?Pk7saz~>&%>MlgE0_~WKaY3 zDGec8zGTYmXNVt#}(G6Jsap~0Pgv7l#o9Khjg=C zp84Z(;kPyxdK@V?AW>qyr*_a zO6GfM$w3HG^-`KG1wOGFR?E=#-z9O)DhHjC|dUK51JP&9h@@0OYv zRODG3*Cn)#-!1(IM=r@Dq-h0P(S)UL>Fq6iTUi*xgCP8|8&{I8b38d}CE>I<7;DZi z_Hzs=D_eJRlg+t4Q)zhf10PM#NDXd^DR>Tv-vY2Se~3c3W+v)YND>%MVIZ!|=a)wV zC2uikfJ62A^~F=?*F$ak2XI_GnF{OLwl`3)#x*5)R@)Dmw2v_v7v^5et>~3Sv0oPisUH zicC{(bcUU^R*`LzhA$wg9`LZrnBvWu@}&1BV2p2I`rc&h*SiSnJJYgmTID~Of4>)o zZT3avf`W2^%);!i|45<6A~68l7&A&oj80G%y#qoDsy*H`*`#vu{#$DeWa%;(e~QYz zduM+43pMWfy{wEFI%km%_Y>tQT0D^|$3WRgL))#8K7rW{k(tw!BPSeZGa+#fBmdpG zw2sr|-O5E4*sb!u$Y7iThKL{R)f;YSq!mvB_KR#9{57=x+_qi!J%Unh_CgpL7WMrE zG5>v8cne_Dqd&OVv(`$HG9bszam&d7PZeV7WCRHajX6%c@q3>1c%NIn zh>b@=6EAMYpE7tSwZpPiEetgaiK!z?!-gl|Cn|2f)h>TUkZ4ceR_y?{xAuq$v2WXR zLj7J(F7o;SG9>953!J>@s}Mj<00KC1{eKZxux^3f&aSaIeQmRdurybF}_b9Y$G0fEQ2fByrTIFy`@095a>oc0q>a0Z* zX|493yVa()h;*K3E17N9R&U?a^6h_fzgSFUnwDHDlgKj5Fc!J!W6ESf*{&fTgE(yN zRN=S*XZ>iQk&zu8>i8H4LPA1rLMzM zXEDY6I#(9b-m)s%w;~ymdox~tXE)4qiN3^_2)aRiVFk|`-jk5VcsREhPv5r}YMarz zbZnij_b(CGATp?B_V!!KvYJeZS)J%$Q!q=4ZGC$4u47jDB)@pun@x72Tz5mjFB=S) zfkYB009+e>U_vthsKxNeYaiB9;4`t{_4P*g*eum=a8D3f0SBnrt~VsFqoB8p(X&$i z8x}IoT~DxkKxK0n-RN<1v>77mSC!4j*%zMA3{g}OkA_pZ?Rd#!q_XOIeM>@km3ilP z-R(E&6AO;a(ILE$o&lTvvsdH!@9T?2o|Q#YFvfgy-JQ`Sw8n35@OuM|Ez*`0ArbL# z9`!|G#6zGQ)gGBjmOamdU&%#9h-{{R{qN3JtCAY0-RdpLgHcI?Ft(C6i>I;iw}yEu z!mubT)A8r4J>Dgi;zeUJD{MH7%Vr1_2*)YFvU-nbeL2}g9pX{U*$=?RE!A;L400u|e=jBc)8J%iYa_F)i~HssmZv#kbW2~V%}$c| zGPa>2j2ROw8#q3$RQR1kQ;^jPh+v@1ytjjES*n5iXoBxA90g7_1d#+5r-i9$9CbA| z#irKAgWU~B?iav3PVCSTooH%-#%wzV6fN+%(~#)*Cy)K7{So6xf7C<$|%r$d4=s} zHZ+`B&(0PgajfhShcV2!{rqwLBqWB1 zt(`%u;lzKVfWwY0Dtyo7h~iFBu?FdE?QOGN&dShsunjI;-oT>NUxn;h(H5b31NUz}?Jw?6)TrhWoHg+O zI1N(0j}Mp(GSheYqJZPASJ=@Wkni1QE`Q&Hw z$FyvPOemgL15dCk(*VNhvb&f(nxkF5y!>Z$xi@+kpWcdPQFMXBU z^Am<=u7*y_)hg<-CmJUD_F}o5H$%sP{OKxxpW_VmPRfl93w#BCN5$gk$Sy?%IF|j4 z#qtMbB3q3#M-^&9=!uSlbi<=Tneln&lSi<#r#ya3clw|CwIJz%{B>>q=ijh2Q>6_k zKOKN58w&N`DWICq=hO87waQplvBi#bNp^blGePn0ZeCcc_EDld(SeYL^KaS|#vtwI zWy3;H${F8%1X1k71WGeFAGN2SJ1e_tDD+wl(KXqU{P|*3{oT>^f#C}$E!45);-Tj$ z{H8)O^V2T^B|vfoND=a`Cz#RGZ!@3=5v~|zljM~Ahy|d@Z_n$rgvj_NDj0{V3}GP7 zq0U9NA55h89sZ{Dq5z%tEe0Ub979L65s=XU1d1*`9>Vy+*)nn@A_U@|$tIN!LiH?p z<5STU>Wlt7wr&v4#8`X?igmTn6X**bt|*Kl`-hqx&O(?^h1>w34CNCLq}`Bm5S^{M z*M!F=M4@SCYJK19o|AI2QI^1k620|HIeU{QLnA-Cj(`JRGmi|PCgZ>wH7IhCZ$A0> z-i8)Nkz-xbjVUdDNSnVYUYj1(S6gpD-@hB}DSoE>k((_I@M`2Dqs9wOHFfa_JA>E+ zGcL%Y&@AabcAz%JN1?zuzOtx)1&YK2v#BD(Pcy|&cml~)`91296qMQ0^Dwd=$r9T>awH6u}qX&VR805Sc0xsN*XzwSG1YWUXQA!y{lydEubQJ~2 zw%>99!cLIryQ1$%Rh^%BzX88JveZvX=#tsnXNiW9KfNg{ei`+BZ;rcxbx$%DwvHZ0 zEdDD=WnGm?GA4N>Ttrfi+K9!#@#UF^JfgIXQ}mzCf9-OBxGV4^rvuLDh$dQiXU9mx zL7Xz36QB=#vZ+khh(SUllM`CePW4dmTq8_9^NsjjeI1?2FBALybJqJO_{#sS0g=5S^RUrr!G)F_}S4N&%T&j70vrZulp!lKh7(m(*(3ys#Se2h6K-2y23l`M&! zj3w-g+-13h(!U+%NNECN6C!{$A|eu>hxIHw8Bn07v(6uFR?&(ZX`^z}ViU zHcA=jqdol%3n+Vu?nWvctB78Y0a8S9+=@2y3k&~ZO*G=KxEgylZO%C{=$Jz7d#w7S zUsBlX3322PgTkpCySlWHWWQB0$-PQ-*X38m9^MwIHzCZ95C^itYJVG`^srrwY`XRl zMj-(fmVo;sin6kDDY>*XBvf=-pU8shF#;{Z7{0!1kvG7J>=#ftNQ)S+w8s6ys<9{uZs-x;dw^%Uze`i3$)F*U|@qTBlhS9O( z7#&xOHEu&f7t}xbFZIW49wRdo>C_QjjXm|(_A|hYjUIQ^Y9g~(K`p)rTp)GnXd%0M zydzX>ANMYUyoO#qMQ`LP%E_R3d*ct`G6nA)f1G#gL3?(MAAbp#lQa1B-8U?pMx%QF z9g>Sx*dz9lv6DBum8LzGZG2_JwWkW6`ONq>Qv`HDPIIY)1}Eb4>k6&I>0Y(%>zCms ztb%0KlK=ta*^T{z6ddPHvC?!-4Ed!yk+#)utUKdFwnFNn@6QLAuY;cnK{FS|iZoeKwxu zK|e!!wt4AE)A%FNJ`pe4Ce`q2lkT*tH1is((e>?P#^tVmKxYMYM`pPcq5l&NnnCw| zK2NugniBlRXixa2_9?Lr<$)=;`g(0;Kp-7QR7?c?JUcwa)!IR zDrFvsrLEqP5`pXXKn%tXg4_dHM$lsNaY{evoloolvSw}NN!#9N#Hd`+0 z9rwT{!ZYYKQ+VFMlqr_lN9&M!i4!Mo4AMARs^K&t49BPXuFh3hmZEmzQyotf_f-pU z?8dv>tPRhPtlqXCU$f+WHQwbO1Y!ELHbpAN`_ ze>!}F@kUzNg^jFYM^}t-*7U0%!Zu7jU3!d;k@>r;eWmwrCG0TMf{hQ9NbZ+E{9@rN zKXKBfPvh@Y^LG|5sH3NI8q?Yvk09xM;s39sIa%ZtC3@gc4{pn>Az)o~!oA${ZQjgS7GYdWYvGsLp;&D?tVIQ#@&f z?fY-WpXtM&ghfLCn{}+f0DQ=P{BIQ=a85(eUg7|De)-eG=uI57${%wKD;$z(Khrf_ zHz_W$Mnc3D$#XCI0`?3CzSmMBEe`tG+3I-h$IQbP8}&PYRo1C?M|jZU=~b07&SGQD zM4HIC8huac+w-JDhDTA+bu|M$0`9g{MMK={w7{E7l2#vM)K*yRrN-RqN$_;X5+gus z@jTeVVNPduM}oekI#Fn7`l8=z@sRA-Aka6#`m+|~tj3Ty&MfeuQ}q( zU}}H))X@~3Z6?rgM+D2O1*W8lJg(m!vrkI2^iB|sEn{q7&>v~?z}P%dU_0Mq)`2E7 zi?)6$Q28UV&Rb8Nt9B>qcUY#JJ=5_}YDt<U^kmbAq)Wf&5UH>lM=R z1NxFDepm=#3X&}CTuUbv!WPEz&t4H=K>SY>W(n}+oto%1+D!xJE8Q6diJR=U#xZ(w++3aptz4kWd<_{|W5lhFsl(h6>dKO^RNV z1@YzfV9;h?cx4i4;cp|+sfAbt&B%@B^^&eVc6O!qH-_59y7vJ!^ylC?ool^U1k61r zmXEi=4d!%_nadxY+4i-SsDq3D|5luFEIhaoEQOtblKxTSolRZz8_lpEs%0tzhJH#q z^PbpTs`M0NYjUpm4)EGc8rceER=xscJ}O#O4vd$(BLFy%BP(@5zjK9W(vs$(7{ZbRD&reJAukU>o4M@}fZOD2mq+lk)w zz+{V0SjJ4P{vqLlluC(Ts$GNiaJ6Ijzsr|ekqFjo52cixE?QXxMVAF1nXfV6V=eU{ zr7~m`al-f+g%Skv;Niq0lMY>_hr_|dgh`Z1Ine({|AeBkzMnE1?JJqn`$s7RcnKOn zLVEGsCkvD;5v0o$vUp=Ug|+CS|80WeXXgU#UNL}FCg{XN-ry_&-^Eoiw)p&iDS*j~TpdoMmWTV;7xVa+gS zHC|`ESiNPbolN5GY|RYVCoQUF+Z9zbq*fS&Rh(3`t{yCYbv?SOv%ad=ZLZ%bnf10l z5&{R7pPUBt>o3V9mObBa)imwAExulS`&nKlaTKk;bW6-%Y?;pPJ2+P#XH0##$fVzP z0eEiQc<9?s4KCbRJ^^KHUG0_Nk&gOIes8@wF7w0E3hU=NucfeWd+qfzmeZnhIG6;l zb&R^u<7O_OlJ8}wbGJitHiwJ+l8X0>T&`Uzx=X9DlI`_%R#Vb*yIXs2b&T54F#5JN zCK*{vAu;Vrv@`qMcK37j*d=pEw@bCodvo=pE5<%H%=#TKi%A_ygB1;fzQjwTXFUxU zb79t7wh^{lwtV$b9g6KIdKp=SZ*6_6)Nca)^;a=Lwp*myR@%p7QNE}~OYN`AjeGR< zjHkdy8{;KoUz_K#&-Ev+Lfo&_^Y!ytguaAT*7m@+-q8B~*X8>&#(KuvJ(ulyy6;w3AZVuXQwr*+d`18`N)j9Z^(72apznACQwOaem<; z<1qCAiTVHj&is<=suC?$DS2y5yAQ2eHBrLfdFO&4$6H|ZBZTaR)e*APUWgz2_)g8l z5gyo`k7k3Lg5ahtI4#Kn(SZesM#Squ^bfa}qXznX@p&D1T+SAwspSa{URUZI3I7!w zk}=yrA)_})YbCtSe<`IXYoRJeGlhCVqn1=a=hdH1t}^YQFR8j35^m4@4$uiOf#Y9c{~OQ_B@E(2p-|w8iEI{>$1_1_@qvtbtyn=337rXa zQ{#Ekj#zYBFt|*5M#;an>uujezUWt_sZx?XKcr&(AI9D~s;cgdA5;XSySuwC-AH$L zN`rt%cStu<0@5KM(gF%fcStGCrBk}3V>aqL^ZTw@v)257@8xjL-upbyryk72fB!c@ z>stDo5m_BflZuQ9wU(x*WeAt`#X}i>p7E};buZk1YG5W|x$lkPqmzsL;q1YMo{fKbl#8l6N2h$GA_ zEQSn1^GBGUD5rCyVwIB2fAh3r?KmM3AnFW93l9r}vzI3fZux*o_U`H~G>s)Is_7D` zz-YuMx-0}q5K%0O9qUatZLpRYT57!o#B2#a)_8r z7i-44=1Ih7AF?b7pJ&<*^Jimi+9Elur2IO(lmqVuN}76PRMe1Y9Sth@_+UDD4sww+)KRq- zJAycFBP0J1x}#0GV%6Mu?NAJJ{&+H>`1&2*nrNC(G5V}v0f-x53C@lR4?LMOG4cXi zO>E~r^OPY_GUB#w&kX8T=}BX80y<4N@F?lu0z)-Ia%yUp{Gm*x1*3cN$SAag8GBkqlI(@BU%ROP&2(G`I**#X0@T%G%1xA{X{Q zBdL0>$^OcvdVse3xTxn)z!Ih^gwCr`BObF`>i#;6(vy~O12wV0g)`0<`|3`bj%tma zLS`??+>*;C4kb{3xdUsQnN~){3?CMoq;=T)bGiP*C0mbk0N?n)zZ>v!@e|sNacxa> zf~6%@&$u%uf0jChXPn&o)z1b(uQv+Uw^DQVPMBq|SQgDg7lzC4+JB}QG;HEiGQFe2 z#yGyK80d4hi9*pPm8y12HeWOln5{kvxUo8KI5e5h@%?ISHC@|-kR5Q8MHnpPd9eI_ z=A@hokx{+r!_puoHWfEg2F(nQogTXOM=fhy%;;(HSZFE{iD-Vi4eC_hI?OC0Egjip z2g5K@#Ehcc@{Do#Q3VadUK>y3>l@m}o!J<*Pff64tKPZX{Y>F|T&RxB`XOzhO@UUg ziCnFjIaV8pGI>8#ix~tHHCnJ~!hNi9^5CW;Q@0qDq4fxhQXhP6Q`_je$)=JmI>?li zVC;ML3qBIdybnku%Eb%uxCaiO3P3+mGm|=EXZ6U2aEY47rZe?U!(*lN!}jqQI2gWf z%esbKr)-&qCO@H-8-e33EkiL(CCt~9!Q`~Y?o^?YpyPuWtq}HVQ+y$)GO-&gs3Pgb z>mOss|F)#s-;g&rFWc_LhiMd0W4`r#@%}mVc^5X%r1J=VYibo#KUPA62d!q4{icR! z@Kv`F{5ypB4Fh4{vTuXNy8S7n?hfM z5Qirz4ivq2zv;ZbbtA-VN13t0NWGvTfXapbE-W0gD8i!dkulq%hQRY;EKmF3?lac$ zS4%`?i|(G8M@chm!%tgbt{xG=$w09S13O!ZU(kF?$$MeJc*PrIW6vbX%0_a(76`q6 zK2I*2Bp;j@66fR`3`^qP?*z>aE#k^T0f!zUDdebSEACFy=NDEeT!>w;@dbB7uo<+}@y%*uI z2MrD315~`<)&H}>?H6ZRWCFK1QMrD>v$r~la#IvU#%FfR3*88cWsf**AW$VKTgWT{ z`WL4;Ym3-nbpFOjvtGEd=bX5OACR5gB9PKr9tAzGOX#1m3X~)M&=VSkR7Z+G!fO%~ zb`%`fe*1lrF*=va>&(;{yrYNwF8GATwBAsTtBR*!a|0pKbo$tzy zSujC$ctmTYwejrM09UZ zea}$Q95hXD1XzzZu_TKh72ptkKaZ8E2!a^aSE~1knZPZAPX>ZGB>FN0 zb`#r#%5S6To zEjpdOZ^)0f>+#FvBm~_ZVqytb$w}!rKg$N0hpD&F%qcWbe=+{fUNK&T@oCW{xMox0 z(A5v8eR>R)j5a1u;qCSop9d4&dQ)(Jrb+c6BIW~bConxHNtav`eHe|$8ryW)kRlGd ze*Y}w{PI14p)#yuY7EV1^YQQ09fg|)QcXIm64e9~(N7+W0%h)#fpdK`HV6q@7Oq0fjB;dztI%mNX~hP8oFbU%(u zD~5tCl2B3FR#z&9%jgit)vU_gA5vMRx$5uN{2oeN_T>v6dqB-)510Q~)qbvxu~zso zbXBx3%<%d`W$q^CI$1AztTGo9&n?0H^qByY7xR+0@W!WIcT3x3-QXfaWek^D*nqNz z>o@dS$>XI5uk*c**9gm6O5%{(3Wd&{fAh}mw*-luFEge}M*%?OMpSsyME3AiJjWsE z7ZVtgUmzhQZ9gd0qcm*}X}MFhLwi*ZmJbd_n5f==*?jw9mLCi5N~Z97+&0A?D~t(w z!mD>-RCG~0U+1S>%2}*T%zk3ugkcnQ5EPDxRmWGR{j)iZV0O$5-{cvhdf%dMP-8^O z)@Es2S0*%*E-*+ZhTSMZQCBCLdrI4DxcQ*JR$+`nBTW0iO;;JKwJ8uA63&gcEO1_C z{i+LYh$iFv?T|R!aeaLFCK>L=NQ?|ATa%b|L|^W!=y2smIX&&j85R*Lb!SDGQVKX% z7loMb4@K`Cx^o81mS6*Wah&N~f*^xK7u#ACt6JkL_LPYX-x9n;vaMN;#$&2LsQ(yK9he3`=8*ROuFWX{6!sBVJUVUtR~~vET()N{X2Y>eAg4 zRL7<#N)=rU`g)-aq*815KW(|y%2r7hXgnB>!#jy|-TzA6-ij$X*wu@< zP8xSyhv_54^b1HA^-TLntIpK}}#hlhTf z{du!Y_~|cG2bNte>?`4IqkJ_Aer`_vv<;>H!eL43HPB3qGKDm}>F>dizsTPyjYw1q z^Q*)vCsQsQMr{W}qV-ijVJ?LMH`zg?rH) zUzZs^wsZ#R25UCT?9x6@8Ou(Ar%+52xl!6%TOkd z%uoi8-b3R;ChQj)lU7+BO=G!Q{PNuU3S{>>4zB&~EOXXm>$n`4%W$6$QA&s71 z{--Sn3yTmhRQ4|n4U9N=+$g_uil!VLQ%FNrU!KSZ9lPihDZZQ_@%sX7Ztf zcSJiVQ6^b4ss3!gKT6=;zV>;iL6t%jM9T2Zd7)Rr-dC}pA!apn66f+4{3jRw-T@`~ z<4@~7e~rVW1^AOQ!TrkTfond&=K`xkK86 zQQna-n~Opgjqd^DgHtYe%Ig3P1{E%V0-oFdEap*Ciq-Fi&rMskAiL+nqk-4}u*G6*Dtp-xS*hX@P*(TiNVkH~! zkTps}Wh76Susi8~xJ*w;J-Uhf{!yE$eRw#v9$~e9ir8V{(-Uf06l>P2kb7Jdv^Y!c z0i9M8`r+^2fM%j8 zTG4e>*pb`Jqo2GH_?f^(UxBKMLJX=#cgCFHj86LKRMqezAYFWL7KMwoL|S2}MmLU#6yiu{mV z@Va5_Xy*J~M45sTe-3v{!n>5@)nyb$qu;v|iYCv(Sv%h|1yc!(jb9F`EFcfV%+~SM%CLqq89e7L8H(MJkIrNxl7qDKJlh4$x-_37_)- z+6dbA6e$m^SUbv&Ai}Y9XU!P7N@e2G?x1xfFHtNDe*Dn#M&1Y`EN)MHe}D1nVLI`$ z0+!$Dk!sC3IM_b@9Hq@T?w_^<<=yXfMHWlg$127-u(D9YgF#o@>NH&!|#Z z*u~BE(P(6-^ax#bYw!xil@VvB;%g@`sJ|(Bs&b4l$V{DaD*a-T-npSV%novnVv+iw zt`~a>4L}v1_8jyNoY+=`l$M}`G|stLf1&+^Q)r?MF=`y0s*FRyo>fpA;N9SqlV;GS z-he3EQcD+|mS@}0NeqQUEpC_3el*CB79=1D49Y=1&y28VtDG4)WaPJ9h}dNz;1>qR z5lNPm9!ho38w+A81)Jvt=DbjWd^fQ@gz);x+AoiY#DB-qDNz$}X~@?b>j2=(FK8)i zRyNmv(7~oExwOiDcRB`T`bJuw*LxzNSGD1K2CQef>YWXb@L?M%-qtsv{Irj0=furY z=;tVTe16;u?wZk|t==O#r?j zG69lF;DLq7*%-BKj?|EnXeMI}kur*8?(dFuTzV^I(yb2 z6-$O4S6yF;uxQ0j4LKHcZJ*FW@#JG0%ZP-y#6vdTVoSCcHTa>%Ie8S|%rr7bWj7qy zRAZvWrsZRJUKhhzPK$^~XF;uSeTdDl?=M(F(eWAgv+~B z0vSc?$65{-t4S$=d3awlms-#^9aYKb3GSk`P44_;AUUkjJ&!~a4U1V;7$A#zn9u|cJmWvF zGAi$`G-hJ>NU*#fV3CzcBWdirgpAK^Y%HbLGP;CzUcWCWPGl4~GH!j6A~9SFE=EjB@$><7nk`?t$O2J+t=$#4*q?|~%;V(Od6I~VDTZQP99>n%~lu8fSoyWKn5RT!wL`-qoZ{J|;LSM4m`D8VM}Xt+v! z#Y&tp3obG|(!ck&6z1ZcLY38i{Ut&5?tyx zjd=KM_J>i(s@B6;ICVegm4da5(m!41^J(l-w0FpJ^5@3M45AVlqZgum0ZfI#8ari> zHip<9I{q$Fzmr!T%1pp+oVM#d7iN3vH9Yye7Bz(s{`(>G%GC;7ivbb=!8=F4Fs;}l z=D3~8CTC$aSYpNfGe>)jB;DxG`sN<)3@p+j^r*x17%-Q;Jf5!!`0yC2 zub$`%Db^J5o$IXx93ZiJyizxtL)PK)RQbSh-h{{ES!_#2W(7J@f3P!BSk!SQCtH7g zqVIa72JnvHMy^E2YHNmOctUQr2|=9WR9AX66!y&&frTdXUu5t9XU+BVkLg4RjyyLYGps>%Yq;4p8y0{Uc6 zznV$3HMFYL(3rYO*eW>TC)DEy!3olnO&!K+Io9s6mr(zg96d!IRJ#j#UD@RO>{n6n zHgWIy8#Lql<`mrKAG_t)1V6QpJ8}p^`D~M-_d9Ekgq&^M5n3pIBu>{bB2sCX8LRfY z0?W1P5hfqbmOsMQmxOPzzHIxkiA%pY;qdM&JB?W+uG?M4G41o&D7tqayO3m2N``w9 zUC@uC+L?BAbYPMw(LbV@+)C_BnCJNu+(N|~;jfG`ZC}MV-DLGtCZ6EC!D;X0OQHNp zm;4eL_y1|_t3~t3R`1;u-A}uJdPePO2veM_Wzu{s4^ zpZOVsu~rclxO?Q#!uIUbUFZoV;?JdDvc|H%bY1NC&vt_-$XOQx_dJvX=v-*+Qlr~kMx^e(!+rJ{ z67)m62$jd~sRnUGe`ACZEuX9U&;{;*X#$b)I(cBiC+KC7A3%ix?VY9bD4pQQvKPtW z{Y0FaakfkA%&a+J&XAZ=*_o!r4-H_Tg07D|zbE1Jer&YlL-DL{E$qVi{5RbZWpc?z z$BD&$4K1(bF?S-=^++N_RxDI0hbsM=%w$Wqk0!iC{=}ofb?TAIFzp)OLpQY-u8e?k zGqe@1#lXaraZNK&L?R&(MJ)pf*uZl*ppM}R(*woCGnG( zRwvET-|4LYJ{>|#E*7VHTj+aUSuX9x2(dk0@YAAXpn)j< zCP?j+jqjM4z^$D5^eJ_`Q=kIJWAaK!V`jDkmTK(HPI%JAq3jojmoLrih&;9Zj=|H| zW=F~>g@qehR4f(es$VJTbYb5@JBPW{M;?0$@}!=*S@LIaJGL1hV8Z|F#aNh_kci^K zwL<~x?8`0R)44$dS3t(qd+uyc6X%{f4`9fykACQjU6nYz`(X>M7X8=F z0k;C>${qD0w8{PH8?p!T9I=pk^NP{%b9rB`7(0LxKwA!vpBDR{0wJpKI+3dcY-kXB z<-`4Z+@0QPs36qwbd5rvTG( z0j5k?SXi(O{{+AT2l%)$k5mhz)+nj>@fx^{l~cD-|Uo+Rxt@P-C+;lLygP2T?!c7j7_H^6O;N1F!dawzHDKOD%_)io?C3Iduw&;6{gFVqp__*W*y8-kNSMK(OF6#;)rhf`7pRupniaL))d_5wh zsDLnwQE~2U9_$k8|8~js@H`lfVvf7)4I9Xd8Pw&g$yV!hp@DZoDT z4E5XFgEqowLj6DZ=D+s1>@I?tHi0@({X5%-4(kPBA}aG9~O z$1aUo|AAc3LrEWWstA|Z&n2j6stMhXHjZ(Q~~-?e(D57!SZt&N_8XvZ^KW;3W3geIZq z(|Es}ZGuZK{{FXj#DRi3(|waB>D7hF0`E%$Kz+Yj@VYjiEvVSy^P!B-`S!FG12?#1 zeAM>wTX+Nn^$tF{eB@j|1mmxFuh~+P)*cW-OG_HCTxaWc9$4+#e~T-puy^(LDLFWr z0=iVY?hZ@wWmJsgFg10SJK}6EaLQ$D--myT-NSiGE_iv^A2C|ExxX#(%Z)ATnDQ-# z|5?A-BZZ=WQUaP8R-+~qV!oGVxbhXiuu%#1>w@c+1_49Jj$&uw&#RFVk=Xn``3FRx z=lck3J-RHPnfKf*=D=zmar3@&MTpK&lWQ<2&7nJ$U_dsPj6k4 zncM`wa;6Hows&NHJj^iZR3%$5E-v#6&|7pZEU4fQ{~4eG*HZ;ot}&KrWYp~ACOw!6 zkQ9{p%{+F!`b&Je6trA@b%d^m4^pVV&}6yCEuGih3T+v}$m}dqYHDgZRrvO;Y~Xj3&rh0#H&;i0 z8G@(Ov8jeT4nsDy(aAz?cj@#k8@bVM+PMBQlI;eIs*cNsed)yJpU9AAW>3fop+qIu z>@6jTQ612UHFAb)aqf7#aiYwU^Z9YFzvxQerx^n70PC!mcrv?QNC65i%6*y+*eUM|a>FDdX{E~|aFPL+)> zvTOZH*ie#Nb!*JM>m0@a&GqN`@=i`BDA0g?4zT>?%i7IyPD}IY&3?50QrdJcs)U$q zk|F#olTQe9Df;StY&dV&pb=DQPq($p4&BT4_7O^F(G7c*+Z{`vhR2eHmy#k;S`PA~ z2;gA23i-%%7WHMG=a?-u(57?PP*={M{6HN>d^1UB2NH`ess|%XL~n8$kM;1wFV${# zi}>b3ZlaV3xu|RaVw)HWW_gn9bAJ18u{=F2Q!jZ(KYsrN20Q# zJ4FaQU{B}i|cdTLrRQmOI(WgD*M0N30yVg7sKL86d-)P|GxlB5Z@BZ*UtA2v zUsEWkpT+&y4BzS9BM3akHX->IrgR%#SXc&;%6Mk9;7e3Bv`c~J6@hQ^s&R<;dF)T> z?0VGiAu8qr!G#UK*&YR9QcbTjhh=#G*y=9n?)zX%BI=FGh4-qv{@chhF+mhNCXx6^ zs}j@AISF1-`(}a@)c+8rgbf~;7E3}LhYf~kwm!GYQ6 z>)Qfaulp)|b`uEz_1dUxt55Nreq^l1s}Nf19@GWP!q3~abBI-_Oyh|r&cTl-xX%yT zfBP9j>fT#riFMgtw0Om4o|Dz=A)5GYY+gg8YxZ58ysWuWKBIOIHJ^-raDE;ulG_w9 z9MT$U))~LLC2Whwdms{n{#gA2C#y~qhZY|$lc;}?9(ItAY=dl7X;;Wc9{(evJQ6Z~ zRomPbw+#3{hU>H8YY|p~vk)QA{pGRM-f{(6CF4Z;WK2%i+?EQx^(&i?IoxQ2LxKxPDa|im(^8Og>oe&qgj%eEWYxhogxW{DJ#0WpaL9$LtMX zt$BDwqfA*}%M^uAe<#7CnxuHG`^t~Q`;HEU;2SJGn`m1J2AI1!(JvTm#NZc+c2O`M zW+!TNPQZ&EGr2nv=7?2jJ4W?Er=AlWk9LzEkN`XM->dZGO8YM(bQ#oxKPT%h8P-GE z>iG8QK|69SC&Ah~&tzovIKbs`y#pS~Vbd{pLRU(!JwA#3u}dx|^P!@-+DE z6giG6>80p=Y4Nh_i~xT<5J`RcBJA2|%cLB6v1;+ET110AFfh=|w-t~PatAra%SnvX zWgxu zaM5zl0}wFvDU)kimF|IwqKxP3@AfbILLqqx9I#>A_ghD6=2TD0zgzXCFFYRFc`Lh+ zrB8u{I6YBLuT!NTG4eQ<<3$GnsEB)ah79=y`9Yl$TA$GB4u~NsS?1Ba0Mbc`Q@G!t zlh{6;IXnW4R>vwjIjv2flKOjVxy>Xv0j}F`3528-UCWwNZe<%RCV`LGn?p3ZaHRVg zH3+$!wibS(r+>C3zKS)9jF}?e>JX%C{n2a_DD0OqFsw>niUzQH(lt?cxQNi|=tCG7 zm=}b+A{az?K^4BLg+GDJ{mTi?LSXc0_8VJ-KWoNW)TzbmoG@mJbgARYfkf0_8Gk|Z ziLa25WnV(jpEEXjE2wBt*KF?dUOAP-2|7y8C)B5-FZ)P#h5ZOY!2fI{QUiEuYamNf%AtK(=XcN}K0&6zrKDP=gJ?o(` zJ8#m2M%x!|6{}a8LtL)IK{8PdjuKMV@rNItqazpBOAnTJv;d#!d@k}HdE;Tr$*7fa z`tz1$3K*DQAK)LSvSh?GdAs~6U_yd45dFze>b!m_M0RO#+fRnpBfKF;8ULdC%J0tM zLURH(Txw;jQRr)Fv;?(Qq*fP8d-}MNt5#bRB^;*vD%*b8T!Gf562kN+qR#lhaQhQ7 zJtOhhr*Cps_ir~FR@A6fZc*m^jcc6b9!nWDhX^H}9WorCEGn0+H12bi3#@nVANkU~ zFjgRmZpHck9SignpR9F~Lv|k1 zf2_;*$!t~NQ#eoKxntJqntuG)ZGQx_MdP&jMO_X4weN4jd5{Yty(!qT8lszZ{V-0y z{d}avRk*oj$FcYguC@x^b#bTFhGi9|1T%rv)kleJA*#OEk9+%OgxhYGs51iPS-u3& zkKeE&Wn4Wdf&TG*)POkr6E7IZ-mUa11s3+*XSwa*fRow6Vs(z-0=>*Gf-~L#J*WjK znbux>ql%5X=b5AwHJxoh#U%(PKr2J#;@CI%&PS)Bi#KR(*?F`eW^(SkQfF1|WvveT zY9aV2!aw1VFp-LX!r=`M*<-y=_o!c5@i56vmOtU&YyVh%Qe6L7HAG7MWJIfM=Fw`e zPl0Ws1O#=hN_}+vxm!G-zH2vF+Wu&E?|7o5VnH~UdHeeXf**y9$Bjjj2E?Uou(YJK z1vpH?3$1Xsbmeg~J#5m0qI1st{P_qa5_K9V7SxDkjr_JWAx4AsWdVW4aR*kh1fEFj zwYt3ph{~fyelpYYGhs(bl&ZsZUiaUx?HRObj~Ez4WiyClmTXz2OC@GF0-S`D2*(gF zU95N-8hPhFzX)@-5dI4^!s#~K;p!P8`c4}yO3TPlMbAZ6UnC@hKrN-;yRpt8v-y_o z4qrLCA`0%a1GRFUPMrCnNY)YFau|L$5_v<0s3%vrVO(?TX<7jdx7yDvK{_)uO z2Ro?~O&g?dX`0{NT&7Q2WAW?Bt2Zi%ekYqFrM{|@(n)i3K<}hZlyf7N&&rO>hDo|$GAGvKl8N1&d- zo4I3aX3e;hj$rL_X#IZ%%4|7kUHFB7WlRLbn9wNsW7f{p4B%l0I(rTh{s6+> z;rURFB5AdBq`)tIaReLC178CRxEoP;>eDyFaO)k82EP1#RE@2f7@_xz)U)OmdVPhM zM88iIbL6a1h&3s86>)F^FQXY&Im_e1Pl5gJZ^{Sc>9 z{IT53xKO*vzVuu0PX0?&z*48?rN+LVaD6VD*3oh_y1w7Eg7QTz-%zZ%OalJkL9qI* zq1j~mK10?b>Po9v{)FlKRg=X}V2}(brkyQh+IS3g{;PWCHtJ71Bs5q=m5%bG(RKa$ zRyy&>zg`?#^+94r5_F2q`So0bzDcnukx#%`z<-vGcOaZ03-#O_HqH`tjR&iuI~p%M zE)M9I9$t^~pX>pK^iih*lfJ*yV`t`g8Sq8V=hgL&rdH&0eGjL|6n=+0tmXXC-kb>?dyZOdeRz#u3Xp; zzhMwjtnHRRG$wP0uStza?*ZGG8N=%HrD`y2{qDnxI)MuzYSlgV{yrRo?Ojk$+%{!J zArM&n%`*4g#QQr?;{8!_>Pdcu=e6Khj1pCl;h-t6yk^u^m)aqs3y*RzPvY8pE)~_$ z2=riztBZ$6NBQ2t_s@XZF9Bi^9PnQ0C!VdBW%2mhSmu~9&(GMFKKnZC5f6HzGY-h>kV*+=iSsW357*t?k0#EW)0k5tb2Xc^S9 zw6>%dw__E`FZrj(Zo=eQjRol~`<1xlFeF;?^WM$AkaW8LPReks^DKE*ds>GOHHKdt zi4}(YdD~a-pO6hD4D(OL@ImP8OBb~qwjm}UG z(4sKLxe%IqJMHvH0)a=5e7EGK#I?%uBz+BnIcr=t`p`iB&wpF`hCucGrs(e-+(gVD z>rA1?w8(+;1D2|t0Rl9AI>OkM!$#p2;$pqBi8UffILxs~WMsBuFEBo%4aHj^do1Tf z?>&>F(lbcUhr@@tN8A$g9{B zzr(FJKz$p1cY$p`TwdDumJ95PKkK+h_0|kb|6vlzkL%bW-mKZ&BK(})Ie}jD3Xdus z*EWQamdt!DtL!4{nQoDLO>p1l3G5e1ti_Ud!~KY7Xmvl3g4j?dKN=bFiTixv$H%FwSqk6dhS7wvcCX}On)v8a=hJk>afkq4O=lSdQ|~h474XW&`Oc(KQhi! zSbT0VQQye2F9)@IlsWKS*;)%I>sM#Ny%o{~fe;*nNh0YecA zRIp#2`Xaidjr2&yD{9z;j~~KHoR3P}K!xH~IIY-V)7>Ec67td#AEz%lP9_1nS+`b& z8rt9;^A9x5ZF!AweaopD6=N#L##YkfUNe68b>Il5H?ib9?kSv}a z$@N?KDk~MIn&RiI$M;8OV45%xwK!5t(`=U#qZ$4 z$V&YuWOU^a%wm-<9eE$cuqjTiRu%f(mRoyI4sfx;!v9ij$qeF_|jXziCO zukJ7e$E~L9A;|c(=RL(Omq+xgK9}uJ>~O((f)#=O7Ve~>tx(EjTFG z#DhPa(ouCJXFL$o|80e_>6AmHm}JlQjrC&=g=OP=s`Eq4%*5MiX{Q@rAbwW1HhRPfoKQ*v?wJuaU^-y^quXd>WABqVa*Ogwnq zAEz22-|?1|U4cN6#aK;;-;dpwEF6saNlAUt#LFmaA?FwNH|>^)G-P*=A72~>>4++p zgFi7g@T_a;!RmaiGQa$L0~JW+nBH#lO5An5l6`C6x-`~Eoi1R-qtY{c{}HkM_Jr?{ zUkh1ziPq~ZBMiH^Xe_XcLdhYUeEAz)-h6aK-rJHWwf*@(Df?_}z;z_kd{Z|3Y;hkH zQcgu<7A3eUoAkJdQ=}uMd+O-c;E4isrVeci>T4blk<^#G@R-dTOg&jkbrNpC%WVGT zx7@1zO$XI&M?#h!fpQUS3_aj5GqpUu9TzXnPMae3^HPnN>&umQ%27&$K!x0-e_b>a1QiWubyXz&mt2~%7Xhj!n0eU@HMoIvK=|5?f!IJmGtM#wpeqZ!5Xa=>fN$@RbB zhsjEV=yH8d(5fEuVF`t+TW-XQ-y$t--0<+9hZ)P3Jp#6f9Qt0*{NQ0B^|FLDF_egB#fO(kd}!LYwFK(*)t?s4Jg7|CB^LLtt_ z>yKcUUC|o-%cM+SYqzSv=E+#vzl|Of8Tnd9(e*=@`|^qvkOV$l>u_$l729W~V9MJ83RJ_; zwkAD#76;bufra_8yb*>vhdEM_VXM&13+ujX>qi8(F*zJjr0DzTfn6k^LHr6W| z)NVhfJxOG?K?4@eyF;bs@S#MpKog*S&k^=+PcbGdT@k=@+7y~yfizOC5O?deV8Wh@J>T6SCrHquyk||QxBvk9vRtV3kzyF zn$uLg7%WL?K<3Nr^~~2Nn|~^>P4dEz&!&C9yGl zHY31X+|2$c8dNXWV^qrE##PSv{OkzJ%ITjbxI`rzX!hqG_`T~h4p){(qG7<;3^+59~5|A?#K(>NsKZf#mKTBid$)N8PtczP8~gcB?;Q8V9%%Zx zmU%<<1~u`2g-E&mCYqC*lPT`<5i@PnmZg`3M$`PabMw0nzr(SvJsIr? z+X#7n?@UPNF3kVK6VljUk)@}ngZm+RanUw1@&@c}ibMp~Ir&4MG9+35M=uektP8q{ z_jeFp@oYH$ERgX<%+l~0DF)pS$?o0*9~`*vwl*Mb-}yJPD+d3&jCGn4pjpYWVn)rH zARatex2F+~8gk($%vK-XDn|R4S$&|h!Ka~=-+1*UyX+lih%TqBEHWEzRBIJ9o$*neDG<2#MlZ46OYdIk z77KK9_~y6w@~cL9CPaQCW7hZp!p)a9hQK5-M13%~a-rq-f5!WPl(Ohv)tpb!hd)YG zBkEoN%Y4$0Z$FugoKo`ip@pt^Slo>8B*Gti@M{oKH;iP=@rwrO+Y=l)m3HW)BMPXt zCcTz}%@dEYQk2W)q;)r$sl{pWPQPoVTKzWGET#Q=Mx9pBd$k6}cSRNX7$I*{gulh((`K!xzN+ulf zB`pK4P1Ky*RdCG{R7) z9-VhkW$EX&t?)s^{1P@hM9=qj)`loMc1nmC^oNq=AFsC}+(^CJTkw4pkSqG1m&o8@ zo>_9q@XEkj@Y<4>zt)c%nv(jUsgFWExuIqdeB5s5(A3-fh+m$g;0;b#BZpPb?cx|B z=h|9;Y)GBC8<9n*w^akPT$k;%eEgXsWNH(=f69Sb_Phz2Hmu=bNFhtj28DxnUarVO zp{J8eT#wMjOXKAH{$UVk1N(M+!rE^jhK&lG-^plX%gT-VzB6~`hq;V@dD_uIk}%hEEzmxqeOe_m+*D9{|Hn47g=5mSW#IrvPxzeL3r+)8j8kN#(aTz znpP1uw^^MqA|!?PbYK(5w9O z?@`E(ziub=>XpMv2XQ|91SZxuGhwX-W2SQ?a2X?7=2tRodaPQV^brKof$qa4GBJCK zf8@L>isJ~1)WK7a;li_?5Y;Dj+;Did{(PI>pcnKNnTG)?fyDO4zi?uu4Y;+P#Shw$ zXg#FmIT{iXc4TD>dlhJ9V&ghSWzA6>7~+4SYQNwJwB+`2O+#I7;j1dg!ddV5RYhh$ z8_nsKR5ogt2VCnZk_fp3dAi`;2v>k&5Z-YN#(>iv`I z#s?eI%Z2P5NcSb`4;H4ClGV4022Ecwp zXXZonX|#v58T4SwH10-PS8I}T)=8u(`Coa_&rv-Ch<>1 zx*J*{L_A+*3p>1UbIQP4>VO-oEL__v&?;D$;xVbt(H8ZZhvLNs5x@| zzJ9b)iCr{m+Oqj&M|+1T>;`(ie4SaV74Tb68@ksYd-R+8$(?wnleC*#2Yqv7d3U;? z63ikG(s%Fv`S^MSmFKS_3rEe*@o+ykoAO{EE5#8SPIwWXhYsOv--N|X%e$`7%>riZ z=#uN2Mk+Gs!Qh$W55F>GXh6tNiPas`(flj`m|vEUAhU zP;$zkX~U4cxs-H&ZDdzPOd2BA;Lf1a7Z%0xpWJSFIT(`52qwvS_>Z;HE)(XBW8GSJ zhHzrk0uwNM1V4^Bry%i}N0_;qU7V7#9;YR=F-7J+PeS$xv*Z^x2zNN5F>>^r)_XiK zWoLwdS4ea&K>PaJFfrS+v;(uydiSm)_*K1DpYoAc|EY7&T>n$&j?4FoR9Zh-`*0x@ zmGiVt&DC93mC&x6iz7Ng5A=(@ApPU7!-ugNyeKLD3b8Lw(!5T>$uku1a0BuNCh4ix zlFDk1@K-A<$<9>W6|w4iiBoMT^cqGiC=z*C1;Ff#u;&!m`wjN=`b#WT+`GQ*ip0CujFb`yl_yO-Xlr^-q%gSvJ=J;q z@CQW=j&ED-R7QhRY$456M(@El}k2Z-Z^Fe`iQ<+#UpsfWHc7 zYp~M_4uV~LC<(!*1H^Oy1JsZIL&LSPL7^;clKTOO{S+K8xf?x;C<{ zu-X6LIqA5yzcclC4_61FK00;WSf&4#()%6%k|df_Bhx`0=ZU5+Ud=e zJ)`Q`9GmNPwNM@D?v)SGgu&ryQqp83hfGuFvL|OjOU35?Dg?Qz_3=5nh%6&dBB}lxo&`YkV0|ho zDhfQSB9*5rNi{Wqc!sFiYy)+%J2b{{(FlijG}5uzc{0#J@$VAMKIewWr)RyD5TRQD zTXCVo7(jMG9469eScx;PIp>{mK-gE>0B{9sL1U85j)(L~r%G z3k@@AP^~dYN%+5L0>Wf|1x+D>P~&LJF#gPbUX1+kwimMt?>S%8Yz%{60cr-9FTFa#W@7U;_CB4crZDS2UQpMf)Iw`LSl=|O+8A36Jxq?qG zGrUB<)}$-)G@A#svs$g8s9_b_X_9}$53$3r-kO;)(_@iz;-mr7nY|QVf3{kD_gF}U zyhh*n-O1e6xZ4v_&LA4KPGO<-%>)2x!>5rId?(;&LgutRI1Y5W*ogrSU=QFz0Mt-Q z5G!iFg{A-DX#(Xl;cOYzp`kNK`gfDh4#Rt5!M7e3kRk7vxKsAVy`gPk<3eX|5+(?h zdEQXlaQ`6euYWzws@Z#<&Y3Yklz z`5#_vtM4P)=JwF^ztyLfOPL%)mcjh)RD1yp#CF^VBVxP*UOS$K#_WJseccGZ7`FODv4H=IapxqBj>5GUhhkwVd@8RTpJT3{QCakzx-~{t^Kq<0tM*dlx(1adgukD=x!^T>7_?y|Cl{Wa_)i;Xo;;3dOOGNnSXm=tF3& z=w2jycvlx_b<~2Kw80W49u=CsZE@Pq@>JR0`k&3gpPv6-`jpk_m{0zFy%!6OVaF$8 zGYBT{F&%V(gXZz*Sy@@hpH!OnSQX;^u82PgTH;c8?Q9ox8gG}GUZ%NsI>9J~iEd?N zulnJ@T}GVgr(6(?-Vh`PUe^)}^iA9uq+XUkVC=b@Vt9Hkd{+$q-c=p)ZYjhTmZX@D zAw(tp%zo$zRFEh;RTqZoi}W80hz_EogJ6H8BpdU!C+V&Tv$Oz6Wz z*{@J)20%8UTdqYw^2j|dAMv!ln1MlT44?AF(~6$6qI>J!J^vjuc!0Dp&S-&)n};Vg zz;yZ`cxGWy8BU5ht~KzT?}e6KkI(p)G#Z_S7J;_YC@rP$7VWlNU%i!*HI2-n8jHTk z(qXq8)!_bn7;xLtFy5YN9Ki`IVh<(a4KcU7OL%Z zM=%OoJNygA0giYhlp(oj8k-+eC3(Y-lRR2Jr$tyVv2GG3f!FN-$I3doj}tILm66l? zMDR>;`*D|eoF$cNUFMcdUZfa2gH-s9;?W#SMpItAid8Md!3RT%lURyBsOXZ$qA7vkycL$Vxt)I$%L-qp9n-9dq>q zNOwx8na^YW`?6fbTWy`d5$A0O1UAahPU_)o>cK0;SWpk@S?n#(qH7DZm(En)U!jlV zH}L!@>;>~k)D(U*>!$}+HkVVBk6fH)FZn@x1sYfUR?Q^V*+O-oP?7Ixlm1CCTTA;@ zVzf5lw~uZf=jQ`oUE*Q1&D)=Su_#gr;#X*iZyUcu(h*msM5l+}lL&wNT`c=+b~bq) z{e~7FmtaJ$loA3rHr%ei@q&z|Cw7z_{5wF)luP5jowu@@xwBFyIxg>%eD;%2C3)`e zVr{Z0Vs>l*nb_iPuyePf14tuxtQ*Ix_wgyq8+hb804UB?5 zxy6kKtHn*M>gLragZ^94hc;>-nNjkADQXTTyXzg%S_3(pm%p$~BxQY3nJEKBbU%Lm z{iyWBE**A!F8p~^i!%onnnurTGstWOf;p-O`84T;^``;G>uOf)_oMA()>A8zCwQ&0 zM{nfV#1n__qy9J3wal|wal{g&Sa0M^t`B~bK3C@h8>f(85gwiPpd)IF-=)rsnQWFw zIh|*F)S!fMgQO|y6`dl*!TUg3OFcyggsX?!B}Chio)xe1#9?;-A1KWWh%n7Ct^)Lq z4$(-u^>Cv`*0yP*2$66c<_Y2X-Q1^3fuf6-vKueILtau}#+_JGyG~ZZY54dN z@!=|&@+JvGeKWV1H_c%?gCLo3@N3%jB*saRn=*mZGM?W!Di(`Hv4xfd#cHFrAA!|f zMB_uvfZ-m{Xi}kl52w|dlZrrYsk-->gw1amUys6#{C7yTvCG2Y_g~e_R$00Q-Rk#L z2yvUpNQu&2pQUL`0?#wgm~&d9c{v~X~;b|)Y0%AG@6b}QLS`dl%u)1so1DC z1%KY8AcmcD+9Jcy)O=4kVk;AScb9UI&S$e_Z!^nwA2F!yQHDT@(WqAPHkM+9PNfDL zOuoJ}N0I+t|EfPww{gnFY2J~L3UO0XtbX)JkA%4g?`>5plFgG{Mw@sLyBuWs#1D!1 zNRcO^8>QZyiUf$v*=|!OpxfKCX6CNabu1`yR)|!E$nXA@>B)>6>J3eE+#(1IVQPf?u=BZRVBK;fJSs zKjXoVq%boAmFa*S75P?w%%>9_OYb~*a>V>ROH+XcTk#H`b6g4P-r+1O21nOg!p61M zEPSRm65xb>i6rb)+ZNCsq4ld^`c5q1r=BM&8(c4mTo0D?ahNJN77XqK-D$~n9^@n_JPgKCeQK?je)ziyq6A$+V z9FCN9FU=GbTiuxTDCiY-KLqBEhi_2UTd+MH7jN+=@{z6PD0tb_c|q60*sWrk+)e)8 zkwx_JrE-vsFt{o1tOR{?OiadCll+$Dhlvd-{FOqFq~eP0hs8=jNFQ~luQM+|?vXM9 zuhU{mpAj6*SAls`-2N}{wRKFp`{5_1%31}Z&jN$ z!Xs7@HJ!*>>UiPbKhof^WBDKR+Od(R6CapDnw4fv9Gb0rDai<|n$oJang}+!Tg7h@ zI8@xZ43`i&3+_&$%>4)m`O+Qq$ix${Y2bdi=RFfYJ zFl|**k~Yic-JI=ble)zgdKgWvSU=RHLgg_epQ@)}l)rv#Nx~wXSAb3-pw8c2R z6}tGQ?{5**+=Sv<^B>x0q+7??r|}Eds2TN8eZutfXC$lwutBp+;Jb0g`u(;66is$= z7d7sJ<98iAb-^f|6DdZ2)xENK!g-};$r)xuiu&B=nRj|?u06Rd5r-$H^BftU_$&p7 zlbLNxs}f|}NjFU6u)Ttx>$uZVZN{lNshl1)S2bBUMT^jk#o@#t*^Ktykq=9@Mu>juihKO>opVY$A zy>{`#563(LhpiY4?^9{T;&_yU&iWs%aCc^4q?IC?EI#AjE-W~k;CHVtRAMt2lra)= zlR68xe=$-2yij(zcXvGNj`6vVhDSQlx6Hw)#mpGB(CbYm$)2y+G+bq49D)NfzSj^Z z2VGg*L7>ns=p4KPiN|lF7hK1qvRrotAOD1)2NQ(ZK`UrUJ05AHO6qK)WkmpKfe?cZ z9;q0s6!~@z_hy~mw-eOBV(7ZG`?S+n;Zhi(lAml8^09wJh|aYCepJ&!OEfTGI?2c>9Opq@Z#AfSH zGS_fi5r2;{^Z{2mSY3CdueBJRI>z9%_O=*S z4xe1y(uz_{_;#Qgf-AV@ztl=?5Dk{cSP1+Hs6A5=-OY>SiU&py?_@xz7MozxG^MSX z%Hbm3c!!X?!d`Lf4+!=rpRD4iALgy;(PnJ`=0H@)9?9t5W(H~K_8mYHQDMQGNbx83 zMgf{{2=j%;;JhE`jZb0DUtv?~U~xZ3;&G%)Q>t~w6(E!OKw68W#y0rnjmVYh1hy0N zx3Qqz{LKdCk>5eWawaRg zgDJxzT!p)0D_&HurwJRxS~Uuc?(-{q6OVeOu*F*_a4Ss5x!#;^GS}ALY|5mi{mWuKkzDHYI1s@ANp?w>I-wWpqW6a#$Z@>|Kok>E$VK#j zO>GlTlSDnt2e8yOahuR!Y^?slKwJKq*Rc>;G3@<=k;ZnZzl;*>tA}|uwgfe6yqnts zg?2D-STQ=Bg-XyLk!q{xi{}0)m=1Q`m_FZuoni!)5YkZ{5(*Tk5i4|g$fH(LS{+xz z^L#jF+&Q+YI|(L6mEHB;e_H?u-9KKY{h(Z8ZIefZxcaLwrUn0=kBt66zHkCT;1*Gs>CWADMy;Fkj<5{xzBi(q_LCg3#r zG*><+{~Us@EfpMC9t8*ejE4&Mz@g8NPuE=C^~v9SmhyFi#^f9-C^!9_KM+^obQIG> z?Z4QZ42*NV53V;UA6kP6ZgWJ5>z~Ov%n>h;MHm?-qrR7Ob7kjseY!E7jKjbOU@?H$ zG-^GV`scb+XwrhqVx{IIP-q5e0Wak8Lj2iSQba03HCev}r=5sAp9zO3>uA%(T_<^B z1QN$qKP?DI+Bmj$gRgKnBAzwxmMXD15;5vC7Xeo+wYerkUk{J7jVAFV^5Dj^tc48@ z`oFzpWpGS_X6c*>MfL#eyQ^158OXT~^VM9I-V#2IOFs)b*WGWGfYJE=WIhRNd|m%* zIh68k=K0I=Db+K3`e^qK^w`XHuvYzX6f)js<%dt<&u=N#wApAk&`f$u;H159u&|IR zVV#Zs)eXFt^PZc8LqP5bk-Dw8bNuZNBt@=Y@f4QC-~J<+f;(>m3Q|OmB$5>vnViZt zQMPy!Of^0?X8pBA1yPSeM%0(f7O$OBgMi5OWbZa!vl5WdM}1uD^sX}6A=INlbaZkG zk-rIyutcn;`q5t}NED0cKc(1WG=K#-V5p8VwE9ZxQ3F%nPIYImz-sN##v zs@*V@w*H1H7B)aGFpdA-TTe{bbhD^*|92_L#m<&>asum3r_duh4o-9fMEi`;i1F>% zP*`};Kl;MP#F3J!B&CI#p?x#3uIlhWbn3fvWo9z01S718be?e)*shs6Tq!=APwb0SQDo1aeQ-jtY=KF{Ch&VfKvNb}97o|^k<}LJg9JOaeR-Pm93CE3lxG?I1Gsh5 zu>=Ana8N3O^X;mypx;$mDuN8m!JU1gkFW0=Q4V-ohUA?3tAZ)-$lbmLl_cA0v|@T* zZtqfq2Js3L*?IN=s@j78IvbF|R;9?hyJvty7T#!Lv-Q@~NT^EZbsuHCEf}ztT>f6* z5DPmcr2=#Gwu_;utd>x*+aMt*+kch7>QCsC)%F3okfBsoG^gKxc`nlT#lS_bjOvg+ zU{b>)f(q96zD^gL3&O-l1p`M3K_Xczoi=y8zrfK0_?uVhMwzlHOo4yutP`S6~ibOSf0gk+e`~KbaELgj2Fs= zJwULm$^R7!xSOkkDICpOvkmG5ldGL+8sH$}`0@oUV|8B$XE;^te6!CZBCav$v+r;Gp#XZ9$;M$vk_;b|jF!P|NQQWO%UCfxvn81z35T@is65LQx=Vh!1_@P?Q&HW`WvD=%%ZYz%~cL zwo^t2bM^iyujf~?w{s$~sKt`g%y8)UPMi2(Sf5qh!ucuU6$v+%xm`zp%4>Gdy8Yhf z+0Y2rhe1h~!#UVQnwTwWP#2(npweOdelOw$8J=uHIh(x8&@ zhtD-oQ(@@Ah8lDYALCz*5!SJ^P$iCHS&E zlm+*sy%}yV&uF+TCAC-)eOenosACoYyAd_F+Y_PQek+d%HlTDB@AUKah$wPL%e~wB z?s>>&^c!>}vFa1xD8f7tLcr*F(d`QpLV!`s zj=XgDIpWvb=Q3s0#0_^J)B(HqOg0?S49HDT6c)U_w)H4WEN{mFM7I-B!0lyBj!KA~ zP=U|yhA`BRmy8qFraO6w^^9ROV1a7c zav?>m@n6{&>bBzeB&IT$;m-uw2%!wU92LLF8k47hHF2%*Dqi592cEvYk_aMa$E3*1 zvzU+P^qjmN?*K1JfdtaDtm9DlxY_~`R;gxPPi9CJGI=(rjbej>daAEt{n-pgZJwGB zsr116XZ$*7VhmgiHHt*&KYMBeEXr4F$b2Qov3u-QT$t8^eM*UV?KT0);Wly18mlpW zLI0PaRB0teV3)te-vb_t(51%H3rs^`Y9;0kjKZv@{gMm6o(j%nbLsXu681q1+<*%a zCorfB428#a(p)gjPX+7GbvN4_v#?`h8KDAFE8y1=_5T4LEKREkQRU4Jh;Y|{@g#?n zWluc{OA-NJ*UNEZ`6o~6j(f|GfKE*CFE(fjV};zT0=oLD$&qeW@2J-Iy4YgpqY|0t zSFp@DkIloWjFF+J2f!;3@*n1gSRg;Q#@GM9x^_s}{1c73(fY5Kw*H5He_o8WC=ygW zJUqQbOnDDqE6!cLiI_?+b#a;(?g?xs(#X^mP)>!b!IL-idzju=3W~rQ17mqB?f)*$ zmKNH)1a6k!hmO-@$Ds2{ba(B$zV~FRmd%&9gsTP`>%UVgUf3TiUd3Ng$X31W<1fuy5 ziRs~+lhwd?_m}6GGWtb>id1AK@VJJ<9R}oXNb(qbO%_l*f1L~K+^Ot{Tak404=kqg z<}&4`6NKZ4psUWqEEi}hW7x4eyRP(#F*-KjqZV;YnsZf(=839a_hC`+1&Ewe><5me zMCo~gmI)VlPw|-nd5M6_`COv|9UjjoimY}QIh5)DIphJ&bl@ta!)|QpOlYtkoQ&U& zU16&d-72g$8G3=fP%-j*rlQrjC1v}BD4IyhH&;8opfW*Vcm*R368*wc(JmNn@Wq@&r zZr6v(q#fg;$750;u|%bQj~mwP;%M02S1*NleGUpQhd}sUsB%OG0;x`u1EQhf3~ky1 z?;;gc=jU>RnY8o4TvoE>l@$-vApnGHYva67I^gp-L;tB#YLoo&vuZjr<>|=SoumJU zljG)qqn?3$cRg;Z5`(N|KXkP0HgZ(2Z{D#v2&v}bisqrYt?*f5x5j_$UpKp_Kfnw~ zuj`g`5aONJJv8=BR!KW1-DK@(J6_LW!GI6ZO$(n{6Oj)G2q5ef6p~>}x1@%*fz#cm z){-})!isd;KCDharqbIlUg!oP1ac|1-sI&GlNdYj zY=3`Tf6jjFMCx8P)n>n2@?2g;03~er|eo4f&c3>8f!6DjOSOX zR-})}y8{BYOPIV#_VajavG{|mzEjoVm?iUg=L7olhU3}1T+U;m) zN_Q&PD`6Ato;PIp*ISsxe4b(`X&X~FD?#b#xD~;aD4Qmi0=Kz1J-5p{OY3Clqqowz zR`Wk206n`4U^@aHT^o{E4YbGyh5zz{#qwN#&|JCZTecL>K<~gmD`*_supQe?=VPU-uZvr`O`% zhB)MqT5=JJOH31F_GVmc!EAr0ri;if1d^DYk>tS0T259B8uM}DL3ykO?KC~Z%Mhp^ zvkkYIaw}8*8#&6VKAcRfF}~Ai*YGh?u~5)cX7vQVoj)JVGK#hh(7O-gmDSlimUTw8 z+F<8T+cDvLEG&}yzZh*~f*o-Czvy}e$bk6BC_}E~KpJ1Za1KJ&st~8mM>hc=9d|TZ zQh-oMY7l->Fhi{Ya5>>B*T*B^@VF%Geu3$sP9hCL6kgckzFO3)w*NbO6L>JZ6B{x=DWI@i^UB&T1~5>UMAv@RBE(8o{u2Q7#bvRKB=VUs*2#2wsGNv?|193vu^XOt^%WW zix0IPJS>1;puj=} z?ui|`U7xG&Sy|`|q9RqRy_;VKPv%)jZZoOFK4v z{Z=fO3Pi8afcbolCM$TjnC#%r7oq6?$kAaXs7?`_2Hw@PxjS*roN<6CFC{Xkp3jwq z><2@t_SGwJ`%#VqHj=aRBY8U1d482T2#x0cM&WLkpQNkF>sf#zYd#*>t92Pn!n5^u z@B1bbttjJ!=G>_tb+0axl}By2I8|Z~KZ-vMr7X!K+A}(Io8Jc#Kt5#+L4O^X6WbSX z!kx1h_z>#jJzZ)HA4MdP0HjUC#42&J^dB%DCBKhDY!)w6E#}HGd^k!@+Tt5})l%|M zyhvb@wZ^QElskMp&jsaU!oED^bIPI@vr|f}LQ#!d@Y~`45z&p#vCb7^g%OWEAgOBb z#in_`0^V;3W@EjzbV>6fB{!o-a*0w8<;?IGKsnBN4$QI60nskcm6_3&+u{Wxin);= zWG`Lh-i8trAmd6M_7^M8eZ(KQ$?m^VenEIv32+;Y=)xlU<@pHrrG%56J(JytCq0!yfM7*96REYHjOH4pMe=}PZ?{RTO50tC?NwTnn zGjx%~ol(EkLHk3gD{?5JOeoaIVjsrWq9k9G?$?P)kzNBF(js|&EpP0^C7)h=4gF82 z4I)}iSR5Y-L11tME%JjmZtpNE#5LXS`6xjry8Ra)87KW$Kf;(mg8p(o7$}8d(rupS zb1?_Xd*Gq?JK;UX=;N@=JM5;@ENXEsO63M)o;ju#n&dO#^A=I=KJnq>j9`bV$l7=Q zT>(reFt8F^IPK6Ae(z_;6t%3WzXU?GUpJ|Z6adQ_b6EQW! z_fsq~(Mvat^2etJ2fmjy0i@1G=iYpXxg%{CoS4wK-Eu@Hj%t-fmqWQW8;S_FcXZ## zm#ralE}jEDk?t7o!zuSCx1;FcZ+dH}zvije&@%b6K03gXj`15Rt1`xC^<|@V(+{2G;Oci>4YzUFMgrq%M z2e&VP<3+dws;nl%+tB72m<&TP!~%g*v807kjpP3V>rl-C1(-shX#PUWA%0A5GtEsj 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/quantizer_groups.png b/releases/2.0.0/_images/quantizer_groups.png new file mode 100644 index 0000000000000000000000000000000000000000..404aa84544528167afb95be5b68dda87c11e5477 GIT binary patch literal 27568 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/quantsim2.0.png b/releases/2.0.0/_images/quantsim2.0.png new file mode 100644 index 0000000000000000000000000000000000000000..bafa27bbce6017a7fafdd175cd052941149e50a2 GIT binary patch literal 108216 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/stages.png b/releases/2.0.0/_images/stages.png new file mode 100644 index 0000000000000000000000000000000000000000..c41a5723c2e8dbe22650e7e5599bc65b1a2b07a1 GIT binary patch literal 13789 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 z zU`f|J1oAV9Vo+~VGGOAs#XvfGygT9c_Dx3Hg!_`|iqoc9@F{flncE@s%|b$D@*p=P zCd6;SmMYVI;W?t??tSxEO@_LKt}v3_dEvvBT#%)gi%+; zyZtCQLcbD3uGJi9+WOjMOqM!oz`eDrUT7vd?i?nJ4Luq2#$h8fI}>`t1_nl_m@qG7 z4U%_&uQFlV%BdA&4`;f!8>i~EpsnlmYXYa6ZFfN*yFb0V0A-Jc3@S^i1Ma5dGM6QZ z@~eBLt%fmqt|3$kdMe%>fsXMc_q#_Qvc5zRw2W>ALcIK4;ivV1$OIG?pK7+mP#vaB9rcOChXqFoz)b zbS#u6HHAJt=dGF4(w8zpd9LKIo@r~dP12F~M3}nwGh5zDD??{p(&`_NI5tk^y=B2% zHx1Eaqf%9tA$lZz8P^S_u0G7#6LDF_A0Bi?dR?R3{Zs7sI`_teYF_H74NYp?g?#qa zTgP#yW@1Y|_4Q9QcVM&&=AmWMPtrW;;|}AKS;0#mAf%q_iyRXk9z>nG^he^El=9&t zPXYT81grj?xT>&EqxU!20cGcf+|$gl%0++g!(u~Og{E)WMg&ak+g7u`0_v1r(cly`Tz$1vgE*-^-9$0dHNse9$1)^|WCKF#3oLlX~zRfO{cHIC# zFNEW7;STKE1rjxOR0WAyPyjl*|IK{%`IXtJXz*Ch!J=zYw1tD(I29Z+t-K8i0 zaI@(Re&n>RRQ@Toa&U#PLiHxgo93ME99+|&hzwDHp0aRuJONlnUyfCEp}2XHr~TDl zzBJiV0&;bZ+%rwmxbstR`K~D;u*Q9I>$8hq4fy zm*k2TYGmE@sMq^8S!WOpNu8N~!6rA>bm-a z2>pO(kCk=NT~`S2j|Sf{hd0y}f%IOxgoxG-d9;4pceMUE_g(mhEC0-rQL9Zd)?D2B zPQqsED5i3)Rfm~Q|EAPTT)glq;8E&-c!Lf+#SoYpK*=cmZmsE`blzp=DVDu`-pN?* z?cY@)GlI8XIy2O;_Y9}z738fBW2d@|>j?bkfBT3*DhQw$B8Vpl-ux4%ZjjJe9TMnM z?LSUue+D4evb8Vy#jr7;RMT8tP)EJX%4di^ZOY=!?DeOe_vIeLS16UUDFr(36GU#d zN^I%`X

    z`bZ&!07+k4YXT=72&n4<)y8=J=g9#8;Nc}M{kM}3`t(GU3?*XB{cM+k zY~O77e*hH8>E)CIX&lH_mL||4zeFk1d-JVP>zIRzVcc4Y^Kr|wab5uv|9+Xzc3DMJ z33cZS6gA%6R-tw1xc$af=2E?xX=P~{<`U`L!}0bR^5Ntu!;%TrgVz~6LTPT}fyuu9 zx)2PKI4_Llsi@wC7!z7R++9*1BK7fQcobnp+xz9S#&-}7E~sXeUNS3|T@EfTSj-oe zft~Z+<mdw;25GIn_1lLBIvLm1E?c8D&N) zd#M^Gf`HNK8|{C(l!n~1!y*BfT6`2xw)Al7b%ls#@AoJIlpG^VnHzSq*{Ld zLa?NzvjGetyKymds=ddCr&3h1t5y?31iv^T;D@ii-R^|b z$8s839QK0F0ot!G_UxCgh=_LEM%pw}qy@Ch+)9fkK{PP7iy6t3C|Pz7LOejhp6@&< zo$=~go5i7u?#XoHh1ty{vAqF%1m8JLP;h6dIizb*zMUEIdCgios<_YaddkuG7?ip!iJ&jE{By$>Tp*PAD&IwaSg&gqM+OMK zI0Yp4{#PZ9-x9C=i`+}edQIwJA*thf6@*(=#*xH{qq;c6_8^N_Xh7h2uZVCEpf6iE zaYVZHRa*BMQMTM=Ya&^7T$<--*Ga*?Vk{t#=i563Oa4(&LCU>1U~9UZf{1m;?3(C1 z>n-3&`17qbhaPvk{M1#ky^3`F4=r>|>eE&i8T^f)4!H}T^0;-yjKdepvZa1MMu_~? zW6Pe@O|jyRsU3_;GbeLgSzk^!LG9kCl+Ooe!@1f1hbJ(W;$TGsQ-?`aFgIVnme4qS z)(sz>&uGzE@;@YW^f!cz5^+5!_s`j{TFA98$V;iYe&;Z??F{Q$V@fAj<6d=#?k87U zso_PgNLf|LbC_ew8O337No>UxE*03%S4!!2QMD04119HydjSMh zHiyK;#gcGw`+4*7OxGj!OXB;#C5pO;hW_)c7lCmJ%KiC#96*xlmtzNTyZ8zKq{O4} zb7X1MK{}UO*PF2o5Pm|>pp$JIwGjQ+|1!(~043K2!S}!82nf^r@9)1f{Qnz%Xq~W literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/vis_4.png b/releases/2.0.0/_images/vis_4.png new file mode 100644 index 0000000000000000000000000000000000000000..e6551c7cc2eebfeb085ca3253724a2135cb9c2f5 GIT binary patch literal 144633 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%0AS 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 ATmS$7 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/vis_7.png b/releases/2.0.0/_images/vis_7.png new file mode 100644 index 0000000000000000000000000000000000000000..bfc338648d15a54ce628771070ade6a454c14ccc GIT binary patch literal 50987 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/weight_svd.png b/releases/2.0.0/_images/weight_svd.png new file mode 100644 index 0000000000000000000000000000000000000000..1c2b548d5e8ca38bf368313945d0227b451966e6 GIT binary patch literal 58733 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 literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/winnow_1.png b/releases/2.0.0/_images/winnow_1.png new file mode 100644 index 0000000000000000000000000000000000000000..ccbb3bfe3b044d16715603a5f51e2184c1a0ba3f GIT binary patch literal 26858 zcmdqJc{J4j|2I5sT0}{yNRm)W%DxPWN+=Uqick?DOALmwlq?}jgpfg&$=I^*L}Xtw z*^PZ0`@S#tbLjJ3&V66!{H}AZbNz95>cq_Z{aT;f>-l&*U+xbSWM~dC9zq}xG_rSZ zDIpNMz2M*4f!*-Q$@GiA5QuXK*;_Z2F<-_D9A7f4;YMt>+Kn-XLnYIueApeiH|lRh zEcwJz(Y-6Cmp-e-SabL@$K%9rUR^AV-^0?)n6Auy7<$`T!=6^B%dGBXm0zhBpl|f+ zY6df1x%YS=@$A9m^D+}g)>p(sJ7&~V)I9nE`|eG!40q)&%>9YWRmmFdnp-h@scwl1 z6ICe`3CB9v$3NeLK-_p7cU*H9jPdB$5V!c%U`S4`1076XA=&eg7xFD7Toa z^WQRGx%oQ-+GZ{$@|twn%>L@|%v-GQ%GomhZ3%;ck9&n(yD}WDbl0oD#>2QmobVgj zG~CC+3=oKmhmfT6FJFqn;2vDTv}dv%zOT=SKpc{>M#=y4qc+OaZmFQO0Uf&w5pj5A z%%CHa$8Iy@R^yAYds`dbTN|_uZ;CcLinv$vs1WR5tC0m68&^7ZvlFgr=&xq9XvM#w z%AYQwzU|n8h`5D*ix(2iTB1d1s7=*!H!qzL&PvG%GhW$RirGInb+6+->d28J+D>N& zHxxA7hvmEmXMHWmT&Z z^qtSR-+*Rh7fK_x_bXZNWULEbQ@_{XLBu$&uwWH4+;dt#TjSg6INsX01D8`MTC{#m zGv%f%^;Nq~OObzdcGCUF->$}SnZ{TrH>3FM_xO{M%G_1oCkPtBhtY;nyNE*G+;C?Zb|pxyY4>r|(W~*GcEr z&UuUU%Hs_YGO4)AsG(jVdGk@?jbJ}pTa%PRi|Lx>KYnXHUA<&0Wm1!0=1e-(%VDxy zOy6jhfVar#A&~+G!ynmx8u1N#3=id25kDq~?65u2a*brGMbDGQ-HGu_R!8pJFV7fvWKMN%S#51?Zhd;#NKa3n@+>^uadSm3X11SY zD|-)XEUV-N?L8C7i58z1nX^Kj?Wf$0pOqeta19*4Dx7ci(bCfX=toW_6h60mxqPJV zNm>E{|ESyN_;v2Yi%PNv?uPpgeX5`gX8df3?by3eH-#r-OrMX7lUD}a^4wxqsW_}@ zaXGwOH?*WSe#cJLlcXO`zLQ*^HnsVaZ|{9ZL}{0}uN}=ax`EiMJ4LS8rKhHyPmfcu zDk9uT$T{hrG5w)CFSRuByyqnvl>U8pr2R;#KzS)&iyAabw-%k18D7gHIWHpo$=;3U zgF>g-<`->;?5XK}9hogSP=hqO+RPk2cE`u(%P=a3uiM#-{Hl11yY)d6yYCySPE zmzUg^&g?PRl9|CNbR}6^JBs#h5KgDGX(X-UJ>N;n8`e23SA>)Xx#H7ek8i8jQp2CF zUW2R;-D!c=NA9yX5-yf2W?amVLtHw!jU;5i59o$c)_@; zKj?$()sR-AV$j?@Xh<`Cw zz^-CAF=!riw&LUyhO-I!9&7i>2Hm_?)$_DydB^LefiM;P6

    |r(oDKxfurea00XH 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 JreGfQ{{WbI7ApV% literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_images/work_flow_amp.png b/releases/2.0.0/_images/work_flow_amp.png new file mode 100644 index 0000000000000000000000000000000000000000..02e3fc203d4475b9459c0645327226d1d61e2352 GIT binary patch literal 25147 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 + + + + + + + aimet_common.defs - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_common.defs

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2019-2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Common type definitions that are used across aimet """
    +
    +import io
    +from enum import Enum
    +from typing import Union, Callable, Any, Optional, Dict, List
    +from decimal import Decimal
    +
    +from aimet_common.layer_database import Layer
    +import aimet_common.libpymo as libpymo
    +
    +
    +# supported quantization schemes
    +
    +[docs] +class QuantScheme(Enum): + """ Enumeration of Quant schemes""" + + post_training_tf = 1 + """ For a Tensor, the absolute minimum and maximum value of the Tensor are used to compute the Quantization + encodings. """ + post_training_tf_enhanced = 2 + """ For a Tensor, searches and selects the optimal minimum and maximum value that minimizes the Quantization Noise. + The Quantization encodings are calculated using the selected minimum and maximum value. """ + training_range_learning_with_tf_init = 3 + """ For a Tensor, the encoding values are initialized with the post_training_tf scheme. Then, the encodings are + learned during training. """ + training_range_learning_with_tf_enhanced_init = 4 + """ For a Tensor, the encoding values are initialized with the post_training_tf_enhanced scheme. Then, the encodings + are learned during training. """ + training_range_learning = 5 + post_training_percentile = 6 + """ For a Tensor, adjusted minimum and maximum values are selected based on the percentile value passed. + The Quantization encodings are calculated using the adjusted minimum and maximum value."""
    + + +MAP_QUANT_SCHEME_TO_PYMO = {QuantScheme.post_training_tf: libpymo.QuantizationMode.QUANTIZATION_TF, + QuantScheme.post_training_tf_enhanced: + libpymo.QuantizationMode.QUANTIZATION_TF_ENHANCED, + QuantScheme.training_range_learning_with_tf_init: + libpymo.QuantizationMode.QUANTIZATION_TF, + QuantScheme.training_range_learning_with_tf_enhanced_init: + libpymo.QuantizationMode.QUANTIZATION_TF_ENHANCED, + QuantScheme.post_training_percentile: + libpymo.QuantizationMode.QUANTIZATION_PERCENTILE} +MAP_ROUND_MODE_TO_PYMO = {'nearest': libpymo.RoundingMode.ROUND_NEAREST, + 'stochastic': libpymo.RoundingMode.ROUND_STOCHASTIC} + +RANGE_LEARNING_SCHEMES = {QuantScheme.training_range_learning_with_tf_init, + QuantScheme.training_range_learning_with_tf_enhanced_init} + + +class ActivationType(Enum): + """ Enums to identify activation type""" + no_activation = 0 + """ No activation """ + + relu = 1 + """ ReLU activation """ + + relu6 = 2 + """ ReLU6 activation """ + + def __eq__(self, other: "ActivationType"): + return self.value == other.value and self.name == other.name # pylint: disable=comparison-with-callable + + +
    +[docs] +class CostMetric(Enum): + """ Enumeration of metrics to measure cost of a model/layer """ + + mac = 1 + """ MAC: Cost modeled for compute requirements """ + + memory = 2 + """ Memory: Cost modeled for space requirements """
    + + + +
    +[docs] +class CompressionScheme(Enum): + """ Enumeration of compression schemes supported in aimet """ + + weight_svd = 1 + """ Weight SVD """ + + spatial_svd = 2 + """ Spatial SVD """ + + channel_pruning = 3 + """ Channel Pruning """
    + + + +class RankSelectScheme(Enum): + """ Enumeration of rank selection schemes supported in aimet """ + + greedy = 1 + """ Greedy scheme""" + + +class LayerCompRatioPair: + """ + Models a pair of (layer: nn.Module, CompRatio: Decimal) + """ + + def __init__(self, layer: Layer, comp_ratio: Union[Decimal, None]): + """ + Constructor + :param layer: Reference to layer + :param comp_ratio: Comp-ratio as a floating point number between 0 and 1 + """ + self.layer = layer + self.comp_ratio = comp_ratio + + def __str__(self): + return 'LayerCompRatioPair: layer={}, comp-ratio={}'.format(self.layer.name, self.comp_ratio) + + +class LayerCompRatioEvalScore: + """ + Models data element with (layer: nn.Module, CompRatio: Decimal, EvalScore: Decimal) attributes + """ + + def __init__(self, layer: Layer, comp_ratio: Union[Decimal, None], eval_score: Optional[Union[Decimal, None]]): + """ + Constructor + :param layer: Reference to layer + :param comp_ratio: Comp-ratio as a floating point number between 0 and 1 + :param eval_score: Eval score as floating point number + """ + self.layer = layer + self.comp_ratio = comp_ratio + self.eval_score = eval_score + + def __str__(self): + return 'LayerCompRatioEvalScore: layer={}, comp-ratio={}, eval_score={}'. \ + format(self.layer.name, self.comp_ratio, self.eval_score) + + +EvalFunction = Callable[[Any, Optional[int], bool], float] + + +
    +[docs] +class GreedySelectionParameters: + """ + Configuration parameters for the Greedy compression-ratio selection algorithm + + :ivar target_comp_ratio: Target compression ratio. Expressed as value between 0 and 1. + Compression ratio is the ratio of cost of compressed model to cost of the original model. + :ivar num_comp_ratio_candidates: Number of comp-ratio candidates to analyze per-layer + More candidates allows more granular distribution of compression at the cost + of increased run-time during analysis. Default value=10. Value should be greater than 1. + :ivar use_monotonic_fit: If True, eval scores in the eval dictionary are fitted to a monotonically increasing + function. This is useful if you see the eval dict scores for some layers are not monotonically increasing. + By default, this option is set to False. + :ivar saved_eval_scores_dict: Path to the eval_scores dictionary pickle file that was + saved in a previous run. This is useful to speed-up experiments when trying + different target compression-ratios for example. aimet will save eval_scores + dictionary pickle file automatically in a ./data directory relative to the + current path. num_comp_ratio_candidates parameter will be ignored when this option is used. + """ + + def __init__(self, + target_comp_ratio: float, + num_comp_ratio_candidates: int = 10, + use_monotonic_fit: bool = False, + saved_eval_scores_dict: Optional[str] = None): + + self.target_comp_ratio = target_comp_ratio + + # Sanity check + if num_comp_ratio_candidates < 2: + raise ValueError("Error: num_comp_ratio_candidates={}. Need more than 1 candidate for " + "Greedy compression-ratio selection".format(num_comp_ratio_candidates)) + + self.num_comp_ratio_candidates = num_comp_ratio_candidates + self.use_monotonic_fit = use_monotonic_fit + self.saved_eval_scores_dict = saved_eval_scores_dict
    + + + +class GreedyCompressionRatioSelectionStats: + """ Statistics for the greedy compression-ratio selection algorithm """ + + def __init__(self, eval_scores_dict: Dict[str, Dict[Decimal, float]]): + """ + Constructor + :param eval_scores_dict: Dictionary of {layer_name: {compression_ratio: eval_score}} + """ + self.eval_scores_dictionary = eval_scores_dict + + def __str__(self): + stream = io.StringIO(newline='\n') + stream.write('\nGreedy Eval Dict\n') + layer_dict = self.eval_scores_dictionary + for layer in layer_dict: + stream.write(' Layer: {}\n'.format(layer)) + + for ratio in sorted(layer_dict[layer]): + stream.write(' Ratio={}, Eval score={}\n'.format(ratio, layer_dict[layer][ratio])) + + return stream.getvalue() + + +class TarCompressionRatioSelectionStats: + """ Statistics for the TAR compression-ratio selection algorithm """ + + def __init__(self, layers_comp_ratio_eval_score_per_rank_index): + """ + Constructor + :param layers_comp_ratio_eval_score_per_rank_index: List of [layer_name: compression_ratio: eval_score] params + """ + self.layers_comp_ratio_eval_score_per_rank_index = layers_comp_ratio_eval_score_per_rank_index + + def __str__(self): + stream = io.StringIO(newline='\n') + stream.write('\nTar Eval table\n') + for data_to_print in self.layers_comp_ratio_eval_score_per_rank_index: + stream.write(' Layer: {}\n'.format(data_to_print.layer)) + stream.write(' Ratio={}, Eval score={}\n'.format((data_to_print.comp_ratio), + (data_to_print.eval_score))) + + return stream.getvalue() + + +class CompressionStats: + """ Statistics generated during model compression """ + + class LayerStats: + """ Statistics for every layer in the model that was compressed """ + + def __init__(self, name: str, comp_ratio: Decimal): + self.name = name + self.compression_ratio = comp_ratio + + def __init__(self, base_accuracy: float, comp_accuracy: float, + mem_comp_ratio: Decimal, mac_comp_ratio: Decimal, + per_layer_stats: List[LayerStats], + comp_ratio_select_stats: Union[GreedyCompressionRatioSelectionStats, None]): + + self.baseline_model_accuracy = format(base_accuracy, '.6f') + self.compressed_model_accuracy = format(comp_accuracy, '.6f') + self.memory_compression_ratio = format(mem_comp_ratio, '.6f') + self.mac_compression_ratio = format(mac_comp_ratio, '.6f') + self.per_layer_stats = per_layer_stats + self.compression_ratio_selection_stats = comp_ratio_select_stats + + def __str__(self): + + stream = io.StringIO(newline='\n') + stream.write('**********************************************************************************************\n') + stream.write('Compressed Model Statistics\n') + stream.write('Baseline model accuracy: {}, Compressed model accuracy: {}\n' + .format(self.baseline_model_accuracy, + self.compressed_model_accuracy)) + stream.write('Compression ratio for memory={}, mac={}\n'.format(self.memory_compression_ratio, + self.mac_compression_ratio)) + stream.write('\n') + stream.write('**********************************************************************************************\n') + + stream.write('\nPer-layer Stats\n') + for layer in self.per_layer_stats: + stream.write(' Name:{}, compression-ratio: {}\n'.format(layer.name, + layer.compression_ratio)) + stream.write('\n') + stream.write('**********************************************************************************************\n') + + stream.write('{}\n'.format(self.compression_ratio_selection_stats)) + stream.write('**********************************************************************************************\n') + + return stream.getvalue() + + +class AdaroundConstants: + """ Constants used for Adarounding """ + + GAMMA = -0.1 + ZETA = 1.1 + + +class QuantizationDataType(Enum): + """ Enumeration of tensor quantizer data types supported """ + undefined = 0 + int = 1 + float = 2 + +class SupportedKernelsAction(Enum): + """ Enumeration to specify the action to apply during supported_kernels validation""" + allow_error = 1 + warn_on_error = 2 + assert_on_error = 3 + + +class QuantDtypeBwInfo: + """ + QuantDtypeBwInfo holds activation dtype/bw and param dtype/bw + """ + + + def __init__(self, act_dtype: QuantizationDataType, act_bw: int, + param_dtype: QuantizationDataType = QuantizationDataType.undefined, param_bw: int = 0): + """ + Data class to hold dtype and bw info + :param act_dtype: Activation datatype of type QuantizationDataType + :param act_bw: Activation bitwidth of type int + :param param_dtype: Param datatype of type QuantizationDataType + :param param_bw: Param bitwidth of type int + """ + self.act_dtype = act_dtype + self.act_bw = act_bw + self.param_dtype = param_dtype + self.param_bw = param_bw + self._validate_inputs() + + def __repr__(self): + return f'(activation:({self.act_dtype}, {self.act_bw}) param:({self.param_dtype}, {self.param_bw})' + + def __str__(self): + return f'activation:({self.act_dtype}, {self.act_bw}) param:({self.param_dtype}, {self.param_bw})' + + def __eq__(self, other): + return self.act_dtype == other.act_dtype and self.act_bw == other.act_bw and \ + self.param_dtype == other.param_dtype and self.param_bw == other.param_bw + + def _validate_inputs(self): + """ + Validate inputs + """ + if self.param_dtype and self.param_bw: + if self.param_dtype == QuantizationDataType.float and self.param_bw not in [16, 32]: + raise ValueError( + 'float param_dtype can only be used when param_bw is set to 16, not ' + str(self.param_bw)) + + if self.act_dtype == QuantizationDataType.float and self.act_bw not in [16, 32]: + raise ValueError( + 'float act_dtype can only be used when act_bw is set to 16, not ' + str(self.act_bw)) + + def is_same_activation(self, dtype: QuantizationDataType, bw: int): + """ + helper function to check if activation of the object is same as input + :param bw: bitwidth to verify against + :param dtype: dtype to verify against + """ + return bw == self.act_bw and dtype == self.act_dtype + + def is_same_param(self, dtype: QuantizationDataType, bw: int): + """ + helper function to check if param of the object is same as input + :param bw: bitwidth to verify against + :param dtype: dtype to verify against + """ + return bw == self.param_bw and dtype == self.param_dtype + + def get_activation(self) -> tuple: + """ getter method for activation candidate""" + return self.act_dtype, self.act_bw + + def get_param(self) -> tuple: + """ getter method for param candidate""" + return self.param_dtype, self.param_bw + + +
    +[docs] +class CallbackFunc: + """ + Class encapsulating call back function and it's arguments + """ + def __init__(self, func: Callable, func_callback_args=None): + """ + :param func: Callable Function + :param func_callback_args: Arguments passed to the callable function + """ + self.func = func + self.args = func_callback_args
    + + +class EncodingType(Enum): + """ Encoding type """ + PER_TENSOR = 0 + PER_CHANNEL = 1 + PER_BLOCK = 2 + LPBQ = 3 + VECTOR = 4 +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_onnx/adaround/adaround_weight.html b/releases/2.0.0/_modules/aimet_onnx/adaround/adaround_weight.html new file mode 100644 index 0000000..6296020 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_onnx/adaround/adaround_weight.html @@ -0,0 +1,703 @@ + + + + + + + + aimet_onnx.adaround.adaround_weight - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_onnx.adaround.adaround_weight

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +# pylint: skip-file
    +
    +""" Top level API for Adaptive Rounding - Post-Training Quantization (PTQ) """
    +import copy
    +import os
    +import tempfile
    +import json
    +from typing import Tuple, Dict, List, Callable
    +from onnx import onnx_pb
    +from onnxruntime.quantization.onnx_quantizer import ONNXModel
    +from tqdm import tqdm
    +
    +# Import AIMET specific modules
    +from aimet_common import quantsim
    +from aimet_common.utils import AimetLogger
    +from aimet_common.defs import QuantScheme, QuantizationDataType
    +
    +from aimet_onnx.adaround.adaround_loss import AdaroundHyperParameters
    +from aimet_onnx.adaround.adaround_tensor_quantizer import AdaroundTensorQuantizer
    +from aimet_onnx.quantsim import QuantizationSimModel
    +from aimet_onnx.qc_quantize_op import OpMode
    +from aimet_onnx.meta.utils import get_module_act_func_pair, get_ordered_ops
    +from aimet_onnx import utils
    +from aimet_onnx.adaround.adaround_optimizer import AdaroundOptimizer
    +from aimet_onnx.adaround.utils import ModelData, ModuleInfo
    +
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.Quant)
    +
    +# The following modules with weights are supported by Adaround
    +AdaroundSupportedModules = ['Conv', 'ConvTranspose', 'MatMul', 'Gemm']
    +
    +
    +
    +[docs] +class AdaroundParameters: + """ + Configuration parameters for Adaround + """ + def __init__(self, data_loader, num_batches: int, + default_num_iterations: int = None, default_reg_param: float = 0.01, + default_beta_range: Tuple = (20, 2), default_warm_start: float = 0.2, + forward_fn: Callable = None, forward_pass_callback_args = None): + """ + :param data_loader: Data loader + :param num_batches: Number of batches to be used for Adaround. + A commonly recommended value for this parameter is the smaller value among (1) len(data_loader) and (2) ceil(2000/batch_size) + :param default_num_iterations: Number of iterations to adaround each layer. + The default value is 10K for models with 8- or higher bit weights, and 15K for models with lower than 8 bit weights. + :param default_reg_param: Regularization parameter, trading off between rounding loss vs reconstruction loss. + Default 0.01 + :param default_beta_range: Start and stop beta parameter for annealing of rounding loss (start_beta, end_beta). + Default (20, 2) + :param default_warm_start: warm up period, during which rounding loss has zero effect. Default 20% (0.2) + :param forward_fn: Function to compute encodings for sim + :param forward_pass_callback_args: These argument(s) are passed to the forward_pass_callback as-is. Up to + the user to determine the type of this parameter. E.g. could be simply an integer representing the number + of data samples to use. Or could be a tuple of parameters or an object representing something more complex. + If set to None, forward_pass_callback will be invoked with no parameters. + """ + if len(data_loader) < num_batches: + raise ValueError(f'Can not fetch {num_batches} batches from ' + f'a data loader of length {len(data_loader)}.') + + self.data_loader = data_loader + self.num_batches = num_batches + self.num_iterations = default_num_iterations + self.reg_param = default_reg_param + self.beta_range = default_beta_range + self.warm_start = default_warm_start + self.forward_fn = forward_fn + self.forward_pass_callback_args = forward_pass_callback_args
    + + + +class Adaround: + """ + Weight-rounding mechanism for Post Training Quantization (PTQ) + """ + @classmethod + def apply_adaround(cls, model: onnx_pb.ModelProto, params: AdaroundParameters, + path: str, filename_prefix: str, default_param_bw: int = 4, + param_bw_override_list: List[Tuple[str, int]] = None, + ignore_quant_ops_list: List[str] = None, + default_quant_scheme: QuantScheme = QuantScheme.post_training_tf_enhanced, + default_config_file: str = None, use_cuda: bool = True, device: int = 0, + user_onnx_libs: List[str] = None) -> onnx_pb.ModelProto: + """ + Returns model with optimized weight rounding of every module (Conv and Linear) and also saves the + corresponding quantization encodings to a separate JSON-formatted file that can then be imported by + QuantSim for inference or QAT + + :param model: Model to Adaround + :param params: Parameters for Adaround + :param path: path where to store parameter encodings + :param filename_prefix: Prefix to use for filename of the encodings file + :param default_param_bw: Default bitwidth (4-31) to use for quantizing layer parameters + :param param_bw_override_list: List of Tuples. Each Tuple is a param name and the corresponding parameter bitwidth + to be used for that param. + :param ignore_quant_ops_list: Ops listed here are skipped during quantization needed for AdaRounding. Do not + specify Conv and Linear modules in this list. Doing so, will affect accuracy. + :param default_quant_scheme: Quantization scheme. Supported options are using Quant Scheme Enum + QuantScheme.post_training_tf or QuantScheme.post_training_tf_enhanced + :param default_config_file: Default configuration file for model quantizers + :param use_cuda: If we should use cuda + :param device: CUDA device ID + :param user_onnx_libs: List of paths to all compiled ONNX custom ops libraries + :return: Model with Adarounded weights and saves corresponding parameter encodings JSON file at provided path + """ + # pylint: disable=too-many-arguments + # Create Quant sim with given parameters + if not isinstance(model, ONNXModel): + model = ONNXModel(model) + + quant_sim = QuantizationSimModel(copy.deepcopy(model), quant_scheme=default_quant_scheme, + default_param_bw=default_param_bw, + config_file=default_config_file, + user_onnx_libs=user_onnx_libs, + use_cuda=use_cuda) + + # For the params in the param_bw_override_list, override the default parameter bitwidths in the QuantSim + if param_bw_override_list: + cls._override_param_bitwidth(quant_sim, param_bw_override_list) + + if ignore_quant_ops_list: + cls._exclude_modules(quant_sim, ignore_quant_ops_list) + + # Compute only param encodings + cls._compute_param_encodings(quant_sim, params) + + return cls._apply_adaround(quant_sim, model, params, path, filename_prefix, use_cuda, device, user_onnx_libs) + + @classmethod + def _apply_adaround(cls, quant_sim: QuantizationSimModel, model: onnx_pb.ModelProto, params: AdaroundParameters, + path: str, filename_prefix: str, use_cuda: bool = True, device: int = 0, + user_onnx_libs: List[str] = None) -> onnx_pb.ModelProto: + """ + Returns model with optimized weight rounding of every module (Conv and Linear) and also saves the + corresponding quantization encodings to a separate JSON-formatted file that can then be imported by + QuantSim for inference or QAT + + :param quant_sim: QuantizationSimModel object to optimize weight rounding. + The activation quantizers are expected to have been disabled. + :param model: Original fp32 model from which quant_sim was created. + :param params: Parameters for Adaround + :param path: path where to store parameter encodings + :param filename_prefix: Prefix to use for filename of the encodings file + :param use_cuda: If we should use cuda + :param device: CUDA device ID + :param user_onnx_libs: List of paths to all compiled ONNX custom ops libraries + :return: Model with Adarounded weights and saves corresponding parameter encodings JSON file at provided path + """ + + # Sanity check: All the input/output quantizers should be disabled + for quantizer_name in quant_sim.activation_names: + assert not quant_sim.qc_quantize_op_dict[quantizer_name].enabled + + # Get the module - activation function pair using ConnectedGraph + module_act_func_pair = get_module_act_func_pair(model) + + cls._adaround_model(model, quant_sim, module_act_func_pair, params, use_cuda, device, user_onnx_libs) + + # Export quantization encodings to JSON-formatted file + cls._export_encodings_to_json(path, filename_prefix, quant_sim) + + quant_sim.remove_quantization_nodes() + logger.info('Completed Adarounding Model') + return quant_sim.model + + @classmethod + def _adaround_model(cls, model: onnx_pb.ModelProto, quant_sim: QuantizationSimModel, module_act_func_pair: Dict, + params: AdaroundParameters, use_cuda: bool = True, device: int = 0, user_onnx_libs: List[str] = None): + """ + Optimize weight rounding of every module (AdaroundSupportedModules) of model in sequential manner + based on occurrence + + :param model: Original fp32 model from which quant_sim was created. + :param quant_sim: QuantizationSimModel object to optimize weight rounding. + The activation quantizers are expected to have been disabled. + :param module_act_func_pair: Dictionary of module to immediate following activation function + :param params: Adaround parameters + :param use_cuda: If we should use cuda + :param device: CUDA device ID + :param user_onnx_libs: List of paths to all compiled ONNX custom ops libraries + """ + # pylint: disable=too-many-locals, protected-access + + num_iterations = params.num_iterations + + if num_iterations is None: + lowest_weight_bw = 32 + for param_name in quant_sim.param_names: + quantizer = quant_sim.qc_quantize_op_dict[param_name] + if quantizer.enabled and quantizer.data_type == QuantizationDataType.int: + lowest_weight_bw = min(lowest_weight_bw, quantizer.bitwidth) + # If the lowest wegith bitwidth is < 8, then set num_iterations to 15K by default + if lowest_weight_bw < 8: + num_iterations = 15000 + else: + num_iterations = 10000 + + with tempfile.TemporaryDirectory() as tmp_dir: + # Cache model input data to temporary directory + cached_dataset = utils.CachedDataset(params.data_loader, params.num_batches, tmp_dir) + + # Optimization Hyper parameters + opt_params = AdaroundHyperParameters(num_iterations, params.reg_param, params.beta_range, + params.warm_start) + param_to_tensor_quantizer_dict = Adaround._create_param_to_tensor_quantizer_dict(quant_sim) + model_data = ModelData(model.model) + quantized_layer_to_input_tensor_name = Adaround._get_quantized_layer_input_tensor_name(quant_sim) + # AdaRound must be applied to modules in the order of occurrence + modules = get_ordered_ops(model) + for module in tqdm(modules): + name = module.name + if cls._is_supported_layer_type(model_data.module_to_info[name]): + # Get module's next following activation function + act_func = module_act_func_pair[name] + quantized_input_name = quantized_layer_to_input_tensor_name[name] + logger.info("Started Optimizing weight rounding of module: %s", name) + AdaroundOptimizer.adaround_module(model_data.module_to_info[name], quantized_input_name, + model, quant_sim.model, act_func, + cached_dataset, opt_params, param_to_tensor_quantizer_dict, + use_cuda, device, user_onnx_libs) + + @classmethod + def _is_supported_layer_type(cls, module_info: ModuleInfo): + if not module_info.type in AdaroundSupportedModules: + return False + + if not "weight" in module_info.params: + return False + + if module_info.type in ("Conv", "ConvTranspose"): + # Only 2d conv/convtranspose is supported + return len(module_info.params["weight"].shape) == 4 + + return True + + @staticmethod + def _compute_param_encodings(quant_sim: QuantizationSimModel, params: AdaroundParameters): + """ + Compute encodings for parameters, needed for initializing Adaround quantizers + + :param quant_sim: Quant sim + :param params: Adaround params + """ + for op_name, qc_op in quant_sim.qc_quantize_op_dict.items(): + if op_name in quant_sim.activation_names: + qc_op.enabled = False + else: + qc_op.op_mode = OpMode.oneShotQuantizeDequantize + + params.forward_fn(quant_sim.session, params.forward_pass_callback_args) + for op_name, qc_op in quant_sim.qc_quantize_op_dict.items(): + if op_name in quant_sim.param_names: + qc_op.compute_encodings() + qc_op.op_mode = OpMode.quantizeDequantize + + @staticmethod + def _create_param_to_tensor_quantizer_dict(quant_sim: QuantizationSimModel) -> Dict[str, AdaroundTensorQuantizer]: + """ + Create Adaround tensor quantizers for weight tensor + + :param quant_sim: Quant sim + :return: Dict of param name to AdaroundTensorQuantizer + """ + param_to_tq_dict = {} + for param_name in quant_sim.param_names: + quantizer = quant_sim.qc_quantize_op_dict[param_name] + ch_axis = -1 + if quantizer.quant_info.usePerChannelMode: + ch_axis = quantizer.quant_info.channelAxis + adaround_quantizer = AdaroundTensorQuantizer(quantizer.bitwidth, 'Adaptive', quantizer.quant_scheme, + quantizer.use_symmetric_encodings, quantizer.enabled, ch_axis) + + adaround_quantizer.use_strict_symmetric = quantizer.use_strict_symmetric + adaround_quantizer.use_unsigned_symmetric = quantizer.use_unsigned_symmetric + + # Set the encodings and replace by Adaround tensor quantizer + adaround_quantizer.encoding = quantizer.encodings + param_to_tq_dict[param_name] = adaround_quantizer + + return param_to_tq_dict + + @classmethod + def _export_encodings_to_json(cls, path: str, filename_prefix: str, quant_sim: QuantizationSimModel): + """ + Save Adadrounded module's parameter encodings to JSON file + + :param path: path where to store param encodings + :param filename_prefix: filename to store exported weight encodings in JSON format + :param quant_sim: QunatSim that contains the model and Adaround tensor quantizers + """ + # pylint: disable=protected-access + param_encodings = quant_sim._get_encodings(quant_sim.param_names, quantsim.encoding_version) + + # export encodings to JSON file + os.makedirs(os.path.abspath(path), exist_ok=True) + encoding_file_path = os.path.join(path, filename_prefix + '.encodings') + with open(encoding_file_path, 'w') as encoding_fp: + json.dump(param_encodings, encoding_fp, sort_keys=True, indent=4) + + @staticmethod + def _override_param_bitwidth(quant_sim: QuantizationSimModel, + param_bw_override_list: List[Tuple[str, int]]): + """ + For the QuantSim, for the list of modules in the param_bw_override_list, + overrides the default parameter bitwidths with the provided bitwidth. + + :param quant_sim: The QuantSim that was created using a deepcopy of the original model. + :param param_bw_override_list: List of Tuples. Each Tuple is a param name and the corresponding parameter bitwidth + to be used for that param. + """ + # For the params specified in the param_bw_override_list, set the weight quantizer bitwidth + for (param_name, bw) in param_bw_override_list: + quant_sim.qc_quantize_op_dict[param_name] = bw + + @classmethod + def _exclude_modules(cls, quant_sim: QuantizationSimModel, + ignore_quant_ops_list: List[str]): + """ + For the modules mentioned in the ignore_quant_ops_list, remove the corresponding quant wrappers from the + quantSim and excludes modules from adaround optimization. + + :param model: The original model + :param quant_sim: The QuantSim that was created using a deepcopy of the original model. + :param ignore_quant_ops_list: The list of quantizers for which the Quantization wrappers are removed from the + QuantSim object. + """ + + @staticmethod + def _get_quantized_layer_input_tensor_name(sim): + quantized_layer_to_input_tensor_name = {} + for node in sim.model.model.graph.node: + if node.op_type in AdaroundSupportedModules: + quantized_layer_to_input_tensor_name[node.name] = node.input[0] + return quantized_layer_to_input_tensor_name +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_onnx/amp/mixed_precision_algo.html b/releases/2.0.0/_modules/aimet_onnx/amp/mixed_precision_algo.html new file mode 100644 index 0000000..80dad6b --- /dev/null +++ b/releases/2.0.0/_modules/aimet_onnx/amp/mixed_precision_algo.html @@ -0,0 +1,887 @@ + + + + + + + + aimet_onnx.amp.mixed_precision_algo - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_onnx.amp.mixed_precision_algo

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +""" Evaluator class for mixed precision """
    +
    +import contextlib
    +import os
    +from collections import defaultdict, OrderedDict
    +import pickle
    +import functools
    +from typing import Any, Callable, Tuple, List, Dict
    +import json
    +import numpy as np
    +import onnxruntime
    +
    +from aimet_common.utils import AimetLogger, save_json_yaml
    +from aimet_common.defs import CallbackFunc
    +from aimet_common.amp.mixed_precision_algo import GreedyMixedPrecisionAlgo as MixedPrecisionAlgo
    +from aimet_common.amp.quantizer_groups import reformat_supported_kernels
    +from aimet_common.amp.utils import (
    +    sort_accuracy_list,
    +    CANDIDATE_WITH_DTYPE,
    +    ACCURACY_LIST,
    +    disable_quantizers,
    +    enable_quantizers,
    +)
    +
    +from aimet_onnx.amp import utils as mixed_precision_utils
    +from aimet_onnx.amp.quantizer_groups import find_quantizer_group, QuantizerGroup, find_supported_candidates
    +from aimet_onnx.quantsim import QuantizationSimModel, load_encodings_to_sim
    +from aimet_onnx.qc_quantize_op import QcQuantizeOp
    +from aimet_onnx.defs import DataLoader
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.MixedPrecision)
    +
    +
    +@contextlib.contextmanager
    +def _disable_all_quantizers(sim: QuantizationSimModel):
    +    """
    +    Temporarily disable all quantizers in the model within with-as block.
    +
    +    :param sim: Quantized sim model
    +    """
    +    active_quantizers = set(quantizer for quantizer in sim.qc_quantize_op_dict.values() if quantizer.enabled)
    +
    +    try:
    +        for quantizer in active_quantizers:
    +            quantizer.enabled = False
    +        yield
    +    finally:
    +        for quantizer in active_quantizers:
    +            quantizer.enabled = True
    +
    +
    +
    +[docs] +class EvalCallbackFactory: + """ + Factory class for various built-in eval callbacks + """ + def __init__(self, + data_loader: DataLoader, + forward_fn: Callable = None): + """ + :param data_loader: Data loader to be used for evaluation + :param forward_fn: Function that runs forward pass and returns the output tensor. + This function is expected to take 1) a model 2) List of starting op names + 3) List of output op names and 4) batch yielded from the data set, and + return a single tf.Tensor (or np.ndarray) object which represents the output of the model. + """ + self._data_loader = data_loader + self._forward_fn = forward_fn or _default_forward_fn + + # storing batchwise fp32 outputs in the list + self._batchwise_fp32_outputs_list = [] + + def _forward_fn_wrapper(self, *args, **kwargs): + output = self._forward_fn(*args, **kwargs) + if not isinstance(output, np.ndarray): + raise RuntimeError( + "Forward pass was expected to return a numpy.ndarray, " + f"but returned an object of type {type(output)}. " + "Try specifying `forward_fn` to adapt the output." + ) + return output + + _DEFAULT_SQNR_NUM_SAMPLES = 128 + +
    +[docs] + def sqnr(self, sim: QuantizationSimModel, num_samples: int = _DEFAULT_SQNR_NUM_SAMPLES) -> CallbackFunc: + """ + Returns SQNR eval callback. + NOTE: sim object is required to enable/disable quantizer_info objects associated with quant ops. + + :param sim: Quantized sim model + :param num_samples: Number of samples used for evaluation + :return: A callback function that evaluates model SQNR between fp32_outputs and quantized outputs. + """ + evaluate_sqnr = functools.partial(_evaluate_sqnr, + sim=sim, + data_loader=self._data_loader, + forward_fn=self._forward_fn_wrapper, + num_samples=num_samples, + batchwise_fp32_outputs_list=self._batchwise_fp32_outputs_list) + return CallbackFunc(evaluate_sqnr)
    +
    + + + +def _default_forward_fn(sess, inputs): + output_tensors = sess.run(None, {'input': inputs})[0] + return output_tensors + + +def _evaluate_sqnr(session: onnxruntime.InferenceSession, _: Any, + sim: QuantizationSimModel, + data_loader: DataLoader, + forward_fn: Callable, + num_samples: int, + batchwise_fp32_outputs_list: list) -> float: + """ + Compute SQNR given a model and a data loader. + + :param session: sim session + :param _: Placeholder for CallbackFunc + :param sim: Quantization sim model + :param data_loader: Data loader to evaluate SQNR from + :param forward_fn: Function that runs forward pass and returns the output tensor. + :param num_samples: Number of samples used for evaluation + :return: SQNR in dB scale + """ + assert sim.session == session, "session associated with sim and session passed to this callback should be same." + capture_fp32_output_only_once = False + if not batchwise_fp32_outputs_list: + capture_fp32_output_only_once = True + + sqnr = 0.0 + batch_size = data_loader.batch_size or 1 + for i, x in enumerate(data_loader): + if i * batch_size < num_samples: + if capture_fp32_output_only_once: + with _disable_all_quantizers(sim): + fp32_output = forward_fn(session, x) + batchwise_fp32_outputs_list.append(fp32_output) + else: + fp32_output = batchwise_fp32_outputs_list[i] + + quantized_output = forward_fn(session, x) + # Accumulate signal by noise ratio + sqnr += _compute_sqnr(fp32_output, quantized_output) + else: + break + + # Convert SQNR into dB scale + sqnr_db = 10 * np.log10(sqnr / num_samples) + return sqnr_db + + +def _compute_sqnr(orig_tensor: np.ndarray, noisy_tensor: np.ndarray) -> float: + """ + Compute SQNR between two tensors. + + :param orig_tensor: Original tensor + :param noisy_tensor: Noisy tensor + :return: SQNR + """ + assert orig_tensor.shape == noisy_tensor.shape + + # SQNR := E[signal**2] / E[noise**2] + signal = orig_tensor + noise = orig_tensor - noisy_tensor + sqnr = (np.power(signal, 2).mean()) / ((np.power(noise, 2).mean()) + 0.0001) + return float(sqnr) + + +class GreedyMixedPrecisionAlgo(MixedPrecisionAlgo): + """ Naive Greedy MixedPrecisionAlgo class """ + # pylint: disable=too-many-arguments + def __init__(self, sim: QuantizationSimModel, + candidates: List[CANDIDATE_WITH_DTYPE], + eval_callback_for_phase1: CallbackFunc, + eval_callback_for_phase2: CallbackFunc, + results_dir: str, clean_start: bool, + forward_pass_callback: CallbackFunc, + use_all_amp_candidates: bool = False, + phase1_optimize: bool = False): + """ + :param sim: Quantized sim model + :param candidates: List of Tuple of all possible [bitwidth, QuantizationDataType] values to quantize to + :param eval_callback_for_phase1: An object of CallbackFunc class which takes in Eval function (callable) and eval + function parameters. This evaluation callback used to measure sensitivity of each + quantizer group during phase 1. The phase 1 involves finding accuracy list/sensitivity of each + module. Therefore, a user might want to run the phase 1 with a smaller dataset + :param eval_callback_for_phase2: An object of CallbackFunc class which takes in Eval function (callable) and eval + function parameters. Evaluation callback used to get accuracy of quantized model + for phase 2 calculations. The phase 2 involves finding pareto front curve + :param results_dir: Path to save results and cache intermediate results + :param clean_start: If true, any cached information from previous runs will be deleted prior to starting the + mixed-precision analysis. If false, prior cached information will be used if applicable. Note + it is the user's responsibility to set this flag to true if anything in the model or + quantization parameters changes compared to the previous run. + :param forward_pass_callback: An object of CallbackFunc class which takes in Forward pass function (callable) and its + function parameters. Forward pass callback used to compute quantization encodings + :param use_all_amp_candidates: Using the “supported_kernels” field in the config file (under defaults + and op_type sections), a list of supported candidates can be specified. All the AMP candidates + which are passed through the “candidates” field may not be supported based on the data passed + through “supported_kernels”. When the field “use_all_amp_candidates” is set to True, the AMP algo + will ignore the "supported_kernels" in the config file and will continue to use all the candidates. + :phase1_optimize: If user set this parameter to true then phase1 optimized logic will be executed else default code will be executed + """ + mac_dict = mixed_precision_utils.create_mac_dict(sim) + self.phase1_optimize = phase1_optimize + + super().__init__(sim, candidates, eval_callback_for_phase1, eval_callback_for_phase2, forward_pass_callback, + mac_dict, results_dir, clean_start) + self._param_name_to_op_name_dict = \ + mixed_precision_utils.find_param_name_to_parent_name_dict(sim.connected_graph) + + supported_kernels = reformat_supported_kernels(sim.get_supported_kernels()) + + self._supported_candidates_per_quantizer_group, self._baseline_candidate_options = find_supported_candidates( + self.quantizer_groups, + candidates, + supported_kernels, + mixed_precision_utils.get_quantizer_to_op_type_dict(sim), + use_all_amp_candidates) + + def _create_and_save_accuracy_list_optimized(self, baseline_candidate) -> ACCURACY_LIST: + """ + Create a list of tuples of (quantizer_group, bitwidth, accuracy score) + + :param baseline_candidate: Candidate [bitwidth, dtype] which yields max accuracy + :return: Sorted accuracy list containing tuples of (quantizer, candidate, accuracy score, bit ops reduction) + """ + # pylint: disable=too-many-locals, too-many-branches, too-many-statements + index_of_quantizer_group = {} + for index, quantizer_group in enumerate(self.quantizer_groups): + index_of_quantizer_group[quantizer_group] = index + + accuracy_list: ACCURACY_LIST = [] + + file = os.path.join(self._results_dir, '.cache', 'accuracy_list.pkl') + combinations_already_computed = set() + + if os.path.isfile(file): + if self._clean_start: + os.remove(file) + logger.info("Removed old cached files and restarting computation") + else: + with open(file, 'rb') as f: + accuracy_list = pickle.load(f) + + combinations_already_computed.update( + (quantizer_group, candidate) + for quantizer_group, candidate, _, _ in accuracy_list + ) + + disabled_quantizers = OrderedDict() + + try: + # Disable all quantizers + for quantizer_group in self.quantizer_groups: + quantizers = quantizer_group.get_active_quantizers(self._module_name_dict) + disable_quantizers(quantizers) + disabled_quantizers[quantizer_group] = quantizers + + # quantizer_groups_per_candidate = {"candidate1":[quantizer_group1,quantizer_group2,...]} + # quantizer_groups_per_candidate is the dictionary with keys as candidates and values as quantizer groups that supports the corresponding candidate + # quantizer_groups_per_candidate is like reverse mapping to self._supported_candidates_per_quantizer_group + quantizer_groups_per_candidate = defaultdict(list) + for quantizer_group, candidates in self._supported_candidates_per_quantizer_group.items(): + for candidate in candidates: + quantizer_groups_per_candidate[candidate].append(quantizer_group) + + # Loop through all possible bitwidths(candidates). Set all the quantizer groups to the corresponding bitwidth(candidate) + # Compute encodings by disabling the parameters and reuse the encodings + for candidate, quantizer_groups in quantizer_groups_per_candidate.items(): + if candidate == baseline_candidate: + continue + + # configure the sim model with the candidate by enabling the quantizers and set quantizers to corresponding candidate + for quantizer_group in quantizer_groups: + quantizers = disabled_quantizers[quantizer_group] + try: + enable_quantizers(quantizers) + # Set quantizer bitwidth to candidate (bitwidth) + quantizer_group.set_quantizers_to_candidate(self._module_name_dict, candidate) + except RuntimeError as e: + logger.info("Exception occured while setting Quantizers to Candidate: %s", e) + + # list to store all the param quantizers + param_quantizers_qgp = [] + + for quantizer_group in quantizer_groups: + for quantizer in quantizer_group.get_param_quantizers(self._module_name_dict): + if quantizer.enabled: + param_quantizers_qgp.append(quantizer) + + # compute encodings + self._sim.compute_encodings(self.algo_params.forward_pass_callback, + self.algo_params.forward_pass_callback_args) + # export encodings + self._export_encodings(self._results_dir) + + # disable the parameter quantization + disable_quantizers(param_quantizers_qgp) + + # compute encodings with out parameter quantization + self._sim.compute_encodings(self.algo_params.forward_pass_callback, + self.algo_params.forward_pass_callback_args) + + # export activation encodings + self._export_activation_encodings(self._results_dir) + # enable the parameter quantization + enable_quantizers(param_quantizers_qgp) + self._load_param_encodings(self._results_dir) + + # Disable all the quantizers + for quantizer_group in quantizer_groups: + quantizers = quantizer_group.get_active_quantizers(self._module_name_dict) + disable_quantizers(quantizers) + disabled_quantizers[quantizer_group] = quantizers + + # Loop over all the quantizer groups and enable one at a time and calculate resulting model accuracy and disable the enabled quantizer + # Accuracy list will contain tuples of the quantizer, bitwidth, and accuracy score + for quantizer_group in quantizer_groups: + quantizers = disabled_quantizers[quantizer_group] + try: + enable_quantizers(quantizers) + + # If starting the computation from an already existing state, then check if that combination + # has already been executed + if (quantizer_group, candidate) in combinations_already_computed: + continue + # Compute accuracy of model with new candidate (bitwidth) + eval_score = self.evaluate_model(self.algo_params.eval_callback_for_phase1) + + bit_ops_reduction = self._find_bit_ops_reduction_for_acc_list(quantizer_group, + baseline_candidate, + candidate) + accuracy_list.append((quantizer_group, candidate, eval_score, bit_ops_reduction)) + # Sort accuracy list, first by descending accuracy score, then by descending order of addition of bitwidths if accuracy + # scores are identical, if that is also identical we sort by relative bit ops change in descending order + # If bit ops reduction is also the same, then we sort in ascending order based on occurence of + # quantizer group in the model + accuracy_list = sort_accuracy_list(accuracy_list, index_of_quantizer_group) + self._export_accuracy_list(accuracy_list, self._results_dir) + logger.info('\n Quantizer: %s candidate: %s eval_score: %f \n', quantizer_group, + candidate, eval_score) + finally: + # Disable the quantizer + disable_quantizers(quantizers) + finally: + # set all quantizers to baseline candidate + for quantizer_group in self.quantizer_groups: + quantizers = disabled_quantizers[quantizer_group] + try: + # Enable the disabled quantizers + enable_quantizers(quantizers) + quantizer_group.set_quantizers_to_candidate(self._module_name_dict, baseline_candidate) + except RuntimeError as e: + logger.info("Exception occured while setting Quantizers to Candidate: %s", e) + + logger.info('Completed Accuracy list computation') + # Recompute encodings after quantizer's bitwidth is set back to self._max_bitwidth + self._sim.compute_encodings(self.algo_params.forward_pass_callback, self.algo_params.forward_pass_callback_args) + return accuracy_list + + def _export_encodings(self, path: str): + """ + Export encodings of the sim model to the given path + + :param path: Encodings will store in the given path/.cache folder + """ + results_dir = os.path.join(path, '.cache') + if not os.path.exists(results_dir): + os.makedirs(results_dir) + path = os.path.join(results_dir, 'encodings_with_param.encodings') + # pylint: disable=protected-access + self._sim._export_encodings(path) + + def _export_activation_encodings(self, path: str): + """ + Export encodings of the sim model to the given path + + :param path: Encodings will store in the given path/.cache folder + """ + results_dir = os.path.join(path, '.cache') + if not os.path.exists(results_dir): + os.makedirs(results_dir) + path = os.path.join(results_dir, 'encodings_with_act.encodings') + # pylint: disable=protected-access + self._sim._export_encodings(path) + + def _load_param_encodings(self, path: str): + """ + Loads parameter encodings to the sim model + + :param path: Folder Path where encodings file is present + """ + param_path = os.path.join(path, '.cache/encodings_with_param.encodings') + + # Load encodings file + with open(param_path) as json_file: + param_encodings = json.load(json_file) + + # Loading activation encodings also along with param encodings to get compatible with load_encodings_to_sim function + # These activation encodings are already present in quantsim model + act_path = os.path.join(path, '.cache/encodings_with_act.encodings') + with open(act_path) as json_file: + act_encodings = json.load(json_file) + + param_encodings['activation_encodings'] = act_encodings['activation_encodings'] + + # Save the updated encodings to the file + save_json_yaml(param_path, param_encodings) + #load encodings + load_encodings_to_sim(self._sim, param_path, strict=True) + + # Removing the files created by _export_encodings function + os.remove(param_path) + os.remove(act_path) + + def _evaluate_model(self, eval_callback: CallbackFunc) -> float: + """ + Evaluates a model + + :param eval_callback: Callback function that contains eval function and eval args + :return: Eval score + """ + return eval_callback.func(self._sim.session, eval_callback.args) + + def _find_quantizer_group(self, sim: QuantizationSimModel) -> Tuple[Dict[str, QcQuantizeOp], List[QuantizerGroup]]: + """ + Finds quantizer groups in a quantization sim + :param sim: Quantization sim + :return: Dictionary mapping quantized op name to quantizer, + and a List of quantizer groups + """ + return find_quantizer_group(sim) + + @property + def baseline_candidate_options(self) -> List[CANDIDATE_WITH_DTYPE]: + """ + Returns the _baseline_candidate_options which is the intersection of amp candidates and candidates supported by + all the quantizer groups + """ + return self._baseline_candidate_options + + def _find_bit_ops_reduction_for_acc_list( + self, + quantizer_group: QuantizerGroup, + max_candidate: CANDIDATE_WITH_DTYPE, + candidate: CANDIDATE_WITH_DTYPE, + ) -> int: + """ + Finds reduction in bit ops from max candidate to new candidate + + :param quantizer_group: Quantizer group + :param max_candidate: Maximum bitwidth and data type for the TensorQuantizer + :param candidate: Activation bitwidth, parameter bitwidth + :return: Bit ops reduction + """ + return mixed_precision_utils.find_bit_ops_reduction(quantizer_group, self._mac_dict, + self._param_name_to_op_name_dict, + max_candidate, candidate) + + def calculate_running_bit_ops( + self, + quantizer_group: QuantizerGroup, + module_bitwidth_dict: Dict[str, int], + max_candidate: CANDIDATE_WITH_DTYPE, + candidate: CANDIDATE_WITH_DTYPE, + running_bit_ops: int, + ) -> int: + """ + Calculates running bit ops value for every quantizer group + + :param quantizer_group: A group of activation & parameter quantizers + :param module_bitwidth_dict: Dict; Key: Module name value: Activation, parameter bitwidth of module + :param max_candidate: Maximum bitwidth and data type for the TensorQuantizer + :param candidate: candidate to change the quantizer group to + :param running_bit_ops: Running bit ops value calculated uptil the quantizer group + :return: Running bit ops value + """ + running_bit_ops = mixed_precision_utils.calculate_running_bit_ops(self._mac_dict, quantizer_group, + self._param_name_to_op_name_dict, + module_bitwidth_dict, + max_candidate, + candidate, + running_bit_ops) + return running_bit_ops + + def _create_and_save_accuracy_list(self, baseline_candidate): + try: + if self.phase1_optimize: + return self._create_and_save_accuracy_list_optimized(baseline_candidate) + return super()._create_and_save_accuracy_list(baseline_candidate) + finally: + pass + + def _create_op_graph(self, sim): + """ + Creates op graph + + :param sim: QuantizationSimModel object + """ + return None + + def _optimize_mp_profile_and_evaluate_model(self): + """ + Uses OpGraph if available to optimize the mixed precision profile in the sim object + """ + # Recompute quantizer encodings + self._sim.compute_encodings(self.algo_params.forward_pass_callback, + self.algo_params.forward_pass_callback_args) + # Compute new accuracy score + eval_score = self.evaluate_model(self.algo_params.eval_callback_for_phase2) + return eval_score + + def _reduce_mp_convert_ops(self): + """ + Reduce mixed precision convert ops if enabled and supported + """ +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_onnx/amp/quantizer_groups.html b/releases/2.0.0/_modules/aimet_onnx/amp/quantizer_groups.html new file mode 100644 index 0000000..fd99695 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_onnx/amp/quantizer_groups.html @@ -0,0 +1,731 @@ + + + + + + + + aimet_onnx.amp.quantizer_groups - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_onnx.amp.quantizer_groups

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Find quantizer groups in a model """
    +import itertools
    +from typing import Dict, Tuple, List
    +from collections import defaultdict
    +from dataclasses import dataclass, field
    +
    +from aimet_common.connected_graph.operation import Op
    +from aimet_common.connected_graph.connectedgraph_utils import get_all_input_ops, get_all_output_ops
    +
    +from aimet_common.amp.utils import CANDIDATE_WITH_DTYPE
    +
    +from aimet_common.connected_graph.connectedgraph import get_ordered_ops
    +from aimet_common.amp.quantizer_groups import QuantizerGroupBase, get_supported_candidates_for_quantizers, \
    +    compute_baseline_candidate_options, find_valid_ops
    +from aimet_common.utils import AimetLogger
    +
    +from aimet_onnx.meta.connectedgraph import ConnectedGraph
    +from aimet_onnx.quantsim import QuantizationSimModel
    +from aimet_onnx.qc_quantize_op import QcQuantizeOp
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.MixedPrecision)
    +
    +
    +
    +[docs] +@dataclass(frozen=True) +class QuantizerGroup(QuantizerGroupBase): + """ + Group of modules and quantizers + """ + parameter_quantizers: Tuple[str, ...] = field(default_factory=tuple) + activation_quantizers: Tuple[str, ...] = field(default_factory=tuple) + +
    +[docs] + def get_candidate(self, name_to_quantizer_dict: Dict) -> CANDIDATE_WITH_DTYPE: + """ + Gets Activation & parameter bitwidth + + :param name_to_quantizer_dict: Gets module from module name + :return: Tuple of Activation, parameter bitwidth and data type + """ + activation_bw, parameter_bw = None, None + activation_dtype, param_dtype = None, None + + for quantizer in self.get_activation_quantizers(name_to_quantizer_dict): + activation_bw = quantizer.bitwidth + activation_dtype = quantizer.data_type + break + + for quantizer in self.get_param_quantizers(name_to_quantizer_dict): + if quantizer.enabled: + parameter_bw = quantizer.bitwidth + param_dtype = quantizer.data_type + break + + return (activation_bw, activation_dtype), (parameter_bw, param_dtype)
    + + +
    +[docs] + def set_quantizers_to_candidate(self, + name_to_quantizer_dict: Dict, + candidate: CANDIDATE_WITH_DTYPE): + """ + Sets a quantizer group to a given candidate bitwidth + + :param name_to_quantizer_dict: Gets module from module name + :param candidate: candidate with act and param bw and data types + """ + (activation_bw, activation_dtype), (param_bw, param_dtype) = candidate + + for quantizer in self.get_activation_quantizers(name_to_quantizer_dict): + quantizer.bitwidth = activation_bw + quantizer.data_type = activation_dtype + + for quantizer in self.get_param_quantizers(name_to_quantizer_dict): + quantizer.bitwidth = param_bw + quantizer.data_type = param_dtype
    + + +
    +[docs] + def to_list(self) -> List[Tuple[str, str]]: + """ + Converts quantizer group to a list + + :return: List containing input/output quantizers & weight quantizers + """ + return list(itertools.chain( + (("activation", module_name) for module_name in self.activation_quantizers), + (("weight", module_name) for module_name in self.parameter_quantizers), + ))
    + + +
    +[docs] + def get_active_quantizers(self, name_to_quantizer_dict) -> List[QcQuantizeOp]: + """ + Find all active tensor quantizers associated with this quantizer group + + :param name_to_quantizer_dict: Gets module from module name + :return: List of active quantizers + """ + quantizers = self.get_activation_quantizers(name_to_quantizer_dict) + \ + self.get_param_quantizers(name_to_quantizer_dict) + return [quantizer for quantizer in quantizers if quantizer.enabled]
    + + +
    +[docs] + def get_activation_quantizers(self, name_to_quantizer_dict): + """ + Gets activation quantizers + + :param name_to_quantizer_dict: Gets module from module name + + :return List of activation quantizers + """ + result = [] + for module_name in self.activation_quantizers: + quantizer = name_to_quantizer_dict[module_name] + result.append(quantizer) + return result
    + + +
    +[docs] + def get_param_quantizers(self, name_to_quantizer_dict): + """ + Gets parameter quantizers + + :param name_to_quantizer_dict: Gets module from module name + + :return List of parameter quantizers + """ + result = [] + for module_name in self.parameter_quantizers: + quantizer = name_to_quantizer_dict[module_name] + result.append(quantizer) + return result
    +
    + + + +op_types_to_ignore = ['Reshape', 'branch', 'Gather', 'Unsqueeze', 'Pad'] +ops_not_to_traverse = ['Shape'] + + +def find_op_groups(connected_graph: ConnectedGraph) -> Dict: + """ + Finds parent child groups based on following rules. + 1) If there is a direct connection between two ops, op1 and op2, then op1 is parent of op2 and they form a group + 2) If the input to an op (op1) is shared with another op (op2), the op producing the input (op0) is the parent, + and op1 and op2 are the children + + :param connected_graph: Connected graph + :return: Dict of parent (key) and children (value) groups + """ + # Get ordered ops in Connected graph + ordered_ops = get_ordered_ops(connected_graph.starting_ops) + valid_ops = find_valid_ops(connected_graph, ops_not_to_traverse) + + parent_child_op_groups = defaultdict(list) + map_for_skipped_ops = {} + + for op in ordered_ops: + if op.dotted_name not in valid_ops or op.type in op_types_to_ignore: + continue + _find_parent_child_op_groups(op, parent_child_op_groups, map_for_skipped_ops) + + return parent_child_op_groups + + +def _find_parent_child_op_groups(op: Op, parent_child_op_groups: Dict, map_for_skipped_ops: Dict): + """ + Finds op groups along the parent to child flow + :param op: Op + :param parent_child_op_groups: parent child op groups dict + :param map_for_skipped_ops: map to find first skipped parents of skipped ops + """ + output = op.output + + if output: + consumers = output.consumers + for consumer in consumers: + dotted_name = op.dotted_name + if consumer.type in ops_not_to_traverse: + continue + if op.dotted_name in map_for_skipped_ops: + dotted_name = map_for_skipped_ops[op.dotted_name] + + if consumer.type in op_types_to_ignore: + map_for_skipped_ops[consumer.dotted_name] = dotted_name + _find_parent_child_op_groups(consumer, parent_child_op_groups, map_for_skipped_ops) + else: + if consumer.dotted_name not in parent_child_op_groups[dotted_name]: + parent_child_op_groups[dotted_name].append(consumer.dotted_name) + if not consumers and op.dotted_name in map_for_skipped_ops: + parent_child_op_groups[map_for_skipped_ops[op.dotted_name]] = [] + else: + dotted_name = op.dotted_name + parent_child_op_groups[dotted_name].append(None) + + +def find_quantizer_group(sim: QuantizationSimModel) -> Tuple[Dict, List[QuantizerGroup]]: + """ + Finds quantizer groups in a quantization sim + :param sim: Quantization sim + :return: Dictionary of quantized op name to sim.quantizer_config object, List of quantizer groups + """ + # Get connected graph from quantsim + connected_graph = sim.connected_graph + + if connected_graph is None: + raise AssertionError('Aborting Auto Mixed Precision, connected graph needs to exist for Auto Mixed precision') + + # Find parent to children mapping for connected graph ops + parent_child_op_groups = find_op_groups(connected_graph) + + # Find mapping of quantized op name to quantizer info + op_name_to_quantizer_dict = _get_op_name_to_act_quantizer_name_dicts(sim) + op_to_param_dict = _get_op_to_param_name_dict(sim) + + quantizer_groups = [] + _add_input_quantizer_group(op_to_param_dict, sim, quantizer_groups) + for parent, children in parent_child_op_groups.items(): + activation_quantizers = [] + if parent in op_name_to_quantizer_dict: + activation_quantizers.append(op_name_to_quantizer_dict[parent]) + parameter_quantizers = [] + for child in children: + if child and child in op_to_param_dict: + parameter_quantizers.append(op_to_param_dict[child]) + + if activation_quantizers or parameter_quantizers: + _add_quantizer_group(quantizer_groups, tuple(activation_quantizers), tuple(parameter_quantizers)) + + _add_output_quantizer_group(op_name_to_quantizer_dict, sim, quantizer_groups) + + return sim.qc_quantize_op_dict, quantizer_groups + + +def _add_quantizer_group(quantizer_groups: List[QuantizerGroup], activation_quantizers: Tuple, + parameter_quantizers: Tuple): + """ + Adds quantizer group to the quantizer groups list + :param quantizer_groups: List of Quantizer groups + :param activation_quantizers: Tuple of activation quantizers + :param parameter_quantizers: Tuple of parameter quantizers + """ + quantizer_group = QuantizerGroup(parameter_quantizers=parameter_quantizers, + activation_quantizers=activation_quantizers) + quantizer_groups.append(quantizer_group) + logger.info('Quantizer Group added: %s', quantizer_group) + + +def _add_input_quantizer_group(op_to_param_dict: Dict, sim: QuantizationSimModel, quantizer_groups: List): + """ + Adds input's (of the model) quantizer group + :param op_to_param_dict: Key: op_name Value: Weight name associated + :param sim: Quantization Sim + :param quantizer_groups: Quantizer Groups List + """ + conn_graph_ops = get_all_input_ops(sim.connected_graph) + for input_op in conn_graph_ops: + parameter_quantizers = [] + activation_quantizers = [] + if input_op.dotted_name in op_to_param_dict: + parameter_quantizers.append(op_to_param_dict[input_op.dotted_name]) + for input_product in input_op.inputs: + activation_quantizer = input_product.tensor_dict[input_op] + if isinstance(activation_quantizer, str) and \ + activation_quantizer in sim.activation_names and \ + sim.qc_quantize_op_dict[activation_quantizer].enabled: + activation_quantizers.append(input_product.tensor_dict[input_op]) + if activation_quantizers or parameter_quantizers: + _add_quantizer_group(quantizer_groups, tuple(activation_quantizers), tuple(parameter_quantizers)) + + +def _add_output_quantizer_group(op_name_to_quantizer_dict: Dict, sim: QuantizationSimModel, quantizer_groups: List): + """ + Adds output's (of the model) quantizer group + :param op_name_to_quantizer_dict: Key: op_name Value: quantizer associated with op name + :param sim: Quantization Sim + :param quantizer_groups: Quantizer Groups List + """ + conn_graph_ops = get_all_output_ops(sim.connected_graph) + for output_op in conn_graph_ops: + activation_quantizers = [] + if output_op.dotted_name in op_name_to_quantizer_dict: + activation_quantizers.append(op_name_to_quantizer_dict[output_op.dotted_name]) + if activation_quantizers: + _add_quantizer_group(quantizer_groups, tuple(activation_quantizers), ()) + + +def _get_op_to_param_name_dict(sim: QuantizationSimModel) -> Dict: + """ + Creates the dict where param name (weight) is mapped to op's name + :param sim: Quantization Sim + """ + op_to_param_dict = {} + conn_graph_ops = sim.connected_graph.get_all_ops() + for op in conn_graph_ops.values(): + for param_name in op.parameters: + _, param_type = op.parameters[param_name] + if param_type == 'weight' and sim.qc_quantize_op_dict[param_name].enabled: + op_to_param_dict[op.dotted_name] = param_name + + return op_to_param_dict + + +def _get_op_name_to_act_quantizer_name_dicts(sim: QuantizationSimModel) -> Dict: + """ + Creates the dict where param quantizers if enabled are mapped to their param_names and activation + quantizer if enabled is mapped to it's inputs name + :param sim: Quantization Sim + :return op_name_to_activation_quantizer_name_dict + """ + op_name_to_activation_quantizer_name_dict = {} + for node in sim.model.model.graph.node: + if 'QcQuantizeOp' in node.name: + continue + for output_product in node.output: + if output_product in sim.activation_names: + activation_quantizer_op = sim.qc_quantize_op_dict[output_product] + if activation_quantizer_op.enabled: + op_name_to_activation_quantizer_name_dict[node.name] = output_product + return op_name_to_activation_quantizer_name_dict + + +def find_supported_candidates(quantizer_groups: List[QuantizerGroup], + amp_candidates: List[CANDIDATE_WITH_DTYPE], + supported_kernels: Dict, + quantizer_to_op_type: Dict, + use_all_amp_candidates: bool) -> Tuple[Dict, List]: + """ + Computes 1. a list of supported candidates per Quantizer and 2. List of candidate options for max_candidate + :param quantizer_groups: List of quantizer groups computed for the given model + :param amp_candidates: List of candidates specified by the user to be used for the AMP algorithm + :param supported_kernels: Dict of supported kernels for a given op/defaults specified in the config file + :param quantizer_to_op_type: Dict of quantizers to onnx op type + :param use_all_amp_candidates: Boolean value representing whether the unsupported candidates in the + "candidates" list need to be considered for creating the output lists. If set to True, all the AMP candidates are + directly used for all the Quantizers, else the candidates per Quantizers are computed. + """ + + quantizers_with_supported_candidates = defaultdict(list) + + for quantizer_group in quantizer_groups: + quantizers = sorted(set(itertools.chain(quantizer_group.activation_quantizers, + quantizer_group.parameter_quantizers))) + + supported_kernels_for_quantizers = get_supported_candidates_for_quantizers(quantizers, + quantizer_to_op_type, + supported_kernels, + amp_candidates, + use_all_amp_candidates) + + quantizers_with_supported_candidates[quantizer_group] = supported_kernels_for_quantizers.copy() + + max_candidate_options = compute_baseline_candidate_options(quantizers_with_supported_candidates, amp_candidates, + use_all_amp_candidates) + + return quantizers_with_supported_candidates, max_candidate_options +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_onnx/auto_quant_v2.html b/releases/2.0.0/_modules/aimet_onnx/auto_quant_v2.html new file mode 100644 index 0000000..2f1a58d --- /dev/null +++ b/releases/2.0.0/_modules/aimet_onnx/auto_quant_v2.html @@ -0,0 +1,2041 @@ + + + + + + + + aimet_onnx.auto_quant_v2 - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_onnx.auto_quant_v2

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +# pylint: disable=too-many-lines, protected-access
    +
    +"""Automatic Post-Training Quantization V2"""
    +
    +import copy
    +from collections import OrderedDict, defaultdict
    +from dataclasses import dataclass
    +import functools
    +import math
    +import traceback
    +import os
    +import sys
    +import io
    +from unittest.mock import patch
    +from typing import Any, Callable, Dict, List, Optional, Tuple, Union, Mapping, Iterable
    +import shutil
    +import pickle
    +from uuid import uuid4
    +from tqdm import tqdm
    +import jinja2
    +import bokeh.plotting
    +from bokeh.resources import CDN
    +
    +import onnx
    +import onnxruntime as ort
    +from onnxruntime.quantization.onnx_quantizer import ONNXModel
    +import numpy as np
    +
    +from aimet_onnx import utils
    +from aimet_onnx.adaround.adaround_weight import Adaround, AdaroundParameters
    +from aimet_onnx.cross_layer_equalization import equalize_model
    +from aimet_onnx.batch_norm_fold import fold_all_batch_norms_to_weight
    +from aimet_onnx.quantsim import QuantizationSimModel
    +from aimet_onnx.amp.mixed_precision_algo import GreedyMixedPrecisionAlgo, EvalCallbackFactory, _default_forward_fn
    +from aimet_onnx.amp.quantizer_groups import QuantizerGroup
    +from aimet_onnx.defs import DataLoader
    +
    +from aimet_common.auto_quant import Diagnostics
    +from aimet_common.cache import Cache
    +from aimet_common.defs import QuantScheme, QuantizationDataType, CallbackFunc
    +from aimet_common.utils import AimetLogger, Spinner
    +from aimet_common.quantsim import validate_quantsim_inputs
    +from aimet_common.amp.utils import (
    +    create_sensitivity_plot,
    +    create_pareto_curve,
    +    CANDIDATE_WITH_DTYPE,
    +    AmpCandidate,
    +)
    +
    +
    +_logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.AutoQuant)
    +
    +cache = Cache()
    +
    +# The number of samples to be used for performance evaluation.
    +# NOTE: None means "all".
    +NUM_SAMPLES_FOR_PERFORMANCE_EVALUATION = None
    +
    +
    +@dataclass(frozen=True)
    +class _QuantSchemePair:
    +    param_quant_scheme: QuantScheme
    +    output_quant_scheme: QuantScheme
    +    param_percentile: Optional[float] = None
    +    output_percentile: Optional[float] = None
    +
    +    def __str__(self):
    +        def scheme_to_str(quant_scheme, percentile):
    +            if quant_scheme == QuantScheme.post_training_percentile:
    +                return f"{percentile}%ile"
    +            if quant_scheme in (QuantScheme.post_training_tf,
    +                                QuantScheme.training_range_learning_with_tf_init):
    +                return "tf"
    +            if quant_scheme in (QuantScheme.post_training_tf_enhanced,
    +                                QuantScheme.training_range_learning_with_tf_enhanced_init):
    +                return "tf-enhanced"
    +            raise ValueError
    +
    +        param_str = scheme_to_str(self.param_quant_scheme, self.param_percentile)
    +        output_str = scheme_to_str(self.output_quant_scheme, self.output_percentile)
    +        return f"W@{param_str} / A@{output_str}"
    +
    +
    +_QUANT_SCHEME_CANDIDATES = (
    +    # Weight:     tf
    +    # Activation: tf
    +    _QuantSchemePair(QuantScheme.post_training_tf,
    +                     QuantScheme.post_training_tf),
    +
    +    # Weight:     tf_enhanced
    +    # Activation: tf
    +    _QuantSchemePair(QuantScheme.post_training_tf_enhanced,
    +                     QuantScheme.post_training_tf),
    +
    +    # Weight:     tf_enhanced
    +    # Activation: tf_enhanced
    +    _QuantSchemePair(QuantScheme.post_training_tf_enhanced,
    +                     QuantScheme.post_training_tf_enhanced),
    +
    +    # TODO: Enable below candidates once we figure out how to set percentile value in QcQuantizeOp's Tensor Quantizer
    +
    +    # Weight:     tf_enhanced
    +    # Activation: percentile(99.9)
    +    # _QuantSchemePair(QuantScheme.post_training_tf_enhanced,
    +    #                  QuantScheme.post_training_percentile,
    +    #                  output_percentile=99.9),
    +
    +    # Weight:     tf_enhanced
    +    # Activation: percentile(99.99)
    +    # _QuantSchemePair(QuantScheme.post_training_tf_enhanced,
    +    #                  QuantScheme.post_training_percentile,
    +    #                  output_percentile=99.99),
    +)
    +
    +
    +def _validate_inputs(model: Union[onnx.ModelProto, ONNXModel], # pylint: disable=too-many-arguments
    +                     data_loader: Iterable[Union[np.ndarray, List[np.ndarray]]],
    +                     eval_callback: Callable[[ort.InferenceSession], float],
    +                     dummy_input: Dict[str, np.ndarray],
    +                     results_dir: str,
    +                     strict_validation: bool,
    +                     quant_scheme: QuantScheme,
    +                     param_bw: int,
    +                     output_bw: int,
    +                     rounding_mode: str):
    +    """
    +    Confirms inputs are of the correct type
    +    :param model: Model to be quantized
    +    :param data_loader: A collection that iterates over an unlabeled dataset, used for computing encodings
    +    :param eval_callback: Function that calculates the evaluation score
    +    :param dummy_input: Dummy input for the model
    +    :param results_dir: Directory to save the results of PTQ techniques
    +    :param strict_validation: Flag set to True by default. When False, AutoQuant will proceed with execution and try to handle errors internally if possible. This may produce unideal or unintuitive results.
    +    :param quant_scheme: Quantization scheme
    +    :param param_bw: Parameter bitwidth
    +    :param output_bw: Output bitwidth
    +    :param rounding_mode: Rounding mode
    +    """
    +    if not isinstance(model, (onnx.ModelProto, ONNXModel)):
    +        raise ValueError('Model must be of type onnx.ModelProto or ONNXModel, not ' + str(type(model).__name__))
    +
    +    if not isinstance(data_loader, Iterable):
    +        raise ValueError('data_loader must be of type Iterable, not ' + str(
    +            type(data_loader).__name__))
    +
    +    if not isinstance(eval_callback, Callable):  # pylint: disable=isinstance-second-argument-not-valid-type
    +        raise ValueError('eval_callback must be of type Callable, not ' + str(type(eval_callback).__name__))
    +
    +    if not isinstance(dummy_input, Dict):
    +        raise ValueError(
    +            'dummy_input must be of type Dict, not ' + str(type(dummy_input).__name__))
    +
    +    if not isinstance(results_dir, str):
    +        raise ValueError('results_dir must be of type str, not ' + str(type(results_dir).__name__))
    +
    +    results_dir = os.path.abspath(results_dir)
    +    os.makedirs(results_dir, exist_ok=True)
    +
    +    if not isinstance(strict_validation, bool):
    +        raise ValueError('strict_validation must be of type bool, not ' + str(type(strict_validation).__name__))
    +
    +    validate_quantsim_inputs(quant_scheme, rounding_mode, output_bw, param_bw)
    +
    +
    +class AutoQuant: # pylint: disable=too-many-instance-attributes
    +    """
    +    Integrate and apply post-training quantization techniques.
    +
    +    AutoQuant includes 1) batchnorm folding, 2) cross-layer equalization,
    +    and 3) Adaround.
    +    These techniques will be applied in a best-effort manner until the model
    +    meets the evaluation goal given as allowed_accuracy_drop.
    +    """
    +
    +    def __init__( # pylint: disable=too-many-arguments, too-many-locals
    +            self,
    +            model: Union[onnx.ModelProto, ONNXModel],
    +            dummy_input: Dict[str, np.ndarray],
    +            data_loader: Iterable[Union[np.ndarray, List[np.ndarray], Tuple[np.ndarray]]],
    +            eval_callback: Callable[[ort.InferenceSession, int], float],
    +            param_bw: int = 8,
    +            output_bw: int = 8,
    +            quant_scheme: QuantScheme = QuantScheme.post_training_tf_enhanced,
    +            rounding_mode: str = 'nearest',
    +            use_cuda: bool = True,
    +            device: int = 0,
    +            config_file: str = None,
    +            results_dir: str = "/tmp",
    +            cache_id: str = None,
    +            strict_validation: bool = True) -> None:
    +        '''
    +        :param model: Model to be quantized.
    +        :param dummy_input: Dummy input dict for the model.
    +        :param data_loader: A collection that iterates over an unlabeled dataset, used for computing encodings
    +        :param eval_callback: Function that calculates the evaluation score given the model session
    +        :param param_bw: Parameter bitwidth
    +        :param output_bw: Output bitwidth
    +        :param quant_scheme: Quantization scheme
    +        :param rounding_mode: Rounding mode
    +        :param use_cuda: True if using CUDA to run quantization op. False otherwise.
    +        :param config_file: Path to configuration file for model quantizers
    +        :param results_dir: Directory to save the results of PTQ techniques
    +        :param cache_id: ID associated with cache results
    +        :param strict_validation: Flag set to True by default. When False, AutoQuant will proceed with execution and handle errors internally if possible. This may produce unideal or unintuitive results.
    +        '''
    +
    +        _validate_inputs(model, data_loader, eval_callback, dummy_input, results_dir,
    +                         strict_validation, quant_scheme, param_bw, output_bw, rounding_mode)
    +
    +        if not isinstance(model, ONNXModel):
    +            model = ONNXModel(model)
    +
    +        self.fp32_model = model
    +        self.dummy_input = dummy_input
    +        self.data_loader = data_loader
    +        self.eval_callback = eval_callback
    +
    +        self._quantsim_params = dict(
    +            param_bw=param_bw,
    +            output_bw=output_bw,
    +            quant_scheme=_QuantSchemePair(quant_scheme, quant_scheme),
    +            rounding_mode=rounding_mode,
    +            config_file=config_file,
    +            use_cuda=use_cuda,
    +            device=device
    +        )
    +
    +        self.results_dir = results_dir
    +        self.cache_dir = None
    +        if cache_id:
    +            self.cache_dir = os.path.join(results_dir, ".auto_quant_cache", cache_id)
    +
    +        def forward_pass_callback(session, _: Any = None):
    +            for input_data in tqdm(data_loader):
    +                input_data_dict = utils.create_input_dict(model.model, input_data)
    +                _ = session.run(None, input_data_dict)
    +
    +        self.forward_pass_callback = forward_pass_callback
    +
    +        # Use at most 2000 samples for AdaRound.
    +        input_instance = next(iter(self.data_loader))
    +        batch_size = len(input_instance[0]) if isinstance(input_instance, (List, Tuple)) else len(input_instance)
    +        num_batches = 0
    +        for _ in self.data_loader:
    +            num_batches += 1
    +        num_samples = min(num_batches * batch_size, 2000)
    +        num_batches = math.ceil(num_samples / batch_size)
    +        self.adaround_params = AdaroundParameters(self.data_loader, num_batches)
    +
    +        self.eval_manager = _EvalManager(
    +            quantsim_factory=self._create_quantsim_and_encodings,
    +            eval_func=self._evaluate_model_performance,
    +            results_dir=self.results_dir,
    +            strict_validation=strict_validation)
    +
    +        self._quant_scheme_candidates = _QUANT_SCHEME_CANDIDATES
    +        self._fp32_acc = None
    +
    +    def _evaluate_model_performance(self, session) -> float:
    +        """
    +        Evaluate the model performance.
    +        """
    +        return self.eval_callback(session, NUM_SAMPLES_FOR_PERFORMANCE_EVALUATION)
    +
    +    def run_inference(self) -> Tuple[QuantizationSimModel, float]:
    +        '''
    +        Creates a quantization model and performs inference
    +
    +        :return: QuantizationSimModel, model accuracy as float
    +        '''
    +        model = self.fp32_model
    +
    +        # Batchnorm Folding
    +        with self.eval_manager.session("Batchnorm Folding - Inference Run") as sess:
    +            model, _ = sess.wrap(self._apply_batchnorm_folding)(model)
    +            if sess.ptq_result is None:
    +                sess.set_ptq_result(model=model,
    +                                    applied_techniques=["batchnorm_folding"])
    +
    +        sim = self._create_quantsim_and_encodings(model)
    +
    +        if sess.ptq_result is None:
    +            # BN folding failed. Need to measure the eval score
    +            acc = self._evaluate_model_performance(sim.session)
    +        else:
    +            # BN folding success. No need to measure the eval score again
    +            acc = sess.ptq_result.accuracy
    +
    +        return sim, acc
    +
    +    def optimize(self, allowed_accuracy_drop: float = 0.0) -> Tuple[ONNXModel, float, str]:
    +        """
    +        Integrate and apply post-training quantization techniques.
    +
    +        :param allowed_accuracy_drop: Maximum allowed accuracy drop
    +        :return: Tuple of (best model, eval score, encoding path)
    +        """
    +        result = self._optimize_helper(self._optimize_main, allowed_accuracy_drop)
    +        return result["model"],\
    +               result["accuracy"],\
    +               result["encoding_path"]
    +
    +    def set_adaround_params(self, adaround_params: AdaroundParameters) -> None:
    +        """
    +        Set Adaround parameters.
    +        If this method is not called explicitly by the user, AutoQuant will use
    +        `data_loader` (passed to `__init__`) for Adaround.
    +
    +        :param adaround_params: Adaround parameters.
    +        """
    +        self.adaround_params = adaround_params
    +
    +    def _create_quantsim_and_encodings( # pylint: disable=too-many-arguments, too-many-locals, too-many-branches
    +            self,
    +            fp32_model: ONNXModel,
    +            rounding_mode: str = None,
    +            output_bw: int = None,
    +            output_quant_scheme: QuantScheme = None,
    +            output_percentile: float = None,
    +            param_bw: int = None,
    +            param_quant_scheme: QuantScheme = None,
    +            param_percentile: float = None,
    +            config_file: str = None,
    +            encoding_path: str = None,
    +    ) -> QuantizationSimModel:
    +        """
    +        Create a QuantizationSimModel and compute encoding. If `encoding_path` is not None,
    +        it is prioritized over other arguments (`output_bw`, `param_bw`, ...).
    +
    +        :param fp32_model: Model to quantize.
    +        :param rounding_mode: Rounding mode. Defaults to self._quantsim_params["rounding_mode"].
    +        :param output_bw: Default bitwidth (4-31) to use for quantizing layer inputs andoutputs.
    +            Defaults to self._quantsim_params["output_bw"].
    +        :param output_quant_scheme: Quantization scheme for output quantizers.
    +            Defaults to self._quantsim_params["quant_scheme"].output_quant_scheme.
    +        :param output_percentile: Percentile value for outputs.
    +            Only valid if output quant scheme is percentile scheme.
    +        :param param_bw: Default bitwidth (4-31) to use for quantizing layer parameters.
    +            Defaults to self._quantsim_params["param_bw"].
    +        :param param_quant_scheme: Quantization scheme for param quantizers.
    +            Defaults to self._quantsim_params["quant_scheme"].param_quant_scheme.
    +        :param param_percentile: Percentile value for parameters.
    +            Only valid if param quant scheme is percentile scheme.
    +        :param config_file: Path to configuration file for model quantizers.
    +                            Defaults to self._quantsim_params["config_file"].
    +        :param encoding_path: Path to parameter encodings file.
    +        :return: Quantsim model.
    +        """
    +        if output_bw is not None:
    +            assert output_bw <= 32
    +
    +        if param_bw is not None:
    +            assert param_bw <= 32
    +
    +        if output_quant_scheme is None or param_quant_scheme is None:
    +            assert self._quantsim_params["quant_scheme"] is not None
    +
    +        model = copy.deepcopy(fp32_model)
    +        kwargs = dict(
    +            rounding_mode=(rounding_mode or self._quantsim_params["rounding_mode"]),
    +            default_activation_bw=(output_bw or self._quantsim_params["output_bw"]),
    +            default_param_bw=(param_bw or self._quantsim_params["param_bw"]),
    +            config_file=(config_file or self._quantsim_params["config_file"]),
    +            use_cuda=self._quantsim_params['use_cuda'],
    +            device=self._quantsim_params['device']
    +        )
    +        sim = QuantizationSimModel(model, self.dummy_input, **kwargs)
    +
    +        param_quantizers, activation_quantizers = sim.get_all_quantizers()
    +
    +        default_quant_scheme = self._quantsim_params.get("quant_scheme")
    +
    +        output_quant_scheme = output_quant_scheme or\
    +                              default_quant_scheme.output_quant_scheme
    +        output_percentile = output_percentile or default_quant_scheme.output_percentile
    +        param_quant_scheme = param_quant_scheme or\
    +                             default_quant_scheme.param_quant_scheme
    +        param_percentile = param_percentile or default_quant_scheme.param_percentile
    +
    +        # Set activation quantizers' quant schemes
    +        for quantizer in activation_quantizers:
    +            quantizer.set_quant_scheme(output_quant_scheme)
    +            # TODO: Enable once we figure out how to set percentile value in QcQuantizeOp's Tensor Quantizer
    +            # if quantizer.quant_scheme == QuantScheme.post_training_percentile and\
    +            #         output_percentile is not None:
    +            #     quantizer.set_percentile_value(output_percentile)
    +
    +        # Set param quantizers' quant schemes
    +        for quantizer in param_quantizers:
    +            quantizer.set_quant_scheme(param_quant_scheme)
    +            # TODO: Enable once we figure out how to set percentile value in QcQuantizeOp's Tensor Quantizer
    +            # if quantizer.quant_scheme == QuantScheme.post_training_percentile and\
    +            #         param_percentile is not None:
    +            #     quantizer.set_percentile_value(param_percentile)
    +
    +        if encoding_path:
    +            sim.set_and_freeze_param_encodings(encoding_path)
    +
    +        # Disable activation quantizers, using fp32 to simulate int32.
    +        if output_bw == 32:
    +            for quantizer in activation_quantizers:
    +                quantizer.enabled = False
    +
    +        # Disable param quantizers, using fp32 to simulate int32.
    +        if param_bw == 32:
    +            for quantizer in param_quantizers:
    +                quantizer.enabled = False
    +
    +        # Skip encoding computation if none of the quantizers are enabled
    +        if any(quantizer.enabled for quantizer in param_quantizers +\
    +                                                  activation_quantizers):
    +            sim.compute_encodings(self.forward_pass_callback, None)
    +
    +        return sim
    +
    +    @staticmethod
    +    @cache.mark("batchnorm_folding")
    +    def _apply_batchnorm_folding(model: ONNXModel)\
    +            -> Tuple[onnx.ModelProto, Tuple[List]]:
    +        """
    +        Apply batchnorm folding.
    +
    +        NOTE: Input model is not mutated.
    +
    +        :param model: Model to apply batchnorm folding.
    +        :return: Output model and folded pairs.
    +        """
    +        model = copy.deepcopy(model)
    +        conv_bns, bn_convs = fold_all_batch_norms_to_weight(model)
    +        return model, conv_bns + bn_convs
    +
    +    @staticmethod
    +    @cache.mark("cle")
    +    def _apply_cross_layer_equalization(model: ONNXModel) -> onnx.ModelProto:
    +        """
    +        Apply cross-layer equalization.
    +
    +        NOTE: Input model is not mutated.
    +
    +        :param model: Model to apply cross-layer-equalization.
    +        :return: Output model.
    +        """
    +        model = copy.deepcopy(model)
    +        equalize_model(model)
    +        return model
    +
    +    @cache.mark("adaround")
    +    def _apply_adaround(self, model: ONNXModel) -> Tuple[onnx.ModelProto, str]:
    +        """
    +        Apply adaround.
    +
    +        NOTE1: Input model is not mutated.
    +        NOTE2: Parameters `param_bw_override_list` and `ignore_quant_ops_list` are always set to None.
    +
    +        :param model: Model to apply adaround.
    +        :return: Output model and the path to the parameter encoding file.
    +        """
    +        filename_prefix = "adaround"
    +        adaround_encoding_path = os.path.join(self.results_dir,
    +                                              "{}.encodings".format(filename_prefix))
    +
    +        sim = self._create_quantsim_and_encodings(model)
    +
    +        _, activation_quantizers = sim.get_all_quantizers()
    +        for quantizer in activation_quantizers:
    +            quantizer.enabled = False
    +
    +        model = Adaround._apply_adaround(sim, model, self.adaround_params, # pylint: disable=protected-access
    +                                         path=self.results_dir, filename_prefix=filename_prefix)
    +
    +        return model, adaround_encoding_path
    +
    +    def _optimize_helper(
    +            self,
    +            optimize_fn: Callable,
    +            allowed_accuracy_drop: float) -> Tuple[ONNXModel, float, str]:
    +        """
    +        Integrate and apply post-training quantization techniques.
    +
    +        :param allowed_accuracy_drop: Maximum allowed accuracy drop
    +        :return: Tuple of (best model, eval score, encoding path)
    +        """
    +        allowed_accuracy_drop = float(allowed_accuracy_drop)
    +        if allowed_accuracy_drop < 0:
    +            raise ValueError(
    +                "`allowed_accuracy_drop` must be a positive value. Got {:.2f}"
    +                .format(allowed_accuracy_drop)
    +            )
    +
    +        self.eval_manager.clear()
    +
    +        try:
    +            with cache.enable(self.cache_dir):
    +                _logger.info("Starting AutoQuant")
    +
    +                if self._quantsim_params['use_cuda']:
    +                    providers = [('CUDAExecutionProvider', {'device_id': self._quantsim_params['device']}), 'CPUExecutionProvider']
    +                else:
    +                    providers = ['CPUExecutionProvider']
    +                fp32_model_session = QuantizationSimModel.build_session(self.fp32_model.model, providers)
    +                self._fp32_acc = self._evaluate_model_performance(fp32_model_session)
    +                target_acc = self._fp32_acc - allowed_accuracy_drop
    +                _logger.info("Target eval score: %f", target_acc)
    +                _logger.info("FP32 eval score (W32A32): %f", self._fp32_acc)
    +
    +                ret = optimize_fn(self.fp32_model, target_acc)
    +
    +                acc = ret["accuracy"]
    +                if acc is not None:
    +                    _logger.info("Best eval score: %f", acc)
    +
    +                    # Save the best model with "best_model_" as prefix
    +                    best_res = self.eval_manager.get_best_ptq_result()
    +                    best_res.save_result_as("best_model")
    +
    +                    if acc < target_acc:
    +                        _logger.info(
    +                            "AutoQuant is unable to match the target accuracy. "
    +                            "Consider Quantization Aware Training."
    +                        )
    +
    +                return ret
    +        finally:
    +            self.eval_manager.export_diagnostics()
    +
    +    def get_quant_scheme_candidates(self) -> Tuple[_QuantSchemePair, ...]:
    +        """
    +        Return the candidates for quant scheme search.
    +        During :meth:`~AutoQuant.optimize`, the candidate with the highest accuracy
    +        will be selected among them.
    +
    +        :return: Candidates for quant scheme search
    +        """
    +        return self._quant_scheme_candidates
    +
    +    def set_quant_scheme_candidates(self, candidates: Tuple[_QuantSchemePair, ...]):
    +        """
    +        Set candidates for quant scheme search.
    +        During :meth:`~AutoQuant.optimize`, the candidate with the highest accuracy
    +        will be selected among them.
    +
    +        :param candidates: Candidates for quant scheme search
    +        """
    +        self._quant_scheme_candidates = copy.copy(candidates)
    +
    +    def _choose_default_quant_scheme(self):
    +        def eval_fn(pair: _QuantSchemePair):
    +            sim = self._create_quantsim_and_encodings(
    +                self.fp32_model,
    +                param_quant_scheme=pair.param_quant_scheme,
    +                param_percentile=pair.param_percentile,
    +                output_quant_scheme=pair.output_quant_scheme,
    +                output_percentile=pair.output_percentile,
    +            )
    +            eval_score = self._evaluate_model_performance(sim.session)
    +            _logger.info("Evaluation finished: %s (eval score: %f)", pair, eval_score)
    +            return eval_score
    +
    +        param_bw = self._quantsim_params["param_bw"]
    +        output_bw = self._quantsim_params["output_bw"]
    +
    +        candidates = self.get_quant_scheme_candidates()
    +
    +        # If the weight representation has sufficient precision (i.e. bitwidth >= 16),
    +        # always use tf scheme
    +        if param_bw >= 16:
    +            candidates = [
    +                candidate for candidate in candidates
    +                if candidate.param_quant_scheme == QuantScheme.post_training_tf
    +            ]
    +
    +        # If the output representation has sufficient precision (i.e. bitwidth >= 16),
    +        # always use tf scheme
    +        if output_bw >= 16:
    +            candidates = [
    +                candidate for candidate in candidates
    +                if candidate.output_quant_scheme == QuantScheme.post_training_tf
    +            ]
    +
    +        # If we have only one candidate left, we don't need to evaluated
    +        # the quant scheme for comparison
    +        if len(candidates) == 1:
    +            return candidates[0]
    +
    +        assert candidates
    +
    +        # Find the quant scheme that yields the best eval score
    +        best_quant_scheme = max(candidates, key=eval_fn)
    +        _logger.info("Best Quant Scheme: %s", best_quant_scheme)
    +
    +        return best_quant_scheme
    +
    +    def _optimize_main(self, fp32_model: ONNXModel, target_acc: float):
    +        """
    +        Helper function of apply().
    +
    +        :param fp32_model: Model to apply PTQ techniques.
    +        :param target_acc: Target eval score.
    +
    +        :raises RuntimeError: If none of the PTQ techniques were finished successfully.
    +
    +        :return: The best ptq result as a dictionary.
    +        """
    +
    +        # Choose best quant scheme automatically.
    +        with self.eval_manager.session("QuantScheme Selection") as sess:
    +            self._quantsim_params["quant_scheme"] = sess.wrap(self._choose_default_quant_scheme)()
    +
    +        # Early exit
    +        with self.eval_manager.session("W32 Evaluation") as sess:
    +            w32_eval_score = sess.wrap(sess.eval)(fp32_model, param_bw=32)
    +            _logger.info("Evaluation finished: W32A%d (eval score: %f)",
    +                         self._quantsim_params["output_bw"], w32_eval_score)
    +
    +            if w32_eval_score < target_acc:
    +                _logger.info(
    +                    "W32A%d eval score (%f) is lower "
    +                    "than the target eval score (%f). This means it is unlikely that "
    +                    "the target eval score can be met using PTQ techniques. "
    +                    "Please consider finetuning the model using range learning.",
    +                    self._quantsim_params["output_bw"], w32_eval_score, target_acc
    +                )
    +
    +                # Since AutoQuant pipeline exited early, all the return values are set to None
    +                return {
    +                    "model": None,
    +                    "accuracy": None,
    +                    "encoding_path": None,
    +                    "applied_techniques": None,
    +                }
    +
    +            sess.result["target_satisfied"] = True
    +
    +        # Batchnorm Folding
    +        with self.eval_manager.session("Batchnorm Folding", ptq=True) as sess:
    +            model, _ = sess.wrap(self._apply_batchnorm_folding)(fp32_model)
    +            if sess.ptq_result is None:
    +                sess.set_ptq_result(model=model,
    +                                    applied_techniques=["batchnorm_folding"])
    +
    +        best_result = self.eval_manager.get_best_ptq_result()
    +        if best_result and best_result.accuracy >= target_acc:
    +            sess.result["target_satisfied"] = True
    +            return best_result.as_dict()
    +
    +        # Cross-Layer Equalization
    +        with self.eval_manager.session("Cross-Layer Equalization", ptq=True) as sess:
    +            model = sess.wrap(self._apply_cross_layer_equalization)(fp32_model)
    +            if sess.ptq_result is None:
    +                sess.set_ptq_result(model=model,
    +                                    applied_techniques=["cross_layer_equalization"])
    +
    +        best_result = self.eval_manager.get_best_ptq_result()
    +        if best_result and best_result.accuracy >= target_acc:
    +            sess.result["target_satisfied"] = True
    +            return best_result.as_dict()
    +
    +        if best_result is None:
    +            model = fp32_model
    +            applied_techniques = []
    +        else:
    +            if "cross_layer_equalization" not in best_result.applied_techniques:
    +                sess.result["effective"] = False
    +            model = best_result.load_model()
    +            applied_techniques = best_result.applied_techniques
    +
    +        # AdaRound
    +        with self.eval_manager.session("AdaRound", ptq=True) as sess:
    +            model, encoding_path = sess.wrap(self._apply_adaround)(model)
    +            if sess.ptq_result is None:
    +                sess.set_ptq_result(model=model,
    +                                    encoding_path=encoding_path,
    +                                    applied_techniques=[*applied_techniques, "adaround"])
    +
    +        best_result = self.eval_manager.get_best_ptq_result()
    +        if best_result:
    +            if "adaround" not in best_result.applied_techniques:
    +                sess.result["effective"] = False
    +            if best_result.accuracy >= target_acc:
    +                sess.result["target_satisfied"] = True
    +            return best_result.as_dict()
    +
    +        raise RuntimeError("None of Batchnorm Folding, CLE, or Adaround "
    +                           "has been finished successfully.")
    +
    +
    +@dataclass
    +class PtqResult:
    +    """
    +    Evaluation results.
    +    :param tag: Identifier string of the evaluation result.
    +    :param model_path: Path to the serialized model.
    +    :param encoding_path: Path to the encoding file.
    +    :param accuracy: Accuracy of the model.
    +    """
    +    model_path: str
    +    encoding_path: str
    +    accuracy: float
    +    applied_techniques: List[str]
    +
    +    def load_model(self) -> ONNXModel:
    +        """
    +        Load model.
    +        :return: Loaded model.
    +        """
    +        return ONNXModel(onnx.load(self.model_path))
    +
    +    def as_dict(self):
    +        """Convert to dictionary"""
    +        return dict(model=self.load_model(),
    +                    accuracy=self.accuracy,
    +                    encoding_path=self.encoding_path,
    +                    applied_techniques=self.applied_techniques)
    +
    +    def save_result_as(self, prefix: str = "best_model"):
    +        """
    +        Creates the copy of the PTQ result files with the given prefix.
    +        :param prefix: prefix to be added to the file's basename
    +        """
    +        src_files = [self.model_path, self.encoding_path]
    +        for file in src_files:
    +            name = os.path.basename(file)
    +            dirname = os.path.dirname(file)
    +            dest = os.path.join(dirname, prefix + "_" + name)
    +            if os.path.exists(file):
    +                if os.path.exists(dest):
    +                    os.remove(dest)
    +                shutil.copyfile(file, dest)
    +
    +
    +class _EvalManager:
    +    """
    +    Evaluation manager for AutoQuant.
    +    """
    +    def __init__(self,
    +                 quantsim_factory: Callable,
    +                 eval_func: Callable[[ort.InferenceSession], float],
    +                 results_dir: str,
    +                 strict_validation: bool):
    +        """
    +        :param quantsim_factory: A factory function that returns QuantizationSimModel.
    +        :param eval_func: Evaluation function.
    +        :param results_dir: Base directory to save the temporary serialized model.
    +        """
    +        self._quantsim_factory = quantsim_factory
    +        self._eval_func = eval_func
    +        self._results_dir = results_dir
    +        self._strict_validation = strict_validation
    +
    +        os.makedirs(self._results_dir, exist_ok=True)
    +
    +        self._all_sessions = OrderedDict() # type: OrderedDict[str, _EvalSession]
    +
    +    def clear(self):
    +        """
    +        Clear all the session status saved in the previous run
    +        """
    +        for sess in self._all_sessions.values():
    +            sess.reset_status()
    +
    +    def get_best_ptq_result(self) -> Optional[PtqResult]:
    +        """
    +        Get the results with the highest evaluation score among the ptq results evaluated so far.
    +        :return: The best evaluation result so far.
    +        """
    +        # pylint: disable=protected-access
    +        ptq_results = [sess.ptq_result for sess in self._all_sessions.values()
    +                       if sess.ptq_result is not None and sess._ptq]
    +        if not ptq_results:
    +            return None
    +
    +        return max(ptq_results, key=lambda ptq_result: ptq_result.accuracy)
    +
    +    def session(self, title: str, ptq: bool = False):
    +        """
    +        Session factory.
    +        :param title: Title of the session.
    +        :param ptq: True if this session is a ptq session
    +        :return: Session object.
    +        """
    +        if title not in self._all_sessions:
    +            session = _EvalSession(title,
    +                                   self._quantsim_factory,
    +                                   self._eval_func,
    +                                   results_dir=os.path.join(self._results_dir, ".trace"),
    +                                   strict_validation=self._strict_validation,
    +                                   ptq=ptq)
    +            self._all_sessions[title] = session
    +        return self._all_sessions[title]
    +
    +    HTML_TEMPLATE_FILE = os.path.join(
    +        os.path.dirname(os.path.abspath(__file__)),
    +        "auto_quant_v2_diagnostics_template.html",
    +    )
    +
    +    def export_diagnostics(self) -> str:
    +        """
    +        Export diagnostics in html format.
    +        :return: Diagnostics string in html format.
    +        """
    +        loader = jinja2.FileSystemLoader(os.path.dirname(self.HTML_TEMPLATE_FILE))
    +        env = jinja2.Environment(loader=loader)
    +        template = env.get_template(os.path.basename(self.HTML_TEMPLATE_FILE))
    +
    +        if any(sess.diagnostics.contains_bokeh() for sess in self._all_sessions.values()):
    +            head = CDN.render()
    +        else:
    +            head = ""
    +
    +        log = io.StringIO()
    +        for sess in self._all_sessions.values():
    +            if sess.diagnostics.is_empty():
    +                continue
    +            log.write(
    +                f"<h1> {sess.title} </h1>\n"
    +            )
    +            content = "\n".join(
    +                line.get_html_elem() for line in sess.diagnostics
    +            )
    +            log.write(f"{content}\n")
    +
    +        result = OrderedDict()
    +        result["ptq_techniques"] = OrderedDict()
    +
    +        for sess in self._all_sessions.values():
    +            if sess.is_ptq_session():
    +                result["ptq_techniques"][sess.title_lowercase] = sess.result
    +            else:
    +                result[sess.title_lowercase] = sess.result
    +
    +        flowchart_metadata = _build_flowchart_metadata(result)
    +
    +        html = template.render(head=head, log=log.getvalue(), **flowchart_metadata)
    +
    +        filename = os.path.join(self._results_dir, "diagnostics.html")
    +        with open(filename, "w") as f:
    +            f.write(html)
    +        return html
    +
    +
    +class _EvalSession: # pylint: disable=too-many-instance-attributes
    +    """
    +    Evaluation session for AutoQuant.
    +
    +    Each session object contains a title and diagnostics produced during the session.
    +    The collected diagnostics will be exported into a html file by _EvalManager.
    +    """
    +    def __init__(
    +            self,
    +            title: str,
    +            quantsim_factory: Callable,
    +            eval_func: Callable[[ort.InferenceSession], float],
    +            results_dir: str,
    +            strict_validation: bool,
    +            ptq: bool,
    +    ):
    +        """
    +        :param title: Title of the session.
    +        :param quantsim_factory: A factory function that returns QuantizationSimModel.
    +        :param eval_func: Evaluation function.
    +        :param results_dir: Base directory to save the temporary serialized model.
    +        :param ptq: True if this session is a ptq session
    +        """
    +        self.title = title
    +        self._quantsim_factory = quantsim_factory
    +        self._eval_func = eval_func
    +        self._results_dir = results_dir
    +        self._strict_validation = strict_validation
    +        self._ptq = ptq
    +
    +        self._spinner = None
    +
    +        self.result = {
    +            "status": None,
    +            "error": None,
    +            "target_satisfied": False,
    +            "effective": True,
    +        }
    +
    +        os.makedirs(self._results_dir, exist_ok=True)
    +
    +        self.diagnostics = Diagnostics()
    +
    +        # Map session title to file name.
    +        # e.g. title: "Cross-Layer Equalization" -> filename: "cross_layer_equalization"
    +        self.title_lowercase = self.title.lower().replace("-", " ")
    +        self.title_lowercase = "_".join(self.title_lowercase.split())
    +
    +        stdout_write = sys.stdout.write
    +        self._log = io.StringIO()
    +
    +        # Redirects stdout to self._log
    +        def write_wrapper(*args, **kwargs):
    +            self._log.write(*args, **kwargs)
    +            return stdout_write(*args, **kwargs)
    +
    +        self._stdout_redirect = patch.object(sys.stdout, "write", write_wrapper)
    +        self._ptq_result = None
    +        self._cached_result = None
    +
    +    def is_ptq_session(self):
    +        """
    +        Getter method of self._ptq flag
    +        """
    +        return self._ptq
    +
    +    def reset_status(self):
    +        """
    +        Reset the session status saved in the previous run
    +        """
    +        self.result = {
    +            "status": None,
    +            "error": None,
    +            "target_satisfied": False,
    +            "effective": True,
    +        }
    +
    +    def wrap(self, fn):
    +        """
    +        Return a wrapper function that caches the return value.
    +
    +        :param fn: Function to wrap.
    +        :returns: Function whose return value is cached.
    +        """
    +        results_dir = self._results_dir
    +        class CachedResult:
    +            """Cached result """
    +            def __init__(self, obj):
    +                self._filename = os.path.join(results_dir, f".{uuid4()}")
    +                while os.path.exists(self._filename):
    +                    self._filename = os.path.join(results_dir, f".{uuid4()}")
    +                with open(self._filename, "wb") as f:
    +                    pickle.dump(obj, f)
    +
    +            def load(self):
    +                """Load cached result """
    +                with open(self._filename, "rb") as f:
    +                    return pickle.load(f)
    +
    +        @functools.wraps(fn)
    +        def wrapper(*args, **kwargs):
    +            if self._cached_result:
    +                return self._cached_result.load()
    +            ret = fn(*args, **kwargs)
    +            self._cached_result = CachedResult(ret)
    +            return ret
    +        return wrapper
    +
    +    def eval(self, model: ONNXModel, **kwargs):
    +        """
    +        Evaluate the model.
    +        :param model: Model to evaluate.
    +        :param **kwargs: Additional arguments to the quantsim factory.
    +        :return: Eval score.
    +        """
    +        sim = self._quantsim_factory(model, **kwargs)
    +        acc = self._eval_func(sim.session)
    +        return acc
    +
    +    def __enter__(self):
    +        self._spinner = Spinner(self.title)
    +        self._spinner.__enter__()
    +        self._stdout_redirect.start()
    +        return self
    +
    +    def __exit__(self, exc_type, exc_val, exc_tb):
    +        if self._ptq_result is not None:
    +            _logger.info("Session finished: %s. (eval score: %f). Applied techniques: %s",
    +                         self.title, self._ptq_result.accuracy, ' '.join(self._ptq_result.applied_techniques))
    +
    +        self._spinner.__exit__(exc_type, exc_val, exc_tb)
    +
    +        if exc_val:
    +            buffer = io.StringIO()
    +            traceback.print_exception(exc_type, exc_val, exc_tb, file=buffer)
    +
    +            if self._strict_validation:
    +                print(buffer.getvalue())
    +            else:
    +                print(
    +                    "################################################################\n"
    +                    "################################################################\n"
    +                    "################################################################\n"
    +                    "WARNING: The following exception was raised but ignored:\n\n"
    +                    f"{buffer.getvalue()}"
    +                    "################################################################\n"
    +                    "################################################################\n"
    +                    "################################################################\n"
    +                )
    +
    +        self._stdout_redirect.stop()
    +        self.diagnostics.add(self._log.getvalue())
    +
    +        self.result["error"] = exc_val
    +        if not exc_val:
    +            self.result["status"] = "success"
    +        elif self._strict_validation:
    +            self.result["status"] = "error-failed"
    +        else:
    +            self.result["status"] = "error-ignored"
    +
    +        if exc_val and not self._strict_validation:
    +            # Return True so that the error doesn't propagate further
    +            return True
    +        return None
    +
    +    @property
    +    def ptq_result(self) -> Optional[PtqResult]:
    +        """Getter of self._ptq_result."""
    +        return self._ptq_result
    +
    +    def set_ptq_result(
    +            self,
    +            applied_techniques: List[str],
    +            model: onnx.ModelProto = None,
    +            sim: QuantizationSimModel = None,
    +            acc: float = None,
    +            **kwargs
    +    ) -> None:
    +        """
    +        Set the result of PTQ. Should be called exactly once inside a with-as block.
    +
    +        Exactly one among model and (sim, acc) pair should be specified.
    +        1) If sim and acc is specified, save them as the result of this session.
    +        2) If model is specified, evaluate the quantized accuracy of the model and save the result.
    +
    +        :param model: Result of PTQ.
    +        :param sim: Result of PTQ. The quamtization encoding (compute_encodings()) is
    +                    assumed to have been computed in advance.
    +        :param acc: Eval score.
    +        :param **kwargs: Additional arguments to the quantsim factory.
    +        :return: None
    +        """
    +
    +        if sim is None:
    +            assert acc is None
    +            assert model is not None
    +            sim = self._quantsim_factory(model, **kwargs)
    +            acc = self._eval_func(sim.session)
    +        else:
    +            assert acc is not None
    +            assert model is None
    +
    +        self._set_ptq_result(sim, acc, applied_techniques)
    +
    +    def _set_ptq_result(
    +            self,
    +            sim: QuantizationSimModel,
    +            acc: float,
    +            applied_techniques: List[str],
    +    ) -> PtqResult:
    +        """
    +        Set the result of PTQ. Should be called exactly once inside a with-as block.
    +
    +        :param sim: Result of PTQ. The quamtization encoding (compute_encodings()) is
    +                    assumed to have been computed in advance.
    +        :param acc: Eval score.
    +        :return: PtqResult object.
    +        """
    +        if self._ptq_result is not None:
    +            raise RuntimeError(
    +                "sess.eval() can be called only once per each _EvalSession instance."
    +            )
    +
    +        model_path, encoding_path = self._export(sim)
    +        self._ptq_result = PtqResult(
    +            model_path=model_path,
    +            encoding_path=encoding_path,
    +            accuracy=acc,
    +            applied_techniques=applied_techniques,
    +        )
    +        return self._ptq_result
    +
    +    def _export(self, sim: QuantizationSimModel) -> Tuple[str, str]:
    +        """
    +        Export quantsim.
    +        :param sim: QuantizationSimModel object to export.
    +        :return: The paths where model and encoding are saved
    +        """
    +        sim.export(path=self._results_dir,
    +                   filename_prefix=self.title_lowercase)
    +        model_path = os.path.join(self._results_dir, f"{self.title_lowercase}.onnx")
    +        encoding_path = os.path.join(self._results_dir, f"{self.title_lowercase}.encodings")
    +        _logger.info("The results of %s is saved in %s and %s.",
    +                     self.title, model_path, encoding_path)
    +        return model_path, encoding_path
    +
    +
    +def _build_flowchart_metadata(result: Mapping) -> Dict: # pylint: disable=too-many-return-statements
    +    """
    +    Build flowchart metadata for the html template of summary report
    +
    +    :param result: Result of AutoQuant with the following format:
    +
    +        result := {
    +            "quantscheme_selection": _stage_result,
    +            "w32_evaluation": _stage_result,
    +            "ptq_techniques" [
    +                "batchnorm_folding": _stage_result,
    +                "cross_layer_equalization": _stage_result,
    +                "adaround": _stage_result,
    +            ]
    +
    +        }
    +
    +        where _stage_result is a dictionary defined as below:
    +
    +        _stage_result := {
    +            "status": str,
    +            "error": Exception,
    +            "target_satisfied": bool,
    +            "effective": bool,
    +        }
    +
    +    :return: Dictionary that contains flowchart metadata for html template
    +    """
    +    metadata = defaultdict(str)
    +    metadata.update(
    +        edge_quant_scheme_selection_in='data-visited="true"',
    +    )
    +    if "quantscheme_selection" in result:
    +        status = result['quantscheme_selection']['status']
    +        metadata.update(
    +            node_quant_scheme_selection=f'data-visited="true" data-stage-result="{status}"',
    +        )
    +
    +        if status == 'error-failed':
    +            return metadata
    +
    +    metadata.update(
    +        edge_quant_scheme_selection_out='data-visited="true"',
    +        node_test_w32_eval_score='data-visited="true"',
    +    )
    +
    +    if not result["w32_evaluation"]["target_satisfied"]:
    +        metadata.update(
    +            edge_test_w32_eval_score_if_false='data-visited="true"',
    +            node_result_fail='data-visited="true"',
    +        )
    +        return metadata
    +
    +    metadata.update(
    +        edge_test_w32_eval_score_if_true='data-visited="true"',
    +    )
    +
    +    for ptq_name, ptq_result in result["ptq_techniques"].items():
    +        status = ptq_result['status']
    +        effective = ptq_result['effective']
    +        if status == "success" and not effective:
    +            status = "discarded"
    +        metadata.update({
    +            f"node_{ptq_name}": f'data-visited="true" data-stage-result="{status}"',
    +        })
    +
    +        if status == 'error-failed':
    +            return metadata
    +
    +        metadata.update({
    +            f'edge_{ptq_name}_out': 'data-visited="true"',
    +            f'node_test_{ptq_name}': 'data-visited="true"',
    +        })
    +
    +        if ptq_result['target_satisfied']:
    +            metadata.update({
    +                f'edge_test_{ptq_name}_if_true': 'data-visited="true"',
    +                'node_result_success': 'data-visited="true"',
    +            })
    +            return metadata
    +
    +        metadata.update({
    +            f'edge_test_{ptq_name}_if_false': 'data-visited="true"',
    +        })
    +
    +    metadata.update(
    +        node_result_fail='data-visited="true"',
    +    )
    +
    +    return metadata
    +
    +ParetoFrontType = List[Tuple[int, float, QuantizerGroup, Tuple]]
    +
    +
    +@dataclass
    +class _MixedPrecisionArgs:
    +    """
    +    Mixed-precision specific arguments.
    +    """
    +    candidates: List[AmpCandidate]
    +    forward_pass_callback: CallbackFunc
    +    eval_callback_factory: EvalCallbackFactory
    +    num_samples_for_phase_1: int
    +    eval_callback_for_phase2: CallbackFunc
    +
    +
    +@dataclass
    +class _MixedPrecisionResult:
    +    """
    +    Mixed precision result
    +    """
    +    pareto_list: ParetoFrontType
    +    sim: QuantizationSimModel
    +    final_eval_score: float
    +    sensitivity_plot: bokeh.plotting.figure
    +    pareto_plot: bokeh.plotting.figure
    +
    +
    +# The number of samples to be used for performance evaluation and AMP.
    +# NOTE: None means "all".
    +DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_1 = EvalCallbackFactory._DEFAULT_SQNR_NUM_SAMPLES
    +DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_2 = None
    +
    +
    +
    +[docs] +class AutoQuantWithAutoMixedPrecision: + """ + Integrate and apply post-training quantization techniques. + + AutoQuant includes 1) batchnorm folding, 2) cross-layer equalization, + 3) Adaround, and 4) Automatic Mixed Precision (if enabled). + These techniques will be applied in a best-effort manner until the model + meets the evaluation goal given as allowed_accuracy_drop. + """ + def __init__( # pylint: disable=too-many-arguments, too-many-locals + self, + model: ONNXModel, + dummy_input: Dict[str, np.ndarray], + data_loader: DataLoader, + eval_callback: Callable[[ort.InferenceSession, int], float], + param_bw: int = 8, + output_bw: int = 8, + quant_scheme: QuantScheme = QuantScheme.post_training_tf_enhanced, + rounding_mode: str = 'nearest', + use_cuda: bool = True, + device: int = 0, + config_file: str = None, + results_dir: str = "/tmp", + cache_id: str = None, + strict_validation: bool = True) -> None: + """ + :param model: Model to be quantized. + :param dummy_input: Dummy input dict for the model. + :param data_loader: A collection that iterates over an unlabeled dataset, used for computing encodings + :param eval_callback: Function that calculates the evaluation score given the model session + :param param_bw: Parameter bitwidth + :param output_bw: Output bitwidth + :param quant_scheme: Quantization scheme + :param rounding_mode: Rounding mode + :param use_cuda: True if using CUDA to run quantization op. False otherwise. + :param config_file: Path to configuration file for model quantizers + :param results_dir: Directory to save the results of PTQ techniques + :param cache_id: ID associated with cache results + :param strict_validation: Flag set to True by default.When False, AutoQuant will proceed with execution and handle errors internally if possible. This may produce unideal or unintuitive results. + """ + self._auto_quant_base = AutoQuant(model=model, + dummy_input=dummy_input, + data_loader=data_loader, + eval_callback=eval_callback, + param_bw=param_bw, + output_bw=output_bw, + quant_scheme=quant_scheme, + rounding_mode=rounding_mode, + use_cuda=use_cuda, + device=device, + config_file=config_file, + results_dir=results_dir, + cache_id=cache_id, + strict_validation=strict_validation) + self._data_loader = data_loader + self._amp_args = None + +
    +[docs] + def run_inference(self) -> Tuple[QuantizationSimModel, float]: + ''' + Creates a quantization model and performs inference + + :return: QuantizationSimModel, model accuracy as float + ''' + return self._auto_quant_base.run_inference()
    + + +
    +[docs] + def optimize(self, allowed_accuracy_drop: float = 0.0)\ + -> Tuple[ONNXModel, float, str, ParetoFrontType]: + """ + Integrate and apply post-training quantization techniques. + + :param allowed_accuracy_drop: Maximum allowed accuracy drop + :return: Tuple of (best model, eval score, encoding path, pareto front). + Pareto front is None if AMP is not enabled or AutoQuant exits + without performing AMP. + """ + html_template_file = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "auto_quant_v2_diagnostics_template_with_amp.html", + ) + with patch.object(_EvalManager, "HTML_TEMPLATE_FILE", html_template_file): + result = self._auto_quant_base._optimize_helper(self._optimize_main, + allowed_accuracy_drop) + return result["model"],\ + result["accuracy"],\ + result["encoding_path"],\ + result["pareto_list"]
    + + +
    +[docs] + def set_adaround_params(self, adaround_params: AdaroundParameters) -> None: + """ + Set Adaround parameters. + If this method is not called explicitly by the user, AutoQuant will use + `data_loader` (passed to `__init__`) for Adaround. + + :param adaround_params: Adaround parameters. + """ + self._auto_quant_base.set_adaround_params(adaround_params)
    + + + # pylint: disable=unused-argument +
    +[docs] + def set_mixed_precision_params( + self, + candidates: List[CANDIDATE_WITH_DTYPE], + num_samples_for_phase_1: Optional[int] = DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_1, + forward_fn: Callable = _default_forward_fn, + num_samples_for_phase_2: Optional[int] = DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_2, + ) -> None: + """ + Set mixed precision parameters. + NOTE: Automatic mixed precision will NOT be enabled unless this method + is explicitly called by the user. + + :param candidates: List of tuples of candidate bitwidths and datatypes. + :param num_samples_for_phase_1: Number of samples to be used for performance + evaluation in AMP phase 1. + :param forward_fn: Function that runs forward pass and returns the output tensor. + which will be used for SQNR compuatation in phase 1. + This function is expected to take 1) a model and 2) a single batch + yielded from the data loader, and return a single np.ndarray object + which represents the output of the model. + :param num_samples_for_phase_2: Number of samples to be used for performance + evaluation in AMP phase 2. + """ + if len(candidates) < 2: + raise ValueError(f"AMP requires at least two candidates. Got {len(candidates)}.") + + baseline_param_bw = self._auto_quant_base._quantsim_params["param_bw"] + baseline_output_bw = self._auto_quant_base._quantsim_params["output_bw"] + baseline_candidate = ( + (baseline_output_bw, QuantizationDataType.int), + (baseline_param_bw, QuantizationDataType.int), + ) + + if baseline_candidate not in candidates: + raise ValueError( + f"AMP candidate must contain W{baseline_param_bw}A{baseline_output_bw}, " + "which was passed to the constructor of AutoQuant as `param_bw` and `output_bw`." + ) + + for candidate in candidates: + ((output_bw, output_dtype), (param_bw, param_dtype)) = candidate + + if output_dtype != param_dtype: + raise ValueError( + "The data types of parameters and outputs should be the same. " + f"Got {output_dtype} output and {param_dtype} for parameter." + ) + + if output_dtype == QuantizationDataType.float: + continue + + # The param/output_bw passed to the constructor of AutoQuant + # must be the baseline-bitwidth candidate among all AMP candidates. + if output_bw < baseline_output_bw or param_bw < baseline_param_bw: + raise ValueError( + "All AMP candidates should be strictly superior to the baseline " + f"W{baseline_param_bw}A{baseline_output_bw}, which was passed " + "to the constructor of AutoQuant. Please make sure that all the INT candidates " + f"satisfy param_bw >= {baseline_param_bw} and output_bw >= {baseline_param_bw}." + ) + + factory = EvalCallbackFactory(self._data_loader, forward_fn=forward_fn) + + candidates = [AmpCandidate(candidate) for candidate in set(candidates)] + + self._amp_args = _MixedPrecisionArgs( + candidates=candidates, + forward_pass_callback=CallbackFunc(self._auto_quant_base.forward_pass_callback, None), + eval_callback_factory=factory, + num_samples_for_phase_1=num_samples_for_phase_1, + eval_callback_for_phase2=CallbackFunc(self._auto_quant_base.eval_callback, + num_samples_for_phase_2) + )
    + + +
    +[docs] + def get_quant_scheme_candidates(self) -> Tuple[_QuantSchemePair, ...]: + """ + Return the candidates for quant scheme search. + During :meth:`~AutoQuant.optimize`, the candidate with the highest accuracy + will be selected among them. + + :return: Candidates for quant scheme search + """ + return self._auto_quant_base.get_quant_scheme_candidates()
    + + +
    +[docs] + def set_quant_scheme_candidates(self, candidates: Tuple[_QuantSchemePair, ...]): + """ + Set candidates for quant scheme search. + During :meth:`~AutoQuant.optimize`, the candidate with the highest accuracy + will be selected among them. + + :param candidates: Candidates for quant scheme search + """ + # pylint: disable=no-member + return self._auto_quant_base.set_quant_scheme_candidates(candidates)
    + + + def _apply_mixed_precision( + self, + model: ONNXModel, + target_acc: float, + amp_args: _MixedPrecisionArgs, + results_dir: str, + encoding_path: str = None, + ) -> _MixedPrecisionResult: + """ + Apply mixed-precision and return the highest accuracy. + + NOTE1: Input model is not mutated. + NOTE2: Parameter `clean_start` is always set to True. + + :param model: Model to apply mixed precision. + :param target_acc: Minimum evaluation score required. + :param encoding_path: Path to parameter encodings file. + :param results_dir: Directory to save the results of AdaRound and mixed precision. + :return: MixedPrecisionAlgo object. + """ + if not amp_args: + raise RuntimeError + + sim = self._auto_quant_base._create_quantsim_and_encodings(model, + encoding_path=encoding_path) + + eval_callback_for_phase1 = amp_args.eval_callback_factory.sqnr(sim=sim, num_samples=amp_args.num_samples_for_phase_1) + + algo = GreedyMixedPrecisionAlgo( + sim, + amp_args.candidates, + eval_callback_for_phase1, + amp_args.eval_callback_for_phase2, + results_dir=results_dir, + clean_start=True, + forward_pass_callback=amp_args.forward_pass_callback + ) + + # Find baseline accuracy and bw corresponding to baseline accuracy + algo.set_baseline(fp32_accuracy=self._auto_quant_base._fp32_acc) + allowed_accuracy_drop = algo.fp32_accuracy - target_acc + + algo.run(allowed_accuracy_drop) + + sensitivity_plot = None + if algo.accuracy_list is not None: + # Visualize quantizer group sensitivity + sensitivity_plot = create_sensitivity_plot(algo.accuracy_list, + algo.baseline_candidate, + algo.fp32_accuracy) + + pareto_plot = None + if algo.pareto_list is not None: + # Create pareto list curve + pareto_plot = create_pareto_curve(algo.pareto_list) + + return _MixedPrecisionResult(algo.pareto_list, + algo._sim, + algo._final_eval_score, + sensitivity_plot, + pareto_plot) + + def _optimize_main(self, fp32_model: ONNXModel, target_acc: float) -> Dict[str, Any]: + """ + Helper function of apply(). + + :param fp32_model: Model to apply PTQ techniques. + :param target_acc: Target eval score. + :return: The best ptq result as a dictionary. + """ + # pylint: disable=broad-except, too-many-locals, too-many-statements, too-many-branches + + if self._amp_args: + candidates = copy.copy(self._amp_args.candidates) + else: + candidates = [] + + eval_manager = self._auto_quant_base.eval_manager + results_dir = self._auto_quant_base.results_dir + strict_validation = eval_manager._strict_validation + + sess = eval_manager.session("") + _multiconfig_adaround_fn = _adaround_wrapper(self._auto_quant_base._apply_adaround, + self._auto_quant_base, + candidates, + target_acc, + sess.eval) + sess_eval_fn = _EvalSession.eval + def eval_fn(_, model, param_bw=None, output_bw=None, **kwargs): + if param_bw == 32: + # For W32 evaluation, use the highest output bitwidth + # among all the AMP candidates + output_bitwidths = [ + output_bw for (output_bw, output_dtype), _ in candidates + if output_dtype == QuantizationDataType.int + ] + output_bitwidths.append(self._auto_quant_base._quantsim_params["output_bw"]) + output_bw = max(output_bitwidths) + return sess_eval_fn(_, model, param_bw=param_bw, output_bw=output_bw, **kwargs) + + with patch.object(self._auto_quant_base, "_apply_adaround", _multiconfig_adaround_fn),\ + patch.object(_EvalSession, "eval", eval_fn): + try: + result = self._auto_quant_base._optimize_main(fp32_model, target_acc) + + # Automatic Mixed Precision + result["pareto_list"] = None + + # An empty `result` dict means AutoQuant early-exited + # because W32 eval score didn't meet the target accuracy. + # In this case, do not proceed to AMP and exit immediately. + if result["model"] is None and\ + result["accuracy"] is None and\ + result["encoding_path"] is None and\ + result["applied_techniques"] is None: + return result + + if result["accuracy"] >= target_acc or not self._amp_args: + return result + + if len(candidates) < 2: + _logger.info( + "After Adaround, we have only one Adarond-compatible candidate left for AMP (W%dA%d). " + "Return without proceeding to AMP", candidates[0].param_bw, candidates[0].output_bw + ) + return result + + model = result["model"] + applied_techniques = result["applied_techniques"] + # Freeze weight encoding to adaround weight encoding + encoding_path = result["encoding_path"] if "adaround" in applied_techniques else None + except Exception: + if strict_validation: + raise + result = {} + model = fp32_model + applied_techniques = [] + encoding_path = None + + amp_args = copy.copy(self._amp_args) + if amp_args: + amp_args.candidates = candidates + + with eval_manager.session("Automatic Mixed Precision", ptq=True) as sess: + amp_result = self._apply_mixed_precision( + model, target_acc, amp_args, results_dir, encoding_path=encoding_path + ) + result["pareto_list"] = amp_result.pareto_list + + if amp_result.sensitivity_plot is not None: + sess.diagnostics.add(amp_result.sensitivity_plot) + + if amp_result.pareto_plot is not None: + sess.diagnostics.add(amp_result.pareto_plot) + + sess.set_ptq_result(sim=amp_result.sim, acc=amp_result.final_eval_score, + applied_techniques=[*applied_techniques, "automatic_mixed_precision"]) + + best_result = eval_manager.get_best_ptq_result() + if best_result: + if "automatic_mixed_precision" not in best_result.applied_techniques: + sess.result["effective"] = False + if best_result.accuracy >= target_acc: + sess.result["target_satisfied"] = True + result.update(best_result.as_dict()) + return result + + raise RuntimeError("None of Batchnorm folding, CLE, Adaround or AMP " + "has been finished successfully.")
    + + +def _adaround_wrapper(apply_adaround_fn: Callable, + auto_quant: AutoQuant, + amp_candidates: List[AmpCandidate], + target_acc: float, + eval_fn: Callable): + @functools.wraps(apply_adaround_fn) + def _apply_adaround_wrapper(*args, **kwargs): # pylint: disable=too-many-locals + # If AMP candidates are empty (i.e. AMP is disabled), + # perform normal (single-round) adaround. + if not amp_candidates: + return apply_adaround_fn(*args, **kwargs) + + def apply_adaround(param_bw: int): + _logger.info("Running Adaround with W%d", param_bw) + + orig_param_bw = auto_quant._quantsim_params["param_bw"] + try: + auto_quant._quantsim_params["param_bw"] = param_bw + return apply_adaround_fn(*args, **kwargs) + finally: + auto_quant._quantsim_params["param_bw"] = orig_param_bw + + int_candidates = [ + candidate for candidate in amp_candidates + if candidate.param_dtype == QuantizationDataType.int + ] + sorted_int_candidates = sorted(int_candidates, + key=lambda candidate: (candidate.param_bw, candidate.output_bw)) + # Run Adaround with the lowest-bitwidth candidate + lowest_candidate = sorted_int_candidates[0] + model, encoding_path = apply_adaround(param_bw=lowest_candidate.param_bw) + + # If the lowest candidate is the only INT candidate, return immediately + if len(sorted_int_candidates) == 1: + return model, encoding_path + + eval_score = eval_fn(model, + param_bw=lowest_candidate.param_bw, + output_bw=lowest_candidate.output_bw, + encoding_path=encoding_path) + _logger.info("W%dA%d eval score after Adaround: %f", + lowest_candidate.param_bw, + lowest_candidate.output_bw, + eval_score) + + # If the lowest candidate satisfy the target accuracy, return immediately + if eval_score >= target_acc: + return model, encoding_path + + # If the lowest candidate fails to meet the target accuracy, + # discard the lowest candidate, apply Adaround to the second-lowest candidate, + # and use it as the baseline for AMP. + second_lowest_candidate = sorted_int_candidates[1] + + if second_lowest_candidate.param_bw != lowest_candidate.param_bw: + model = None + model, encoding_path = apply_adaround(param_bw=second_lowest_candidate.param_bw) + eval_score = eval_fn(model, + param_bw=second_lowest_candidate.param_bw, + output_bw=second_lowest_candidate.output_bw, + encoding_path=encoding_path) + _logger.info("W%dA%d eval score after Adaround: %f", + second_lowest_candidate.param_bw, + second_lowest_candidate.output_bw, + eval_score) + + # Only the candidates that are compatible with adaround can be used for AMP + adaround_compatible_amp_candidates = [ + candidate for candidate in amp_candidates + if candidate.param_bw == second_lowest_candidate.param_bw or\ + candidate.param_dtype == QuantizationDataType.float + ] + + # Fill in AMP candidates with Adaround-compatible candidates only + amp_candidates.clear() + amp_candidates.extend(adaround_compatible_amp_candidates) + + return model, encoding_path + + return _apply_adaround_wrapper +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_onnx/batch_norm_fold.html b/releases/2.0.0/_modules/aimet_onnx/batch_norm_fold.html new file mode 100644 index 0000000..fc7f3c1 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_onnx/batch_norm_fold.html @@ -0,0 +1,817 @@ + + + + + + + + aimet_onnx.batch_norm_fold - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_onnx.batch_norm_fold

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +""" ONNX Code to fold batch-norm layers """
    +
    +from typing import Dict, List, Tuple
    +import contextlib
    +import numpy as np
    +import onnx
    +from onnx import numpy_helper
    +from onnxruntime.quantization.onnx_quantizer import ONNXModel
    +from packaging import version
    +
    +# pylint: disable=wrong-import-order
    +from aimet_common.bias_correction import ConvBnPatternHandler
    +from aimet_common.graph_pattern_matcher import PatternType
    +from aimet_common.graph_searcher import GraphSearcher
    +from aimet_common.connected_graph.connectedgraph_utils import get_ordered_ops
    +import aimet_common.libpymo as libpymo
    +from aimet_common.utils import AimetLogger
    +
    +from aimet_onnx.meta.connectedgraph import ConnectedGraph
    +from aimet_onnx.meta.connectedgraph import WEIGHT_INDEX, BIAS_INDEX, RUNNING_MEAN_INDEX, RUNNING_VAR_INDEX
    +from aimet_onnx.meta.operations import Op
    +from aimet_onnx.utils import get_node_attribute, remove_node, transpose_tensor, ParamUtils, retrieve_constant_input
    +
    +# pylint: disable=no-name-in-module, ungrouped-imports
    +if version.parse(onnx.__version__) >= version.parse("1.14.0"):
    +    from onnx import NodeProto, TensorProto, ModelProto
    +else:
    +    from onnx.onnx_pb import NodeProto, TensorProto, ModelProto
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.BatchNormFolding)
    +
    +ConvType = ['Conv', 'ConvTranspose']
    +LinearType = ['Gemm', 'MatMul']
    +BatchNormType = ['BatchNormalization']
    +
    +class BNLayer:
    +    """ Captures beta and gamma parameter for BatchNorm layers to be used during High Bias absorption """
    +    def __init__(self):
    +        self.bn_layer = None
    +        self.gamma = None
    +        self.beta = None
    +
    +
    +def _find_conv_bn_pairs(connected_graph: ConnectedGraph) -> Dict:
    +    """
    +    Uses searcher to find preceding and next bn layers for a conv/linear layer
    +    :param connected_graph: ConnectedGraph object.
    +    :return: dictionary of conv/linear Op with associated bn op / activation info
    +    """
    +
    +    # initialize all patterns to be matched and associated call back functions
    +    patterns_with_callbacks = []
    +    layer_select_handler = ConvBnPatternHandler()
    +    preceding_linear_op_types = ['Flatten', 'Reshape']
    +
    +    # Linear layer combinations
    +    for linear_op in LinearType:
    +        for preceding_linear_op_type in preceding_linear_op_types:
    +            # BN -> Linear
    +            patterns_with_callbacks.append(PatternType(pattern=['BatchNormalization', preceding_linear_op_type, linear_op],
    +                                                       action=layer_select_handler))
    +
    +    for op_type in ConvType + LinearType:
    +        patterns_with_callbacks.append(PatternType(pattern=['BatchNormalization', op_type],
    +                                                   action=layer_select_handler))
    +        patterns_with_callbacks.append(PatternType(pattern=[op_type, 'BatchNormalization'],
    +                                                   action=layer_select_handler))
    +
    +    # create graph searcher instance with connected graph and patterns to search
    +    graph_searcher = GraphSearcher(connected_graph, patterns_with_callbacks)
    +
    +    # get all conv/linear and bn info
    +    graph_searcher.find_all_patterns_in_graph_apply_actions()
    +    convs_bn_activation_dict = layer_select_handler.get_conv_linear_bn_info_dict()
    +
    +    return convs_bn_activation_dict
    +
    +
    +def find_all_batch_norms_to_fold(connected_graph: ConnectedGraph,
    +                                 ) -> Tuple[List[Tuple[NodeProto, NodeProto]],
    +                                            List[Tuple[NodeProto, NodeProto]]]:
    +    """
    +    Find all possible batch norm layers that can be folded. Returns a list of pairs such that (bn, layer)
    +    means bn will be forward-folded into layer and (layer, bn) means bn will be backward-folded into layer
    +    :param connected_graph: connected graph model to search
    +    :return: A list of (layer, bn) pairs and a list of (bn, layer) pairs,
    +             where `bn` can be folded into to `layer`.
    +    """
    +    conv_linear_bn_activation_info_dict = _find_conv_bn_pairs(connected_graph)
    +    model = connected_graph.model
    +    # To mark BN's already picked for backward folding
    +    bn_picked_for_folding = set()
    +
    +    ordered_conv_fc_nodes = get_ordered_conv_linears(connected_graph)
    +
    +    conv_bn_pairs = []
    +    # Backward fold is given priority over Forward fold
    +    for node in ordered_conv_fc_nodes:
    +        # Filter out combinations that are not supported
    +        if node in conv_linear_bn_activation_info_dict.keys():
    +            bn_info = conv_linear_bn_activation_info_dict[node]
    +            if bn_info.output_bn and bn_info.output_bn not in bn_picked_for_folding:
    +                if is_valid_bn_fold(node.get_module(), model, True):
    +                    conv_bn_pairs.append((node.get_module(), bn_info.output_bn.get_module()))
    +                    bn_picked_for_folding.add(bn_info.output_bn)
    +                else:
    +                    logger.info('...... invalid combination to fold %s', [node.name, bn_info.output_bn.name])
    +
    +    bn_conv_pairs = []
    +    for node in ordered_conv_fc_nodes:
    +        # Filter out combinations that are not supported
    +        if node in conv_linear_bn_activation_info_dict.keys():
    +            bn_info = conv_linear_bn_activation_info_dict[node]
    +            if bn_info.input_bn and bn_info.input_bn not in bn_picked_for_folding:
    +                if is_valid_bn_fold(node.get_module(), model, False):
    +                    bn_conv_pairs.append((bn_info.input_bn.get_module(), node.get_module()))
    +                    bn_picked_for_folding.add(bn_info.input_bn)
    +                else:
    +                    logger.info('...... invalid combination to fold %s', [bn_info.input_bn.name, node.name])
    +
    +    return conv_bn_pairs, bn_conv_pairs
    +
    +
    +def get_ordered_conv_linears(conn_graph: ConnectedGraph) -> List[Op]:
    +    """
    +    helper to select a list of candidate layers for BatchNorm folding
    +    :param conn_graph: connected graph to search
    +    :return: List of conv/linear layers
    +    """
    +    # get ordered operations list from the connected graph
    +    list_of_ordered_ops = get_ordered_ops(conn_graph.starting_ops)
    +
    +    # look for conv/linear layers
    +    ordered_convs = []
    +    for op in list_of_ordered_ops:
    +        if op.type in ConvType + LinearType:
    +            ordered_convs.append(op)
    +    return ordered_convs
    +
    +
    +def is_valid_bn_fold(conv_linear: NodeProto, model: ModelProto, fold_backward: bool) -> bool:
    +    """
    +    Determine if a given layer can successfully absorb a BatchNorm given the layer type and parameters
    +    :param conv_linear: The Conv/Linear layer to fold a BatchNorm into.
    +    :param model: The model to which the Conv/Linear layer belongs.
    +    :param fold_backward: True if BatchNorm comes after Conv/Linear layer
    +    :return: True if a BatchNorm layer can be folded without causing output error.
    +    """
    +    valid = True
    +    if conv_linear.op_type in LinearType:
    +        # Check if this is actually a fully connected layer or a dynamic matmul
    +        w = retrieve_constant_input(conv_linear, model, WEIGHT_INDEX)[0]
    +        if w is None:
    +            valid = False
    +    if not fold_backward:
    +        # Cannot fold BN -> Conv with padding. AIMET does not support forward folding to grouped or DW Conv
    +        if conv_linear.op_type == 'Conv':
    +            valid &= all(item == 0 for item in get_node_attribute(conv_linear, "pads"))
    +            valid &= get_node_attribute(conv_linear, "group") == 1
    +        # AIMET does not support forward folding to ConvTranspose
    +        elif conv_linear.op_type == 'ConvTranspose':
    +            valid = False
    +    else:
    +        # AIMET does not support backwards folding to grouped ConvTranspose
    +        if conv_linear.op_type == 'ConvTranspose':
    +            valid &= get_node_attribute(conv_linear, "group") in (1, get_input_output_channels(conv_linear, model)[0])
    +    return valid
    +
    +
    +
    +[docs] +def fold_all_batch_norms_to_weight(model: ModelProto) -> [List]: + """ + Fold all possible batch_norm layers in a model into the weight of the corresponding conv layers + + :param model: onnx Model to perform BN fold on + :return: A list of pairs of layers [(Conv/Linear, BN layer that got folded)] + """ + if isinstance(model, ONNXModel): + model = model.model + connected_graph = ConnectedGraph(model) + model = connected_graph.model + conv_bn_pairs, bn_conv_pairs = find_all_batch_norms_to_fold(connected_graph) + conv_bns = [] + bn_convs = [] + for conv, bn in conv_bn_pairs: + bn_layer = _fold_to_weight(model, conv, bn, True) + conv_bns.append((conv, bn_layer)) + remove_node(bn, model.graph) + + for bn, conv in bn_conv_pairs: + bn_layer = _fold_to_weight(model, conv, bn, False) + bn_convs.append((conv, bn_layer)) + remove_node(bn, model.graph) + + _update_standalone_batchnorm_ops(model) + + return conv_bns, bn_convs
    + + + +def _fold_to_weight(model: ModelProto, + conv_linear: NodeProto, + bn: NodeProto, + fold_backward: bool): + """ + Fold BatchNorm into the weight and bias of the given layer. + + :param model: onnx model to which the conv/bn pair belong + :param conv_linear: Conv or linear layer to fold BN into. + :param bn: BatchNorm to fold. + :param fold_backward: True if the BatchNorm comes after the Conv + """ + # Must convert MatMul layers to Gemm to allow bias + if conv_linear.op_type == "MatMul": + _matmul_to_gemm(conv_linear, model) + + weight = ParamUtils.get_param(model, conv_linear, WEIGHT_INDEX) + bias = ParamUtils.get_param(model, conv_linear, BIAS_INDEX) + groups = get_node_attribute(conv_linear, "group") + + # If layer doesn't have bias, create a bias initializer and add it to the model, then retrieve it + if not bias: + bias_data = np.zeros(get_input_output_channels(conv_linear, model)[1]) + bias_name = conv_linear.name + ".bias" + bias = numpy_helper.from_array(bias_data.astype(np.float32), name=bias_name) + model.graph.initializer.append(bias) + conv_linear.input.append(bias_name) + bias = ParamUtils.get_param(model, conv_linear, BIAS_INDEX) + + # Transpose weights to C, N, H, W from N, C, H, W since axis are flipped for transposed conv + # However depthwise conv layers are always N, 1, H, W whether transposed-conv or not, so no need to transpose + # if conv_linear.type == "ConvTranspose" and conv_linear groups == 1: + if conv_linear.op_type == "ConvTranspose" and groups == 1: + weight = transpose_tensor(weight, (1, 0, 2, 3)) + # Gemm layers may or may not need to have weights transposed depending on value of transB attribute + elif conv_linear.op_type in LinearType and not get_node_attribute(conv_linear, "transB"): + weight = transpose_tensor(weight, (1, 0)) + + channels = weight.dims[0] if fold_backward else weight.dims[1] + bn_param = get_bn_params(model, bn, channels) + bn_layer = copy_bn_params_to_bn_layer(bn, bn_param) + + _call_mo_batch_norm_fold(weight, bias, bn_param, fold_backward=fold_backward) + + # Transpose weight back to original configuration + if conv_linear.op_type == "ConvTranspose" and groups == 1: + weight = transpose_tensor(weight, (1, 0, 2, 3)) + elif conv_linear.op_type in LinearType and not get_node_attribute(conv_linear, "transB"): + weight = transpose_tensor(weight, (1, 0)) + + weight_param = ParamUtils.get_param(model, conv_linear, WEIGHT_INDEX) + weight_param.raw_data = weight.raw_data + return bn_layer + + +def _matmul_to_gemm(node: NodeProto, model: ModelProto): + """ + Convert MatMul node to Gemm and initialize bias to zeros + + :param node: MatMul node to convert to Gemm + :param model: model to which the node belongs + """ + assert node.op_type == "MatMul" + + weight, transposed = retrieve_constant_input(node, model, WEIGHT_INDEX) + if transposed: + node.input[WEIGHT_INDEX] = weight.name + model.graph.initializer.remove(weight) + weight = transpose_tensor(weight, (1, 0)) + model.graph.initializer.append(weight) + node.op_type = "Gemm" + node.name = node.name.replace("MatMul", "Gemm") + # Create bias vector for Gemm operation + bias_name = node.name + ".bias" + bias_data = np.zeros(weight.dims[1]) + bias = numpy_helper.from_array(bias_data.astype(np.float32), name=bias_name) + model.graph.initializer.append(bias) + node.input.append(bias_name) + + +def _call_mo_batch_norm_fold(weight: TensorProto, + bias: TensorProto, + bn_params: libpymo.BNParams, + fold_backward: bool): + """ + Calls C++ batch norm folding API. + + :param weight: Weight or scale tensor to fold BN into. + :param bias: Bias tensor to fold BN into. + :param bn_params: Batch Norm layer + :param fold_backward: True if BatchNorm comes after Conv/Linear layer + """ + weight_tensor = libpymo.TensorParams() + + weight_tensor.data = numpy_helper.to_array(weight).reshape(-1) + weight_tensor.shape = np.array(weight.dims) + + bias_tensor = libpymo.TensorParams() + + bias_tensor.data = numpy_helper.to_array(bias).reshape(-1) + bias_tensor.shape = np.array(bias.dims) + is_bias_valid = True + + with _expand_shape_to_4d(weight_tensor): + _bias = libpymo.fold(bn_params, weight_tensor, bias_tensor, is_bias_valid, fold_backward) + + bias.raw_data = np.asarray(_bias, dtype=np.float32).tobytes() + weight.raw_data = np.asarray(weight_tensor.data, dtype=np.float32).tobytes() + + +def get_bn_params(model: ModelProto, bn: NodeProto, channels: int) -> libpymo.BNParams: + """ + Returns the populated libpymo.BNParams object for the given BatchNormalization layer with + parameters repeated if necessary. + + :param model: model to which the bn layer belongs + :param bn: BatchNormalization layer to retrieve the parameters from + :param channels: The effective number of channels the BatchNorm layer operates on (needed for Gemm layers) + :return: libpymo.BNParams object for the input BatchNorm layer + """ + bn_params = libpymo.BNParams() + gamma = numpy_helper.to_array(ParamUtils.get_param(model, bn, WEIGHT_INDEX)).reshape(-1) + # In the case of BatchNorm2d -> Flatten -> Gemm, must resize the BN parameters to the Gemm input feature length + resize = channels / len(gamma) + bn_params.gamma = np.repeat(gamma, resize) + bn_params.beta = np.repeat(numpy_helper.to_array(ParamUtils.get_param(model, bn, BIAS_INDEX)).reshape(-1), resize) + bn_params.runningMean = np.repeat( + numpy_helper.to_array(ParamUtils.get_param(model, bn, RUNNING_MEAN_INDEX)).reshape(-1), resize) + runningVar = numpy_helper.to_array(ParamUtils.get_param(model, bn, RUNNING_VAR_INDEX)) + + epsilon = get_node_attribute(bn, "epsilon") + if epsilon is None: + epsilon = 1e-5 # Default onnx epsilon value + sigma = np.sqrt(runningVar + epsilon) + bn_params.runningVar = np.repeat(sigma.reshape(-1), resize) + + return bn_params + + +def copy_bn_params_to_bn_layer(bn: NodeProto, bn_params: libpymo.BNParams) -> BNLayer: + """ + Copies bn params to a BN layer which can be used later by High bias absorption + :param bn: BN layer + :param bn_params: libpymo.BNParams object for the BatchNorm layer + :return BNLayer object + """ + bn_layer = BNLayer() + bn_layer.bn_layer = bn + bn_layer.gamma = bn_params.gamma + bn_layer.beta = bn_params.beta + return bn_layer + + +@contextlib.contextmanager +def _expand_shape_to_4d(weight_tensor: libpymo.TensorParams): + """ Expand the shape of the weight into 4d. """ + dims = len(weight_tensor.shape) + + if dims > 4: + raise RuntimeError + + if dims == 4: + yield weight_tensor + + else: + orig_shape = weight_tensor.shape + _4d_shape = np.append(orig_shape, [1 for _ in range(4-dims)]).astype(int) + try: + weight_tensor.shape = _4d_shape + yield weight_tensor + finally: + weight_tensor.shape = orig_shape + + +def get_input_output_channels(node: NodeProto, model: ModelProto) -> Tuple[int, int]: + """ + Find the input and output channels of a given layer. + :param node: The node to find the input/output channels of + :param model: The onnx model to which the layers belong + :return: Tuple of (num channels in, num channels out) + """ + weight = ParamUtils.get_param(model, node, WEIGHT_INDEX) + groups = get_node_attribute(node, "group") + # If group atttribute does not exist in the node,then default is 1 + if not groups: + groups = 1 + if node.op_type == "Conv": + num_in_channels = weight.dims[1] * groups + num_out_channels = weight.dims[0] + elif node.op_type == "ConvTranspose": + num_in_channels = weight.dims[0] + num_out_channels = weight.dims[1] * groups + elif node.op_type == "Gemm": + transB = get_node_attribute(node, "transB") + if transB == 1: + num_out_channels = weight.dims[0] + num_in_channels = weight.dims[1] + else: + num_out_channels = weight.dims[1] + num_in_channels = weight.dims[0] + else: + num_out_channels = None + num_in_channels = None + return num_in_channels, num_out_channels + + +# pylint: disable=too-many-locals +def _update_standalone_batchnorm_ops(model: ModelProto): + """ + Update weight and bias of standalone batchnorm ops in the model. + :param model: onnx Model for which batchnorm parameters are to be updated. + """ + + for node in model.graph.node: + if node.op_type in BatchNormType: + + # get parameter names and indices + weight_name, bias_name, running_mean_name, running_var_name = node.input[1:] + init_w, init_b, init_rm, init_rv = [ParamUtils.get_param(model, node, idx) for idx in range(1, 5)] + + attr = [item for item in node.attribute if item.name == "epsilon"] + if not attr: + attr = onnx.helper.make_attribute("epsilon", 1e-5) # Default epsilon value + node.attribute.append(attr) + else: + attr = attr[0] + + epsilon = attr.f + tensor_w = numpy_helper.to_array(init_w) + tensor_b = numpy_helper.to_array(init_b) + tensor_rm = numpy_helper.to_array(init_rm) + tensor_rv = numpy_helper.to_array(init_rv) + + # update values + inv_sigma = np.reciprocal(np.sqrt(tensor_rv + epsilon)) + tensor_w = tensor_w * inv_sigma + tensor_b = tensor_b - tensor_rm * tensor_w + tensor_rm = np.zeros(tensor_w.shape, tensor_w.dtype) + tensor_rv = np.ones(tensor_w.shape, tensor_w.dtype) + attr.f = 0. + + init_w_ = numpy_helper.from_array(tensor_w, weight_name) + init_b_ = numpy_helper.from_array(tensor_b, bias_name) + init_rm_ = numpy_helper.from_array(tensor_rm, running_mean_name) + init_rv_ = numpy_helper.from_array(tensor_rv, running_var_name) + + # update initializers + init_w.CopyFrom(init_w_) + init_b.CopyFrom(init_b_) + init_rm.CopyFrom(init_rm_) + init_rv.CopyFrom(init_rv_) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_onnx/cross_layer_equalization.html b/releases/2.0.0/_modules/aimet_onnx/cross_layer_equalization.html new file mode 100644 index 0000000..d8fbb5c --- /dev/null +++ b/releases/2.0.0/_modules/aimet_onnx/cross_layer_equalization.html @@ -0,0 +1,709 @@ + + + + + + + + aimet_onnx.cross_layer_equalization - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_onnx.cross_layer_equalization

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Cross Layer Equalization
    +
    +Some terminology for this code.
    +CLS set: Set of layers (2 or 3) that can be used for cross-layer scaling
    +Layer groups: Groups of layers that are immediately connected and can be decomposed further into CLS sets
    +"""
    +
    +from typing import Tuple, List, Union
    +import numpy as np
    +import onnx
    +from onnx import numpy_helper
    +from onnxruntime.quantization.onnx_quantizer import ONNXModel
    +from packaging import version
    +
    +# pylint: disable=wrong-import-order
    +from aimet_common.utils import AimetLogger
    +from aimet_common.connected_graph.connectedgraph import get_ordered_ops
    +from aimet_common.cross_layer_equalization import GraphSearchUtils, CrossLayerScaling as CLS, ClsSetInfo, \
    +    HighBiasFold as HBF
    +import aimet_common.libpymo as libpymo      # pylint: disable=import-error
    +
    +from aimet_onnx.meta.connectedgraph import ConnectedGraph, WEIGHT_INDEX, BIAS_INDEX
    +from aimet_onnx.meta.operations import Op
    +from aimet_onnx.utils import transpose_tensor, ParamUtils, get_node_attribute, replace_relu6_with_relu
    +from aimet_onnx.batch_norm_fold import BNLayer, fold_all_batch_norms_to_weight
    +
    +# pylint: disable=no-name-in-module, ungrouped-imports
    +if version.parse(onnx.__version__) >= version.parse("1.14.0"):
    +    from onnx import NodeProto, ModelProto
    +else:
    +    from onnx.onnx_pb import NodeProto, ModelProto
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.Quant)
    +
    +ClsSet = Union[Tuple['Conv', 'Conv'],
    +               Tuple['Conv', 'Conv', 'Conv']]
    +ScaleFactor = Union[np.ndarray, Tuple[np.ndarray]]
    +cls_supported_layer_types = ['Conv', 'ConvTranspose']
    +cls_supported_activation_types = ['Relu', 'PRelu']
    +
    +
    +def get_ordered_list_of_conv_modules(list_of_starting_ops: List) -> List:
    +    """
    +    Finds order of nodes in graph
    +    :param list_of_starting_ops: list of starting ops for the model
    +    :return: List of names in graph in order
    +    """
    +    module_list = get_ordered_ops(list_of_starting_ops)
    +    module_list = [[module.dotted_name, module] for module in module_list if module.type in cls_supported_layer_types]
    +    return module_list
    +
    +
    +class CrossLayerScaling(CLS):
    +    """
    +    Scales a model's layers to equalize the weights between consecutive layers
    +    """
    +    def __init__(self, model: ModelProto):
    +        """
    +        :param model: ONNX model
    +        """
    +        super().__init__()
    +        self._model = model
    +
    +    def scale_model(self) -> List[ClsSetInfo]:
    +        """
    +        Uses cross-layer scaling to scale all applicable layers in the given model
    +
    +        :param model: Model to scale
    +        :return: CLS information for each CLS set
    +        """
    +        # Find layer groups
    +        connected_graph = ConnectedGraph(self._model)
    +        ordered_module_list = get_ordered_list_of_conv_modules(connected_graph.starting_ops)
    +        graph_search = GraphSearchUtils(connected_graph, ordered_module_list, cls_supported_layer_types,
    +                                        cls_supported_activation_types)
    +        layer_groups = graph_search.find_layer_groups_to_scale()
    +
    +        # Find cls sets from the layer groups
    +        cls_sets = []
    +        for layer_group in layer_groups:
    +            cls_set = GraphSearchUtils.convert_layer_group_to_cls_sets(layer_group)
    +            cls_sets += cls_set
    +
    +        # Scale the CLS sets
    +        scale_factors = self.scale_cls_sets(cls_sets)
    +
    +        # Find if there were relu activations between layers of each cls set
    +        is_relu_activation_in_cls_sets = graph_search.is_relu_activation_present_in_cls_sets(cls_sets)
    +
    +        # Convert to a list of cls-set-info elements
    +        cls_set_info_list = CrossLayerScaling.create_cls_set_info_list(cls_sets, scale_factors,
    +                                                                       is_relu_activation_in_cls_sets)
    +
    +        return cls_set_info_list
    +
    +    def _populate_libpymo_params(self, module: NodeProto,
    +                                 layer_param: libpymo.EqualizationParams):
    +        """
    +        Populates libpymo weight parameter
    +        """
    +        weight = ParamUtils.get_param(self._model.model, module, WEIGHT_INDEX)
    +        groups = get_node_attribute(module, "group")
    +
    +        # Transpose weights to C, N, H, W from N, C, H, W since axis are flipped for transposed conv
    +        if module.op_type == "ConvTranspose" and groups == 1:
    +            weight = transpose_tensor(weight, (1, 0, 2, 3))
    +
    +        layer_param.weight = numpy_helper.to_array(weight).reshape(-1)
    +        weight_shape = get_weight_dimensions(np.array(weight.dims))
    +        layer_param.weightShape = weight_shape
    +
    +    def _pack_params_for_conv(self,
    +                              cls_set,
    +                              prev_layer_params: libpymo.EqualizationParams,
    +                              curr_layer_params: libpymo.EqualizationParams):
    +        """
    +        Prepare and pack data structure for previous and current layer in given cls set.
    +
    +        :param cls_set: Consecutive Conv layers Tuple whose weights and biases need to be equalized.
    +        :param prev_layer_params: Data structure holding weight and bias for previous layer in cls set.
    +        :param curr_layer_params: Data structure holding weight and bias for current layer in cls set.
    +        """
    +        self._populate_libpymo_params(cls_set[0].get_module(), prev_layer_params)
    +        self._populate_libpymo_params(cls_set[1].get_module(), curr_layer_params)
    +
    +        cls_set_0_bias = ParamUtils.get_param(self._model.model, cls_set[0].get_module(), BIAS_INDEX)
    +        if cls_set_0_bias is not None:
    +            prev_layer_params.bias = numpy_helper.to_array(cls_set_0_bias).reshape(-1)
    +        else:
    +            prev_layer_params.isBiasNone = True
    +
    +    def _update_weight_for_layer_from_libpymo_obj(self, layer_param: libpymo.EqualizationParams,
    +                                                  module: NodeProto):
    +        """
    +        Update weight parameter from libpymo object
    +        """
    +        weight = ParamUtils.get_param(self._model.model, module, WEIGHT_INDEX)
    +        weight.raw_data = np.asarray(layer_param.weight, dtype=np.float32).tobytes()
    +        groups = get_node_attribute(module, "group")
    +        # Transpose weight back to original configuration
    +        if module.op_type == "ConvTranspose" and groups == 1:
    +            weight = transpose_tensor(weight, (1, 0, 2, 3))
    +
    +        weight_param = ParamUtils.get_param(self._model.model, module, WEIGHT_INDEX)
    +        weight_param.raw_data = weight.raw_data
    +
    +    def _update_params_for_conv(self,
    +                                cls_set,
    +                                prev_layer_params: libpymo.EqualizationParams,
    +                                curr_layer_params: libpymo.EqualizationParams):
    +        """
    +        Update weight and biases for cls set using updated data structures.
    +
    +        :param cls_set: Consecutive Conv layers Tuple whose weights and biases need to be equalized.
    +        :param prev_layer_params: Data structure holding weight and bias for previous layer in cls set.
    +        :param curr_layer_params: Data structure holding weight and bias for current layer in cls set.
    +        """
    +        self._update_weight_for_layer_from_libpymo_obj(prev_layer_params, cls_set[0].get_module())
    +        self._update_weight_for_layer_from_libpymo_obj(curr_layer_params, cls_set[1].get_module())
    +
    +        if not prev_layer_params.isBiasNone:
    +            bias_param = ParamUtils.get_param(self._model.model, cls_set[0].get_module(),
    +                                              BIAS_INDEX)
    +            bias_param.raw_data = np.asarray(prev_layer_params.bias, dtype=np.float32).tobytes()
    +
    +    def _pack_params_for_depthwise_conv(self, cls_set,
    +                                        prev_layer_params: libpymo.EqualizationParams,
    +                                        curr_layer_params: libpymo.EqualizationParams,
    +                                        next_layer_params: libpymo.EqualizationParams):
    +        """
    +        Prepare and pack data structure for previous, current and next layer in given cls set.
    +
    +        :param cls_set: Consecutive Conv layers Tuple whose weights and biases need to be equalized.
    +        :param prev_layer_params: Data structure holding weight and bias for previous layer in cls set.
    +        :param curr_layer_params: Data structure holding weight and bias for current layer in cls set.
    +        :param next_layer_params: Data structure holding weight and bias for next layer in cls set.
    +        """
    +
    +        self._populate_libpymo_params(cls_set[0].get_module(), prev_layer_params)
    +
    +        assert cls_set[1].groups > 1
    +
    +        weight = ParamUtils.get_param(self._model.model, cls_set[1].get_module(), WEIGHT_INDEX)
    +        curr_layer_params.weight = numpy_helper.to_array(weight).reshape(-1)
    +        curr_layer_params.weightShape = np.array(weight.dims)
    +
    +        self._populate_libpymo_params(cls_set[2].get_module(), next_layer_params)
    +
    +        cls_set_0_bias = ParamUtils.get_param(self._model.model, cls_set[0].get_module(), BIAS_INDEX)
    +        if cls_set_0_bias is not None:
    +            prev_layer_params.bias = numpy_helper.to_array(cls_set_0_bias).reshape(-1)
    +        else:
    +            prev_layer_params.isBiasNone = True
    +
    +        cls_set_1_bias = ParamUtils.get_param(self._model.model, cls_set[1].get_module(), BIAS_INDEX)
    +        if cls_set_1_bias is not None:
    +            curr_layer_params.bias = numpy_helper.to_array(cls_set_1_bias).reshape(-1)
    +        else:
    +            curr_layer_params.isBiasNone = True
    +
    +    def _update_params_for_depthwise_conv(self, cls_set,
    +                                          prev_layer_params: libpymo.EqualizationParams,
    +                                          curr_layer_params: libpymo.EqualizationParams,
    +                                          next_layer_params: libpymo.EqualizationParams):
    +        """
    +        Update weight and biases for cls set using updated data structures.
    +
    +        :param cls_set: Consecutive Conv layers Tuple whose weights and biases need to be equalized.
    +        :param prev_layer_params: Data structure holding weight and bias for previous layer in cls set.
    +        :param curr_layer_params: Data structure holding weight and bias for current layer in cls set.
    +        :param next_layer_params: Data structure holding weight and bias for next layer in cls set.
    +        """
    +        self._update_weight_for_layer_from_libpymo_obj(prev_layer_params, cls_set[0].get_module())
    +        self._update_weight_for_layer_from_libpymo_obj(curr_layer_params, cls_set[1].get_module())
    +        self._update_weight_for_layer_from_libpymo_obj(next_layer_params, cls_set[2].get_module())
    +
    +        if not prev_layer_params.isBiasNone:
    +            bias_param = ParamUtils.get_param(self._model.model, cls_set[0].get_module(),
    +                                              BIAS_INDEX)
    +            bias_param.raw_data = np.asarray(prev_layer_params.bias, dtype=np.float32).tobytes()
    +
    +        if not curr_layer_params.isBiasNone:
    +            bias_param = ParamUtils.get_param(self._model.model, cls_set[1].get_module(),
    +                                              BIAS_INDEX)
    +            bias_param.raw_data = np.asarray(curr_layer_params.bias, dtype=np.float32).tobytes()
    +
    +
    +class HighBiasFold(HBF):
    +    """
    +    Code to apply the high-bias-fold technique to a model
    +    """
    +    def __init__(self, model: ModelProto):
    +        self._model = model
    +
    +    def _check_if_bias_is_none(self, layer: Op) -> bool:
    +        """ Returns if bias is a None for a layer. True if bias is None"""
    +        bias = ParamUtils.get_param(self._model.model, layer.get_module(), BIAS_INDEX)
    +        return not bias
    +
    +    def _populate_bn_params_in_libpymo_obj(self, prev_layer_bn_params: libpymo.BNParamsHighBiasFold,
    +                                           bn_layer: BNLayer):
    +        """
    +        Populates BatchNorm params in the libpymo object
    +        :param prev_layer_bn_params: Data structure to pack batch norm parameter
    +        :param bn_layer: BatchNorm layer
    +        """
    +        prev_layer_bn_params.gamma = bn_layer.gamma
    +        prev_layer_bn_params.beta = bn_layer.beta
    +
    +    def _pack_previous_and_current_layer_params(self, cls_pair_info: ClsSetInfo.ClsSetLayerPairInfo,
    +                                                prev_layer_params: libpymo.LayerParams,
    +                                                curr_layer_params: libpymo.LayerParams):
    +        """
    +        Helper method to pack information of previous and current layer.
    +
    +        :param cls_pair_info: Layer pairs that were scaled using CLS and related information.
    +        :param prev_layer_params: Data structure to pack previous layer parameters.
    +        :param curr_layer_params: Data structure to pack current layer parameters.
    +        """
    +        prev_layer_params.activationIsRelu = cls_pair_info.relu_activation_between_layers
    +
    +        bias = ParamUtils.get_param(self._model.model, cls_pair_info.layer1.get_module(),
    +                                    BIAS_INDEX)
    +
    +        prev_layer_params.bias = numpy_helper.to_array(bias).reshape(-1)
    +
    +        module = cls_pair_info.layer2.get_module()
    +        weight = ParamUtils.get_param(self._model.model, module, WEIGHT_INDEX)
    +        bias = ParamUtils.get_param(self._model.model, module, BIAS_INDEX)
    +
    +        groups = get_node_attribute(module, "group")
    +
    +        # Transpose weights to C, N, H, W from N, C, H, W since axis are flipped for transposed conv
    +        if module.op_type == "ConvTranspose" and groups == 1:
    +            weight = transpose_tensor(weight, (1, 0, 2, 3))
    +
    +        curr_layer_params.bias = numpy_helper.to_array(bias).reshape(-1)
    +        curr_layer_params.weight = numpy_helper.to_array(weight).reshape(-1)
    +        curr_layer_params.weightShape = get_weight_dimensions(np.array(weight.dims))
    +
    +    def _update_bias_for_layer_from_libpymo_obj(self, layer_param: libpymo.LayerParams,
    +                                                module: NodeProto):
    +        """
    +        Update bias parameter from libpymo object
    +        """
    +        bias = ParamUtils.get_param(self._model.model, module, BIAS_INDEX)
    +
    +        bias.raw_data = np.asarray(layer_param.bias, dtype=np.float32).tobytes()
    +
    +    def _update_previous_and_current_layer_bias(self, cls_pair_info: ClsSetInfo.ClsSetLayerPairInfo,
    +                                                prev_layer_params: libpymo.LayerParams,
    +                                                curr_layer_params: libpymo.LayerParams):
    +        """
    +        Update biases for previous and current layer.
    +
    +        :param cls_pair_info: Layer pairs that were scaled using CLS and related information.
    +        :param prev_layer_params: Data structure holding weight and bias for previous layer in cls set.
    +        :param curr_layer_params: Data structure holding weight and bias for current layer in cls set.
    +        """
    +        self._update_bias_for_layer_from_libpymo_obj(prev_layer_params, cls_pair_info.layer1.get_module())
    +        self._update_bias_for_layer_from_libpymo_obj(curr_layer_params, cls_pair_info.layer2.get_module())
    +
    +
    +def get_weight_dimensions(weight_shape: np.array) -> np.array:
    +    """
    +    Returns a length 4 weight shape
    +    :param weight_shape: shape of the weight tensor
    +    """
    +    dims = len(weight_shape)
    +    if dims == 4:
    +        return weight_shape
    +    return np.append(weight_shape, [1 for _ in range(4 - dims)]).astype(int)
    +
    +
    +
    +[docs] +def equalize_model(model: ModelProto): + """ + High-level API to perform Cross-Layer Equalization (CLE) on the given model. The model is equalized in place. + + :param model: Model to equalize + """ + if not isinstance(model, ONNXModel): + model = ONNXModel(model) + conv_bn_pairs, bn_conv_pairs = fold_all_batch_norms_to_weight(model) + + replace_relu6_with_relu(model) + + bn_dict = {} + for conv_bn in conv_bn_pairs: + bn_dict[conv_bn[0].name] = conv_bn[1] + + for bn_conv in bn_conv_pairs: + bn_dict[bn_conv[1].name] = bn_conv[0] + + # perform cross-layer scaling on applicable layer sets + cls = CrossLayerScaling(model) + cls_set_info = cls.scale_model() + + # high-bias fold + hbf = HighBiasFold(model) + hbf.bias_fold(cls_set_info, bn_dict)
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_onnx/layer_output_utils.html b/releases/2.0.0/_modules/aimet_onnx/layer_output_utils.html new file mode 100644 index 0000000..d3d1833 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_onnx/layer_output_utils.html @@ -0,0 +1,512 @@ + + + + + + + + aimet_onnx.layer_output_utils - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_onnx.layer_output_utils

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" This module contains utilities to capture and save intermediate layer-outputs of a model """
    +
    +import copy
    +from typing import List, Dict, Tuple, Union
    +import re
    +import numpy as np
    +import onnxruntime as ort
    +import onnx
    +from packaging import version
    +
    +# pylint: disable=wrong-import-order
    +from aimet_common.utils import AimetLogger
    +from aimet_common.layer_output_utils import SaveInputOutput, save_layer_output_names
    +
    +from aimet_onnx.quantsim import QuantizationSimModel
    +from aimet_onnx.utils import create_input_dict, add_hook_to_get_activation
    +
    +# pylint: disable=no-name-in-module, ungrouped-imports
    +if version.parse(onnx.__version__) >= version.parse("1.14.0"):
    +    from onnx import ModelProto
    +else:
    +    from onnx.onnx_pb import ModelProto
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.LayerOutputs)
    +
    +
    +
    +[docs] +class LayerOutputUtil: + """ Implementation to capture and save outputs of intermediate layers of a model (fp32/quantsim) """ + + def __init__(self, model: ModelProto, dir_path: str, device: int = 0): + """ + Constructor - It initializes the utility classes that captures and saves layer-outputs + + :param model: ONNX model + :param dir_path: Directory wherein layer-outputs will be saved + :param device: CUDA device-id to be used + """ + self.model = model + + # Fetch appropriate execution providers depending on availability + providers = ['CPUExecutionProvider'] + if 'CUDAExecutionProvider' in ort.get_available_providers(): + providers = [('CUDAExecutionProvider', {'device_id': device}), 'CPUExecutionProvider'] + + # Utility to capture layer-outputs + self.layer_output = LayerOutput(model=model, providers=providers, dir_path=dir_path) + + # Utility to save model inputs and their corresponding layer-outputs + self.save_input_output = SaveInputOutput(dir_path, 'NCHW') + +
    +[docs] + def generate_layer_outputs(self, input_instance: Union[np.ndarray, List[np.ndarray], Tuple[np.ndarray]]): + """ + This method captures output of every layer of a model & saves the inputs and corresponding layer-outputs to disk. + + :param input_instance: Single input instance for which we want to obtain layer-outputs. + :return: None + """ + logger.info("Generating layer-outputs for input instance %d", self.save_input_output.input_cntr+1) + + input_dict = create_input_dict(self.model, input_instance) + + layer_output_dict = self.layer_output.get_outputs(input_dict) + self.save_input_output.save(input_instance, layer_output_dict) + + logger.info('Layer-outputs generated for input instance %d', self.save_input_output.input_cntr)
    +
    + + + +class LayerOutput: + """ + This class creates a layer-output name to layer-output dictionary. + """ + def __init__(self, model: ModelProto, providers: List, dir_path: str): + """ + Constructor - It initializes few lists that are required for capturing and naming layer-outputs. + + :param model: ONNX model + :param providers: execution providers to execute onnxruntime + :param dir_path: directory to store topological order of layer-output names + """ + self.model = copy.deepcopy(model) + self.activation_names = LayerOutput.get_activation_names(self.model) + + quantized_activation_names = [name for name in self.activation_names if name.endswith('_updated')] + if quantized_activation_names: + self.activation_names = quantized_activation_names + + LayerOutput.register_activations(self.model, self.activation_names) + + self.session = QuantizationSimModel.build_session(self.model, providers) + + # Replace special characters with underscore. This gives valid file names to store activation tensors. + self.sanitized_activation_names = [re.sub(r'\W+', "_", name.replace('_updated', '')) for name in self.activation_names] + + # Save activation names which are in topological order of model graph. This order can be used while comparing layer-outputs. + save_layer_output_names(self.sanitized_activation_names, dir_path) + + def get_outputs(self, input_dict: Dict) -> Dict[str, np.ndarray]: + """ + This function creates layer-output name to layer-output dictionary. + + :param input_dict: input name to input tensor map + :return: layer-output name to layer-output dictionary + """ + activation_values = self.session.run(self.activation_names, input_dict) + return dict(zip(self.sanitized_activation_names, activation_values)) + + @staticmethod + def get_activation_names(model: ModelProto) -> List[str]: + """ + This function fetches the activation names (layer-output names) of the given onnx model. + + :param model: ONNX model + :return: list of activation names + """ + activation_names = [] + constant_activations = [] # No need to capture them + for node in model.graph.input: + activation_names.append(node.name) + for node in model.graph.node: + if node.op_type == 'Constant': + # Ignore and keep track to further ignore its quantized version + constant_activations.append(node.output[0]+'_updated') + else: + for output in node.output: + if output not in constant_activations: + activation_names.append(output) + return activation_names + + @staticmethod + def register_activations(model: ModelProto, activation_names: List): + """ + This function adds the intermediate activations into the model's ValueInfoProto so that they can be fetched via + running the session. + + :param model: ONNX model + :param activation_names: list of activation names to be registered + :return: + """ + for act_name in activation_names: + _ = add_hook_to_get_activation(model, act_name) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_onnx/mixed_precision.html b/releases/2.0.0/_modules/aimet_onnx/mixed_precision.html new file mode 100644 index 0000000..ae141b4 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_onnx/mixed_precision.html @@ -0,0 +1,457 @@ + + + + + + + + aimet_onnx.mixed_precision - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_onnx.mixed_precision

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +""" Mixed precision inference """
    +
    +from typing import Union, Tuple, List
    +
    +from aimet_common.utils import AimetLogger
    +from aimet_common.amp.utils import (
    +    visualize_quantizer_group_sensitivity,
    +    visualize_pareto_curve,
    +    CANDIDATE_WITH_DTYPE,
    +    AMPSearchAlgo,
    +)
    +from aimet_common.defs import CallbackFunc
    +from aimet_onnx.quantsim import QuantizationSimModel
    +from aimet_onnx.amp.mixed_precision_algo import GreedyMixedPrecisionAlgo
    +from aimet_onnx.amp.quantizer_groups import QuantizerGroup
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.MixedPrecision)
    +
    +
    +# pylint: disable=too-many-arguments
    +
    +[docs] +def choose_mixed_precision(sim: QuantizationSimModel, + candidates: List[CANDIDATE_WITH_DTYPE], eval_callback_for_phase1: CallbackFunc, + eval_callback_for_phase2: CallbackFunc, allowed_accuracy_drop: Union[None, float], + results_dir: str, clean_start: bool, forward_pass_callback: CallbackFunc, + use_all_amp_candidates: bool = False, phase1_optimize: bool = True, + amp_search_algo: AMPSearchAlgo = AMPSearchAlgo.Binary) -> \ + Union[List[Tuple[int, float, QuantizerGroup, int]], None]: + """ + High-level API to perform in place Mixed Precision evaluation on the given sim model. A pareto list is created and + a curve for Accuracy vs BitOps is saved under the results directory + + :param sim: Quantized sim model + :param candidates: List of tuples for all possible bitwidth values for activations and parameters + Suppose the possible combinations are- + ((Activation bitwidth - 8, Activation data type - int), (Parameter bitwidth - 16, parameter data type - int)) + ((Activation bitwidth - 16, Activation data type - float), (Parameter bitwidth - 16, parameter data type - float)) + candidates will be [((8, QuantizationDataType.int), (16, QuantizationDataType.int)), + ((16, QuantizationDataType.float), (16, QuantizationDataType.float))] + :param eval_callback_for_phase1: An object of CallbackFunc class which takes in Eval function (callable) and eval + function parameters. This evaluation callback used to measure sensitivity of each + quantizer group during phase 1. The phase 1 involves finding accuracy list/sensitivity of each + module. Therefore, a user might want to run the phase 1 with a smaller dataset + :param eval_callback_for_phase2: An object of CallbackFunc class which takes in Eval function (callable) and eval + function parameters. Evaluation callback used to get accuracy of quantized model + for phase 2 calculations. The phase 2 involves finding pareto front curve + :param allowed_accuracy_drop: Maximum allowed drop in accuracy from FP32 baseline. The pareto front curve is plotted only till the point where the allowable + accuracy drop is met. To get a complete plot for picking points on the curve, the user + can set the allowable accuracy drop to None. + :param results_dir: Path to save results and cache intermediate results + :param clean_start: If true, any cached information from previous runs will be deleted prior to starting the + mixed-precision analysis. If false, prior cached information will be used if applicable. Note + it is the user's responsibility to set this flag to true if anything in the model or + quantization parameters changes compared to the previous run. + :param forward_pass_callback: An object of CallbackFunc class which takes in Forward pass function (callable) and its + function parameters. Forward pass callback used to compute quantization encodings + :param use_all_amp_candidates: Using the “supported_kernels” field in the config file (under defaults + and op_type sections), a list of supported candidates can be specified. All the AMP candidates + which are passed through the “candidates” field may not be supported based on the data passed + through “supported_kernels”. When the field “use_all_amp_candidates” is set to True, the AMP + algorithm will ignore the "supported_kernels" in the config file and continue to use all candidates. + :phase1_optimize: If user set this parameter to false then phase1 default logic will be executed else optimized logic will be executed. + :param amp_search_algo: A valid value from the Enum AMPSearchAlgo. Defines the search algorithm to be used for + the phase 2 of AMP. + + :return: Pareto front list containing information including Bitops, QuantizerGroup candidates and + corresponding eval scores. The Pareto front list can be used for plotting a pareto front curve which + provides information regarding how bit ops vary w.r.t. accuracy. If the allowable accuracy drop is set to + 100% then a user can use the pareto front curve to pick points and re-run, + None if we early exit the mixed precision algorithm. + """ + mixed_precision_algo = GreedyMixedPrecisionAlgo(sim, candidates, eval_callback_for_phase1, + eval_callback_for_phase2, results_dir, clean_start, + forward_pass_callback, use_all_amp_candidates, phase1_optimize) + mixed_precision_algo.run(allowed_accuracy_drop, amp_search_algo) + + if mixed_precision_algo.accuracy_list is not None and mixed_precision_algo.pareto_list is not None: + # Print mixed precision stats + logger.info(mixed_precision_algo) + + # Visualize quantizer group sensitivity + visualize_quantizer_group_sensitivity(mixed_precision_algo.accuracy_list, + mixed_precision_algo.baseline_candidate, + mixed_precision_algo.fp32_accuracy, + results_dir=results_dir) + # Create pareto list curve + visualize_pareto_curve(mixed_precision_algo.pareto_list, results_dir) + return mixed_precision_algo.pareto_list + + return None
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_onnx/quant_analyzer.html b/releases/2.0.0/_modules/aimet_onnx/quant_analyzer.html new file mode 100644 index 0000000..f57959a --- /dev/null +++ b/releases/2.0.0/_modules/aimet_onnx/quant_analyzer.html @@ -0,0 +1,998 @@ + + + + + + + + aimet_onnx.quant_analyzer - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_onnx.quant_analyzer

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Quant Analyzer """
    +
    +import os
    +import re
    +from typing import Union, Tuple, Dict, List, Iterable
    +import copy
    +from collections import defaultdict
    +
    +import numpy as np
    +from onnx import ModelProto
    +import onnxruntime as ort
    +from onnxruntime.quantization.onnx_model import ONNXModel
    +from sklearn.metrics import mean_squared_error
    +
    +from aimet_common.utils import AimetLogger, CallbackFunc
    +from aimet_common.defs import QuantScheme
    +from aimet_common.quant_analyzer import save_json, export_per_layer_sensitivity_analysis_plot, \
    +    create_and_export_min_max_ranges_plot, export_per_layer_mse_plot, export_stats_histogram_plot
    +
    +from aimet_onnx.qc_quantize_op import QcQuantizeOp
    +from aimet_onnx.quantsim import QuantizationSimModel
    +from aimet_onnx.batch_norm_fold import fold_all_batch_norms_to_weight
    +from aimet_onnx.adaround.activation_sampler import ModuleData
    +from aimet_onnx import utils
    +from aimet_onnx.meta.operations import Op
    +
    +_logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.QuantAnalyzer)
    +
    +
    +
    +[docs] +class QuantAnalyzer: + """ + QuantAnalyzer provides following utilities: + + 1) model sensitivity to weight and activation quantization + 2) per layer sensitivity analysis + 3) per layer encoding (min - max range) + 4) per layer quantizer historgram analysis and + 5) per layer MSE analysis + """ + def __init__(self, + model: Union[ModelProto, ONNXModel], + dummy_input: Dict[str, np.ndarray], + forward_pass_callback: CallbackFunc, + eval_callback: CallbackFunc, + ): + """ + :param model: FP32 model to analyze for quantization. + :param dummy_input: Dummy input to model. + :param forward_pass_callback: A callback function for model calibration that simply runs + forward passes on the model to compute encoding (delta/offset). This + callback function should use representative data and should be subset of + entire train/validation dataset (~1000 images/samples). + :param eval_callback: A callback function for model evaluation that determines model + performance. This callback function is expected to return scalar value + representing the model performance evaluated against entire test/evaluation dataset. + """ + if not isinstance(forward_pass_callback, CallbackFunc): + raise ValueError('forward_pass_callback and its argument(s) are not encapsulated by CallbackFunc class.') + if not isinstance(eval_callback, CallbackFunc): + raise ValueError('eval_callback and its argument(s) are not encapsulated by CallbackFunc class.') + + self._onnx_model = model + if not isinstance(self._onnx_model, ONNXModel): + self._onnx_model = ONNXModel(self._onnx_model) + self._dummy_input = dummy_input + self._forward_pass_callback = forward_pass_callback + self._eval_callback = eval_callback + self._unlabeled_dataset_iterable = None + self._num_batches = None + +
    +[docs] + def analyze(self, + quant_scheme: QuantScheme = QuantScheme.post_training_tf_enhanced, + default_param_bw: int = 8, + default_activation_bw: int = 8, + config_file: str = None, + results_dir: str = "./tmp/", + ): + """ + Analyzes model for quantization and point out sensitive parts/hotspots of the model by performing + 1) model sensitivity to quantization, + 2) perform per layer sensitivity analysis by enabling and disabling quantizers, + 3) export per layer encodings min - max ranges, + 4) export per layer quantizer stats histogram, + 5) per layer MSE analysis + + :param quant_scheme: Quantization scheme. Supported values are + QuantScheme.post_training_tf or QuantScheme.post_training_tf_enhanced. + :param default_param_bw: Default bitwidth (4-31) to use for quantizing layer parameters. + :param default_activation_bw: Default bitwidth (4-31) to use for quantizing layer inputs and outputs. + :param config_file: Path to configuration file for model quantizers. + :param results_dir: Directory to save the results. + """ + sim = self.create_quantsim_and_encodings(quant_scheme, + default_param_bw, + default_activation_bw, + config_file) + + results_dir = os.path.abspath(results_dir) + os.makedirs(results_dir, exist_ok=True) + + # Check model sensitivity to weight and activation quantization individually. + self.check_model_sensitivity_to_quantization(sim) + + # Perform per layer analysis by enabling its quantizers (OPTION-1). + self.perform_per_layer_analysis_by_enabling_quantizers(sim, results_dir) + + # Perform per layer analysis by disabling its quantizers (OPTION-2). + self.perform_per_layer_analysis_by_disabling_quantizers(sim, results_dir) + + # Export encoding min-max range. + self.export_per_layer_encoding_min_max_range(sim, results_dir) + + # Export PDF of statistics. + if quant_scheme == QuantScheme.post_training_tf_enhanced: + self.export_per_layer_stats_histogram(sim, results_dir) + + # Export per layer MSE loss between fp32 and quantized output activations. + if self._unlabeled_dataset_iterable: + self.export_per_layer_mse_loss(sim, results_dir)
    + + +
    +[docs] + def create_quantsim_and_encodings(self, quant_scheme: QuantScheme, default_param_bw: int, + default_activation_bw: int, config_file: str) \ + -> QuantizationSimModel: + """ + Creates quantsim object and computes encodings. + + :param quant_scheme: Quantization scheme. + :param default_param_bw: Default bitwidth (4-31) to use for quantizing layer parameters. + :param default_activation_bw: Default bitwidth (4-31) to use for quantizing layer inputs and outputs. + :param config_file: Path to configuration file for model quantizers. + :return: Quantsim object. + """ + _ = fold_all_batch_norms_to_weight(self._onnx_model) + kwargs = dict( + quant_scheme=quant_scheme, + default_activation_bw=default_activation_bw, + default_param_bw=default_param_bw, + config_file=config_file, + ) + sim = QuantizationSimModel(copy.deepcopy(self._onnx_model), self._dummy_input, **kwargs) + sim.compute_encodings(self._forward_pass_callback.func, self._forward_pass_callback.args) + return sim
    + + +
    +[docs] + def check_model_sensitivity_to_quantization(self, + sim: QuantizationSimModel, + ) -> Tuple[float, float, float]: + """ + Performs model sensitivity analysis to weight and activation quantization individually. + + :param sim: Quantsim model. + :return: FP32 eval score, weight-quantized eval score, act-quantized eval score. + """ + # pylint: disable=protected-access + fp32_eval_score = self._eval_model(self._onnx_model.model) + _logger.info("FP32 eval score (W32A32): %f", fp32_eval_score) + + weight_quantized_eval_score = self._eval_weight_quantized_model(sim) + _logger.info("Weight-quantized eval score (W%dA32): %f", sim._default_param_bw, + weight_quantized_eval_score) + + act_quantized_eval_score = self._eval_activation_quantized_model(sim) + _logger.info("Activation-quantized eval score (W32A%d): %f", sim._default_activation_bw, + act_quantized_eval_score) + + return fp32_eval_score, weight_quantized_eval_score, act_quantized_eval_score
    + + + def _eval_model(self, model): + """ + Evaluate the model performance. + + :param model: ONNX model to be evaluated. + :return: Scaler value representing model performance. + """ + if 'CUDAExecutionProvider' in ort.get_available_providers(): + providers = [('CUDAExecutionProvider', {'cudnn_conv_algo_search': 'DEFAULT'}), 'CPUExecutionProvider'] + else: + providers = ['CPUExecutionProvider'] + session = ort.InferenceSession( + path_or_bytes=model.SerializeToString(), + providers=providers, + ) + return self._eval_callback.func(session, self._eval_callback.args) + + def _eval_weight_quantized_model(self, sim: QuantizationSimModel)-> float: + """ + Evaluate weight quantized model performance. + For weight quantized model performance, disable enabled activation quantizers, measure + eval score and enable again. + + :param sim: Quantsim model. + :return: Quantized model performance. + """ + enabled_activation_quantizers = self._get_enabled_activation_quantizers(sim) + self._enable_disable_quantizers(enabled_activation_quantizers, enabled=False) + eval_score = self._eval_callback.func(sim.session, self._eval_callback.args) + self._enable_disable_quantizers(enabled_activation_quantizers, enabled=True) + return eval_score + + def _eval_activation_quantized_model(self, sim: QuantizationSimModel)-> float: + """ + Evaluate activation quantized model performance. + For activation quantized model performance, disable enabled param quantizers, measure + eval score and enable again. + + :param sim: Quantsim model. + :return: Quantized model performance. + """ + enabled_param_quantizers = self._get_enabled_param_quantizers(sim) + self._enable_disable_quantizers(enabled_param_quantizers, enabled=False) + eval_score = self._eval_callback.func(sim.session, self._eval_callback.args) + self._enable_disable_quantizers(enabled_param_quantizers, enabled=True) + return eval_score + + @staticmethod + def _get_enabled_param_quantizers(sim: QuantizationSimModel) -> List[QcQuantizeOp]: + """ + For given quantsim model, get all enabled param quantizers. + :param sim: Quantsim model. + :return: List of enabled param quantizers. + """ + param_quantizers, _ = sim.get_all_quantizers() + enabled_param_quantizers = [quantizer for quantizer in param_quantizers if quantizer.enabled] + return enabled_param_quantizers + + @staticmethod + def _get_enabled_activation_quantizers(sim: QuantizationSimModel) -> List[QcQuantizeOp]: + """ + For given quantsim model, get all enabled activation quantizers. + :param sim: Quantsim model. + :return: List of enabled activation quantizers. + """ + _, act_quantizers = sim.get_all_quantizers() + enabled_activation_quantizers = [quantizer for quantizer in act_quantizers if quantizer.enabled] + return enabled_activation_quantizers + + @staticmethod + def _enable_disable_quantizers(quantizers: List[QcQuantizeOp], enabled: bool): + """ + For given list of quantizers, set (enable/disable) quantizer's enabled. + + :param quantizers: List of quantizers. + :param enabled: Enabled flag. + """ + for quantizer in quantizers: + quantizer.enabled = enabled + +
    +[docs] + def perform_per_layer_analysis_by_enabling_quantizers(self, + sim: QuantizationSimModel, + results_dir: str, + ) -> Dict: + """ + Performs layer-wise quantization sensitivity analysis by enabling its quantizers + + 1. All parameter and activation quantizers are disabled. + 2. For every layer, based on occurrence: + a. Each layer's parameters and activations quantizers are enabled as per JSON config file + and set to bit-width specified. + b. Measure and record eval score on subset of dataset. + c. Disable enabled quantizers in step a. + 3. Returns dictionary containing layer name and corresponding eval score. + + :param sim: Quantsim model. + :param results_dir: Directory to save the results. + :return: layer wise eval score dictionary. dict[layer_name] = eval_score + """ + results_dir = os.path.abspath(results_dir) + os.makedirs(results_dir, exist_ok=True) + + _logger.info("OPTION-1: All the quantizers are disabled. " + "Starting per-layer analysis by enabling layer-specific quantizers as per config file.") + layer_wise_eval_score_dict = self._perform_per_layer_analysis(sim, + disable_all_quantizers=True, + enabled_before=True, + enabled_after=False) + export_per_layer_sensitivity_analysis_plot(layer_wise_eval_score_dict, + results_dir, + title="per_layer_quant_enabled") + save_json(layer_wise_eval_score_dict, + results_dir, + title="per_layer_quant_enabled.json") + _logger.info("Exported per-layer quant analysis (enabled) plot.") + return layer_wise_eval_score_dict
    + + +
    +[docs] + def perform_per_layer_analysis_by_disabling_quantizers(self, + sim: QuantizationSimModel, + results_dir: str, + ) -> Dict: + """ + Performs layer-wise quantization sensitivity analysis by disabling its quantizers + + 1. All parameter and activation quantizers are enabled as per JSON config file + and set to bit-width specified. + 2. For every layer, based on occurrence: + a. Each layer's parameters and activations quantizers are disabled. + b. Measure and record eval score on subset of dataset. + c. Enable disabled quantizers in step a. + 3. Returns dictionary containing layer name and corresponding eval score. + + :param sim: Quantsim model. + :param results_dir: Directory to save the results. + :return: layer wise eval score dictionary. dict[layer_name] = eval_score + """ + results_dir = os.path.abspath(results_dir) + os.makedirs(results_dir, exist_ok=True) + + _logger.info("OPTION-2: All the quantizers are enabled as per config file. " + "Starting per-layer analysis by disabling layer-specific quantizers.") + layer_wise_eval_score_dict = self._perform_per_layer_analysis(sim, + disable_all_quantizers=False, + enabled_before=False, + enabled_after=True) + export_per_layer_sensitivity_analysis_plot(layer_wise_eval_score_dict, + results_dir, + title="per_layer_quant_disabled") + save_json(layer_wise_eval_score_dict, + results_dir, + title="per_layer_quant_disabled.json") + _logger.info("Exported per-layer quant analysis (disabled) plot.") + return layer_wise_eval_score_dict
    + + + def _perform_per_layer_analysis(self, + sim: QuantizationSimModel, + disable_all_quantizers: bool, + enabled_before: bool, + enabled_after: bool, + ) -> Dict: + """ + Helper function for perform_per_layer_analysis_by_enabling_quantizers() and + perform_per_layer_analysis_by_disabling_quantizers() + + :param sim: Quantsim model. + :param disable_all_quantizers: Flag to disable all the quantizers before per-layer analysis. + :param enabled_before: Flag to set enabled for quantizers before computing encodings. + :param enabled_after: Flag to set enabled for quantizers after computing encodings. + :return: layer wise eval score dictionary. dict[layer_name] = eval_score. + """ + + # Mapping of ops and their enabled quantizers + op_to_quantizers_dict = defaultdict(list) + for op in sim.connected_graph.ordered_ops: + input_quantizers, output_quantizers, param_quantizers = self._get_op_quantizers(op, sim) + if not input_quantizers and not output_quantizers and not param_quantizers: + continue + op_to_quantizers_dict[op.name_op].extend(input_quantizers) + op_to_quantizers_dict[op.name_op].extend(output_quantizers) + op_to_quantizers_dict[op.name_op].extend(list(param_quantizers.values())) + + if disable_all_quantizers: + for enabled_quantizers in op_to_quantizers_dict.values(): + self._enable_disable_quantizers(enabled_quantizers, enabled=False) + + eval_score_dict = {} + for op_name, enabled_quantizers in op_to_quantizers_dict.items(): + self._enable_disable_quantizers(enabled_quantizers, enabled=enabled_before) + + # Record eval score. + eval_score_dict[op_name] = self._eval_callback.func(sim.session, self._eval_callback.args) + _logger.debug("For layer: %s, the eval score is: %f", op_name, eval_score_dict[op_name]) + + self._enable_disable_quantizers(enabled_quantizers, enabled=enabled_after) + + if disable_all_quantizers: + for enabled_quantizers in op_to_quantizers_dict.values(): + self._enable_disable_quantizers(enabled_quantizers, enabled=True) + + return eval_score_dict + + @staticmethod + def _get_op_quantizers(op: Op, sim: QuantizationSimModel) -> (List, List, Dict): + """ + This function returns the enabled input, output and param quantizers of the given connected graph op. + + :param op: Connected Graph Op + :param sim: QuantSim object + :return: list of input quantizers, list of output quantizers and dictionary of param quantizers + """ + input_quantizers, output_quantizers, param_quantizers = sim.get_op_quantizers(op) + input_quantizers = [q for q in input_quantizers if q.enabled] + output_quantizers = [q for q in output_quantizers if q.enabled] + param_quantizers = {name: q for name, q in param_quantizers.items() if q.enabled} + return input_quantizers, output_quantizers, param_quantizers + + # pylint: disable=no-self-use, too-many-branches, too-many-locals +
    +[docs] + def export_per_layer_encoding_min_max_range(self, sim: QuantizationSimModel, results_dir: str) -> Tuple[Dict, Dict]: + """ + Exports encoding min and max range for all weights and activations. results_dir has + html files in following format. + + -results_dir + -activations.html, + -weights.html + + If per channel quantization(PCQ) is enabled then, + + -results_dir + -activations.html, + -{layer_name}_{param_name}.html + + :param sim: Quantsim model. + :param results_dir: Directory to save the results. + :return: layer wise min-max range for weights and activations. + """ + min_max_ranges_dir = os.path.join(results_dir, "min_max_ranges") + + min_max_range_for_activations_dict = {} + min_max_range_for_weights_dict = {} + + for op in sim.connected_graph.ordered_ops: + input_quantizers, output_quantizers, param_quantizers = self._get_op_quantizers(op, sim) + op_name = re.sub(r'\W+', '_', op.name_op) + + # Get input activations' encodings if starting op + for index, quantizer in enumerate(input_quantizers): + name = f"{op_name}_input_{index}" + encodings = quantizer.get_encodings() + min_max_range_for_activations_dict[name] = (encodings[0].min, encodings[0].max) + + # Get output activations' encodings + for index, quantizer in enumerate(output_quantizers): + name = f"{op_name}_output_{index}" + encodings = quantizer.get_encodings() + min_max_range_for_activations_dict[name] = (encodings[0].min, encodings[0].max) + + # Get parameters' encodings + for param_name, quantizer in param_quantizers.items(): + name = re.sub(r'\W+', '_', f"{op_name}_{param_name}") + encodings = quantizer.get_encodings() + if len(encodings) > 1: # per-channel + per_channel_encodings = {} + for index, encoding in enumerate(encodings): + per_channel_encodings[f"{name}_{index}"] = (encoding.min, encoding.max) + min_max_range_for_weights_dict[name] = per_channel_encodings + else: # per-tensor + min_max_range_for_weights_dict[name] = (encodings[0].min, encodings[0].max) + + create_and_export_min_max_ranges_plot(min_max_range_for_weights_dict, min_max_ranges_dir, title="weights") + create_and_export_min_max_ranges_plot(min_max_range_for_activations_dict, min_max_ranges_dir, title="activations") + + save_json(min_max_range_for_weights_dict, min_max_ranges_dir, title="weights.json") + save_json(min_max_range_for_activations_dict, min_max_ranges_dir, title="activations.json") + + _logger.info("Exported per layer encodings min-max ranges plot(s).") + + return min_max_range_for_weights_dict, min_max_range_for_activations_dict
    + + + # pylint: disable=too-many-branches, too-many-locals +
    +[docs] + def export_per_layer_stats_histogram(self, + sim: QuantizationSimModel, + results_dir: str, + ): + """ + NOTE: Not to invoke when quantization scheme is not TF-Enhanced. + + Exports histogram that represents a PDF of collected statistics by a quantizer. + After invoking this API, results_dir should have html files in following + format for every quantizers in the model. + + -results_dir + -activations_pdf + name_{input/output}_{index}.html + -weights_pdf + -name + param_name_{channel_index}.html + + :param sim: Quantsim model. + :param results_dir: Directory to save the results. + """ + weights_pdf_dir = os.path.join(results_dir, "weights_pdf") + activations_pdf_dir = os.path.join(results_dir, "activations_pdf") + + for op in sim.connected_graph.ordered_ops: + input_quantizers, output_quantizers, param_quantizers = self._get_op_quantizers(op, sim) + op_name = re.sub(r'\W+', '_', op.name_op) + + # Collect stats histogram of input activation quantizers + for index, quantizer in enumerate(input_quantizers): + self._create_and_export_stats_histogram_plot(quantizer, + activations_pdf_dir, + title=f"{op_name}_input_q{index}") + + # Collect stats histogram of output activation quantizers + for index, quantizer in enumerate(output_quantizers): + self._create_and_export_stats_histogram_plot(quantizer, + activations_pdf_dir, + title=f"{op_name}_output_q{index}") + + # Collect stats histogram of param quantizers + for param_name, quantizer in param_quantizers.items(): + sanitized_param_name = re.sub(r'\W+', '_', param_name) + self._create_and_export_stats_histogram_plot(quantizer, + os.path.join(weights_pdf_dir, op_name), + title=f"{op_name}_{sanitized_param_name}") + + _logger.info("Exported per layer stats histogram plot(s).")
    + + + @staticmethod + def _create_and_export_stats_histogram_plot(quantizer: QcQuantizeOp, results_dir: str, title: str): + """ + For given quantizer, create and export histogram (PDF) of statistics in html format. + + :param quantizer: Quantizer. + :param results_dir: Directory to save the results. + :param title: Title of the plot. + """ + os.makedirs(results_dir, exist_ok=True) + + histograms = quantizer.get_stats_histogram() + encodings = quantizer.get_encodings() + + if not isinstance(encodings, List): + encodings = [encodings] + + for index, (histogram, encoding) in enumerate(zip(histograms, encodings)): + export_stats_histogram_plot(histogram, encoding, results_dir, title=f"{title}_{index}") + +
    +[docs] + def enable_per_layer_mse_loss(self, unlabeled_dataset_iterable: Iterable, num_batches: int): + """ + Enables per layer MSE loss analysis. + + :param unlabeled_dataset_iterable: A collection (i.e. iterable with `__len__`) + that iterates over an unlabeled dataset. The values yielded by this iterable are expected + to be able to be passed directly to the model. + :param num_batches: Number of batches. Approximately 256 samples/images are recommended, + so if batch size of data loader is 64, then 4 number of batches leads to 256 samples/images. + """ + if len(unlabeled_dataset_iterable) < num_batches: + raise ValueError(f'Can not fetch {num_batches} batches from ' + f'a data loader of length {len(unlabeled_dataset_iterable)}.') + + self._unlabeled_dataset_iterable = unlabeled_dataset_iterable + self._num_batches = num_batches
    + + +
    +[docs] + def export_per_layer_mse_loss(self, sim: QuantizationSimModel, results_dir: str) -> Dict: + """ + Exports MSE loss between fp32 and quantized output activations for each layer. + + :param sim: Quantsim model. + :param results_dir: Directory to save the results. + :return: layer wise MSE loss. dict[layer_name] = MSE loss. + """ + results_dir = os.path.abspath(results_dir) + os.makedirs(results_dir, exist_ok=True) + + mse_loss_dict = {} + for op_node in self._onnx_model.nodes(): + if op_node.op_type == 'Constant': + continue + op_output = op_node.output[0] + if op_output in sim.qc_quantize_op_dict: + quantized_op_output = op_output + '_updated' + loss = self._compute_mse_loss(op_output, quantized_op_output, self._onnx_model, sim.model) + mse_loss_dict[op_node.name] = loss + + export_per_layer_mse_plot(mse_loss_dict, + results_dir, + title="per_layer_mse_loss") + save_json(mse_loss_dict, results_dir, title="per_layer_mse_loss.json") + _logger.info("Exported per layer MSE loss plot.") + return mse_loss_dict
    + + + # pylint: disable=too-many-locals + def _compute_mse_loss(self, fp32_act_name: str, quantized_act_name: str, + fp32_model: ONNXModel, quantized_model: ONNXModel) -> float: + """ + Compute MSE loss between fp32 and quantized output activations for each batch, add for + all the batches and return averaged mse loss. + + :param fp32_act_name: module from the fp32_model. + :param quantized_act_name: Corresponding quant wrapper from the QuantSim model. + :param fp32_model: PyTorch model. + :param sim: Quantsim model. + :return: MSE loss between fp32 and quantized output activations. + """ + + providers = ['CPUExecutionProvider'] + if 'CUDAExecutionProvider' in ort.get_available_providers(): + providers = [('CUDAExecutionProvider', {'cudnn_conv_algo_search': 'DEFAULT'}), 'CPUExecutionProvider'] + + # output activations collector. + orig_module_collector = ModuleData(fp32_model, fp32_act_name, providers) + quant_module_collector = ModuleData(quantized_model, quantized_act_name, providers) + + total = 0 + loss = 0.0 + batch_index = 0 + for model_inputs in self._unlabeled_dataset_iterable: + model_inputs = utils.create_input_dict(fp32_model.model, model_inputs) + _, quantized_out_acts = quant_module_collector.collect_inp_out_data(model_inputs, + collect_input=False, + collect_output=True) + _, fp32_out_acts = orig_module_collector.collect_inp_out_data(model_inputs, + collect_input=False, + collect_output=True) + loss += mean_squared_error(fp32_out_acts[0].reshape(fp32_out_acts[0].shape[0], -1), + quantized_out_acts[0].reshape(fp32_out_acts[0].shape[0], -1)) + total += fp32_out_acts[0].shape[0] + batch_index += 1 + if batch_index == self._num_batches: + break + + average_loss = loss/total + return float(average_loss)
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_onnx/quantsim.html b/releases/2.0.0/_modules/aimet_onnx/quantsim.html new file mode 100644 index 0000000..f072816 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_onnx/quantsim.html @@ -0,0 +1,1601 @@ + + + + + + + + aimet_onnx.quantsim - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_onnx.quantsim

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +""" Implementation for simulating models running on Quantized hardware """
    +
    +import contextlib
    +import tempfile
    +from dataclasses import dataclass
    +from pathlib import Path
    +import os
    +from typing import Dict, List, Union, Tuple, Optional
    +import json
    +import warnings
    +import numpy as np
    +import onnx
    +
    +from onnx import helper
    +import onnxruntime as ort
    +from onnxruntime import SessionOptions, GraphOptimizationLevel, InferenceSession
    +from onnxruntime.quantization.onnx_quantizer import ONNXModel
    +from packaging import version
    +
    +# pylint: disable=wrong-import-order
    +from aimet_common import libpymo, quantsim
    +from aimet_common import libquant_info
    +from aimet_common.defs import QuantScheme, QuantizationDataType
    +from aimet_common.quantsim import extract_global_quantizer_args, VALID_ENCODING_VERSIONS
    +from aimet_common.utils import save_json_yaml, AimetLogger, _red
    +from aimet_common.connected_graph.product import Product
    +from aimet_onnx import utils
    +from aimet_onnx.meta.operations import Op
    +from aimet_onnx.meta.utils import get_op_given_param_name, get_param_shape_using_connected_graph
    +from aimet_onnx.meta.connectedgraph import ConnectedGraph
    +from aimet_onnx.qc_quantize_op import QcQuantizeOp, OpMode, TensorQuantizerParams, GroupedBlockQuantizeDequantize
    +from aimet_onnx.quantsim_config.quantsim_config import QuantSimConfigurator
    +from aimet_onnx.utils import make_dummy_input, add_hook_to_get_activation, remove_activation_hooks
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.Quant)
    +
    +# pylint: disable=no-name-in-module, ungrouped-imports, too-many-lines
    +if version.parse(onnx.__version__) >= version.parse("1.14.0"):
    +    from onnx import ModelProto
    +else:
    +    from onnx.onnx_pb import ModelProto
    +
    +# List of ops whose outputs are not to be quantized
    +op_outputs_to_ignore = ["branch", "Flatten", "Gather", "Reshape", "Shape", "Unsqueeze", "Squeeze", "Split",
    +                        "Compress", "Tile", "Transpose", "Identity"]
    +
    +# List of ops whose params are not to be quantized
    +op_params_to_ignore = ['Resize']
    +
    +allowed_op_type_for_per_channel = ['Conv', 'Gemm', 'MatMul', 'ConvTranspose']
    +
    +# List of op types whose input and output quantizers to be tied
    +op_types_to_tie_qtzrs = ['Concat', 'MaxPool', 'AveragePool', 'Resize']
    +_tie_qtzrs = False
    +
    +data_types_to_quantize = [np.float32]
    +
    +
    +@contextlib.contextmanager
    +def _apply_constraints(flag: bool):
    +    """
    +    Apply runtime specific constraints.
    +    For certain ``op_types_to_tie_qtzrs``, runtime has constraints to have same encodings for
    +     input and output quantizers.
    +
    +    NOTE: Default setting doesn't apply these constraints.
    +    """
    +    global _tie_qtzrs # pylint: disable=global-statement
    +    orig_flag = _tie_qtzrs
    +    try:
    +        _tie_qtzrs = flag
    +        yield
    +    finally:
    +        _tie_qtzrs = orig_flag
    +
    +
    +@dataclass
    +class EncodingMismatchInfo:
    +    """
    +    Dataclass tracking information about mismatched quantizer vs. encoding settings.
    +    """
    +    quantizer_name: str
    +    enabled_mismatch: Optional[Tuple] = None
    +    dtype_mismatch: Optional[Tuple] = None
    +    bitwidth_mismatch: Optional[Tuple] = None
    +    is_symmetric_mismatch: Optional[Tuple] = None
    +    is_strict_symmetric_mismatch: Optional[Tuple] = None
    +    is_unsigned_symmetric_mismatch: Optional[Tuple] = None
    +
    +    def has_mismatch(self) -> bool:
    +        """
    +        Returns True if there is a mismatched setting.
    +
    +        :return: True if there is a mismatched setting, False otherwise
    +        """
    +        return (self.enabled_mismatch is not None or
    +                self.dtype_mismatch is not None or
    +                self.bitwidth_mismatch is not None or
    +                self.is_symmetric_mismatch is not None or
    +                self.is_strict_symmetric_mismatch is not None or
    +                self.is_unsigned_symmetric_mismatch is not None)
    +
    +
    +
    +[docs] +class QuantizationSimModel: + """ Creates a QuantizationSimModel model by adding quantization simulations ops to a given model """ + + # pylint: disable=too-many-arguments, too-many-locals, too-many-instance-attributes + def __init__(self, + model: ModelProto, + dummy_input: Dict[str, np.ndarray] = None, + quant_scheme: QuantScheme = QuantScheme.post_training_tf_enhanced, + rounding_mode: str = 'nearest', + default_param_bw: int = 8, + default_activation_bw: int = 8, + use_symmetric_encodings: bool = False, use_cuda: bool = True, + device: int = 0, config_file: str = None, + default_data_type: QuantizationDataType = QuantizationDataType.int, + user_onnx_libs: List[str] = None, path: str = None): + """ + Constructor + + :param model: ONNX model + :param dummy_input: Dummy input to the model. If None, will attempt to auto-generate a dummy input + :param quant_scheme: Quantization scheme (e.g. QuantScheme.post_training_tf) + :param rounding_mode: Rounding mode (e.g. nearest) + :param default_param_bw: Quantization bitwidth for parameter + :param default_activation_bw: Quantization bitwidth for activation + :param use_symmetric_encodings: True if symmetric encoding is used. False otherwise. + :param use_cuda: True if using CUDA to run quantization op. False otherwise. + :param config_file: Path to Configuration file for model quantizers + :param default_data_type: Default data type to use for quantizing all layer inputs, outputs and parameters. + Possible options are QuantizationDataType.int and QuantizationDataType.float. + Note that the mode default_data_type=QuantizationDataType.float is only supported with + default_output_bw=16 and default_param_bw=16 + :param user_onnx_libs: List of paths to all compiled ONNX custom ops libraries + :param path: Directory to save the artifacts. + """ + self.model = model + if not isinstance(model, ONNXModel): + self.model = ONNXModel(model) + if not dummy_input: + dummy_input = make_dummy_input(self.model.model) + self.qc_quantize_op_dict = {} + self.connected_graph = ConnectedGraph(self.model) + self._quant_scheme = quant_scheme + self._rounding_mode = rounding_mode + self._default_param_bw = default_param_bw + self._default_activation_bw = default_activation_bw + self._default_quantization_data_type = default_data_type + self._use_symmetric_encodings = use_symmetric_encodings + self._use_cuda = use_cuda + if 'CUDAExecutionProvider' not in ort.get_available_providers(): + self._use_cuda = False + if self._use_cuda: + self._op_domain = "aimet.customop.cuda" + self.providers = [('CUDAExecutionProvider', {'device_id': device, 'cudnn_conv_algo_search': 'DEFAULT'}), 'CPUExecutionProvider'] + else: + self._op_domain = "aimet.customop.cpu" + self.providers = ['CPUExecutionProvider'] + self._user_onnx_libs = user_onnx_libs + self.param_names = [] + self.input_quantizers_name = [] + self.activation_names = [] + self.activation_dtypes = {} + self._path = path if path else tempfile.mkdtemp() + if not os.path.exists(self._path): + os.makedirs(self._path, exist_ok=True) + + # Get names of parameters and activations to quantize + self._get_param_names() + self._get_activations_to_quantize(dummy_input) + + # Disable bias quantization + self._disable_bias_quantization() + self._add_quantization_nodes() + + # Apply configurations based on provided config file. + quantsim_configurator = self._add_configuration_(config_file) + self._hw_version = quantsim_configurator._get_hw_version() + self._supported_kernels = quantsim_configurator.get_supported_kernels() + self._op_to_supported_kernel = quantsim_configurator.get_op_to_supported_kernels() + self.quant_args = extract_global_quantizer_args(quant_scheme, quantsim_configurator) + self._apply_exception_rules() + self._tie_quantizers() + + # Build onnxruntime inference session + self.session = QuantizationSimModel.build_session(self.model.model, self.providers, + user_onnx_libs=self._user_onnx_libs, path=self._path) + + def get_supported_kernels(self) -> Dict: + """ + Return _supported_kernels parsed from the config file + :return: Dictionary containing supported_kernels + """ + return self._supported_kernels + + def _add_configuration_(self, config_file: str): + """ + Add configuration based on config file + + :param config_file: Path to Configuration file for model quantizers + """ + quantsim_configurator = QuantSimConfigurator(self.model, self.connected_graph, config_file, + self._default_activation_bw, self._default_param_bw, + self._default_quantization_data_type) + quantsim_configurator.configure_quantizers(self.qc_quantize_op_dict, self.param_names, self.activation_names, + self.input_quantizers_name) + + return quantsim_configurator + + def _get_param_names(self): + """ + Get the names of params + """ + valid_ops = self._get_ops_with_parameter() + for op in valid_ops: + for param_info in op.parameters.values(): + param, _ = param_info + if param.name and param.name not in self.param_names: + self.param_names.append(param.name) + + def _get_ops_with_parameter(self) -> List[Op]: + """ + Gets ops with parameters to add quantization nodes for + + :return: Connected graph ops + """ + valid_ops = list(self.connected_graph.get_all_ops().values()) + return valid_ops + + def _get_activations_to_quantize(self, dummy_input: Dict[str, np.ndarray]): + """ + Get the names of activations to quantize + + :param dummy_input: Sample input to be run through the model + """ + self.fill_activation_dtypes(dummy_input) + self.input_name_to_nodes = self.model.input_name_to_nodes() + self.output_name_to_node = self.model.output_name_to_node() + + # Capture model inputs + for node in self.model.graph().input: + name = node.name + if name not in self.activation_names and name not in self.param_names and self._is_tensor_quantizable(name): + self.activation_names.append(name) + + # Capture intermediate activations and model outputs + for node in self.model.nodes(): + for name in node.input: + if name not in self.activation_names and name not in self.param_names and self._is_tensor_quantizable(name): + self.activation_names.append(name) + self.input_quantizers_name.append(name) + + for name in node.output: + if name not in self.activation_names and name not in self.param_names and self._is_tensor_quantizable(name): + self.activation_names.append(name) + + # Rename model output node + for node in self.model.graph().output: + if node.name in self.activation_names: + node.name += '_updated' + + def _is_tensor_quantizable(self, name: str) -> bool: + """ + Checks whether the given tensor should be quantized + + :param name: Name of the tensor + :return: True if the tensor should be quantized + """ + # Check if the tensor data-type can be quantized + if name in self.model.get_initializer_name_set(): # static activation + if self.model.get_initializer(name).data_type != 1: # 1 corresponds to float, dictionary can be found by using onnx.TensorProto.DataType.items() + return False + else: # dynamic activation + if name not in self.activation_dtypes.keys() or self.activation_dtypes[name] not in data_types_to_quantize: + return False + + # Check if the tensor is param to certain ops (eg: Resize) + consumer_nodes = self.input_name_to_nodes.get(name) + if consumer_nodes: + for consumer_node in consumer_nodes: + if consumer_node.op_type in op_params_to_ignore and \ + consumer_node.input[0] != name: # except first input rest are params (only valid for unary ops) + return False + + # Check if the tensor is output of certain ops + producer_node = self.output_name_to_node.get(name) + if producer_node and producer_node.op_type in op_outputs_to_ignore: + return False + + return True + + def _disable_bias_quantization(self): + """ + Exclude bias params from the quantization. + """ + # TODO: hitameht: we should find better way to find such patterns and corner cases. May be + # belongs to QuantSimConfigurator class. + for node in self.model.nodes(): + if node.op_type == 'Add': + if self._check_matmul_add_patten(node): + for inp_name in node.input: + param_name = inp_name + # ensure that the second input of Add op (bias) won't be configured + # with activation precision. + if (param_name in self.model.get_initializer_name_set() and + len(self.model.get_initializer(param_name).dims) == 1 and + param_name in self.activation_names): + self.activation_names.remove(param_name) + self.input_quantizers_name.remove(param_name) + + def _check_matmul_add_patten(self, node: onnx.NodeProto) -> bool: + """ + For given node, check if the previous and the current nodes are of type 'MatMul' and 'Add' respectively. + + NOTE: + Linear = (Matmul -> Add) gets fused into a single MatMul / FullyConnected HTP op. + Second input of Add (Bias) needs to be either uint8 or int32. + This utility will find such pattern and help ensure that the second input of Add op (bias) won't be configured + with activation precision. + + :param node: Onnx node + :return: True if the MatMul + Add pattern is found, False otherwise. + """ + cg_op = self.connected_graph.get_op_from_module_name(node.name) + for inp in cg_op.input_ops: + prev_cg_op = inp + # Ensure that the MatMul isn't consumed by other op. + if prev_cg_op.type == 'MatMul' and cg_op.type == 'Add' and len(prev_cg_op.output_ops) == 1: + return True + return False + + def fill_activation_dtypes(self, dummy_input: Dict[str, np.ndarray]): + """ + Get the data type for each activation + + :param dummy_input: Sample input to run through the model + """ + activations = utils.get_graph_intermediate_activations(self.model.graph()) + hooks = [] + for name in activations: + hooks.append(add_hook_to_get_activation(self.model.model, name)) + sess = QuantizationSimModel.build_session(self.model.model, ['CPUExecutionProvider'], + user_onnx_libs=self._user_onnx_libs, path=self._path) + outputs = sess.run(None, dummy_input) + for idx in range(len(self.model.graph().output)): + act_name = self.model.graph().output[idx].name + dtype = outputs[idx].dtype + self.activation_dtypes[act_name] = dtype + remove_activation_hooks(self.model.model, hooks) + + def _add_quantization_nodes(self): + """ + Call insert functions for quantization nodes + """ + self._insert_param_quantization_nodes() + self._insert_activation_quantization_nodes() + + def _replace_input_of_all_nodes(self, old_name, new_name): + if old_name not in self.connected_graph.get_all_products(): + raise ValueError(f"Tensor name {old_name} was not found in graph tensors " + f"{self.connected_graph.get_all_products().keys()}.") + + product = self.connected_graph.get_all_products()[old_name] + for consumer in product.consumers: + node = consumer.get_module() + for idx, tensor in enumerate(node.input): + if tensor == old_name: + node.input[idx] = new_name + + def _insert_param_quantization_nodes(self): + """ + Insert quantization node for each param tensor + """ + for name in self.param_names: + self._replace_input_of_all_nodes(name, name + '_qdq') + + quant_info, tensor_quantizer_params = self._create_quant_info_object_for_param(name) + custom_node = helper.make_node( + op_type='QcQuantizeOp', + inputs=[name], + outputs=[name + '_qdq'], + name='QcQuantizeOp_' + name, + domain=self._op_domain, + op_name=name, + quant_info=libpymo.PtrToInt64(quant_info), + ) + self.model.add_node(custom_node) + self.qc_quantize_op_dict[name] = QcQuantizeOp(quant_info=quant_info, + quant_scheme=self._quant_scheme, + rounding_mode=self._rounding_mode, + op_mode=OpMode.oneShotQuantizeDequantize, + bitwidth=self._default_param_bw, + use_symmetric_encodings=self._use_symmetric_encodings, + tensor_quantizer_params=tensor_quantizer_params) + + def _create_quant_info_object_for_param(self, param_name: str): + """ + Creates quant info object for QcQuantizeOp and QDQ node + + :param param_name: Name of the parameter for which the quant info object will be created + :return: quant info object + """ + quant_info = libquant_info.QcQuantizeInfo() + quant_info.usePerChannelMode = False + op = get_op_given_param_name(self.connected_graph, param_name) + param_shape = get_param_shape_using_connected_graph(self.connected_graph, param_name) + tensor_quantizer_params = TensorQuantizerParams(param_shape) + + if len(param_shape) == 1: + tensor_quantizer_params.channel_axis = 0 + tensor_quantizer_params.block_axis = None + else: + channel_axis, block_axis = self._get_quantization_axes(op) + tensor_quantizer_params.channel_axis = channel_axis + tensor_quantizer_params.block_axis = block_axis + + return quant_info, tensor_quantizer_params + + @staticmethod + def _get_quantization_axes(op: Op) -> Tuple[int, int]: + """ + Gets quantization axes for per-channel and blockwise quantization + + :param op: Connected graph op + return: axis + """ + if op.type in ['Conv']: + return 0, 1 + if op.type in ['ConvTranspose']: + return 1, 0 + if op.type in ['Gemm', 'MatMul'] and op.transposed_params: + return 0, 1 + if op.type in ['Gemm', 'MatMul']: + return 1, 0 + return None, None + + def _insert_activation_quantization_nodes(self): + """ + Insert quantization node for each activation tensor + """ + for name in self.activation_names: + self._replace_input_of_all_nodes(name, name + '_updated') + quant_info = libquant_info.QcQuantizeInfo() + custom_node = helper.make_node( + op_type='QcQuantizeOp', + inputs=[name], + outputs=[name + '_updated'], + name='QcQuantizeOp_' + name, + domain=self._op_domain, + op_name=name, + quant_info=libpymo.PtrToInt64(quant_info) + ) + self.model.add_node(custom_node) + self.qc_quantize_op_dict[name] = QcQuantizeOp(quant_info=quant_info, + quant_scheme=self._quant_scheme, + rounding_mode=self._rounding_mode, + op_mode=OpMode.updateStats, + bitwidth=self._default_activation_bw, + use_symmetric_encodings=self._use_symmetric_encodings) + + @staticmethod + def build_session(model: onnx.ModelProto, providers: List, user_onnx_libs: List[str] = None, path: str = None): + """ + Build and return onnxruntime inference session + + :param model: onnx model + :param providers: providers to execute onnxruntime + :param user_onnx_libs: list of paths to user custom ONNX op libraries + :param path: path where to store model external data + """ + sess_options = SessionOptions() + shared_library = os.path.dirname(libquant_info.__file__) + shared_library = os.path.join(shared_library, "libaimet_onnxrt_ops.so") + sess_options.register_custom_ops_library(shared_library) + if user_onnx_libs is not None: + for lib in user_onnx_libs: + sess_options.register_custom_ops_library(lib) + sess_options.graph_optimization_level = GraphOptimizationLevel.ORT_DISABLE_ALL + + # Convert and save ONNX model to external data if larger than 2GB. + # External data will be saved under same directory. + path = path if path else tempfile.mkdtemp() + if not os.path.exists(path): + os.makedirs(path, exist_ok=True) + model_size = model.ByteSize() + save_as_external_data = model_size >= onnx.checker.MAXIMUM_PROTOBUF + output_path = os.path.join(path, 'model.onnx') + if save_as_external_data: + # Note: Saving as external data mutates the saved model, removing all initializer data + onnx.save_model(model, output_path, save_as_external_data=True, location=Path(output_path).name + ".data") + onnx.load_external_data_for_model(model, base_dir=path) + + path_or_bytes = output_path if save_as_external_data else model.SerializeToString() + session = InferenceSession( + path_or_bytes=path_or_bytes, + sess_options=sess_options, + providers=providers, + ) + return session + + def get_qc_quantize_op(self): + """ + Return dict of qc quantize ops + """ + return self.qc_quantize_op_dict + + def get_op_quantizers(self, op: Op) -> (List, List, Dict): + """ + This function returns the input, output and param quantizers of the given connected graph op. + + :param op: Connected Graph Op + :return: list of input quantizers, list of output quantizers and dictionary of param quantizers + """ + input_quantizers = [] + output_quantizers = [] + param_quantizers = {} + + # Capture as input quantizer if tensor is not a layer output or parameter + for cg_product in op.inputs: + if not cg_product.producer and not cg_product.is_parm: + input_name = cg_product.name + if input_name in self.qc_quantize_op_dict: + input_quantizers.append(self.qc_quantize_op_dict[input_name]) + + # Capture output quantizers of the op + cg_product = op.output + if cg_product.name in self.qc_quantize_op_dict: + output_quantizers.append(self.qc_quantize_op_dict[cg_product.name]) + + # Capture param quantizers of the op + for param_name, (_, param_type) in op.parameters.items(): + if param_name in self.qc_quantize_op_dict: + param_quantizers[param_type] = self.qc_quantize_op_dict[param_name] + + return input_quantizers, output_quantizers, param_quantizers + + def _apply_exception_rules(self): + """ + Apply exception rules to specific op. For example, a rule can override high bitwidth to GroupNorm op. + """ + for op in self.connected_graph.ordered_ops: + input_quantizers, output_quantizers, param_quantizers = self.get_op_quantizers(op) + + if op.type == 'GroupNormalization': + if self._hw_version not in {'V73', 'V75', 'V79'}: + continue + if 'weight' in param_quantizers: + output_quantizer = output_quantizers[0] + for _, param_quantizer in param_quantizers.items(): + param_quantizer.bitwidth = output_quantizer.bitwidth + param_quantizer.use_symmetric_encodings = output_quantizer.use_symmetric_encodings + + elif op.type == 'MatMul': + first_input_quantizer = input_quantizers[0] if input_quantizers else None + second_input_quantizer = list(param_quantizers.values())[0] if param_quantizers else None + + first_input_op = op.inputs[0].producer if not first_input_quantizer else None + second_input_op = op.inputs[1].producer if not second_input_quantizer else None + + target_quantizer_for_first_input = self._get_target_quantizer(first_input_quantizer, first_input_op) + target_quantizer_for_second_input = self._get_target_quantizer(second_input_quantizer, second_input_op) + + # According to opdef for Matmul in HTP: + # 16bit Weight(second input for dynamic MatMul) must have 16bit Activation(first input for dynamic MatMul). + # 16bit Activation and 16bit Weight require minimum arch V73. + # 16bit Weight must be symmetric quantized. + + # Below are the possible combinations for MatMul with 8/16 bitwidth: + # If version is V73/V75: {input0->8, input1->8 symm/asymm} {input0->16 , input1->8 symm/asymm} {input0->16, input1->16 symmetric} + # If version is lesser than V73: {input0->8, input1->8 symmetric} {input0->16, input1->8 symmetric} + + if self._hw_version in {'V66', 'V68', 'V69'}: + if target_quantizer_for_second_input is None: + logger.warning("The target quantizer for second input could not be found. MatMul exception rule does not apply for op: %s.", op.name) + else: + target_quantizer_for_second_input.use_symmetric_encodings = True + target_quantizer_for_second_input.bitwidth = 8 + elif self._hw_version in {'V73', 'V75', 'V79'}: + if target_quantizer_for_first_input is None or target_quantizer_for_second_input is None: + logger.warning("The target quantizers could not be found. MatMul exception rule does not apply for op: %s.", op.name) + elif target_quantizer_for_second_input.bitwidth == 16: + target_quantizer_for_second_input.use_symmetric_encodings = True + target_quantizer_for_first_input.bitwidth = 16 + + def _get_target_quantizer(self, input_quantizer: QcQuantizeOp, input_op: Op) -> QcQuantizeOp: + """ + Returns input quantizer if enabled otherwise returns closest enabled parent output quantizer. + + :param input_quantizer: Input quantizer + :param input_op: CG op + :return: Target quantizer + """ + target_quantizer = None + if input_quantizer: + if input_quantizer.enabled: + target_quantizer = input_quantizer + else: + target_quantizer = self._get_closest_target_quantizer(input_op) + return target_quantizer + + # pylint: disable=inconsistent-return-statements + def _get_closest_target_quantizer(self, op: Op) -> QcQuantizeOp: + """ + Returns the closest parent output quantizer. + + :param op: CG op whose output quantizer is to be analyzed + :return: Target quantizer + """ + onnx_op = op.get_module() + + if onnx_op is None: + return self._get_closest_target_quantizer(op.input_ops[0]) + + output_tensor = onnx_op.output[0] + target_quantizer = self.qc_quantize_op_dict.get(output_tensor, None) + + if target_quantizer and target_quantizer.enabled: + return target_quantizer + + if target_quantizer is None or not target_quantizer.enabled: + if len(op.input_ops) == 1: + return self._get_closest_target_quantizer(op.input_ops[0]) + logger.warning("The op: %s with output quantization disabled has no input or more than one input exists. " + "It's ambiguous to find the closest target quantizer in this case", op.name) + return None + + def save_model_graph(self, filename_prefix: str): + """ + Save model to given path + + :param filename_prefix: filename to save the onnx model + """ + self.model.save_model_to_file(os.path.join(self._path, filename_prefix) + '.onnx') + +
    +[docs] + def compute_encodings(self, forward_pass_callback, forward_pass_callback_args): + """ + Compute and return the encodings of each tensor quantizer + + :param forward_pass_callback: A callback function that simply runs forward passes on the model. This callback + function should use representative data for the forward pass, so the calculated encodings work for all + data samples. This callback internally chooses the number of data samples it wants to use for calculating + encodings. + :param forward_pass_callback_args: These argument(s) are passed to the forward_pass_callback as-is. Up to + the user to determine the type of this parameter. E.g. could be simply an integer representing the number + of data samples to use. Or could be a tuple of parameters or an object representing something more complex. + If set to None, forward_pass_callback will be invoked with no parameters. + """ + for op_name, qc_op in self.qc_quantize_op_dict.items(): + qc_op.reset_encoding_stats() + if op_name in self.activation_names: + qc_op.op_mode = OpMode.updateStats + else: + qc_op.op_mode = OpMode.oneShotQuantizeDequantize + if qc_op.is_encoding_frozen(): + qc_op.op_mode = OpMode.quantizeDequantize + + forward_pass_callback(self.session, forward_pass_callback_args) + for op_name, qc_op in self.qc_quantize_op_dict.items(): + if qc_op.data_type == QuantizationDataType.int and not qc_op.is_encoding_frozen(): + qc_op.compute_encodings() + qc_op.op_mode = OpMode.quantizeDequantize
    + + + def _get_encodings(self, quantizer_names, enc_version): + encoding_dict = {} + for name in quantizer_names: + encoding = self.qc_quantize_op_dict[name].export_encodings(enc_version) + if encoding is None: + continue + encoding_dict[name] = encoding + + if version.parse(enc_version) < version.parse("1.0.0"): + return encoding_dict + + for name, encoding in encoding_dict.items(): + encoding["name"] = name + return list(encoding_dict.values()) + + def _export_encodings(self, encoding_file_path): + """ + Export encodings to json file + + :param encoding_file_path: path to save the encoding file + """ + enc_version = quantsim.encoding_version + if enc_version not in VALID_ENCODING_VERSIONS: + raise NotImplementedError(f'Encoding version {enc_version} not in set of valid encoding ' + f'versions {VALID_ENCODING_VERSIONS}.') + + param_encodings = self._get_encodings(self.param_names, enc_version) + activation_encodings = self._get_encodings(self.activation_names, enc_version) + + encodings_dict = {'version': enc_version, + 'activation_encodings': activation_encodings, + 'param_encodings': param_encodings, + 'quantizer_args': self.quant_args} + + save_json_yaml(encoding_file_path, encodings_dict) + + def remove_quantization_nodes(self): + """ + Remove quantization nodes + """ + self.model = self.remove_quantizers(self.model) + + @staticmethod + def remove_quantizers(model: ONNXModel): + """ + Removes all QcQuantizeOp layers from model + """ + nodes_to_remove = [] + for node in model.nodes(): + if node.op_type == 'QcQuantizeOp': + nodes_to_remove.append(node) + else: + for name in node.input: + model.replace_input_of_all_nodes(name, name.replace('_qdq', '').replace('_updated', '')) + model.remove_nodes(nodes_to_remove) + + for node in model.graph().output: + node.name = node.name.replace('_updated', '') + + return model + +
    +[docs] + def export(self, path: str, filename_prefix: str): + """ + Compute encodings and export to files + + :param path: dir to save encoding files + :param filename_prefix: filename to save encoding files + """ + if quantsim.encoding_version == '0.6.1': + msg = _red("Encoding version 0.6.1 will be deprecated in a future release, with version 1.0.0 becoming " + "the default. If your code depends on parsing the exported encodings file, ensure that it is " + "updated to be able to parse 1.0.0 format.\n" + "To swap the encoding version to 1.0.0, run the following lines prior to calling quantsim " + "export:\n\n" + "from aimet_common import quantsim\n" + "quantsim.encoding_version = '1.0.0'") + warnings.warn(msg, DeprecationWarning, stacklevel=2) + self._export_encodings(os.path.join(path, filename_prefix) + '.encodings') + self.remove_quantization_nodes() + if self.model.model.ByteSize() >= onnx.checker.MAXIMUM_PROTOBUF: + # Note: Saving as external data mutates the saved model, removing all initializer data + self.model.save_model_to_file(os.path.join(path, filename_prefix) + '.onnx', use_external_data_format=True) + onnx.load_external_data_for_model(self.model.model, base_dir=path) + else: + self.model.save_model_to_file(os.path.join(path, filename_prefix) + '.onnx')
    + + + def set_and_freeze_param_encodings(self, encoding_path: str): + """ + Set and freeze parameter encodings from encodings JSON file + + :param encoding_path: path from where to load parameter encodings file + """ + + # Load encodings file + with open(encoding_path) as json_file: + encodings = json.load(json_file) + + for quantizer_name in encodings: + if quantizer_name in self.qc_quantize_op_dict: + libpymo_encodings = _create_libpymo_encodings(encodings[quantizer_name]) + is_symmetric, is_strict_symmetric, is_unsigned_symmetric = \ + get_symmetric_properties(encodings[quantizer_name]) + data_type = QuantizationDataType.int if encodings[quantizer_name][0]['dtype'] == 'int' else \ + QuantizationDataType.float + self.qc_quantize_op_dict[quantizer_name].update_quantizer_and_load_encodings(libpymo_encodings, + is_symmetric, + is_strict_symmetric, + is_unsigned_symmetric, + data_type) + self.qc_quantize_op_dict[quantizer_name].freeze_encodings() + + def get_all_quantizers(self) -> Tuple[List, List]: + """ + Returns all QcQuantizeOps through which TensorQuantizer's attributes can be accessed. + """ + param_quantizers = [] + activation_quantizers = [] + + for param in self.param_names: + param_quantizers.append(self.qc_quantize_op_dict[param]) + + for activation in self.activation_names: + activation_quantizers.append(self.qc_quantize_op_dict[activation]) + + return param_quantizers, activation_quantizers + + def _tie_quantizers(self): + """ + Tie the input and output quantizers for given op types. + """ + if not _tie_qtzrs: + return + + cg = self.connected_graph + + def _set_quant_info(dst_qtzr_node_name: str, src_qtzr: QcQuantizeOp): + """ + Set quant_info attribute (pointer to the libquant_info object) + + :param dst_qtzr_node_name: destination quantizer node name in graph. + :param src_qtzr: source quantizer. + """ + for node in self.model.graph().node: + if node.op_type == 'QcQuantizeOp' and node.name == dst_qtzr_node_name: + for atr in node.attribute: + if atr.name == "quant_info": + atr.i = libpymo.PtrToInt64(src_qtzr.quant_info) + return + + def _set_qtzr(dst_qtzr: QcQuantizeOp, src_qtzr: QcQuantizeOp): + """ + Set the dst quantizer by src quantizer and update quant_info attribute (pointer to the libquant_info object) + in the graph node. + + :param dst_qtzr: destination quantizer. + :param src_qtzr: source quantizer + """ + for name, qtzr in self.qc_quantize_op_dict.items(): + if dst_qtzr == qtzr: + self.qc_quantize_op_dict[name] = src_qtzr + dst_qtzr_node_name = 'QcQuantizeOp_' + name + # update quant_info attribute (pointer to the libquant_info object) in the graph node. + _set_quant_info(dst_qtzr_node_name, src_qtzr) + return + + def _set_src_qtzr(x: Product, consumer: Op, src_qtzr): + producer = x.producer + + if not producer: + # ``x`` is a root input (i.e. has no producer). + # In this case, set the input quantizer of the consumer to ``src_qtzr`` + i = consumer.inputs.index(x) + inp_qtzr, _, __ = self.get_op_quantizers(consumer) + if i >= len(inp_qtzr): + return + + _set_qtzr(dst_qtzr=inp_qtzr[i], src_qtzr=src_qtzr) + return + + _, out_qtzr, __ = self.get_op_quantizers(producer) + + if out_qtzr: + # There exists output quantizer associated with the graph node ``producer`` + # In this case, set the output quantizer of the producer to ``src_qtzr` + outputs = [producer.output] + i = outputs.index(x) + _set_qtzr(dst_qtzr=out_qtzr[i], src_qtzr=src_qtzr) + + if not out_qtzr or producer.type in op_outputs_to_ignore: + # 1. There is no output quantizer associated with the graph node ``producer``, or + # 2. op is a math invariant op (reshape, permute, etc.). + # In these cases, propagate encoding further to the ancestors + for inp in producer.inputs: + _set_src_qtzr(inp, consumer=producer, src_qtzr=src_qtzr) + + for op in reversed(cg.ordered_ops): + if op.type not in op_types_to_tie_qtzrs: + continue + + _, out_qtzr, __ = self.get_op_quantizers(op) + + if not out_qtzr: + continue + + if len(out_qtzr) != 1: + msg = 'Encoding propagation is only supported for ops with exactly ' \ + f'1 output quantizer, but found {len(out_qtzr)} ' \ + 'output quantizers' + raise RuntimeError(msg) + + for inp in op.inputs: + _set_src_qtzr(inp, consumer=op, src_qtzr=out_qtzr[0])
    + + + +
    +[docs] +def load_encodings_to_sim(quant_sim_model: QuantizationSimModel, onnx_encoding_path: str, strict=True) -> \ + List[EncodingMismatchInfo]: + """ + Loads the saved encodings to quant sim model. The encoding filename to load should end in .encodings, + generated as part of quantsim export. + + :param quant_sim_model: Quantized model to load encodings for. Note: The model configuration should be the same as + when encodings were exported. + :param onnx_encoding_path: Path of the encodings file to load. + :param strict: If set to True and encoding settings between encodings to load do not line up with Quantsim + initialized settings, an assertion will be thrown. If set to False, quantizer settings will update to align with + encodings to load. + :return: List of EncodingMismatchInfo objects containing quantizer names and mismatched settings + """ + mismatched_encodings = [] + + # Load encodings file + with open(onnx_encoding_path) as json_file: + encodings = json.load(json_file) + + validate_encodings_to_load(encodings, quant_sim_model) + + # First pass through quantizers to check for mismatched encodings + for quantizer_name, quantizer in quant_sim_model.qc_quantize_op_dict.items(): + if quantizer_name not in encodings['activation_encodings'] and \ + quantizer_name not in encodings['param_encodings']: + mismatched_info = get_encoding_mismatch_info(quantizer_name, quantizer, None) + if mismatched_info.has_mismatch(): + mismatched_encodings.append(mismatched_info) + continue + + if quantizer_name in encodings['activation_encodings']: + encodings_to_load = encodings['activation_encodings'][quantizer_name] + else: + encodings_to_load = encodings['param_encodings'][quantizer_name] + + mismatched_info = get_encoding_mismatch_info(quantizer_name, quantizer, encodings_to_load) + if mismatched_info.has_mismatch(): + mismatched_encodings.append(mismatched_info) + + log_and_catch_mismatched_encodings(mismatched_encodings, strict) + + # Second pass through quantizers to set quantizer settings + for quantizer_name, quantizer in quant_sim_model.qc_quantize_op_dict.items(): + if quantizer_name not in encodings['activation_encodings'] and \ + quantizer_name not in encodings['param_encodings']: + quantizer.enabled = False + continue + + if quantizer_name in encodings['activation_encodings']: + encodings_to_load = encodings['activation_encodings'][quantizer_name] + else: + encodings_to_load = encodings['param_encodings'][quantizer_name] + + is_symmetric, is_strict_symmetric, is_unsigned_symmetric = \ + get_symmetric_properties(encodings_to_load) + data_type = QuantizationDataType.int if encodings_to_load[0]['dtype'] == 'int' else \ + QuantizationDataType.float + libpymo_encodings = _create_libpymo_encodings(encodings_to_load) + quant_sim_model.qc_quantize_op_dict[quantizer_name].update_quantizer_and_load_encodings( + libpymo_encodings, is_symmetric, is_strict_symmetric, is_unsigned_symmetric, data_type) + + return mismatched_encodings
    + + + +def validate_encodings_to_load(encodings_to_load: Dict, quant_sim_model: QuantizationSimModel): + """ + Validate that all names of encodings to load are found in the model. + + :param encodings_to_load: Encodings to load + :param quant_sim_model: Quantsim model to check for encoding names. + """ + # Check that all encoding names in the encodings to load are found in the model. This check only works for verifying + # that names in encodings_to_load are valid. The reverse check will not work, since quantizers which are disabled + # will not show up in encodings_to_load. + encoding_names_not_found = [] + for quantizer_name in (list(encodings_to_load['activation_encodings'].keys()) + + list(encodings_to_load['param_encodings'].keys())): + if quantizer_name not in quant_sim_model.qc_quantize_op_dict: + encoding_names_not_found.append(quantizer_name) + if encoding_names_not_found: + logger.error('The following encoding names were present in the encodings to load but not found in the model: ' + '%s', str(encoding_names_not_found)) + raise AssertionError('The following encoding names were present in the encodings to load but not found in the ' + 'model: ' + str(encoding_names_not_found)) + + +def log_and_catch_mismatched_encodings(mismatched_encodings: List[EncodingMismatchInfo], strict: bool): + """ + If mismatched_encodings is not empty, log details for each entry. If strict is True, raise an AssertionError. + + :param mismatched_encodings: List of mismatched quantizer names and encoding settings + :param strict: If True, raise an AssertionError if there are mismatched settings + """ + if mismatched_encodings: + logging_strings = ['The following quantizers had settings not matching with provided encodings to load:'] + for mismatched_encoding_info in mismatched_encodings: + logging_strings.append(mismatched_encoding_info.quantizer_name + ':') + if mismatched_encoding_info.enabled_mismatch: + logging_strings.append(f'\tenabled: {mismatched_encoding_info.enabled_mismatch[0]}, ' + f'loaded encoding enabled: ' + f'{mismatched_encoding_info.enabled_mismatch[1]}') + + if mismatched_encoding_info.dtype_mismatch: + logging_strings.append(f'\tdtype: {mismatched_encoding_info.dtype_mismatch[0]}, ' + f'loaded encoding dtype: ' + f'{mismatched_encoding_info.dtype_mismatch[1]}') + + if mismatched_encoding_info.bitwidth_mismatch: + logging_strings.append(f'\tbitwidth: ' + f'{mismatched_encoding_info.bitwidth_mismatch[0]}, loaded encoding bitwidth:' + f'{mismatched_encoding_info.bitwidth_mismatch[1]}') + + if mismatched_encoding_info.is_symmetric_mismatch: + logging_strings.append(f'\tsymmetric: ' + f'{mismatched_encoding_info.is_symmetric_mismatch[0]}, ' + f'loaded encoding symmetric: ' + f'{mismatched_encoding_info.is_symmetric_mismatch[1]}') + + if mismatched_encoding_info.is_strict_symmetric_mismatch: + logging_strings.append(f'\tstrict symmetric: ' + f'{mismatched_encoding_info.is_strict_symmetric_mismatch[0]}, ' + f'loaded encoding strict symmetric: ' + f'{mismatched_encoding_info.is_strict_symmetric_mismatch[1]}') + + if mismatched_encoding_info.is_unsigned_symmetric_mismatch: + logging_strings.append(f'\tunsigned symmetric: ' + f'{mismatched_encoding_info.is_unsigned_symmetric_mismatch[0]}, ' + f'loaded encoding unsigned symmetric: ' + f'{mismatched_encoding_info.is_unsigned_symmetric_mismatch[1]}') + log_message = '\n'.join(logging_strings) + if strict: + logger.error(log_message) + raise AssertionError(log_message) + logger.info(log_message) + + +def _create_libpymo_encodings(encoding: Dict[str, Union[str, int, float]]) -> List[libpymo.TfEncoding]: + """ + Given encoding dict, return a TfEncoding object with corresponding info. + + :param encoding: Encoding dict to create TfEncoding object with + :return: TfEncoding object containing encoding dict info + """ + libpymo_encodings = [] + for enc_val in encoding: + enc = libpymo.TfEncoding() + enc.bw = enc_val['bitwidth'] + enc.delta, enc.max, enc.min, enc.offset = 0.0, 0.0, 0.0, 0 + if enc_val['dtype'] == 'int': + enc.delta, enc.max, enc.min, enc.offset = (enc_val['scale'], enc_val['max'], enc_val['min'], + enc_val['offset']) + libpymo_encodings.append(enc) + return libpymo_encodings + + +def get_symmetric_properties(encodings: List[Dict]) -> Tuple[Optional[bool], Optional[bool], Optional[bool]]: + """ + Return symmetric properties of the given encodings. If encodings are float, return None for each. + + :param encodings: Encodings to get symmetric properties for + :return: Tuple of is_symmetric, is_strict_symmetric, and is_unsigned symmetric properties + """ + if encodings[0]['dtype'] == 'float': + return None, None, None + + is_symmetric = encodings[0]['is_symmetric'] == 'True' + + is_strict_symmetric = False + if is_symmetric and encodings[0]['offset'] == -2**(encodings[0]['bitwidth'] - 1) + 1: + is_strict_symmetric = True + + # Note: Even if the original quantizer had is_unsigned_symmetric set to True, if any observed values were negative, + # the resulting encodings will look signed. This logic can only perform a best effort check to return True only if + # any encoding showed unsigned symmetric properties. + is_unsigned_symmetric = False + if is_symmetric: + for encoding in encodings: + if encoding['offset'] == 0: + is_unsigned_symmetric = True + break + return is_symmetric, is_strict_symmetric, is_unsigned_symmetric + +def get_encoding_mismatch_info(quantizer_name: str, quantizer: QcQuantizeOp, + encodings_to_load: Optional[List[Dict]]) -> EncodingMismatchInfo: + """ + Check that quantizer settings align with the settings in encodings_to_load. If settings do not align, track the + mismatching settings in a EncodingMismatchInfo object and add it to mismatched_encodings_info list. + + :param quantizer_name: Name of quantizer to check + :param quantizer: Quantizer to check + :param encodings_to_load: Encodings to check + """ + encoding_mismatch_info = EncodingMismatchInfo(quantizer_name) + + # Match enabled state + if quantizer.enabled and encodings_to_load is None: + encoding_mismatch_info.enabled_mismatch = (quantizer.enabled, False) + if not quantizer.enabled and encodings_to_load is not None: + encoding_mismatch_info.enabled_mismatch = (quantizer.enabled, True) + + if encodings_to_load is not None: + is_symmetric, is_strict_symmetric, is_unsigned_symmetric = get_symmetric_properties(encodings_to_load) + + if quantizer.bitwidth != encodings_to_load[0]['bitwidth']: + encoding_mismatch_info.bitwidth_mismatch = (quantizer.bitwidth, encodings_to_load[0]['bitwidth']) + if quantizer.data_type.name != encodings_to_load[0]['dtype']: + encoding_mismatch_info.dtype_mismatch = (quantizer.data_type.name, encodings_to_load[0]['dtype']) + if quantizer.use_symmetric_encodings != is_symmetric: + encoding_mismatch_info.is_symmetric_mismatch = (quantizer.use_symmetric_encodings, is_symmetric) + if quantizer.use_strict_symmetric != is_strict_symmetric: + encoding_mismatch_info.is_strict_symmetric_mismatch = (quantizer.use_strict_symmetric, is_strict_symmetric) + + # Unsigned symmetric is a special case because even if the setting is true, the encodings may appear to be + # signed symmetric if any observed tensor values were < 0. + # In this case, only mark a mismatch if quantizer was set to signed symmetric but an unsigned symmetric + # encoding was seen. + if quantizer.use_unsigned_symmetric != is_unsigned_symmetric and not quantizer.use_unsigned_symmetric: + encoding_mismatch_info.is_unsigned_symmetric_mismatch = (quantizer.use_unsigned_symmetric, + is_unsigned_symmetric) + + return encoding_mismatch_info + + +def set_blockwise_quantization_for_weights(sim: QuantizationSimModel, + op_types: Union[str, Tuple], + bitwidth: int, + symmetric: bool, + block_size: int, + strict: bool = False): + """ + Set weight quantizers for the given operator types to use blockwise affine quantization. + + :param sim: Quantsim object to configure weight quantizers for + :param op_types: Operator types for which to enable blockwise weight quantizaiton + :param bitwidth: Bitwidth for quantization + :param symmetric: True if quantization is symmetric, False otherwise + :param block_size: Block size for affine quantization. The block size will be applied to the weight's input features + dimension, while per-channel will be used for the weight's output features dimension + :param strict: If False, only enable blockwise quant for layers with dimensions evenly divisible by block_size. + If True, throw an error for layers with incompatible shapes. + + Examples: + + >>> # Assume 'sim' is a QuantizationSimModel object + >>> # Allows setting of all Linear and Conv weight quantizers to block_size 64 in the input_channels dimension: + >>> set_blockwise_quantization_for_weights(sim=sim, + ... op_types=("Gemm", "MatMul", "Conv"), + ... bitwidth=4, + ... symmetric=True, + ... block_size=64) + """ + + if isinstance(op_types, str): + op_types = (op_types, ) + + for op in sim.connected_graph.ordered_ops: + if op.type in op_types: + _, _, param_quantizers = sim.get_op_quantizers(op) + + if "weight" in param_quantizers.keys(): + weight_quantizer: QcQuantizeOp = param_quantizers["weight"] + + try: + weight_quantizer._enable_blockwise_quantization(block_size) # pylint:disable = protected-access + except ValueError as e: + if strict: + raise e + else: + weight_quantizer.set_bitwidth(bitwidth) + weight_quantizer.use_symmetric_encodings = symmetric + weight_quantizer.data_type = QuantizationDataType.int + + +
    +[docs] +def set_grouped_blockwise_quantization_for_weights(sim: QuantizationSimModel, + op_types: Union[str, Tuple], + bitwidth: int, + decompressed_bw: int, + block_size: int, + strict: bool = False): + """ + Set weight parameter quantizers of modules to grouped blockwise quantization. + + :param sim: Quantsim to set weight quantizers for + :param op_types: Operator types for which to enable grouped blockwise weight quantizaiton + :param bitwidth: Bitwidth for affine quantization + :param decompressed_bw: Decompressed bw for grouped block quantization + :param block_size: Block size for affine quantization. The block size will be applied to the weight's input features + dimension, while per-channel will be used for the weight's output features dimension + + Examples: + + >>> # Assume 'sim' is a QuantizationSimModel object + >>> # Sets of all Gemm, MatMul, and Conv weight quantizers to block_size 64 in the input_channels dimension: + >>> set_grouped_blockwise_quantization_for_weights(sim=sim, + ... op_types=("Gemm", "MatMul", "Conv"), + ... bitwidth=4, + ... decompressed_bw=8, + ... block_size=64) + """ + + if isinstance(op_types, str): + op_types = (op_types, ) + + for op in sim.connected_graph.ordered_ops: + + if op.type in op_types: + _, _, param_quantizers = sim.get_op_quantizers(op) + + + if "weight" in param_quantizers.keys(): + weight_quantizer: QcQuantizeOp = param_quantizers["weight"] + + try: + grouped_quantizer = GroupedBlockQuantizeDequantize(weight_quantizer.quant_info, + bitwidth, + decompressed_bw, + block_size, + weight_quantizer.quant_scheme, + weight_quantizer.op_mode, + weight_quantizer.tensor_quantizer_params) + except ValueError as e: + if strict: + raise e + else: + for name, quantizer in sim.qc_quantize_op_dict.items(): + if quantizer is weight_quantizer: + sim.qc_quantize_op_dict[name] = grouped_quantizer
    + + + +# pylint: disable=protected-access +def clamp_activation_encodings(quant_sim: QuantizationSimModel, clamp_val: float): + """ + Clamp activations to specific range if out of bound. + + :param quant_sim: quantsim object + :param clamp_val: positive float value + :return: + """ + for act_name in quant_sim.activation_names: + quantizer = quant_sim.qc_quantize_op_dict.get(act_name) + is_clipped = quantizer.clip_and_recompute_encodings(clamp_val) + if is_clipped: + logger.info("Clamped tensor %s", act_name) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_onnx/sequential_mse/seq_mse.html b/releases/2.0.0/_modules/aimet_onnx/sequential_mse/seq_mse.html new file mode 100644 index 0000000..be27513 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_onnx/sequential_mse/seq_mse.html @@ -0,0 +1,979 @@ + + + + + + + + aimet_onnx.sequential_mse.seq_mse - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_onnx.sequential_mse.seq_mse

    +# /usr/bin/env python
    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Sequential MSE implementation """
    +
    +# pylint: disable=no-name-in-module, ungrouped-imports, too-many-lines
    +
    +import copy
    +from typing import List
    +import numpy as np
    +import torch
    +from onnxruntime.quantization.onnx_quantizer import ONNXModel
    +from onnx import numpy_helper
    +from onnx.utils import Extractor
    +
    +# pylint: disable=wrong-import-order
    +from aimet_onnx.quantsim import QuantizationSimModel
    +from aimet_onnx.qc_quantize_op import QcQuantizeOp
    +from aimet_onnx.sequential_mse.dependency_graph_utils import DependencyGraphUtils
    +from aimet_onnx.sequential_mse.dependency_graph import DependencyGraph
    +from aimet_onnx.sequential_mse.dependency_graph import DependencyNode
    +from aimet_common.libpymo import TensorQuantizerOpMode
    +from aimet_common.defs import QuantScheme
    +from aimet_onnx.meta.connectedgraph import ConnectedGraph
    +from aimet_common.utils import AimetLogger
    +from dataclasses import dataclass
    +
    +from onnx import TensorProto
    +
    +
    +SUPPORTED_MODULES = ("Conv", "Gemm", "MatMul")
    +
    +_logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.SeqMse)
    +
    +
    +[docs] +@dataclass +class SeqMseParams: + """ + Sequential MSE parameters + + :param num_batches: Number of batches. + :param num_candidates: Number of candidates to perform grid search. Default 20. + :param inp_symmetry: Input symmetry. Available options are 'asym', 'symfp' and 'symqt'. Default 'symqt'. + :param loss_fn: Loss function. Available options are 'mse', 'l1' and 'sqnr'. Default 'mse'. + """ + num_batches: int = 4 + num_candidates: int = 20 + inp_symmetry: str = 'symqt' + loss_fn: str = 'mse'
    + + +# pylint: disable=too-many-instance-attributes +class SequentialMse: + """ + Sequentially minimizing activation MSE loss in layer-wise way to decide optimal param quantization encodings. + """ + + def __init__(self, + model, + sim: QuantizationSimModel, + params: SeqMseParams, + data_loader): + + """ + Initialize the sequential mse object + + :param model: float model + :param sim: QuantizationSimModel object + :param data_loader: Torch Dataloader + :param params: Sequential MSE parameters + """ + + # pylint: disable=protected-access + assert sim._quant_scheme in (QuantScheme.post_training_tf, QuantScheme.training_range_learning_with_tf_init), \ + "Use TF quant-scheme with sequential MSE." + + self.sim = sim + self.model = model + self.params = params + self.node_name_to_input_names = dict() + self.static_tensor_name_to_proto = dict() + + if not isinstance(self.model, ONNXModel): + self.model = ONNXModel(self.model) + + self._fill_node_name_to_input_names() + self._fill_static_tensor_name_to_proto() + + raw_data = dict() + for initializer in self.model.model.graph.initializer: + if initializer.HasField('raw_data'): + raw_data[initializer.name] = initializer.raw_data + initializer.ClearField("raw_data") + + self._float_extractor = Extractor(self.model.model) + + for initializer in self.model.model.graph.initializer: + if initializer.name in raw_data: + initializer.raw_data = raw_data[initializer.name] + + for initializer in self._float_extractor.model.graph.initializer: + if initializer.name in raw_data: + initializer.raw_data = raw_data[initializer.name] + + self._sim_extractor = copy.deepcopy(self._float_extractor) + + self._update_value_info() + + self._sim_extractor.model = self.sim.model.model + self._sim_extractor.graph = self.sim.model.model.graph + + self.connected_graph = ConnectedGraph(self.model) + + self.data_loader = data_loader + + self.dependency_graph = DependencyGraph() + self.dependency_graph_utils = DependencyGraphUtils(self.connected_graph, self.node_name_to_input_names, + self.static_tensor_name_to_proto) + self.quantizers_to_be_disabled = self._get_quantizers_to_be_disabled() # check this + + def _update_value_info_for_output(self, node): + """ + Updates the value info for output of a node in sim model. + Value info for QcQuantizeOp is not present in _sim_extractor + + :param node: onnx node + """ + + input_name = node.input[0] + output_name = node.output[0] + if input_name in self._sim_extractor.vimap and output_name not in self._sim_extractor.vimap: + value_info_for_output = copy.deepcopy(self._sim_extractor.vimap[input_name]) + value_info_for_output.name = node.output[0] + self._sim_extractor.vimap[node.output[0]] = value_info_for_output + + def _update_value_info_for_input(self, node): + """ + Updates the value info for input of a node in sim model. + Value info for QcQuantizeOp is not present in _sim_extractor + + :param node: onnx node + """ + + input_name = node.input[0] + output_name = node.output[0] + if output_name in self._sim_extractor.vimap and input_name not in self._sim_extractor.vimap: + value_info_for_input = copy.deepcopy(self._sim_extractor.vimap[output_name]) + value_info_for_input.name = node.input[0] + self._sim_extractor.vimap[node.input[0]] = value_info_for_input + + def _update_value_info_for_graph_output(self): + """ + Updates the value info for input of a node in sim model. + Value info for QcQuantizeOp is not present in _sim_extractor + + :param node: onnx node + """ + + for value_info in self.model.model.graph.output: + self._float_extractor.vimap[value_info.name] = value_info + + for value_info in self.sim.model.model.graph.output: + self._sim_extractor.vimap[value_info.name] = value_info + + def _update_value_info(self): + """ + Updates the value info for sim model. + Value info for QcQuantizeOp is not present in _sim_extractor + """ + + self._update_value_info_for_graph_output() + + for node in self.sim.model.nodes(): + if node.op_type == "QcQuantizeOp": + self._update_value_info_for_output(node) + self._update_value_info_for_input(node) + + def _fill_static_tensor_name_to_proto(self): + """ + Fills the mapping from static tensor name to the prop buf + """ + for initializer in self.model.model.graph.initializer: + self.static_tensor_name_to_proto[initializer.name] = initializer + + for node in self.model.model.graph.node: + if node.op_type == "Constant": + self.static_tensor_name_to_proto[node.output[0]] = node + + # pylint: disable=inconsistent-return-statements + def _extract_float_data_from_proto(self, name): + """ + returns the tensor value of the given name using static_tensor_name_to_proto dictionary + :param name: name of the static tensor + :return tensor value + """ + if name in self.static_tensor_name_to_proto: + proto_buf = self.static_tensor_name_to_proto[name] + if isinstance(proto_buf, TensorProto): + return numpy_helper.to_array(proto_buf) + + for attr in proto_buf.attribute: + if attr.name == "value": + return numpy_helper.to_array(attr.t) + else: + raise ValueError(name, " is neither constant or initializer") + + def _fill_node_name_to_input_names(self): + """ + Fills the mapping from node name to input names + """ + for node in self.model.nodes(): + self.node_name_to_input_names[node.name] = node.input + + @staticmethod + def apply_seq_mse(model, sim: QuantizationSimModel, params: SeqMseParams, data_loader): + """ + It performs following steps: + 1) creates seq_mse object + 2) call apply_seq_algo() member function + + :param model: float model + :param sim: QuantizationSimModel object + :param data_loader: Data loader + :param params: Sequential MSE parameters + """ + seq_mse = SequentialMse(model, sim, params, data_loader) + seq_mse.apply_seq_mse_algo() + + def apply_seq_mse_algo(self): + """ + It performs following steps: + 1) disable the quantizer for unsupported modules + 2) create the dependency graph + 3) run the onnx graph and compute encoding using seq mse algorithm + 4) re-enable the quantizer disabled in first step + """ + + try: + self.temporarily_disable_quantizers() + self.dependency_graph = self.dependency_graph_utils.create_dependency_graph(self.data_loader, + self.params.num_batches) + self._run_onnx_graph_dependency_graph_order() + finally: + self.re_enable_quantizers() + + def _get_quantizers_to_be_disabled(self) -> List[QcQuantizeOp]: + """ + :return Returns the quantizers of unsupported modules + """ + + quantizer_to_disable_name = list() + quantizer_to_not_disable_name = list() + + for name, qc_quantize_op in self.sim.qc_quantize_op_dict.items(): + if qc_quantize_op.enabled: + quantizer_to_disable_name.append(name) + + for node in self.model.nodes(): + if self.dependency_graph_utils.is_supported_module(node): + weight_node_name = node.input[1] + quantizer_to_not_disable_name.append(weight_node_name) + + quantizer_to_disable_name = [name for name in quantizer_to_disable_name + if name not in quantizer_to_not_disable_name] + + quantizer_to_disable = list() + + for name in quantizer_to_disable_name: + if name in self.sim.qc_quantize_op_dict: + quantizer_to_disable.append(self.sim.qc_quantize_op_dict[name]) + + return quantizer_to_disable + + def temporarily_disable_quantizers(self): + """ + Disable quantizers needed to be disabled before applying sequential MSE. + """ + for quantizer in self.quantizers_to_be_disabled: + quantizer.enabled = False + + def re_enable_quantizers(self): + """ + Re-enable quantizers that were disabled by temporarily_disable_quantizers method + """ + for quantizer in self.quantizers_to_be_disabled: + quantizer.enabled = True + + def _get_min_max_from_weights(self, dependency_node: DependencyNode): + """ + Get per channel min/max values across output channel. + + :param dependency_node: Dependevy node which is to be optimized + :return: per_channel_min and per_channel_max + """ + + weight_name = self.node_name_to_input_names[dependency_node.op_name][1] + weight_data = self._extract_float_data_from_proto(weight_name) + + connected_op = self.connected_graph.get_op_from_module_name(dependency_node.op_name) + # pylint: disable=protected-access + channel_axis = QuantizationSimModel._get_quantization_axes(connected_op)[0] + # pylint: disable=consider-using-generator, use-a-generator + axis = tuple([i for i in range(len(weight_data.shape)) if i != channel_axis]) + + per_channel_max = np.max(abs(weight_data), axis=axis) + + return [-per_channel_max, per_channel_max] + + def _get_candidates(self, per_channel_max, per_channel_min): + """ + Perform grid search. + :param per_channel_max: Per channel max values + :param per_channel_min: Per channel min values + :return: candidates + """ + candidates = list() + num_candidates = self.params.num_candidates + for i in range(num_candidates): + cand_max = per_channel_max / num_candidates * (i + 1) + cand_min = per_channel_min / num_candidates * (i + 1) + candidates.append((cand_max, cand_min)) + return candidates + + def _compute_encoding_from_candidate(self, candidate, dependency_node: DependencyNode): + """ + computes the encoding using candidate min and candidate max + + :param candidate: list containing min and max value + :param dependency_node: Corresponding Dependency node + :return: encoding + """ + + cand_max = candidate[0] + cand_min = candidate[1] + + cand = np.stack((cand_max, cand_min), axis=-1) + + weight_name = self.node_name_to_input_names[dependency_node.op_name][1] + + quantize_op = self.sim.qc_quantize_op_dict[weight_name] + + quantize_op.reset_encoding_stats() + + # pylint: disable=protected-access + tensor_quantizers = quantize_op._tensor_quantizer + + if len(tensor_quantizers) != len(cand) and len(tensor_quantizers) != 1: + raise ValueError(weight_name, " should be per-tensor or number of " + "quantizer must match with number of channels") + + # pylint: disable=protected-access + if len(tensor_quantizers) == 1: + tensor_quantizer = tensor_quantizers[0] + tensor_quantizer.updateStats(cand, False) + else: + for i, tensor_quantizer in enumerate(tensor_quantizers): + tensor_quantizer.updateStats(cand[i], False) + + quantize_op.compute_encodings() + + quantize_op.op_mode = TensorQuantizerOpMode.quantizeDequantize + + def _freeze_encodings(self, dependency_node: DependencyNode): + """ + Freezes the encoding after the node is optimized + :param dependency_node: Optimized dependency node + """ + weight_name = self.node_name_to_input_names[dependency_node.op_name][1] + quantize_op = self.sim.qc_quantize_op_dict[weight_name] + quantize_op.freeze_encodings() + + @staticmethod + def neg_sqnr(pred: torch.Tensor, target: torch.Tensor, eps=1e-10, reduction="none"): + """ + Loss function to minimize negative SQNR which is equivalent to maximizing SQNR. + + :param pred: X^Q^ quantized-dequantized values + :param target: XW FP32 values + :param eps: epsilon + :param reduction: unused arg + :return: Negative SQNR + """ + # pylint: disable=unused-argument + quant_error = target - pred + exp_noise = torch.mean(quant_error ** 2, 0, keepdim=True) + eps + exp_signal = torch.mean(target ** 2, 0, keepdim=True) + sqnr = exp_signal / exp_noise + sqnr_db = 10 * torch.log10(sqnr) + return -sqnr_db + + def _compute_recon_loss(self, sim_output, float_output, dependency_node): + """ + Compute reconstruction loss and return the sum by reducing over all the dimensions except last channel dimension. + + :param xqwq: X^Q^ quantized-dequantized values + :param xw: XW FP32 values + :param params: Sequential MSE parameters + :return: loss + """ + + xqwq = torch.from_numpy(sim_output) + xw = torch.from_numpy(float_output) + + if dependency_node.op_type == "Conv": + permute_order = [0] + list(range(2, xw.dim())) + [1] + xqwq = xqwq.permute(permute_order) + xw = xw.permute(permute_order) + + if self.params.loss_fn == "mse": + loss_fn = torch.nn.functional.mse_loss + elif self.params.loss_fn == "l1": + loss_fn = torch.nn.functional.l1_loss + elif self.params.loss_fn == "sqnr": + loss_fn = SequentialMse.neg_sqnr + else: + raise ValueError(f"Invalid loss function: {self.params.loss_fn}") + + + + channel_dim = xqwq.shape[-1] + xqwq = xqwq.reshape(-1, channel_dim) + xw = xw.reshape(-1, channel_dim) + loss = loss_fn(xqwq, xw, reduction="none").sum(0) + assert loss.size() == torch.Size([channel_dim]) + return np.array(loss) + + # pylint: disable-msg=too-many-locals + def _do_seq_mse(self, dependency_node: DependencyNode): + """ + Find and freeze optimal parameter encodings candidate for given dependency node. + :param dependency_node: Corresponding Dependency node + """ + per_channel_min, per_channel_max = self._get_min_max_from_weights(dependency_node) + + candidates = self._get_candidates(per_channel_max, per_channel_min) + + total_loss = list() + + float_split_model, sim_split_model = self._split_onnx_graph(dependency_node.op_input_names, + dependency_node.op_output_names) + + _logger.info("Finding and freezing optimal param encodings candidate of op: %s", dependency_node.op_name) + # for different modes only inputs will change + if self.params.inp_symmetry == "asym": + float_inputs = self.dependency_graph.get_float_data(dependency_node) + sim_inputs = self.dependency_graph.get_sim_data(dependency_node) + elif self.params.inp_symmetry == "symfp": + float_inputs = self.dependency_graph.get_float_data(dependency_node) + sim_inputs = self.dependency_graph.get_float_data(dependency_node) + elif self.params.inp_symmetry == "symqt": + float_inputs = self.dependency_graph.get_sim_data(dependency_node) + sim_inputs = self.dependency_graph.get_sim_data(dependency_node) + else: + raise ValueError(f"Invalid inp_symmetry: {self.params.inp_symmetry}") + + float_outputs = self._run_onnx_graph(float_split_model, float_inputs) + float_outputs = np.concatenate(float_outputs[0], axis=0) + + for candidate in candidates: + + self._compute_encoding_from_candidate(candidate, dependency_node) + + sim_outputs = self._run_onnx_graph(sim_split_model, sim_inputs) + sim_outputs = np.concatenate(sim_outputs[0], axis=0) + + loss = self._compute_recon_loss(sim_outputs, float_outputs, dependency_node) + + total_loss.append(loss) + + stacked_loss = np.stack(total_loss, axis=0) + arg_min_ = np.argmin(stacked_loss, axis=0, keepdims=True) + + best_max = torch.stack([torch.tensor(cand_max) for cand_max, _ in candidates]).gather(0, torch.tensor(arg_min_))[0] + best_min = torch.stack([torch.tensor(cand_min) for _, cand_min in candidates]).gather(0, torch.tensor(arg_min_))[0] + + best_candidate = (best_max, best_min) + + self._compute_encoding_from_candidate(best_candidate, dependency_node) + self._freeze_encodings(dependency_node) + + # pylint: disable=no-self-use + def _get_input_names_from_dependencies(self, dependency_node: DependencyNode): + """ + Returns the input names for the op corresponding to dependency node + + :param dependency_node: Corresponding Dependency node + :return: input names for the op corresponding to dependency node + """ + + input_names = set() + + for inward_node in dependency_node.inward_nodes: + input_names.update(inward_node.op_input_names) + + return list(input_names) + + def _get_inputs_from_dependencies(self, dependency_node: DependencyNode): + """ + Returns the input needed for the op corresponding to the dependency node + + :param dependency_node: Corresponding dependency node + :return: float inputs and sim inputs + """ + + float_inputs = dict() + sim_inputs = dict() + + for inward_node in dependency_node.inward_nodes: + float_inputs.update(self.dependency_graph.get_float_data(inward_node)) + sim_inputs.update(self.dependency_graph.get_sim_data(inward_node)) + + return float_inputs, sim_inputs + + def _split_onnx_graph(self, input_names, output_names): + """ + Splits the onnx graph from input names to output names using extractor + + :param input_names: input names of split graph + :param output_names: output names of split graph + :return: float split model and sim split model + """ + float_split_model = self._float_extractor.extract_model(list(input_names), list(output_names)) + sim_split_model = self._sim_extractor.extract_model(list(input_names), list(output_names)) + return float_split_model, sim_split_model + + def _run_onnx_graph(self, model, inputs): + """ + Run the onnx graph using onnx runtime + + :param model: Corresponding model + :param inputs: inputs to the model + :return: outputs + """ + # pylint: disable=protected-access + session = QuantizationSimModel.build_session(model, self.sim.providers, + user_onnx_libs=self.sim._user_onnx_libs, path=self.sim._path) + + outputs = list() + + num_batches = min(self.params.num_batches, len(self.data_loader.dataset) // self.data_loader.batch_size) + + for i in range(num_batches): + input_batch = dict() + for name, data in inputs.items(): + input_batch[name] = data[i] + output = session.run(None, input_batch) + if len(outputs) == 0: + outputs = [list() for _ in range(len(output))] + for idx, out in enumerate(output): + outputs[idx].append(out) + + return outputs + + def _process_dependency_nodes(self, dependency_node: DependencyNode): + """ + 1) Get input names, output names using dependency graph + 2) Split the graph using input names and output names + 3) Run the split graph + 4) Decrease the out-degree of the inward nodes by -1, if outdegree becomes zero, then delete the data + 5) Optimize the dependency node + + :param dependency_node: Corresponding dependency node + """ + # get input names and output names, split and run and do_seq_mse + # then make out_degree of the inward nodes -1, if that becomes zero delete the data + + input_names = self._get_input_names_from_dependencies(dependency_node=dependency_node) + + graph_inputs = [node.name for node in self.model.model.graph.input] + output_names = [name for name in dependency_node.op_input_names if name not in graph_inputs] + + float_split_model, sim_split_model = self._split_onnx_graph(input_names=input_names, output_names=output_names) + float_inputs, sim_inputs = self._get_inputs_from_dependencies(dependency_node=dependency_node) + + float_outputs = self._run_onnx_graph(model=float_split_model, inputs=float_inputs) + self.dependency_graph.update_float_data(output_names, float_outputs) + + sim_outputs = self._run_onnx_graph(model=sim_split_model, inputs=sim_inputs) + self.dependency_graph.update_sim_data(output_names, sim_outputs) + + for inward_node in dependency_node.inward_nodes: + inward_node.outdegree = inward_node.outdegree - 1 + if inward_node.outdegree == 0: + self.dependency_graph.dec_ref_count(inward_node) + + if dependency_node.op_type in SUPPORTED_MODULES: + self._do_seq_mse(dependency_node=dependency_node) + + def _do_topo_sort_helper(self, dependency_node: DependencyNode): + """ + 1) Decrease indegree of the child ops by -1, if the indegree becomes zero, then process the node + 2) run _do_topo_sort_helper for the child node + + :param dependency_node: Corresponding dependency node + """ + # make indegree of the child ops -1, if the indegree becomes zero split and run and do_seq_mse + # then make out_degree of the inward nodes -1, if that becomes zero delete the data + # then call _do_topo_sort_helper for that node + + for child_node in dependency_node.outward_nodes: + child_node.indegree = child_node.indegree - 1 + if child_node.indegree == 0: + self._process_dependency_nodes(dependency_node=child_node) + self._do_topo_sort_helper(dependency_node=child_node) + + def _run_onnx_graph_dependency_graph_order(self): + """ + Start the topo sort from the starting ops i.e. ops having indegree equal to zero + """ + + for start_op in self.dependency_graph.starting_ops: + if start_op.op_type in SUPPORTED_MODULES: + self._do_seq_mse(dependency_node=start_op) + self._do_topo_sort_helper(dependency_node=start_op) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_tensorflow/keras/adaround_weight.html b/releases/2.0.0/_modules/aimet_tensorflow/keras/adaround_weight.html new file mode 100644 index 0000000..ba2f043 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_tensorflow/keras/adaround_weight.html @@ -0,0 +1,698 @@ + + + + + + + + aimet_tensorflow.keras.adaround_weight - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_tensorflow.keras.adaround_weight

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Top level API for Adaptive Rounding - Post-Training Quantization (PTQ) """
    +
    +import os
    +import json
    +from typing import Dict, List, Union, Iterable, Tuple
    +import numpy as np
    +import tensorflow as tf
    +from tensorflow.keras.utils import Progbar
    +
    +import aimet_common.libpymo as libpymo
    +from aimet_common.utils import AimetLogger
    +from aimet_common.defs import QuantScheme
    +from aimet_common.quantsim_config.json_config_importer import JsonConfigImporter, ConfigDictKeys, ConfigDictType
    +from aimet_tensorflow.keras.adaround.activation_sampler import ActivationSampler
    +from aimet_tensorflow.keras.adaround.adaround_loss import AdaroundHyperParameters
    +from aimet_tensorflow.keras.adaround.adaround_wrapper import AdaroundWrapper
    +from aimet_tensorflow.keras.adaround.adaround_optimizer import AdaroundOptimizer
    +from aimet_tensorflow.keras.connectedgraph import ConnectedGraph, map_keras_types_to_onnx
    +from aimet_tensorflow.keras.quantsim_config.quantsim_config import MAP_TF_PARAM_NAME_TO_QUANTSIM_NAME
    +
    +_logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.Quant)
    +
    +AdaroundSupportedOps = (tf.keras.layers.Conv2D, tf.keras.layers.DepthwiseConv2D, tf.keras.layers.Dense)
    +
    +
    +
    +[docs] +class AdaroundParameters: + """ + Configuration parameters for Adaround + """ + def __init__(self, data_set: tf.data.Dataset, num_batches: int, default_num_iterations: int = 10000, + default_reg_param: float = 0.01, default_beta_range: Tuple = (20, 2), default_warm_start: float = 0.2): + """ + :param data_set: TF Data set + :param num_batches: Number of batches + :param default_num_iterations: Number of iterations to adaround each layer. Default 10000 + :param default_reg_param: Regularization parameter, trading off between rounding loss vs reconstruction loss. + Default 0.01 + :param default_beta_range: Start and stop beta parameter for annealing of rounding loss (start_beta, end_beta). + Default (20, 2) + :param default_warm_start: warm up period, during which rounding loss has zero effect. Default 20% (0.2) + """ + self.data_set = data_set + self.num_batches = num_batches + self.num_iterations = default_num_iterations + self.reg_param = default_reg_param + self.beta_range = default_beta_range + self.warm_start = default_warm_start + + def __eq__(self, other: "AdaroundParameters"): + return self.data_set == other.data_set and\ + self.num_batches == other.num_batches and\ + self.num_iterations == other.num_iterations and\ + self.reg_param == other.reg_param and\ + self.beta_range == other.beta_range and\ + self.warm_start == other.warm_start
    + + + +class Adaround: + """ + Weight-rounding mechanism for Post Training Quantization (PTQ) + """ + # pylint: disable=too-many-locals + # pylint: disable=too-many-arguments + @classmethod + def apply_adaround(cls, model: tf.keras.Model, params: AdaroundParameters, path: str, filename_prefix: str, + default_param_bw: int = 4, + default_quant_scheme: QuantScheme = QuantScheme.post_training_tf_enhanced, + config_file: str = None) -> tf.keras.Model: + """ + Returns model with optimized weight rounding of every op (Conv and Linear) and also saves the + corresponding quantization encodings to a separate JSON-formatted file that can then be imported by + QuantSim for inference or QAT + + :param model: Model to adaround + :param params: Parameters for adaround + :param path: path where to store parameter encodings + :param filename_prefix: Prefix to use for filename of the encodings file + :param default_param_bw: Default bitwidth (4-31) to use for quantizing layer parameters. Default 4 + :param default_quant_scheme: Quantization scheme. Supported options are QuantScheme.post_training_tf or + QuantScheme.post_training_tf_enhanced. Default QuantScheme.post_training_tf_enhanced + :param config_file: Configuration file for model quantizers + :return: Model with Adarounded weights + """ + + # Get parameters from config file. To allow one central place for Adaround and Quantsim + configs, strict_symmetric, unsigned_symmetric, per_channel_enabled = cls.get_config_dict_keys(config_file) + + # Optimization Hyper parameters + opt_params = AdaroundHyperParameters(params.num_iterations, params.reg_param, params.beta_range, + params.warm_start) + + # Activation sampler + act_sampler = ActivationSampler(params.data_set, params.num_batches) + + hard_rounded_model = tf.keras.models.clone_model(model) + hard_rounded_model.set_weights(model.get_weights()) + soft_rounded_model = tf.keras.models.clone_model(model) + soft_rounded_model.set_weights(model.get_weights()) + + ordered_layer_indices = cls._get_ordered_adaround_layer_indices(model) + module_act_func_pair = cls._get_module_act_func_pair(model) + param_encodings = {} + + progbar = Progbar(len(ordered_layer_indices)) + for idx in ordered_layer_indices: + use_symmetric_encodings = cls.get_is_symmetric_flag_for_op_param(configs, model.layers[idx], + param_name='weight', + framework_to_onnx_type_dict=map_keras_types_to_onnx) + cls.adaround_layer(act_sampler, use_symmetric_encodings, strict_symmetric, unsigned_symmetric, + default_param_bw, default_quant_scheme, model, hard_rounded_model, soft_rounded_model, + idx, module_act_func_pair, opt_params, param_encodings, per_channel_enabled) + progbar.add(1) + + # Export quantization encodings to JSON-formatted file at provided path + cls.export_encoding_to_json(path, filename_prefix, param_encodings) + return soft_rounded_model + + # pylint: disable=too-many-locals + # pylint: disable=too-many-arguments + @classmethod + def adaround_layer(cls, act_sampler, is_symmetric, strict_symmetric, unsigned_symmetric, default_param_bw, + default_quant_scheme, orig_model, hard_rounded_model, soft_rounded_model, idx, + module_act_func_pair, opt_params, param_encodings, per_channel_enabled): + """ + Perform adaround on a specific layer. + :param act_sampler: Activation sampler + :param is_symmetric: True if symmetric encodings is used, else asymmetric encodings + :param strict_symmetric: Taken from config file, False by default + :param unsigned_symmetric: Taken from config file, True by default + :param default_param_bw: Default bitwidth (4-31) to use for quantizing layer parameters + :param default_quant_scheme: Quantization scheme. Supported options are QuantScheme.post_training_tf or + QuantScheme.post_training_tf_enhanced + :param orig_model: Original model + :param hard_rounded_model: Model with hard rounded weights + :param soft_rounded_model: Model with soft rounded weights + :param idx: Index of layer in model to Adaround + :param module_act_func_pair: Dictionary mapping modules to subsequent activation functions + :param opt_params: Adaround hyperparameters + :param param_encodings: Dictionary holding parameter encodings information + :param per_channel_enabled: Flag for per channel quantization + """ + # Collect input and output activations data + all_inp_data, all_out_data = act_sampler.sample_activation(orig_model.layers[idx], orig_model, + hard_rounded_model.layers[idx], + hard_rounded_model) + # Get module's next following activation function + act_func = module_act_func_pair[orig_model.layers[idx]] + + output_height, output_width, output_channels = None, None, None + if isinstance(orig_model.layers[idx], tf.keras.layers.Conv2DTranspose): + data_format = 'NHWC' if orig_model.layers[idx].data_format == 'channels_last' else 'NCHW' + output_height, output_width, output_channels = \ + cls.get_conv2d_transpose_output_tensor_shape(data_format, all_out_data) + + wrapper = AdaroundWrapper(orig_model.layers[idx], default_param_bw, default_quant_scheme, + is_symmetric, strict_symmetric, unsigned_symmetric, per_channel_enabled, + output_height, output_width, output_channels) + hard_rounded_weight, soft_rounded_weight = AdaroundOptimizer.adaround_wrapper(wrapper, act_func, + all_inp_data, all_out_data, + opt_params) + # Update param encodings dictionary + Adaround._update_param_encodings_dict(param_encodings, orig_model.layers[idx], wrapper.encoding, + is_symmetric) + hard_rounded_model.layers[idx].set_weights([hard_rounded_weight] + + hard_rounded_model.layers[idx].get_weights()[1:]) + soft_rounded_model.layers[idx].set_weights([soft_rounded_weight] + + soft_rounded_model.layers[idx].get_weights()[1:]) + + @classmethod + def _get_module_act_func_pair(cls, model) -> Dict[tf.keras.layers.Layer, Union[None, tf.keras.layers.Layer]]: + """ + Get dictionary mapping modules to subsequent activation functions. If the activation function is built into the + layer, map None to that layer. + :param model: Model to obtain module to activation info from + :return: Dictionary mapping modules to subsequent activation functions + """ + conn_graph = ConnectedGraph(model) + module_act_func_pair = {} + activation_types = (tf.keras.layers.ELU, tf.keras.layers.PReLU, tf.keras.layers.Softmax, tf.keras.layers.ReLU, + tf.keras.layers.LeakyReLU, tf.keras.layers.ThresholdedReLU, tf.keras.layers.Activation) + for op in conn_graph.get_all_ops().values(): + # Get module associated with op + cur_module = op.get_module() + if cur_module: + module_act_func_pair[cur_module] = None + if hasattr(cur_module, 'activation'): + if tf.keras.activations.serialize(cur_module.activation) != 'linear': + # If the activation is not passthrough, it is built into the layer. Use None for the associated + # activation since running forward pass on the layer will already include the activation. + continue + if op.output: + assert op.output.consumers, 'op output should have at least one consumer op.' + # Get the next op + next_op = op.output.consumers[0] + # Get module associated with next op + next_module = next_op.get_module() + + # Get the appropriate activation function + if isinstance(next_module, activation_types): + module_act_func_pair[cur_module] = next_module + _logger.debug("Module: %s is followed by activation function: %s", op.dotted_name, + next_op.dotted_name) + + return module_act_func_pair + + @staticmethod + def _update_param_encodings_dict(encoding_dict: Dict, layer: tf.keras.layers.Layer, + encoding: Union[libpymo.TfEncoding, List[libpymo.TfEncoding]], + is_symmetric: bool): + """ + Add layer's parameter encoding to dictionary to be used for exporting. + :param encoding_dict: Encoding dictionary + :param layer: Layer to obtain parameter encoding information for + :param encoding: Encoding + :param is_symmetric: Symmetric vs Asymmetric boolean + """ + tensor_name = layer.weights[0].name + if not isinstance(encoding, Iterable): + encoding = [encoding] + encoding_dict[tensor_name] = [{'min': enc.min, + 'max': enc.max, + 'scale': enc.delta, + 'offset': int(enc.offset), + 'bitwidth': enc.bw, + 'is_symmetric': str(is_symmetric)} for enc in encoding] + + @staticmethod + def _get_ordered_adaround_layer_indices(model: tf.keras.Model) -> List[int]: + """ + Get a list of ordered layer indices corresponding to layers to Adaround. + :param model: Model to find indices for + :return: List of ordered layer indices to Adaround + """ + return [idx for idx, layer in enumerate(model.layers) if isinstance(layer, AdaroundSupportedOps)] + + @staticmethod + def get_config_dict_keys(config_file: str) -> Tuple[ConfigDictType, bool, bool, bool]: + """ + Get config dictionary keys from config file. Config file will default if no provided one. + :param config_file: configuration file. + :return: Config dictionary, strict symmetric flag, unsigned symmetric flag, enable per channel flag. + """ + configs = JsonConfigImporter.import_json_config_file(config_file) + strict_symmetric = configs[ConfigDictKeys.DEFAULTS].get(ConfigDictKeys.STRICT_SYMMETRIC, False) + unsigned_symmetric = configs[ConfigDictKeys.DEFAULTS].get(ConfigDictKeys.UNSIGNED_SYMMETRIC, False) + + # Read per-channel quantization field. Default = False + per_channel_enabled = configs[ConfigDictKeys.DEFAULTS].get(ConfigDictKeys.PER_CHANNEL_QUANTIZATION, False) + + return configs, strict_symmetric, unsigned_symmetric, per_channel_enabled + + @staticmethod + def get_is_symmetric_flag_for_op_param(configs: ConfigDictType, tf_op_type: str, param_name: str, + framework_to_onnx_type_dict: dict) -> bool: + """ + NOTE: Checks config file in reverse order of specificity. + Returns is_symmetric flag for op's param if it is set in config file else returns + False. First check all ops of specific types, second check all params of specific + and lastly check for default types. If not specified, it will return default is + symmetric False. + :param configs: Dictionary containing configs. + :param tf_op_type: TF op type. + :param param_name: Parameter name. + :param framework_to_onnx_type_dict: Dictionary mapping framework type to ONNX type. + :return: is_symmetric flag for given op's param. + """ + assert param_name in MAP_TF_PARAM_NAME_TO_QUANTSIM_NAME.keys(), "param name is invalid." + + # third level of specificity which applies to specific op_type's parameters. + try: + onnx_type = framework_to_onnx_type_dict[tf_op_type] + return configs[ConfigDictKeys.OP_TYPE] \ + [onnx_type] \ + [ConfigDictKeys.PARAMS] \ + [param_name] \ + [ConfigDictKeys.IS_SYMMETRIC] + except KeyError: + pass + + # Second level of specificity which applies to all parameters only. + try: + return configs[ConfigDictKeys.PARAMS] \ + [param_name] \ + [ConfigDictKeys.IS_SYMMETRIC] + except KeyError: + pass + + # First level of specificity which applies to all the ops and parameters. + try: + return configs[ConfigDictKeys.DEFAULTS] \ + [ConfigDictKeys.PARAMS] \ + [ConfigDictKeys.IS_SYMMETRIC] + except KeyError: + pass + + # Default is_symmetric False. + return False + + @classmethod + def export_encoding_to_json(cls, path: str, filename_prefix: str, param_encodings: Dict): + """ + Save Adadrounded op's parameter encodings to JSON file + :param path: path where to store param encodings + :param filename_prefix: filename to store exported weight encodings in JSON format + :param param_encodings: Parameter encodings dictionary + """ + # export encodings to JSON file + os.makedirs(os.path.abspath(path), exist_ok=True) + encoding_file_path = os.path.join(path, filename_prefix + '.encodings') + with open(encoding_file_path, 'w') as encoding_fp: + json.dump(param_encodings, encoding_fp, sort_keys=True, indent=4) + + @staticmethod + def get_conv2d_transpose_output_tensor_shape(data_format: str, output_data: np.ndarray): + """ + Get output height, width, and channels from output_data for use in adarounding conv2d transpose op. + :param data_format: Data format for the op (NHWC or NCHW) + :param output_data: numpy array containing sampled output of the op + :return: Tuple containing output height, width, and channels of the op + """ + if data_format == 'NHWC': + output_height = output_data.shape[1] + output_width = output_data.shape[2] + output_channels = output_data.shape[3] + else: + output_height = output_data.shape[2] + output_width = output_data.shape[3] + output_channels = output_data.shape[1] + return output_height, output_width, output_channels +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_tensorflow/keras/amp/quantizer_groups.html b/releases/2.0.0/_modules/aimet_tensorflow/keras/amp/quantizer_groups.html new file mode 100644 index 0000000..dc827eb --- /dev/null +++ b/releases/2.0.0/_modules/aimet_tensorflow/keras/amp/quantizer_groups.html @@ -0,0 +1,749 @@ + + + + + + + + aimet_tensorflow.keras.amp.quantizer_groups - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_tensorflow.keras.amp.quantizer_groups

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Find quantizer groups in a model """
    +import itertools
    +from typing import Dict, List, Tuple
    +from collections import defaultdict
    +from dataclasses import dataclass, field
    +import tensorflow as tf
    +
    +
    +from aimet_common.connected_graph.operation import Op
    +from aimet_common.utils import AimetLogger
    +from aimet_common.amp.utils import CANDIDATE_WITH_DTYPE
    +from aimet_common.amp.quantizer_groups import QuantizerGroupBase
    +
    +from aimet_tensorflow.keras.connectedgraph import ConnectedGraph
    +from aimet_tensorflow.keras.quantsim import QuantizationSimModel, substitutable_modules
    +from aimet_tensorflow.keras.quant_sim.tensor_quantizer import TensorQuantizer
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.MixedPrecision)
    +
    +
    +ops_to_skip = ['view', 'NumToTensor', 'Split', 'PythonOp']
    +ops_not_to_traverse = ['size']
    +INPUT_OPS_STR = 'input_ops'
    +OUTPUT_OPS_STR = 'output_ops'
    +
    +
    +
    +
    +[docs] +@dataclass(frozen=True) +class QuantizerGroup(QuantizerGroupBase): + """ + Group of modules and quantizers + """ + input_quantizers: Tuple[str, ...] = field(default_factory=tuple) + output_quantizers: Tuple[str, ...] = field(default_factory=tuple) + parameter_quantizers: Tuple[str, ...] = field(default_factory=tuple) + +
    +[docs] + def get_candidate(self, name_to_quantizer_dict: Dict) -> CANDIDATE_WITH_DTYPE: + """ + Gets Activation & parameter bitwidth + :param name_to_quantizer_dict: Gets module from module name + :return: Tuple of Activation, parameter bitwidth and data type + """ + activation_bw, parameter_bw = None, None + activation_data_type, parameter_data_type = None, None + for module_name in self.input_quantizers: + module = self.lookup_quantizer(module_name, name_to_quantizer_dict) + for layer in module.input_quantizers.layers: + activation_bw = layer.bitwidth + activation_data_type = layer.data_type + break + break + + for module_name in self.output_quantizers: + module = self.lookup_quantizer(module_name, name_to_quantizer_dict) + for layer in module.output_quantizers.layers: + activation_bw = layer.bitwidth + activation_data_type = layer.data_type + break + break + + if self.parameter_quantizers: + for module_name in self.parameter_quantizers: + module = self.lookup_quantizer(module_name, name_to_quantizer_dict) + for layer in module.param_quantizers.layers: + parameter_bw = layer.bitwidth + parameter_data_type = layer.data_type + break + break + + + return (activation_bw, activation_data_type), (parameter_bw, parameter_data_type)
    + + +
    +[docs] + @staticmethod + def lookup_quantizer(quantizer_name: str, name_to_quantizer_dict: Dict) -> tf.keras.layers.Layer: + """ + Returns the quantizer layer corresponding to the name + :quantizer_name: Name of the quantizer + :name_to_quantizer_dict: Dictionary of mappings from quantizer name to quantizer layer + """ + if isinstance(quantizer_name, tuple): + quantizer_name = quantizer_name[0] + module = name_to_quantizer_dict[quantizer_name] + return module
    + + +
    +[docs] + def set_quantizers_to_candidate(self, + name_to_quantizer_dict: Dict, + candidate: CANDIDATE_WITH_DTYPE) -> None: + """ + Sets a quantizer group to a given candidate bitwidth + :param name_to_quantizer_dict: Gets module from module name + :param candidate: candidate with act and param bw and data types + """ + (activation_bw, activation_data_type), (param_bw, param_data_type) = candidate + for module_name in self.input_quantizers: + module = self.lookup_quantizer(module_name, name_to_quantizer_dict) + for layer in module.input_quantizers.layers: + layer.bitwidth = activation_bw + layer.data_type = activation_data_type + + for module_name in self.output_quantizers: + module = self.lookup_quantizer(module_name, name_to_quantizer_dict) + for layer in module.output_quantizers.layers: + layer.bitwidth = activation_bw + layer.data_type = activation_data_type + + if not self.parameter_quantizers: + return + + for module_name in self.parameter_quantizers: + module = self.lookup_quantizer(module_name, name_to_quantizer_dict) + for layer in module.param_quantizers: + layer.bitwidth = param_bw + layer.data_type = param_data_type
    + + +
    +[docs] + def to_list(self) -> List[Tuple[str, str]]: + """ + Converts quantizer group to a list + :return: List containing input/output quantizers & weight quantizers + """ + if self.parameter_quantizers: + ret_list = list(itertools.chain( + (("input", module_name) for module_name in self.input_quantizers), + (("output", module_name) for module_name in self.output_quantizers), + (("weight", module_name) for module_name in self.parameter_quantizers), + )) + else: + ret_list = list(itertools.chain( + (("input", module_name) for module_name in self.input_quantizers), + (("output", module_name) for module_name in self.output_quantizers), + )) + return ret_list
    + + +
    +[docs] + def get_active_quantizers(self, name_to_quantizer_dict: Dict) -> List[TensorQuantizer]: + """ Find all active tensor quantizers associated with this quantizer group """ + quantizers = [] + for module_name in self.input_quantizers: + module = self.lookup_quantizer(module_name, name_to_quantizer_dict) + quantizers += list(module.input_quantizers.layers) + + for module_name in self.output_quantizers: + module = self.lookup_quantizer(module_name, name_to_quantizer_dict) + quantizers += list(module.output_quantizers.layers) + + if self.parameter_quantizers: + for module_name in self.parameter_quantizers: + module = self.lookup_quantizer(module_name, name_to_quantizer_dict) + quantizers += list(module.param_quantizers.layers) + + return list(set(quantizer for quantizer in quantizers if quantizer.is_enabled()))
    + + +
    +[docs] + def get_active_param_quantizers(self, name_to_quantizer_dict: Dict) -> List[TensorQuantizer]: + """ Find all active param tensor quantizers associated with this quantizer group + :param name_to_quantizer_dict: Contains mapping of module name to sim.quantizer_config object + """ + quantizers = [] + if self.parameter_quantizers: + for module_name in self.parameter_quantizers: + module = self.lookup_quantizer(module_name, name_to_quantizer_dict) + quantizers += list(module.param_quantizers.layers) + return list(set(quantizer for quantizer in quantizers if quantizer.is_enabled()))
    +
    + + +def find_output_quantizer_groups(op: Op, parent_child_op_groups: Dict, map_for_skipped_ops: Dict): + """ + Finds quantizer groups along the parent to child flow + :param op: pytorch module + :param parent_child_op_groups: parent child relationships in graph + :param map_for_skipped_ops: map to find first skipped parents of skipped ops + """ + output = op.output + if output: + consumers = output.consumers + for consumer in consumers: + name = op.name + if consumer.type in ops_not_to_traverse: + continue + if op.dotted_name in map_for_skipped_ops: + name = map_for_skipped_ops[op.name] + + if consumer.type in ops_to_skip: + map_for_skipped_ops[consumer.name] = name + find_output_quantizer_groups(consumer, parent_child_op_groups, map_for_skipped_ops) + # If there is a one to one connection between quantizers + else: + if name in map_for_skipped_ops: + name = map_for_skipped_ops[name] + parent_child_op_groups[name].append(consumer.name) + else: + if op.dotted_name in map_for_skipped_ops: + parent_child_op_groups[map_for_skipped_ops[op.dotted_name]] = [] + +def find_op_groups(graph: ConnectedGraph) -> Dict: + """ + Finds parent children relationship based on three rules + 1) If there is a direct connection between two ops, op1 and op2, then op1 is parent of op2 and they form a group + 2) If the input to an op (op1) is shared with another op (op2), the op producing the input (op0) is the parent, and op1 and op2 are the children + :param graph: connected graph + :return: Dict of parent (key) and children (value) relationship + """ + parent_child_op_groups = defaultdict(list) + map_for_skipped_ops = {} + + for op in graph.ordered_ops: + # Add 1st op as child + if not op.input_ops: + parent_child_op_groups[INPUT_OPS_STR].append(op.name) + # Add output op as child to put output of model as a quantizer group + if op.output is None: + parent_child_op_groups[OUTPUT_OPS_STR].append(op.name) + + for op in graph.get_all_ops().values(): + if op.type in ops_to_skip or op.type in ops_not_to_traverse: + continue + find_output_quantizer_groups(op, parent_child_op_groups, map_for_skipped_ops) + + return parent_child_op_groups + +def get_module_name_to_module_dict(sim: QuantizationSimModel) -> Dict: + """ + Creates a dictionary of wrapped module's name to quantizer module + :param sim: quantization sim + :return: Dict key: name of wrapped module value: quantization wrapper + """ + module_name_to_quantizer_dict = {} + for layer in sim.quant_wrappers(): + for quantizer in layer.input_quantizers: + module_name_to_quantizer_dict[quantizer.name] = layer + for quantizer in layer.output_quantizers: + module_name_to_quantizer_dict[quantizer.name] = layer + for quantizer in layer.param_quantizers: + module_name_to_quantizer_dict[quantizer.name] = layer + + return module_name_to_quantizer_dict + +# pylint: disable-msg=too-many-locals +# pylint: disable-msg=too-many-branches +def find_quantizer_group(sim: QuantizationSimModel) -> Tuple[Dict, List[QuantizerGroup]]: + """ + Finds quantizer groups in a quantization sim model + :param sim: Quantization sim + :return: List of Quantizer groups + """ + # Get connected graph from quantsim for model without wrappers + connected_graph = sim.connected_graph + + if connected_graph is None: + raise AssertionError('Aborting Auto Mixed Precision, connected graph needs to exist for Auto Mixed precision') + + quantizer_groups = [] + + parent_child_op_groups = find_op_groups(connected_graph) + + quantized_op_name_to_quantizer_dict = get_module_name_to_module_dict(sim) + + if INPUT_OPS_STR in parent_child_op_groups: + for child in parent_child_op_groups[INPUT_OPS_STR]: + # Add one quantizer group for each input and it's weight param + layer = connected_graph.get_layer_from_op_name(child) + if isinstance(layer, tuple(substitutable_modules.keys())): + sub_quantizer_groups = get_quantizers_groups_substituted_layer(sim, layer) + quantizer_groups.extend(sub_quantizer_groups) + continue + + input_quantizer_names, output_quantizer_names, param_quantizer_names = sim.get_quantizer_name_by_layer(layer) + + if input_quantizer_names or param_quantizer_names: + quantizer_group = QuantizerGroup( + input_quantizers=input_quantizer_names, + parameter_quantizers=param_quantizer_names + ) + quantizer_groups.append(quantizer_group) + logger.debug('\n Quantizer Group Added: %s', quantizer_group) + + # Based on which quantizers are enabled, create a list of quantizer_groups + for parents in parent_child_op_groups: + if parents in [INPUT_OPS_STR, OUTPUT_OPS_STR]: + continue + + if not isinstance(parents, tuple): + parents = [parents] + + for parent in parents: + layer = connected_graph.get_layer_from_op_name(parent) + if isinstance(layer, tuple(substitutable_modules.keys())): + sub_quantizer_groups = get_quantizers_groups_substituted_layer(sim, layer) + quantizer_groups.extend(sub_quantizer_groups) + continue + + input_quantizer_names, output_quantizer_names, param_quantizer_names = sim.get_quantizer_name_by_layer(layer) + + # Don't add quantizer group if it is empty + if input_quantizer_names or output_quantizer_names or param_quantizer_names: + quantizer_group = QuantizerGroup( + input_quantizers=input_quantizer_names, + output_quantizers=output_quantizer_names, + parameter_quantizers=param_quantizer_names + ) + quantizer_groups.append(quantizer_group) + logger.debug('\n Quantizer Group added: %s', quantizer_group) + + if OUTPUT_OPS_STR in parent_child_op_groups: + for parent in parent_child_op_groups[OUTPUT_OPS_STR]: + # Add one quantizer group for each input and it's weight param + + layer = connected_graph.get_layer_from_op_name(parent) + if isinstance(layer, tuple(substitutable_modules.keys())): + sub_quantizer_groups = get_quantizers_groups_substituted_layer(sim, layer) + quantizer_groups.extend(sub_quantizer_groups) + continue + + input_quantizer_names, output_quantizer_names, param_quantizer_names = sim.get_quantizer_name_by_layer(layer) + + if output_quantizer_names: + quantizer_group = QuantizerGroup( + input_quantizers=input_quantizer_names, + output_quantizers=output_quantizer_names, + parameter_quantizers=param_quantizer_names + ) + quantizer_groups.append(quantizer_group) + logger.debug('\n Quantizer Group added: %s', quantizer_group) + + return quantized_op_name_to_quantizer_dict, quantizer_groups + +# pylint: disable=protected-access +def get_quantizers_groups_substituted_layer(sim: QuantizationSimModel, layer) -> List[QuantizerGroup]: + """ Helper function to return the quantizer groups for the substituted layers """ + layer = sim._substituted_layer[layer] + quantizer_groups = [] + for quant_wrapper in layer.quant_wrappers(): + input_quantizers = quant_wrapper.input_quantizers + output_quantizers = quant_wrapper.output_quantizers + param_quantizers = quant_wrapper.param_quantizers + + + input_quantizer_names = QuantizationSimModel._quantizer_to_name_tuple(input_quantizers) + output_quantizer_names = QuantizationSimModel._quantizer_to_name_tuple(output_quantizers) + param_quantizer_names = QuantizationSimModel._quantizer_to_name_tuple(param_quantizers) + + if input_quantizer_names or output_quantizer_names or param_quantizer_names: + quantizer_group = QuantizerGroup( + input_quantizers=input_quantizer_names, + output_quantizers=output_quantizer_names, + parameter_quantizers=param_quantizer_names + ) + quantizer_groups.append(quantizer_group) + logger.debug('\n Quantizer Group added: %s', quantizer_group) + + return quantizer_groups + + +def find_wrapper_module(op_name: str, module_name_to_quantizer_dict: Dict) -> Tuple[str, tf.keras.layers.Layer]: + """ + Finds quantization (wrapping) module corresponding to the wrapper module's dotted name + :param op_name: Dotted name of op as represented in connected graph + :param module_name_to_quantizer_dict: Dict key: name of wrapped module value: quantization wrapper + :return: Module name and the corresponding quant-wrapper module in the sim + """ + # pylint:disable = protected-access + module_name = op_name[op_name.find('.') + 1:] + if module_name in module_name_to_quantizer_dict: + return module_name, module_name_to_quantizer_dict[module_name] + # Else it is a functional op + raise KeyError +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_tensorflow/keras/auto_quant_v2.html b/releases/2.0.0/_modules/aimet_tensorflow/keras/auto_quant_v2.html new file mode 100644 index 0000000..c044c48 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_tensorflow/keras/auto_quant_v2.html @@ -0,0 +1,2018 @@ + + + + + + + + aimet_tensorflow.keras.auto_quant_v2 - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_tensorflow.keras.auto_quant_v2

    +#!/usr/bin/env python3
    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +# pylint: disable=too-many-lines
    +
    +"""Automatic Post-Training Quantization"""
    +import contextlib
    +import itertools
    +import math
    +import functools
    +import os
    +import sys
    +from collections import OrderedDict, defaultdict
    +from dataclasses import dataclass
    +from typing import List, Callable, Dict, Any, Tuple, Optional, Mapping
    +import io
    +from unittest.mock import patch
    +import traceback
    +import shutil
    +import copy
    +from tqdm import tqdm
    +import jinja2
    +import bokeh.plotting
    +from bokeh.resources import CDN
    +import tensorflow as tf
    +
    +from aimet_common.cache import Cache
    +from aimet_common.defs import QuantScheme, QuantizationDataType, CallbackFunc
    +from aimet_common.quantsim import validate_quantsim_inputs
    +from aimet_common.utils import AimetLogger, Spinner
    +from aimet_common.auto_quant import Diagnostics
    +from aimet_common.amp.utils import CANDIDATE_WITH_DTYPE, create_sensitivity_plot, create_pareto_curve, AmpCandidate
    +from aimet_tensorflow.keras.adaround_weight import AdaroundParameters
    +from aimet_tensorflow.keras.adaround_weight import Adaround
    +from aimet_tensorflow.keras.batch_norm_fold import fold_all_batch_norms
    +from aimet_tensorflow.keras.cache import KerasModelSerializationProtocol
    +from aimet_tensorflow.keras.cross_layer_equalization import equalize_model
    +from aimet_tensorflow.keras.quantsim import QuantizationSimModel
    +from aimet_tensorflow.keras.amp.quantizer_groups import QuantizerGroup
    +from aimet_tensorflow.keras.amp.mixed_precision_algo import GreedyMixedPrecisionAlgo, EvalCallbackFactory, _default_forward_fn
    +
    +
    +_logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.AutoQuant) # pylint: disable=invalid-name
    +
    +cache = Cache() # pylint: disable=invalid-name
    +
    +# The number of samples to be used for performance evaluation.
    +# NOTE: None means "all".
    +NUM_SAMPLES_FOR_PERFORMANCE_EVALUATION = None
    +
    +@dataclass(frozen=True)
    +class _QuantSchemePair:
    +    param_quant_scheme: QuantScheme
    +    output_quant_scheme: QuantScheme
    +    param_percentile: Optional[float] = None
    +    output_percentile: Optional[float] = None
    +
    +    def __str__(self):
    +        def scheme_to_str(quant_scheme, percentile):
    +            if quant_scheme == QuantScheme.post_training_percentile:
    +                return f"{percentile}%ile"
    +            if quant_scheme in (QuantScheme.post_training_tf,
    +                                QuantScheme.training_range_learning_with_tf_init):
    +                return "tf"
    +            if quant_scheme in (QuantScheme.post_training_tf_enhanced,
    +                                QuantScheme.training_range_learning_with_tf_enhanced_init):
    +                return "tf-enhanced"
    +            raise ValueError
    +
    +        param_str = scheme_to_str(self.param_quant_scheme, self.param_percentile)
    +        output_str = scheme_to_str(self.output_quant_scheme, self.output_percentile)
    +        return f"W@{param_str} / A@{output_str}"
    +
    +
    +_QUANT_SCHEME_CANDIDATES = (
    +    # Weight:     tf
    +    # Activation: tf
    +    _QuantSchemePair(QuantScheme.post_training_tf,
    +                     QuantScheme.post_training_tf),
    +
    +    # Weight:     tf_enhanced
    +    # Activation: tf
    +    _QuantSchemePair(QuantScheme.post_training_tf_enhanced,
    +                     QuantScheme.post_training_tf),
    +
    +    # Weight:     tf_enhanced
    +    # Activation: tf_enhanced
    +    _QuantSchemePair(QuantScheme.post_training_tf_enhanced,
    +                     QuantScheme.post_training_tf_enhanced),
    +
    +    # Weight:     tf_enhanced
    +    # Activation: percentile(99.9)
    +    _QuantSchemePair(QuantScheme.post_training_tf_enhanced,
    +                     QuantScheme.post_training_percentile,
    +                     output_percentile=99.9),
    +
    +    # Weight:     tf_enhanced
    +    # Activation: percentile(99.99)
    +    _QuantSchemePair(QuantScheme.post_training_tf_enhanced,
    +                     QuantScheme.post_training_percentile,
    +                     output_percentile=99.99),
    +)
    +
    +def _validate_inputs(model: tf.keras.Model, # pylint: disable=too-many-arguments
    +                     dataset: tf.data.Dataset,
    +                     eval_callback: Callable[[tf.keras.Model], float],
    +                     results_dir: str,
    +                     strict_validation: bool,
    +                     quant_scheme: QuantScheme,
    +                     param_bw: int,
    +                     output_bw: int,
    +                     rounding_mode: str):
    +    """
    +    Confirms inputs are of the correct type
    +    :param model: Model to be quantized
    +    :param dataset: A collection that iterates over an unlabeled dataset,
    +        used for computing encodings
    +    :param eval_callback: Function that calculates the evaluation score
    +    :param results_dir: Directory to save the results of PTQ techniques
    +    :param strict_validation: Flag set to True by default.
    +        When False, AutoQuant will proceed with execution
    +        and try to handle errors internally if possible.
    +        This may produce unideal or unintuitive results.
    +    :param quant_scheme: Quantization scheme
    +    :param param_bw: Parameter bitwidth
    +    :param output_bw: Output bitwidth
    +    :param rounding_mode: Rounding mode
    +    """
    +    if not isinstance(model, tf.keras.Model):
    +        raise ValueError('Model must be of type tf.keras.Model, not ' + str(type(model).__name__))
    +
    +    if not isinstance(dataset, tf.data.Dataset):
    +        raise ValueError('dataset must be of type tf.data.Dataset, not ' + str(
    +            type(dataset).__name__))
    +
    +    if not isinstance(eval_callback, Callable):  # pylint: disable=isinstance-second-argument-not-valid-type
    +        raise ValueError('eval_callback must be of type Callable, not ' +
    +                         str(type(eval_callback).__name__))
    +
    +    if not isinstance(results_dir, str):
    +        raise ValueError('results_dir must be of type str, not ' +
    +                         str(type(results_dir).__name__))
    +
    +    results_dir = os.path.abspath(results_dir)
    +    os.makedirs(results_dir, exist_ok=True)
    +
    +    if not isinstance(strict_validation, bool):
    +        raise ValueError('strict_validation must be of type bool, not ' +
    +                         str(type(strict_validation).__name__))
    +
    +    validate_quantsim_inputs(quant_scheme, rounding_mode, output_bw, param_bw)
    +
    +
    +
    +class AutoQuant: # pylint: disable=too-many-instance-attributes
    +    """
    +    Integrate and apply post-training quantization techniques.
    +
    +    AutoQuant includes 1) batchnorm folding, 2) cross-layer equalization,
    +    and 3) Adaround.
    +    These techniques will be applied in a best-effort manner until the model
    +    meets the evaluation goal given as allowed_accuracy_drop.
    +    """
    +
    +    # pylint: disable=too-many-arguments
    +    def __init__(self, # pylint: disable=too-many-arguments, too-many-locals
    +                 model: tf.keras.Model,
    +                 eval_callback: Callable[[tf.keras.Model], float],
    +                 dataset: tf.data.Dataset,
    +                 param_bw: int = 8,
    +                 output_bw: int = 8,
    +                 quant_scheme: QuantScheme = QuantScheme.post_training_tf_enhanced,
    +                 rounding_mode: str = "nearest",
    +                 config_file: str = None,
    +                 results_dir: str = "/tmp",
    +                 cache_id: str = None,
    +                 strict_validation: bool = True) -> None:
    +        '''
    +        :param model: Model to be quantized. Assumes model is on the correct device
    +        :param eval_callback: Function that calculates the evaluation score
    +        :param dataset: A collection that iterates over an unlabeled dataset,
    +            used for computing encodings
    +        :param param_bw: Parameter bitwidth
    +        :param output_bw: Output bitwidth
    +        :param quant_scheme: Quantization scheme
    +        :param rounding_mode: Rounding mode
    +        :param config_file: Path to configuration file for model quantizers
    +        :param results_dir: Directory to save the results of PTQ techniques
    +        :param cache_id: ID associated with cache results
    +        :param strict_validation: Flag set to True by default.
    +            When False, AutoQuant will proceed with execution and
    +            handle errors internally if possible.
    +            This may produce unideal or unintuitive results.
    +        '''
    +
    +        _validate_inputs(model, dataset, eval_callback, results_dir, strict_validation, \
    +                         quant_scheme, param_bw, output_bw, rounding_mode)
    +        model.trainable = False
    +        self.fp32_model = model
    +        self._fp32_acc = None
    +        self.dataset = dataset
    +        self.eval_callback = eval_callback
    +
    +        self._quantsim_params = dict(
    +            param_bw=param_bw,
    +            output_bw=output_bw,
    +            quant_scheme=_QuantSchemePair(quant_scheme, quant_scheme),
    +            rounding_mode=rounding_mode,
    +            config_file=config_file,
    +        )
    +
    +        self.results_dir = results_dir
    +        if cache_id:
    +            self.cache_dir = os.path.join(results_dir, ".auto_quant_cache", cache_id)
    +        else:
    +            self.cache_dir = None
    +
    +        def forward_pass_callback(model, _: Any = None):
    +            for input_data in tqdm(self.dataset):
    +                model(input_data, training=False)
    +
    +        self.forward_pass_callback = forward_pass_callback
    +
    +        # Use at most 2000 samples for AdaRound.
    +        batch_size = None
    +        for data in self.dataset:
    +            if not batch_size:
    +                batch_size = len(data)
    +                break
    +        batch_size = batch_size or 1
    +        num_batches = math.ceil(2000 / batch_size)
    +        num_batches = min(num_batches, len(self.dataset))
    +
    +        self.adaround_params = AdaroundParameters(self.dataset,
    +                                                  num_batches)
    +        self.eval_manager = _EvalManager(
    +            quantsim_factory=self._create_quantsim_and_encodings,
    +            eval_func=self._evaluate_model_performance,
    +            results_dir=self.results_dir,
    +            strict_validation=strict_validation
    +        )
    +        self._quant_scheme_candidates = _QUANT_SCHEME_CANDIDATES
    +
    +    def _evaluate_model_performance(self, model: tf.keras.Model) -> float:
    +        """
    +        Evaluate the model performance
    +
    +        :param model: Model to evaluate
    +        :return: Evaluation score
    +        """
    +        return self.eval_callback(model, NUM_SAMPLES_FOR_PERFORMANCE_EVALUATION)
    +
    +    def run_inference(self) -> Tuple[QuantizationSimModel, float]:
    +
    +        '''
    +        Creates a quantization model and performs inference
    +
    +        :return: QuantizationSimModel, model accuracy as float
    +        '''
    +
    +        model = self.fp32_model
    +
    +        with self.eval_manager.session("Batchnorm Folding", ptq=True) as sess:
    +            model, _ = self._apply_batchnorm_folding(model)
    +            if sess.ptq_result is None:
    +                sess.set_ptq_result(applied_techniques=["batchnorm_folding"], model=model,)
    +
    +        sim = self._create_quantsim_and_encodings(model)
    +
    +        if sess.ptq_result is None:
    +            # BN folding failed. Need to measure the eval score
    +            acc = self._evaluate_model_performance(sim.model)
    +        else:
    +            # BN folding success. No need to measure the eval score again
    +            acc = sess.ptq_result.accuracy
    +
    +        return sim, acc
    +
    +    def optimize(self, allowed_accuracy_drop: float = 0.0) -> Tuple[tf.keras.Model, float, str]:
    +        """
    +        Integrate and apply post-training quantization techniques.
    +
    +        :param allowed_accuracy_drop: Maximum allowed accuracy drop
    +        :return: Tuple of (best model, eval score, encoding path)
    +        """
    +        result = self._optimize_helper(self._optimize_main, allowed_accuracy_drop)
    +        return result["model"], \
    +            result["accuracy"], \
    +            result["encoding_path"]
    +
    +    def set_adaround_params(self, adaround_params: AdaroundParameters):
    +        """
    +        Set Adaround parameters.
    +        If this method is not called explicitly by the user, AutoQuant will use
    +        `dataset` (passed to `__init__`) for Adaround.
    +
    +        :param adaround_params: Adaround parameters.
    +        """
    +        self.adaround_params = adaround_params
    +
    +
    +    def _create_quantsim_and_encodings(self, # pylint: disable=too-many-arguments, too-many-locals, too-many-branches
    +                                       model: tf.keras.Model,
    +                                       rounding_mode: str = None,
    +                                       output_bw: int = None,
    +                                       output_quant_scheme: QuantScheme = None,
    +                                       output_percentile: float = None,
    +                                       param_bw: int = None,
    +                                       param_quant_scheme: QuantScheme = None,
    +                                       param_percentile: float = None,
    +                                       config_file: str = None,
    +                                       encoding_path: str = None) -> QuantizationSimModel:
    +        """
    +
    +        :param rounding_mode: Rounding mode. Defaults to self._quantsim_params["rounding_mode"].
    +        :param output_bw: Default bitwidth (4-31) to use for quantizing layer inputs andoutputs.
    +            Defaults to self._quantsim_params["output_bw"].
    +        :param output_quant_scheme: Quantization scheme for output quantizers.
    +            Defaults to self._quantsim_params["quant_scheme"].output_quant_scheme.
    +        :param output_percentile: Percentile value for outputs.
    +            Only valid if output quant scheme is percentile scheme.
    +        :param param_bw: Default bitwidth (4-31) to use for quantizing layer parameters.
    +            Defaults to self._quantsim_params["param_bw"].
    +        :param param_quant_scheme: Quantization scheme for param quantizers.
    +            Defaults to self._quantsim_params["quant_scheme"].param_quant_scheme.
    +        :param param_percentile: Percentile value for parameters.
    +            Only valid if param quant scheme is percentile scheme.
    +        :param config_file: Path to configuration file for model quantizers.
    +                            Defaults to self._quantsim_params["config_file"].
    +        :param encoding_path: Path to parameter encodings file.
    +        :return: Quantsim model.
    +        """
    +        if output_bw is not None:
    +            assert output_bw <= 32
    +
    +        if param_bw is not None:
    +            assert param_bw <= 32
    +
    +        if output_quant_scheme is None or param_quant_scheme is None:
    +            assert self._quantsim_params["quant_scheme"] is not None
    +
    +        kwargs = dict(
    +            rounding_mode=(rounding_mode or self._quantsim_params["rounding_mode"]),
    +            default_output_bw=(output_bw or self._quantsim_params["output_bw"]),
    +            default_param_bw=(param_bw or self._quantsim_params["param_bw"]),
    +            config_file=(config_file or self._quantsim_params["config_file"]),
    +        )
    +        sim = QuantizationSimModel(model, **kwargs)
    +        input_quantizers, param_quantizers, output_quantizers = sim._get_quantizer_list() # pylint: disable=protected-access
    +
    +        default_quant_scheme = self._quantsim_params.get("quant_scheme")
    +
    +        if default_quant_scheme is not None:
    +            output_quant_scheme = output_quant_scheme or \
    +                                  default_quant_scheme.output_quant_scheme
    +            output_percentile = output_percentile or default_quant_scheme.output_percentile
    +            param_quant_scheme = param_quant_scheme or \
    +                                 default_quant_scheme.param_quant_scheme
    +            param_percentile = param_percentile or default_quant_scheme.param_percentile
    +
    +        # Set input/output quantizers' quant schemes
    +        for quantizer in itertools.chain(input_quantizers, output_quantizers):
    +            quantizer.quant_scheme = output_quant_scheme
    +            if quantizer.quant_scheme == QuantScheme.post_training_percentile and \
    +                    output_percentile is not None:
    +                quantizer.set_percentile_value(output_percentile)
    +
    +        # Set param quantizers' quant schemes
    +        for quantizer in param_quantizers:
    +            quantizer.quant_scheme = param_quant_scheme
    +            if quantizer.quant_scheme == QuantScheme.post_training_percentile and \
    +                    param_percentile is not None:
    +                quantizer.set_percentile_value(param_percentile)
    +
    +        if encoding_path:
    +            sim.set_and_freeze_param_encodings(encoding_path)
    +
    +        input_quantizers, param_quantizers, output_quantizers = sim._get_quantizer_list() # pylint: disable=protected-access
    +
    +        # Disable input/output quantizers, using fp32 to simulate int32.
    +        if output_bw == 32:
    +            for quantizer in input_quantizers + output_quantizers:
    +                quantizer.disable()
    +        # Disable param quantizers, using fp32 to simulate int32.
    +        if param_bw == 32:
    +            for quantizer in param_quantizers:
    +                quantizer.disable()
    +
    +        # Skip encoding computation if none of the quantizers are enabled
    +        if any(quantizer.is_enabled() for quantizer in param_quantizers + \
    +                                                  input_quantizers + \
    +                                                  output_quantizers):
    +            sim.compute_encodings(self.forward_pass_callback, None)
    +        return sim
    +
    +    # pylint: disable=no-self-use
    +    def _apply_batchnorm_folding(self, model: tf.keras.Model) -> Tuple[tf.keras.Model, List[Tuple]]:
    +        """
    +        Apply batchnorm folding
    +        Note: Input model is not mutated
    +        :param model: Model to apply batchnorm folding
    +        :return: Output model and folded pairs
    +        """
    +        original_weight = model.get_weights()
    +        model = tf.keras.models.clone_model(model)
    +        model.set_weights(original_weight)
    +        folded_pairs, model = fold_all_batch_norms(model)
    +        return model, folded_pairs
    +
    +    # pylint: disable=no-self-use
    +    @cache.mark("cle", KerasModelSerializationProtocol())
    +    def _apply_cross_layer_equalization(self, model: tf.keras.Model) -> tf.keras.Model:
    +        """
    +        Apply cross-layer equalization
    +        Note: Input model is not mutated
    +        :param model: Model to apply cross-layer-equalization
    +        :return: CLE applied model
    +        """
    +        original_weight = model.get_weights()
    +        model = tf.keras.models.clone_model(model)
    +        model.set_weights(original_weight)
    +        return equalize_model(model)
    +
    +    def _apply_adaround(self,
    +                        model: tf.keras.Model) -> Tuple[tf.keras.Model, str]:
    +        """
    +        Apply adaround
    +
    +        NOTE: Input model is not mutated
    +        :param model: Model to apply adaround
    +        :param results_dir: Directory to save the results of AdaRound
    +        :return: Output model and the path to the parameter encoding file
    +        """
    +        filename_prefix = "adaround"
    +        adaround_encoding_path = os.path.join(self.results_dir,
    +                                              f"{filename_prefix}.encodings")
    +        if self._quantsim_params["param_bw"] == 4:
    +            self.adaround_params.num_iterations = 15000
    +
    +        _apply_adaround_cached = cache.mark("adaround", KerasModelSerializationProtocol()) \
    +            (Adaround.apply_adaround)
    +
    +        model = _apply_adaround_cached(model, # pylint: disable=protected-access
    +                                       self.adaround_params,
    +                                       path=self.results_dir,
    +                                       filename_prefix=filename_prefix,
    +                                       default_param_bw=self._quantsim_params["param_bw"],
    +                                       default_quant_scheme=self._quantsim_params.get("quant_scheme").param_quant_scheme,
    +                                       config_file=self._quantsim_params["config_file"])
    +
    +        return model, adaround_encoding_path
    +
    +    def _optimize_helper(
    +            self,
    +            optimize_fn: Callable,
    +            allowed_accuracy_drop: float) -> Tuple[tf.keras.Model, float, str]:
    +        """
    +        Integrate and apply post-training quantization techniques.
    +
    +        :param allowed_accuracy_drop: Maximum allowed accuracy drop
    +        :return: Tuple of (best model, eval score, encoding path)
    +        """
    +        allowed_accuracy_drop = float(allowed_accuracy_drop)
    +        if allowed_accuracy_drop < 0:
    +            raise ValueError(
    +                "`allowed_accuracy_drop` must be a positive value. Got {:.2f}"
    +                .format(allowed_accuracy_drop)
    +            )
    +
    +        self.eval_manager.clear()
    +
    +        try:
    +            with cache.enable(self.cache_dir):
    +                _logger.info("Starting AutoQuant")
    +                self._fp32_acc = self._evaluate_model_performance(self.fp32_model)
    +                target_acc = self._fp32_acc - allowed_accuracy_drop
    +                _logger.info("Target eval score: %f", target_acc)
    +                _logger.info("FP32 eval score (W32A32): %f", self._fp32_acc)
    +
    +                ret = optimize_fn(self.fp32_model, target_acc)
    +
    +                acc = ret["accuracy"]
    +                if acc is not None:
    +                    _logger.info("Best eval score: %f", acc)
    +
    +                    # Save the best model with "best_model_" as prefix
    +                    best_res = self.eval_manager.get_best_ptq_result()
    +                    best_res.save_result_as("best_model")
    +
    +                    if acc < target_acc:
    +                        _logger.info(
    +                            "AutoQuant is unable to match the target accuracy. "
    +                            "Consider Quantization Aware Training."
    +                        )
    +
    +                return ret
    +        finally:
    +            self.eval_manager.export_diagnostics()
    +
    +    def get_quant_scheme_candidates(self) -> Tuple[_QuantSchemePair, ...]:
    +        """
    +        Return the candidates for quant scheme search.
    +        During :meth:`~AutoQuant.optimize`, the candidate with the highest accuracy
    +        will be selected among them.
    +
    +        :return: Candidates for quant scheme search
    +        """
    +        return self._quant_scheme_candidates
    +
    +    def set_quant_scheme_candidates(self, candidates: Tuple[_QuantSchemePair, ...]):
    +        """
    +        Set candidates for quant scheme search.
    +        During :meth:`~AutoQuant.optimize`, the candidate with the highest accuracy
    +        will be selected among them.
    +
    +        :param candidates: Candidates for quant scheme search
    +        """
    +        self._quant_scheme_candidates = copy.copy(candidates) # pylint: disable=E1101
    +
    +    def _choose_default_quant_scheme(self):
    +        def eval_fn(pair: _QuantSchemePair):
    +            sim = self._create_quantsim_and_encodings(
    +                self.fp32_model,
    +                param_quant_scheme=pair.param_quant_scheme,
    +                param_percentile=pair.param_percentile,
    +                output_quant_scheme=pair.output_quant_scheme,
    +                output_percentile=pair.output_percentile,
    +            )
    +            return self._evaluate_model_performance(sim.model)
    +
    +        param_bw = self._quantsim_params["param_bw"]
    +        output_bw = self._quantsim_params["output_bw"]
    +
    +        candidates = self.get_quant_scheme_candidates()
    +
    +        # If the weight representation has sufficient precision (i.e. bitwidth >= 16),
    +        # always use tf scheme
    +        if param_bw >= 16:
    +            candidates = [
    +                candidate for candidate in candidates
    +                if candidate.param_quant_scheme == QuantScheme.post_training_tf
    +            ]
    +
    +        # If the output representation has sufficient precision (i.e. bitwidth >= 16),
    +        # always use tf scheme
    +        if output_bw >= 16:
    +            candidates = [
    +                candidate for candidate in candidates
    +                if candidate.output_quant_scheme == QuantScheme.post_training_tf
    +            ]
    +
    +        # If we have only one candidate left, we don't need to evaluated
    +        # the quant scheme for comparison
    +        if len(candidates) == 1:
    +            return candidates[0]
    +
    +        assert candidates
    +
    +        # Find the quant scheme that yields the best eval score
    +        return max(candidates, key=eval_fn)
    +
    +
    +    def _optimize_main(self, fp32_model: tf.keras.Model, target_acc: float):
    +        """
    +        Helper function of apply().
    +
    +        :param fp32_model: Model to apply PTQ techniques.
    +        :param target_acc: Target eval score.
    +
    +        :raises RuntimeError: If none of the PTQ techniques were finished successfully.
    +
    +        :return: The best ptq result as a dictionary.
    +        """
    +
    +        # Choose quant scheme automatically.
    +        with self.eval_manager.session("QuantScheme Selection") as sess:
    +            self._quantsim_params["quant_scheme"] = self._choose_default_quant_scheme()
    +
    +        with self.eval_manager.session("W32 Evaluation") as sess:
    +            w32_eval_score = sess.eval(model=fp32_model, param_bw=32)
    +            _logger.info("Evaluation finished: W32A%d (eval score: %f)",
    +                         self._quantsim_params["output_bw"], w32_eval_score)
    +
    +            # Early exit
    +            if w32_eval_score < target_acc:
    +                _logger.info(
    +                    "W32A%d eval score (%f) is lower "
    +                    "than the target eval score (%f). This means it is unlikely that "
    +                    "the target eval score can be met using PTQ techniques. "
    +                    "Please consider finetuning the model using range learning.",
    +                    self._quantsim_params["output_bw"], w32_eval_score, target_acc
    +                )
    +
    +                # Since AutoQuant pipeline exited early, all the return values are set to None
    +                return {
    +                    "model": None,
    +                    "accuracy": None,
    +                    "encoding_path": None,
    +                    "applied_techniques": None,
    +                }
    +
    +            sess.result["target_satisfied"] = True
    +
    +        # Batchnorm Folding
    +        with self.eval_manager.session("Batchnorm Folding", ptq=True) as sess:
    +            model, _ = self._apply_batchnorm_folding(fp32_model)
    +            if sess.ptq_result is None:
    +                sess.set_ptq_result(model=model,
    +                                    applied_techniques=["batchnorm_folding"])
    +
    +        best_result = self.eval_manager.get_best_ptq_result()
    +        if best_result and best_result.accuracy >= target_acc:
    +            sess.result["target_satisfied"] = True
    +            return best_result.as_dict()
    +
    +        # Cross-Layer Equalization
    +        with self.eval_manager.session("Cross-Layer Equalization", ptq=True) as sess:
    +            model = self._apply_cross_layer_equalization(fp32_model)
    +            if sess.ptq_result is None:
    +                sess.set_ptq_result(model=model,
    +                                    applied_techniques=["cross_layer_equalization"])
    +
    +        best_result = self.eval_manager.get_best_ptq_result()
    +        if best_result and best_result.accuracy >= target_acc:
    +            sess.result["target_satisfied"] = True
    +            return best_result.as_dict()
    +
    +        if best_result is None:
    +            model = fp32_model
    +            applied_techniques = []
    +        else:
    +            if "cross_layer_equalization" not in best_result.applied_techniques:
    +                sess.result["effective"] = False
    +            model = best_result.load_model()
    +            applied_techniques = best_result.applied_techniques
    +
    +        # AdaRound
    +        with self.eval_manager.session("AdaRound", ptq=True) as sess:
    +            model, encoding_path = self._apply_adaround(model)
    +            if sess.ptq_result is None:
    +                sess.set_ptq_result(model=model,
    +                                    encoding_path=encoding_path,
    +                                    applied_techniques=[*applied_techniques, "adaround"])
    +
    +        best_result = self.eval_manager.get_best_ptq_result()
    +        if best_result:
    +            if "adaround" not in best_result.applied_techniques:
    +                sess.result["effective"] = False
    +            if best_result.accuracy >= target_acc:
    +                sess.result["target_satisfied"] = True
    +            return best_result.as_dict()
    +
    +        raise RuntimeError("None of batchnorm folding, CLE, or Adaround "
    +                           "has been finished successfully.")
    +
    +
    +@dataclass
    +class PtqResult:
    +    """
    +    Evaluation results
    +    :param model_path: Path to the serialized model.
    +    :param encoding_path: Path to the encoding file.
    +    :param accuracy: Accuracy of the model.
    +    :param applied_techniques: Applied ptq techniques.
    +    """
    +    model_path: str
    +    encoding_path: str
    +    accuracy: float
    +    applied_techniques: List[str]
    +
    +    def load_model(self):
    +        """
    +        Load model
    +        :return: Loaded model
    +        """
    +        return tf.keras.models.load_model(self.model_path)
    +    def save_result_as(self, prefix: str = "best_model"):
    +        """
    +        Creates the copy of the PTQ result files with the given prefix.
    +        :param prefix: prefix to be added to the file's basename
    +        """
    +        src_files = [self.model_path+".h5", self.model_path+"_converted.pb", self.encoding_path]
    +        for file in src_files:
    +            name = os.path.basename(file)
    +            dirname = os.path.dirname(file)
    +            dest = os.path.join(dirname, prefix + "_" + name)
    +            if os.path.exists(file):
    +                if os.path.exists(dest):
    +                    os.remove(dest)
    +                shutil.copyfile(file, dest)
    +    def as_dict(self):
    +        """Convert to dictionary"""
    +        return dict(model=self.load_model(),
    +                    accuracy=self.accuracy,
    +                    encoding_path=self.encoding_path,
    +                    applied_techniques=self.applied_techniques)
    +
    +
    +class _EvalManager:
    +    """
    +    Evaluation manager for AutoQuant.
    +    """
    +
    +    def __init__(self,
    +                 quantsim_factory: Callable,
    +                 eval_func: Callable[[tf.keras.Model], float],
    +                 results_dir: str,
    +                 strict_validation: bool):
    +        """
    +        :param quantsim_factory: A factory function that returns QuantizationSimModel.
    +        :param eval_func: Evaluation function.
    +        :param results_dir: Base directory to save the temporary serialized model.
    +        :param strict_validation: Flag set to True by default.
    +            When False, AutoQuant will proceed with execution and
    +            handle errors internally if possible.
    +            This may produce unideal or unintuitive results.
    +        """
    +        self._quantsim_factory = quantsim_factory
    +        self._eval_func = eval_func
    +        self._results_dir = results_dir
    +        self._strict_validation = strict_validation
    +        os.makedirs(self._results_dir, exist_ok=True)
    +
    +        self._all_sessions = OrderedDict()
    +
    +    def clear(self):
    +        """
    +        Clear all the session status saved in the previous run
    +        """
    +        for sess in self._all_sessions.values():
    +            sess.reset_status()
    +
    +    def get_best_ptq_result(self) -> PtqResult:
    +        """
    +        Get the results with the highest evaluation score among the ptq results evaluated so far.
    +        :return: The best evaluation result so far.
    +        """
    +        ptq_results = [sess.ptq_result for sess in self._all_sessions.values()
    +                       if sess.ptq_result is not None]
    +        if not ptq_results:
    +            return None
    +
    +        return max(ptq_results, key=lambda ptq_result: ptq_result.accuracy)
    +
    +    def session(self, title: str, ptq: bool = False):
    +        """
    +        Session factory.
    +        :param title: Title of the session.
    +        :param ptq: True if this session is a ptq session
    +        :return: Session object.
    +        """
    +        if title not in self._all_sessions:
    +            session = _EvalSession(title,
    +                                   self._quantsim_factory,
    +                                   self._eval_func,
    +                                   results_dir=os.path.join(self._results_dir, ".trace"),
    +                                   strict_validation=self._strict_validation,
    +                                   ptq=ptq)
    +            self._all_sessions[title] = session
    +        return self._all_sessions[title]
    +
    +    HTML_TEMPLATE_FILE = os.path.join(
    +        os.path.dirname(os.path.abspath(__file__)),
    +        "auto_quant_v2_diagnostics_template.html",
    +    )
    +
    +    def export_diagnostics(self) -> str:
    +        """
    +        Export diagnostics in html format.
    +        :return: Diagnostics string in html format.
    +        """
    +        loader = jinja2.FileSystemLoader(os.path.dirname(os.path.abspath(self.HTML_TEMPLATE_FILE)))
    +        env = jinja2.Environment(loader=loader)
    +        template = env.get_template(os.path.basename(self.HTML_TEMPLATE_FILE))
    +
    +        if any(sess.diagnostics.contains_bokeh() for sess in self._all_sessions.values()):
    +            head = CDN.render()
    +        else:
    +            head = ""
    +
    +        log = io.StringIO()
    +        for sess in self._all_sessions.values():
    +            if sess.diagnostics.is_empty():
    +                continue
    +            log.write(
    +                f"<h1> {sess.title} </h1>\n"
    +            )
    +            content = "\n".join(
    +                line.get_html_elem() for line in sess.diagnostics
    +            )
    +            log.write(f"{content}\n")
    +
    +        result = OrderedDict()
    +        result["ptq_techniques"] = OrderedDict()
    +
    +        for sess in self._all_sessions.values():
    +            if sess.is_ptq_session():
    +                result["ptq_techniques"][sess.title_lowercase] = sess.result
    +            else:
    +                result[sess.title_lowercase] = sess.result
    +
    +        flowchart_metadata = _build_flowchart_metadata(result)
    +
    +        html = template.render(head=head, log=log.getvalue(), **flowchart_metadata)
    +
    +        filename = os.path.join(self._results_dir, "diagnostics.html")
    +        with open(filename, "w") as file_name:
    +            file_name.write(html)
    +        return html
    +
    +
    +class _EvalSession: # pylint: disable=too-many-instance-attributes
    +    """
    +    Evaluation session for AutoQuant.
    +
    +    Each session object contains a title and diagnostics produced during the session.
    +    The collected diagnostics will be exported into a html file by _EvalManager.
    +    """
    +    def __init__(self, # pylint: disable=too-many-arguments
    +                 title: str,
    +                 quantsim_factory: Callable,
    +                 eval_func: Callable[[tf.keras.Model], float],
    +                 results_dir: str,
    +                 strict_validation: bool,
    +                 ptq: bool,):
    +        """
    +        :param title: Title of the session.
    +        :param quantsim_factory: A factory function that returns QuantizationSimModel.
    +        :param eval_func: Evaluation function.
    +        :param results_dir: Base directory to save the temporary serialized model.
    +        :param strict_validation: Flag set to True by default.
    +            When False, AutoQuant will proceed with execution
    +            and handle errors internally if possible.
    +            This may produce unideal or unintuitive results.
    +        :param ptq: True if this session is a ptq session
    +        """
    +        self.title = title
    +        self._quantsim_factory = quantsim_factory
    +        self._eval_func = eval_func
    +        self._results_dir = results_dir
    +        self._strict_validation = strict_validation
    +        self._ptq = ptq
    +        self._spinner = None
    +
    +        self.result = {
    +            "status": None,
    +            "error": None,
    +            "target_satisfied": False,
    +            "effective": True,
    +        }
    +
    +        os.makedirs(self._results_dir, exist_ok=True)
    +
    +        self.diagnostics = Diagnostics()
    +
    +        # Map session title to file name.
    +        # e.g. title: "Cross-Layer Equalization" -> filename: "cross_layer_equalization"
    +        self.title_lowercase = self.title.lower().replace("-", " ")
    +        self.title_lowercase = "_".join(self.title_lowercase.split())
    +
    +        stdout_write = sys.stdout.write
    +        self._log = io.StringIO()
    +
    +        # Redirects stdout to self._log
    +        def write_wrapper(*args, **kwargs):
    +            self._log.write(*args, **kwargs)
    +            return stdout_write(*args, **kwargs)
    +
    +        self._stdout_redirect = patch.object(sys.stdout, "write", write_wrapper)
    +        self._ptq_result = None
    +        self._cached_result = None
    +
    +    def is_ptq_session(self):
    +        """
    +        Getter method of self._ptq flag
    +        """
    +        return self._ptq
    +
    +    def reset_status(self):
    +        """
    +        Reset the session status saved in the previous run
    +        """
    +        self.result = {
    +            "status": None,
    +            "error": None,
    +            "target_satisfied": False,
    +            "effective": True,
    +        }
    +
    +    def eval(self, model: tf.keras.Model, **kwargs):
    +        """
    +        Evaluate the model
    +        :param model: Model to evaluate.
    +        :param kwargs: Additional arguments to the quantsim factory.
    +        :return: Eval score
    +        """
    +        sim = self._quantsim_factory(model, **kwargs)
    +        acc = self._eval_func(sim.model)
    +        return acc
    +
    +    def __enter__(self):
    +        self._spinner = Spinner(self.title)
    +        self._spinner.__enter__()
    +        self._stdout_redirect.start()
    +        return self
    +
    +    def __exit__(self, exc_type, exc_val, exc_tb):
    +        if self._ptq_result is not None:
    +            _logger.info("Session finished: %s. (eval score: %f)",
    +                         self.title, self._ptq_result.accuracy)
    +        self._spinner.__exit__(exc_type, exc_val, exc_tb)
    +
    +        if exc_val:
    +            buffer = io.StringIO()
    +            traceback.print_exception(exc_type, exc_val, exc_tb, file=buffer)
    +
    +            if self._strict_validation:
    +                print(buffer.getvalue())
    +            else:
    +                print(
    +                    "################################################################\n"
    +                    "################################################################\n"
    +                    "################################################################\n"
    +                    "WARNING: The following exception was raised but ignored:\n\n"
    +                    f"{buffer.getvalue()}"
    +                    "################################################################\n"
    +                    "################################################################\n"
    +                    "################################################################\n"
    +                )
    +
    +        self._stdout_redirect.stop()
    +        self.diagnostics.add(self._log.getvalue())
    +
    +        self.result["error"] = exc_val
    +        if not exc_val:
    +            self.result["status"] = "success"
    +        elif self._strict_validation:
    +            self.result["status"] = "error-failed"
    +        else:
    +            self.result["status"] = "error-ignored"
    +
    +        if exc_val and not self._strict_validation:
    +            # Return True so that the error doesn't propagate further
    +            return True
    +        return None
    +    @property
    +    def ptq_result(self) -> PtqResult:
    +        """Getter of self._ptq_result."""
    +        return self._ptq_result
    +
    +    def set_ptq_result(self,
    +                       applied_techniques: List[str],
    +                       model: tf.keras.Model = None,
    +                       sim: QuantizationSimModel = None,
    +                       acc: float = None,
    +                       **kwargs):
    +        """
    +        Set the result of PTQ. Should be called exactly once inside a with-as block
    +
    +        Exactly one among model and (sim, acc) pair should be specified
    +        1) If sim and acc is specified, save them as the result of this session
    +        2) If model is specified, evaluate the quantized accuracy of the model and save the result
    +        :param applied_techniques: List of applied technique names
    +        :param model: Result of PTQ
    +        :param sim: Result of PTQ. The quantization encoding (compute_encodings()) is
    +                    assumed to have been computed in advance
    +        :param acc: Eval score
    +        :param kwargs: Additional arguments to the quantsim factory
    +        """
    +        if sim is None:
    +            assert acc is None
    +            assert model is not None
    +            sim = self._quantsim_factory(model, **kwargs)
    +            acc = self._eval_func(sim.model)
    +        else:
    +            assert acc is not None
    +            assert model is None
    +
    +        self._set_ptq_result(sim, acc, applied_techniques)
    +
    +    def _set_ptq_result(self,
    +                        sim: QuantizationSimModel,
    +                        acc: float,
    +                        applied_techniques: List[str]) -> PtqResult:
    +        """
    +        Set the result of PTQ. Should be called exactly once inside a with-as block
    +        :param sim: Result of PTQ. The quantization encoding (compute_encodings()) is
    +                    assumed to have been computed in advance
    +        :param acc: Eval score
    +        :param applied_techniques: List of applied technique names
    +        :return: PtqResult object
    +        """
    +        if self._ptq_result is not None:
    +            raise RuntimeError(
    +                "sess.eval() can be called only once per each _EvalSession instance."
    +            )
    +        model_path, encoding_path = self._export(sim)
    +        self._ptq_result = PtqResult(model_path=model_path,
    +                                     encoding_path=encoding_path,
    +                                     accuracy=acc,
    +                                     applied_techniques=applied_techniques)
    +        _logger.info(self._ptq_result)
    +        return self._ptq_result
    +
    +    def _export(self, sim: QuantizationSimModel) -> Tuple[str, str]:
    +        """
    +        Export quantsim
    +        :param sim: QuantizationSimModel object to export
    +        :return: The paths where model and encoding are saved
    +        """
    +        sim.export(path=self._results_dir, filename_prefix=self.title_lowercase)
    +        model_path = os.path.join(self._results_dir, f"{self.title_lowercase}")
    +        encoding_path = os.path.join(self._results_dir, f"{self.title_lowercase}.encodings")
    +        _logger.info("The results of %s is saved in %s and %s.",
    +                     self.title, model_path, encoding_path)
    +        return model_path, encoding_path
    +
    +
    +@contextlib.contextmanager
    +def spy_auto_quant(auto_quant: AutoQuant):
    +    """
    +    Install a spy that collects the handles to the ptq result of
    +    each stage of AutoQuant.
    +
    +    Typical usage::
    +        >>> auto_quant = AutoQuant(...)
    +        ... with auto_quant_spy(auto_quant) as spy:
    +        ...     _ = auto_quant.apply(...)
    +        ...
    +        ... for result in spy.get_all_ptq_results():
    +        ...     print(result.applied_techniques)
    +        ...     print(result.accuracy)
    +        ...     print(result.encoding_path)
    +        ...     model = result.load_model()
    +        ...     ...
    +    """
    +
    +    # pylint: disable=protected-access
    +    class Spy:
    +        """
    +        Spy that collects the handles to the ptq result of
    +        each stage of AutoQuant.
    +        """
    +
    +        def __init__(self, eval_manager):
    +            self._eval_manager = eval_manager
    +
    +        def get_all_ptq_results(self) -> List[PtqResult]:
    +            """Return handles to the results of AutoQuant"""
    +            if self._eval_manager is None:
    +                return []
    +            return [sess.ptq_result for sess in self._eval_manager._all_sessions.values()
    +                    if sess.ptq_result is not None]
    +
    +    spy = Spy(auto_quant.eval_manager)
    +
    +    _optimize_main = auto_quant._optimize_main
    +
    +    def _optimize_main_wrapper(fp32_model, target_acc):
    +        return _optimize_main(fp32_model, target_acc)
    +
    +    try:
    +        setattr(auto_quant, "_optimize_main", _optimize_main_wrapper)
    +        yield spy
    +    finally:
    +        setattr(auto_quant, "_optimize_main", _optimize_main)
    +
    +
    +def _build_flowchart_metadata(result: Mapping) -> Dict: # pylint: disable=too-many-return-statements
    +    """
    +    Build flowchart metadata for the html template of summary report
    +
    +    :param result: Result of AutoQuant with the following format:
    +
    +        result := {
    +            "quantscheme_selection": _stage_result,
    +            "w32_evaluation": _stage_result,
    +            "ptq_techniques" [
    +                "batchnorm_folding": _stage_result,
    +                "cross_layer_equalization": _stage_result,
    +                "adaround": _stage_result,
    +            ]
    +
    +        }
    +
    +        where _stage_result is a dictionary defined as below:
    +
    +        _stage_result := {
    +            "status": str,
    +            "error": Exception,
    +            "target_satisfied": bool,
    +            "effective": bool,
    +        }
    +
    +    :return: Dictionary that contains flowchart metadata for html template
    +    """
    +    metadata = defaultdict(str)
    +
    +    metadata.update(
    +        edge_quant_scheme_selection_in='data-visited="true"',
    +    )
    +    if "quantscheme_selection" in result:
    +        status = result['quantscheme_selection']['status']
    +        metadata.update(
    +            node_quant_scheme_selection=f'data-visited="true" data-stage-result="{status}"',
    +        )
    +
    +        if status == 'error-failed':
    +            return metadata
    +
    +    metadata.update(
    +        edge_quant_scheme_selection_out='data-visited="true"',
    +        node_test_w32_eval_score='data-visited="true"',
    +    )
    +
    +    if not result["w32_evaluation"]["target_satisfied"]:
    +        metadata.update(
    +            edge_test_w32_eval_score_if_false='data-visited="true"',
    +            node_result_fail='data-visited="true"',
    +        )
    +        return metadata
    +
    +    metadata.update(
    +        edge_test_w32_eval_score_if_true='data-visited="true"',
    +    )
    +
    +
    +    for ptq_name, ptq_result in result["ptq_techniques"].items():
    +        status = ptq_result['status']
    +        effective = ptq_result['effective']
    +        if status == "success" and not effective:
    +            status = "discarded"
    +        metadata.update({
    +            f"node_{ptq_name}": f'data-visited="true" data-stage-result="{status}"',
    +        })
    +
    +        if status == 'error-failed':
    +            return metadata
    +
    +        metadata.update({
    +            f'edge_{ptq_name}_out': 'data-visited="true"',
    +            f'node_test_{ptq_name}': 'data-visited="true"',
    +        })
    +
    +        if ptq_result['target_satisfied']:
    +            metadata.update({
    +                f'edge_test_{ptq_name}_if_true': 'data-visited="true"',
    +                'node_result_success': 'data-visited="true"',
    +            })
    +            return metadata
    +
    +        metadata.update({
    +            f'edge_test_{ptq_name}_if_false': 'data-visited="true"',
    +        })
    +
    +    metadata.update(
    +        node_result_fail='data-visited="true"',
    +    )
    +
    +    return metadata
    +
    +
    +ParetoFrontType = List[Tuple[int, float, QuantizerGroup, Tuple]]
    +
    +@dataclass
    +class _MixedPrecisionArgs:
    +    """
    +    Mixed-precision specific arguments.
    +    """
    +    candidates: List[AmpCandidate]
    +    forward_pass_callback: CallbackFunc
    +    eval_callback_for_phase1: CallbackFunc
    +    eval_callback_for_phase2: CallbackFunc
    +
    +@dataclass
    +class _MixedPrecisionResult:
    +    """
    +    Mixed precision result
    +    """
    +    pareto_list: ParetoFrontType
    +    sim: QuantizationSimModel
    +    final_eval_score: float
    +    sensitivity_plot: bokeh.plotting.figure
    +    pareto_plot: bokeh.plotting.figure
    +
    +
    +# The number of samples to be used for performance evaluation and AMP.
    +# NOTE: None means "all".
    +DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_1 = EvalCallbackFactory._DEFAULT_SQNR_NUM_SAMPLES # pylint: disable=protected-access
    +DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_2 = None
    +
    +
    +[docs] +class AutoQuantWithAutoMixedPrecision: + """ + Integrate and apply post-training quantization techniques. + + AutoQuant includes 1) batchnorm folding, 2) cross-layer equalization, + 3) Adaround, and 4) Automatic Mixed Precision (if enabled). + These techniques will be applied in a best-effort manner until the model + meets the evaluation goal given as allowed_accuracy_drop. + """ + + # pylint: disable=too-many-arguments + def __init__(self, + model: tf.keras.Model, + eval_callback: Callable[[tf.keras.Model], float], + dataset: tf.data.Dataset, + param_bw: int = 8, + output_bw: int = 8, + quant_scheme: QuantScheme = QuantScheme.post_training_tf_enhanced, + rounding_mode: str = "nearest", + config_file: str = None, + results_dir: str = "/tmp", + cache_id: str = None, + strict_validation: bool = True): + """ + :param model: Model to be quantized. Assumes model is on the correct device + :param eval_callback: A function that maps model and the number samples + to the evaluation score. This callback is expected to return a + scalar value representing the model performance evaluated + against exactly `N` samples, where `N` is the number of samples + passed as the second argument of this callback. + NOTE: If `N` is None, the model is expected to be evaluated against + the whole evaluation dataset. + :param dataset: An unlabeled dataset for encoding computation. + By default, this dataset will be also used for Adaround unless + otherwise specified by `self.set_adaround_params` + :param param_bw: Parameter bitwidth + :param output_bw: Output bitwidth + :param quant_scheme: Quantization scheme + :param rounding_mode: Rounding mode + :param config_file: Path to configuration file for model quantizers + :param results_dir: Directory to save the results of PTQ techniques + :param cache_id: ID associated with cache results + :param strict_validation: Flag set to True by default.hen False, AutoQuant will proceed with execution and handle errors internally if possible. This may produce unideal or unintuitive results. + """ + self._auto_quant_base = AutoQuant(model, + eval_callback, + dataset, + param_bw, + output_bw, + quant_scheme, + rounding_mode, + config_file, + results_dir, + cache_id, + strict_validation) + self.dataset = dataset + self._amp_args = None + +
    +[docs] + def run_inference(self) -> Tuple[QuantizationSimModel, float]: + ''' + Creates a quantization model and performs inference + + :return: QuantizationSimModel, model accuracy as float + ''' + return self._auto_quant_base.run_inference()
    + + +
    +[docs] + def optimize(self, allowed_accuracy_drop: float = 0.0) \ + -> Tuple[tf.keras.Model, float, str, ParetoFrontType]: + """ + Integrate and apply post-training quantization techniques. + + :param allowed_accuracy_drop: Maximum allowed accuracy drop + :return: Tuple of (best model, eval score, encoding path, pareto front). + Pareto front is None if AMP is not enabled or AutoQuant exits + without performing AMP. + """ + html_template_file = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "auto_quant_v2_diagnostics_template_with_amp.html", + ) + with patch.object(_EvalManager, "HTML_TEMPLATE_FILE", html_template_file): + result = self._auto_quant_base._optimize_helper(self._optimize_main, # pylint: disable=protected-access + allowed_accuracy_drop) + return result["model"], \ + result["accuracy"], \ + result["encoding_path"], \ + result["pareto_list"]
    + + +
    +[docs] + def set_adaround_params(self, adaround_params: AdaroundParameters): + """ + Set Adaround parameters. + If this method is not called explicitly by the user, AutoQuant will use + `dataset` (passed to `__init__`) for Adaround. + + :param adaround_params: Adaround parameters. + """ + return self._auto_quant_base.set_adaround_params(adaround_params)
    + + +
    +[docs] + def set_mixed_precision_params(self, # pylint: disable=too-many-locals + candidates: List[CANDIDATE_WITH_DTYPE], + num_samples_for_phase_1: Optional[int] = DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_1, + forward_fn: Callable = _default_forward_fn, + num_samples_for_phase_2: Optional[int] = DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_2): + """ + Set mixed precision parameters. + NOTE: Automatic mixed precision will NOT be enabled unless this method + is explicitly called by the user. + + :param candidates: List of tuples of candidate bitwidths and datatypes. + :param num_samples_for_phase_1: Number of samples to be used for performance + evaluation in AMP phase 1. + :param forward_fn: Function that runs forward pass and returns the output tensor. + which will be used for SQNR compuatation in phase 1. + This function is expected to take 1) a model and 2) a single batch + yielded from the dataset, and return a single torch.Tensor object + which represents the output of the model. + :param num_samples_for_phase_2: Number of samples to be used for performance + evaluation in AMP phase 2. + """ + if len(candidates) < 2: + raise ValueError(f"AMP requires at least two candidates. Got {len(candidates)}.") + + baseline_param_bw = self._auto_quant_base._quantsim_params["param_bw"] # pylint: disable=protected-access + baseline_output_bw = self._auto_quant_base._quantsim_params["output_bw"] # pylint: disable=protected-access + baseline_candidate = ( + (baseline_output_bw, QuantizationDataType.int), + (baseline_param_bw, QuantizationDataType.int), + ) + + if baseline_candidate not in candidates: + raise ValueError( + f"AMP candidate must contain W{baseline_param_bw}A{baseline_output_bw}, " + "which was passed to the constructor of AutoQuant as `param_bw` and `output_bw`." + ) + + for candidate in candidates: + ((output_bw, output_dtype), (param_bw, param_dtype)) = candidate + + if output_dtype != param_dtype: + raise ValueError( + "The data types of parameters and outputs should be the same. " + f"Got {output_dtype} output and {param_dtype} for parameter." + ) + + if output_dtype == QuantizationDataType.float: + continue + + # The param/output_bw passed to the constructor of AutoQuant + # must be the baseline-bitwidth candidate among all AMP candidates. + if output_bw < baseline_output_bw or param_bw < baseline_param_bw: + raise ValueError( + "All AMP candidates should be strictly superior to the baseline " + f"W{baseline_param_bw}A{baseline_output_bw}, which was passed " + "to the constructor of AutoQuant. Please make sure that all the INT candidates " + f"satisfy param_bw >= {baseline_param_bw} and output_bw >= {baseline_param_bw}." + ) + + def dataloader_wrapper(): + + return self.dataset + + factory = EvalCallbackFactory(dataloader_wrapper, forward_fn=forward_fn) + sqnr_eval_callback = factory.sqnr(num_samples=num_samples_for_phase_1) + + candidates = [AmpCandidate(candidate) for candidate in set(candidates)] + + self._amp_args = _MixedPrecisionArgs( + candidates=candidates, + forward_pass_callback=CallbackFunc(self._auto_quant_base.forward_pass_callback, None), + eval_callback_for_phase1=sqnr_eval_callback, + eval_callback_for_phase2=CallbackFunc(self._auto_quant_base.eval_callback, + num_samples_for_phase_2) + )
    + +
    +[docs] + def get_quant_scheme_candidates(self) -> Tuple[_QuantSchemePair, ...]: + """ + Return the candidates for quant scheme search. + During :meth:`~AutoQuant.optimize`, the candidate with the highest accuracy + will be selected among them. + + :return: Candidates for quant scheme search + """ + return self._auto_quant_base.get_quant_scheme_candidates()
    + + +
    +[docs] + def set_quant_scheme_candidates(self, candidates: Tuple[_QuantSchemePair, ...]): + """ + Set candidates for quant scheme search. + During :meth:`~AutoQuant.optimize`, the candidate with the highest accuracy + will be selected among them. + + :param candidates: Candidates for quant scheme search + """ + return self._auto_quant_base.set_quant_scheme_candidates(candidates)
    + + + def _apply_mixed_precision(self, + model: tf.keras.Model, + target_acc: float, + amp_args: _MixedPrecisionArgs, + results_dir: str, + encoding_path: str = None) -> _MixedPrecisionResult: + """ + Apply mixed-precision and return the highest accuracy. + + NOTE1: Input model is not mutated. + NOTE2: Parameter `clean_start` is always set to True. + + :param model: tf.keras.Model to apply mixed precision. + :param target_acc: Minimum evaluation score required. + :param results_dir: Directory to save the results of AdaRound and mixed precision. + :param encoding_path: Path to parameter encodings file. + :return: MixedPrecisionAlgo object. + """ + if not amp_args: + raise RuntimeError + + sim = self._auto_quant_base._create_quantsim_and_encodings(model, # pylint: disable=protected-access + encoding_path=encoding_path) + + algo = GreedyMixedPrecisionAlgo(sim, + amp_args.candidates, + amp_args.eval_callback_for_phase1, + amp_args.eval_callback_for_phase2, + results_dir=results_dir, + clean_start=True, + forward_pass_callback=amp_args.forward_pass_callback) + + # Find baseline accuracy and bw corresponding to baseline accuracy + algo.set_baseline(fp32_accuracy=self._auto_quant_base._fp32_acc) # pylint: disable=protected-access + allowed_accuracy_drop = algo.fp32_accuracy - target_acc + + algo.run(allowed_accuracy_drop) + + sensitivity_plot = None + if algo.accuracy_list is not None: + # Visualize quantizer group sensitivity + sensitivity_plot = create_sensitivity_plot(algo.accuracy_list, + algo.baseline_candidate, + algo.fp32_accuracy) + pareto_plot = None + if algo.pareto_list is not None: + # Create pareto list curve + pareto_plot = create_pareto_curve(algo.pareto_list) + + return _MixedPrecisionResult(algo.pareto_list, + algo._sim, # pylint: disable=protected-access + algo._final_eval_score, # pylint: disable=protected-access + sensitivity_plot, + pareto_plot) + + def _optimize_main(self, fp32_model: tf.keras.Model, target_acc: float) -> Dict[str, Any]: + """ + Helper function of apply(). + + :param fp32_model: Model to apply PTQ techniques. + :param target_acc: Target eval score. + :return: The best ptq result as a dictionary. + """ + # pylint: disable=broad-except, too-many-locals, too-many-statements, too-many-branches + + if self._amp_args: + candidates = copy.copy(self._amp_args.candidates) + else: + candidates = [] + + eval_manager = self._auto_quant_base.eval_manager + results_dir = self._auto_quant_base.results_dir + strict_validation = eval_manager._strict_validation # pylint: disable=protected-access + + sess = eval_manager.session("") + _multiconfig_adaround_fn = _adaround_wrapper(self._auto_quant_base._apply_adaround, # pylint: disable=protected-access + self._auto_quant_base, + candidates, + target_acc, + sess.eval) + sess_eval_fn = _EvalSession.eval + def eval_fn(_, model, param_bw=None, output_bw=None, **kwargs): + if param_bw == 32: + # For W32 evaluation, use the highest output bitwidth + # among all the AMP candidates + output_bitwidths = [ + output_bw for (output_bw, output_dtype), _ in candidates + if output_dtype == QuantizationDataType.int + ] + output_bitwidths.append(self._auto_quant_base._quantsim_params["output_bw"]) # pylint: disable=protected-access + output_bw = max(output_bitwidths) + return sess_eval_fn(_, model, param_bw=param_bw, output_bw=output_bw, **kwargs) + + with patch.object(self._auto_quant_base, "_apply_adaround", _multiconfig_adaround_fn), \ + patch.object(_EvalSession, "eval", eval_fn): + try: + result = self._auto_quant_base._optimize_main(fp32_model, target_acc) # pylint: disable=protected-access + + # Automatic Mixed Precision + result["pareto_list"] = None + + # An empty `result` dict means AutoQuant early-exited + # because W32 eval score didn't meet the target accuracy. + # In this case, do not proceed to AMP and exit immediately. + if result["model"] is None and \ + result["accuracy"] is None and \ + result["encoding_path"] is None and \ + result["applied_techniques"] is None: + return result + + if result["accuracy"] >= target_acc or not self._amp_args: + return result + + if len(candidates) < 2: + _logger.info( + "After Adaround, we have only one Adarond-compatible candidate left for AMP (W%dA%d). " + "Return without proceeding to AMP", candidates[0].param_bw, candidates[0].output_bw + ) + return result + + model = result["model"] + applied_techniques = result["applied_techniques"] + # Freeze weight encoding to adaround weight encoding + encoding_path = result["encoding_path"] if "adaround" in applied_techniques else None + except Exception: + if strict_validation: + raise + result = {} + model = fp32_model + applied_techniques = [] + encoding_path = None + + amp_args = copy.copy(self._amp_args) + if amp_args: + amp_args.candidates = candidates + + with eval_manager.session("Automatic Mixed Precision", ptq=True) as sess: + amp_result = self._apply_mixed_precision( + model, target_acc, amp_args, results_dir, encoding_path=encoding_path + ) + result["pareto_list"] = amp_result.pareto_list + + if amp_result.sensitivity_plot is not None: + sess.diagnostics.add(amp_result.sensitivity_plot) + + if amp_result.pareto_plot is not None: + sess.diagnostics.add(amp_result.pareto_plot) + + sess.set_ptq_result(sim=amp_result.sim, acc=amp_result.final_eval_score, + applied_techniques=[*applied_techniques, "automatic_mixed_precision"]) + + best_result = eval_manager.get_best_ptq_result() + if best_result: + if "automatic_mixed_precision" not in best_result.applied_techniques: + sess.result["effective"] = False + if best_result.accuracy >= target_acc: + sess.result["target_satisfied"] = True + result.update(best_result.as_dict()) + return result + + raise RuntimeError("None of batchnorm folding, CLE, or Adaround " + "has been finished successfully.")
    + + +def _adaround_wrapper(apply_adaround_fn: Callable, + auto_quant: AutoQuant, + amp_candidates: List[AmpCandidate], + target_acc: float, + eval_fn: Callable): + @functools.wraps(apply_adaround_fn) + def _apply_adaround_wrapper(*args, **kwargs): # pylint: disable=too-many-locals + # If AMP candidates are empty (i.e. AMP is disabled), + # perform normal (single-round) adaround. + original_model = args[0] + if not amp_candidates: + input_model = tf.keras.models.clone_model(original_model) + input_model.set_weights(original_model.get_weights()) + new_args = (input_model,) + args[1:] + return apply_adaround_fn(*new_args, **kwargs) + + def apply_adaround(param_bw: int): + _logger.info("Running Adaround with W%d", param_bw) + + orig_param_bw = auto_quant._quantsim_params["param_bw"] # pylint: disable=protected-access + try: + auto_quant._quantsim_params["param_bw"] = param_bw # pylint: disable=protected-access + input_model = tf.keras.models.clone_model(original_model) + input_model.set_weights(original_model.get_weights()) + new_args = (input_model,) + args[1:] + return apply_adaround_fn(*new_args, **kwargs) + finally: + auto_quant._quantsim_params["param_bw"] = orig_param_bw # pylint: disable=protected-access + + int_candidates = [ + candidate for candidate in amp_candidates + if candidate.param_dtype == QuantizationDataType.int + ] + sorted_int_candidates = sorted(int_candidates, + key=lambda candidate: (candidate.param_bw, candidate.output_bw)) + # Run Adaround with the lowest-bitwidth candidate + lowest_candidate = sorted_int_candidates[0] + model, encoding_path = apply_adaround(param_bw=lowest_candidate.param_bw) + + #If the lowest candidate is the only INT candidate, return immediately + if len(sorted_int_candidates) == 1: + return model, encoding_path + + eval_score = eval_fn(model, + param_bw=lowest_candidate.param_bw, + output_bw=lowest_candidate.output_bw, + encoding_path=encoding_path) + _logger.info("W%dA%d eval score after Adaround: %f", + lowest_candidate.param_bw, + lowest_candidate.output_bw, + eval_score) + + #If the lowest candidate satisfy the target accuracy, return immediately + if eval_score >= target_acc: + return model, encoding_path + + # If the lowest candidate fails to meet the target accuracy, + # discard the lowest candidate, apply Adaround to the second-lowest candidate, + # and use it as the baseline for AMP. + second_lowest_candidate = sorted_int_candidates[1] + + if second_lowest_candidate.param_bw != lowest_candidate.param_bw: + model = None + model, encoding_path = apply_adaround(param_bw=second_lowest_candidate.param_bw) + eval_score = eval_fn(model, + param_bw=second_lowest_candidate.param_bw, + output_bw=second_lowest_candidate.output_bw, + encoding_path=encoding_path) + _logger.info("W%dA%d eval score after Adaround: %f", + second_lowest_candidate.param_bw, + second_lowest_candidate.output_bw, + eval_score) + + # Only the candidates that are compatible with adaround can be used for AMP + adaround_compatible_amp_candidates = [ + candidate for candidate in amp_candidates + if candidate.param_bw == second_lowest_candidate.param_bw or \ + candidate.param_dtype == QuantizationDataType.float + ] + + # Fill in AMP candidates with Adaround-compatible candidates only + amp_candidates.clear() + amp_candidates.extend(adaround_compatible_amp_candidates) + + return model, encoding_path + + return _apply_adaround_wrapper +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_tensorflow/keras/batch_norm_fold.html b/releases/2.0.0/_modules/aimet_tensorflow/keras/batch_norm_fold.html new file mode 100644 index 0000000..71800f8 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_tensorflow/keras/batch_norm_fold.html @@ -0,0 +1,1363 @@ + + + + + + + + aimet_tensorflow.keras.batch_norm_fold - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_tensorflow.keras.batch_norm_fold

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2021-2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +#pylint: disable=too-many-lines
    +""" Utility for batch norm fold in tf 2.x """
    +from typing import Iterable, Optional, Tuple, Union, List, Dict, Set
    +import numpy as np
    +import tensorflow as tf
    +import tensorflow.keras.backend as K
    +from packaging import version  # pylint: disable=wrong-import-order
    +
    +if version.parse(tf.version.VERSION) >= version.parse("2.10"):
    +    # Ignore pylint errors as keras module is not available in TF 2.4
    +    from keras.layers.core.tf_op_layer import TFOpLambda # pylint: disable=import-error
    +    from keras.engine.functional import Functional # pylint: disable=import-error
    +else:
    +    # Ignore pylint errors due to conditional imports
    +    from tensorflow.python.keras.engine.functional import Functional # pylint: disable=ungrouped-imports
    +    from tensorflow.python.keras.layers.core import TFOpLambda # pylint: disable=ungrouped-imports
    +
    +# pylint: disable=wrong-import-position
    +from aimet_common.defs import QuantScheme, MAP_ROUND_MODE_TO_PYMO
    +
    +import aimet_common.libpymo as libpymo
    +from aimet_common.utils import AimetLogger
    +from aimet_tensorflow.keras.model_preparer import _KerasModelPreparer
    +from aimet_tensorflow.keras.quant_sim.qc_quantize_wrapper import QcQuantizeWrapper
    +from aimet_tensorflow.keras.quant_sim.tensor_quantizer import ParamPerTensorQuantizer
    +from aimet_tensorflow.keras.quantsim import QuantizationSimModel
    +from aimet_tensorflow.keras.utils import common
    +from aimet_tensorflow.keras.utils.model_connection_utils import ModelLayerConnections, ModelLayerConnectionsProperties
    +from aimet_tensorflow.keras.utils.quantizer_utils import get_wrappers_bias_quantizer, get_wrappers_weight_quantizer
    +from aimet_tensorflow.keras.utils.weight_tensor_utils import WeightTensorUtils
    +
    +_logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.Utils)
    +
    +LayerType = Union[
    +    tf.keras.layers.Conv2D,
    +    tf.keras.layers.Dense,
    +    tf.keras.layers.Conv2DTranspose,
    +    tf.keras.layers.DepthwiseConv2D
    +]
    +_supported_layers = LayerType.__args__
    +
    +PairType = Union[Tuple[LayerType, tf.keras.layers.BatchNormalization, bool],
    +                 Tuple[tf.keras.layers.BatchNormalization, LayerType, bool]]
    +
    +BatchNormType = tf.keras.layers.BatchNormalization
    +_supported_batchnorms = BatchNormType
    +
    +# Todo: search for more types of convolution
    +LinearType = tf.keras.layers.Dense
    +ConvType = Union[tf.keras.layers.Conv1D,
    +                 tf.keras.layers.Conv2D,
    +                 tf.keras.layers.DepthwiseConv2D,
    +                 tf.keras.layers.Conv2DTranspose]
    +_supported_convs = ConvType.__args__
    +
    +FlattenType = Union[tf.keras.layers.Flatten, tf.keras.layers.Reshape]
    +
    +MAP_PYMO_TO_ROUND_MODE = {v: k for k, v in MAP_ROUND_MODE_TO_PYMO.items()}
    +def _check_layer_to_find_pattern(cur_layer: tf.keras.layers.Layer,
    +                                 conv_linear_with_bn_dict: Dict[Union[ConvType, LinearType],
    +                                                                List[Union[None, BatchNormType]]],
    +                                 layer_out_node_ref: Dict,
    +                                 has_seen: List[Union[None, ConvType, BatchNormType, FlattenType]]):
    +    """
    +    find all paths in the model considering all inputs.
    +
    +    :param cur_layer: layer to investigate for finding a pattern
    +    :param conv_linear_with_bn_dict: dictionary to store possible conv_bn pairs,
    +        key: Dense or Conv layer & Value: list of BNS;
    +        first index in this list shows bn_in and the second index shows bn_out
    +    :param layer_out_node_ref: dictionary includes layer_ref as a key, outbound nodes as value
    +    :param has_seen: for storing the layer which is useful for finding pattern in the next layers;
    +        index 0 is for conv op, index 2 is for bn op and index 3 is for storing flatten/reshape op
    +    """
    +
    +    # pylint: disable=too-many-branches
    +    if isinstance(cur_layer, _supported_convs):
    +        if has_seen[1] is not None:
    +            conv_linear_with_bn_dict[cur_layer] = [has_seen[1], None]
    +            has_seen[1] = None
    +        if (cur_layer.activation is tf.keras.activations.linear) and \
    +                (cur_layer in layer_out_node_ref) and len(layer_out_node_ref[cur_layer]) == 1:
    +            has_seen[0] = cur_layer
    +    elif isinstance(cur_layer, BatchNormType):
    +        if has_seen[0] is not None:
    +            if has_seen[0] in conv_linear_with_bn_dict:
    +                conv_linear_with_bn_dict[has_seen[0]][1] = cur_layer
    +            else:
    +                conv_linear_with_bn_dict[has_seen[0]] = [None, cur_layer]
    +            has_seen[0] = None
    +        if (cur_layer in layer_out_node_ref) and len(layer_out_node_ref[cur_layer]) == 1:
    +            has_seen[1] = cur_layer
    +    elif isinstance(cur_layer, (tf.keras.layers.Flatten, tf.keras.layers.Reshape)):
    +        if (cur_layer in layer_out_node_ref) and len(layer_out_node_ref[cur_layer]) == 1:
    +            if has_seen[1]:
    +                has_seen[2] = cur_layer
    +            else:
    +                has_seen[1] = None
    +        if has_seen[0]:
    +            has_seen[0] = None
    +    elif isinstance(cur_layer, LinearType):
    +        if has_seen[1] is not None and has_seen[2] is not None:
    +            conv_linear_with_bn_dict[cur_layer] = [has_seen[1], None]
    +        has_seen[2] = None
    +        has_seen[1] = None
    +    else:
    +        has_seen[0] = None
    +        has_seen[1] = None
    +        has_seen[2] = None
    +
    +
    +def _add_children_layer_before_parent_layer(cur_layer: tf.keras.layers.Layer, node_layer_map: Dict,
    +                                            layer_out_node_map: Dict,
    +                                            visited_layers: Set[tf.keras.layers.Layer],
    +                                            reversed_ordered_layers: List[tf.keras.layers.Layer]):
    +    """
    +    Function to use topological sorting for finding all the layers which are accessible
    +    from the specific input_layer in the opposite order of occurrence.
    +
    +    :param cur_layer:layer that we want to find path from
    +    :param node_layer_map: dictionary includes node_ref as a key, in_layers and out_layer as value
    +    :param layer_out_node_map: dictionary includes layer_ref as a key, outbound nodes as value
    +    :param visited_layers: Set of all layers that have been visited
    +    :param reversed_ordered_layers: List of layers in the opposite order of occurrence
    +        for the layers that we have visited so far
    +    """
    +
    +    # Mark the current layer as visited.
    +    visited_layers.add(cur_layer)
    +
    +    if cur_layer in layer_out_node_map:
    +        # Recur for all the layers adjacent to this layer
    +        for next_node in layer_out_node_map[cur_layer]:
    +            next_layer = node_layer_map[next_node][1]
    +            if next_layer not in visited_layers:
    +                _add_children_layer_before_parent_layer(next_layer, node_layer_map,
    +                                                        layer_out_node_map, visited_layers,
    +                                                        reversed_ordered_layers)
    +            reversed_ordered_layers.append(cur_layer)
    +    else:
    +        reversed_ordered_layers.append(cur_layer)
    +
    +
    +def _get_ordered_layers(node_layer_map: Dict,
    +                        layer_out_node_map: Dict) -> List[tf.keras.layers.Layer]:
    +    """
    +    Function to return the list with all the layers in which layers come before parent layer.
    +
    +    :param node_layer_map: dictionary includes node_ref as a key, in_layers and out_layer as value
    +    :param layer_out_node_map: dictionary includes layer_ref as a key, outbound nodes as value
    +    :return: ordered_layers: List of all layers in the order of occurrence
    +    """
    +    # to find the input layers of the model
    +    input_layers = common.find_input_layers(node_layer_map)
    +
    +    #  Set of all layers that have been visited (to cut short duplicate traversals)
    +    visited_layers = set()
    +
    +    # List of all layers in the opposite of order of occurrence
    +    reversed_ordered_layers = []
    +
    +    for input_layer in input_layers:
    +        _add_children_layer_before_parent_layer(input_layer, node_layer_map, layer_out_node_map,
    +                                                visited_layers, reversed_ordered_layers)
    +
    +    # reverse the list because layers are in reverse order
    +    ordered_layers = reversed_ordered_layers[::-1]
    +
    +    # # filter ordered ops for only valid ops
    +    # ordered_ops = [op for op in ordered_ops if op in valid_ops]
    +
    +    return ordered_layers
    +
    +
    +def _get_ordered_conv_linears(node_layer_map: Dict,
    +                              layer_out_node_map: Dict) -> List[Union[ConvType, LinearType]]:
    +    """
    +    helper to select a list of conv_linears in the order of occurence
    +
    +    :param node_layer_map: dictionary includes node_ref as a key, in_layers and out_layer as value
    +    :param layer_out_node_map: dictionary includes layer_ref as a key, outbound nodes as value
    +    :return: return List of conv/linear layer refs
    +    """
    +    # get ordered layers list in node_layer map dictionary
    +    list_of_ordered_layers = _get_ordered_layers(node_layer_map, layer_out_node_map)
    +
    +    # look for conv layers
    +    ordered_conv_linears = []
    +    for layer in list_of_ordered_layers:
    +        if isinstance(layer, _supported_layers):
    +            ordered_conv_linears.append(layer)
    +    return ordered_conv_linears
    +
    +
    +def _fill_conv_linear_bn_dict(cur_layer: tf.keras.layers.Layer, node_layer_ref: Dict,
    +                              layer_out_node_ref: Dict,
    +                              has_seen: List[Union[None, ConvType, BatchNormType, FlattenType]],
    +                              visited_layer: Set[tf.keras.layers.Layer],
    +                              conv_linear_with_bn_dict: Dict[Union[ConvType, LinearType],
    +                                                             List[Union[None, BatchNormType]]]):
    +    """
    +    fill conv_linear_bn_dict for the model
    +
    +    :param cur_layer: dictionary includes node_ref as a key, in_layers and out_layer as value
    +    :param node_layer_ref: dictionary includes node_ref as a key, in_layers and out_layer as value
    +    :param layer_out_node_ref: dictionary includes layer_ref as a key, outbound nodes as value
    +    :paramm has_seen: for storing the layer which is useful for finding pattern in the next layers;
    +        index 0 is for conv op, index 2 is for bn op and index 3 is for storing flatten/reshape op
    +    :param visited_layer: to store all the layers that have been visited so far in the dictionary
    +    :param conv_linear_with_bn_dict: dictionary of all possible conv_bn pairs,
    +        key: Dense or Conv layer & Value: list of BNS;
    +        first index in this list shows bn_in and the second index shows bn_out
    +    """
    +
    +    # Mark the current layer as visited to prevent passing from one layer more than once
    +    visited_layer.add(cur_layer)
    +
    +    _check_layer_to_find_pattern(cur_layer, conv_linear_with_bn_dict, layer_out_node_ref, has_seen)
    +
    +    if cur_layer in layer_out_node_ref:
    +        for next_node in layer_out_node_ref[cur_layer]:
    +            next_layer = node_layer_ref[next_node][1]
    +            if next_layer not in visited_layer:
    +                _fill_conv_linear_bn_dict(next_layer, node_layer_ref, layer_out_node_ref, has_seen,
    +                                          visited_layer, conv_linear_with_bn_dict)
    +            else:
    +                has_seen[0] = None
    +                has_seen[1] = None
    +                has_seen[2] = None
    +
    +
    +def _find_possible_convs_linears_bn(node_layer_map: Dict, layer_out_node_map: Dict)\
    +        -> Dict[Union[ConvType, LinearType], List[Union[None, BatchNormType]]]:
    +    """
    +    find all possible convs_linears_bn by traversing all paths in the model considering all inputs
    +
    +    :param node_layer_map:  dictionary includes node_ref as a key, in_layers and out_layer as value
    +    :param layer_out_node_map: dictionary includes layer_ref as a key, outbound nodes as value
    +    :return: return dictionary of all possible conv_bn pairs,
    +        key: Dense or Conv layer & Value: list of BNS;
    +        first index in this list shows bn_in and the second index shows bn_out
    +    """
    +
    +    input_layers = common.find_input_layers(node_layer_map)
    +    visited_layer = set()
    +    conv_linear_with_bn_dict = {}
    +
    +    for input_layer in input_layers:
    +        _fill_conv_linear_bn_dict(input_layer, node_layer_map, layer_out_node_map,
    +                                  [None, None, None], visited_layer, conv_linear_with_bn_dict)
    +
    +    return conv_linear_with_bn_dict
    +
    +
    +def _get_bn_params(bn: tf.keras.layers.BatchNormalization) -> libpymo.BNParams():
    +    """
    +    helper to populate BN params from given BN Layer, required for fold
    +
    +    :param bn: BatchNorm Layer
    +    :return: return bn params in libpymo.TensorParams() format.
    +    """
    +    if bn.gamma is None:
    +        _logger.warning("Gamma for BatchNormalization '%s' is None. Setting to ones.", bn.name)
    +        # Batch Normalization layers can having missing gammas with two different cases. One is that the 'gamma' attribute
    +        # is set to None. The second is if `scale` is set to False upon creation of the layer which turns off gamma.
    +        with tf.name_scope(bn.name):
    +            weights_with_gamma_and_before_rebuild = [np.ones_like(bn.beta)] + bn.get_weights()
    +            bn.scale = True
    +            bn.build(bn.input.shape)
    +            bn.set_weights(weights_with_gamma_and_before_rebuild)
    +            bn.gamma = next(filter(lambda w: 'gamma' in w.name, bn.weights))
    +
    +    bn_params = libpymo.BNParams()
    +
    +    bn_params.gamma = bn.gamma.numpy().reshape(-1)
    +    bn_params.beta = bn.beta.numpy().reshape(-1)
    +    bn_params.runningMean = bn.moving_mean.numpy().reshape(-1)
    +    bn_params.runningVar = bn.moving_variance.numpy().reshape(-1)
    +    epsilon = bn.epsilon
    +    var = bn.moving_variance.numpy()
    +    var_with_epsilon = var + epsilon
    +    sigma = np.sqrt(var_with_epsilon)
    +    bn_params.runningVar = sigma
    +
    +    return bn_params
    +
    +
    +def _get_bias_tensor(conv_linear: LayerType) -> libpymo.TensorParams():
    +    """
    +    Get bias tensor in given conv layer.
    +
    +    Packs bias in the format required for BN fold
    +    (libpymo.TensorParams()).
    +    :param conv_linear: conv Layer
    +    :return: return bias param in libpymo.TensorParams() format.
    +    """
    +
    +    bias_tensor = libpymo.TensorParams()
    +    if conv_linear.bias is not None:
    +        bias_tensor.data = conv_linear.bias.numpy().reshape(-1)
    +        bias_tensor.shape = np.array(conv_linear.bias.shape)
    +
    +    return bias_tensor
    +
    +
    +def _get_weight_tensor_transpose_reshape(conv_linear: LayerType) -> libpymo.TensorParams():
    +    """
    +    Get weight tensor from conv layer.
    +
    +    Converts to right format - performs transpose and reshape.
    +    Packs it to the format required for BN fold (libpymo.TensorParams()).
    +    :param conv_linear: conv layer
    +    :return: return weight tensor in libpymo.TensorParams() format.
    +    """
    +
    +    # Weight tensor libpymo format
    +    weight_tensor = libpymo.TensorParams()
    +
    +    # linear array to be sent for bn fold
    +    weight = conv_linear.get_weights()[0]
    +    shape = weight.shape
    +
    +    if isinstance(conv_linear, tf.keras.layers.DepthwiseConv2D):
    +        # Depthwise conv layers in TF have outputs(Noc) set to 1.
    +        # we will use format [Nic, Noc, kh, kw] -
    +        # to be compatible with cpp backend.
    +        weight = np.transpose(weight, (2, 3, 0, 1))
    +        # [Nic, Noc, kh, kw]
    +        shape = np.array([shape[2], shape[3], shape[0], shape[1]])
    +    elif isinstance(conv_linear, tf.keras.layers.Dense):
    +        shape = np.concatenate((np.array([1, 1]), shape))
    +        weight = np.transpose(weight, (1, 0))
    +        # [Noc, Nic, kh, kw]
    +        shape = np.array([shape[3], shape[2], shape[0], shape[1]])
    +    elif isinstance(conv_linear, tf.keras.layers.Conv2DTranspose):
    +        weight = np.transpose(weight, (2, 3, 0, 1))
    +        # [Noc, Nic, kh, kw]
    +        shape = np.array([shape[2], shape[3], shape[0], shape[1]])
    +    elif isinstance(conv_linear, tf.keras.layers.Conv2D):
    +        weight = np.transpose(weight, (3, 2, 0, 1))
    +        # [Noc, Nic, kh, kw]
    +        shape = np.array([shape[3], shape[2], shape[0], shape[1]])
    +    else:
    +        _logger.error("_get_weight_tensor_transpose_reshape(): Operation type unsupported")
    +
    +    weight_tensor.data = weight.reshape(-1)
    +    weight_tensor.shape = shape
    +
    +    return weight_tensor
    +
    +
    +class PassThroughOp(tf.keras.layers.Layer):
    +    """
    +    This is a pass-through op, used for purpose of making an op a no-op
    +    """
    +
    +    # pylint: disable=arguments-differ
    +    @staticmethod
    +    def call(inputs):
    +        """
    +        This is a function to return input as an output
    +        :param inputs: input to pass through
    +        """
    +        return inputs
    +
    +# pylint: disable=too-many-branches, protected-access, too-many-locals, too-many-nested-blocks
    +@common.to_functional
    +def _delete_bn_from_functional(model: tf.keras.Model,
    +                               bn_layers_to_remove: List[tf.keras.layers.BatchNormalization]) -> tf.keras.Model:
    +    """
    +    This function is used to remove ALL batch normalization layers from a functional model passed via the
    +    bn_layers_to_remove parameter. Removing in place is not possible for functional models as the layers inbound and
    +    outbound connections are immutable. This function returns a new model with the batch normalization layers removed.
    +
    +    :param model: Model to remove bn_layers from
    +    :param bn_layers_to_remove: List of batch normalization layers to remove from the model
    +    :return: A new model with the batch normalization layers removed
    +    """
    +
    +    # In order to do this, we first need to know the original models inbound and outbound connections to each layer.
    +    # We then need to create a new model with the same inbound and outbound connections, but with the batch normalization
    +    # layers removed. This is done by rerouting the inbound nodes of the batch normalization layers to the inbound nodes
    +    # of the next layer. This can be seen in the following diagram:
    +    #
    +    # Original model flow ------------------------->
    +    #   ______________        ______________        ______________
    +    #  |             |       |             |       |             |
    +    #  |    Conv     |  -X-> |  Batch Norm |  -X-> |    ReLU     |
    +    #  |_____________|       |_____________|     ^ |_____________|
    +    #  New model flow   \                       /
    +    #                    \                     /
    +    #                     \___________________/
    +
    +
    +    def wrapped_bn_layer_in_bns_to_remove(layer: tf.keras.layers.Layer) -> bool:
    +        return isinstance(layer, QcQuantizeWrapper) and layer._layer_to_wrap in bn_layers_to_remove
    +
    +    tf.keras.backend.clear_session() # clear session to not have tensor name conflicts
    +
    +    # Step 1: Get the inbound and outbound connections for each layer in the model
    +    model_layer_connections = ModelLayerConnections.get_model_layers_connection_properties(model)
    +
    +    for inp in model.inputs:
    +        model_layer_connections[ModelLayerConnectionsProperties.OUTPUT_TENSORS].update({inp.name: inp})
    +
    +    # Step 2: Create a new model with the batch normalization layers removed by iterating through the layers in the model
    +    # and using the inbound and outbound connections to rerouting around the batch normalization layers.
    +    batch_norms_replaced_with_names = {}
    +    model_outputs = []
    +    for current_layer in model.layers:
    +        if isinstance(current_layer, tf.keras.layers.InputLayer):
    +            continue
    +
    +        # Determine input tensors of the given layer
    +        layer_input = [model_layer_connections[ModelLayerConnectionsProperties.OUTPUT_TENSORS][layer_aux]
    +                       for layer_aux in model_layer_connections[ModelLayerConnectionsProperties.INBOUND_NODES][current_layer.name]]
    +
    +        layer_input = layer_input[0] if len(layer_input) == 1 else layer_input
    +
    +        # Reroute around batch normalization layers if the layer is in the list of layers to remove
    +        if current_layer in bn_layers_to_remove or wrapped_bn_layer_in_bns_to_remove(current_layer):
    +            _logger.debug("Removing Batch Normalization layer %s", current_layer.name)
    +
    +            for outbound_node in current_layer._outbound_nodes:  # pylint: disable=protected-access
    +                # Find and replace the Batch Normalization output layers input that holds the Batch Normalization layer
    +                # node and replace it with the input layers of the Batch Normalization layer.
    +                # For example, if ReLU's inputs are [conv1_bn] and conv1_bn's inputs are [conv1], then we replace
    +                # ReLU's inputs with [conv1]
    +
    +                all_batch_norms_inbound_layers_names = \
    +                    [inbound_node.inbound_layers.name for inbound_node in current_layer._inbound_nodes]
    +
    +                # Go through all the outbound layers of the batch normalization layer and replace the batch normalization
    +                # layer name with the input layer names of the batch normalization layer.
    +                batch_norms_outbound_layers_new_inbound_layers_names = \
    +                    [outlayer.replace(current_layer.name, *all_batch_norms_inbound_layers_names)
    +                     for outlayer in model_layer_connections[ModelLayerConnectionsProperties.INBOUND_NODES][outbound_node.outbound_layer.name]]
    +
    +                # Keras Batch Norm only supports one input tensors. Meaning there is one singular layer coming into it.
    +                # Hence, 'inbound_nodes[0]'.
    +                batch_norms_replaced_with_names[current_layer.name] = current_layer._inbound_nodes[0].inbound_layers.name
    +
    +                model_layer_connections[ModelLayerConnectionsProperties.INBOUND_NODES].update(
    +                    {outbound_node.outbound_layer.name: batch_norms_outbound_layers_new_inbound_layers_names})
    +
    +                # The above updates our dict for the mapping of the inputs, but we need to also update what Keras thinks
    +                # the inputs are. This is done by updating the inbound nodes of the output layer of the Batch Normalization.
    +                # THIS IS ONLY FOR MAPPING THE INPUTS TO BUILD A NEW MODEL. The original models underlying structure is
    +                # not changed.
    +                outbound_node.outbound_layer._inbound_nodes = current_layer.inbound_nodes  # pylint: disable=protected-access
    +
    +        # Otherwise, treat like a normal layer
    +        else:
    +            # For layers that have multiple inputs, order matters for what is fed into the layer. For example, if we have
    +            # an Add layer with inputs from a ReLU and a Batch Norm, the order they go into the Add matters. Furthermore,
    +            # if the Batch Norm is deleted, then it needs to be replaced with it's folded layer in the same order.
    +
    +            KERAS_SYMBOLIC_TENSORS_INDEX = 0
    +            # Check if we need to change layer_input order. If there is just one input, there is no order.
    +            # Special case when there is a Lambda layer with multiple inputs is handled seperately
    +            if isinstance(layer_input, List) and not isinstance(current_layer, TFOpLambda):
    +                # Original models keras symbolic tensor order
    +                original_keras_symbolic_tensors_order = model_layer_connections[ModelLayerConnectionsProperties.CALL_ARGS][
    +                    current_layer.name][KERAS_SYMBOLIC_TENSORS_INDEX]
    +
    +                # Special case for Lambda layers. Lambda layers can be thought of as z = x + y. Unfortunately, their call
    +                # args for the keras symbolic tensors will ONLY have the x portion. In our layer_input we have both x and y.
    +                # This statement is added to wrap the x portion of the original call args and check if it's a batch norm
    +                # folded out.
    +                if not isinstance(original_keras_symbolic_tensors_order, List):
    +                    original_keras_symbolic_tensors_order = [original_keras_symbolic_tensors_order]
    +
    +                # Check if a Batch Norm that was deleted is in the original keras symbolic order.
    +                name_of_bn_replaced = [
    +                    tensor._keras_history.layer.name
    +                    for tensor in original_keras_symbolic_tensors_order
    +                    if tensor._keras_history.layer.name in batch_norms_replaced_with_names
    +                ]
    +
    +                # If a Batch Norm is found, then the keras symbolic tensor order is slightly updated to replace the
    +                # Batch Norm with the folded layer. Otherwise, we can just use the original keras symbolic tensor order.
    +                if name_of_bn_replaced:
    +
    +                    updated_keras_symbolic_tensors_order = []
    +                    for keras_symbolic_tensor in original_keras_symbolic_tensors_order:
    +                        if (name_of_bn := keras_symbolic_tensor._keras_history.layer.name) in name_of_bn_replaced: #pylint: disable=superfluous-parens
    +                            updated_keras_symbolic_tensors_order.append(
    +                                model_layer_connections[ModelLayerConnectionsProperties.OUTPUT_TENSORS][
    +                                    batch_norms_replaced_with_names[name_of_bn]
    +                                ]
    +                            )
    +                        else:
    +                            updated_keras_symbolic_tensors_order.append(keras_symbolic_tensor)
    +
    +                    # Dictionary of the keras symbolic tensor name to the order.
    +                    ordered_inputs = {k.name: v for v, k in enumerate(updated_keras_symbolic_tensors_order)}
    +
    +                    # Sort layer_input based on the above dictionary.
    +                    layer_input = sorted(layer_input, key=lambda current_input, oi=ordered_inputs: oi[current_input.name])
    +
    +            # Since we are rerouting around the batch normalization layers, we need to temporarily remove the inbound
    +            # and outbound nodes of the batch normalization layers so that the model can be built correctly and not
    +            # duplicate the non batch normalization layers inbound/outbound nodes.
    +            current_layer._inbound_nodes = []  # pylint: disable=protected-access
    +            # Special case for when there is a Lambda operation with multiple inputs. For example, z = x + y.
    +            if isinstance(current_layer, TFOpLambda):
    +                kmp = _KerasModelPreparer.get_instance_for_common_layer_passthrough_functions(model_layer_connections)
    +                x = kmp._handle_normal_keras_layer(current_layer)  # pylint: disable=protected-access
    +                # Updating the Model layer connections
    +                kmp._update_output_tensors_in_model_layers_connections(  # pylint: disable=protected-access
    +                    current_layer, x, model
    +                )
    +            else:
    +                x = current_layer(layer_input)
    +            current_layer._outbound_nodes = []  # pylint: disable=protected-access
    +
    +            # Set new output tensor (in this case, it will be the same as the original model)
    +            model_layer_connections[ModelLayerConnectionsProperties.OUTPUT_TENSORS].update({current_layer.name: x})
    +
    +        # Save tensor in output list if it is output in the initial model
    +        if current_layer.name in model.output_names:
    +            model_outputs.append(x)
    +
    +    return tf.keras.Model(inputs=model.inputs, outputs=model_outputs)
    +
    +
    +def _delete_bn_from_sequential(layer: tf.keras.layers.Layer,
    +                               bn: tf.keras.layers.BatchNormalization):
    +
    +    """
    +    This is the function for removing batch normalization layers that are layers of sequential model
    +
    +    :param layer: model to obtain bn_layer that we want to remove
    +    :param bn: batch normalization layer that needs to be removed
    +    """
    +
    +    layers_after_bn = []
    +    visited = False
    +    idx = None
    +    # pylint: disable=protected-access
    +    for index, inner_layer in enumerate(layer.layers):
    +        if visited:
    +            layers_after_bn.append(inner_layer)
    +
    +        elif inner_layer == bn:
    +            visited = True
    +            idx = index
    +
    +        elif inner_layer.submodules:
    +            _delete_bn_for_non_subclassed_model(inner_layer, bn)
    +
    +    if visited and idx is not None:
    +        # pylint: disable=protected-access
    +        for _ in range(len(layer.layers) - idx):
    +            layer.pop()
    +        for layer_to_add in layers_after_bn:
    +            layer.add(layer_to_add)
    +
    +
    +def _delete_bn_for_non_subclassed_model(model: Union[tf.keras.Model, tf.keras.layers.Layer],
    +                                        bn_layer: tf.keras.layers.BatchNormalization):
    +    """
    +    Remove bn layer for those model which are not part of model subclassing
    +
    +    :param model: model to delete bn layers from
    +    :param bn_layer: bn layer that should be removed
    +    """
    +
    +    if isinstance(model, tf.keras.Sequential):
    +        _delete_bn_from_sequential(model, bn_layer)
    +
    +    # We are expecting to find sequential model in functional model
    +    # or model subclassing in the elif statement
    +    elif isinstance(model, (tf.keras.layers.Layer, tf.keras.Model)):
    +        for layer in model.layers:
    +            if layer.submodules:
    +                _delete_bn_for_non_subclassed_model(layer, bn_layer)
    +
    +
    +def _delete_bn_from_model_subclassing(module_to_name_map: Dict[tf.keras.layers.Layer,
    +                                                               Tuple[tf.keras.Model, str]],
    +                                      bn_layer: tf.keras.layers.BatchNormalization):
    +    """
    +    Remove bn layer which is part of model subclassing api
    +    or model inheriting from tf.keras.layers.Layer
    +
    +    :param module_to_name_map: model to remove bn from
    +    :param bn_layer: bn layer that should be removed
    +    """
    +
    +    parent_ref, module_name = module_to_name_map[bn_layer]
    +    op = PassThroughOp()
    +    setattr(parent_ref, module_name, op)
    +
    +# pylint: disable=inconsistent-return-statements
    +def _delete_all_bns_from_model(model: Union[tf.keras.Model, tf.keras.layers.Layer],
    +                               bn_layers: List[tf.keras.layers.BatchNormalization]) -> Optional[tf.keras.Model]:
    +    """
    +    Remove all bn layers for a given model.
    +
    +    :param model: Model to have the bn layers removed from
    +    :param bn_layers: bn layers that should be removed
    +    :return: new model with bn layers removed, if model is functional else None
    +    """
    +    if bn_layers:
    +        # QuantizationSimModel's model will fall into this case.
    +        if isinstance(model, Functional) and not isinstance(model, tf.keras.Sequential) or any(isinstance(l, QcQuantizeWrapper) for l in model.layers):
    +            return _delete_bn_from_functional(model, bn_layers)
    +
    +        module_to_name_map = common.module_to_name_map(model)
    +
    +        for bn_layer in bn_layers:
    +            if bn_layer in module_to_name_map:
    +                _delete_bn_from_model_subclassing(module_to_name_map, bn_layer)
    +            else:
    +                _delete_bn_for_non_subclassed_model(model, bn_layer)
    +
    +
    +def _find_all_batch_norms_to_fold(model: tf.keras.Model) -> Tuple[List[PairType], List[PairType], Set[tf.keras.layers.BatchNormalization]]:
    +    """
    +    uses searcher to choose layers for bias correction
    +
    +    :param model: model to obtain conv_linear pairs for
    +    :return: List of conv/linear layers with associated bn op / activation info and
    +            a Set of all the batch norms which are marked for folding.
    +    """
    +
    +    node_layer_map = common.create_node_to_layer_map(model)
    +    layer_out_node_map = common.create_layer_to_out_node_map(model)
    +
    +    possible_convs_linears_bn = _find_possible_convs_linears_bn(node_layer_map, layer_out_node_map)
    +
    +    # get all ordered convs/ linears layers
    +    ordered_conv_linears = _get_ordered_conv_linears(node_layer_map, layer_out_node_map)
    +
    +    bn_picked_for_folding = set()
    +    def get_pairs(conv_is_first=False) -> List:
    +        index = 1 if conv_is_first else 0
    +
    +        pairs_list = []
    +        for conv_linear in ordered_conv_linears:
    +            if conv_linear in possible_convs_linears_bn and (bn_info := possible_convs_linears_bn[conv_linear]):
    +                if bn_info[index] and bn_info[index] not in bn_picked_for_folding:
    +                    pairs_list.append((conv_linear, bn_info[index]) if conv_is_first else (bn_info[index], conv_linear))
    +                    bn_picked_for_folding.add(bn_info[index])
    +
    +        return pairs_list
    +
    +    conv_bn_pairs = get_pairs(conv_is_first=True)
    +    bn_conv_pairs = get_pairs(conv_is_first=False)
    +
    +    return conv_bn_pairs, bn_conv_pairs, bn_picked_for_folding
    +
    +
    +
    +[docs] +def fold_all_batch_norms(model: tf.keras.Model) \ + -> Tuple[List[Tuple[LayerType, BatchNormType]], tf.keras.Model]: + """ + Fold all batch_norm layers in a model into corresponding conv/linear layers + + :param model: model to find all batch norms for + + :return: A tuple of List of conv/linear layers with associated bn op / activation info + and a new model with the Batch Normalization layers folded + """ + + conv_bn_pairs, bn_conv_pairs, folded_bns = _find_all_batch_norms_to_fold(model) + + # Potential new model is returned in case the model is a functional model + potential_new_model = _fold_given_batch_norms(model, conv_bn_pairs, bn_conv_pairs) + model = potential_new_model if potential_new_model else model + + # Convert the standalone BNs which are not folded + bn_converted = convert_standalone_batchnorms(model, folded_bns) + if bn_converted: + _logger.info("%d BatchNorms' weights got converted", len(bn_converted)) + model.compile() + _logger.warning("A new model is returned with the Batch Normalization layers removed for Keras models. " + "Please use this new model for the rest of the AIMET flow.") + + return conv_bn_pairs + [(conv, bn) for bn, conv in bn_conv_pairs], model
    + + + +def convert_standalone_batchnorms(model: tf.keras.Model, folded_bns: set) -> List[tf.keras.layers.BatchNormalization]: + """ + Converts the weights of standalone batch norms remaining in the model after BN folding + :param model: keras model on which batch norm folding is being performed + :param folded_bns: list of batch norms which got folded + :return: list of BatchNorms whose weights is converted + """ + + bn_converted = [] + for layer in model.layers: + if isinstance(layer, tf.keras.layers.BatchNormalization) and layer not in folded_bns: + convert_batchnorm_parameters(layer) + _logger.debug("%s weights got converted", layer.name) + bn_converted.append(layer) + return bn_converted + + +def convert_batchnorm_parameters(bn: tf.keras.layers.BatchNormalization): + """ + Convert the weights of BN such that it works as y = weights * x + bias + :param bn: Batch Norm layer whose weights need to be converted + """ + bn_params = _get_bn_params(bn) + + # inv :: 1/ Sqrt(var + eps) + inv = tf.math.rsqrt(bn.moving_variance.numpy() + bn.epsilon) + weight = np.array(bn_params.gamma) * np.array(inv) + bias = np.array(bn_params.beta) - np.array(bn_params.runningMean) * weight + + new_bn_weights = [weight.data, bias.data, + np.zeros(shape=bn.moving_mean.shape, dtype=np.float32), + np.ones(shape=bn.moving_variance.shape, dtype=np.float32)] + bn.trainable = False + bn.set_weights(new_bn_weights) + bn.epsilon = 0 + + +# pylint: disable=protected-access +
    +[docs] +def fold_all_batch_norms_to_scale(sim: QuantizationSimModel) -> List[Tuple[QcQuantizeWrapper, QcQuantizeWrapper]]: + """ + Fold all batch_norm layers in a model into the quantization scale parameter + of the corresponding conv layers + + :param sim: QuantizationSimModel to be folded + :return: A list of pairs of layers [(Conv/Linear, BN layer that got folded)] + """ + + assert sim.model is not None, "QuantizationSimModel attribute 'model' is None." + + model = sim._model_without_wrappers + + quant_wrappers = { + quant_wrapper._layer_to_wrap: quant_wrapper + for quant_wrapper in sim.quant_wrappers() + } + + conv_bn_pairs, bn_conv_pairs, _ = _find_all_batch_norms_to_fold(model) + conv_bn_pairs = [ + (quant_wrappers[conv], quant_wrappers[bn]) for conv, bn in conv_bn_pairs + ] + bn_conv_pairs = [ + (quant_wrappers[bn], quant_wrappers[conv]) for bn, conv in bn_conv_pairs + ] + + old_model_without_wrappers = tf.keras.models.clone_model(model) + conv_bn_pairs_without_wrappers, _, _ = _find_all_batch_norms_to_fold(old_model_without_wrappers) + old_model_without_wrappers.set_weights(WeightTensorUtils.get_all_sim_models_layer_to_wrap_weights(sim.model)) + + # We fold both the sim.model and sim._model_without_wrappers because we rebuild the QuantizationSimModel during + # export and this utilizes the sim._model_without_wrappers to achieve this. + bn_fold_sim_model = _fold_given_batch_norms(sim.model, conv_bn_pairs, bn_conv_pairs) + sim.model = bn_fold_sim_model if bn_fold_sim_model else sim.model + + bn_fold_model = _fold_given_batch_norms(old_model_without_wrappers, conv_bn_pairs_without_wrappers, []) + sim._model_without_wrappers = bn_fold_model if bn_fold_model else old_model_without_wrappers + + return conv_bn_pairs + [(conv, bn) for bn, conv in bn_conv_pairs]
    + + +def fold_given_batch_norms(model: tf.keras.Model, layer_pairs: List[PairType]) -> Optional[tf.keras.Model]: + """ + Fold a given set of batch_norm layers into conv_linear layers + + :param model: Either a Keras Model or a QuantizationSimModel's model + :param layer_pairs: Tuple of conv, bn layers and is_batch_norm_second flag + :return: new model with batch norm layers folded if model is a functional model, else None + """ + # pylint: disable=protected-access + conv_bn_paris = [] + bn_conv_pairs = [] + + def is_batchnorm(layer: tf.keras.layers.Layer) -> bool: + if isinstance(layer, QcQuantizeWrapper): + layer = layer._layer_to_wrap + return isinstance(layer, _supported_batchnorms) + + def is_conv_linear(layer: tf.keras.layers.Layer) -> bool: + if isinstance(layer, QcQuantizeWrapper): + layer = layer._layer_to_wrap + return isinstance(layer, _supported_layers) + + for x, y in layer_pairs: + if is_batchnorm(x): + assert is_conv_linear(y) + bn = x + conv = y + bn_conv_pairs.append((bn, conv)) + else: + assert is_conv_linear(x) + assert is_batchnorm(y) + conv = x + bn = y + conv_bn_paris.append((conv, bn)) + + return _fold_given_batch_norms(model, conv_bn_paris, bn_conv_pairs) + +def _fold_given_batch_norms(model: tf.keras.Model, + conv_bn_pairs: Iterable[Tuple[tf.keras.layers.Layer, tf.keras.layers.Layer]], + bn_conv_pairs: Iterable[Tuple[tf.keras.layers.Layer, tf.keras.layers.Layer]]) -> \ + Optional[tf.keras.Model]: + """ + Fold a given set of batch_norm layers into conv layers + + :param model: Model + :param conv_bn_pairs: List of (conv, bn) pairs to fold + :param bn_conv_pairs: List of (bn, conv) pairs to fold + """ + for bn, conv in bn_conv_pairs: + if isinstance(conv, QcQuantizeWrapper): + raise RuntimeError(f"Forward folding to scale is not possible. Got {conv.name}") + + bn_layers = [] + + def _fold(conv, bn, fold_backward): + is_wrapped = isinstance(conv, QcQuantizeWrapper) or isinstance(bn, QcQuantizeWrapper) + try: + if is_wrapped: + assert isinstance(conv, QcQuantizeWrapper) and isinstance(bn, QcQuantizeWrapper) + bn._layer_to_wrap.trainable = False + _fold_to_scale(conv, bn) + bn_layers.append(bn._layer_to_wrap) + else: + bn.trainable = False + _fold_to_weight(conv, bn, fold_backward=fold_backward) + except _BatchNormFoldingNotSupported as e: + bn_name = bn._layer_to_wrap.name if is_wrapped else bn.name + conv_name = conv._layer_to_wrap.name if is_wrapped else conv.name + _logger.warning( + "Failed to fold %s to %s. [Reason] %s", bn_name, conv_name, str(e) + ) + else: + bn_layers.append(bn._layer_to_wrap if is_wrapped else bn) + + for conv, bn in conv_bn_pairs: + _fold(conv, bn, fold_backward=True) + + for bn, conv in bn_conv_pairs: + _fold(conv, bn, fold_backward=False) + + return _delete_all_bns_from_model(model, bn_layers) + +class _BatchNormFoldingNotSupported(RuntimeError): + pass + +def _fold_to_scale(conv_wrapper: QcQuantizeWrapper, bn_wrapper: QcQuantizeWrapper): + """ + Fold BatchNorm into the scale and bias of the given layer. + + :param conv_wrapper: QcQuantizeWrapper that wraps conv or linear layer + :param bn_wrapper: QcQuantizeWrapper that wraps the Batch Norm layer + """ + # pylint: disable=protected-access, too-many-statements, too-many-locals + conv = conv_wrapper._layer_to_wrap + bn = bn_wrapper._layer_to_wrap + + weight_quantizer = get_wrappers_weight_quantizer(conv_wrapper.param_quantizers) + bias_quantizer = get_wrappers_bias_quantizer(conv_wrapper.param_quantizers) + + # Checking QuantScheme as aimet_tensorflow.keras does not have LearnedGridTensorQuantizer + if weight_quantizer.quant_scheme not in [QuantScheme.training_range_learning_with_tf_init, + QuantScheme.training_range_learning_with_tf_enhanced_init]: + raise _BatchNormFoldingNotSupported( + "BatchNorm folding to scale supports training_range_learning_with_tf_init or " + "training_range_learning_with_tf_enhanced_init only. " + f"got {weight_quantizer.quant_scheme}" + ) + + output_quantizer = conv_wrapper.output_quantizers[0] + + if output_quantizer.is_enabled(): + raise _BatchNormFoldingNotSupported( + "BatchNorm should belong to the same supergroup with the layer to be folded to." + ) + + if bias_quantizer: + if bias_quantizer.is_enabled(): + raise _BatchNormFoldingNotSupported( + "Can't fold BatchNorm to scale if bias quantizer is enabled." + ) + + enc_min = weight_quantizer._encoding_min + enc_max = weight_quantizer._encoding_max + + if not weight_quantizer.is_encoding_valid(): + raise RuntimeError + + with bn_wrapper._quantize_params(): + _fold_to_weight(conv, bn, fold_backward=True) + + gamma = bn.gamma + sigma = K.sqrt(bn.moving_variance + bn.epsilon) + + for i, c in enumerate(gamma/sigma): + c = float(c) + if c >= 0: + enc_max[i].assign(enc_max[i] * c) + enc_min[i].assign(enc_min[i] * c) + else: + enc_max_before_reassign = enc_max[i] + enc_max[i].assign(enc_min[i] * c) + enc_min[i].assign(enc_max_before_reassign * c) + + + # Copy batchnorm's output quantizers to conv output quantizers + for conv_output_quantizer, bn_output_quantizer in \ + zip(conv_wrapper.output_quantizers, bn_wrapper.output_quantizers): + if bn_output_quantizer.encoding is not None: + conv_output_quantizer._encoding_min.assign(bn_output_quantizer._encoding_min) + conv_output_quantizer._encoding_max.assign(bn_output_quantizer._encoding_max) + conv_output_quantizer._is_encoding_valid = True + + tensor_quantizers = conv_output_quantizer._tensor_quantizer if isinstance(conv_output_quantizer._tensor_quantizer, List) else [conv_output_quantizer._tensor_quantizer] + for tensor_quantizer in tensor_quantizers: + tensor_quantizer.isEncodingValid = True + + if bn_output_quantizer.is_enabled(): + conv_output_quantizer.enable() + else: + conv_output_quantizer.disable() + + + + bn_output_quantizer.disable() + + if bias_quantizer is None: + bias_quantizer = ParamPerTensorQuantizer(conv, + conv.bias.name.split(':')[0], + weight_quantizer.quant_scheme, + MAP_PYMO_TO_ROUND_MODE[weight_quantizer.round_mode], + weight_quantizer.bitwidth, + weight_quantizer.data_type, + weight_quantizer.is_symmetric, + weight_quantizer.use_strict_symmetric, + weight_quantizer.use_unsigned_symmetric, + enabled=False) + tensor_quantizers = bias_quantizer._tensor_quantizer if isinstance(bias_quantizer._tensor_quantizer, List) else [bias_quantizer._tensor_quantizer] + for tensor_quantizer in tensor_quantizers: + tensor_quantizer.isEncodingValid = True + conv_wrapper.param_quantizers.append(bias_quantizer) + + +def _fold_to_weight(conv_linear: LayerType, bn: BatchNormType, fold_backward: bool): + """ + Fold BatchNorm into the weight and bias of the given layer. + + :param conv_linear: Conv or linear layer to fold BN into. + :param bn: BatchNorm to fold. + :param fold_backward: To fold backwards or not + """ + + is_bias_valid = conv_linear.bias is not None + + bn_params = _get_bn_params(bn) + weight_tensor = _get_weight_tensor_transpose_reshape(conv_linear) + bias_tensor = _get_bias_tensor(conv_linear) + + # Updated weight and bias + bias = libpymo.fold(bn_params, weight_tensor, bias_tensor, is_bias_valid, fold_backward) + + if isinstance(conv_linear, tf.keras.layers.DepthwiseConv2D): + # Depthwise conv layers in TF have outputs(Noc) set to 1. + # we send in format [Nic, Noc, kh, kw] + numpy_weight_reshaped = np.reshape(weight_tensor.data, weight_tensor.shape).transpose((2, 3, 0, 1)) + + elif isinstance(conv_linear, tf.keras.layers.Dense): + # o, i - convert to i , o + numpy_weight_reshaped = np.reshape( + weight_tensor.data, + [weight_tensor.shape[0], weight_tensor.shape[1]]).transpose(1, 0) + + elif isinstance(conv_linear, tf.keras.layers.Conv2DTranspose): + # we sent in format [Noc, Nic, kh, kw] + numpy_weight_reshaped = np.reshape(weight_tensor.data, weight_tensor.shape).transpose((2, 3, 0, 1)) + + else: + # conv2D case + # we sent in format [Noc, Nic, kh, kw] + numpy_weight_reshaped = np.reshape(weight_tensor.data, weight_tensor.shape).transpose((2, 3, 1, 0)) + + # update bias tensor, even in case there was no existing bias add op in given conv2D op. + bias_tensor_shape = [weight_tensor.shape[0]] + numpy_bias_reshaped = np.reshape(bias, bias_tensor_shape) + + if not is_bias_valid: + conv_linear.use_bias = True + conv_linear.bias = conv_linear.add_weight(name=f"{conv_linear.name}/bias", + shape=(weight_tensor.shape[0],), + dtype=conv_linear.dtype, + trainable=True) + conv_linear.set_weights([numpy_weight_reshaped.data, numpy_bias_reshaped]) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_tensorflow/keras/bn_reestimation.html b/releases/2.0.0/_modules/aimet_tensorflow/keras/bn_reestimation.html new file mode 100644 index 0000000..8307a0c --- /dev/null +++ b/releases/2.0.0/_modules/aimet_tensorflow/keras/bn_reestimation.html @@ -0,0 +1,463 @@ + + + + + + + + aimet_tensorflow.keras.bn_reestimation - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_tensorflow.keras.bn_reestimation

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +"""BatchNorm Reestimation"""
    +from typing import List, Dict
    +import numpy as np
    +import tensorflow as tf
    +from aimet_common.utils import Handle, AimetLogger
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.Utils)
    +
    +def _get_bn_submodules(model: tf.keras.Model) -> List[tf.keras.layers.Layer]:
    +    bn_layers = []
    +    for layer in model.submodules:
    +        if isinstance(layer, tf.keras.layers.BatchNormalization):
    +            bn_layers.append(layer)
    +    return bn_layers
    +
    +
    +def _reset_bn_stats(bn_layers: List[tf.keras.layers.Layer], bn_mean_checkpoints: Dict, bn_var_checkpoints: Dict, bn_momentum_checkpoints: Dict) -> Handle:
    +    """
    +    reset bn stats
    +    :param bn_layers: keras bn_layers
    +    :param bn_mean_checkpoints: Dict for original bn mean
    +    :param bn_var_checkpoints: Dict for original bn var
    +    :param bn_momentum_checkpoints: Dict for original bn momentum
    +    :return:
    +    """
    +
    +    def cleanup():
    +        """
    +        Restore Bn stats
    +        """
    +        for layer in bn_layers:
    +            move_mean = bn_mean_checkpoints[layer.name]
    +            move_var = bn_var_checkpoints[layer.name]
    +            gamma, beta, _, _ = layer.get_weights()
    +            layer.set_weights([gamma, beta, move_mean, move_var])
    +            layer.momentum = bn_momentum_checkpoints[layer.name]
    +
    +    try:
    +        for layer in bn_layers:
    +            layer.momentum = 0.0
    +        return Handle(cleanup)
    +    except:
    +        cleanup()
    +        raise ValueError('exception for reset_bn_stats')  # pylint: disable=raise-missing-from
    +
    +# pylint: disable=too-many-locals
    +
    +[docs] +def reestimate_bn_stats(model: tf.keras.Model, bn_re_estimation_dataset: tf.data.Dataset, + bn_num_batches: int = 100) -> Handle: + """ + + top level api for end user directly call + + :param model: tf.keras.Model + :param bn_re_estimation_dataset: Training dataset + :param bn_num_batches: The number of batches to be used for reestimation + :returns: Handle that undos the effect of BN reestimation upon handle.remove() + """ + + bn_layers = _get_bn_submodules(model) + + # save checkpoints + bn_mean_ori = {layer.name: layer.moving_mean.numpy() for layer in bn_layers} + bn_var_ori = {layer.name: layer.moving_variance.numpy() for layer in bn_layers} + bn_momentum_ori = {layer.name: layer.momentum for layer in bn_layers} + # 1. switch to re-estimation mode and setup remove + handle = _reset_bn_stats(bn_layers, bn_mean_ori, bn_var_ori, bn_momentum_ori) + + # 2. mean &var initialization + mean_sum_dict = {layer.name: np.zeros(layer.moving_mean.shape, dtype=layer.moving_mean.dtype.as_numpy_dtype) for layer in bn_layers} + var_sum_dict = {layer.name: np.zeros(layer.moving_variance.shape, dtype=layer.moving_variance.dtype.as_numpy_dtype) for layer in bn_layers} + + # 3 per batch forward for BN re-estimation, accumulate into mean&var buffers + bn_dataset_iterator = iter(bn_re_estimation_dataset) + for batch_index in range(bn_num_batches): + try: + batch_data = next(bn_dataset_iterator) + model(batch_data, training=True) + for layer in bn_layers: + mean_sum_dict[layer.name] += layer.moving_mean.numpy() + var_sum_dict[layer.name] += layer.moving_variance.numpy() + if batch_index == bn_num_batches - 1: + break + except tf.errors.OutOfRangeError: + logger.info("tf.errors.OutOfRangeError:: End of dataset.") + break + + # 4 average mean&var buffers, Override BN stats with the reestimated stats + for layer in bn_layers: + move_mean = mean_sum_dict[layer.name]/bn_num_batches + move_var = var_sum_dict[layer.name]/bn_num_batches + gamma, beta, _, _ = layer.get_weights() + layer.set_weights([gamma, beta, move_mean, move_var]) + + return handle
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_tensorflow/keras/compress.html b/releases/2.0.0/_modules/aimet_tensorflow/keras/compress.html new file mode 100644 index 0000000..969230d --- /dev/null +++ b/releases/2.0.0/_modules/aimet_tensorflow/keras/compress.html @@ -0,0 +1,445 @@ + + + + + + + + aimet_tensorflow.keras.compress - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_tensorflow.keras.compress

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Top-level API for aimet compression library """
    +
    +from typing import Union, Tuple, Callable
    +import tensorflow as tf
    +
    +from aimet_common.defs import CostMetric, CompressionScheme, EvalFunction, CompressionStats
    +from aimet_common.bokeh_plots import BokehServerSession
    +
    +from aimet_tensorflow.keras.utils.graph_saver import keras_wrapper_func, keras_save_and_load_graph, keras_remove_hanging_nodes
    +from aimet_tensorflow.keras.defs import SpatialSvdParameters
    +from aimet_tensorflow.keras.compression_factory import CompressionFactory
    +
    +
    +
    +[docs] +class ModelCompressor: + """ aimet model compressor: Enables model compression using various schemes """ + + # pylint: disable=too-many-arguments + +
    +[docs] + @staticmethod + def compress_model(model: tf.keras.Model, eval_callback: EvalFunction, eval_iterations, + compress_scheme: CompressionScheme, cost_metric: CostMetric, + parameters: Union[SpatialSvdParameters], + trainer: Callable = None, visualization_url: str = None) -> Tuple[tf.keras.Model, CompressionStats]: + """ + Compress a given model using the specified parameters + + :param model: Model, represented by a tf.keras.Model, to compress + :param eval_callback: Evaluation callback. Expected signature is evaluate(model, iterations, use_cuda). + Expected to return an accuracy metric. + :param eval_iterations: Iterations to run evaluation for. + :param compress_scheme: Compression scheme. See the enum for allowed values + :param cost_metric: Cost metric to use for the compression-ratio (either mac or memory) + :param parameters: Compression parameters specific to given compression scheme + :param trainer: Training function + None: If per layer fine-tuning is not required while creating the final compressed model + :param visualization_url: url the user will need to input where visualizations will appear + :return: A tuple of the compressed model session, and compression statistics + """ + + # If no url is passed in, then do not create a bokeh server session + if not visualization_url: + bokeh_session = None + else: + # create a bokeh session to publish visualizations to the server document for compression + bokeh_session = BokehServerSession(url=visualization_url, session_id="compression") + + if parameters.multiplicity < 1: + raise ValueError('Rounding Multiplicity should be greater than 1') + + # wrapper_func saves and reloads the graph before evaluation + # In Keras after making changes to the graph you must save and reload, then evaluate + eval_callback = keras_wrapper_func(eval_callback) + + if compress_scheme == CompressionScheme.spatial_svd: + algo = CompressionFactory.create_spatial_svd_algo(model, eval_callback, eval_iterations, + cost_metric, parameters, bokeh_session) + elif compress_scheme == CompressionScheme.weight_svd: + raise NotImplementedError("Not yet implemented for: {}".format(compress_scheme)) + elif compress_scheme == CompressionScheme.channel_pruning: + raise NotImplementedError("Not yet implemented for: {}".format(compress_scheme)) + else: + raise ValueError("Compression scheme not supported: {}".format(compress_scheme)) + + compressed_layer_db, stats = algo.compress_model(cost_metric, trainer) + + # In keras after making changes to the model you must save and reload, then evaluate + tmp_dir = './data/saved_model' + updated_model = keras_save_and_load_graph(tmp_dir, compressed_layer_db.model) + + # Remove the hanging nodes + updated_model = keras_remove_hanging_nodes(updated_model) + + return updated_model, stats
    +
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_tensorflow/keras/cross_layer_equalization.html b/releases/2.0.0/_modules/aimet_tensorflow/keras/cross_layer_equalization.html new file mode 100644 index 0000000..3b2a3a2 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_tensorflow/keras/cross_layer_equalization.html @@ -0,0 +1,828 @@ + + + + + + + + aimet_tensorflow.keras.cross_layer_equalization - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_tensorflow.keras.cross_layer_equalization

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +"""Cross Layer Equalization"""
    +
    +import typing
    +
    +import numpy as np
    +import tensorflow as tf
    +
    +import aimet_common.libpymo as libpymo
    +from aimet_common.utils import AimetLogger
    +from aimet_tensorflow.keras.batch_norm_fold import fold_all_batch_norms
    +from aimet_tensorflow.keras.graphsearchtuils import GraphSearchUtils, ClsSet
    +from aimet_tensorflow.keras.utils import model_transform_utils
    +from aimet_tensorflow.keras.utils.weight_tensor_utils import WeightTensorUtils
    +
    +_logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.CrosslayerEqualization)
    +
    +BatchNormFoldedPair = typing.Union[typing.Tuple[tf.keras.layers.Conv2D,
    +                                                tf.keras.layers.BatchNormalization],
    +                                   typing.Tuple[tf.keras.layers.Dense,
    +                                                tf.keras.layers.BatchNormalization]]
    +
    +ScaleFactor = typing.Union[np.ndarray, typing.Tuple[np.ndarray, np.ndarray]]
    +ReluFlag = typing.Union[bool, typing.Tuple[bool, bool]]
    +
    +Convs = typing.Union[tf.keras.layers.Conv2D,
    +                     tf.keras.layers.DepthwiseConv2D,
    +                     tf.keras.layers.Conv2DTranspose]
    +
    +_supported_convs = Convs.__args__
    +
    +class ClsSetInfo:
    +    """
    +    This class hold information about the layers in a CLS set, along with corresponding scaling factors
    +    and other information like if there is a ReLU activation function between the CLS set layers
    +    """
    +
    +    class ClsSetLayerPairInfo:
    +        """
    +        Models a pair of layers that were scaled using CLS. And related information.
    +        """
    +
    +        def __init__(self, layer1: tf.keras.layers.Conv2D, layer2: tf.keras.layers.Conv2D, scale_factor: np.ndarray,
    +                     relu_activation_between_layers: bool):
    +            """
    +            :param layer1: Layer whose bias is folded
    +            :param layer2: Layer to which bias of previous layer's bias is folded
    +            :param scale_factor: Scale Factor found from Cross Layer Scaling to scale BN parameters
    +            :param relu_activation_between_layers: If the activation between layer1 and layer2 is Relu
    +            """
    +            self.layer1 = layer1
    +            self.layer2 = layer2
    +            self.scale_factor = scale_factor
    +            self.relu_activation_between_layers = relu_activation_between_layers
    +
    +        def __eq__(self, other):
    +            if isinstance(self, other.__class__):
    +                return self.layer1 == other.layer1 and \
    +                       self.layer2 == other.layer2 and \
    +                       np.allclose(self.scale_factor, other.scale_factor) and \
    +                       self.relu_activation_between_layers == other.relu_activation_between_layers
    +            return False
    +
    +    def __init__(self, cls_pair_1: ClsSetLayerPairInfo, cls_pair_2: ClsSetLayerPairInfo = None):
    +        """
    +        Constructor takes 2 pairs if Depth-wise separable layer is being folded
    +        :param cls_pair_1: Pair between two conv or conv and depth-wise conv
    +        :param cls_pair_2: Pair between depth-wise conv and point-wise conv
    +        """
    +        if cls_pair_2:
    +            self.cls_pair_info_list = [cls_pair_1, cls_pair_2]
    +        else:
    +            self.cls_pair_info_list = [cls_pair_1]
    +
    +    def __eq__(self, other):
    +        if isinstance(self, other.__class__):
    +            return self.cls_pair_info_list == other.cls_pair_info_list
    +
    +        return False
    +
    +class CrossLayerScaling:
    +    """
    +    Code to apply the cross-layer-scaling technique to a model
    +    """
    +
    +    @staticmethod
    +    def scale_cls_set_with_conv_layers(
    +            cls_set: typing.Tuple[tf.keras.layers.Conv2D, tf.keras.layers.Conv2D]) -> np.ndarray:
    +        """
    +        API to invoke equalize layer params (update for weights and bias is in place)
    +        :param cls_set: Consecutive Conv layers Tuple whose weights and biases need to be equalized
    +        :return: Scaling factor S_12 for each conv layer pair: numpy array
    +        """
    +
    +        for layer in cls_set:
    +            # NOTE: DepthwiseConv2D and Conv2DTranspose is subclass of Conv2D
    +            #   The check below covers all of Conv2D, DepthwiseConv2D and Conv2DTranspose class
    +            if not isinstance(layer, tf.keras.layers.Conv2D):
    +                raise ValueError("Only Conv or Transposed Conv layers are supported for CLE")
    +
    +        scaling_factor, prev_layer_params, curr_layer_params = CrossLayerScaling.call_mo_scale(cls_set)
    +
    +        prev_layer, curr_layer = cls_set
    +        weight_and_bias_0 = CrossLayerScaling._unpack_equalization_params(prev_layer, prev_layer_params,
    +                                                                          unpack_bias=True)
    +        prev_layer.set_weights(weight_and_bias_0)
    +
    +        weight_and_bias_1 = CrossLayerScaling._unpack_equalization_params(curr_layer, curr_layer_params,
    +                                                                          unpack_bias=False)
    +        curr_layer.set_weights(weight_and_bias_1)
    +
    +        return scaling_factor
    +
    +    @staticmethod
    +    def call_mo_scale(cls_set: typing.Tuple[tf.keras.layers.Conv2D, tf.keras.layers.Conv2D]) \
    +            -> typing.Tuple[np.ndarray, libpymo.EqualizationParams, libpymo.EqualizationParams]:
    +        """
    +        Invokes scale API in model optimization library
    +        :param cls_set: Consecutive Conv layers Tuple whose weights and biases need to be equalized
    +        :return: Scaling factor, prev and current layer updated parameters
    +        """
    +        prev_layer_params = CrossLayerScaling._pack_equalization_params(cls_set[0], pack_bias=True)
    +        curr_layer_params = CrossLayerScaling._pack_equalization_params(cls_set[1], pack_bias=False)
    +
    +        scaling_factor = libpymo.scaleLayerParams(prev_layer_params, curr_layer_params)
    +        return scaling_factor, prev_layer_params, curr_layer_params
    +
    +    @staticmethod
    +    def scale_cls_set_with_depthwise_conv_layers(
    +            cls_set: typing.Tuple[tf.keras.layers.Conv2D,
    +                                  tf.keras.layers.DepthwiseConv2D,
    +                                  tf.keras.layers.Conv2D]) -> typing.Tuple[np.ndarray, np.ndarray]:
    +        """
    +        API to invoke equalize layer params (update for weights and bias is in place)
    +        :param cls_set: Consecutive Conv layers whose weights and biases need to be equalized.
    +                        Second Conv layer is a depth-wise conv and third conv layer is point-wise conv
    +        :return: Scaling factors S_12 and S_23 : numpy arrays
    +        """
    +
    +        for layer in cls_set:
    +            if not isinstance(layer, _supported_convs):
    +                raise ValueError("Only Conv or Transposed Conv layers are supported for CLE")
    +
    +        scaling_params, prev_layer_params, curr_layer_params, next_layer_params = \
    +            CrossLayerScaling.call_mo_scale_depthwise_separable_layer(cls_set)
    +
    +        prev_layer, curr_layer, next_layer = cls_set
    +        weight_and_bias_0 = CrossLayerScaling._unpack_equalization_params(prev_layer,
    +                                                                          prev_layer_params,
    +                                                                          unpack_bias=True)
    +        prev_layer.set_weights(weight_and_bias_0)
    +
    +        weight_and_bias_1 = CrossLayerScaling._unpack_equalization_params(curr_layer,
    +                                                                          curr_layer_params,
    +                                                                          unpack_bias=True)
    +        curr_layer.set_weights(weight_and_bias_1)
    +
    +        weight_and_bias_2 = CrossLayerScaling._unpack_equalization_params(next_layer,
    +                                                                          next_layer_params,
    +                                                                          unpack_bias=False)
    +        next_layer.set_weights(weight_and_bias_2)
    +
    +        return scaling_params.scalingMatrix12, scaling_params.scalingMatrix23
    +
    +    @staticmethod
    +    def call_mo_scale_depthwise_separable_layer(
    +            cls_set: typing.Tuple[tf.keras.layers.Conv2D,
    +                                  tf.keras.layers.DepthwiseConv2D,
    +                                  tf.keras.layers.Conv2D]) -> typing.Tuple[libpymo.RescalingParamsVectors,
    +                                                                           libpymo.EqualizationParams,
    +                                                                           libpymo.EqualizationParams,
    +                                                                           libpymo.EqualizationParams]:
    +        """
    +        Invokes scale API in model optimization library
    +        :param cls_set: Consecutive Conv layers whose weights and biases need to be equalized
    +        :return: Scaling factors, prev, current and next layer updated parameters
    +        """
    +
    +        prev_layer_params = CrossLayerScaling._pack_equalization_params(cls_set[0], pack_bias=True)
    +        curr_layer_params = CrossLayerScaling._pack_equalization_params(cls_set[1], pack_bias=True)
    +        next_layer_params = CrossLayerScaling._pack_equalization_params(cls_set[2], pack_bias=False)
    +
    +        scaling_params = libpymo.scaleDepthWiseSeparableLayer(prev_layer_params, curr_layer_params, next_layer_params)
    +        return scaling_params, prev_layer_params, curr_layer_params, next_layer_params
    +
    +    @staticmethod
    +    def _pack_equalization_params(layer: tf.keras.layers.Conv2D, pack_bias: bool) -> libpymo.EqualizationParams:
    +        equalization_params = libpymo.EqualizationParams()
    +
    +        param_tensors = layer.get_weights()
    +
    +        weight_tensor = param_tensors[0]
    +        weight_tensor = WeightTensorUtils.transpose_from_tf_to_libpymo_format(weight_tensor, layer)
    +
    +        equalization_params.weight = weight_tensor.reshape(-1)
    +        equalization_params.weightShape = np.array(weight_tensor.shape)
    +
    +        if pack_bias:
    +            if layer.use_bias:
    +                equalization_params.bias = param_tensors[1]
    +            else:
    +                equalization_params.isBiasNone = True
    +
    +        return equalization_params
    +
    +    @staticmethod
    +    def _unpack_equalization_params(layer: tf.keras.layers.Conv2D,
    +                                    equalization_params: libpymo.EqualizationParams,
    +                                    unpack_bias: bool) -> typing.List:
    +
    +        weight_tensor = np.reshape(equalization_params.weight, equalization_params.weightShape)
    +        weight_tensor = WeightTensorUtils.transpose_from_libpymo_to_tf_format(weight_tensor, layer)
    +
    +        if layer.use_bias:
    +            if unpack_bias:
    +                bias_tensor = np.reshape(equalization_params.bias, equalization_params.weightShape[0])
    +            else:
    +                _, bias_tensor = layer.get_weights()
    +
    +            param_tensors = [weight_tensor, bias_tensor]
    +        else:
    +            param_tensors = [weight_tensor]
    +
    +        return param_tensors
    +
    +    @staticmethod
    +    def scale_cls_sets(cls_sets: typing.List[ClsSet]) -> \
    +            typing.List[typing.Union[np.ndarray, typing.Tuple[np.ndarray, np.ndarray]]]:
    +        """
    +        Scale each cls set
    +        :param cls_sets: Cls sets to scale
    +        :return: List of scale factors corresponding to each scaled cls set
    +        """
    +        scale_factor_list = []
    +        for cls_set in cls_sets:
    +            if len(cls_set) == 3:
    +                scale_factor = CrossLayerScaling.scale_cls_set_with_depthwise_conv_layers(cls_set)
    +            else:
    +                scale_factor = CrossLayerScaling.scale_cls_set_with_conv_layers(cls_set)
    +            scale_factor_list.append(scale_factor)
    +        return scale_factor_list
    +
    +    @staticmethod
    +    def create_cls_set_info_list(cls_sets: typing.List[ClsSet],
    +                                 scale_factors: typing.List[ScaleFactor],
    +                                 is_relu_activation_in_cls_sets: typing.List[ReluFlag]) -> typing.List[ClsSetInfo]:
    +        """
    +        Binds information from there separate lists into one [ClsInfoSet] data structure
    +        :param cls_sets: List of CLS sets
    +        :param scale_factors: List of scale factors for each cls set
    +        :param is_relu_activation_in_cls_sets: List of ReLU flag whether there is ReLU activation in each cls set
    +        :return: List of ClsSetInfo
    +        """
    +        assert len(cls_sets) == len(scale_factors) == len(is_relu_activation_in_cls_sets)
    +
    +        cls_set_info_list = []
    +        for cls_set, scale_factor, has_relu_activation in zip(cls_sets,
    +                                                              scale_factors,
    +                                                              is_relu_activation_in_cls_sets):
    +            # Depthwise separable convolution layer case (triplet of layers)
    +            # Should have two scale factors and ReLU flags
    +            if isinstance(scale_factor, tuple):
    +                assert len(cls_set) == 3
    +                assert len(scale_factor) == len(has_relu_activation) == 2
    +
    +                prev_layer, curr_layer, next_layer = cls_set
    +                cls_pair_1 = ClsSetInfo.ClsSetLayerPairInfo(prev_layer, curr_layer,
    +                                                            scale_factor[0], has_relu_activation[0])
    +                cls_pair_2 = ClsSetInfo.ClsSetLayerPairInfo(curr_layer, next_layer,
    +                                                            scale_factor[1], has_relu_activation[1])
    +                cls_set_info = ClsSetInfo(cls_pair_1, cls_pair_2)
    +
    +            # Standard convolution layer case (tuple of layers)
    +            # Should have one scale factor and ReLU flag
    +            else:
    +                prev_layer, curr_layer = cls_set
    +                cls_pair = ClsSetInfo.ClsSetLayerPairInfo(prev_layer, curr_layer,
    +                                                          scale_factor, has_relu_activation)
    +                cls_set_info = ClsSetInfo(cls_pair)
    +
    +            cls_set_info_list.append(cls_set_info)
    +
    +        return cls_set_info_list
    +
    +    @staticmethod
    +    def scale_model(model: tf.keras.Model) -> typing.List[ClsSetInfo]:
    +        """
    +        Uses cross-layer scaling to scale all applicable layers in the given model
    +        :param model: tf.keras.Model
    +        :return: CLS information for each CLS set
    +        """
    +
    +        # Find layer groups
    +        graph_search_util = GraphSearchUtils(model)
    +        layer_groups = graph_search_util.find_layer_groups_to_scale()
    +
    +        # Find cls sets from the layer groups
    +        cls_sets = []
    +        for layer_group in layer_groups:
    +            cls_set = GraphSearchUtils.convert_layer_group_to_cls_sets(layer_group)
    +            cls_sets += cls_set
    +
    +        # Scale the CLS sets
    +        scale_factors = CrossLayerScaling.scale_cls_sets(cls_sets)
    +
    +        # Find if there were ReLU activations between layers of each cls set
    +        is_relu_activation_in_cls_sets = graph_search_util.is_relu_activation_present_in_cls_sets(cls_sets)
    +
    +        # Convert to a list of cls set info elements
    +        cls_set_info_list = CrossLayerScaling.create_cls_set_info_list(cls_sets,
    +                                                                       scale_factors,
    +                                                                       is_relu_activation_in_cls_sets)
    +
    +        return cls_set_info_list
    +
    +
    +class HighBiasFold:
    +    """
    +    Code to apply the high-bias-fold technique to a model
    +    """
    +
    +    @staticmethod
    +    def bias_fold(cls_set_info_list: typing.List[ClsSetInfo],
    +                  bn_layers: typing.Dict[tf.keras.layers.Conv2D, tf.keras.layers.BatchNormalization]):
    +        """
    +        Folds bias values greater than 3 * sigma to next layer's bias
    +        :param cls_set_info_list: List of info elements for each cls set
    +        :param bn_layers: Key: Conv/Linear layer Value: Corresponding folded BN layer
    +        """
    +        if not bn_layers:
    +            _logger.info('High Bias folding is not supported for models without BatchNorm Layers')
    +            return
    +
    +        for cls_set_info in cls_set_info_list:
    +            for cls_pair_info in cls_set_info.cls_pair_info_list:
    +                if (not cls_pair_info.layer1.use_bias) or (not cls_pair_info.layer2.use_bias) or \
    +                        (cls_pair_info.layer1 not in bn_layers):
    +                    continue
    +
    +                prev_layer_params, curr_layer_params = HighBiasFold.call_mo_high_bias_fold(cls_pair_info, bn_layers)
    +
    +                layer1 = cls_pair_info.layer1
    +                layer1_weight_tensor, _ = layer1.get_weights()
    +                layer1_bias_tensor = np.array(prev_layer_params.bias)
    +                layer1.set_weights([layer1_weight_tensor, layer1_bias_tensor])
    +
    +                layer2 = cls_pair_info.layer2
    +                layer2_weight_tensor, _ = layer2.get_weights()
    +                layer2_bias_tensor = np.array(curr_layer_params.bias)
    +                layer2.set_weights([layer2_weight_tensor, layer2_bias_tensor])
    +
    +    @staticmethod
    +    def call_mo_high_bias_fold(cls_pair_info: ClsSetInfo.ClsSetLayerPairInfo,
    +                               bn_layers: typing.Dict[tf.keras.layers.Conv2D, tf.keras.layers.BatchNormalization]) \
    +            -> typing.Tuple[libpymo.LayerParams, libpymo.LayerParams]:
    +        """
    +        Invokes high bias fold MO API
    +        :param cls_pair_info: Pair of layers that were scaled using CLS and related information
    +        :param bn_layers: Key: Conv/Linear layer Value: Corresponding folded BN layer
    +        :return: Updated layer params
    +        """
    +
    +        bn_layer = bn_layers[cls_pair_info.layer1]
    +        prev_layer_bn_params = HighBiasFold._pack_bn_params_high_bias_fold(bn_layer, cls_pair_info.scale_factor)
    +
    +        prev_layer_params, curr_layer_params = HighBiasFold._pack_layer_params(cls_pair_info)
    +
    +        libpymo.updateBias(prev_layer_params, curr_layer_params, prev_layer_bn_params)
    +        return prev_layer_params, curr_layer_params
    +
    +    @staticmethod
    +    def _pack_bn_params_high_bias_fold(bn_layer: tf.keras.layers.BatchNormalization,
    +                                       scaling_parameter: np.ndarray) -> libpymo.BNParamsHighBiasFold:
    +        """
    +        Helper method to pack BatchNormalization parameter for high bias fold
    +        :param bn_layer: Target batch normalization layer
    +        :param scaling_parameter: Scaling parameters for each channel obtained from cross layer scaling
    +        :return: Packed BNParamsHighBiasFold
    +        """
    +        bn_params = libpymo.BNParamsHighBiasFold()
    +
    +        # Note: In BatchNormFold, we initialize gamma and beta to 1 and 0 respectively to work as Identity
    +        # So if the original value was set, use it for High Bias Fold
    +        if hasattr(bn_layer, "original_gamma") and hasattr(bn_layer, "original_beta"):
    +            gamma, beta = bn_layer.original_gamma, bn_layer.original_beta
    +        else:
    +            gamma, beta, _, _ = bn_layer.get_weights()
    +
    +        if len(scaling_parameter) != len(gamma) or len(scaling_parameter) != len(beta):
    +            raise ValueError("High Bias absorption is not supported for networks with fold-forward BatchNorms")
    +
    +        bn_params.gamma = np.divide(gamma, scaling_parameter)
    +        bn_params.beta = np.divide(beta, scaling_parameter)
    +
    +        return bn_params
    +
    +    @staticmethod
    +    def _pack_layer_params(cls_pair_info: ClsSetInfo.ClsSetLayerPairInfo) \
    +            -> typing.Tuple[libpymo.LayerParams, libpymo.LayerParams]:
    +        """
    +        Helper method to pack information of previous and current layer
    +        :param cls_pair_info: Pair of layers that were scaled using CLS and related information
    +        :return: Packed layer parameter tuple
    +        """
    +        # Pack parameters for previous layer
    +        prev_layer_params = libpymo.LayerParams()
    +
    +        prev_layer = cls_pair_info.layer1
    +        prev_layer_params.activationIsRelu = cls_pair_info.relu_activation_between_layers
    +
    +        _, prev_layer_bias_tensor = prev_layer.get_weights()
    +        prev_layer_params.bias = prev_layer_bias_tensor
    +
    +        # Pack parameters for current layer
    +        curr_layer_params = libpymo.LayerParams()
    +
    +        curr_layer = cls_pair_info.layer2
    +        curr_layer_weight_tensor, curr_layer_bias_tensor = curr_layer.get_weights()
    +        curr_layer_weight_tensor = WeightTensorUtils.transpose_from_tf_to_libpymo_format(curr_layer_weight_tensor,
    +                                                                                         curr_layer)
    +
    +        curr_layer_params.bias = curr_layer_bias_tensor
    +        curr_layer_params.weight = curr_layer_weight_tensor.reshape(-1)
    +        curr_layer_params.weightShape = np.array(curr_layer_weight_tensor.shape)
    +
    +        return prev_layer_params, curr_layer_params
    +
    +
    +
    +[docs] +def equalize_model(model: tf.keras.Model) -> tf.keras.Model: + """ + High-level API to perform Cross-Layer Equalization (CLE) on the given model + + :param model: tf.keras.Model + :return: CLE applied tf.keras.Model + """ + # replace any ReLU6 layers with ReLU + model_for_cle, _ = model_transform_utils.replace_relu6_with_relu(model) + + folded_pairs, model_for_cle = fold_all_batch_norms(model_for_cle) + + equalize_bn_folded_model(model_for_cle, folded_pairs) + + return model_for_cle
    + + + +def equalize_bn_folded_model(model: tf.keras.Model, + folded_pairs: typing.List[BatchNormFoldedPair]): + """ + Perform Cross-Layer Scaling (CLS) and High Bias Folding (HBF) on a batchnorm-folded model in-place + :param model: BatchNorm-folded model to equalize + :param folded_pairs: List of pairs of folded layers + """ + bn_dict = {} + for conv_or_linear, bn in folded_pairs: + bn_dict[conv_or_linear] = bn + + # perform cross-layer scaling on applicable layer sets + cls_set_info_list = CrossLayerScaling.scale_model(model) + + # high-bias fold + HighBiasFold.bias_fold(cls_set_info_list, bn_dict) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_tensorflow/keras/defs.html b/releases/2.0.0/_modules/aimet_tensorflow/keras/defs.html new file mode 100644 index 0000000..a8435f0 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_tensorflow/keras/defs.html @@ -0,0 +1,462 @@ + + + + + + + + aimet_tensorflow.keras.defs - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_tensorflow.keras.defs

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2018-2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Common type definitions that are used across aimet """
    +
    +from enum import Enum
    +from typing import List, Optional, Union
    +import tensorflow as tf
    +
    +from aimet_common.defs import GreedySelectionParameters
    +
    +
    +# Ways to handle getting number of channels from axes. Default is to get it from the last dimension. For depthwise
    +# conv2d, it will be obtained from the last two dimensions.
    +class AxisHandling(Enum):
    +    """
    +    Enum for axis handling used as input variable to QcQuantizePerChannelOp. This defines how to interpret the
    +    number of output channels from the weight dimensions.
    +    """
    +    LAST_AXIS = 0
    +    LAST_TWO_AXES = 1
    +
    +
    +class ModuleCompRatioPair:
    +    """
    +    Pair of tf.Operation and a compression-ratio
    +    :ivar module: Module of type tf.Operation
    +    :ivar comp_ratio: Compression ratio. Compression ratio is the ratio of cost of compressed model
    +            to cost of the original model.
    +    """
    +
    +    def __init__(self, module: tf.Operation, comp_ratio: float):
    +        self.module = module
    +        self.comp_ratio = comp_ratio
    +
    +
    +
    +[docs] +class SpatialSvdParameters: + """ Configuration parameters for spatial svd compression """ + +
    +[docs] + class ManualModeParams: + """ + Configuration parameters for manual-mode spatial svd compression + """ + + def __init__(self, list_of_module_comp_ratio_pairs: List[ModuleCompRatioPair]): + """ + :param list_of_module_comp_ratio_pairs: List of (module, comp-ratio) pairs + """ + self.list_of_module_comp_ratio_pairs = list_of_module_comp_ratio_pairs
    + + +
    +[docs] + class AutoModeParams: + """ + Configuration parameters for auto-mode compression + """ + + def __init__(self, greedy_select_params: GreedySelectionParameters, + modules_to_ignore: Optional[List[tf.Operation]] = None): + """ + :param greedy_select_params: Params for greedy comp-ratio selection algorithm + :param modules_to_ignore: List of modules to ignore (None indicates nothing to ignore) + """ + self.greedy_params = greedy_select_params + self.modules_to_ignore = [] if modules_to_ignore is None else modules_to_ignore
    + + +
    +[docs] + class Mode(Enum): + """ Mode enumeration """ + + manual = 1 + """ Manual mode """ + + auto = 2 + """ Auto mode """
    + + + def __init__(self, input_op_names: List[str], output_op_names: List[str], mode: Mode, + params: Union[ManualModeParams, AutoModeParams], multiplicity=1): + """ + :param input_op_names: list of input op names to the model + :param output_op_names: List of output op names of the model + :param mode: Either auto mode or manual mode + :param params: Parameters for the mode selected + :param multiplicity: The multiplicity to which ranks/input channels will get rounded. Default: 1 + """ + self.input_op_names = input_op_names + self.output_op_names = output_op_names + self.mode = mode + self.mode_params = params + self.multiplicity = multiplicity
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_tensorflow/keras/layer_output_utils.html b/releases/2.0.0/_modules/aimet_tensorflow/keras/layer_output_utils.html new file mode 100644 index 0000000..72cf796 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_tensorflow/keras/layer_output_utils.html @@ -0,0 +1,493 @@ + + + + + + + + aimet_tensorflow.keras.layer_output_utils - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_tensorflow.keras.layer_output_utils

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" This module contains utilities to capture and save intermediate layer-outputs of a model. """
    +
    +import os
    +from typing import Union, List, Tuple
    +import re
    +from collections import OrderedDict
    +import json
    +import numpy as np
    +import tensorflow as tf
    +from aimet_tensorflow.keras.quantsim import QcQuantizeWrapper, QcQuantizableMultiHeadAttention
    +from aimet_common.layer_output_utils import SaveInputOutput
    +from aimet_common.utils import AimetLogger
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.LayerOutputs)
    +
    +
    +[docs] +class LayerOutputUtil: + """ Implementation to capture and save outputs of intermediate layers of a model (fp32/quantsim) """ + + def __init__(self, model: tf.keras.Model, save_dir: str = "./KerasLayerOutput"): + """ + Constructor for LayerOutputUtil. + + :param model: Keras (fp32/quantsim) model. + :param save_dir: Directory to save the layer outputs. + """ + # Freeze the model weights and state + model.trainable = False + + # Get intermediate model for layer-outputs + self.intermediate_model = self._get_intermediate_model(model) + + # Get actual Layer output name to modified layer output name dict + self.original_name_to_modified_name_mapper = self._get_original_name_to_modified_name_mapper(model) + + # Saving the actual layer output name to modified layer output name (valid file name to save) in a json file + os.makedirs(save_dir, exist_ok=True) + with open(os.path.join(save_dir, "LayerOutputNameMapper.json"), 'w', encoding='utf-8') as fp: + json.dump(self.original_name_to_modified_name_mapper, fp=fp, indent=4) + + # Identify the axis-layout used for representing an image tensor + axis_layout = 'NHWC' if tf.keras.backend.image_data_format() == 'channels_last' else 'NCHW' + + # Utility to save model inputs and their corresponding layer-outputs + self.save_inp_out_obj = SaveInputOutput(save_dir, axis_layout=axis_layout) + + @classmethod + def _get_layer_output_name(cls, layer: Union[QcQuantizeWrapper, QcQuantizableMultiHeadAttention, tf.keras.layers.Layer]): + """ + This function returns the actual layer output name for a given layer + :param layer: Keras model layer. + :return: Actual layer output name for the layer + """ + if isinstance(layer, QcQuantizeWrapper): + return layer.original_layer.output.name + return layer.output.name + + @classmethod + def _get_intermediate_model(cls, model: tf.keras.Model): + """ + This function instantiates the feature extraction model for per layer outputs + :param model: Keras model. + :return: Intermediate keras model for feature extraction + """ + outputs = [layer.output for layer in model.layers] + intermediate_model = tf.keras.models.Model(inputs=model.inputs, outputs=outputs) + intermediate_model.trainable = False + return intermediate_model + + @classmethod + def _get_original_name_to_modified_name_mapper(cls, model: tf.keras.Model): + """ + This function captures the per-layer output name and modifies it to make a valid file name + (by removing non-word characters) so that the layer output can be easily saved with the modified name. + :param model: Keras model. + :return: Actual layer name to modified layer name dict + """ + original_name_to_modified_name_mapper = OrderedDict() + for layer in model.layers: + layer_output_name = cls._get_layer_output_name(layer) + + # Replace all non-word characters with "_" to make it a valid file name for saving the results + # For Eg.: "conv2d/BiasAdd:0" gets converted to "conv2d_BiasAdd_0" + modified_layer_output_name = re.sub(r'\W+', "_", layer_output_name) + + original_name_to_modified_name_mapper[layer_output_name] = modified_layer_output_name + + return original_name_to_modified_name_mapper + + def get_outputs(self, input_instance: Union[tf.Tensor, List[tf.Tensor], Tuple[tf.Tensor]]): + """ + This function captures layer-outputs and renames them as per the AIMET exported model. + :param input_instance: Single input instance for which we want to obtain layer-outputs. + :return: layer-output name to layer-output dict + """ + # Run in inference mode + outs = self.intermediate_model(input_instance, training=False) + output_pred = [out.numpy() for out in outs] + + return dict(zip(self.original_name_to_modified_name_mapper.values(), output_pred)) + +
    +[docs] + def generate_layer_outputs(self, input_instance: Union[tf.Tensor, List[tf.Tensor], Tuple[tf.Tensor]]): + """ + This method captures output of every layer of a model & saves the inputs and corresponding layer-outputs to disk. + + :param input_instance: Single input instance for which layer output need to be generated + :return: None + """ + layer_output_dict = self.get_outputs(input_instance) + + # Skip constant scalar layer-outputs + const_scalar_layer_name = [] + for layer_name, layer_output in layer_output_dict.items(): + if not isinstance(layer_output, np.ndarray): + const_scalar_layer_name.append(layer_name) + for layer_name in const_scalar_layer_name: + logger.info("Skipping constant scalar output of layer %s", layer_name) + _ = layer_output_dict.pop(layer_name) + + self.save_inp_out_obj.save(np.array(input_instance), layer_output_dict) + + logger.info("Layer outputs saved for input instance %d", self.save_inp_out_obj.input_cntr)
    +
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_tensorflow/keras/mixed_precision.html b/releases/2.0.0/_modules/aimet_tensorflow/keras/mixed_precision.html new file mode 100644 index 0000000..c535b35 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_tensorflow/keras/mixed_precision.html @@ -0,0 +1,520 @@ + + + + + + + + aimet_tensorflow.keras.mixed_precision - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_tensorflow.keras.mixed_precision

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Mixed precision inference """
    +
    +from typing import Union, Tuple, List, Callable
    +
    +from aimet_common.utils import AimetLogger
    +from aimet_common.defs import CallbackFunc
    +from aimet_common.amp.utils import (
    +    visualize_quantizer_group_sensitivity,
    +    visualize_pareto_curve,
    +    CANDIDATE_WITH_DTYPE,
    +    AMPSearchAlgo
    +)
    +
    +from aimet_tensorflow.keras.quantsim import QuantizationSimModel
    +from aimet_tensorflow.keras.amp.mixed_precision_algo import GreedyMixedPrecisionAlgo, EvalCallbackFactory
    +from aimet_tensorflow.keras.amp.quantizer_groups import QuantizerGroup
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.MixedPrecision)
    +
    +
    +# pylint: disable=too-many-arguments
    +
    +[docs] +def choose_mixed_precision(sim: QuantizationSimModel, candidates: List[CANDIDATE_WITH_DTYPE], + eval_callback_for_phase1: CallbackFunc, eval_callback_for_phase2: CallbackFunc, + allowed_accuracy_drop: Union[float, None], results_dir: str, + clean_start: bool, forward_pass_callback: CallbackFunc, + amp_search_algo: AMPSearchAlgo = AMPSearchAlgo.Binary, phase1_optimize: bool = True) \ + -> Union[List[Tuple[int, float, QuantizerGroup, int]], None]: + """ + High-level API to perform in place Mixed Precision evaluation on the given sim model. A pareto list is created and + a curve for Accuracy vs BitOps is saved under the results directory + + :param sim: Quantized sim model + :param input_shape: tuple or list of tuples of input shape to the model + :param starting_op_names: List of starting op names of the model + :param output_op_names: List of output op names of the model + :param candidates: List of tuples for all possible bitwidth values for activations and parameters + Suppose the possible combinations are- + ((Activation bitwidth - 8, Activation data type - int), (Parameter bitwidth - 16, parameter data type - int)) + ((Activation bitwidth - 16, Activation data type - float), (Parameter bitwidth - 16, parameter data type - float)) + candidates will be [((8, QuantizationDataType.int), (16, QuantizationDataType.int)), + ((16, QuantizationDataType.float), (16, QuantizationDataType.float))] + :param eval_callback_for_phase1: An object of CallbackFunc class which takes in Eval function (callable) and eval + function parameters. This evaluation callback used to measure sensitivity of each + quantizer group during phase 1. The phase 1 involves finding accuracy list/sensitivity of each + module. Therefore, a user might want to run the phase 1 with a smaller dataset + :param eval_callback_for_phase2: An object of CallbackFunc class which takes in Eval function (callable) and eval + function parameters. Evaluation callback used to get accuracy of quantized model + for phase 2 calculations. The phase 2 involves finding pareto front curve + :param allowed_accuracy_drop: Maximum allowed drop in accuracy from FP32 baseline. The pareto front curve is plotted only till the point where the allowable + accuracy drop is met. To get a complete plot for picking points on the curve, the user + can set the allowable accuracy drop to None. + :param results_dir: Path to save results and cache intermediate results + :param clean_start: If true, any cached information from previous runs will be deleted prior to starting the + mixed-precision analysis. If false, prior cached information will be used if applicable. Note + it is the user's responsibility to set this flag to true if anything in the model or + quantization parameters changes compared to the previous run. + :param forward_pass_callback: An object of CallbackFunc class which takes in Forward pass function (callable) and its + function parameters. Forward pass callback used to compute quantization encodings + :param amp_search_algo: A valid value from the Enum AMPSearchAlgo. Defines the search algorithm to be used for + the phase 2 of AMP. Default to BruteForce for regular AMP. + :param phase1_optimize: If user set this parameter to false then phase1 default logic will be executed else optimized logic will be executed. + :return: Pareto front list containing a list of (Relative bit ops wrt baseline candidate, eval score, quantizer group + and the candidate being used in each step). The Pareto front list can be used for plotting a pareto front + curve which provides information regarding how bit ops vary w.r.t. accuracy. If the allowable accuracy drop + is set to 100% then a user can use the pareto front curve to pick points and re-run, + None if we early exit the mixed precision algorithm. + """ + + mixed_precision_algo = GreedyMixedPrecisionAlgo(sim, candidates, eval_callback_for_phase1, + eval_callback_for_phase2, results_dir, + clean_start, forward_pass_callback, phase1_optimize=phase1_optimize) + + return _run_amp(mixed_precision_algo, allowed_accuracy_drop, amp_search_algo, results_dir)
    + + + +# pylint: disable=too-many-arguments +
    +[docs] +def choose_fast_mixed_precision(sim: QuantizationSimModel, candidates: List[CANDIDATE_WITH_DTYPE], + data_loader_wrapper: Callable, eval_callback_for_phase2: CallbackFunc, + allowed_accuracy_drop: Union[float, None], results_dir: str, clean_start: bool, + forward_pass_callback: CallbackFunc, forward_pass_callback_2: Callable = None, + amp_search_algo: AMPSearchAlgo = AMPSearchAlgo.Binary, phase1_optimize: bool = True) \ + -> Union[List[Tuple[int, float, QuantizerGroup, int]], None]: + """ + High-level API to perform in place Mixed Precision evaluation on the given sim model. A pareto list is created and + a curve for Accuracy vs BitOps is saved under the results directory + + :param sim: Quantized sim model + :param candidates: List of tuples for all possible bitwidth values for activations and parameters + Suppose the possible combinations are- + ((Activation bitwidth - 8, Activation data type - int), (Parameter bitwidth - 16, parameter data type - int)) + ((Activation bitwidth - 16, Activation data type - float), (Parameter bitwidth - 16, parameter data type - float)) + candidates will be [((8, QuantizationDataType.int), (16, QuantizationDataType.int)), + ((16, QuantizationDataType.float), (16, QuantizationDataType.float))] + :param data_loader_wrapper: A Callable function which when called should return a dataloader to be used to do phase 1 forward pass. + :param eval_callback_for_phase2: An object of CallbackFunc class which takes in Eval function (callable) and eval + function parameters. Evaluation callback used to get accuracy of quantized model + for phase 2 calculations. The phase 2 involves finding pareto front curve + :param allowed_accuracy_drop: Maximum allowed drop in accuracy from FP32 baseline. The pareto front curve is plotted only till the point where the allowable + accuracy drop is met. To get a complete plot for picking points on the curve, the user + can set the allowable accuracy drop to None. + :param results_dir: Path to save results and cache intermediate results + :param clean_start: If true, any cached information from previous runs will be deleted prior to starting the + mixed-precision analysis. If false, prior cached information will be used if applicable. Note + it is the user's responsibility to set this flag to true if anything in the model or + quantization parameters changes compared to the previous run. + :param forward_pass_callback: An object of CallbackFunc class which takes in Forward pass function (callable) and its + function parameters. Forward pass callback used to compute quantization encodings + :param forward_pass_callback_2: forward pass callback function which will take an input model and inputs and perform forward pass + on it and return the output nupy ndarray of the last layer. Can be kept None if the model works with the standard model.predict() forward pass + :param amp_search_algo: A valid value from the Enum AMPSearchAlgo. Defines the search algorithm to be used for + the phase 2 of AMP. Default to Interpolation for fast AMP. + :param phase1_optimize: If user set this parameter to false then phase1 default logic will be executed else optimized logic will be executed. + :return: Pareto front list containing a list of (Relative bit ops wrt baseline candidate, eval score, quantizer group + and the candidate being used in each step). The Pareto front list can be used for plotting a pareto front + curve which provides information regarding how bit ops vary w.r.t. accuracy. If the allowable accuracy drop + is set to 100% then a user can use the pareto front curve to pick points and re-run, + None if we early exit the mixed precision algorithm. + """ + + # pylint: disable=protected-access + eval_callback_for_phase1 = EvalCallbackFactory(data_loader_wrapper, forward_pass_callback_2).sqnr(sim._model_without_wrappers) + mixed_precision_algo = GreedyMixedPrecisionAlgo(sim, candidates, eval_callback_for_phase1, + eval_callback_for_phase2, results_dir, + clean_start, forward_pass_callback, phase1_optimize=phase1_optimize) + + return _run_amp(mixed_precision_algo, allowed_accuracy_drop, amp_search_algo, results_dir)
    + + + +def _run_amp(mixed_precision_algo: GreedyMixedPrecisionAlgo, + allowed_accuracy_drop: float, + amp_search_algo, + results_dir: str): + mixed_precision_algo.run(allowed_accuracy_drop, amp_search_algo) + + if mixed_precision_algo.accuracy_list is not None and mixed_precision_algo.pareto_list is not None: + # Print mixed precision stats + logger.info(mixed_precision_algo) + + # Visualize quantizer group sensitivity + visualize_quantizer_group_sensitivity(mixed_precision_algo.accuracy_list, + mixed_precision_algo.baseline_candidate, + mixed_precision_algo.fp32_accuracy, + results_dir=results_dir) + # Create pareto list curve + visualize_pareto_curve(mixed_precision_algo.pareto_list, results_dir) + return mixed_precision_algo.pareto_list + + return None +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_tensorflow/keras/model_preparer.html b/releases/2.0.0/_modules/aimet_tensorflow/keras/model_preparer.html new file mode 100644 index 0000000..74d0cbc --- /dev/null +++ b/releases/2.0.0/_modules/aimet_tensorflow/keras/model_preparer.html @@ -0,0 +1,1302 @@ + + + + + + + + aimet_tensorflow.keras.model_preparer - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_tensorflow.keras.model_preparer

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Implementation to automatically prepare keras models for AIMET by converting them to a functional model """
    +import typing
    +
    +import inspect
    +import logging
    +from typing import Any, Dict, List, Set, Union, Optional
    +import re
    +import numpy as np
    +import tensorflow as tf
    +
    +import tensorflow.keras.backend as K
    +from packaging import version  # pylint: disable=wrong-import-order
    +
    +if version.parse(tf.version.VERSION) >= version.parse("2.10"):
    +    # Ignore pylint errors as keras module is not available in TF 2.4
    +    from keras.engine.base_layer_utils import is_subclassed  # pylint: disable=import-error
    +    from keras.engine.functional import Functional  # pylint: disable=import-error
    +    from keras.engine.keras_tensor import KerasTensor  # pylint: disable=import-error
    +    from keras.layers.core.tf_op_layer import TFOpLambda  # pylint: disable=import-error
    +    from keras.layers.merging.base_merge import _Merge as MergeLayersParentClass  # pylint: disable=import-error
    +else:
    +    # Ignore pylint errors due to conditional imports
    +    from tensorflow.python.keras.engine.base_layer_utils import is_subclassed  # pylint: disable=ungrouped-imports
    +    from tensorflow.python.keras.engine.keras_tensor import KerasTensor  # pylint: disable=ungrouped-imports
    +    from tensorflow.python.keras.engine.functional import Functional  # pylint: disable=ungrouped-imports
    +    from tensorflow.python.keras.layers.core import TFOpLambda  # pylint: disable=ungrouped-imports
    +    # pylint: disable=ungrouped-imports
    +    from tensorflow.python.keras.layers.merge import \
    +        _Merge as MergeLayersParentClass
    +
    +# pylint: disable=wrong-import-position
    +from aimet_tensorflow.keras.utils.model_connection_utils import ModelLayerConnections, ModelLayerConnectionsProperties
    +from aimet_tensorflow.keras.utils.model_transform_utils import replace_separable_conv_with_depthwise_pointwise, \
    +    replace_relu6_with_relu
    +from aimet_common.utils import AimetLogger
    +
    +_logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.ModelPreparer)
    +
    +regex_for_camel_case_to_snake_case = re.compile(r'(?<!^)(?=[A-Z])')
    +_TEMP_MODEL_NAME = "temp_aimet_intermediate_model"
    +
    +"""
    +This file contains the implementation to automatically prepare keras models for AIMET by converting them to a functional model.
    +"""
    +
    +
    +class _KerasModelPreparer:
    +
    +    def __init__(
    +        self,
    +        original_model: Optional[tf.keras.Model] = None,
    +        input_layer: Optional[tf.keras.layers.InputLayer] = None
    +    ):
    +        self.model_outputs = []  # Both normal init and "passthrough" init utilize this
    +        if original_model:
    +            self.input_layer = self._format_input_layer(original_model, input_layer)
    +
    +            if self._inherits_from_keras_model(original_model):
    +                _logger.debug("This model inherits from tf.keras.Model. Need to connect model.")
    +                self.original_model = self._connect_inherited_model(original_model, input_layer, is_original_model=True)
    +
    +            else:
    +                self.original_model = original_model
    +
    +            # Used to fix weight names at end of unwrapping
    +            # Originally set to the name of the original model's class in the case that there is an inherited model
    +            self.class_names = self._get_class_names_in_model(self.original_model)
    +
    +            self.model_layers_connections = \
    +                ModelLayerConnections.get_model_layers_connection_properties(self.original_model)
    +            self._set_prepared_models_input_layer()
    +
    +            self.original_models_last_layer = self.original_model.layers[-1]
    +
    +            self.prepared_model = None
    +            self.custom_objects = None
    +            self.original_weights_in_prepared_model_order = None
    +
    +    @classmethod
    +    def get_instance_for_common_layer_passthrough_functions(
    +            cls, model_layers_connections: ModelLayerConnectionsProperties.TYPE
    +    ):
    +        """
    +        Special function to __init__ for classes outside _KerasModelPreparer that want access to useful
    +        functions like _handle_normal_keras_layer. ONLY use this for internal use. For normal Keras Model Preparer,
    +        please utilize the prepare_model function.
    +
    +        :param model_layers_connections: Dictionary of Model Layer Connections for the functions to use.
    +        :return: A slim instance of _KerasModelPreparer
    +        """
    +
    +        self = cls(original_model=None, input_layer=None)
    +        self.model_layers_connections = model_layers_connections
    +        return self
    +
    +    def _get_original_models_weights_in_functional_model_order(self) -> List[np.ndarray]:
    +        """
    +        Map the original model's weights to the functional model's weights.
    +
    +        :return: A list of the original model's weights in the order of the functional model's weights
    +        """
    +        # Make the original model's weights into a dictionary for quick lookup by name
    +        # The original subclassed layers names are removed to match the new functional model's names
    +        original_model_weights = {}
    +        for weight in self.original_model.weights:
    +            # pop out class_names of weight name
    +            weight_name = weight.name
    +            for class_name in self.class_names:
    +                weight_name = weight_name.replace(class_name + '/', '')
    +            original_model_weights[weight_name] = weight.numpy()
    +
    +        # Get the functional model's weights in order as a dictionary for quick lookup where the key is the weight name
    +        # and the position of the weight's order is the value
    +        prepared_model_weight_order = {
    +            weight.name: position
    +            for position, weight in enumerate(self.prepared_model.weights)
    +        }
    +
    +        # Using the functional model's weights order, get the original model's weights in the same order. The lambda
    +        # here uses the weight's name to get position in the functional model's weights order and the sorts the
    +        # original model's weights by that position.
    +        self.original_weights_in_prepared_model_order = [
    +            weight for _, weight in
    +            sorted(original_model_weights.items(), key=lambda weight_info: prepared_model_weight_order[weight_info[0]])
    +        ]
    +
    +        return self.original_weights_in_prepared_model_order
    +
    +    def _set_prepared_models_weights(self):
    +        """
    +        Set the functional model's weights to the original model's weights in the correct order
    +        """
    +
    +        assert self.prepared_model, (
    +            "The prepared model must be created before setting weights. Please call "
    +                "prepare_model() before calling set_weights()."
    +        )
    +
    +        try:
    +            self.prepared_model.set_weights(self._get_original_models_weights_in_functional_model_order())
    +        except ValueError:
    +            _logger.error(
    +                "Could not copy weights from original model to the prepared model. This can occur when "
    +                "custom sublayers are defined not in the same order as the sublayers call method. Please ensure that "
    +                "the sublayers internal layers are defined in the same order as the sublayers call method.")
    +            raise
    +
    +        _logger.debug("Functional model weights copied.")
    +        _logger.info("Model prepared for AIMET in Functional API format.")
    +
    +    @staticmethod
    +    def _format_input_layer(
    +            original_model: tf.keras.Model,
    +            input_layer: Union[tf.keras.layers.InputLayer, List[tf.keras.layers.InputLayer], dict]
    +    ) -> tf.keras.layers.Layer:
    +        """
    +        This function formats the input layer by either using the original models input layer or the user provided
    +        input layer. This function will also raise an error if the model needs a defined input layer to be prepared
    +        for AIMET.
    +
    +        :param original_model: The original model to be copied
    +        :param input_layer: The input layer to be used for the functional model
    +        :return: The input layer
    +        """
    +        if hasattr(original_model, "input"):
    +            input_layer = original_model.input
    +        elif isinstance(input_layer, tf.keras.layers.InputLayer):
    +            _logger.info("Input layer explicitly passed in")
    +            return input_layer
    +        else:
    +            _logger.info("Input layer not found. Using input layer passed in.")
    +            if input_layer is None:
    +                raise ValueError(
    +                    "The top layer of this model is subclassed. Please provide an input layer via the "
    +                    "\'input_layer\' parameter."
    +                )
    +
    +        if isinstance(input_layer, dict):  # Keras allows passing in tensors via tensor_name : tensor
    +            input_layer = list(input_layer.values())
    +            if len(input_layer) == 1:
    +                return input_layer[0]
    +
    +        return input_layer
    +
    +    @staticmethod
    +    def _get_class_names_in_model(model: Union[tf.keras.Model, tf.keras.layers.Layer]) -> Set[str]:
    +        """
    +        Helper function to get the class name for a nested layer.
    +
    +        :param model: the 'layer' or 'model' to get the class name
    +        :return: A set containing the class name
    +        """
    +        return {
    +            regex_for_camel_case_to_snake_case.sub("_", name).lower()
    +            for name in (model.name, model.__class__.__name__)
    +        }
    +
    +    @staticmethod
    +    def _is_nested_layer(layer: tf.keras.layers.Layer) -> bool:
    +        """
    +        Checks if the given layer is a nested layer.
    +
    +        :param layer: The layer to check
    +        :return: True if the layer is a nested layer, False otherwise
    +        """
    +        keras_defined_subclassed_layer = is_subclassed(layer)
    +        # pylint: disable=use-a-generator
    +        is_aimet_defined_subclassed = keras_defined_subclassed_layer and any(
    +            [isinstance(v, tf.keras.layers.Layer) for v in layer.__dict__.values()]
    +        )  # check if the subclass is holding subclassed layer attributes. we only care if this is the case.
    +
    +        return (
    +            is_aimet_defined_subclassed or
    +            _KerasModelPreparer._is_functional_model(layer) or
    +            _KerasModelPreparer._is_sequential_model(layer)
    +        )
    +
    +    @staticmethod
    +    def _is_functional_model(layer: tf.keras.layers.Layer) -> bool:
    +        """
    +        Checks if the given layer is a functional layer.
    +
    +        :param layer: The layer to check
    +        :return: True if the layer is a functional layer, False otherwise
    +        """
    +        return isinstance(layer, Functional) and not isinstance(layer, tf.keras.Sequential)
    +
    +    @staticmethod
    +    def _is_sequential_model(layer: tf.keras.layers.Layer) -> bool:
    +        """
    +        Checks if the given layer is a sequential layer.
    +
    +        :param layer: The layer to check
    +        :return: True if the layer is a sequential layer, False otherwise
    +        """
    +        return isinstance(layer, tf.keras.Sequential)
    +
    +    def _set_prepared_models_input_layer(self):
    +        """
    +        This function sets the input layer of the model to the input layer of the functional model.
    +        """
    +
    +        def set_input_layer_factory(input_layer: Union[tf.keras.layers.InputLayer, List[tf.keras.layers.InputLayer]]):
    +            if isinstance(input_layer, list):
    +                for inp in input_layer:
    +                    self.model_layers_connections[ModelLayerConnectionsProperties.OUTPUT_TENSORS].update(
    +                        {inp.name: inp}
    +                    )
    +            else:
    +                self.model_layers_connections[ModelLayerConnectionsProperties.OUTPUT_TENSORS].update(
    +                    {input_layer.name: input_layer}
    +                )
    +
    +        try:
    +            set_input_layer_factory(self.input_layer)
    +        except AttributeError:
    +            # For models that are not connected
    +            _logger.info("Model is not connected. Setting input layer to input layer passed in.")
    +
    +            input_layer_name = [inp.name for inp in self.input_layer] if isinstance(self.input_layer, list) else \
    +                [self.input_layer.name]
    +            self.model_layers_connections[ModelLayerConnectionsProperties.INBOUND_NODES].update(
    +                {self.original_model.layers[0].name: [*input_layer_name]}
    +            )
    +
    +            set_input_layer_factory(self.input_layer)
    +
    +    def _get_layer_input(self, layer: tf.keras.layers.Layer) -> tf.keras.layers.Layer:
    +        """
    +        Helper function to get the input layer of a layer.
    +
    +        :param layer: The layer to get the input layer of
    +        :return: The input layer of the layer
    +        """
    +        try:
    +            layer_input = [
    +                self.model_layers_connections[ModelLayerConnectionsProperties.OUTPUT_TENSORS][layer_aux]
    +                for layer_aux in
    +                self.model_layers_connections[ModelLayerConnectionsProperties.INBOUND_NODES][layer.name]
    +            ]
    +
    +            if len(layer_input) == 1:
    +                layer_input = layer_input[0]
    +        except KeyError:
    +            layer_input = self._get_most_recently_added_output_tensor()
    +            self.model_layers_connections[ModelLayerConnectionsProperties.INBOUND_NODES].update(
    +                {layer.name: [layer_input.name]}
    +            )
    +            _logger.warning(
    +                "Could not find input tensor for layer: %s. Using %s as input, the most recent output tensor.",
    +                layer.name, layer_input.name
    +            )
    +
    +        return layer_input
    +
    +    @staticmethod
    +    def _is_tf_or_keras_tensor_input(arg: Any) -> bool:
    +        """
    +        Helper function to check if a given argument is a valid Keras tensor.
    +
    +        :param arg: The argument in question
    +        :return: True if it is valid, False if not
    +        """
    +        if arg is not None:
    +            if isinstance(arg, List):
    +                return all(isinstance(x, KerasTensor) for x in arg) or all(isinstance(x, tf.Tensor) for x in arg)
    +            return isinstance(arg, (KerasTensor, tf.Tensor))
    +        return False
    +
    +    def _get_updated_call_args(self, layer: tf.keras.layers.Layer) -> List[Union[KerasTensor, List[KerasTensor], Any]]:
    +        """
    +        Helper function to get the call arguments of a layer.
    +
    +        :param layer: The layer to get the call arguments of
    +        :return: The call arguments of the layer
    +        """
    +
    +        def _is_tf_tensor(arg_in_question: Any) -> bool:
    +            return isinstance(arg_in_question, tf.Tensor)
    +
    +        try:
    +            original_call_args = self.model_layers_connections[ModelLayerConnectionsProperties.CALL_ARGS][layer.name]
    +        except KeyError:
    +            _logger.warning("Could not find call args for layer: '%s'. Using keras tensor only as input.", layer.name)
    +            return [self._get_layer_input(layer)]
    +
    +        updated_call_args = []
    +        found_keras_tensor = False
    +        for arg in original_call_args:
    +            if self._is_tf_or_keras_tensor_input(arg):
    +
    +                if found_keras_tensor and _is_tf_tensor(arg):
    +                    updated_call_args.append(arg)
    +
    +                elif not found_keras_tensor:
    +                    layer_input = self._get_layer_input(layer)
    +                    if isinstance(layer_input, List):
    +                        updated_call_args.extend(layer_input)
    +                    else:
    +                        updated_call_args.append(layer_input)
    +                    found_keras_tensor = True
    +
    +            else:
    +                updated_call_args.append(arg)
    +
    +        assert found_keras_tensor, f"No keras tensor found in call args of layer {layer.name}"
    +        return updated_call_args
    +
    +    def _get_call_kwargs(self, layer: tf.keras.layers.Layer) -> Dict[Union[KerasTensor, List[KerasTensor]], Any]:
    +        """
    +        Helper function to get call keyword arguments for a given layer.
    +
    +        :param layer: The layer to get the call keyword arguments of
    +        :return: The call keyword arguments of the layer
    +        """
    +        if original_call_kwargs := \
    +                self.model_layers_connections[ModelLayerConnectionsProperties.CALL_KWARGS][layer.name]:
    +            call_kwargs = {}
    +            for key, value in original_call_kwargs.items():
    +                # The Keras tensor is already in the call args, so we don't need to add it again. call_kwargs are for
    +                # keyword arguments that are not Keras tensors such as 'axis', 'training', etc.
    +                if self._is_tf_or_keras_tensor_input(value):
    +                    continue
    +                call_kwargs[key] = value
    +        else:
    +            _logger.debug("No kwargs for layer: '%s'", layer.name)
    +            return {}
    +        return call_kwargs
    +
    +    def _update_nested_values(self, values: typing.List | typing.Tuple, old_to_new_tensor_mapper: typing.Dict):
    +        """
    +        Helper function to update the nested Lists/Tuples based on the dictionary provided
    +        :param values: List/Tuple of values
    +        :param old_to_new_tensor_mapper: Update dictionary
    +        :return: Any
    +        """
    +        if isinstance(values, typing.Tuple):
    +            return tuple(self._update_nested_values(x, old_to_new_tensor_mapper) for x in values)
    +        if isinstance(values, typing.List):
    +            return [self._update_nested_values(x, old_to_new_tensor_mapper) for x in values]
    +        if isinstance(values, KerasTensor) and values.name in old_to_new_tensor_mapper:
    +            return old_to_new_tensor_mapper[values.name]
    +        return values
    +
    +    def _update_output_tensors_in_model_layers_connections(
    +            self,
    +            layer: tf.keras.layers.Layer,
    +            new_output_tensor: KerasTensor,
    +            model: tf.keras.Model
    +    ):
    +        """
    +        Helper function to update the output tensors in the model layers connections dictionary.
    +
    +        :param layer: The layer to update the output tensors of
    +        :param new_output_tensor: The new output tensor to update with
    +        :param model: The model currently being checked. Used to add model outputs
    +        """
    +        # pylint: disable=too-many-nested-blocks, disable=protected-access, too-many-locals, too-many-branches
    +        if isinstance(new_output_tensor, List):
    +            # Handling case where layer has list of output tensors
    +            old_tensors = self.model_layers_connections[ModelLayerConnectionsProperties.LAYER_OUTPUT_TENSOR_MAP][layer.name]
    +            # Updating layer_output_tensor_map to new tensors
    +            self.model_layers_connections[ModelLayerConnectionsProperties.LAYER_OUTPUT_TENSOR_MAP][layer.name] = [tensor.name for tensor in new_output_tensor]
    +
    +            old_to_new_tensor_mapper = {old_tensor_name: new_output_tensor[i] for i, old_tensor_name in
    +                                        enumerate(old_tensors)}
    +
    +            old_name_of_inputs = None
    +            if layer.name in self.model_layers_connections[ModelLayerConnectionsProperties.INBOUND_NODES]:
    +                old_name_of_inputs = self.model_layers_connections[ModelLayerConnectionsProperties.INBOUND_NODES].pop(
    +                    layer.name
    +                )
    +            for out_tensor in new_output_tensor:
    +                new_name = out_tensor.name
    +                if old_name_of_inputs is not None:
    +                    self.model_layers_connections[ModelLayerConnectionsProperties.INBOUND_NODES].update(
    +                        {new_name: old_name_of_inputs}
    +                    )
    +                self.model_layers_connections[ModelLayerConnectionsProperties.OUTPUT_TENSORS].update(
    +                    {out_tensor.name: out_tensor}
    +                )
    +
    +            # Update inbound_nodes with new tensor names
    +            for node_name, values in self.model_layers_connections[ModelLayerConnectionsProperties.INBOUND_NODES].items():
    +                if layer.name in values:
    +                    # Update tensor for this entire layer
    +                    tensor_list = self._flatten_list(self.model_layers_connections[ModelLayerConnectionsProperties.CALL_ARGS][node_name])
    +                    tensor_list.extend(self._flatten_list(list(self.model_layers_connections[ModelLayerConnectionsProperties.CALL_KWARGS][node_name].values())))
    +                    tensor_list = [tensor for tensor in tensor_list if isinstance(tensor, KerasTensor)]
    +                    assert len(tensor_list) >= len(values), f"{node_name} has mismatched number of inbound nodes"
    +                    for idx, value in enumerate(values):
    +                        if value == layer.name and tensor_list[idx].name in old_to_new_tensor_mapper:
    +                            values[idx] = old_to_new_tensor_mapper[tensor_list[idx].name].name
    +
    +            # Update call_kwargs with new tensors
    +            for _, kwargs_dict in self.model_layers_connections[ModelLayerConnectionsProperties.CALL_KWARGS].items():
    +                for key, values in kwargs_dict.items():
    +                    kwargs_dict[key] = self._update_nested_values(values, old_to_new_tensor_mapper)
    +
    +            # Update call_args with new tensors
    +            for key, args in self.model_layers_connections[ModelLayerConnectionsProperties.CALL_ARGS].items():
    +                self.model_layers_connections[ModelLayerConnectionsProperties.CALL_ARGS][key] = self._update_nested_values(args, old_to_new_tensor_mapper)
    +
    +        elif layer.name != new_output_tensor.name:
    +            new_name = new_output_tensor.name
    +            old_name_of_inputs = self.model_layers_connections[ModelLayerConnectionsProperties.INBOUND_NODES].pop(
    +                layer.name
    +            )
    +            self.model_layers_connections[ModelLayerConnectionsProperties.INBOUND_NODES].update(
    +                {new_name: old_name_of_inputs}
    +            )
    +
    +            # Replace values in model_layers_connections[NetworkDictProperties.INBOUND_NODES] with new_name
    +            for value in self.model_layers_connections[ModelLayerConnectionsProperties.INBOUND_NODES].values():
    +                if layer.name in value:
    +                    idx = value.index(layer.name)
    +                    value[idx] = new_name
    +
    +            # Update the kwargs dict in case there's keras tensor
    +            # pylint: disable=protected-access
    +            for _, kwargs_dict in self.model_layers_connections[ModelLayerConnectionsProperties.CALL_KWARGS].items():
    +                for key, values in kwargs_dict.items():
    +                    if isinstance(values, List):
    +                        for i, value in enumerate(values):
    +                            if isinstance(value, KerasTensor) and value._keras_history.layer.name == layer.name:
    +                                values[i] = new_output_tensor
    +                    elif isinstance(values, KerasTensor) and values._keras_history.layer.name == layer.name:
    +                        kwargs_dict[key] = new_output_tensor
    +
    +
    +            self.model_layers_connections[ModelLayerConnectionsProperties.OUTPUT_TENSORS].update(
    +                {new_name: new_output_tensor}
    +            )
    +        else:
    +            # Set new output tensor (in this case, it will be the same as the original model)
    +            self.model_layers_connections[ModelLayerConnectionsProperties.OUTPUT_TENSORS].update(
    +                {layer.name: new_output_tensor}
    +            )
    +
    +        # Save tensor in output list if it is output in the initial model
    +        # TODO: Update so that the last conditional is only checked when it's not the last layer.
    +        if model.output_names and layer.name in model.output_names:
    +            _logger.debug("Layer '%s' added as output layer", layer.name)
    +            self.model_outputs.append(new_output_tensor)
    +
    +    def _get_most_recently_added_output_tensor(self) -> KerasTensor:
    +        """
    +        Helper function to get the most recently added output tensor from the model layers connections.
    +
    +        :return: The most recently added output tensor
    +        """
    +        return next(reversed(self.model_layers_connections[ModelLayerConnectionsProperties.OUTPUT_TENSORS].items()))[-1]
    +
    +    @staticmethod
    +    def _get_temporary_model(layer: tf.keras.layers.Layer, layer_input: tf.keras.layers.Layer) -> tf.keras.Model:
    +        """
    +        Helper function to create a temporary functional model from a layer.
    +
    +        :param layer: The layer to create the temporary model from
    +        :param layer_input: The input layer of the layer
    +        :return: The temporary model
    +        """
    +
    +        def verify_weights(original_layer_weights: Set[tf.Variable], temp_model_weights: Set[tf.Variable]):
    +            if missing_weights := original_layer_weights.difference(temp_model_weights):
    +                raise ValueError(f"""
    +    The number of weights in the temporary model for unwrapping layer '{layer.name}' does not match the
    +    number of weights of the original layer. The missing weight(s) are {missing_weights}. This occurs when the Keras 
    +    Symbolic tensor passed into the layers call function does not interact with a layer defined inside of the nested 
    +    layer. Please refer to the documentation for more information.
    +
    +    This is the call function that is causing this error:
    +    {inspect.getsource(layer.call)}
    +    """)
    +
    +        layer_input = layer_input if isinstance(layer_input, List) else [layer_input]
    +        temp_inputs = [
    +            tf.keras.layers.Input(shape=inp.shape[1:], name=inp.name.split(':')[0] + "_temp_input")
    +            for inp in layer_input
    +        ]
    +        if len(temp_inputs) == 1:
    +            temp_inputs = temp_inputs[0]
    +
    +        try:
    +            if _KerasModelPreparer._inherits_from_keras_model(layer):
    +                temp_model = _KerasModelPreparer._connect_inherited_model(layer, temp_inputs)
    +            else:
    +                temp_model = tf.keras.Model(inputs=temp_inputs,
    +                                            outputs=layer.call(temp_inputs, training=False),
    +                                            name=_TEMP_MODEL_NAME)
    +            _logger.debug("Model created for layer '%s'", layer.name)
    +        except TypeError as e:
    +            if "call() got an unexpected keyword argument 'training'" in e.__str__():
    +                _logger.error(
    +                    "Model preparer calls subclassed layers call functions with the parameter 'training=False', "
    +                    "in the case that the layer behaves differently during evaluation. Please add **kwargs to your "
    +                    "call function for layer '%s.'",
    +                    layer.name
    +                )
    +            raise
    +
    +        temp_model.summary(print_fn=_logger.debug)
    +        verify_weights({w.name for w in layer.weights}, {w.name for w in temp_model.weights})
    +
    +        return temp_model
    +
    +    @staticmethod
    +    def _update_temporary_model_layers_connections_inbound_nodes(
    +            temp_model_model_layers_connections: ModelLayerConnectionsProperties.TYPE,
    +            temp_model: tf.keras.Model,
    +            layer_input: tf.keras.layers.Layer
    +    ):
    +        """
    +        Helper function to update the inbound nodes of the temporary model layers connections dictionary.
    +
    +        :param temp_model_model_layers_connections: The temporary model layers connections dictionary
    +        :param temp_model: The temporary model
    +        :param layer_input: The input layer of the layer
    +        """
    +        temp_model_input_names = [inp.name for inp in temp_model.input] if isinstance(temp_model.input, List) else \
    +            [temp_model.input.name]
    +        layer_inputs_name = [
    +            inp.name for inp in (layer_input if isinstance(layer_input, List) else [layer_input])
    +        ]  # pylint: disable=superfluous-parens
    +
    +        for layers_name, input_tensor_name in temp_model_model_layers_connections[
    +                ModelLayerConnectionsProperties.INBOUND_NODES].items():
    +            for idx, current_input_name in enumerate(input_tensor_name):
    +                if current_input_name in temp_model_input_names:
    +                    if len(layer_inputs_name) == 1:  # Special case where the same input is feed in multiple times
    +                        temp_model_model_layers_connections[ModelLayerConnectionsProperties.INBOUND_NODES][layers_name][
    +                            idx] = layer_inputs_name[0]
    +                    else:
    +                        temp_model_model_layers_connections[ModelLayerConnectionsProperties.INBOUND_NODES][layers_name][
    +                            idx] = layer_inputs_name[idx]
    +
    +    def _handle_nested_layer(self, layer: tf.keras.layers.Layer) -> KerasTensor:
    +        """
    +        Helper function to handle nested layers such as subclass, functional, or sequential.
    +
    +        :param layer: The layer to handle
    +        :return: The output tensor of the layer
    +        """
    +        _logger.debug("Extracting layers for '%s'", layer.name)
    +
    +        # Converts CamelCase to snake_case of nested layers class name
    +        self.class_names.update([layer.name] if self._inherits_from_keras_model(
    +            layer) else self._get_class_names_in_model(layer))
    +
    +        # Create a model based on the nested layer.
    +        # This is done with the layer input from the model layers connections dictionary.
    +        # 1) The input layer is used to create the temporary functional model
    +        # 2) The input layer is used in the nested layers call function as a symbolic tensor to get internal layers
    +        layer_input = self._get_layer_input(layer)
    +        temp_model = tf.keras.models.clone_model(self._get_temporary_model(layer, layer_input))
    +
    +        # Get the model layers connections dictionary for the temporary model and merge it with the model layers
    +        # connections dictionary for the functional model. This is done, so we can keep track of the sublayer and
    +        # their inputs and outputs.
    +        temp_model_model_layers_connections = ModelLayerConnections.get_model_layers_connection_properties(temp_model)
    +        self._update_temporary_model_layers_connections_inbound_nodes(
    +            temp_model_model_layers_connections, temp_model, layer_input
    +        )
    +
    +        self.model_layers_connections = ModelLayerConnections.merge_model_layers_connections(
    +            self.model_layers_connections, temp_model_model_layers_connections
    +        )
    +
    +        return self._prepare_model_helper(temp_model)
    +
    +    @staticmethod
    +    def _get_keras_tensor_index(value: Any, search_list: List):
    +        """
    +        Helper function to check whether the value is a KerasTensor and return the index of it from the search_list
    +        :param value: Value to search in the list
    +        :param search_list: List to search
    +        :return: Index of value in the search list
    +        """
    +        if not isinstance(value, KerasTensor):
    +            return None
    +        for idx, k_tensor in enumerate(search_list):
    +            if isinstance(k_tensor, KerasTensor) and value.name == k_tensor.name:
    +                return idx
    +        return None
    +
    +    def _flatten_list(self, values: typing.List | typing.Tuple):
    +        """
    +        A helper function that returns flatten list of values in the given List or Tuple
    +        :param values: List or Tuple of values
    +        :return: List of flattened values
    +        """
    +        flat_vals = []
    +        for val in values:
    +            if isinstance(val, (typing.List, typing.Tuple)):
    +                flat_vals.extend(self._flatten_list(val))
    +            else:
    +                flat_vals.append(val)
    +        return flat_vals
    +
    +    def _handle_normal_keras_layer(self, layer: tf.keras.layers.Layer) -> KerasTensor:
    +        """
    +        Helper function to handle normal keras layers. This function will create a new output tensor for the layer
    +        and return it.
    +
    +        :param layer: The layer to create the output tensor for
    +        :return: The output tensor of the layer
    +        """
    +        # pylint: disable=too-many-branches, too-many-nested-blocks
    +        call_args = self._get_updated_call_args(layer)
    +
    +        if isinstance(layer, TFOpLambda):
    +            if call_kwargs := self._get_call_kwargs(layer):
    +                # Special case for 'tf.concat' that takes a list of inputs with kwargs attached
    +                # may need to updated in the future
    +
    +                # Remove keras tensor from call_args in case it is used in one of the keyword arguments
    +                for _, values in call_kwargs.items():
    +                    if not isinstance(values, List):
    +                        values = [values]
    +                    for value in values:
    +                        keras_tensor_index = self._get_keras_tensor_index(value, call_args)
    +                        if keras_tensor_index is not None:
    +                            call_args.pop(keras_tensor_index)
    +
    +                if hasattr(layer, "function") and hasattr(layer.function, "__name__") and \
    +                        layer.function.__name__ == "concat":
    +                    new_output_tensor = layer.call([*call_args], **call_kwargs)
    +                elif hasattr(layer, "function") and hasattr(layer.function, "__name__") and \
    +                        layer.function.__name__ == "cast":
    +                    # Handling the case for cast op where the dtype of input tensor and the cast op is same
    +                    source_tensor = call_kwargs['x'] if 'x' in call_kwargs else call_args[0]
    +                    source_dtype = source_tensor.dtype
    +                    target_dtype = call_kwargs['dtype'] if 'dtype' in call_kwargs else call_args[1].dtype
    +                    new_output_tensor = source_tensor if source_dtype == target_dtype else \
    +                        layer.call(*call_args, **call_kwargs)
    +                else:
    +                    new_output_tensor = layer.call(*call_args, **call_kwargs)
    +            else:
    +                new_output_tensor = layer.call(*call_args)
    +        # Special case for "Merge" layers that take a list of inputs such as "tf.keras.layers.Concatenate" and
    +        # "tf.keras.layers.Add"
    +        elif isinstance(layer, MergeLayersParentClass):
    +            new_output_tensor = layer(call_args)
    +        else:
    +            new_output_tensor = layer(*call_args)
    +
    +        return new_output_tensor
    +
    +    def _prepare_model_helper(self, model: tf.keras.Model) -> KerasTensor:
    +        """
    +        Helper function to recursively prepare a model. This function will be recursively called if a nested layer is
    +        found. This function will extract the layers from the nested layer and add them to the functional model.
    +        Otherwise, it will add the layer to the functional model.
    +
    +        :param model: The model to prepare
    +        :return: The last layer of the model
    +        """
    +        for current_layer in model.layers:
    +            _logger.debug("Processing layer: '%s'", current_layer.name)
    +            # Skip input layers
    +            if isinstance(current_layer, tf.keras.layers.InputLayer):
    +                continue
    +
    +            # If the current layer is either a subclassed layer, functional model or sequential model, we need to
    +            # extract the layers from the nested layer and add them to the functional model.
    +            if self._is_nested_layer(current_layer):
    +                new_output_tensor = self._handle_nested_layer(current_layer)
    +                # If we are at the end of the original model, we want the model_outputs to be the end model outputs
    +                if current_layer == self.original_models_last_layer:
    +                    _logger.debug(
    +                        "Last layer was a nested layer. "
    +                        "Using temp model's output from _handle_nested_layer as model_output"
    +                    )
    +                    continue
    +                self.model_outputs.clear()
    +            else:
    +                new_output_tensor = self._handle_normal_keras_layer(current_layer)
    +
    +            self._update_output_tensors_in_model_layers_connections(current_layer, new_output_tensor, model)
    +        return new_output_tensor
    +
    +    def prepare_model(self):
    +        """
    +        Function to get the prepared model. This function sets up the input layer and calls the helper function to
    +        recursively prepare the model.
    +        """
    +        _ = self._prepare_model_helper(self.original_model)
    +
    +        # If the model outputs are empty, then we need to get the most recently added output tensor. This is the case
    +        # when a model might be sparse and not fully connected or when a Functional model is inside an inherited model.
    +        if not self.model_outputs:
    +            _logger.warning(
    +                "No model outputs found. This usually occurs when a models is made by inheriting from "
    +                "'tf.keras.Model' and placing a Functional model inside. Using most recently added output tensor as "
    +                "prepared models output."
    +            )
    +            self.model_outputs = self._get_most_recently_added_output_tensor()
    +
    +        setattr(self, "prepared_model", tf.keras.Model(
    +            inputs=self.input_layer,
    +            outputs=self.model_outputs,
    +            name=f"{self.original_model.name}_prepared"
    +        ))
    +
    +        # Cloning model to remove any references to the original model
    +        K.clear_session()  # To avoid name conflicts
    +        self.prepared_model = tf.keras.models.clone_model(self.prepared_model)
    +        setattr(
    +            self, "custom_objects",  # For acceptable subclass layers
    +            self._get_models_custom_objects(self.prepared_model)
    +        )
    +        _logger.info("Prepared Model Summary: \n")
    +        self.prepared_model.summary(print_fn=_logger.info)
    +
    +        # Copying over weights from original model to functional model
    +        _logger.debug("Final class_names: %s", self.class_names)
    +        self._set_prepared_models_weights()
    +
    +        # Extra prepare step to replace Separable Conv's with Depthwise Pointwise pattern.
    +        self.prepared_model, _ = replace_separable_conv_with_depthwise_pointwise(
    +            self.prepared_model,
    +            custom_objects=self.custom_objects
    +        )
    +        self.prepared_model, _ = replace_relu6_with_relu(
    +            self.prepared_model,
    +            custom_objects=self.custom_objects
    +        )
    +
    +        self.verify_prepared_model()
    +
    +    @staticmethod
    +    def _get_models_custom_objects(model: tf.keras.Model) -> Optional[Dict[str, tf.keras.layers.Layer]]:
    +        """
    +        Helper function to return a models `custom_objects` if there are any present in the model.
    +
    +        :param model: The model to check
    +        :return: A dictionary {layer name : layer obj} of the custom objects or None if there are not any
    +        """
    +
    +        return {
    +            layer.__class__.__name__: layer.__class__
    +            for layer in model.layers
    +            if not getattr(layer, "__module__", None).split(".")[0] == "keras" and  # TF 2.10.1 and up
    +            not getattr(layer, "__module__", None).split(".")[0] == "tensorflow"    # TF 2.4.3 support
    +        } or None
    +
    +    @staticmethod
    +    def _model_has_nested_layers(model: tf.keras.Model) -> bool:
    +        """
    +        Helper function to check if a model is needed to be prepared or not based on if the model has nested layers such as
    +        subclass, functional, or sequential.
    +
    +        :param model: The model to check
    +        :return: If the model needs to be prepared or not
    +        """
    +        for layer in model.layers:
    +            if _KerasModelPreparer._is_nested_layer(layer):
    +                return True
    +        return False
    +
    +    @staticmethod
    +    def _inherits_from_keras_model(model: tf.keras.Model) -> bool:
    +        """
    +        Helper function to check if a model itself is inheriting from tf.keras.Model. If so, then the model needs to connected.
    +
    +        :param model: The model to check.
    +        :return: If the model is inheriting from tf.keras.Model
    +        """
    +
    +        return (
    +            type(model).__bases__[0] == tf.keras.Model and
    +            not _KerasModelPreparer._is_functional_model(model) and
    +            not _KerasModelPreparer._is_sequential_model(model)
    +        )
    +
    +    @staticmethod
    +    def _connect_inherited_model(model: tf.keras.Model, input_layer: Union[
    +            tf.keras.layers.InputLayer, List[tf.keras.layers.InputLayer]],
    +                                 is_original_model: bool = False) -> tf.keras.Model:
    +        """
    +        Function to loop through models that inherit from tf.keras.Model and therefore could potentially have no
    +        outbound nodes.
    +
    +        :param model: Model to connect.
    +        :param input_layer: The input layer to connect the model.
    +        :param is_original_model: Flag to clone the model if the original model is the one passed in.
    +        This is to fix naming issues. Otherwise, the model is not cloned.
    +        :return: A model with the outbound nodes generated.
    +        """
    +
    +        # TODO: Fix case where the layers are all the same. Maybe user has to?
    +        model = tf.keras.Model(inputs=input_layer, outputs=model.call(input_layer), name=_TEMP_MODEL_NAME)
    +        if is_original_model:
    +            try:
    +                return tf.keras.models.clone_model(model)
    +            except TypeError as e:
    +                _logger.error("The layer %s inherits from tf.keras.Model and has layer that does not have a "
    +                              "`get_config` defined. Due to this, Keras cannot clone this layer. Please override the "
    +                              "`get_config` function and provide the missing keys mentioned in the Keras error logs.",
    +                              model.name)
    +                raise e
    +        return model
    +
    +    def verify_prepared_model(self):
    +        """
    +        Function to verify that the prepared model is correct. This function will check that the prepared model has
    +        the same weights as the original model and that the prepared model has the same outputs as the original model.
    +        """
    +
    +        # Check that the prepared model has the same number of parameters as the original model
    +        assert self.prepared_model.count_params() == self.original_model.count_params(), \
    +            "Prepared model and original model do not have the same number of parameters"
    +        _logger.debug("Prepared model and original model have the same number of parameters")
    +
    +        # Check the weights of the prepared model and the original model
    +        for original_weight, prepared_weight in zip(
    +                self.original_weights_in_prepared_model_order, self.prepared_model.get_weights()):
    +            np.testing.assert_array_equal(
    +                original_weight, prepared_weight,
    +                err_msg="Weights of prepared model and original model do not match"
    +            )
    +        _logger.debug("Weights of prepared model and original model match")
    +
    +        # Create a random input to test the prepared model
    +        if isinstance(self.prepared_model.input_shape, List):
    +            random_input = []
    +            for current_input_shape in self.original_model.input_shape:
    +                input_shape = [shape if shape is not None else 1 for shape in current_input_shape]
    +                random_input.append(np.random.rand(*input_shape).astype(np.float32))
    +        else:
    +            input_shape = [shape if shape is not None else 1 for shape in self.prepared_model.input_shape]
    +            random_input = np.random.rand(*input_shape).astype(np.float32)
    +
    +        verbose = logging.DEBUG == _logger.level
    +        original_model_output = self.original_model.predict(random_input, verbose=verbose)
    +        prepared_model_output = self.prepared_model.predict(random_input, verbose=verbose)
    +
    +        # Check the outputs of the prepared model and the original model
    +        err_msg = """
    +        Outputs of prepared model and original model do not match. Since the weights match and params 
    +        match, this is likely due to a mismatch in the model's architecture. Specifically, if there is a reuse of a 
    +        layer, then the prepared model will not have the same output as the original model. For example, 
    +        if a ReLU layer is defined once and then used twice, then the prepared model will only have one ReLU layer 
    +        while the original model will have two ReLU layers. Please check the model's architecture to see if there are 
    +        any layers that are reused.
    +        """
    +
    +        if isinstance(original_model_output, Dict):
    +            original_model_output = list(original_model_output.values())
    +            if len(original_model_output) == 1:
    +                original_model_output = original_model_output[0]
    +
    +        if isinstance(original_model_output, List):
    +            for original_output, prepared_output in zip(original_model_output, prepared_model_output):
    +                np.testing.assert_array_equal(original_output, prepared_output, err_msg=err_msg)
    +        else:
    +            np.testing.assert_array_equal(original_model_output, prepared_model_output, err_msg=err_msg)
    +        _logger.debug("Outputs of prepared model and original model match")
    +
    +        _logger.info("Prepared model verified")
    +
    +
    +
    +[docs] +def prepare_model(original_model: tf.keras.Model, + input_layer: Union[tf.keras.layers.InputLayer, List[tf.keras.layers.InputLayer]] = None) \ + -> tf.keras.Model: + """ + This function prepares a Keras model before continuing on with AIMET. Specifically, it will convert the model into + a purely Functional API model and copy over the original models weights. + + :param original_model: The original model to be prepared + :param input_layer: The input layer to be used for the new model. By default, the input layer is set to None. If the + beginning portion of the model is subclassed, then the input layer must be passed in. + :return: The prepared model if needed, or the original model + """ + + # Initial check to see if preparing model is necessary + # pylint: disable=protected-access + if not _KerasModelPreparer._model_has_nested_layers(original_model) and \ + not _KerasModelPreparer._inherits_from_keras_model(original_model): + _logger.info("Model does not contain any nested layers. " + "Returning original model after going through " + "'replace_separable_conv_with_depthwise_pointwise' and 'replace_relu6_with_relu.") + custom_objects = _KerasModelPreparer._get_models_custom_objects(original_model) + prepared_model, _ = replace_relu6_with_relu(original_model, custom_objects=custom_objects) + prepared_model, _ = replace_separable_conv_with_depthwise_pointwise(prepared_model, + custom_objects=custom_objects) + return prepared_model + + keras_model_preparer = _KerasModelPreparer(original_model, input_layer=input_layer) + + keras_model_preparer.prepare_model() + + return keras_model_preparer.prepared_model
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_tensorflow/keras/quant_analyzer.html b/releases/2.0.0/_modules/aimet_tensorflow/keras/quant_analyzer.html new file mode 100644 index 0000000..9f27325 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_tensorflow/keras/quant_analyzer.html @@ -0,0 +1,965 @@ + + + + + + + + aimet_tensorflow.keras.quant_analyzer - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_tensorflow.keras.quant_analyzer

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +"""Quant Analyzer"""
    +import os
    +from collections import OrderedDict, defaultdict
    +from typing import Dict, List, Tuple
    +
    +import tensorflow as tf
    +
    +from aimet_common.defs import QuantScheme
    +from aimet_common.quant_analyzer import export_per_layer_sensitivity_analysis_plot, save_json, \
    +    create_and_export_min_max_ranges_plot, export_stats_histogram_plot, export_per_layer_mse_plot
    +from aimet_common.utils import CallbackFunc, AimetLogger, Spinner
    +from aimet_tensorflow.keras.batch_norm_fold import fold_all_batch_norms
    +from aimet_tensorflow.keras.graphsearchtuils import GraphSearchUtils
    +from aimet_tensorflow.keras.quant_sim.qc_quantize_wrapper import QcQuantizeWrapper
    +from aimet_tensorflow.keras.quant_sim.tensor_quantizer import TensorQuantizer
    +from aimet_tensorflow.keras.quantsim import QuantizationSimModel
    +from aimet_tensorflow.keras.utils.quantizer_utils import get_enabled_activation_quantizers, enable_disable_quantizers, \
    +    get_enabled_param_quantizers
    +
    +_logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.Quant)
    +
    +
    +def _sort_quant_wrappers_based_on_occurrence(sim: QuantizationSimModel) -> Dict[str, QcQuantizeWrapper]:
    +    """
    +    Sort quant wrappers based on occurrence for given quantsim model.
    +
    +    :param sim: Quantsim model.
    +    :return: Ordered dictionary which maps wrapped layer name to quant wrapper.
    +    """
    +    sorted_quant_wrappers_dict = OrderedDict()
    +    for wrapper in sim.model.layers:
    +        if not isinstance(wrapper, QcQuantizeWrapper):
    +            continue
    +
    +        sorted_quant_wrappers_dict[wrapper.original_layer.name] = wrapper
    +
    +    return sorted_quant_wrappers_dict
    +
    +
    +def _get_enabled_quantizers(sorted_quant_wrappers: Dict[str, QcQuantizeWrapper]) -> \
    +        Dict[QcQuantizeWrapper, List[TensorQuantizer]]:
    +    """
    +    For given sorted quant wrappers dict, get enabled quantizers.
    +
    +    :param sorted_quant_wrappers: Dictionary containing quant wrappers sorted based on occurrence.
    +    :return: Dictionary which maps a quant wrapper to a list of enabled quantizers in it.
    +    """
    +    enabled_quant_wrappers = defaultdict(list)
    +
    +    for quant_wrapper in sorted_quant_wrappers.values():
    +        for quantizer in quant_wrapper.param_quantizers:
    +            if quantizer.is_enabled():
    +                enabled_quant_wrappers[quant_wrapper].append(quantizer)
    +
    +        for quantizer in quant_wrapper.output_quantizers:
    +            if quantizer.is_enabled():
    +                enabled_quant_wrappers[quant_wrapper].append(quantizer)
    +
    +        for quantizer in quant_wrapper.input_quantizers:
    +            if quantizer.is_enabled():
    +                enabled_quant_wrappers[quant_wrapper].append(quantizer)
    +
    +    return enabled_quant_wrappers
    +
    +
    +def _get_output_of_intermediate_layer(model: tf.keras.Model,
    +                                      input_tensor: tf.Tensor,
    +                                      layer_index: int) -> tf.Tensor:
    +    """
    +    Return output tensor from model extracted up to target intermediate layer
    +
    +    :param model: tf.keras.Model
    +    :param input_tensor: Input tensor to feed
    +    :param layer_index: Index of layer
    +    :return: Output tensor from intermediate layer
    +    """
    +    layer_output = model.get_layer(index=layer_index).output
    +    extracted_model = tf.keras.Model(inputs=model.inputs, outputs=layer_output)
    +
    +    return extracted_model(input_tensor)
    +
    +
    +
    +[docs] +class QuantAnalyzer: + """ + QuantAnalyzer tool provides + + 1) model sensitivity to weight and activation quantization + 2) per layer sensitivity analysis + 3) per layer encoding (min - max range) + 4) per PDF analysis and + 5) per layer MSE analysis + """ + + def __init__(self, + model: tf.keras.Model, + forward_pass_callback: CallbackFunc, + eval_callback: CallbackFunc): + """ + :param model: FP32 model to analyze for quantization. + :param forward_pass_callback: A callback function for model calibration that simply runs + forward passes on the model to compute encoding (delta/offset). This + callback function should use representative data and should be subset of + entire train/validation dataset (~1000 images/samples). + :param eval_callback: A callback function for model evaluation that determines model + performance. This callback function is expected to return scalar value + representing the model performance evaluated against entire test/evaluation dataset. + """ + if not isinstance(forward_pass_callback, CallbackFunc): + raise ValueError('forward_pass_callback and its argument(s) are not encapsulated by CallbackFunc class.') + if not isinstance(eval_callback, CallbackFunc): + raise ValueError('eval_callback and its argument(s) are not encapsulated by CallbackFunc class.') + + self._model = model + self._forward_pass_callback = forward_pass_callback + self._eval_callback = eval_callback + self._unlabeled_dataset = None + self._num_batches = None + + # pylint: disable=unused-argument, no-self-use +
    +[docs] + def analyze(self, + quant_scheme: QuantScheme = QuantScheme.post_training_tf_enhanced, + rounding_mode: str = "nearest", + default_param_bw: int = 8, + default_output_bw: int = 8, + config_file: str = None, + results_dir: str = "./tmp/"): + """ + Analyze model for quantization and point out sensitive parts/hotspots of the model by performing + 1) model sensitivity to quantization, + 2) perform per layer sensitivity analysis by enabling and disabling quant wrappers, + 3) export per layer encodings min - max ranges, + 4) export per layer statistics histogram (PDF) when quant scheme is TF-Enhanced, + 5) per layer MSE analysis + + :param quant_scheme: Quantization scheme. Supported values are + QuantScheme.post_training_tf or QuantScheme.post_training_tf_enhanced. + :param rounding_mode: The round scheme to used. One of: 'nearest' or 'stochastic', defaults to 'nearest' + :param default_param_bw: Default bitwidth (4-31) to use for quantizing layer parameters. + :param default_output_bw: Default bitwidth (4-31) to use for quantizing layer inputs and outputs. + :param config_file: Path to configuration file for model quantizers. + :param results_dir: Directory to save the results. + """ + results_dir = os.path.abspath(results_dir) + os.makedirs(results_dir, exist_ok=True) + + sim = self._create_quantsim_and_encodings(quant_scheme, + rounding_mode, + default_param_bw, + default_output_bw, + config_file) + + # Check model sensitivity to weight and activation quantization individually. + self.check_model_sensitivity_to_quantization(sim, default_param_bw, default_output_bw) + + # Perform per layer analysis by enabling each quant wrapper (OPTION-1). + self.perform_per_layer_analysis_by_enabling_quant_wrappers(sim, results_dir) + + # Perform per layer analysis by disabling each quant wrapper (OPTION-2). + self.perform_per_layer_analysis_by_disabling_quant_wrappers(sim, results_dir) + + # Export encoding min-max range. + self.export_per_layer_encoding_min_max_range(sim, results_dir) + + # Export PDF of statistics + if quant_scheme == QuantScheme.post_training_tf_enhanced: + self.export_per_layer_stats_histogram(sim, results_dir) + + # Export per layer MSE loss between fp32 and quantized output activations. + if self._unlabeled_dataset and self._num_batches: + self.export_per_layer_mse_loss(sim, results_dir)
    + + + def _create_quantsim_and_encodings(self, + quant_scheme: QuantScheme, + rounding_mode: str, + default_param_bw: int, + default_output_bw: int, + config_file: str) -> QuantizationSimModel: + """ + Create Quantsim and compute encodings. + + :param quant_scheme: Quantization scheme. + :param rounding_mode: The round scheme to used. One of: 'nearest' or 'stochastic', defaults to 'nearest' + :param default_param_bw: Default bitwidth (4-31) to use for quantizing layer parameters. + :param default_output_bw: Default bitwidth (4-31) to use for quantizing layer inputs and outputs. + :param config_file: Path to configuration file for model quantizers. + :return: Quantsim model. + """ + _, self._model = fold_all_batch_norms(self._model) # pylint: disable=attribute-defined-outside-init + sim = QuantizationSimModel(self._model, + quant_scheme=quant_scheme, + rounding_mode=rounding_mode, + default_output_bw=default_output_bw, + default_param_bw=default_param_bw, + config_file=config_file) + + sim.compute_encodings(forward_pass_callback=self._forward_pass_callback.func, + forward_pass_callback_args=self._forward_pass_callback.args) + + return sim + +
    +[docs] + def check_model_sensitivity_to_quantization(self, + sim: QuantizationSimModel, + default_param_bw: int, + default_output_bw: int): + """ + Perform the sensitivity analysis to weight and activation quantization + individually. + + :param sim: Quantsim model. + :param default_param_bw: Default bitwidth (4-31) to use for quantizing layer parameters. + :param default_output_bw: Default bitwidth (4-31) to use for quantizing layer inputs and outputs. + :return: FP32 eval score, weight-quantized eval score, act-quantized eval score. + """ + fp32_eval_score = self._eval_model(self._model) + _logger.info("FP32 eval score (W32A32): %f", fp32_eval_score) + + weight_quantized_eval_score = self._eval_weight_quantized_model(sim) + _logger.info("Weight-quantized eval score (W%dA32): %f", default_param_bw, + weight_quantized_eval_score) + + act_quantized_eval_score = self._eval_activation_quantized_model(sim) + _logger.info("Activation-quantized eval score (W32A%d): %f", default_output_bw, + act_quantized_eval_score)
    + + + def _eval_model(self, model: tf.keras.Model) -> float: + """ + Evaluate the model performance. + :param model: tf.keras.Model to be evaluated + :return: Scalar value representing model performance + """ + return self._eval_callback.func(model, self._eval_callback.args) + + def _eval_weight_quantized_model(self, sim: QuantizationSimModel) -> float: + """ + Evaluate weight quantized model performance. + For weight quantized model performance, disable enabled activation quantizers, measure + eval score and enable again. + + :param sim: Quantsim model. + :return: Quantized model performance. + """ + enabled_activation_quantizers = get_enabled_activation_quantizers(sim) + enable_disable_quantizers(enabled_activation_quantizers, enabled=False) + eval_score = self._eval_model(sim.model) + enable_disable_quantizers(enabled_activation_quantizers, enabled=True) + return eval_score + + def _eval_activation_quantized_model(self, sim: QuantizationSimModel) -> float: + """ + Evaluate activation quantized model performance. + For activation quantized model performance, disable enabled param quantizers, measure + eval score and enable again. + + :param sim: Quantsim model. + :return: Quantized model performance. + """ + enabled_param_quantizers = get_enabled_param_quantizers(sim) + enable_disable_quantizers(enabled_param_quantizers, enabled=False) + eval_score = self._eval_model(sim.model) + enable_disable_quantizers(enabled_param_quantizers, enabled=True) + return eval_score + +
    +[docs] + def perform_per_layer_analysis_by_enabling_quant_wrappers(self, + sim: QuantizationSimModel, + results_dir: str) -> Dict[str, float]: + """ + NOTE: Option 1 + + 1. All quant wrappers' parameters and activations quantizers are disabled. + 2. For every quant wrappers, based on occurrence: + i. Each quant wrapper's parameters and activations quantizers are enabled as per JSON config file and set to bit-width specified. + ii. Measure and record eval score on subset of dataset. + iii. Disable enabled quantizers in step i. + 3. Returns dictionary containing quant wrapper name and corresponding eval score. + + :param sim: Quantsim model. + :param results_dir: Directory to save the results. + :return: layer-wise eval score dictionary. dict[layer_name] = eval_score + """ + results_dir = os.path.abspath(results_dir) + os.makedirs(results_dir, exist_ok=True) + + _logger.info("\nOPTION-1:\nAll the quant wrappers are disabled.\n" + "Starting per-layer analysis by enabling quant wrappers as per config file.") + + layer_wise_eval_score_dict = self._perform_per_layer_analysis(sim, + disable_all_quantizers=True, + enabled_before=True, + enabled_after=False) + export_per_layer_sensitivity_analysis_plot(layer_wise_eval_score_dict, + results_dir, + title="per_layer_quant_enabled") + save_json(layer_wise_eval_score_dict, + results_dir, + title="per_layer_quant_enabled.json") + _logger.info("Exported per-layer quant analysis (enabled) plot.") + return layer_wise_eval_score_dict
    + + +
    +[docs] + def perform_per_layer_analysis_by_disabling_quant_wrappers(self, + sim: QuantizationSimModel, + results_dir: str) -> Dict[str, float]: + """ + NOTE: Option 2 + + 1. All quant wrappers' parameters and activations quantizers are enabled as per JSON config file and set to bit-width specified. + 2. For every quant wrappers, based on occurrence: + i. Each quant wrapper's parameters and activations quantizers are disabled. + ii. Measure and record eval score on subset of dataset. + iii. Enable disabled quantizers in step i. + 3. Returns dictionary containing quant wrapper name and corresponding eval score. + + :param sim: Quantsim model. + :param results_dir: Directory to save the results. + :return: layer wise eval score dictionary. dict[layer_name] = eval_score + """ + results_dir = os.path.abspath(results_dir) + os.makedirs(results_dir, exist_ok=True) + + _logger.info("\nOPTION-2:\nAll the quant wrappers are enabled as per config file.\n" + "Starting per-layer analysis by disabling quant wrappers.") + layer_wise_eval_score_dict = self._perform_per_layer_analysis(sim, + disable_all_quantizers=False, + enabled_before=False, + enabled_after=True) + export_per_layer_sensitivity_analysis_plot(layer_wise_eval_score_dict, + results_dir, + title="per_layer_quant_disabled") + save_json(layer_wise_eval_score_dict, + results_dir, + title="per_layer_quant_disabled.json") + _logger.info("Exported per-layer quant analysis (disabled) plot.") + return layer_wise_eval_score_dict
    + + + def _perform_per_layer_analysis(self, + sim: QuantizationSimModel, + disable_all_quantizers: bool, + enabled_before: bool, + enabled_after: bool) -> Dict[str, float]: + """ + Helper function for perform_per_layer_analysis_by_enabling_quant_wrappers() and + perform_per_layer_analysis_by_disabling_quant_wrappers() + + :param sim: Quantsim model. + :param disable_all_quantizers: Flag to disable all the quantizers before per-layer analysis. + :param enabled_before: Flag to set enabled for quantizers before computing encodings. + :param enabled_after: Flag to set enabled for quantizers after computing encodings. + :return: layer wise eval score dictionary. dict[layer_name] = eval_score. + """ + # Sorted quant wrappers based on occurrence. + # maps wrapped module name to a quant wrapper. + sorted_quant_wrappers = _sort_quant_wrappers_based_on_occurrence(sim) + + # quant wrappers and it's enabled quantizers. + # maps quant wrapper to a list of enabled quantizers in it. + enabled_quant_wrappers = _get_enabled_quantizers(sorted_quant_wrappers) + + if disable_all_quantizers: + for enabled_quantizers in enabled_quant_wrappers.values(): + enable_disable_quantizers(enabled_quantizers, enabled=False) + + eval_score_dict = {} + for name, quant_wrapper in sorted_quant_wrappers.items(): + if quant_wrapper in enabled_quant_wrappers: + enabled_quantizers = enabled_quant_wrappers[quant_wrapper] + enable_disable_quantizers(enabled_quantizers, enabled=enabled_before) + + # Record eval score. + eval_score_dict[name] = self._eval_model(sim.model) + _logger.debug("For layer: %s, the eval score is: %f", name, eval_score_dict[name]) + + enable_disable_quantizers(enabled_quantizers, enabled=enabled_after) + + if disable_all_quantizers: + for enabled_quantizers in enabled_quant_wrappers.values(): + enable_disable_quantizers(enabled_quantizers, enabled=True) + + return eval_score_dict + + # pylint: disable=no-self-use +
    +[docs] + def export_per_layer_encoding_min_max_range(self, + sim: QuantizationSimModel, + results_dir: str) -> Tuple[Dict, Dict]: + """ + Export encoding min and max range for all weights and activations. results_dir should have + html files in following format. + + -results_dir + -activations.html + -weights.html + + If per channel quantization(PCQ) is enabled then, + + -results_dir + -activations.html + -{wrapped_module_name}_{param_name}.html + + :param sim: Quantsim model. + :param results_dir: Directory to save the results. + :return: layer wise min-max range for weights and activations. + """ + min_max_ranges_dir = os.path.join(results_dir, "min_max_ranges") + + min_max_range_for_activations_dict = {} + min_max_range_for_weights_dict = {} + for quant_wrapper in sim.quant_wrappers(): + wrapped_layer_name = quant_wrapper.original_layer.name + + for index, quantizer in enumerate(quant_wrapper.input_quantizers): + if quantizer.is_enabled(): + name = f"{wrapped_layer_name}_input_{index}" + min_max_range_for_activations_dict[name] = (quantizer.encoding.min, quantizer.encoding.max) + + for index, quantizer in enumerate(quant_wrapper.output_quantizers): + if quantizer.is_enabled(): + name = f"{wrapped_layer_name}_output_{index}" + min_max_range_for_activations_dict[name] = (quantizer.encoding.min, quantizer.encoding.max) + + for quantizer in quant_wrapper.param_quantizers: + if quantizer.is_enabled(): + # Keras parameter name usually contains slash (/) and it can cause incorrect file path when saving + # Replace slash (/) with dash (-) to avoid it + quantizer_name = quantizer.name.replace("/", "-") + name = f"{wrapped_layer_name}_{quantizer_name}" + + if isinstance(quantizer.encoding, List): # per-channel + per_channel_encodings = {} + for index, encoding in enumerate(quantizer.encoding): + per_channel_encodings[f"{name}_{index}"] = (encoding.min, encoding.max) + min_max_range_for_weights_dict[name] = per_channel_encodings + else: # per-tensor + min_max_range_for_weights_dict[name] = (quantizer.encoding.min, quantizer.encoding.max) + + create_and_export_min_max_ranges_plot(min_max_range_for_weights_dict, + min_max_ranges_dir, + title="weights") + create_and_export_min_max_ranges_plot(min_max_range_for_activations_dict, + min_max_ranges_dir, + title="activations") + save_json(min_max_range_for_weights_dict, min_max_ranges_dir, title="weights.json") + save_json(min_max_range_for_activations_dict, min_max_ranges_dir, title="activations.json") + _logger.info("Exported per layer encodings min-max ranges plot(s).") + return min_max_range_for_weights_dict, min_max_range_for_activations_dict
    + + +
    +[docs] + def export_per_layer_stats_histogram(self, sim: QuantizationSimModel, results_dir: str) -> None: + """ + NOTE: Not to invoke when quantization scheme is not TF-Enhanced. + + Export histogram that represents a PDF of collected statistics by a quantizer for every + quant wrapper. After invoking this API, results_dir should have html files in following + format for every quantizers of quant wrappers. + + -results_dir + -activations_pdf + name_{input/output}_{index}.html + -weights_pdf + -name + param_name_{channel_index}.html + + :param sim: Quantsim model. + :param results_dir: Directory to save the results. + """ + weights_pdf_dir = os.path.join(results_dir, "weights_pdf") + activations_pdf_dir = os.path.join(results_dir, "activations_pdf") + + for quant_wrapper in sim.quant_wrappers(): + wrapped_layer_name = quant_wrapper.original_layer.name + + for index, quantizer in enumerate(quant_wrapper.input_quantizers): + if quantizer.encoding: + self._create_and_export_stats_histogram_plot(quantizer, activations_pdf_dir, + title=f"{wrapped_layer_name}_input_q{index}") + + for index, quantizer in enumerate(quant_wrapper.output_quantizers): + if quantizer.encoding: + self._create_and_export_stats_histogram_plot(quantizer, activations_pdf_dir, + title=f"{wrapped_layer_name}_output_q{index}") + + for quantizer in quant_wrapper.param_quantizers: + if quantizer.encoding: + # Keras parameter name usually contains slash (/) and it can cause incorrect file path when saving + # Replace slash (/) with dash (-) to avoid it + param_name = quantizer.name.replace("/", "-") + self._create_and_export_stats_histogram_plot(quantizer, + os.path.join(weights_pdf_dir, wrapped_layer_name), + title=f"{wrapped_layer_name}_{param_name}") + _logger.info("Exported per layer stats histogram plot(s).")
    + + + @staticmethod + def _create_and_export_stats_histogram_plot(quantizer: TensorQuantizer, + results_dir: str, + title: str) -> None: + """ + For given quantizer, create and export histogram (PDF) of statistics in html format. + + :param quantizer: Quantizer. + :param results_dir: Directory to save the results. + :param title: Title of the plot. + """ + os.makedirs(results_dir, exist_ok=True) + + histograms = quantizer.get_stats_histogram() + encodings = quantizer.encoding + if not isinstance(encodings, List): + encodings = [encodings] + + for index, (histogram, encoding) in enumerate(zip(histograms, encodings)): + export_stats_histogram_plot(histogram, encoding, results_dir, title=f"{title}_{index}") + +
    +[docs] + def export_per_layer_mse_loss(self, + sim: QuantizationSimModel, + results_dir: str) -> Dict[str, float]: + """ + NOTE: Need to pass same model input data through both fp32 and quantsim model to + tap output activations of each layer. + + Export MSE loss between fp32 and quantized output activations for each layer. + :param sim: Quantsim model. + :param results_dir: Directory to save the results. + :return layer wise MSE loss. dict[layer_name] = MSE loss. + """ + results_dir = os.path.abspath(results_dir) + os.makedirs(results_dir, exist_ok=True) + + mse_loss_dict = {} + with Spinner("Calculating per-layer MSE loss"): + for index, layer in enumerate(self._model.layers): + if isinstance(layer, tf.keras.layers.InputLayer) or \ + GraphSearchUtils.is_folded_batch_normalization(layer): + continue + + loss = self._compute_mse_loss(sim, index) + mse_loss_dict[layer.name] = loss + + export_per_layer_mse_plot(mse_loss_dict, + results_dir, + title="per_layer_mse_loss") + save_json(mse_loss_dict, results_dir, title="per_layer_mse_loss.json") + _logger.info("Exported per layer MSE loss plot.") + return mse_loss_dict
    + + + def _compute_mse_loss(self, + sim: QuantizationSimModel, + index: int) -> float: + """ + Compute MSE loss between fp32 and quantized output activations for each batch, add for + all the batches and return averaged mse loss. + + :param sim: Quantsim model. + :param index: Index of layer + :return: MSE loss between fp32 and quantized output activations. + """ + loss = 0.0 + total = 0 + mse = tf.keras.losses.MeanSquaredError() + for tensor in self._unlabeled_dataset.take(self._num_batches): + quantized_output = _get_output_of_intermediate_layer(sim.model, tensor, index) + fp32_output = _get_output_of_intermediate_layer(self._model, tensor, index) + + loss += mse(quantized_output, fp32_output).numpy() + total += tensor.shape[0] + + return loss / total + +
    +[docs] + def enable_per_layer_mse_loss(self, unlabeled_dataset: tf.data.Dataset, num_batches: int) -> None: + """ + Enable per layer MSE loss analysis. + + :param unlabeled_dataset: tf.data.Dataset provided as input to the model + and used to calculate mse loss + :param num_batches: Maximum number of batches to be used for MSE loss calculation + """ + self._unlabeled_dataset = unlabeled_dataset + self._num_batches = num_batches
    +
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_tensorflow/keras/quantsim.html b/releases/2.0.0/_modules/aimet_tensorflow/keras/quantsim.html new file mode 100644 index 0000000..bbb2c6f --- /dev/null +++ b/releases/2.0.0/_modules/aimet_tensorflow/keras/quantsim.html @@ -0,0 +1,1203 @@ + + + + + + + + aimet_tensorflow.keras.quantsim - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_tensorflow.keras.quantsim

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +""" Quantsim for Keras """
    +from __future__ import annotations
    +
    +import contextlib
    +from dataclasses import dataclass
    +import json
    +import os
    +from typing import Union, Dict, Tuple, Optional, List
    +
    +import tensorflow as tf
    +from aimet_common import libpymo
    +
    +from aimet_common.defs import QuantScheme, QuantizationDataType
    +from aimet_common.utils import AimetLogger, save_json_yaml
    +from aimet_common import quantsim
    +from aimet_common.quantsim import extract_global_quantizer_args
    +from aimet_tensorflow.keras.connectedgraph import ConnectedGraph
    +from aimet_tensorflow.keras.graphsearchtuils import GraphSearchUtils
    +from aimet_tensorflow.keras.quant_sim.qc_quantize_wrapper import QcQuantizeWrapper, QuantizerSettings
    +from aimet_tensorflow.keras.quant_sim.qc_mha_wrapper import QcQuantizableMultiHeadAttention
    +from aimet_tensorflow.keras.rnn.qc_quant_LSTM import QuantizedLSTM
    +from aimet_tensorflow.keras.quant_sim.tensor_quantizer import TensorQuantizer, ActivationTensorQuantizer, \
    +    ParamPerTensorQuantizer, StaticGridPerChannelQuantizer, ParamPerChannelQuantizer
    +from aimet_tensorflow.keras.quantsim_config.quantsim_config import QuantSimConfigurator, INPUT_QUANTIZERS, \
    +    OUTPUT_QUANTIZERS, PARAM_QUANTIZERS
    +from aimet_tensorflow.keras.utils.common import convert_h5_model_to_pb_model
    +
    +from aimet_tensorflow.keras.defs import AxisHandling
    +import aimet_tensorflow.keras.utils.common as keras_common_utils
    +
    +_logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.Quant)
    +
    +unquantizable_modules = (tf.keras.layers.InputLayer, QcQuantizeWrapper)
    +substitutable_modules = {
    +    tf.keras.layers.MultiHeadAttention: QcQuantizableMultiHeadAttention,
    +    tf.keras.layers.LSTM: QuantizedLSTM
    +}
    +
    +
    +@dataclass
    +class QuantizationSimModelParams:
    +    """
    +    Data class that holds parameters for QuantizationSimModel. Used specifically to rebuild after converting to TF frozen pb
    +    """
    +    quant_scheme: Union[QuantScheme, str] = 'tf_enhanced'
    +    rounding_mode: str = 'nearest'
    +    default_output_bw: int = 8
    +    default_param_bw: int = 8
    +    in_place: bool = False
    +    config_file: str = None
    +    default_data_type: QuantizationDataType = QuantizationDataType.int
    +
    +
    +# pylint: disable=too-many-ancestors
    +# pylint: disable=too-many-instance-attributes
    +
    +[docs] +class QuantizationSimModel(tf.keras.Model): + """ + Implements mechanism to add quantization simulations ops to a model. This allows for off-target simulation of + inference accuracy. Also allows the model to be fine-tuned to counter the effects of quantization. + """ + + # pylint: disable=too-many-arguments + # pylint: disable=unused-argument + def __init__(self, model, quant_scheme: Union[QuantScheme, str] = 'tf_enhanced', rounding_mode: str = 'nearest', + default_output_bw: int = 8, default_param_bw: int = 8, in_place: bool = False, + config_file: str = None, default_data_type: QuantizationDataType = QuantizationDataType.int): + """ + :param model: Model to quantize + :param quant_scheme: Quantization Scheme, currently supported schemes are post_training_tf and + post_training_tf_enhanced, defaults to post_training_tf_enhanced + :param rounding_mode: The round scheme to used. One of: 'nearest' or 'stochastic', defaults to 'nearest'. + :param default_output_bw: bitwidth to use for activation tensors, defaults to 8 + :param default_param_bw: bitwidth to use for parameter tensors, defaults to 8 + :param in_place: If True, then the given 'model' is modified in-place to add quant-sim nodes. + Only suggested use of this option is when the user wants to avoid creating a copy of the model + :param config_file: Path to a config file to use to specify rules for placing quant ops in the model + :param default_data_type: Default data type to use for quantizing all layer parameters. + Possible options are QuantizationDataType.int and QuantizationDataType.float. + Note that the mode default_data_type=QuantizationDataType.float is only supported with + default_output_bw=16 and default_param_bw=16 + """ + super().__init__() + + self._model_without_wrappers = model + if not in_place: + self._model_without_wrappers = tf.keras.models.clone_model(model) + n_weights = len(self._model_without_wrappers.weights) + self._model_without_wrappers.set_weights(model.get_weights()[:n_weights]) + self._layer_name_to_quant_wrapper = {} + self._substituted_layer = {} # to hold the substituted layers + self._validate_model() + self.connected_graph = ConnectedGraph(self._model_without_wrappers) + self._quantsim_configurator = self._initialize_quantsim_configurator(quant_scheme, rounding_mode, + default_output_bw, default_param_bw, + default_data_type, config_file) + self.quant_scheme = quant_scheme + self._percentile_value = 100 # default percentile value + self.per_channel_quantization_enabled = self._quantsim_configurator.per_channel_quantization_flag + self.model = self._add_quantization_wrappers(quant_scheme, rounding_mode, + default_output_bw, default_param_bw, default_data_type) + self.quant_args = extract_global_quantizer_args(quant_scheme, self._quantsim_configurator) + + self._params = QuantizationSimModelParams(quant_scheme, rounding_mode, default_output_bw, default_param_bw, + in_place, config_file, default_data_type) + + def _validate_model(self): + """ + Check that model is appropriate for quantsim. + """ + multiple_inbound_node_layers = [] + + for layer in self._model_without_wrappers.layers: + if len(layer.inbound_nodes) > 1: + multiple_inbound_node_layers.append(layer.name) + + if multiple_inbound_node_layers: + error_msg = (f'Layers with more than one inbound nodes are unsupported. This may occur if a layer is ' + f'reused multiple times in the model definition.\n' + f'Layers with multiple inbound nodes: {multiple_inbound_node_layers}') + _logger.error(error_msg) + raise NotImplementedError(error_msg) + + sep_conv_found = self.check_separable_conv(self._model_without_wrappers) + if sep_conv_found: + # Raising an assertion error incase there's SeparableConv2D in the model because in this case we have two sets of weights: Depthwise + # and Pointwise. For depthwise kernels, LAST TWO AXIS should be considered and for pointwise kernels LAST AXIS + # should be considered, which is not handled here. Running model preparer beforehand will resolve this as there the + # SeparableConv2D is splitted into two layers Depthwise and Pointwise seperately. + raise AssertionError("SeparableConv2D found in the model. Please run model preparer before calling QuantizationSimModel") + + def check_separable_conv(self, model: tf.keras.models.Model | tf.keras.Sequential) -> bool: + """ + Checks for SeparableConv2D layer in the model + :param model: Keras Model + :return: Boolean value, True if SeperableConv layer is found else False + """ + for layer in model.layers: + if isinstance(layer, tf.keras.Sequential): + if self.check_separable_conv(layer): + return True + elif isinstance(layer, tf.keras.layers.SeparableConv2D): + return True + return False + + def _get_quantizer_list(self) -> Tuple[List, List, List]: + """ + Method to provide a list of input, output and parameter quantizers + :return: Three lists containing input, paramater and output quantizers respectively + """ + input_quantizers = [] + parameter_quantizers = [] + output_quantizers = [] + + for wrapper in self.quant_wrappers(): + for quantizer in wrapper.input_quantizers: + input_quantizers.append(quantizer) + + for quantizer in wrapper.param_quantizers: + parameter_quantizers.append(quantizer) + + for quantizer in wrapper.output_quantizers: + output_quantizers.append(quantizer) + + return input_quantizers, parameter_quantizers, output_quantizers + + def set_percentile_value(self, percentile_value: float): + """ + Set the percentile value to be used while computing encodings for quantizers having percentile quant scheme. + + :param percentile_value: Percentile value to be set to + """ + if percentile_value < 90 or percentile_value > 100: + raise ValueError("Percentile value must be in range [90, 100]") + self._percentile_value = percentile_value + + # Set the percentile value to the activation quantizers + input_quantizers, _, output_quantizers = self._get_quantizer_list() + for quantizer in input_quantizers + output_quantizers: + if quantizer.quant_scheme == QuantScheme.post_training_percentile: + quantizer.set_percentile_value(self._percentile_value) + + def _initialize_quantsim_configurator(self, quant_scheme: Union[QuantScheme, str], rounding_mode: str, + default_output_bw: int, default_param_bw: int, + default_data_type: QuantizationDataType = QuantizationDataType.int, + config_file: str = None) -> QuantSimConfigurator: + """ + Initialize quantsim configurator + :param quant_scheme: Quantization Scheme + :param rounding_mode: The round scheme to used + :param default_output_bw: bitwidth to use for activation tensors + :param default_param_bw: bitwidth to use for parameter tensors + :param default_data_type: data type to use for the parameter tensors + :param config_file: Path to a config file to use to specify rules for placing quant ops in the model + :return: QuantSimConfigurator + """ + return QuantSimConfigurator(self.connected_graph, quant_scheme, rounding_mode, + default_output_bw, default_param_bw, default_data_type, config_file) + + def _add_quantization_wrappers(self, quant_scheme, rounding_mode, + default_output_bw, default_param_bw, default_data_type): + """ + Add quantization wrappers to the model and return a new model with the wrappers inserted. + :param quant_scheme: Quantization scheme to use + :param rounding_mode: Rounding mode to use + :param default_output_bw: Default bitwidth for activation quantizers + :param default_param_bw: Default bitwidth for param quantizers + :param default_data_type: data type to use for param quantizers + """ + + def wrap_layer(layer) -> tf.keras.layers.Layer: + """ + Function to wrap layers with QcQuantizeWrappers, used by keras clone_model() + :param layer: Layer to wrap + :return: Wrapped layer, or original layer if layer is not to be wrapped + """ + if isinstance(layer, tuple(substitutable_modules.keys())): + new_class = substitutable_modules[type(layer)] + config = layer.get_config() + config["copy_source_weights"] = layer.get_weights() + + if isinstance(layer, tf.keras.layers.LSTM): + if isinstance(self._model_without_wrappers, tf.keras.Sequential): + config["is_sequential_model"] = True + + # pylint: disable=protected-access + if self._quantsim_configurator._layer_to_config_dict[layer]["is_input_quantized"]["setting"]: + config["is_input_quantized"] = True + config["quant_scheme"] = quant_scheme + config["rounding_mode"] = rounding_mode + config["default_output_bw"] = default_output_bw + config["default_param_bw"] = default_param_bw + config["default_data_type"] = default_data_type + + wrapped_layer = new_class.from_config(config) + self._substituted_layer[layer] = wrapped_layer + return wrapped_layer + + if isinstance(layer, tf.keras.Sequential): + return tf.keras.models.clone_model(layer, clone_function=wrap_layer) + + if isinstance(layer, unquantizable_modules) or layer.submodules: + return layer + + activation_quant_settings = QuantizerSettings(default_output_bw, default_data_type, rounding_mode, + quant_scheme, False, False, False) + param_quant_settings = QuantizerSettings(default_param_bw, default_data_type, rounding_mode, + quant_scheme, False, False, False) + + input_quantizers, output_quantizers, param_quantizers = self._get_quantizers_by_layer(layer) + wrapper = QcQuantizeWrapper(layer, activation_quant_settings, param_quant_settings, + num_inputs=len(layer.inbound_nodes[0].keras_inputs), + input_quantizers=input_quantizers, + output_quantizers=output_quantizers, + param_quantizers=param_quantizers, + per_channel_quantization_enabled=self.per_channel_quantization_enabled) + self._layer_name_to_quant_wrapper[layer.name] = wrapper + return wrapper + + return tf.keras.models.clone_model(self._model_without_wrappers, clone_function=wrap_layer) + + def _get_quantizers_by_layer(self, layer: tf.keras.layers.Layer) -> Tuple[Optional[ActivationTensorQuantizer], + Optional[ActivationTensorQuantizer], + Union[ParamPerTensorQuantizer, + ParamPerChannelQuantizer]]: + """ + Get input/output/param quantizers from quantizers dictionary or initialize quantizers if layer is not found + :param layer: Target layer + :return: tuple of input, output, param quantizers + """ + quantizers_dict = self._quantsim_configurator.get_quantizers_dict(layer) + if quantizers_dict is None: + _logger.warning("%s not found in quantizers dict, will generate quantizers automatically", layer.name) + input_quantizers = None + output_quantizers = None + param_quantizers = None + else: + input_quantizers = quantizers_dict.get(INPUT_QUANTIZERS) + output_quantizers = quantizers_dict.get(OUTPUT_QUANTIZERS) + param_quantizers = quantizers_dict.get(PARAM_QUANTIZERS) + + return input_quantizers, output_quantizers, param_quantizers + + @staticmethod + def _quantizer_to_name_tuple(quantizers: List[TensorQuantizer]) -> Tuple[Optional[List[str]]]: + """ + Converts a list of quantizers to a tuple of quantizer names + :param quantizers: quantizers + :return: tuple of quantizer names + """ + quant_list = [] + if not quantizers: + return None + + for quantizer in quantizers: + quant_list.append(quantizer.name) + return tuple(quant_list) + + def get_quantizer_name_by_layer(self, layer: tf.keras.layers.Layer) -> Tuple[Optional[List[str]], + Optional[List[str]], + Optional[List[str]]]: + """ + Get the names of input, output and param quantizers + :param layer: the keras layer + :return: Tuple of quantizer names + """ + input_quantizers, output_quantizers, param_quantizers = self._get_quantizers_by_layer(layer) + output_quantizers_names = self._quantizer_to_name_tuple(output_quantizers) + input_quantizers_names = self._quantizer_to_name_tuple(input_quantizers) + parameter_quantizers_names = self._quantizer_to_name_tuple(param_quantizers) + + return input_quantizers_names, output_quantizers_names, parameter_quantizers_names + + def _disable_quantizers_in_folded_batchnorm(self): + """ + Disable input/output/param quantizers if layer is folded batch normalization + """ + for quantsim_wrapper in self._layer_name_to_quant_wrapper.values(): + if GraphSearchUtils.is_folded_batch_normalization(quantsim_wrapper.original_layer): + for q in quantsim_wrapper.input_quantizers: + q.disable() + for q in quantsim_wrapper.output_quantizers: + q.disable() + for q in quantsim_wrapper.param_quantizers: + q.disable() + + @staticmethod + def _get_encoding_dict_for_quantizer(quantizer: TensorQuantizer) -> Union[List[Dict[str, Union[str, int, float]]], + Dict[str, Union[str, int, float]]]: + """ + Get encoding dict for a tensor quantizer. + + :param quantizer: Quantizer to get encoding info from + :return: Dictionary or List of dictionaries containing encodings info for the tensor quantizer + """ + if not isinstance(quantizer, ParamPerChannelQuantizer) or quantizer.data_type == QuantizationDataType.float: + quantizer_encodings = [quantizer.encoding] + else: + quantizer_encodings = quantizer.encoding + return [ + { + 'min': encoding.min, + 'max': encoding.max, + 'scale': encoding.delta, + 'offset': int(encoding.offset), + 'bitwidth': encoding.bw, + 'is_symmetric': str(quantizer.is_symmetric), + 'dtype': 'int' + } if quantizer.data_type == QuantizationDataType.int + else {'dtype': 'float', 'bitwidth': int(quantizer.bitwidth)} + for encoding in quantizer_encodings + ] + + def get_encodings_dict(self) -> Dict[str, Union[str, Dict]]: + """ + Get encodings dict containing all activation and parameter encodings info in the model + :return: Dictionary containing all activation and parameter encodings info in the model + """ + # pylint: disable=protected-access, too-many-branches + model_input_tensor_names = [inp.name for inp in self.model.inputs] + activation_encodings = {} + param_encodings = {} + for wrapper in self.quant_wrappers(): + for idx, input_quantizer in enumerate(wrapper.input_quantizers): + if input_quantizer.is_encoding_valid() or input_quantizer.data_type == QuantizationDataType.float: + # because dense layers in quantizable MHA are not explicitly sublayers, they don't have their + # inbound_nodes parameter populated, so the name of the quantizer is used instead + if not wrapper._layer_to_wrap.inbound_nodes: + tensor_name = wrapper.name + "/" + input_quantizer.name + ":0" + else: + tensor_name = wrapper._layer_to_wrap.inbound_nodes[0].keras_inputs[idx].name + encoding_dict = self._get_encoding_dict_for_quantizer(input_quantizer) + if tensor_name in model_input_tensor_names: + tensor_name += ":0" + activation_encodings[tensor_name] = encoding_dict + for idx, param_quantizer in enumerate(wrapper.param_quantizers): + if param_quantizer.is_encoding_valid() or param_quantizer.data_type == QuantizationDataType.float: + param_name = wrapper._layer_to_wrap.weights[idx].name + encoding_dict = self._get_encoding_dict_for_quantizer(param_quantizer) + param_encodings[param_name] = encoding_dict + for idx, output_quantizer in enumerate(wrapper.output_quantizers): + if output_quantizer.is_encoding_valid() or output_quantizer.data_type == QuantizationDataType.float: + # because dense layers in quantizable MHA are not explicitly sublayers, they don't have their + # inbound_nodes parameter populated, so the name of the quantizer is used instead + if not wrapper._layer_to_wrap.inbound_nodes: + tensor_name = wrapper.name + ":0" + elif isinstance(wrapper._layer_to_wrap.output, List): + tensor_name = wrapper._layer_to_wrap.output[idx].name + else: + tensor_name = wrapper._layer_to_wrap.output.name + encoding_dict = self._get_encoding_dict_for_quantizer(output_quantizer) + activation_encodings[tensor_name] = encoding_dict + return { + 'version': quantsim.encoding_version, + 'activation_encodings': activation_encodings, + 'param_encodings': param_encodings, + 'quantizer_args': self.quant_args if hasattr(self, "quant_args") else {} + } + +
    +[docs] + def compute_encodings(self, forward_pass_callback, forward_pass_callback_args): + """ + Computes encodings for all quantization sim nodes in the model. + + :param forward_pass_callback: A callback function that is expected to run forward passes on a model. + This callback function should use representative data for the forward pass, so the calculated encodings work for all data samples. + :param forward_pass_callback_args: These argument(s) are passed to the forward_pass_callback as-is. + Up to the user to determine the type of this parameter. E.g. could be simply an integer representing the number of data samples to use. + Or could be a tuple of parameters or an object representing something more complex. + """ + ops_with_invalid_encodings = [] + self._compute_and_set_parameter_encodings(ops_with_invalid_encodings) + + self._set_op_mode_parameters(libpymo.TensorQuantizerOpMode.quantizeDequantize) + + forward_pass_callback(self.model, forward_pass_callback_args) + for quant_wrapper in self.quant_wrappers(): + quant_wrapper.compute_encoding(ops_with_invalid_encodings) + + op_mode = self._param_op_mode_after_analysis(self.quant_scheme) + + self._set_op_mode_parameters(op_mode) + + if ops_with_invalid_encodings: + _logger.info('The following quantizers did not have valid encodings and have been set to passThrough mode: ' + '%s', ops_with_invalid_encodings) + _logger.info('This can be due to the quantizers not having been evaluated during the forward pass in ' + 'compute encodings. Evaluation is required to collect statistics needed to compute valid ' + 'encodings.\n' + 'As a result, the quantizers have been set to passThrough mode, meaning no quantization noise ' + 'will be simulated for these ops if they are evaluated in the future.\n' + 'If this is not desired, amend the forward pass to evaluate tensors which require these ops ' + 'to be evaluated, and recompute encodings.')
    + + + def _set_op_mode_parameters(self, op_mode: libpymo.TensorQuantizerOpMode): + """ + Sets quant mode for parameters and if the encodings are invalid, then adds those wrappers + to wrappers_with_invalid_encodings + :param op_mode: Quant mode to set to + """ + + for quantizer_info in self.quant_wrappers(): + for param_quantizer in quantizer_info.param_quantizers: + if param_quantizer.is_enabled(): + param_quantizer.quant_mode = op_mode + + @staticmethod + @contextlib.contextmanager + def _set_encoding_version_to_0_6_1(): + assert quantsim.encoding_version in {'0.6.1', '1.0.0'} + if quantsim.encoding_version == '1.0.0': + _logger.info('Exporting to encoding version 1.0.0 is not yet supported. Exporting using version 0.6.1 ' + 'instead.') + old_encoding_version = quantsim.encoding_version + quantsim.encoding_version = '0.6.1' + + yield + + quantsim.encoding_version = old_encoding_version + +
    +[docs] + def export(self, path, filename_prefix, custom_objects=None, convert_to_pb=True): + """ + This method exports out the quant-sim model so it is ready to be run on-target. Specifically, the following are saved + + 1. The sim-model is exported to a regular Keras model without any simulation ops + 2. The quantization encodings are exported to a separate JSON-formatted file that can then be imported by the on-target runtime (if desired) + + :param path: path where to store model pth and encodings + :param filename_prefix: Prefix to use for filenames of the model pth and encodings files + :param custom_objects: If there are custom objects to load, Keras needs a dict of them to map them + """ + with self._set_encoding_version_to_0_6_1(): + model_path = os.path.join(path, filename_prefix) + + #TF Version 2.4 has bug i.e. save() in tf format don't work for unrolled LSTM. + for layer in self._model_without_wrappers.layers: + if isinstance(layer, tf.keras.layers.LSTM): + break + else: + self._model_without_wrappers.save(model_path) + + self._model_without_wrappers.save(model_path + '.h5', save_format='h5') + + # Conversion of saved h5 model to pb model for consumption by SNPE/QNN + try: + if convert_to_pb: + convert_h5_model_to_pb_model(f'{model_path}.h5', custom_objects=custom_objects) + except ValueError: + _logger.error("Could not convert h5 to frozen pb. " + "Please call export() again with custom_objects defined.") + raise + finally: + encodings_dict = self.get_encodings_dict() + encoding_file_path = os.path.join(path, filename_prefix + '.encodings') + save_json_yaml(encoding_file_path, encodings_dict)
    + + + def _compute_and_set_parameter_encodings(self, ops_with_invalid_encodings: List): + # pylint: disable=too-many-nested-blocks + for quantizer_wrapper in self.quant_wrappers(): + for idx, param_quantizer in enumerate(quantizer_wrapper.param_quantizers): + if param_quantizer.is_enabled() and param_quantizer.data_type == QuantizationDataType.int: + # 0th input to our quant wrapper is the tensor being quantized + weight_tensor = quantizer_wrapper.original_layer.get_weights()[idx] + + # Per-channel + if isinstance(param_quantizer, StaticGridPerChannelQuantizer): + for index, tensor_quantizer in enumerate(param_quantizer.tensor_quantizer): + if param_quantizer.axis_handling == AxisHandling.LAST_TWO_AXES.value: + last_two_axes_combined_shape = list(weight_tensor.shape[:-2]) + [-1] + channel_slice = weight_tensor.reshape(*last_two_axes_combined_shape) + channel_slice = channel_slice.take(index, channel_slice.ndim - 1) + elif isinstance(quantizer_wrapper.original_layer, tf.keras.layers.Conv2DTranspose): + if weight_tensor.ndim == 4: + channel_slice = weight_tensor.take(index, weight_tensor.ndim - 2) + else: + # For bias in Transpose layers + channel_slice = weight_tensor.take(index, weight_tensor.ndim - 1) + else: + channel_slice = weight_tensor.take(index, weight_tensor.ndim - 1) + tensor_quantizer.updateStats(channel_slice, False) + + # Per-tensor + else: + tensor_quantizer = param_quantizer.tensor_quantizer + tensor_quantizer.updateStats(weight_tensor, False) + + param_quantizer.compute_encoding(ops_with_invalid_encodings) + + def set_and_freeze_param_encodings(self, encoding_path: str): + """ + Set and freeze parameter encodings from encodings JSON file + :param encoding_path: path from where to load parameter encodings file + """ + # Load parameter encodings file + with open(encoding_path) as json_file: + param_encodings = json.load(json_file) + + for quant_wrapper in self.quant_wrappers(): + quant_wrapper.set_and_freeze_param_encoding(param_encodings) + + # pylint: disable=too-many-nested-blocks +
    +[docs] + def load_encodings_to_sim(self, encoding_file_path: str): + """ + Loads the saved encodings to quant sim model + + :param encoding_file_path: path from where to load encodings file + :return: + """ + # pylint: disable=protected-access, too-many-branches, too-many-locals, too-many-statements + # Load encodings file + with open(encoding_file_path) as json_file: + encodings = json.load(json_file) + + param_encodings = encodings['param_encodings'] + activation_encodings = encodings['activation_encodings'] + + model_input_tensor_names = [inp.name for inp in self.model.inputs] + + for wrapper in self.quant_wrappers(): + for idx, input_quantizer in enumerate(wrapper.input_quantizers): + # because dense layers in quantizable MHA and RNN are not explicitly sublayers, they don't have their + # inbound_nodes parameter populated, so the name of the quantizer is used instead + if not wrapper._layer_to_wrap.inbound_nodes: + tensor_name = wrapper.name + "/" + input_quantizer.name + ":0" + else: + tensor_name = wrapper._layer_to_wrap.inbound_nodes[0].keras_inputs[idx].name + if tensor_name in model_input_tensor_names: + tensor_name += ":0" + + if tensor_name in activation_encodings: + if not input_quantizer.is_enabled(): + _logger.info("Not loading encodings for quantizer: %s as it is disabled", tensor_name) + continue + encoding_dict = activation_encodings[tensor_name][0] + if encoding_dict['dtype'] == 'int': + encoding, is_symmetric = keras_common_utils.create_encoding_from_dict(encoding_dict) + input_quantizer.tensor_quantizer.isEncodingValid = True + input_quantizer.set_quantizer_encodings(encoding.bw, is_symmetric, encoding, + libpymo.TensorQuantizerOpMode.quantizeDequantize) + _logger.info("Setting encodings for : %s", tensor_name) + elif encoding_dict['dtype'] == 'float': + input_quantizer.data_type = QuantizationDataType.float + input_quantizer.bitwidth = encoding_dict['bitwidth'] + _logger.info("Setting quantizer dtype to float for : %s", tensor_name) + else: + raise RuntimeError("Unrecognized dtype %s for: %s" % (encoding_dict['dtype'], tensor_name)) + else: + if input_quantizer.is_enabled(): + input_quantizer.disable() + _logger.info("Encoding for quantizer: %s is not present thus disabling it.", tensor_name) + + for idx, param_quantizer in enumerate(wrapper.param_quantizers): + param_name = wrapper._layer_to_wrap.weights[idx].name + + if param_name in param_encodings: + if not param_quantizer.is_enabled(): + _logger.info("Not loading encodings for parameter: %s as quantizer is disabled", param_name) + continue + if isinstance(param_quantizer, StaticGridPerChannelQuantizer): + if param_encodings[param_name][0]['dtype'] == 'float': + wrapper.param_quantizers[idx] = ParamPerTensorQuantizer(layer=param_quantizer._original_layer, + name=param_quantizer.name, + quant_scheme=param_quantizer._quant_scheme, + round_mode='nearest', + bitwidth=param_encodings[param_name][0]['bitwidth'], + data_type=QuantizationDataType.float, + is_symmetric=param_quantizer.is_symmetric, + use_strict_symmetric=param_quantizer.use_strict_symmetric, + use_unsigned_symmetric=param_quantizer.use_unsigned_symmetric, + enabled=False) + else: + encoding, is_symmetric = keras_common_utils.create_encoding_from_dict( + param_encodings[param_name]) + for tensor_quantizer in param_quantizer.tensor_quantizer: + tensor_quantizer.isEncodingValid = True + bw = encoding[0].bw + param_quantizer.set_quantizer_encodings(bw, is_symmetric, encoding, + libpymo.TensorQuantizerOpMode.oneShotQuantizeDequantize) + _logger.info("Setting encodings for : %s", param_name) + else: + encoding_dict = param_encodings[param_name][0] + if encoding_dict['dtype'] == 'int': + encoding, is_symmetric = keras_common_utils.create_encoding_from_dict(encoding_dict) + param_quantizer.tensor_quantizer.isEncodingValid = True + bw = encoding.bw + param_quantizer.set_quantizer_encodings(bw, is_symmetric, encoding, + libpymo.TensorQuantizerOpMode.oneShotQuantizeDequantize) + _logger.info("Setting encodings for : %s", param_name) + elif encoding_dict['dtype'] == 'float': + param_quantizer.data_type = QuantizationDataType.float + param_quantizer.bitwidth = encoding_dict['bitwidth'] + _logger.info("Setting quantizer to float for : %s", param_name) + else: + raise RuntimeError("Unrecognized dtype %s for: %s" % (encoding_dict['dtype'], tensor_name)) + else: + if param_quantizer.is_enabled(): + param_quantizer.disable() + _logger.info("Encoding for parameter: %s not present thus disabling this quantizer.", + param_name) + + # Loading encodings means that compute encodings was called. Therefore, these two lines set the correct + # op mode for the correct quant scheme and if the quantization was per channel or not. + op_mode = self._param_op_mode_after_analysis(self.quant_scheme) + self._set_op_mode_parameters(op_mode) + + for idx, output_quantizer in enumerate(wrapper.output_quantizers): + # because dense layers in quantizable MHA are not explicitly sublayers, they don't have their + # inbound_nodes parameter populated, so the name of the quantizer is used instead + if not wrapper._layer_to_wrap.inbound_nodes: + tensor_names = [wrapper.name + ":0"] + else: + # There can be multiple outputs if there is a + # `tf.split` in the model. + if isinstance(wrapper._layer_to_wrap.output, list): + tensor_names = [ + output.name + for output in wrapper._layer_to_wrap.output + ] + else: + tensor_names = [wrapper._layer_to_wrap.output.name] + + for tensor_name in tensor_names: + if tensor_name in activation_encodings: + if not output_quantizer.is_enabled(): + _logger.info("Not loading encodings for quantizer: %s as it is disabled", tensor_name) + continue + encoding_dict = activation_encodings[tensor_name][0] + if encoding_dict['dtype'] == 'int': + encoding, is_symmetric = keras_common_utils.create_encoding_from_dict(encoding_dict) + output_quantizer.tensor_quantizer.isEncodingValid = True + output_quantizer.set_quantizer_encodings(encoding.bw, is_symmetric, encoding, + libpymo.TensorQuantizerOpMode.quantizeDequantize) + _logger.info("Setting encodings for : %s", tensor_name) + elif encoding_dict['dtype'] == 'float': + output_quantizer.data_type = QuantizationDataType.float + output_quantizer.bitwidth = encoding_dict['bitwidth'] + _logger.info("Setting quantizer dtype to float for : %s", tensor_name) + else: + raise RuntimeError("Unrecognized dtype %s for: %s" % (encoding_dict['dtype'], tensor_name)) + else: + if output_quantizer.is_enabled(): + output_quantizer.disable() + _logger.info("Encoding for quantizer: %s is not present thus disabling it.", tensor_name)
    + + + def _param_op_mode_after_analysis(self, quant_scheme) -> libpymo.TensorQuantizerOpMode: + """ + Returns quant mode to use for parameters after encodings have been computed + :param quant_scheme: Quantization scheme to use + :return: Quant mode to use + """ + if quant_scheme in [QuantScheme.training_range_learning_with_tf_init, + QuantScheme.training_range_learning_with_tf_enhanced_init] \ + or self.per_channel_quantization_enabled: + return libpymo.TensorQuantizerOpMode.quantizeDequantize + return libpymo.TensorQuantizerOpMode.oneShotQuantizeDequantize + + def quant_wrappers(self): + """ + Generator for yielding all quantization wrappers + """ + for layer in self.model.layers: + if isinstance(layer, QcQuantizeWrapper): + yield layer + if isinstance(layer, tuple(substitutable_modules.values())): + yield from layer.quant_wrappers() + + # For Getting Quantizers from Sequantial Block + if isinstance(layer, tf.keras.Sequential): + yield from quant_wrappers_for_sequential_block(layer) + + def get_quant_wrapper_for_layer_name(self, layer_name: str) -> QcQuantizeWrapper: + """ + Return qc quant wrapper corresponding to a layer name + :param layer_name: Layer name to get quantize wrapper for + :return: Qc quant wrapper corresponding to a layer name + """ + return self._layer_name_to_quant_wrapper.get(layer_name) + + # pylint: disable=too-many-locals + def _fill_missing_encoding_min_max_gradients(self, gradients: list): + """ + Computes the encoding min/max gradients and populates the gradients list + :param gradients: gradients computed using GradientTape(gradients for encoding min/max will be `None`) + """ + + def _find_weight_in_layer(weight_name: str, model_layer: tf.keras.layers.Layer): + + for weight in model_layer.weights: + if weight.name.split(":")[0] == weight_name: + return weight + + return None + + # Mapping used to get the gradients of weights(kernel, bias etc) + weight_name_to_gradient = dict(zip([weight.name.split(":")[0] for weight in self.model.trainable_weights], + gradients)) + + # Mapping used to get index of encoding min/max gradients (which would be `None`) and fill them + weight_name_to_index = dict(zip([weight.name for weight in self.model.trainable_weights], + range(len(self.model.trainable_weights)))) + + # Only process layers where 'param_quantizers' is defined (i.e. QcQuantizeWrapper layers) + for layer in filter(lambda _layer: hasattr(_layer, 'param_quantizers'), self.model.layers): + for param_quantizer in layer.param_quantizers: + if param_quantizer.name in weight_name_to_gradient: + # Value of weight associated with this param quantizer + weight_tensor = _find_weight_in_layer(param_quantizer.name, layer.original_layer) + + # Gradients of the weights + grad = weight_name_to_gradient[param_quantizer.name] + + # Using the weights and it's gradients, compute gradients for encoding min/max + dloss_by_dmin, dloss_by_dmax = param_quantizer.get_gradients_for_encoding_min_max(weight_tensor, + grad) + + enc_min_index = weight_name_to_index[param_quantizer.encoding_min.name] + enc_max_index = weight_name_to_index[param_quantizer.encoding_max.name] + + gradients[enc_min_index] = dloss_by_dmin + gradients[enc_max_index] = dloss_by_dmax + + # TODO: Remove this logic once this has been resolved in QNN/SNPE + # Go through activation quantizers (Input/Output) and set any ReLU's encoding min to 0 + relu_quantize_wrappers = [ + _layer for _layer in self.model.layers + if isinstance(_layer, QcQuantizeWrapper) and isinstance(_layer.original_layer, tf.keras.layers.ReLU) + ] + + def _set_encoding_min_grad_to_None(quantizer): + enc_min_index = weight_name_to_index[quantizer.encoding_min.name] + gradients[enc_min_index] = None + + for relu_quantizer in relu_quantize_wrappers: + for output_quantizer in relu_quantizer.output_quantizers: + _set_encoding_min_grad_to_None(output_quantizer) + + # pylint: disable=useless-super-delegation + def get_config(self): + return super().get_config() + + def call(self, inputs, training=None, mask=None): + return self.model.call(inputs, training, mask) + + def train_step(self, data): + """ + Custom training loop, equivalent to overriding `keras.Model.fit` function + Reference: https://keras.io/guides/customizing_what_happens_in_fit/ + Only relevant when using range-learning, otherwise equivalent to `keras.Model.fit` + Param quantizers are disconnected in the op graph of the wrapped model + Because of this, the gradients are not computed for encoding min/max(when range learning is enabled) + This custom train_step function computes the missing gradients for encoding min/max of param quantizers + """ + x, y = data + + with tf.GradientTape() as tape: + predictions = self(x, training=True) + loss = self.compiled_loss(y, predictions) + + gradients = tape.gradient(loss, self.model.trainable_weights) + + # Manually compute missing gradients for encoding min/max when using range learning + if self.quant_scheme in [QuantScheme.training_range_learning_with_tf_init, + QuantScheme.training_range_learning_with_tf_enhanced_init]: + self._fill_missing_encoding_min_max_gradients(gradients) + + gradients_to_apply = [(gradient, weight) for gradient, weight in zip(gradients, self.model.trainable_weights) + if gradient is not None] + + self.optimizer.apply_gradients(gradients_to_apply) + + self.compiled_metrics.update_state(y, predictions) + + return {m.name: m.result() for m in self.metrics}
    + + + +def quant_wrappers_for_sequential_block(seq_block: tf.keras.Sequential): + """ + Generator for yielding all quantization wrappers for a Sequantial Block + """ + for layer in seq_block.layers: + if isinstance(layer, QcQuantizeWrapper): + yield layer + if isinstance(layer, tuple(substitutable_modules.values())): + yield from layer.quant_wrappers() + + # in cases of nested Sequential Block + if isinstance(layer, tf.keras.Sequential): + yield from quant_wrappers_for_sequential_block(layer) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/_base/adaround/adaround_weight.html b/releases/2.0.0/_modules/aimet_torch/_base/adaround/adaround_weight.html new file mode 100644 index 0000000..c56e5f5 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/_base/adaround/adaround_weight.html @@ -0,0 +1,921 @@ + + + + + + + + aimet_torch._base.adaround.adaround_weight - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch._base.adaround.adaround_weight

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +""" Defines Adaround base classes shared across aimet_torch.v1 and v2 """
    +
    +from abc import ABC, abstractmethod
    +import os
    +import contextlib
    +import json
    +import tempfile
    +from typing import Tuple, Union, Dict, List, Callable, Optional, Any
    +import torch
    +from torch.utils.data import DataLoader
    +from tqdm import tqdm
    +
    +# Import AIMET specific modules
    +from aimet_common.utils import AimetLogger, convert_configs_values_to_bool
    +from aimet_common.defs import QuantScheme
    +
    +from aimet_torch import utils
    +from aimet_torch.meta import connectedgraph_utils
    +from aimet_torch._base.quantsim import _QuantizationSimModelInterface, _QuantizedModuleProtocol
    +from aimet_torch._base.adaround.adaround_optimizer import AdaroundOptimizer
    +from aimet_torch._base.adaround.adaround_loss import AdaroundHyperParameters
    +from aimet_torch._base.adaround.activation_sampler import create_modulelist_for_group_modules, get_block_inputs, \
    +    get_block_outputs, create_cached_block_schedule_list
    +from aimet_torch.utils import get_named_module
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.Quant)
    +
    +# The following modules with weights are supported by Adaround
    +AdaroundSupportedModules = (torch.nn.Conv2d, torch.nn.ConvTranspose2d, torch.nn.Linear)
    +
    +
    +
    +[docs] +class AdaroundParameters: + """ + Configuration parameters for Adaround + """ + def __init__(self, data_loader: DataLoader, num_batches: int, + default_num_iterations: int = None, default_reg_param: float = 0.01, + default_beta_range: Tuple = (20, 2), default_warm_start: float = 0.2, + forward_fn: Callable[[torch.nn.Module, Any], Any] = None): + """ + :param data_loader: Data loader + :param num_batches: Number of batches to be used for Adaround. + A commonly recommended value for this parameter is the smaller value among (1) len(data_loader) and (2) ceil(2000/batch_size) + :param default_num_iterations: Number of iterations to adaround each layer. + The default value is 10K for models with 8- or higher bit weights, and 15K for models with lower than 8 bit weights. + :param default_reg_param: Regularization parameter, trading off between rounding loss vs reconstruction loss. + Default 0.01 + :param default_beta_range: Start and stop beta parameter for annealing of rounding loss (start_beta, end_beta). + Default (20, 2) + :param default_warm_start: warm up period, during which rounding loss has zero effect. Default 20% (0.2) + :param forward_fn: Optional adapter function that performs forward pass given a model and inputs + yielded from the data loader. The function expects model as first argument and inputs to model + as second argument. + """ + if len(data_loader) < num_batches: + raise ValueError(f'Can not fetch {num_batches} batches from ' + f'a data loader of length {len(data_loader)}.') + + self.data_loader = data_loader + self.num_batches = num_batches + self.num_iterations = default_num_iterations + self.reg_param = default_reg_param + self.beta_range = default_beta_range + self.warm_start = default_warm_start + self.forward_fn = forward_fn
    + + + +class AdaroundBase(ABC): + """ + Weight-rounding mechanism for Post Training Quantization (PTQ) + """ + @classmethod + def apply_adaround(cls, model: torch.nn.Module, dummy_input: Union[torch.Tensor, Tuple], params: AdaroundParameters, + path: str, filename_prefix: str, default_param_bw: int = 4, + param_bw_override_list: List[Tuple[torch.nn.Module, int]] = None, + ignore_quant_ops_list: List[torch.nn.Module] = None, + default_quant_scheme: QuantScheme = QuantScheme.post_training_tf_enhanced, + default_config_file: str = None) -> torch.nn.Module: + """ + Returns model with optimized weight rounding of every module (Conv and Linear) and also saves the + corresponding quantization encodings to a separate JSON-formatted file that can then be imported by + QuantSim for inference or QAT + + :param model: Model to Adaround + :param dummy_input: Dummy input to the model. Used to parse model graph. If the model has more than one input, + pass a tuple. User is expected to place the tensors on the appropriate device. + :param params: Parameters for Adaround + :param path: path where to store parameter encodings + :param filename_prefix: Prefix to use for filename of the encodings file + :param default_param_bw: Default bitwidth (4-31) to use for quantizing layer parameters + :param param_bw_override_list: List of Tuples. Each Tuple is a module and the corresponding parameter bitwidth + to be used for that module. + :param ignore_quant_ops_list: Ops listed here are skipped during quantization needed for AdaRounding. Do not + specify Conv and Linear modules in this list. Doing so, will affect accuracy. + :param default_quant_scheme: Quantization scheme. Supported options are using Quant Scheme Enum + QuantScheme.post_training_tf or QuantScheme.post_training_tf_enhanced + :param default_config_file: Default configuration file for model quantizers + :return: Model with Adarounded weights and saves corresponding parameter encodings JSON file at provided path + """ + # pylint: disable=too-many-arguments + # Create Quant sim with given parameters + quant_sim = cls._get_quantsim(model, dummy_input=dummy_input, quant_scheme=default_quant_scheme, + default_param_bw=default_param_bw, + config_file=default_config_file) + + # For the modules in the param_bw_override_list, override the default parameter bitwidths in the QuantSim + if param_bw_override_list: + cls._override_param_bitwidth(model, quant_sim, param_bw_override_list) + + if ignore_quant_ops_list: + cls._exclude_modules(model, quant_sim, ignore_quant_ops_list) + + # Compute only param encodings + cls._compute_param_encodings(quant_sim) + + return cls._apply_adaround(quant_sim, model, dummy_input, params, path, filename_prefix) + + @classmethod + def _apply_adaround(cls, quant_sim: _QuantizationSimModelInterface, model: torch.nn.Module, + dummy_input: Union[torch.Tensor, Tuple], params: AdaroundParameters, + path: str, filename_prefix: str, checkpoints_config: str = None) -> torch.nn.Module: + """ + Returns model with optimized weight rounding of every module (Conv and Linear) and also saves the + corresponding quantization encodings to a separate JSON-formatted file that can then be imported by + QuantSim for inference or QAT + + :param quant_sim: QuantizationSimModel object to optimize weight rounding. + The activation quantizers are expected to have been disabled. + :param model: Original fp32 model from which quant_sim was created. + :param dummy_input: Dummy input to the model. Used to parse model graph. If the model has more than one input, + pass a tuple. User is expected to place the tensors on the appropriate device. + :param params: Parameters for Adaround + :param path: path where to store parameter encodings + :param filename_prefix: Prefix to use for filename of the encodings file + :param checkpoints_config: Config files to split fp32/quant model by checkpoints + :return: Model with Adarounded weights and saves corresponding parameter encodings JSON file at provided path + """ + + # Sanity check: All the input/output quantizers should be disabled + cls._check_input_output_quantizers_for_adaround(quant_sim.model) + + # Get the module - activation function pair using ConnectedGraph + module_act_func_pair = connectedgraph_utils.get_module_act_func_pair(model, dummy_input) + + cls._adaround_model(model, quant_sim, module_act_func_pair, params, dummy_input, checkpoints_config) + + # Export quantization encodings to JSON-formatted file + cls._export_encodings_to_json(path, filename_prefix, quant_sim) + + cls._remove_quantization_wrappers(quant_sim.model) + logger.info('Completed Adarounding Model') + return quant_sim.model + + @classmethod + def _adaround_model(cls, model: torch.nn.Module, quant_sim: _QuantizationSimModelInterface, module_act_func_pair: Dict, + params: AdaroundParameters, dummy_input: Union[torch.Tensor, Tuple], + checkpoints_config: str = None): + """ + Optimize weight rounding of every module (AdaroundSupportedModules) of model in sequential manner + based on occurrence + + NOTE: When checkpoints_config file is provided, assumption is that the outputs from previous group modules (block) + should feed directly into next group modules (block) + + :param model: Original fp32 model from which quant_sim was created. + :param quant_sim: QuantizationSimModel object to optimize weight rounding. + The activation quantizers are expected to have been disabled. + :param module_act_func_pair: Dictionary of module to immediate following activation function + :param params: Adaround parameters + :param dummy_input: Dummy input to the model + :param checkpoints_config: Config files to split fp32/quant model by checkpoints to speedup activations sampling + """ + # pylint: disable=too-many-locals, protected-access, too-many-branches, too-many-statements + + num_iterations = params.num_iterations + + if num_iterations is None: + lowest_weight_bw = cls._get_lowest_weight_bw(quant_sim.model) + # If the lowest wegith bitwidth is < 8, then set num_iterations to 15K by default + if lowest_weight_bw < 8: + num_iterations = 15000 + else: + num_iterations = 10000 + + with tempfile.TemporaryDirectory() as tmp_dir: + # Cache model input data to temporary directory + cached_dataset = utils.CachedDataset(params.data_loader, params.num_batches, tmp_dir) + + # Optimization Hyper parameters + opt_params = AdaroundHyperParameters(num_iterations, params.reg_param, params.beta_range, + params.warm_start) + + # AdaRound must be applied to modules in the order of occurrence + if checkpoints_config: + # Load the predefined json file for checkpoints info + checkpoint_config = json.load(open(checkpoints_config)) + convert_configs_values_to_bool(checkpoint_config) + + assert 'cache_on_cpu' in checkpoint_config.keys(), \ + "Please define cache_on_cpu to determine whether to cache intermediate tensors on CPU" + cache_on_cpu = checkpoint_config['cache_on_cpu'] + + checkpoint_type = checkpoint_config.get('checkpoint_type', 'sequential') + if checkpoint_type == 'sequential': + assert 'grouped_modules' in checkpoint_config.keys(), \ + "Please provide a dictionary of grouped_modules in the file to define checkpoints" + assert 'include_static_inputs' in checkpoint_config.keys(), \ + "Please provide a dictionary of include_static_inputs in the file to define checkpoints" + + grouped_modules = checkpoint_config['grouped_modules'] + breakpoint_module_name = checkpoint_config['grouped_modules'][list(grouped_modules.keys())[0]][0] + include_static_inputs = checkpoint_config['include_static_inputs'] + cached_fp_dataset, cached_quant_dataset = get_block_inputs(model, quant_sim, + breakpoint_module_name, + cached_dataset, cache_on_cpu, + params.forward_fn, params.num_batches, + tmp_dir) + # Get the device of model to latter be used to place input tensor on the same device + device = utils.get_device(model) + model.cpu() + quant_sim.model.cpu() + + # Forward function for the ModuleList object + def fwd_mod_ls(mod_ls, x): + for mod in mod_ls: + x = params.forward_fn(mod, x) + return x + + sub_fp_models, sub_sim_models = create_modulelist_for_group_modules(model, quant_sim, grouped_modules) + for i, (fp_block, quant_sim_block, static_input) in enumerate(zip(sub_fp_models, + sub_sim_models, + include_static_inputs)): + modules = utils.get_ordered_list_of_modules(fp_block, cached_fp_dataset[0], fwd_mod_ls) + cls._run_adaround_model(modules, fp_block, quant_sim_block, + module_act_func_pair, opt_params, + fwd_mod_ls, + cached_fp_dataset, cached_quant_dataset) + + # Get the outputs from the current block and assign to be the inputs for next block + # except for the last block + if i < len(sub_fp_models) - 1: + get_block_outputs(fp_block, quant_sim_block, static_input, + cached_fp_dataset, cached_quant_dataset, cache_on_cpu, + fwd_mod_ls, device, tmp_dir) + + # After finishing Adaround, placing the quant model back to its original device + quant_sim.model.to(device) + else: + assert 'cached_blocks' in checkpoint_config.keys(), \ + "Please provide a list of modules that can be cached" + + block_list = create_cached_block_schedule_list( + model, dummy_input, checkpoint_config['cached_blocks'], AdaroundSupportedModules) + + for block_cfg, modules in tqdm(block_list, desc='block'): + if block_cfg is None: # doesn't belong to a cached block + cls._run_adaround_model(modules, model, quant_sim.model, module_act_func_pair, opt_params, + params.forward_fn, cached_dataset) + else: + block_name, fp_block = block_cfg + quant_sim_block: torch.nn.Module = get_named_module(quant_sim.model, block_name) + + cached_fp_dataset, cached_quant_dataset = get_block_inputs(model, quant_sim, + block_name, + cached_dataset, cache_on_cpu, + params.forward_fn, + params.num_batches, + tmp_dir, + incl_kwargs=True) + + def block_fwd(_model, x): + return _model(*x) + + cls._run_adaround_model(modules, fp_block, quant_sim_block, module_act_func_pair, + opt_params, + block_fwd, cached_fp_dataset, cached_quant_dataset) + del cached_fp_dataset + del cached_quant_dataset + else: + modules = utils.get_ordered_list_of_modules(model, dummy_input) + cls._run_adaround_model(modules, model, quant_sim.model, module_act_func_pair, opt_params, + params.forward_fn, cached_dataset) + + @classmethod + def _run_adaround_model(cls, modules: List, model: torch.nn.Module, quant_sim_model: torch.nn.Module, + module_act_func_pair: Dict, opt_params: AdaroundHyperParameters, forward_fn: Callable, + cached_dataset: utils.CachedDataset, + cached_quant_dataset: Optional[utils.CachedDataset] = None): + """ + Iterate through all modules to find out Adaround supported modules and + apply Adaround optimization to those modules + + :param modules: Candidate modules + :param model: Original fp32 model + :param quant_sim_model: QuantSim model + :param module_act_func_pair: Activation function pairs + :param opt_params: Optimization parameters + :param forward_fn: Adapter function that performs forward pass given a model and inputs + yielded from the data loader + :param cached_dataset: Cached dataset for the fp32 model + :param cached_quant_dataset: Cached dataset for the quant model + """ + # pylint: disable=too-many-arguments, too-many-locals, protected-access + for name, module in tqdm(modules): + if isinstance(module, AdaroundSupportedModules): + # Using name, get corresponding quantized wrapper module from Quant sim model + quant_wrapper = cls._get_quant_wrapper(quant_sim_model, name) + if not quant_wrapper: + continue + + # Wraps the quant module with adaround wrapper + # and temporarily replace quant module with wrapped module + with cls._replace_quantization_layer(quant_sim_model, name) as adaround_wrapper: + + # Get module's next following activation function + act_func = module_act_func_pair[module] + + logger.info("Started Optimizing weight rounding of module: %s", name) + AdaroundOptimizer.adaround_module(module, adaround_wrapper, model, quant_sim_model, act_func, + cached_dataset, forward_fn, opt_params, cached_quant_dataset) + weight = adaround_wrapper.weight + + # Fold trained alpha to weight + with torch.no_grad(): + # Use soft rounding to compute Adarounded weight + adaround_wrapper.use_soft_rounding = True + adarounded_weight = adaround_wrapper.apply_adaround(weight) + weight.copy_(adarounded_weight) + del adarounded_weight + + @staticmethod + @abstractmethod + def _compute_param_encodings(quant_sim: _QuantizationSimModelInterface): + """ + Compute encodings for parameters, needed for initializing Adaround quantizers + :param quant_sim: Quant sim + """ + + @staticmethod + @abstractmethod + def _get_quantsim(model: torch.nn.Module, dummy_input: torch.Tensor, + quant_scheme: QuantScheme, default_param_bw: int, config_file: str): + ... + + @staticmethod + @abstractmethod + def _get_adaround_wrapper(quant_module: _QuantizedModuleProtocol): + ... + + @staticmethod + @abstractmethod + def _remove_quantization_wrappers(module: torch.nn.Module): + ... + + @staticmethod + @contextlib.contextmanager + def _patch_module_layer(model, layer_name, new_layer): + """ + Temporarily replace model layer + """ + original_layer = getattr(model, layer_name) + setattr(model, layer_name, new_layer) + yield + setattr(model, layer_name, original_layer) + + @staticmethod + @abstractmethod + def _validate_quant_module_for_adaround(quant_module: _QuantizedModuleProtocol): + ... + + @staticmethod + @abstractmethod + def _check_input_output_quantizers_for_adaround(quant_model: torch.nn.Module): + ... + + @staticmethod + @abstractmethod + def _get_lowest_weight_bw(quant_model: torch.nn.Module): + ... + + @classmethod + @contextlib.contextmanager + def _replace_quantization_layer(cls, quant_sim_model: torch.nn.Module, module_name: str): + """ + Replace the quantized module's weight tensor quantizer with the Adaround tensor quantizer + :param quant_module: quant module + """ + quant_module = utils.get_named_module(quant_sim_model, module_name) + cls._validate_quant_module_for_adaround(quant_module) + adaround_layer = cls._get_adaround_wrapper(quant_module) + + # We need to look for the container to patch for modules inside submodule + upper_module = quant_sim_model + upper_module_name, _, target_module_name = module_name.rpartition('.') + if upper_module_name: + upper_module = utils.get_named_module(quant_sim_model, upper_module_name) + + # Temporarily replace quant module with wrapped module + with cls._patch_module_layer(upper_module, target_module_name, adaround_layer): + yield adaround_layer + + @staticmethod + @abstractmethod + def _get_quant_wrapper(quant_sim_model: torch.nn.Module, module_name: str) -> Union[_QuantizedModuleProtocol, None]: + """ + For given module name, get the quantized wrapper module from the QuantSim model + :param quant_sim_model: Model with simulation ops + :param module_name: Module name + :return: Quantized wrapper module or None + """ + ... + + @classmethod + def _export_encodings_to_json(cls, path: str, filename_prefix: str, quant_sim: _QuantizationSimModelInterface): + """ + Save Adadrounded module's parameter encodings to JSON file + :param path: path where to store param encodings + :param filename_prefix: filename to store exported weight encodings in JSON format + :param quant_sim: QunatSim that contains the model and Adaround tensor quantizers + """ + # pylint: disable=protected-access + # Create a dictionary to export to JSON file + param_encodings = {} + + for name, quant_module in quant_sim.model.named_modules(): + if isinstance(quant_module, _QuantizedModuleProtocol) and \ + isinstance(quant_module.get_original_module(), AdaroundSupportedModules): + + if 'weight' in quant_module.param_quantizers: + cls._update_param_encodings_dict(quant_module, name, param_encodings) + + # Unify the encoding format to be same as that of full encoding export file + encoding = {'param_encodings': param_encodings} + # export encodings to JSON file + os.makedirs(os.path.abspath(path), exist_ok=True) + encoding_file_path = os.path.join(path, filename_prefix + '.encodings') + with open(encoding_file_path, 'w') as encoding_fp: + json.dump(encoding, encoding_fp, sort_keys=True, indent=4) + + @classmethod + def _update_param_encodings_dict(cls, quant_module: _QuantizedModuleProtocol, name: str, param_encodings: Dict): + """ + Add module's weight parameter encodings to dictionary to be used for exporting encodings + :param quant_module: quant module + :param name: name of module + :param param_encodings: Dictionary of param encodings + """ + for orig_param_name, encodings in quant_module.export_param_encodings(encoding_version='0.6.1').items(): + if orig_param_name == 'weight' and encodings: + param_name = name + '.' + orig_param_name + param_encodings[param_name] = encodings + + @staticmethod + def _override_param_bitwidth(model: torch.nn.Module, quant_sim: _QuantizationSimModelInterface, + param_bw_override_list: List[Tuple[torch.nn.Module, int]]): + """ + For the QuantSim, for the list of modules in the param_bw_override_list, + overrides the default parameter bitwidths with the provided bitwidth. + + :param model: The original model + :param quant_sim: The QuantSim that was created using a deepcopy of the original model. + :param param_bw_override_list: List of Tuples. Each Tuple is a module and the corresponding parameter bitwidth + to be used for that module. + """ + # Create a mapping of original model's AdaRoundable module and their name + module_to_name = {} + for name, module in model.named_modules(): + if isinstance(module, AdaroundSupportedModules): + module_to_name[module] = name + + # Create a mapping of QuantSim model's AdaRoundable module name and their module + name_to_module = {} + for q_name, q_module in quant_sim.model.named_modules(): + if isinstance(q_module, _QuantizedModuleProtocol): + if isinstance(q_module.get_original_module(), AdaroundSupportedModules): # pylint: disable=protected-access + name_to_module[q_name] = q_module + + # For the modules specified in the param_bw_override_list, set the weight quantizer bitwidth + for (module, bw) in param_bw_override_list: + module_name = module_to_name[module] + quant_wrapper = name_to_module[module_name] + quant_wrapper.param_quantizers['weight'].bitwidth = bw + + @classmethod + def _exclude_modules(cls, model: torch.nn.Module, quant_sim: _QuantizationSimModelInterface, + ignore_quant_ops_list: List[torch.nn.Module]): + """ + For the modules mentioned in the ignore_quant_ops_list, remove the corresponding quant wrappers from the + quantSim and excludes modules from adaround optimization. + + :param model: The original model + :param quant_sim: The QuantSim that was created using a deepcopy of the original model. + :param ignore_quant_ops_list: The list of modules for which the Quantization wrappers are removed from the + QuantSim object. + """ + quant_wrappers_to_exclude = [] + for module in ignore_quant_ops_list: + for m in module.modules(): + name = utils.get_layer_name(model, m) + quant_wrapper = cls._get_quant_wrapper(quant_sim.model, name) + if quant_wrapper: + quant_wrappers_to_exclude.append(quant_wrapper) + + quant_sim.exclude_layers_from_quantization(quant_wrappers_to_exclude) + + @classmethod + def apply_adaround_with_cache(cls, model: torch.nn.Module, dummy_input: Union[torch.Tensor, Tuple], + params: AdaroundParameters, + path: str, filename_prefix: str, default_param_bw: int = 4, + param_bw_override_list: List[Tuple[torch.nn.Module, int]] = None, + ignore_quant_ops_list: List[torch.nn.Module] = None, + default_quant_scheme: QuantScheme = QuantScheme.post_training_tf_enhanced, + default_config_file: str = None, + checkpoints_config: str = None) -> torch.nn.Module: + """ + Returns model with optimized weight rounding of every module (Conv and Linear) and also saves the + corresponding quantization encodings to a separate JSON-formatted file that can then be imported by + QuantSim for inference or QAT + :param model: Model to Adaround + :param dummy_input: Dummy input to the model. Used to parse model graph. If the model has more than one input, + pass a tuple. User is expected to place the tensors on the appropriate device. + :param params: Parameters for Adaround + :param path: path where to store parameter encodings + :param filename_prefix: Prefix to use for filename of the encodings file + :param default_param_bw: Default bitwidth (4-31) to use for quantizing layer parameters + :param param_bw_override_list: List of Tuples. Each Tuple is a module and the corresponding parameter bitwidth + to be used for that module. + :param ignore_quant_ops_list: Ops listed here are skipped during quantization needed for AdaRounding. Do not + specify Conv and Linear modules in this list. Doing so, will affect accuracy. + :param default_quant_scheme: Quantization scheme. Supported options are using Quant Scheme Enum + QuantScheme.post_training_tf or QuantScheme.post_training_tf_enhanced + :param default_config_file: Default configuration file for model quantizers + :param checkpoints_file: JSON file to define checkpoints for caching intermediate tensors of fp32/quant model + :return: Model with Adarounded weights and saves corresponding parameter encodings JSON file at provided path + """ + # pylint: disable=too-many-arguments + assert checkpoints_config is not None, "To run Adaround with cached tensors, please provide a JSON file with checkpoints defined" + # Create Quant sim with given parameters + quant_sim = cls._get_quantsim(model, dummy_input=dummy_input, quant_scheme=default_quant_scheme, + default_param_bw=default_param_bw, + config_file=default_config_file) + + # For the modules in the param_bw_override_list, override the default parameter bitwidths in the QuantSim + if param_bw_override_list: + cls._override_param_bitwidth(model, quant_sim, param_bw_override_list) + + if ignore_quant_ops_list: + cls._exclude_modules(model, quant_sim, ignore_quant_ops_list) + + # Compute only param encodings + cls._compute_param_encodings(quant_sim) + + return cls._apply_adaround(quant_sim, model, dummy_input, params, path, filename_prefix, checkpoints_config) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/_base/amp/mixed_precision_algo.html b/releases/2.0.0/_modules/aimet_torch/_base/amp/mixed_precision_algo.html new file mode 100644 index 0000000..abdb0dc --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/_base/amp/mixed_precision_algo.html @@ -0,0 +1,924 @@ + + + + + + + + aimet_torch._base.amp.mixed_precision_algo - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch._base.amp.mixed_precision_algo

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +""" Evaluator class for mixed precision """
    +import os
    +from collections import defaultdict, OrderedDict
    +import pickle
    +import functools
    +from typing import Any, Callable, Union, Tuple, List, Dict
    +import numpy as np
    +import torch
    +from torch.utils.data import DataLoader
    +from aimet_common.utils import AimetLogger
    +from aimet_common.defs import CallbackFunc
    +from aimet_common.amp.mixed_precision_algo import GreedyMixedPrecisionAlgo as MixedPrecisionAlgo
    +from aimet_common.amp.quantizer_groups import reformat_supported_kernels
    +from aimet_common.amp.utils import (
    +    sort_accuracy_list,
    +    CANDIDATE_WITH_DTYPE,
    +    ACCURACY_LIST,
    +    disable_quantizers,
    +    enable_quantizers,
    +)
    +from aimet_common.amp.convert_ops_reduction import SamplingStrategy
    +from aimet_torch import utils
    +from aimet_torch._base.amp import utils as mixed_precision_utils
    +from aimet_torch._base.amp.convert_ops_reduction import ReduceConvertOps
    +from aimet_torch._base.amp.quantizer_groups import find_quantizer_group, QuantizerGroup, get_module_name_to_module_dict, find_supported_candidates
    +from aimet_torch._base.quantsim import _QuantizationSimModelInterface
    +
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.MixedPrecision)
    +
    +
    +
    +[docs] +class EvalCallbackFactory: + """ + Factory class for various built-in eval callbacks + """ + def __init__(self, + data_loader: DataLoader, + forward_fn: Callable[[torch.nn.Module, Any], torch.Tensor] = None): + """ + + :param data_loader: Data loader to be used for evaluation + :param forward_fn: Function that runs forward pass and returns the output tensor. + This function is expected to take 1) a model and 2) a single batch + yielded from the data loader, and return a single torch.Tensor object + which represents the output of the model. + The default forward function is roughly equivalent to + ``lambda model, batch: model(batch)`` + """ + self._data_loader = data_loader + self._forward_fn = forward_fn or _default_forward_fn + + # storing batchwise fp32 outputs in the list + self._batchwise_fp32_outputs_list = [] + + def _forward_fn_wrapper(self, *args, **kwargs): + output = self._forward_fn(*args, **kwargs) + if not isinstance(output, torch.Tensor): + raise RuntimeError( + "Forward pass was expected to return a torch.Tensor, " + f"but returned an object of type {type(output)}. " + "Try specifying `forward_fn` to adapt the output." + ) + return output + + _DEFAULT_SQNR_NUM_SAMPLES = 128 + + +
    +[docs] + def sqnr(self, num_samples: int = _DEFAULT_SQNR_NUM_SAMPLES) -> CallbackFunc: + """ + Returns SQNR eval callback. + + :param num_samples: Number of samples used for evaluation + :return: A callback function that evaluates the input model's SQNR + between fp32 outputs and fake-quantized outputs + """ + evaluate_sqnr = functools.partial(_evaluate_sqnr, + data_loader=self._data_loader, + forward_fn=self._forward_fn_wrapper, + num_samples=num_samples, + batchwise_fp32_outputs_list=self._batchwise_fp32_outputs_list) + return CallbackFunc(evaluate_sqnr)
    +
    + + + +def _default_forward_fn(model, inputs): + if isinstance(inputs, torch.Tensor): + return model(inputs) + + assert isinstance(inputs, (tuple, list)) + return model(*inputs) + + +def _evaluate_sqnr(model: torch.nn.Module, _: Any, + data_loader: DataLoader, + forward_fn: Callable[[torch.nn.Module, Any], torch.Tensor], + num_samples: int, + batchwise_fp32_outputs_list: list) -> float: + """ + Compute SQNR given a model and a data loader. + + :param model: Root module + :param _: Placeholder for CallbackFunc + :param data_loader: Data loader to evaluate SQNR from + :param forward_fn: Function that runs forward pass and returns the output tensor. + :param num_samples: Number of samples used for evaluation + :param batchwise_fp32_outputs_list: List to store the model FP32 final outputs + :return: SQNR in dB scale + """ + # If capture_fp32_output_only_once is true then batchwise_fp32_outputs_list would be empty so we can calculate outputs by passing through model + # we can store those results and use instead of passing to model + # Initially capture_fp32_output_only_once is false and we make it to true if batchwise_fp32_outputs_list is empty to store the outputs in the list + + capture_fp32_output_only_once = False + if not batchwise_fp32_outputs_list: + capture_fp32_output_only_once = True + + sqnr = 0.0 + batch_size = data_loader.batch_size or 1 + device = utils.get_device(model) + with utils.in_eval_mode(model), torch.no_grad(): + for i, x in enumerate(data_loader): + if i * batch_size < num_samples: + x = utils.change_tensor_device_placement(x, device) + # First time we pass input to model and store the outputs in batchwise_fp32_outputs_list + if capture_fp32_output_only_once: + with utils.disable_all_quantizers(model): + fp32_output = forward_fn(model, x) + batchwise_fp32_outputs_list.append(fp32_output) + else: + # Re-using the stored outputs instead of computing again + fp32_output = batchwise_fp32_outputs_list[i] + + quantized_output = forward_fn(model, x) + + # Accumulate signal by noise ratio + # changed in_place to False otherwise it overwrites the batchwise_fp32_outputs_list + sqnr += _compute_sqnr(fp32_output, quantized_output, in_place=False) + else: + break + + # Convert SQNR into dB scale + sqnr_db = 10 * np.log10(sqnr / num_samples) + return sqnr_db + + +def _compute_sqnr(orig_tensor: torch.Tensor, + noisy_tensor: torch.Tensor, + in_place: bool = False) -> float: + """ + Compute SQNR between two tensors. + + IMPORTANT: If in_place is True, the input tensors will be used as in-place buffer + and hence will have been corrupted when this function returns. + + :param orig_tensor: Original tensor + :param noisy_tensor: Noisy tensor + :param in_place: If True, use the input tensors as in-place buffer + :return: SQNR + """ + assert orig_tensor.shape == noisy_tensor.shape + assert orig_tensor.dtype == noisy_tensor.dtype + + # SQNR := E[signal**2] / E[noise**2] + if in_place: + signal = orig_tensor + noise = noisy_tensor.negative_().add_(orig_tensor) + else: + signal = orig_tensor.detach().clone() + noise = orig_tensor - noisy_tensor + + sqnr = signal.square_().mean() / (noise.square_().mean() + 0.0001) + return float(sqnr) + + +class GreedyMixedPrecisionAlgo(MixedPrecisionAlgo): + """ Naive Greedy MixedPrecisionAlgo class """ + + ENABLE_MP_PROFILE_OPTIMIZE = False # Enables op_graph.optimize() during Phase-2 + ENABLE_CONVERT_OP_REDUCTION = False # Run phase-3 + + # pylint: disable=too-many-arguments + def __init__(self, sim: _QuantizationSimModelInterface, + dummy_input: Union[torch.Tensor, Tuple], + candidates: List[CANDIDATE_WITH_DTYPE], + eval_callback_for_phase1: CallbackFunc, + eval_callback_for_phase2: CallbackFunc, + results_dir: str, clean_start: bool, + forward_pass_callback: CallbackFunc, + use_all_amp_candidates: bool = False, + phase2_reverse: bool = False, + phase1_optimize: bool = False): + """ + + :param sim: Quantized sim model + :param dummy_input: Dummy input to the model. If the model has more than one input, pass a tuple. + User is expected to place the tensors on the appropriate device. + :param candidates: List of Tuple of all possible [bitwidth, QuantizationDataType] values to quantize to + :param eval_callback_for_phase1: An object of CallbackFunc class which takes in Eval function (callable) and eval + function parameters. This evaluation callback used to measure sensitivity of each + quantizer group during phase 1. The phase 1 involves finding accuracy list/sensitivity of each + module. Therefore, a user might want to run the phase 1 with a smaller dataset + :param eval_callback_for_phase2: An object of CallbackFunc class which takes in Eval function (callable) and eval + function parameters. Evaluation callback used to get accuracy of quantized model + for phase 2 calculations. The phase 2 involves finding pareto front curve + :param results_dir: Path to save results and cache intermediate results + :param clean_start: If true, any cached information from previous runs will be deleted prior to starting the + mixed-precision analysis. If false, prior cached information will be used if applicable. Note + it is the user's responsibility to set this flag to true if anything in the model or + quantization parameters changes compared to the previous run. + :param forward_pass_callback: An object of CallbackFunc class which takes in Forward pass function (callable) and its + function parameters. Forward pass callback used to compute quantization encodings + :param use_all_amp_candidates: Using the “supported_kernels” field in the config file (under defaults + and op_type sections), a list of supported candidates can be specified. All the AMP candidates + which are passed through the “candidates” field may not be supported based on the data passed + through “supported_kernels”. When the field “use_all_amp_candidates” is set to True, the AMP algo + will ignore the "supported_kernels" in the config file and will continue to use all the candidates. + :param phase2_reverse: If user will set this parameter to True, then phase1 of amp algo, that is calculating accuracy list will not be changed, + whereas the phase2 algo of amp, which generate the pareto list will be changed. In phase2, algo will start, model with all quantizer groups in least candidate, and + one by one, it will put nodes in higher candidate till target accuracy does not meet. + :phase1_optimize: If user set this parameter to True then phase1 optimized logic will be executed else common code will be executed + """ + mac_dict = mixed_precision_utils.create_mac_dict(sim.model, dummy_input) + self.phase1_optimize = phase1_optimize + self.dummy_input = dummy_input + + super().__init__(sim, candidates, + eval_callback_for_phase1, + eval_callback_for_phase2, + forward_pass_callback, + mac_dict, + results_dir, clean_start, phase2_reverse) + + supported_kernels = reformat_supported_kernels(sim.get_supported_kernels()) + + # Find 1. candidates for each of the quantizers by using supported_kernels, candidates and + # use_all_amp_candidates (flag) + # 2. max_candidate_options based on the candidates which are present in all the quantizers + self._supported_candidates_per_quantizer_group, self._baseline_candidate_options = find_supported_candidates( + self.quantizer_groups, + candidates, + supported_kernels, + get_module_name_to_module_dict(sim), + use_all_amp_candidates) + + + def _create_and_save_accuracy_list_optimized(self, baseline_candidate) -> ACCURACY_LIST: + """ + Create a list of tuples of (quantizer_group, bitwidth, accuracy score) + + :param baseline_candidate: Candidate [bitwidth, dtype] which yields max accuracy + :return: Sorted accuracy list containing tuples of (quantizer, candidate, accuracy score, bit ops reduction) + """ + # pylint: disable=too-many-locals, too-many-branches, too-many-statements + index_of_quantizer_group = {} + for index, quantizer_group in enumerate(self.quantizer_groups): + index_of_quantizer_group[quantizer_group] = index + + accuracy_list: ACCURACY_LIST = [] + + file = os.path.join(self._results_dir, '.cache', 'accuracy_list.pkl') + combinations_already_computed = set() + + if os.path.isfile(file): + if self._clean_start: + os.remove(file) + logger.info("Removed old cached files and restarting computation") + else: + with open(file, 'rb') as f: + accuracy_list = pickle.load(f) + + combinations_already_computed.update( + (quantizer_group, candidate) + for quantizer_group, candidate, _, _ in accuracy_list + ) + + disabled_quantizers = OrderedDict() + + try: + # Disable all quantizers + for quantizer_group in self.quantizer_groups: + quantizers = quantizer_group.get_active_quantizers(self._module_name_dict) + disable_quantizers(quantizers) + disabled_quantizers[quantizer_group] = quantizers + + # quantizer_groups_per_candidate = {"candidate1":[quantizer_group1,quantizer_group2,...]} + # quantizer_groups_per_candidate is the dictionary with keys as candidates and values as quantizer groups that supports the corresponding candidate + # quantizer_groups_per_candidate is like reverse mapping to self._supported_candidates_per_quantizer_group + quantizer_groups_per_candidate = defaultdict(list) + for quantizer_group, candidates in self._supported_candidates_per_quantizer_group.items(): + for candidate in candidates: + quantizer_groups_per_candidate[candidate].append(quantizer_group) + + # Loop through all possible bitwidths(candidates). Set all the quantizer groups to the corresponding bitwidth(candidate) + # Compute encodings by disabling the parameters and reuse the encodings + for candidate, quantizer_groups in quantizer_groups_per_candidate.items(): + if candidate == baseline_candidate: + continue + + # configure the sim model with the candidate by enabling the quantizers and set quantizers to corresponding candidate + for quantizer_group in quantizer_groups: + quantizers = disabled_quantizers[quantizer_group] + try: + enable_quantizers(quantizers) + # Set quantizer bitwidth to candidate (bitwidth) + quantizer_group.set_quantizers_to_candidate(self._module_name_dict, candidate) + except RuntimeError as e: + logger.info("Exception occured while setting Quantizers to Candidate: %s", e) + + # list to store all the param quantizers + param_quantizers = [] + + for _, wrapper in self._sim.quant_wrappers(): + for _, param_quantizer in wrapper.param_quantizers.items(): + if param_quantizer.enabled: + param_quantizers.append(param_quantizer) + + # disable the parameter quantization + disable_quantizers(param_quantizers) + + + # compute encodings with out parameter quantization + self._sim.compute_encodings(self.algo_params.forward_pass_callback, + self.algo_params.forward_pass_callback_args) + + # enable the parameter quantization + enable_quantizers(param_quantizers) + + + # Disable all the quantizers + for quantizer_group in quantizer_groups: + quantizers = quantizer_group.get_active_quantizers(self._module_name_dict) + disable_quantizers(quantizers) + disabled_quantizers[quantizer_group] = quantizers + + # Loop over all the quantizer groups and enable one at a time and calculate resulting model accuracy and disable the enabled quantizer + # Accuracy list will contain tuples of the quantizer, bitwidth, and accuracy score + for quantizer_group in quantizer_groups: + quantizers = disabled_quantizers[quantizer_group] + try: + enable_quantizers(quantizers) + + # If starting the computation from an already existing state, then check if that combination + # has already been executed + if (quantizer_group, candidate) in combinations_already_computed: + continue + # Compute accuracy of model with new candidate (bitwidth) + eval_score = self.evaluate_model(self.algo_params.eval_callback_for_phase1) + + bit_ops_reduction = self._find_bit_ops_reduction_for_acc_list(quantizer_group, + baseline_candidate, + candidate) + accuracy_list.append((quantizer_group, candidate, eval_score, bit_ops_reduction)) + # Sort accuracy list, first by descending accuracy score, then by descending order of addition of bitwidths if accuracy + # scores are identical, if that is also identical we sort by relative bit ops change in descending order + # If bit ops reduction is also the same, then we sort in ascending order based on occurence of + # quantizer group in the model + accuracy_list = sort_accuracy_list(accuracy_list, index_of_quantizer_group) + self._export_accuracy_list(accuracy_list, self._results_dir) + logger.info('\n Quantizer: %s candidate: %s eval_score: %f \n', quantizer_group, + candidate, eval_score) + finally: + # Disable the quantizer + disable_quantizers(quantizers) + finally: + + # set all quantizers to baseline candidate + for quantizer_group in self.quantizer_groups: + quantizers = disabled_quantizers[quantizer_group] + try: + # Enable the disabled quantizers + enable_quantizers(quantizers) + quantizer_group.set_quantizers_to_candidate(self._module_name_dict, baseline_candidate) + except RuntimeError as e: + logger.info("Exception occured while setting Quantizers to Candidate: %s", e) + + logger.info('Completed Accuracy list computation') + # Recompute encodings after quantizer's bitwidth is set back to self._max_bitwidth + self._sim.compute_encodings(self.algo_params.forward_pass_callback, self.algo_params.forward_pass_callback_args) + return accuracy_list + + + + def _evaluate_model(self, eval_callback) -> float: + """ + Evaluates a model + + :param eval_callback: Callback function that contains eval function and eval args + :return: Eval score + """ + return eval_callback.func(self._sim.model, eval_callback.args) + + def _find_quantizer_group(self, sim) -> Tuple[Dict, List[QuantizerGroup]]: + """ + Finds quantizer groups in a quantization sim + + :param sim: Quantization sim + :return: Dictionary mapping quantized op name to sim.quantizer_config, + and a List of quantizer groups + """ + return find_quantizer_group(sim) + + @property + def baseline_candidate_options(self) -> List[CANDIDATE_WITH_DTYPE]: + """ + Returns the _baseline_candidate_options which is the intersection of amp candidates and candidates supported by + all the quantizer groups + """ + return self._baseline_candidate_options + + def _find_bit_ops_reduction_for_acc_list( + self, + quantizer_group: QuantizerGroup, + max_candidate: CANDIDATE_WITH_DTYPE, + candidate: CANDIDATE_WITH_DTYPE, + ) -> int: + """ + Finds reduction in bit ops from max candidate to new candidate + + :param quantizer_group: Quantizer group + :param max_candidate: Maximum bitwidth and data type for the TensorQuantizer + :param candidate: Activation bitwidth, parameter bitwidth + :return: Bit ops reduction + """ + return mixed_precision_utils.find_bit_ops_reduction(quantizer_group, self._mac_dict, + max_candidate, candidate) + + def calculate_running_bit_ops( + self, + quantizer_group: QuantizerGroup, + module_bitwidth_dict: Dict, + max_candidate: CANDIDATE_WITH_DTYPE, + candidate: CANDIDATE_WITH_DTYPE, + running_bit_ops: int, + ) -> int: + """ + Calculates running bit ops value for every quantizer group + + :param quantizer_group: A group of activation & parameter quantizers + :param module_bitwidth_dict: Dict; Key: Module name value: Activation, parameter bitwidth of module + :param max_candidate: Maximum bitwidth and data type for the TensorQuantizer + :param candidate: candidate to change the quantizer group to + :param running_bit_ops: Running bit ops value calculated uptil the quantizer group + :return: Running bit ops value + """ + running_bit_ops = mixed_precision_utils.calculate_running_bit_ops(self._mac_dict, quantizer_group, + module_bitwidth_dict, + max_candidate, + candidate, + running_bit_ops) + return running_bit_ops + + def _create_and_save_accuracy_list(self, baseline_candidate): + def disable_all_quantizers(): + return utils.disable_all_quantizers(self._sim.model) + + # Note: "disable_all_quantizers" will be migrated to the open source codew + # as a method of QuantizationSimModel. + try: + setattr(self._sim, "disable_all_quantizers", disable_all_quantizers) + if self.phase1_optimize: + return self._create_and_save_accuracy_list_optimized(baseline_candidate) + return super()._create_and_save_accuracy_list(baseline_candidate) + finally: + delattr(self._sim, "disable_all_quantizers") + + def set_quantizer_groups_candidates(self, quantizer_group_candidates: List[Tuple]) -> None: + """ + Setter function to set quantizer groups to given candidate. This method also computes the encodings following + the change in quantizer groups + :param quantizer_group_candidates: list of quantizer groups and their candidates + """ + def validate_quantizer_candidate(qg: QuantizerGroup, qg_candidate) -> bool: + """ + Helper method to validate whether candidate can be applied + :param qg: quantizer group whose candidate needs to be changed + :param qg_candidate: the new candidate which needs to be applied to the quantizer group + :return: boolean value True if success else False + """ + supported_candidates = self._supported_candidates_per_quantizer_group.get(qg) + if not qg.parameter_quantizers: + (activation_bw, activation_data_type), _ = qg_candidate + # Since only activation quantizers are present, validate activation candidate + for supported_candidate in supported_candidates: + if supported_candidate[0] == (activation_bw, activation_data_type): + return True + return False + + # both activation and param quantizers are present in the quantizer group + return qg_candidate in supported_candidates + + for quantizer_group, candidate in quantizer_group_candidates: + assert validate_quantizer_candidate(quantizer_group, candidate) + quantizer_group.set_quantizers_to_candidate(self._module_name_dict, candidate) + + self._sim.compute_encodings(self.algo_params.forward_pass_callback, self.algo_params.forward_pass_callback_args) + + def _create_op_graph(self, sim): + """ + Creates op graph + + :param sim: QuantizationSimModel object + """ + return None + + def _optimize_mp_profile_and_evaluate_model(self): + """ + Get the eval score of the model based on whether ENABLE_MP_PROFILE_OPTIMIZE is enabled. + """ + + # Recompute quantizer encodings + self._sim.compute_encodings(self.algo_params.forward_pass_callback, + self.algo_params.forward_pass_callback_args) + # Compute new accuracy score + eval_score = self.evaluate_model(self.algo_params.eval_callback_for_phase2) + + return eval_score + + # pylint: disable=protected-access + def _reduce_mp_convert_ops(self): + """ + Reduce mixed precision convert ops if enabled and supported + """ + if self.ENABLE_CONVERT_OP_REDUCTION: + reduce_convert_ops_algo = ReduceConvertOps(self._sim, self.quantizer_groups, self.algo_params.candidates, self._mac_dict) + + # Check if phase 2 solution is all 8 bits + phase2_all_8bits = all( + reduce_convert_ops_algo._phase_two_sol[qg] == 8 for qg in + reduce_convert_ops_algo._phase_two_sol) + + # Check if phase 2 solution is all 16 bits + phase2_all_16bits = all( + reduce_convert_ops_algo._phase_two_sol[qg] == 16 for qg in + reduce_convert_ops_algo._phase_two_sol) + + dummy_input_cpu = reduce_convert_ops_algo.convert_tensor_to_cpu(self.dummy_input) + + if phase2_all_8bits or phase2_all_16bits: + logger.warning('Skipping phase3 because there is no scope to reduce convert-op overhead') + else: + for alpha in reduce_convert_ops_algo.DEFAULT_ALPHA_OPTIONS: + phase_three_sol, solve_data_dict = \ + reduce_convert_ops_algo.run_amp_phase_3(alpha, SamplingStrategy.weighted_with_predicted_convert_cost) + qg_candidates = reduce_convert_ops_algo.generate_qg_solution(phase_three_sol) + + # save sim state with the new quantizer settings + self.set_quantizer_groups_candidates(qg_candidates) + + # export + self._sim.export(path=self._results_dir, filename_prefix=f'AMP_ph3_export_alpha_{alpha}', + dummy_input=dummy_input_cpu) + + reduce_convert_ops_algo.save_phase_3_data_as_json(solve_data_dict, self._results_dir, + filename_suffix="alpha_{}".format(alpha)) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/_base/amp/quantizer_groups.html b/releases/2.0.0/_modules/aimet_torch/_base/amp/quantizer_groups.html new file mode 100644 index 0000000..afecb03 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/_base/amp/quantizer_groups.html @@ -0,0 +1,838 @@ + + + + + + + + aimet_torch._base.amp.quantizer_groups - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch._base.amp.quantizer_groups

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Find quantizer groups in a model """
    +import itertools
    +from typing import Dict, List, Tuple, Optional
    +from collections import defaultdict
    +from dataclasses import dataclass, field
    +import torch
    +
    +from aimet_common.connected_graph.connectedgraph_utils import CG_SPLIT
    +from aimet_common.connected_graph.operation import Op
    +from aimet_common.utils import AimetLogger
    +from aimet_common.amp.utils import CANDIDATE_WITH_DTYPE
    +from aimet_common.amp.quantizer_groups import QuantizerGroupBase, get_supported_candidates_for_quantizers, \
    +    compute_baseline_candidate_options
    +
    +from aimet_torch.meta.connectedgraph import ConnectedGraph
    +from aimet_torch._base.quantsim import _QuantizationSimModelInterface, _QuantizedModuleProtocol
    +from aimet_torch import onnx_utils
    +from aimet_torch.translation_mapping import aimet_op_to_backend_op_name_map
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.MixedPrecision)
    +
    +
    +
    +[docs] +@dataclass(frozen=True) +class QuantizerGroup(QuantizerGroupBase): + """ + Group of modules and quantizers + """ + input_quantizers: Tuple[str, ...] = field(default_factory=tuple) + output_quantizers: Tuple[str, ...] = field(default_factory=tuple) + parameter_quantizers: Tuple[str, ...] = field(default_factory=tuple) + supported_kernel_ops: Tuple[str, ...] = field(default_factory=tuple) + +
    +[docs] + def get_candidate(self, name_to_quantizer_dict: Dict) -> CANDIDATE_WITH_DTYPE: + """ + Gets Activation & parameter bitwidth + :param name_to_quantizer_dict: Gets module from module name + :return: Tuple of Activation, parameter bitwidth and data type + """ + activation_bw, parameter_bw = None, None + activation_data_type, parameter_data_type = None, None + + for quantizer in self._get_input_quantizers(name_to_quantizer_dict) +\ + self._get_output_quantizers(name_to_quantizer_dict): + activation_bw = quantizer.bitwidth + activation_data_type = quantizer.data_type + break + + for quantizer in self._get_param_quantizers(name_to_quantizer_dict): + if quantizer.enabled: + parameter_bw = quantizer.bitwidth + parameter_data_type = quantizer.data_type + break + + return (activation_bw, activation_data_type), (parameter_bw, parameter_data_type)
    + + +
    +[docs] + def set_quantizers_to_candidate(self, + name_to_quantizer_dict: Dict, + candidate: CANDIDATE_WITH_DTYPE) -> None: + """ + Sets a quantizer group to a given candidate bitwidth + :param name_to_quantizer_dict: Gets module from module name + :param candidate: candidate with act and param bw and data types + """ + if len(candidate) == 1: + (activation_bw, activation_data_type), = candidate + param_bw, param_data_type = None, None + else: + (activation_bw, activation_data_type), (param_bw, param_data_type) = candidate + + for quantizer in self._get_input_quantizers(name_to_quantizer_dict) +\ + self._get_output_quantizers(name_to_quantizer_dict): + quantizer.bitwidth = activation_bw + quantizer.data_type = activation_data_type + + if param_bw is not None: + for quantizer in self._get_param_quantizers(name_to_quantizer_dict): + quantizer.bitwidth = param_bw + quantizer.data_type = param_data_type
    + + +
    +[docs] + def to_list(self) -> List[Tuple[str, str]]: + """ + Converts quantizer group to a list + :return: List containing input/output quantizers & weight quantizers + """ + return list(itertools.chain( + (("input", module_name) for module_name in self.input_quantizers), + (("output", module_name) for module_name in self.output_quantizers), + (("weight", module_name) for module_name in self.parameter_quantizers), + ))
    + + +
    +[docs] + def get_active_quantizers(self, name_to_quantizer_dict): + """ Find all active tensor quantizers associated with this quantizer group """ + quantizers = self._get_input_quantizers(name_to_quantizer_dict) +\ + self._get_output_quantizers(name_to_quantizer_dict) +\ + self._get_param_quantizers(name_to_quantizer_dict) + return [quantizer for quantizer in quantizers if quantizer.enabled]
    + + + def _get_input_quantizers(self, name_to_quantizer_dict): + result = [] + for quantizer_name in self.input_quantizers: + out = quantizer_name.split("_input_quantizer_idx_") + assert len(out) == 2 + module_name, quantizer_idx = out[0], int(out[1]) + module = name_to_quantizer_dict[module_name] + result.append(module.input_quantizers[quantizer_idx]) + return result + + def _get_output_quantizers(self, name_to_quantizer_dict): + result = [] + for module_name in self.output_quantizers: + module = name_to_quantizer_dict[module_name] + result += module.output_quantizers + return result + + def _get_param_quantizers(self, name_to_quantizer_dict): + result = [] + for module_name in self.parameter_quantizers: + module = name_to_quantizer_dict[module_name] + for _, param_quantizer in module.param_quantizers.items(): + result.append(param_quantizer) + return result + +
    +[docs] + def get_input_quantizer_modules(self): + """helper method to get the module names corresponding to input_quantizers""" + result = set() + for quantizer_name in self.input_quantizers: + out = quantizer_name.split("_input_quantizer_idx_") + assert len(out) == 2 + result.add(out[0]) + return tuple(sorted(result))
    +
    + + + +def find_wrapper_module(op_name: str, module_name_to_quantizer_dict: Dict) -> \ + Tuple[Optional[str], Optional[torch.nn.Module]]: + """ + Finds quantization (wrapping) module corresponding to the wrapper module's dotted name + :param op_name: Dotted name of op as represented in connected graph + :param module_name_to_quantizer_dict: Dict key: name of wrapped module value: quantization wrapper + :return: Module name and the corresponding torch module in the sim + """ + # pylint:disable = protected-access + module_name = op_name[op_name.find('.') + 1:] + if module_name in module_name_to_quantizer_dict: + return module_name, module_name_to_quantizer_dict[module_name] + # Else it is a functional op + return None, None + + +def get_module_name_to_module_dict(sim: _QuantizationSimModelInterface) -> Dict: + """ + Creates a dictionary of wrapped module's name to quantizer module + :param sim: quantization sim + :return: Dict key: name of wrapped module value: quantization wrapper + """ + module_name_to_quantizer_dict = {} + for name, ref_module in sim.model.named_modules(): + if isinstance(ref_module, _QuantizedModuleProtocol): + module_name_to_quantizer_dict[name] = ref_module + return module_name_to_quantizer_dict + + +ops_to_skip = ['view', + 'NumToTensor', + 'Split', + CG_SPLIT, + 'PythonOp', + 'Tile', + 'transpose', + 'reshape', + 'flatten', + 'permute', + 'Permute', # tensor.transpose() results in Permute. Name obtained after mpp + 'Reshape', # Name obtained after MPP + 'ChannelShuffle', # Obtained without going thru mpp. torch.nn.ChannelShuffle fails mpp + 'TopK', # Name obtained after MPP + 'PixelShuffle', # Name obtained after MPP + 'Expand', # Name obtained after MPP. Reproduce using tensor.expand + 'Pad', # Name obtained after MPP + 'Slice', # Name obtained after MPP + 'Gather', # Name obtained after MPP + 'ScatterElements', # Name obtained after MPP + 'ReduceMin', # Name obtained after MPP + 'ReduceMax', # Name obtained after MPP + 'Upsample', # Name obtained after MPP + 'RoIPool', # Name obtained after MPP + 'MaxPool', # Name obtained after MPP + 'Transpose' # Name obtained after MPP + ] +ops_not_to_traverse = ['size'] + +def find_output_quantizer_groups(op: Op, parent_child_op_groups: Dict, map_for_skipped_ops: Dict): + """ + Finds quantizer groups along the parent to child flow + :param op: pytorch module + :param parent_child_op_groups: parent child relationships in graph + :param map_for_skipped_ops: map to find first skipped parents of skipped ops + """ + output = op.output + if output: + consumers = output.consumers + for consumer in consumers: + if consumer.type in ops_not_to_traverse: + continue + dotted_name = op.dotted_name + if op.dotted_name in map_for_skipped_ops: + dotted_name = map_for_skipped_ops[op.dotted_name] + if consumer.type in ops_to_skip: + map_for_skipped_ops[consumer.dotted_name] = dotted_name + find_output_quantizer_groups(consumer, parent_child_op_groups, map_for_skipped_ops) + # If there is a one to one connection between quantizers + else: + parent_child_op_groups[dotted_name].append(consumer.dotted_name) + else: + if op.dotted_name in map_for_skipped_ops: + parent_child_op_groups[map_for_skipped_ops[op.dotted_name]] = [] + + +def find_op_groups(graph: ConnectedGraph) -> Dict: + """ + Finds parent children relationship based on three rules + 1) If there is a direct connection between two ops, op1 and op2, then op1 is parent of op2 and they form a group + 2) If the input to an op (op1) is shared with another op (op2), the op producing the input (op0) is the parent, and op1 and op2 are the children + :param graph: connected graph + :return: Dict of parent (key) and children (value) relationship + """ + parent_child_op_groups = defaultdict(list) + map_for_skipped_ops = {} + + for op in graph.ordered_ops: + # Add 1st op as child + if not op.input_ops: + parent_child_op_groups['input_ops'].append(op.dotted_name) + # Add output op as child to put output of model as a quantizer group + if op.output is None: + parent_child_op_groups['output_ops'].append(op.dotted_name) + for op in graph.get_all_ops().values(): + if op.type in ops_to_skip or op.type in ops_not_to_traverse: + continue + find_output_quantizer_groups(op, parent_child_op_groups, map_for_skipped_ops) + + return parent_child_op_groups + + +# This code is not currently called anywhere but it can be used to combine two ops who feed into an elementwise op +def find_input_quantizer_groups(graph, map_for_skipped_ops, parent_child_op_groups): + """ + Combines two groups which share the same output + :param graph: connected graph + :param map_for_skipped_ops: map to find first skipped parents of skipped ops + :param parent_child_op_groups: parent child relationships in graph + """ + + for op in graph.get_all_ops().values(): + inputs = op.input_ops + if len(inputs) > 1: + new_parents = set() + new_children = set() + for input_op in inputs: + dotted_name = input_op.dotted_name + + if input_op.type in ops_to_skip: + dotted_name = map_for_skipped_ops[dotted_name] + + new_parents.add(dotted_name) + + if dotted_name in parent_child_op_groups: + for name in parent_child_op_groups[dotted_name]: + new_children.add(name) + del parent_child_op_groups[dotted_name] + if len(new_parents) == 1: + parent_child_op_groups[tuple(new_parents)[0]] = new_children + else: + parent_child_op_groups[tuple(new_parents)] = new_children + + +def get_input_and_param_quantizers( + child: str, module_name_to_module_dict: Dict +) -> Tuple[Tuple[str, ...], Tuple[str, ...]]: + """ + Adds child's input quantizer and param quantizer to quantizer group + :param child: name of child + :param module_name_to_module_dict: name to module ref dict + :param quantizer_group: quantizer group + """ + input_quantizers = [] + parameter_quantizers = [] + module_name, module = find_wrapper_module(child, module_name_to_module_dict) + if module_name is not None: + for idx, input_quantizer in enumerate(module.input_quantizers): + if input_quantizer.enabled: + input_quantizers.append(module_name + '_input_quantizer_idx_' + str(idx)) + for _, param_quantizer in module.param_quantizers.items(): + if param_quantizer.enabled: + parameter_quantizers.append(module_name) + return tuple(input_quantizers), tuple(parameter_quantizers) + + +# pylint: disable=too-many-branches, too-many-locals +def find_quantizer_group(sim: _QuantizationSimModelInterface) -> Tuple[Dict, List[QuantizerGroup]]: + """ + Finds quantizer groups in a quantization sim model + :param sim: Quantization sim + :return: List of Quantizer groups + """ + # Get connected graph from quantsim for model without wrappers + connected_graph = sim.connected_graph + + if connected_graph is None: + raise AssertionError('Aborting Auto Mixed Precision, connected graph needs to exist for Auto Mixed precision') + + quantizer_groups = [] + + parent_child_op_groups = find_op_groups(connected_graph) + + module_name_to_module_dict = get_module_name_to_module_dict(sim) + + if 'input_ops' in parent_child_op_groups: + for child in parent_child_op_groups['input_ops']: + # Add one quantizer group for each input and it's weight param + input_quantizers, parameter_quantizers = get_input_and_param_quantizers(child, module_name_to_module_dict) + if input_quantizers or parameter_quantizers: + child_module_name, _ = find_wrapper_module(child, module_name_to_module_dict) + supported_kernel_ops = [] + if child_module_name is not None: + supported_kernel_ops.append(child_module_name) + quantizer_group = QuantizerGroup( + input_quantizers=input_quantizers, + parameter_quantizers=parameter_quantizers, + supported_kernel_ops=tuple(supported_kernel_ops) + ) + quantizer_groups.append(quantizer_group) + logger.debug('\n Quantizer Group Added: %s', quantizer_group) + + # Based on which quantizers are enabled, create a list of quantizer_groups + for parents, children in parent_child_op_groups.items(): + input_quantizers = () + output_quantizers = () + parameter_quantizers = () + if parents in ['input_ops', 'output_ops']: + continue + if not isinstance(parents, tuple): + parents = [parents] + for parent in parents: + module_name, module = find_wrapper_module(parent, module_name_to_module_dict) + if module is not None: + for output_quantizer in module.output_quantizers: + if output_quantizer.enabled: + output_quantizers += (module_name,) + + supported_kernel_ops = [] + for child in children: + input_q, param_q = get_input_and_param_quantizers(child, module_name_to_module_dict) + input_quantizers += input_q + parameter_quantizers += param_q + child_module_name, _ = find_wrapper_module(child, module_name_to_module_dict) + if child_module_name is not None: + supported_kernel_ops.append(child_module_name) + + # Don't add quantizer group if it is empty + if input_quantizers or output_quantizers or parameter_quantizers: + quantizer_group = QuantizerGroup( + input_quantizers=input_quantizers, + output_quantizers=output_quantizers, + parameter_quantizers=parameter_quantizers, + supported_kernel_ops=tuple(supported_kernel_ops) + ) + quantizer_groups.append(quantizer_group) + logger.debug('\n Quantizer Group added: %s', quantizer_group) + + if 'output_ops' in parent_child_op_groups: + for parent in parent_child_op_groups['output_ops']: + # Add one quantizer group for each input and it's weight param + module_name, module = find_wrapper_module(parent, module_name_to_module_dict) + if module is not None: + for output_quantizer in module.output_quantizers: + if output_quantizer.enabled: + # Using empty supported kernel ops so that model output quantizers are able to consider all + # default candidates + quantizer_group = QuantizerGroup( + output_quantizers=(module_name,), + supported_kernel_ops=tuple() + ) + quantizer_groups.append(quantizer_group) + logger.debug('\n Quantizer Group added: %s', quantizer_group) + + return module_name_to_module_dict, quantizer_groups + + +def find_supported_candidates(quantizer_groups: List[QuantizerGroup], + amp_candidates: List[CANDIDATE_WITH_DTYPE], + supported_kernels: Dict, + module_name_to_module_dict: Dict, + use_all_amp_candidates: bool) -> Tuple[Dict, List]: + """ + Computes 1. a list of supported candidates per Quantizer and 2. List of candidate options for max_candidate + :param quantizer_groups: List of quantizer groups computed for the given model + :param amp_candidates: List of candidates specified by the user to be used for the AMP algorithm + :param supported_kernels: Dict of supported kernels for a given op/defaults specified in the config file + :param module_name_to_module_dict: Dict mapping module name to module/quantizer + :param use_all_amp_candidates: Boolean value representing whether the unsupported candidates in the + "candidates" list need to be considered for creating the output lists. If set to True, all the AMP candidates are + directly used for all the Quantizers, else the candidates per Quantizers are computed. + """ + + quantizers_with_supported_candidates = defaultdict(list) + + # pylint: disable=too-many-nested-blocks + # pylint: disable=protected-access + for quantizer_group in quantizer_groups: + quantizers = sorted(set(itertools.chain(quantizer_group.get_input_quantizer_modules(), + quantizer_group.output_quantizers, + quantizer_group.parameter_quantizers))) + + # quantizers are now unique ops present in the given quantizer_group + onnx_ops = defaultdict(list) + supported_kernel_types = set() + for supported_kernel_op in quantizer_group.supported_kernel_ops: + try: + module = module_name_to_module_dict[supported_kernel_op]._module_to_wrap + except AttributeError: + module = module_name_to_module_dict[supported_kernel_op].get_original_module() + backend_type = aimet_op_to_backend_op_name_map.get(type(module)) + + if backend_type in supported_kernels: + supported_kernel_types.add(backend_type) + else: + onnx_types = onnx_utils.map_torch_types_to_onnx.get(type(module), []) + + if not onnx_types: + logger.warning("No mapping found for %s in the torch to onnx op type mapping dictionary.", + type(module)) + + supported_kernel_types.update(onnx_types) + + for onnx_type in onnx_types: + if onnx_type not in supported_kernels.keys(): + if module in supported_kernels: + supported_kernels[onnx_type] = supported_kernels[module] + + for quantizer in quantizers: + onnx_ops[quantizer] = list(supported_kernel_types) + + supported_kernels_for_quantizers = get_supported_candidates_for_quantizers(quantizers, + onnx_ops, + supported_kernels, + amp_candidates, + use_all_amp_candidates) + + quantizers_with_supported_candidates[quantizer_group] = supported_kernels_for_quantizers.copy() + + max_candidate_options = compute_baseline_candidate_options(quantizers_with_supported_candidates, amp_candidates, + use_all_amp_candidates) + + return quantizers_with_supported_candidates, max_candidate_options +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/_base/mixed_precision.html b/releases/2.0.0/_modules/aimet_torch/_base/mixed_precision.html new file mode 100644 index 0000000..51bc108 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/_base/mixed_precision.html @@ -0,0 +1,464 @@ + + + + + + + + aimet_torch._base.mixed_precision - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch._base.mixed_precision

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Mixed precision inference """
    +
    +from typing import Union, Tuple, List
    +import torch
    +
    +from aimet_common.utils import AimetLogger
    +from aimet_common.amp.utils import (
    +    visualize_quantizer_group_sensitivity,
    +    visualize_pareto_curve,
    +    CANDIDATE_WITH_DTYPE as TORCH_CANDIDATE,
    +    AMPSearchAlgo,
    +)
    +from aimet_common.defs import CallbackFunc
    +from .quantsim import _QuantizationSimModelInterface
    +from .amp.mixed_precision_algo import GreedyMixedPrecisionAlgo
    +from .amp.quantizer_groups import QuantizerGroup
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.MixedPrecision)
    +
    +
    +# pylint: disable=too-many-arguments
    +
    +[docs] +def choose_mixed_precision(sim: _QuantizationSimModelInterface, dummy_input: Union[torch.Tensor, Tuple], + candidates: List[TORCH_CANDIDATE], eval_callback_for_phase1: CallbackFunc, + eval_callback_for_phase2: CallbackFunc, allowed_accuracy_drop: Union[None, float], + results_dir: str, clean_start: bool, forward_pass_callback: CallbackFunc, + use_all_amp_candidates: bool = False, phase2_reverse: bool = False, + phase1_optimize: bool = True, amp_search_algo: AMPSearchAlgo = AMPSearchAlgo.Binary) -> \ + Union[List[Tuple[int, float, QuantizerGroup, int]], None]: + """ + High-level API to perform in place Mixed Precision evaluation on the given sim model. A pareto list is created and + a curve for Accuracy vs BitOps is saved under the results directory + + :param sim: Quantized sim model + :param dummy_input: Dummy input to the model. If the model has more than one input, pass a tuple. + User is expected to place the tensors on the appropriate device. + :param candidates: List of tuples for all possible bitwidth values for activations and parameters + Suppose the possible combinations are- + ((Activation bitwidth - 8, Activation data type - int), (Parameter bitwidth - 16, parameter data type - int)) + ((Activation bitwidth - 16, Activation data type - float), (Parameter bitwidth - 16, parameter data type - float)) + candidates will be [((8, QuantizationDataType.int), (16, QuantizationDataType.int)), + ((16, QuantizationDataType.float), (16, QuantizationDataType.float))] + :param eval_callback_for_phase1: An object of CallbackFunc class which takes in Eval function (callable) and eval + function parameters. This evaluation callback used to measure sensitivity of each + quantizer group during phase 1. The phase 1 involves finding accuracy list/sensitivity of each + module. Therefore, a user might want to run the phase 1 with a smaller dataset + :param eval_callback_for_phase2: An object of CallbackFunc class which takes in Eval function (callable) and eval + function parameters. Evaluation callback used to get accuracy of quantized model + for phase 2 calculations. The phase 2 involves finding pareto front curve + :param allowed_accuracy_drop: Maximum allowed drop in accuracy from FP32 baseline. The pareto front curve is plotted only till the point where the allowable + accuracy drop is met. To get a complete plot for picking points on the curve, the user + can set the allowable accuracy drop to None. + :param results_dir: Path to save results and cache intermediate results + :param clean_start: If true, any cached information from previous runs will be deleted prior to starting the + mixed-precision analysis. If false, prior cached information will be used if applicable. Note + it is the user's responsibility to set this flag to true if anything in the model or + quantization parameters changes compared to the previous run. + :param forward_pass_callback: An object of CallbackFunc class which takes in Forward pass function (callable) and its + function parameters. Forward pass callback used to compute quantization encodings + :param use_all_amp_candidates: Using the “supported_kernels” field in the config file (under defaults + and op_type sections), a list of supported candidates can be specified. All the AMP candidates + which are passed through the “candidates” field may not be supported based on the data passed + through “supported_kernels”. When the field “use_all_amp_candidates” is set to True, the AMP + algorithm will ignore the "supported_kernels" in the config file and continue to use all candidates. + :param phase2_reverse: If user will set this parameter to True, then phase1 of amp algo, that is calculating accuracy list + will not be changed, whereas the phase2 algo of amp, which generate the pareto list will be changed. In phase2, algo will start, + model with all quantizer groups in least candidate, and one by one, it will put nodes in higher candidate till target accuracy does not meet. + :param phase1_optimize: If user set this parameter to false then phase1 default logic will be executed else optimized logic will be executed. + :param amp_search_algo: A valid value from the Enum AMPSearchAlgo. Defines the search algorithm to be used for + the phase 2 of AMP. + + :return: Pareto front list containing information including Bitops, QuantizerGroup candidates and + corresponding eval scores. The Pareto front list can be used for plotting a pareto front curve which + provides information regarding how bit ops vary w.r.t. accuracy. If the allowable accuracy drop is set to + 100% then a user can use the pareto front curve to pick points and re-run, + None if we early exit the mixed precision algorithm. + """ + mixed_precision_algo = GreedyMixedPrecisionAlgo(sim, dummy_input, candidates, eval_callback_for_phase1, + eval_callback_for_phase2, results_dir, clean_start, + forward_pass_callback, use_all_amp_candidates, phase2_reverse, phase1_optimize) + mixed_precision_algo.run(allowed_accuracy_drop, amp_search_algo) + + if mixed_precision_algo.accuracy_list is not None and mixed_precision_algo.pareto_list is not None: + # Print mixed precision stats + logger.info(mixed_precision_algo) + + # Visualize quantizer group sensitivity + visualize_quantizer_group_sensitivity(mixed_precision_algo.accuracy_list, + mixed_precision_algo.baseline_candidate, + mixed_precision_algo.fp32_accuracy, + results_dir=results_dir) + # Create pareto list curve + visualize_pareto_curve(mixed_precision_algo.pareto_list, results_dir) + return mixed_precision_algo.pareto_list + + return None
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/_base/seq_mse.html b/releases/2.0.0/_modules/aimet_torch/_base/seq_mse.html new file mode 100644 index 0000000..ee328d6 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/_base/seq_mse.html @@ -0,0 +1,904 @@ + + + + + + + + aimet_torch._base.seq_mse - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch._base.seq_mse

    +# /usr/bin/env python
    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Sequential MSE base """
    +
    +from abc import abstractmethod, ABC
    +import json
    +import os
    +import tempfile
    +import contextlib
    +from dataclasses import dataclass
    +from typing import Optional, Tuple, List, Callable
    +import torch
    +import torch.nn.functional as functional
    +from torch.utils.data import DataLoader
    +
    +from aimet_common.utils import AimetLogger
    +
    +from aimet_torch.utils import CachedDataset, get_ordered_list_of_modules, in_eval_mode, StopForwardException,\
    +    change_tensor_device_placement, get_device
    +from aimet_torch._base.adaround.activation_sampler import create_modulelist_for_group_modules,\
    +    get_block_inputs, get_block_outputs
    +
    +# The following modules with weights are supported
    +SUPPORTED_MODULES = (torch.nn.Linear, torch.nn.Conv2d, )
    +
    +# Skip running Sequential MSE if param BW is higher than supported PARAM_BW.
    +SUPPORTED_PARAM_BW = 4
    +
    +_logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.SeqMse)
    +
    +
    +def default_forward_fn(model, inputs):
    +    """
    +    Default forward function.
    +    :param model: pytorch model
    +    :param inputs: model inputs
    +    """
    +    if isinstance(inputs, torch.Tensor):
    +        inputs = [inputs]
    +    return model(*inputs)
    +
    +
    +
    +[docs] +@dataclass +class SeqMseParams: + """ + Sequential MSE parameters + + :param num_batches: Number of batches. + :param num_candidates: Number of candidates to perform grid search. Default 20. + :param inp_symmetry: Input symmetry. Available options are 'asym', 'symfp' and 'symqt'. Default 'symqt'. + :param loss_fn: Loss function. Available options are 'mse', 'l1' and 'sqnr'. Default 'mse'. + :param forward_fn: Optional adapter function that performs forward pass given a model and inputs + yielded from the data loader. The function expects model as first argument and inputs to model as second argument. + """ + num_batches: int + num_candidates: int = 20 + inp_symmetry: str = 'symqt' + loss_fn: str = 'mse' + forward_fn: Callable = default_forward_fn
    + + + +class SequentialMseBase(ABC): + """ + Sequentially minimizing activation MSE loss in layer-wise way to decide optimal param quantization encodings. + """ + @classmethod + def apply_seq_mse(cls, + model: torch.nn.Module, + sim, + data_loader: DataLoader, + params: SeqMseParams, + modules_to_exclude: Optional[List[torch.nn.Module]] = None, + checkpoints_config: Optional[str] = None): + """ + Sequentially minimizing activation MSE loss in layer-wise way to decide optimal param quantization encodings. + + 1 Disable all input/output quantizers, param quantizers of non-supported modules + 2 Find and feeze optimal parameter encodings candidate for remaining supported modules + 3 Re-enable disabled quantizers from step 1 + + Example userflow: + model = Model().eval() + sim = QuantizationSimModel(...) + apply_seq_mse(...) + sim.compute_encodings(...) [compute encodings for all activations and parameters of non-supported modules] + sim.export(...) + + NOTE: + 1) module reference passed to modules_to_exclude should be from FP32 model. + 2) module from modules_to_exclude won't be quantized and skipped when applying sequential MSE. + 3) Except finding param encodings for supported modules, config JSON file will be respected and + final state of sim will be unchanged. + + :param model: Original fp32 model + :param sim: Corresponding QuantizationSimModel object + :param data_loader: Data loader + :param params: Sequential MSE parameters + :param modules_to_exclude: List of supported type module(s) to exclude when applying Sequential MSE + :param checkpoints_config: Config files to split fp32/quant model by checkpoints to speedup activations sampling + """ + # disable all input/output activation quantizers and + # param quantizers of all the non-supported modules and from modules_to_exclude list. + # then, re-enable disabled quantizers after running sequential mse. + # this ensures that config JSON file will be respected and final state of sim will be unchanged. + with cls.temporarily_disable_quantizers(model, sim, modules_to_exclude), \ + tempfile.TemporaryDirectory() as tempdir: + + # Initialize param encodings of modules of supported types. + cls.compute_all_param_encodings(sim) + + cached_dataset = CachedDataset(data_loader, params.num_batches, os.path.join(tempdir, 'cached_dataset')) + if checkpoints_config: + cls.apply_seq_mse_using_opt_sampling(checkpoints_config, model, sim, modules_to_exclude, cached_dataset, params, + tempdir) + else: + dummy_input = change_tensor_device_placement(next(iter(data_loader)), get_device(model)) + fp32_modules = get_ordered_list_of_modules(model, dummy_input, fwd_func=params.forward_fn) + fp32_modules = [(name, module) for name, module in fp32_modules if isinstance(module, SUPPORTED_MODULES)] + if modules_to_exclude: + fp32_modules = [(name, module) for name, module in fp32_modules if not module in modules_to_exclude] + + # Find and freeze optimal param encodings candidate + cls.run_seq_mse(fp32_modules, model, sim.model, params, params.forward_fn, + cached_dataset, cached_quant_dataset=None) + + @classmethod + def apply_seq_mse_using_opt_sampling(cls, + checkpoints_config: str, + model: torch.nn.Module, + sim, + modules_to_exclude: Optional[List[torch.nn.Module]], + cached_dataset: CachedDataset, + params: SeqMseParams, + tempdir: str): + """ + Apply sequential MSE using optimized sampling of intermediate data. When checkpoints_config file is provided, + intermediate activations from breakpoint are treated as model inputs for next blocks. + + NOTE: Assumption is that the outputs from the current block are fed directly to following block + and there are no functional operations in-between. + + :param checkpoints_config: Config files to split fp32/quant model by checkpoints to speedup activations sampling + :param model: Original fp32 model + :param sim: Corresponding QuantizationSimModel object + :param modules_to_exclude: List of supported type module(s) to exclude when applying Sequential MSE + :param cached_dataset: Cached dataset + :param params: Sequential MSE parameters + :param tempdir: temporary working directory + """ + # pylint: disable=too-many-locals + ckpts_file = json.load(open(checkpoints_config)) + assert 'grouped_modules' in ckpts_file.keys(), \ + "Please provide a dictionary of grouped_modules in the file to define checkpoints" + assert 'include_static_inputs' in ckpts_file.keys(), \ + "Please provide a dictionary of include_static_inputs in the file to define checkpoints" + assert 'cache_on_cpu' in ckpts_file.keys(), \ + "Please define cache_on_cpu to determine whether to cache intermediate tensors on CPU" + + grouped_modules = ckpts_file['grouped_modules'] + breakpoint_module_name = ckpts_file['grouped_modules'][list(grouped_modules.keys())[0]][0] + include_static_inputs = ckpts_file['include_static_inputs'] + cache_on_cpu = ckpts_file['cache_on_cpu'] + cached_fp_dataset, cached_quant_dataset = get_block_inputs(model, sim, + breakpoint_module_name, + cached_dataset, cache_on_cpu, + params.forward_fn, params.num_batches, + tempdir) + device = get_device(model) + model.cpu() + sim.model.cpu() + + # Forward function for the ModuleList object + def fwd_fn_modulelist(modulelists, x): + for mod in modulelists: + x = mod(*x) if isinstance(x, (tuple, list)) else mod(x) + return x + + sub_fp_models, sub_sim_models = create_modulelist_for_group_modules(model, sim, grouped_modules) + for i, (fp_block, quant_sim_block, static_input) in enumerate(zip(sub_fp_models, + sub_sim_models, + include_static_inputs)): + fp32_modules = get_ordered_list_of_modules(fp_block, cached_fp_dataset[0], fwd_func=fwd_fn_modulelist) + fp32_modules = [(name, module) for name, module in fp32_modules if isinstance(module, SUPPORTED_MODULES)] + if modules_to_exclude: + fp32_modules = [(name, module) for name, module in fp32_modules if not module in modules_to_exclude] + + cls.run_seq_mse(fp32_modules, fp_block, quant_sim_block, params, fwd_fn_modulelist, + cached_fp_dataset, cached_quant_dataset=cached_quant_dataset) + + # Get the outputs from the current block and assign to be the inputs for next block + # except for the last block + if i < len(sub_fp_models) - 1: + get_block_outputs(fp_block, quant_sim_block, static_input, + cached_fp_dataset, cached_quant_dataset, cache_on_cpu, + fwd_fn_modulelist, device, tempdir) + model.to(device) + sim.model.to(device) + + @classmethod + def run_seq_mse(cls, + fp32_modules: List[Tuple[str, torch.nn.Module]], + model: torch.nn.Module, + quant_model: torch.nn.Module, + params: SeqMseParams, + forward_fn: Callable, + cached_fp_dataset: CachedDataset, + cached_quant_dataset: Optional[CachedDataset] = None, + ): + """ + Run Sequential MSE + + :param fp32_modules: List of FP32 candidate modules in order of occurence + :param model: FP32 model + :param quant_model: QuantizationSimModel object + :param params: Sequential MSE parameters + :param forward_fn: Optional adapter function that performs forward pass given a model and inputs + yielded from the data loader. The function expects model as first argument and inputs to model as second argument. + :param cached_fp_dataset: Cached dataset object + :param cached_quant_dataset: Cached dataset object + """ + name_to_quant_module = {} + for name, quant_module in quant_model.named_modules(): + name_to_quant_module[name] = quant_module + + if not cached_quant_dataset: + cached_quant_dataset = cached_fp_dataset + + for module_qualified_name, fp32_module in fp32_modules: + try: + quant_module = name_to_quant_module[module_qualified_name] + except KeyError: + continue + + if quant_module.param_quantizers['weight'].bitwidth > SUPPORTED_PARAM_BW: + continue + + _logger.info("Finding and freezing optimal param encodings candidate of module: %s", module_qualified_name) + if params.inp_symmetry == "asym": + fp32_inp_acts = cls.get_module_inp_acts(fp32_module, model, params, forward_fn, cached_fp_dataset) + quant_inp_acts = cls.get_module_inp_acts(quant_module, quant_model, params, forward_fn, cached_quant_dataset) + cls.optimize_module(quant_module, fp32_inp_acts, quant_inp_acts, params) + elif params.inp_symmetry == "symfp": + fp32_inp_acts = cls.get_module_inp_acts(fp32_module, model, params, forward_fn, cached_fp_dataset) + cls.optimize_module(quant_module, fp32_inp_acts, fp32_inp_acts, params) + elif params.inp_symmetry == "symqt": + quant_inp_acts = cls.get_module_inp_acts(quant_module, quant_model, params, forward_fn, cached_quant_dataset) + cls.optimize_module(quant_module, quant_inp_acts, quant_inp_acts, params) + else: + raise ValueError(f"Invalid inp_symmetry: {params.inp_symmetry}") + + @staticmethod + def get_module_inp_acts(module: torch.nn.Module, + model: torch.nn.Module, + params: SeqMseParams, + forward_fn: Callable, + cached_dataset: CachedDataset, + ) -> torch.Tensor: + """ + For given module, get inputs to the module. + + :param module: FP32/quant module + :param model: FP32/quant model + :param params: Sequential MSE parameters + :param forward_fn: Optional adapter function that performs forward pass given a model and inputs + yielded from the data loader. The function expects model as first argument and inputs to model as second argument. + :param cached_dataset: Cached dataset + :return: Concatenated inputs + """ + inp_acts = [] + def hook_fn(_, inp, __): + if isinstance(inp, tuple): + inp_acts.append(inp[0]) + raise StopForwardException + handle = module.register_forward_hook(hook_fn) + + iterator = iter(cached_dataset) + for _ in range(params.num_batches): + batch = change_tensor_device_placement(next(iterator), get_device(model)) + try: + with in_eval_mode(model), torch.no_grad(): + forward_fn(model, batch) + except StopForwardException: + pass + handle.remove() + + inp_acts = torch.stack(inp_acts) + return inp_acts + + @staticmethod + def _get_quantizers_to_be_disabled( + model: torch.nn.Module, + sim, + modules_to_exclude: Optional[List[torch.nn.Module]], + ): + """ + For given quantsim model, get all quantizers to be disabled before applying sequential MSE. + """ + # pylint: disable=protected-access + name_to_fp32_module_dict = {} + for name, fp32_module in model.named_modules(): + name_to_fp32_module_dict[name] = fp32_module + + quantizers_to_be_disabled = [] + for name, quant_wrapper in sim.quant_wrappers(): + for quantizer in quant_wrapper.input_quantizers: + if quantizer.enabled: + quantizers_to_be_disabled.append(quantizer) + + for quantizer in quant_wrapper.output_quantizers: + if quantizer.enabled: + quantizers_to_be_disabled.append(quantizer) + + for quantizer in quant_wrapper.param_quantizers.values(): + if not isinstance(quant_wrapper._module_to_wrap, SUPPORTED_MODULES) and quantizer.enabled: + quantizers_to_be_disabled.append(quantizer) + + # disable param quantizers from exclusion list + if modules_to_exclude: + with contextlib.suppress(KeyError): + fp32_module = name_to_fp32_module_dict[name] + if fp32_module in modules_to_exclude: + for quantizer in quant_wrapper.param_quantizers.values(): + if quantizer.enabled: + quantizers_to_be_disabled.append(quantizer) + + return quantizers_to_be_disabled + + @staticmethod + def get_candidates(num_candidates: int, + per_channel_max: torch.Tensor, + per_channel_min: Optional[torch.Tensor]) -> List[Tuple[torch.Tensor, torch.Tensor]]: + """ + Perform grid search. + + :param num_candidates: Number of candidates + :param per_channel_max: Per channel max values + :param per_channel_min: Per channel min values + :return: candidates + """ + candidates = [] + if per_channel_min is not None: + for cand in range(num_candidates): + cand_max = torch.tensor(per_channel_max / num_candidates * (cand + 1)) + cand_min = torch.tensor(per_channel_min / num_candidates * (cand + 1)) + candidates.append((cand_max, cand_min)) + else: + for cand in range(num_candidates): + cand_max = torch.tensor(per_channel_max / num_candidates * (cand + 1)) + cand_min = -cand_max + candidates.append((cand_max, cand_min)) + return candidates + + @staticmethod + def compute_recon_loss(xqwq: torch.Tensor, xw: torch.Tensor, params: SeqMseParams): + """ + Compute reconstruction loss and return the sum by reducing over all the dimensions except last channel dimension. + + :param xqwq: X^Q^ quantized-dequantized values + :param xw: XW FP32 values + :param params: Sequential MSE parameters + :return: loss + """ + if params.loss_fn == "mse": + loss_fn = functional.mse_loss + elif params.loss_fn == "l1": + loss_fn = functional.l1_loss + elif params.loss_fn == "sqnr": + loss_fn = neg_sqnr + else: + raise ValueError(f"Invalid loss function: {params.loss_fn}") + + channel_dim = xqwq.shape[-1] + xqwq = xqwq.reshape(-1, channel_dim) + xw = xw.reshape(-1, channel_dim) + loss = loss_fn(xqwq, xw, reduction="none").sum(0) + assert loss.size() == torch.Size([channel_dim]) + return loss + + @classmethod + def get_per_channel_min_and_max(cls, quant_module) -> Tuple[torch.Tensor, torch.Tensor]: + """ + Get per channel min/max values across output channel. + + :param quant_module: Quant module to be optimized + :return: + """ + # pylint: disable=protected-access + module = cls._get_original_module(quant_module) + + if isinstance(module, torch.nn.Conv2d): + channel_dim = module.out_channels + weight = module.weight.reshape(channel_dim, -1) + elif isinstance(module, torch.nn.Linear): + weight = module.weight + else: + raise ValueError('Unsupported module: ', module) + + if cls._is_symmetric_quantizer(quant_module.param_quantizers["weight"]): + per_channel_max = torch.max(weight.abs(), dim=1)[0].detach() + per_channel_min = None + else: + per_channel_max = torch.max(weight, dim=1)[0].detach() + per_channel_min = torch.min(weight, dim=1)[0].detach() + + return per_channel_min, per_channel_max + + @classmethod + def compute_outputs(cls, + quant_module, + x: torch.Tensor, + xq: torch.Tensor, + w: torch.Tensor, + wq: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: + """ + Compute X^W^ and XW output activations. + + :param quant_module: Wrapper module to be optimized + :param x: Inputs from FP32 model + :param xq: Inputs from QuantSim model + :param w: FP32 weights + :param wq: Quantized-dequantized weights + :return: xqwq, xw + """ + # pylint: disable=protected-access + module = cls._get_original_module(quant_module) + + if isinstance(module, torch.nn.Linear): + xqwq = functional.linear(xq, wq) + xw = functional.linear(x, w) + elif isinstance(module, torch.nn.Conv2d): + xqwq = functional.conv2d(xq, wq, stride=module.stride, dilation=module.dilation, + padding=module.padding, groups=module.groups) + xw = functional.conv2d(x, w, stride=module.stride, dilation=module.dilation, + padding=module.padding, groups=module.groups) + + # [N, C, H, W] --> [N, H, W, C], so that loss can be computed across channel dimension. + xqwq = xqwq.permute(0, 2, 3, 1) + xw = xw.permute(0, 2, 3, 1) + else: + raise ValueError('Unsupported module: ', module) + return xqwq, xw + + @classmethod + @abstractmethod + def temporarily_disable_quantizers( + cls, + model: torch.nn.Module, + sim, + modules_to_exclude: Optional[List[torch.nn.Module]], + ): + """ + For given quantsim model, disable quantizers needed to be disabled before applying sequential MSE. + + :param model: Original fp32 model + :param sim: QuantizationSimModel object + :param modules_to_exclude: List of supported modules to exclude when applying Sequential MSE + :return: List of quantizers to be disabled. + """ + + @classmethod + @abstractmethod + def compute_all_param_encodings(cls, sim): + """ + Compute encodings for all parameters, needed for initializing Sequential MSE + + :param sim: Quant sim + """ + + @classmethod + @abstractmethod + def optimize_module(cls, + quant_module, + x: torch.Tensor, + xq: torch.Tensor, + params: SeqMseParams): + """ + Find and freeze optimal parameter encodings candidate for given module. + + :param quant_module: Quant module to be optimized + :param x: Inputs to module from FP32 model + :param xq: Inputs to module from QuantSim model + :param params: Sequenial MSE parameters + """ + + @classmethod + @abstractmethod + def compute_param_encodings(cls, + quantizer, + x_min: torch.Tensor, + x_max: torch.Tensor): + """ + Compute encodings for parameter quantizer using given x_min and x_max values. + + :param quantizer: Tensor quantizer + :param x_min: min values + :param x_max: max values + """ + + @classmethod + @abstractmethod + def _is_symmetric_quantizer(cls, quantizer): + ... + + @classmethod + @abstractmethod + def _freeze_quantizer_encoding(cls, quantizer): + ... + + @classmethod + @abstractmethod + def _get_quantized_weight(cls, quant_module): + ... + + @classmethod + @abstractmethod + def _get_original_module(cls, quant_module): + ... + + +def neg_sqnr(pred: torch.Tensor, target: torch.Tensor, eps=1e-10, reduction="none"): + """ + Loss function to minimize negative SQNR which is equivalent to maximizing SQNR. + + :param pred: X^Q^ quantized-dequantized values + :param target: XW FP32 values + :param eps: epsilon + :param reduction: unused arg + :return: Negative SQNR + """ + # pylint: disable=unused-argument + quant_error = target - pred + exp_noise = torch.mean(quant_error ** 2, 0, keepdim=True) + eps + exp_signal = torch.mean(target ** 2, 0, keepdim=True) + sqnr = exp_signal / exp_noise + sqnr_db = 10 * torch.log10(sqnr) + return -sqnr_db +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/bn_reestimation.html b/releases/2.0.0/_modules/aimet_torch/bn_reestimation.html new file mode 100644 index 0000000..4e52f27 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/bn_reestimation.html @@ -0,0 +1,517 @@ + + + + + + + + aimet_torch.bn_reestimation - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.bn_reestimation

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +"""BatchNorm Reestimation"""
    +
    +import itertools
    +from typing import Iterable, List, Callable, Any
    +
    +from tqdm import tqdm
    +import torch
    +from torch.utils.data import DataLoader
    +from torch.nn.modules.batchnorm import _BatchNorm
    +from aimet_torch.utils import in_eval_mode, in_train_mode
    +from aimet_common.utils import Handle
    +
    +def _get_active_bn_modules(model: torch.nn.Module) -> Iterable[_BatchNorm]:
    +    for module in model.modules():
    +        if isinstance(module, _BatchNorm):
    +            bn = module
    +            if bn.running_mean is not None and bn.running_var is not None:
    +                yield bn
    +
    +
    +def _for_each_module(modules: Iterable[torch.nn.Module],
    +                     action: Callable[[torch.nn.Module], Handle]) -> Handle:
    +    """
    +    Apply an undoable action to each module.
    +
    +    :param modules: Modules to apply the action.
    +    :param action: Action to be applied to the modules.
    +    :returns: Handle that undos the applied action.
    +    """
    +
    +    handles: List[Handle] = []
    +
    +    def cleanup():
    +        for handle in handles:
    +            handle.remove()
    +
    +    try:
    +        for module in modules:
    +            handle = action(module)
    +            assert isinstance(handle, Handle)
    +            handles.append(handle)
    +        return Handle(cleanup)
    +    except:
    +        cleanup()
    +        raise
    +
    +
    +def _reset_bn_stats(module: _BatchNorm) -> Handle:
    +    """
    +    Reset BN statistics to the initial values.
    +
    +    :param module: BatchNorm module.
    +    :returns: Handle that restores the original BN statistics upon handle.remove().
    +    """
    +    orig_running_mean = module.running_mean.clone()
    +    orig_running_var = module.running_var.clone()
    +    orig_num_batches_tracked = module.num_batches_tracked.clone()
    +
    +    def cleanup():
    +        module.running_mean.copy_(orig_running_mean)
    +        module.running_var.copy_(orig_running_var)
    +        module.num_batches_tracked.copy_(orig_num_batches_tracked)
    +
    +    try:
    +        module.reset_running_stats()
    +        return Handle(cleanup)
    +    except:
    +        cleanup()
    +        raise
    +
    +
    +def _reset_momentum(module: _BatchNorm) -> Handle:
    +    """
    +    Set BN momentum to 1.0.
    +
    +    :param module: BatchNorm module.
    +    :returns: Handle that restores the original BN momentum upon handle.remove().
    +    """
    +    momentum = module.momentum
    +
    +    def cleanup():
    +        module.momentum = momentum
    +
    +    try:
    +        module.momentum = 1.0
    +        return Handle(cleanup)
    +    except:
    +        cleanup()
    +        raise
    +
    +
    +DEFAULT_NUM_BATCHES = 100
    +
    +
    +
    +[docs] +def reestimate_bn_stats(model: torch.nn.Module, + dataloader: DataLoader, + num_batches: int = DEFAULT_NUM_BATCHES, + forward_fn: Callable[[torch.nn.Module, Any], Any] = None) -> Handle: + """ + Reestimate BatchNorm statistics (running mean and var). + + :param model: Model to reestimate the BN stats. + :param dataloader: Training dataset. + :param num_batches: The number of batches to be used for reestimation. + :param forward_fn: Optional adapter function that performs forward pass + given a model and a input batch yielded from the data loader. + :returns: Handle that undos the effect of BN reestimation upon handle.remove(). + """ + forward_fn = forward_fn or (lambda model, data: model(data)) + bn_modules = tuple(_get_active_bn_modules(model)) + + # Set all the layers to eval mode except batchnorm layers + with in_eval_mode(model), in_train_mode(bn_modules), torch.no_grad(): + with _for_each_module(bn_modules, action=_reset_momentum): + handle = _for_each_module(bn_modules, action=_reset_bn_stats) + + try: + # Batchnorm statistics accumulation buffer + buffer = { + bn: {"sum_mean": torch.zeros_like(bn.running_mean), + "sum_var": torch.zeros_like(bn.running_var)} + for bn in bn_modules + } + + num_batches = min(len(dataloader), num_batches) + dataloader_slice = itertools.islice(dataloader, num_batches) + + for data in tqdm(dataloader_slice, + total=num_batches, + desc="batchnorm reestimation"): + forward_fn(model, data) + + for bn in bn_modules: + buffer[bn]["sum_mean"] += bn.running_mean + buffer[bn]["sum_var"] += bn.running_var + + for bn in bn_modules: + sum_mean = buffer[bn]["sum_mean"] + sum_var = buffer[bn]["sum_var"] + + # Override BN stats with the reestimated stats. + bn.running_mean.copy_(sum_mean / min(len(dataloader), num_batches)) + bn.running_var.copy_(sum_var / min(len(dataloader), num_batches)) + + return handle + except: + handle.remove() + raise
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/compress.html b/releases/2.0.0/_modules/aimet_torch/compress.html new file mode 100644 index 0000000..aa7cef0 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/compress.html @@ -0,0 +1,448 @@ + + + + + + + + aimet_torch.compress - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.compress

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2018, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Top-level API to AIMET compression library """
    +
    +from typing import Union, Tuple
    +import torch
    +
    +from aimet_common.defs import CostMetric, CompressionScheme, EvalFunction, CompressionStats
    +from aimet_common.bokeh_plots import BokehServerSession
    +
    +from aimet_torch.defs import SpatialSvdParameters, WeightSvdParameters, ChannelPruningParameters
    +from aimet_torch.compression_factory import CompressionFactory
    +
    +
    +
    +[docs] +class ModelCompressor: + """ AIMET model compressor: Enables model compression using various schemes """ + # Too many arguments in this function, disabling pylint for now +
    +[docs] + @staticmethod + def compress_model(model: torch.nn.Module, eval_callback: EvalFunction, eval_iterations, + input_shape: Tuple, + compress_scheme: CompressionScheme, cost_metric: CostMetric, + parameters: Union[SpatialSvdParameters, + WeightSvdParameters, + ChannelPruningParameters], + trainer=None, visualization_url=None) -> Tuple[torch.nn.Module, CompressionStats]: + + """ + Compress a given model using the specified parameters + + :param model: Model to compress + :param eval_callback: Evaluation callback. Expected signature is evaluate(model, iterations, use_cuda). + Expected to return an accuracy metric. + :param eval_iterations: Iterations to run evaluation for + :param trainer: Training Class: Contains a callable, train_model, which takes model, layer which is being fine + tuned and an optional parameter train_flag as a parameter + None: If per layer fine tuning is not required while creating the final compressed model + :param input_shape: Shape of the input tensor for model + :param compress_scheme: Compression scheme. See the enum for allowed values + :param cost_metric: Cost metric to use for the compression-ratio (either mac or memory) + :param parameters: Compression parameters specific to given compression scheme + :param visualization_url: url the user will need to input where visualizations will appear + :return: A tuple of the compressed model, and compression statistics + """ + # pylint:disable=too-many-arguments + # If no url is passed in, then do not create a bokeh server session + if not visualization_url: + bokeh_session = None + else: + # create a bokeh session to publish visualizations to the server document for compression + bokeh_session = BokehServerSession(url=visualization_url, session_id="compression") + + # put model in eval mode. This is important because otherwise running a forward pass can change module buffers + # e.g. for batchnorm layers that can affect model evaluation results + if trainer is not None: + trainer.train_model(model, model, train_flag=False) + + model = model.eval() + + if parameters.multiplicity < 1: + raise ValueError('Rounding Multiplicity should be greater than 1') + + if compress_scheme == CompressionScheme.spatial_svd: + algo = CompressionFactory.create_spatial_svd_algo(model, eval_callback, eval_iterations, + input_shape, cost_metric, parameters, bokeh_session) + + elif compress_scheme == CompressionScheme.weight_svd: + algo = CompressionFactory.create_weight_svd_algo(model, eval_callback, eval_iterations, + input_shape, cost_metric, parameters, bokeh_session) + + elif compress_scheme == CompressionScheme.channel_pruning: + algo = CompressionFactory.create_channel_pruning_algo(model, eval_callback, eval_iterations, + input_shape, cost_metric, parameters, bokeh_session) + + else: + raise ValueError("Compression scheme not supported: {}".format(compress_scheme)) + + compressed_layer_db, stats = algo.compress_model(cost_metric, trainer) + return compressed_layer_db.model, stats
    +
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/cross_layer_equalization.html b/releases/2.0.0/_modules/aimet_torch/cross_layer_equalization.html new file mode 100644 index 0000000..fd56bb9 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/cross_layer_equalization.html @@ -0,0 +1,1079 @@ + + + + + + + + aimet_torch.cross_layer_equalization - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.cross_layer_equalization

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2019-2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Cross Layer Equalization
    +
    +Some terminology for this code.
    +CLS set: Set of layers (2 or 3) that can be used for cross-layer scaling
    +Layer groups: Groups of layers that are immediately connected and can be decomposed further into CLS sets
    +"""
    +# pylint: disable=too-many-lines
    +
    +from typing import Tuple, List, Union, Dict
    +import numpy as np
    +import torch
    +
    +from aimet_common.utils import AimetLogger
    +from aimet_common.cross_layer_equalization import ClsLayerType, ClsSetInfo, ClsImpl, HbfImpl
    +from aimet_torch import utils
    +from aimet_torch.meta.connectedgraph import ConnectedGraph
    +from aimet_torch.batch_norm_fold import fold_all_batch_norms
    +from aimet_torch.utils import (get_device, get_ordered_list_of_modules, create_rand_tensors_given_shapes,
    +                               place_model)
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.CrosslayerEqualization)
    +
    +ClsSet = Union[Tuple[torch.nn.Conv2d, torch.nn.Conv2d],
    +               Tuple[torch.nn.Conv2d, torch.nn.Conv2d, torch.nn.Conv2d]]
    +
    +ClsSupportedLayer = Union[torch.nn.Conv1d, torch.nn.Conv2d, torch.nn.ConvTranspose1d, torch.nn.ConvTranspose2d]
    +
    +ScaleFactor = Union[np.ndarray, Tuple[np.ndarray]]
    +
    +cls_supported_layers = (torch.nn.Conv2d, torch.nn.ConvTranspose2d, torch.nn.Conv1d, torch.nn.ConvTranspose1d)
    +cls_supported_activations = (torch.nn.ReLU, torch.nn.PReLU)
    +
    +
    +def get_ordered_list_of_conv_modules(model: torch.nn.Module, dummy_input: Union[torch.Tensor, Tuple]) -> List:
    +    """
    +    Finds order of nodes in graph
    +    :param model: model
    +    :param dummy_input: Dummy input to the model. Used to parse model graph.
    +    :return: List of names in graph in order
    +    """
    +    module_list = get_ordered_list_of_modules(model, dummy_input)
    +    module_list = [[name, module] for name, module in module_list if isinstance(module, cls_supported_layers)]
    +    return module_list
    +
    +
    +class GraphSearchUtils:
    +    """
    +    Code to search a model graph to find nodes to use for cross-layer-scaling and high-bias-fold
    +    """
    +
    +    def __init__(self, model: torch.nn.Module, input_shapes: Union[Tuple, List[Tuple]],
    +                 dummy_input: Union[torch.Tensor, List[torch.Tensor]] = None):
    +        """
    +
    +        :param model: PyTorch model.
    +        :param input_shapes: Input shape for the model (can be one or multiple inputs)
    +        :param dummy_input: Dummy input to the model. Used to parse model graph. dummy_input is expected to be placed
    +         on the same device as model.
    +        """
    +        if dummy_input is None:
    +            inp_tensor_list = tuple(utils.create_rand_tensors_given_shapes(input_shapes, get_device(model)))
    +        else:
    +            inp_tensor_list = dummy_input
    +        self._connected_graph = ConnectedGraph(model, inp_tensor_list)
    +        self._ordered_module_list = get_ordered_list_of_conv_modules(model, inp_tensor_list)
    +
    +
    +    @staticmethod
    +    def find_downstream_layer_groups_to_scale(op, layer_groups, current_group=None, visited_nodes=None):
    +        """
    +        Recursive function to find cls layer groups downstream from a given op
    +        :param op: Starting op to search from
    +        :param layer_groups: Running list of layer groups
    +        :param current_group: Running current layer group
    +        :param visited_nodes: Running list of visited nodes (to short-circuit recursion)
    +        :return: None
    +        """
    +
    +        if not visited_nodes:
    +            visited_nodes = []
    +        if not current_group:
    +            current_group = []
    +
    +        if op in visited_nodes:
    +            return
    +        visited_nodes.append(op)
    +        # print("Visiting node: {}".format(op.dotted_name))
    +
    +        # If current node is Conv2D, add to the current group
    +        if op.model_module and isinstance(op.model_module.get_module(), cls_supported_layers):
    +            current_group.append(op.model_module.get_module())
    +
    +        # Terminating condition for current group
    +        if not op.model_module or not isinstance(op.model_module.get_module(),
    +                                                 cls_supported_layers + cls_supported_activations):
    +
    +            if (len(current_group) > 1) and (current_group not in layer_groups):
    +                layer_groups.append(current_group)
    +            current_group = []
    +
    +        if op.output:
    +            for consumer in op.output.consumers:
    +                GraphSearchUtils.find_downstream_layer_groups_to_scale(consumer, layer_groups,
    +                                                                       current_group, visited_nodes)
    +
    +        # Reached a leaf.. See if the current group has something to grab
    +        if (len(current_group) > 1) and (current_group not in layer_groups):
    +            layer_groups.append(current_group)
    +
    +    @staticmethod
    +    def convert_layer_group_to_cls_sets(layer_group):
    +        """
    +        Helper function to convert a layer group to a list of cls sets
    +        :param layer_group: Given layer group to generate cls sets
    +        :return: List of cls sets
    +
    +        Supported layer combinations for CLS are:
    +        1. Conv + Conv
    +        2. DepthwiseConv + Conv
    +        3. Conv + DepthwiseConv + Conv
    +
    +        Can be rewritten as,
    +        Conv
    +            -> Conv
    +            -> DepthwiseConv
    +                -> Conv
    +        DepthwiseConv
    +            -> Conv
    +
    +        If a combination is partially supported, the cls_set is completely omitted and restarted from the next
    +        supported layer
    +        For example: Consider Conv + DepthwiseConv + Depthwise(unsupported)
    +        - Since Depthwise(unsupported) is the last layer encountered, we need to omit all the three layers and restart
    +        the cls sets from the next supported layer.
    +
    +        """
    +
    +        # pylint: disable=too-many-branches
    +        def convert_to_cls_layer_type(layer: ClsSupportedLayer) -> Tuple[ClsLayerType, ClsSupportedLayer]:
    +            """
    +            Given the layer, check if its supported in CLS
    +            :param layer: layer to check
    +            :return: Tuple of ClsLayerType and the layer
    +            """
    +            if layer.groups == 1:
    +                layer_type = ClsLayerType.Conv
    +            elif layer.groups == layer.in_channels and layer.in_channels == layer.out_channels:
    +                # depthwiseConv layer with depth multiplier = 1
    +                layer_type = ClsLayerType.DepthwiseConv
    +            else:
    +                layer_type = ClsLayerType.Unsupported
    +            return layer_type, layer
    +
    +        def get_next_layer() -> Union[Tuple[ClsLayerType, Union[ClsSupportedLayer, None]]]:
    +            """
    +            :return: Tuple of ClsLayerType and the next layer in layer_group
    +            """
    +            if not layer_group:
    +                return ClsLayerType.Unsupported, None
    +            layer = layer_group.pop(0)
    +            return convert_to_cls_layer_type(layer)
    +
    +        cls_sets = []
    +
    +        first_layer_to_scale = (ClsLayerType.Unsupported, None)
    +        while layer_group:
    +            while layer_group and first_layer_to_scale[0] is ClsLayerType.Unsupported:
    +                first_layer_to_scale = get_next_layer()
    +                if first_layer_to_scale[0] is ClsLayerType.Unsupported:
    +                    logger.info('Layer %s is not supported. Ignoring for cls', first_layer_to_scale[1])
    +
    +            second_layer_to_scale = get_next_layer()
    +            if first_layer_to_scale[0] == ClsLayerType.Conv:
    +                if second_layer_to_scale[0] == ClsLayerType.Conv:
    +                    cls_sets.append((first_layer_to_scale[1], second_layer_to_scale[1]))
    +                    first_layer_to_scale = second_layer_to_scale
    +                elif second_layer_to_scale[0] == ClsLayerType.DepthwiseConv:
    +                    if layer_group:
    +                        # do not pop third layer yet, determine its type and then pop it
    +                        third_layer_to_scale = convert_to_cls_layer_type(layer_group[0])
    +                        if third_layer_to_scale[0] == ClsLayerType.Conv:
    +                            cls_sets.append(
    +                                (first_layer_to_scale[1], second_layer_to_scale[1], third_layer_to_scale[1]))
    +                            # adding third_layer_to_scale for the next round of CLS set determination
    +                            first_layer_to_scale = get_next_layer()
    +                        else:
    +                            # unsupported combination encountered
    +                            first_layer_to_scale = second_layer_to_scale
    +                else:
    +                    logger.info('Layer %s is not supported. Ignoring for cls', second_layer_to_scale[1])
    +                    first_layer_to_scale = (ClsLayerType.Unsupported, None)
    +            elif first_layer_to_scale[0] == ClsLayerType.DepthwiseConv:
    +                if second_layer_to_scale[0] == ClsLayerType.Conv:
    +                    cls_sets.append((first_layer_to_scale[1], second_layer_to_scale[1]))
    +                first_layer_to_scale = second_layer_to_scale
    +            else:
    +                logger.info('Layer %s is not supported. Ignoring for cls', first_layer_to_scale[1])
    +                first_layer_to_scale = second_layer_to_scale
    +
    +        return cls_sets
    +
    +    def find_layer_groups_to_scale(self) -> List[List[torch.nn.Conv2d]]:
    +        """
    +        :return: List of groups of layers. Each group can be independently equalized
    +        """
    +
    +        # Find the input node(s) in the graph
    +        input_nodes = []
    +        for op in self._connected_graph.get_all_ops().values():
    +            if op.inputs and op.inputs[0].is_model_input:
    +                input_nodes.append(op)
    +
    +        layer_groups = []
    +        for op in input_nodes:
    +            self.find_downstream_layer_groups_to_scale(op, layer_groups)
    +
    +        # Sort the layer groups in order of occurrence in the model
    +        ordered_layer_groups = []
    +        for _, module in self._ordered_module_list:
    +            for layer_group in layer_groups:
    +                if layer_group[0] is module:
    +                    ordered_layer_groups.append(layer_group)
    +
    +        return ordered_layer_groups
    +
    +    @staticmethod
    +    def does_module_have_relu_activation(connected_graph: ConnectedGraph, module: torch.nn.Module) -> bool:
    +        """
    +        Finds if a given module has a ReLU activation
    +        :param connected_graph: Reference to ConnectedGraph instance
    +        :param module: PyTorch module to find activation for
    +        :return: True if module has a relu activation
    +        """
    +
    +        for op in connected_graph.get_all_ops().values():
    +
    +            if op.model_module and op.model_module.get_module() is module:
    +                assert len(op.output.consumers) == 1
    +                is_relu_activation = isinstance(op.output.consumers[0].model_module.get_module(),
    +                                                (torch.nn.ReLU, torch.nn.PReLU))
    +                return is_relu_activation
    +
    +        return False
    +
    +    def is_relu_activation_present_in_cls_sets(self, cls_sets: List[ClsSet]):
    +        """
    +        :param cls_sets: CLS sets to find relu activations in
    +        :return: List of groups of layers. Each group can be independently equalized
    +        """
    +
    +        is_relu_activation_in_cls_sets = []
    +        for cls_set in cls_sets:
    +
    +            # We need to check activation functions for all layers but the last one in the set
    +            # Because we are only interested in checking activation functions between the layers we will scale
    +            cls_set = cls_set[:-1]
    +
    +            is_relu_activation_in_cls_set = ()
    +            for module in cls_set:
    +                is_relu_activation_in_cls_set += (self.does_module_have_relu_activation(self._connected_graph,
    +                                                                                        module), )
    +
    +            if len(is_relu_activation_in_cls_set) == 1:
    +                is_relu_activation_in_cls_set = is_relu_activation_in_cls_set[0]
    +
    +            is_relu_activation_in_cls_sets.append(is_relu_activation_in_cls_set)
    +
    +        return is_relu_activation_in_cls_sets
    +
    +
    +class CrossLayerScaling:
    +    """
    +    Code to apply the cross-layer-scaling technique to a model
    +    """
    +
    +    @staticmethod
    +    def scale_cls_sets(cls_sets: List[ClsSet]) -> List[ScaleFactor]:
    +        """
    +        Scale multiple CLS sets
    +
    +        :param cls_sets: List of CLS sets
    +        :return: Scaling factors calculated and applied for each CLS set in order
    +        """
    +        scale_factor_list = []
    +        for cls_set in cls_sets:
    +            scale_factor = CrossLayerScaling.scale_cls_set(cls_set)
    +            scale_factor_list.append(scale_factor)
    +        return scale_factor_list
    +
    +    @staticmethod
    +    def scale_cls_set(cls_set: ClsSet) -> ScaleFactor:
    +        """
    +        Scale a CLS set
    +        :param cls_set: Either a pair or regular conv layers or a triplet of depthwise separable layers
    +        :return: Scaling factor calculated and applied
    +        """
    +        if len(cls_set) == 3:
    +            scale_factor = CrossLayerScaling.scale_cls_set_with_depthwise_layers(cls_set)
    +        else:
    +            scale_factor = CrossLayerScaling.scale_cls_set_with_conv_layers(cls_set)
    +
    +        return scale_factor
    +
    +    @classmethod
    +    def scale_cls_set_with_conv_layers(cls, cls_set: ClsSet) -> np.ndarray:
    +        """
    +        API to invoke equalize layer params (update for weights and bias is in place)
    +
    +        :param cls_set: Consecutive Conv layers Tuple whose weights and biases need to be equalized
    +        :return: Scaling factor S_12 for each conv layer pair: numpy array
    +        """
    +        on_gpu = False
    +        for module in cls_set:
    +            if not isinstance(module, cls_supported_layers):
    +                raise ValueError(f"Only Conv or Transposed Conv layers are supported for cross layer equalization."
    +                                 f" Layer class {str(module.__class__)} is not supported.")
    +            if module.weight.is_cuda:
    +                on_gpu = True
    +                module.cpu()
    +
    +        cls_impl = PythonClsImpl()
    +        scaling_factor = cls_impl.scale_cls_set_with_conv_layers(cls_set)
    +
    +        if on_gpu:
    +            for module in cls_set:
    +                module.to(device="cuda")
    +
    +        return scaling_factor
    +
    +    @classmethod
    +    def scale_cls_set_with_depthwise_layers(cls, cls_set: ClsSet) -> [np.ndarray, np.ndarray]:
    +        """
    +        API to invoke equalize layer params for depth wise separable layers(update for weights and bias is in place)
    +
    +        :param cls_set: Consecutive Conv layers whose weights and biases need to be equalized.
    +                        Second Conv layer is a depth-wise conv and third conv layer is point-wise conv
    +        :return: Scaling factors S_12 and S_23 : numpy arrays
    +        """
    +        on_gpu = False
    +        for module in cls_set:
    +            if not isinstance(module, cls_supported_layers):
    +                raise ValueError(f"Only Conv or Transposed Conv layers are supported for cross layer equalization."
    +                                 f" Layer class {str(module.__class__)} is not supported.")
    +            if module.weight.is_cuda:
    +                on_gpu = True
    +                module.cpu()
    +
    +        cls_impl = PythonClsImpl()
    +        scaling_factors = cls_impl.scale_cls_set_with_depthwise_layers(cls_set)
    +
    +        if on_gpu:
    +            for module in cls_set:
    +                module.to(device="cuda")
    +
    +        return scaling_factors
    +
    +    @staticmethod
    +    def create_cls_set_info_list(cls_sets: List[ClsSet], scale_factors: List[ScaleFactor],
    +                                 is_relu_activation_in_cls_sets):
    +        """
    +        Binds information from there separate lists into one [ClsInfoSet] data-structure
    +        :param cls_sets: List of CLS sets
    +        :param scale_factors: Scale-factors for each cls-set
    +        :param is_relu_activation_in_cls_sets: Information if there is relu activation in each cls-set
    +        :return: List of ClsSetInfo
    +        """
    +        cls_set_info_list = []
    +        assert len(cls_sets) == len(scale_factors) == len(is_relu_activation_in_cls_sets)
    +
    +        for index, cls_set in enumerate(cls_sets):
    +
    +            if isinstance(scale_factors[index], tuple):
    +                # If we are dealing with a triplet of layers, then we should have 2 scale factors and 2 relu flags
    +                # Assert that this is true
    +                assert len(cls_set) == 3
    +                assert len(scale_factors[index]) == len(is_relu_activation_in_cls_sets[index]) == 2
    +
    +                cls_pair_1 = ClsSetInfo.ClsSetLayerPairInfo(cls_set[0], cls_set[1], scale_factors[index][0],
    +                                                            is_relu_activation_in_cls_sets[index][0])
    +                cls_pair_2 = ClsSetInfo.ClsSetLayerPairInfo(cls_set[1], cls_set[2], scale_factors[index][1],
    +                                                            is_relu_activation_in_cls_sets[index][1])
    +
    +                cls_set_info = ClsSetInfo(cls_pair_1, cls_pair_2)
    +
    +            else:
    +                cls_pair = ClsSetInfo.ClsSetLayerPairInfo(cls_set[0], cls_set[1], scale_factors[index],
    +                                                          is_relu_activation_in_cls_sets[index])
    +
    +                cls_set_info = ClsSetInfo(cls_pair)
    +
    +            cls_set_info_list.append(cls_set_info)
    +
    +        return cls_set_info_list
    +
    +    @staticmethod
    +    def scale_model(model: torch.nn.Module, input_shapes: Union[Tuple, List[Tuple]] = None,
    +                    dummy_input: Union[torch.Tensor, List[torch.Tensor]] = None) -> List[ClsSetInfo]:
    +        """
    +        Uses cross-layer scaling to scale all applicable layers in the given model
    +
    +        :param model: Model to scale
    +        :param input_shapes: Input shape for the model (can be one or multiple inputs)
    +        :param dummy_input: A dummy input to the model. Can be a Tensor or a Tuple of Tensors. dummy_input will be
    +         placed on CPU if not already.
    +        :return: CLS information for each CLS set
    +        """
    +        if isinstance(model, torch.nn.DataParallel):
    +            return CrossLayerScaling.scale_model(model.module, input_shapes, dummy_input=dummy_input)
    +
    +        # The use of input_shapes will be removed in the future release. It is maintained now for backward compatibility.
    +        if input_shapes and dummy_input is None:
    +            dummy_input = create_rand_tensors_given_shapes(input_shapes, torch.device('cpu'))
    +        if input_shapes is None and dummy_input is None:
    +            raise ValueError("Both input_shapes and dummy_input can't be None")
    +
    +        # Place model and dummy input on the cpu.
    +        with place_model(model, torch.device("cpu")):
    +            dummy_input = utils.change_tensor_device_placement(dummy_input, device=torch.device('cpu'))
    +
    +            # Find layer groups
    +            graph_search = GraphSearchUtils(model, input_shapes, dummy_input=dummy_input)
    +            layer_groups = graph_search.find_layer_groups_to_scale()
    +
    +            # Find cls sets from the layer groups
    +            cls_sets = []
    +            for layer_group in layer_groups:
    +                cls_set = GraphSearchUtils.convert_layer_group_to_cls_sets(layer_group)
    +                cls_sets += cls_set
    +
    +            # Scale the CLS sets
    +            scale_factors = CrossLayerScaling.scale_cls_sets(cls_sets)
    +
    +            # Find if there were relu activations between layers of each cls set
    +            is_relu_activation_in_cls_sets = graph_search.is_relu_activation_present_in_cls_sets(cls_sets)
    +
    +            # Convert to a list of cls-set-info elements
    +            cls_set_info_list = CrossLayerScaling.create_cls_set_info_list(cls_sets, scale_factors,
    +                                                                           is_relu_activation_in_cls_sets)
    +        return cls_set_info_list
    +
    +
    +class PythonClsImpl(ClsImpl):
    +    """
    +    This class implements the CLS algorithm using Python version while following the base Implementation interface.
    +    """
    +    def scale_cls_set_with_depthwise_layers(self, cls_set) -> [np.ndarray, np.ndarray]:
    +        """
    +        API to invoke equalize layer params for depth wise separable layers(update for weights and bias is in place)
    +
    +        :param cls_set: Consecutive Conv layers whose weights and biases need to be equalized.
    +                        Second Conv layer is a depth-wise conv and third conv layer is point-wise conv
    +        :return: Scaling factors S_12 and S_23 : numpy arrays
    +        """
    +        weight_0 = self._prepare_params(cls_set[0])
    +        assert cls_set[1].groups > 1
    +        weight_1 = self._prepare_params(cls_set[1])
    +        weight_2 = self._prepare_params(cls_set[2])
    +        weight_0 = weight_0.numpy()
    +        weight_1 = weight_1.numpy()
    +        weight_2 = weight_2.numpy()
    +
    +        bias_0 = None
    +        if cls_set[0].bias is not None:
    +            bias_0 = cls_set[0].bias.detach().cpu().numpy()
    +        bias_1 = None
    +        if cls_set[1].bias is not None:
    +            bias_1 = cls_set[1].bias.detach().cpu().numpy()
    +
    +        # compute scaling factors and folded parameters.
    +        s_12, s_23 = self.compute_scaling_params_for_depthwise_conv(weight_0, weight_1, weight_2)
    +        _weight_0, _weight_1, _weight_2, _bias_0, _bias_1 = (
    +            self.fold_scaling_params_for_depthwise_conv(weight_0, weight_1, weight_2, bias_0, bias_1, s_12, s_23))
    +
    +        with torch.no_grad():
    +            self._restore_params(cls_set[0], torch.from_numpy(_weight_0))
    +            self._restore_params(cls_set[1], torch.from_numpy(_weight_1))
    +            self._restore_params(cls_set[2], torch.from_numpy(_weight_2))
    +
    +            if cls_set[0].bias is not None:
    +                cls_set[0].bias.copy_(torch.from_numpy(_bias_0).reshape_as(cls_set[0].bias)).to(device=cls_set[0].bias.device,
    +                                                                                                dtype=cls_set[0].bias.dtype)
    +            if cls_set[1].bias is not None:
    +                cls_set[1].bias.copy_(torch.from_numpy(_bias_1).reshape_as(cls_set[1].bias)).to(device=cls_set[1].bias.device,
    +                                                                                                dtype=cls_set[1].bias.dtype)
    +        return s_12, s_23
    +
    +    def scale_cls_set_with_conv_layers(self, cls_set) -> np.ndarray:
    +        """
    +        API to invoke equalize layer params for regular conv layers (update for weights and bias is in place)
    +
    +        :param cls_set: Consecutive Conv layers Tuple whose weights and biases need to be equalized
    +        :return: Scaling factor S_12 for each conv layer pair: numpy array
    +        """
    +        weight_0 = self._prepare_params(cls_set[0])
    +        weight_1 = self._prepare_params(cls_set[1])
    +        weight_0 = weight_0.numpy()
    +        weight_1 = weight_1.numpy()
    +
    +        bias_0 = None
    +        if cls_set[0].bias is not None:
    +            bias_0 = cls_set[0].bias.detach().cpu().numpy()
    +
    +        # compute scaling factors and folded parameters.
    +        scale_factor = self.compute_scaling_params_for_conv(weight_0, weight_1)
    +        _weight_0, _weight_1, _bias_0 = (
    +            self.fold_scaling_params_for_conv(weight_0, weight_1, bias_0, scale_factor))
    +
    +        with torch.no_grad():
    +            self._restore_params(cls_set[0], torch.from_numpy(_weight_0))
    +            self._restore_params(cls_set[1], torch.from_numpy(_weight_1))
    +            if cls_set[0].bias is not None:
    +                cls_set[0].bias.copy_(torch.from_numpy(_bias_0).reshape_as(cls_set[0].bias)).to(device=cls_set[0].bias.device,
    +                                                                                                dtype=cls_set[0].bias.dtype)
    +        return scale_factor
    +
    +    @staticmethod
    +    def _transpose_tensor(module: torch.nn.Module, tensor: torch.Tensor) -> torch.Tensor:
    +        """
    +        During preparation:
    +        For TransposeConv2d, Transpose tensor in the common format [Noc, Nin, Kh, Kw].
    +        For TransposeConv1d, Transpose tensor in common format [Noc, Nin, K].
    +
    +        During restoration:
    +        For TransposeConv2d, Transpose tensor in the original format [Nin, Noc, Kh, Kw].
    +        For TransposeConv1d, Transpose tensor in back in original format [Nin, Noc, K].
    +
    +        :param module: Module.
    +        :param tensor: Input tensor.
    +        :return: Output tensor.
    +        """
    +        if isinstance(module, torch.nn.ConvTranspose2d) and module.groups == 1:
    +            tensor = tensor.permute(1, 0, 2, 3).contiguous()
    +
    +        if isinstance(module, torch.nn.ConvTranspose1d) and module.groups == 1:
    +            tensor = tensor.permute(1, 0, 2).contiguous()
    +        return tensor
    +
    +    @staticmethod
    +    def _make_4d_tensor(module: torch.nn.Module, tensor: torch.Tensor) -> torch.Tensor:
    +        """
    +        Return 4 dimensional tensor by adding a dimension on the end if the tensor is not 4d.
    +
    +        :param module: Module.
    +        :param tensor: Input tensor.
    +        :return: Output tensor.
    +        """
    +        if isinstance(module, (torch.nn.Conv1d, torch.nn.ConvTranspose1d)):
    +            assert len(tensor.shape) == 3, "Module should have 3d weight tensor."
    +            tensor = torch.unsqueeze(tensor, dim=-1)
    +        return tensor
    +
    +    def _prepare_params(self, module: torch.nn.Module) -> torch.Tensor:
    +        """
    +        Prepare weight parameters for CLS.
    +
    +        :param module: PyTorch module.
    +        :return: Prepared weight.
    +        """
    +        weight = module.weight.detach().cpu()
    +        weight = self._transpose_tensor(module, weight)
    +        weight = self._make_4d_tensor(module, weight)
    +        return weight
    +
    +    def _restore_params(self, module: torch.nn.Module, tensor: torch.Tensor):
    +        """
    +        Restore the weight parameters.
    +
    +        :param module: PyTorch module.
    +        :param tensor: updated parameters.
    +        """
    +        if isinstance(module, (torch.nn.Conv1d, torch.nn.ConvTranspose1d)):
    +            tensor = torch.squeeze(tensor, dim=-1)
    +
    +        _weight_0 = self._transpose_tensor(module, tensor)
    +        module.weight.copy_(_weight_0.reshape_as(module.weight)).to(device=module.weight.device,
    +                                                                    dtype=module.weight.dtype)
    +
    +
    +class HighBiasFold:
    +    """
    +    Code to apply the high-bias-fold technique to a model
    +    """
    +
    +    ActivationIsReluForFirstModule = bool
    +    ScaleForFirstModule = np.ndarray
    +
    +    @classmethod
    +    def bias_fold(cls, cls_set_info_list: List[ClsSetInfo],
    +                  bn_layers: Dict[Union[torch.nn.Conv2d, torch.nn.ConvTranspose2d], torch.nn.BatchNorm2d]):
    +        """
    +        Folds bias values greater than 3 * sigma to next layer's bias
    +
    +        :param cls_set_info_list: List of info elements for each cls set
    +        :param bn_layers: Key: Conv/Linear layer Value: Corresponding folded BN layer
    +        :return: None
    +        """
    +        if not bn_layers:
    +            logger.info('High Bias folding is not supported for models without BatchNorm Layers')
    +            return
    +
    +        for cls_set_info in cls_set_info_list:
    +            for cls_pair_info in cls_set_info.cls_pair_info_list:
    +
    +                if (cls_pair_info.layer1.bias is None) or (cls_pair_info.layer2.bias is None) or \
    +                        (cls_pair_info.layer1 not in bn_layers):
    +                    continue
    +
    +                hbf_impl = PythonHbfImpl()
    +                hbf_impl.bias_fold(cls_pair_info, bn_layers)
    +
    +
    +class PythonHbfImpl(HbfImpl):
    +    """
    +    This class implements the HBF algorithm using python version while following the base Implementation interface.
    +    """
    +    # pylint: disable=no-self-use
    +    def bias_fold(self, cls_pair_info, bn_layers):
    +        """
    +        Bias fold implementation using python version.
    +
    +        :param cls_pair_info: Layer pairs that were scaled using CLS and related information.
    +        :param bn_layers: Dictionary with Key being Conv/Linear layer and value being corresponding folded BN layer.
    +        """
    +        weight = cls_pair_info.layer2.weight.detach().cpu()
    +        if isinstance(cls_pair_info.layer2, (torch.nn.Conv1d, torch.nn.ConvTranspose1d)):
    +            weight = torch.unsqueeze(weight, dim=-1)
    +        # Transpose weights to C, N, H, W from N, C, H, W since axis are flipped for transposed conv
    +        if isinstance(cls_pair_info.layer2, (torch.nn.ConvTranspose1d, torch.nn.ConvTranspose2d)) and \
    +                cls_pair_info.layer2.groups == 1:
    +            weight = weight.permute(1, 0, 2, 3)
    +        weight = weight.numpy()
    +
    +        activation_is_relu = cls_pair_info.relu_activation_between_layers
    +
    +        beta = bn_layers[cls_pair_info.layer1].bias.detach().cpu().numpy() / cls_pair_info.scale_factor
    +        gamma = bn_layers[cls_pair_info.layer1].weight.detach().cpu().numpy() / cls_pair_info.scale_factor
    +
    +        bias_prev_layer = cls_pair_info.layer1.bias.detach().cpu().numpy()
    +        bias_curr_layer = cls_pair_info.layer2.bias.detach().cpu().numpy()
    +
    +        # Absorb high biases
    +        _bias_prev_layer, _bias_curr_layer = (
    +            self._absorb_bias(activation_is_relu, beta, gamma, weight, bias_curr_layer, bias_prev_layer))
    +
    +        with torch.no_grad():
    +            cls_pair_info.layer1.bias.copy_(torch.from_numpy(_bias_prev_layer).reshape_as(cls_pair_info.layer1.bias)).to(
    +                device=cls_pair_info.layer1.bias.device, dtype=cls_pair_info.layer1.bias.dtype)
    +            cls_pair_info.layer2.bias.copy_(torch.from_numpy(_bias_curr_layer).reshape_as(cls_pair_info.layer2.bias)).to(
    +                device=cls_pair_info.layer2.bias.device, dtype=cls_pair_info.layer2.bias.dtype)
    +
    +
    +[docs] +def equalize_model(model: torch.nn.Module, input_shapes: Union[Tuple, List[Tuple]] = None, + dummy_input: Union[torch.Tensor, Tuple] = None): + """ + High-level API to perform Cross-Layer Equalization (CLE) on the given model. The model is equalized in place. + + :param model: Model to equalize + :param input_shapes: Shape of the input (can be a tuple or a list of tuples if multiple inputs) + :param dummy_input: A dummy input to the model. Can be a Tensor or a Tuple of Tensors. dummy_input will be + placed on CPU if not already. + """ + if isinstance(model, torch.nn.DataParallel): + equalize_model(model.module, input_shapes, dummy_input) + else: + # The use of input_shapes will be removed in the future release. It is maintained now for backward compatibility. + if input_shapes and dummy_input is None: + dummy_input = create_rand_tensors_given_shapes(input_shapes, torch.device('cpu')) + if input_shapes is None and dummy_input is None: + raise ValueError("Both input_shapes and dummy_input can't be None") + + # Place model and dummy input on the cpu. + with place_model(model, torch.device('cpu')): + dummy_input = utils.change_tensor_device_placement(dummy_input, device=torch.device('cpu')) + + # fold batchnorm layers and perform CLE on the folded model. + folded_pairs = fold_all_batch_norms(model, input_shapes, dummy_input=dummy_input) + equalize_bn_folded_model(model, input_shapes, folded_pairs, + dummy_input=dummy_input)
    + + + +def equalize_bn_folded_model(model: torch.nn.Module, + input_shapes: Union[Tuple, List[Tuple]], + folded_pairs: List[Tuple[torch.nn.Module, torch.nn.BatchNorm2d]], + dummy_input: Union[torch.Tensor, Tuple] = None + ): + """ + Perform Cross-Layer Scaling (CLS) and High Bias Folding (HBF) on a batchnorm-folded model. + The model is equalized in place. + + :param model: Batchnorm-folded model to equalize + :param input_shapes: Shape of the input (can be a tuple or a list of tuples if multiple inputs) + :param dummy_input: A dummy input to the model. Can be a Tensor or a Tuple of Tensors. dummy_input will be + placed on CPU if not already. + :param folded_pairs: List of pairs of folded layers + """ + if isinstance(model, torch.nn.DataParallel): + equalize_bn_folded_model(model.module, input_shapes, folded_pairs, dummy_input=dummy_input) + else: + bn_dict = {} + for conv_bn in folded_pairs: + bn_dict[conv_bn[0]] = conv_bn[1] + + with place_model(model, torch.device('cpu')): + # replace any ReLU6 layers with ReLU + utils.replace_modules_of_type1_with_type2(model, torch.nn.ReLU6, torch.nn.ReLU) + + # perform cross-layer scaling on applicable layer sets + cls_set_info_list = CrossLayerScaling.scale_model(model, input_shapes, dummy_input=dummy_input) + + # high-bias fold + HighBiasFold.bias_fold(cls_set_info_list, bn_dict) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/defs.html b/releases/2.0.0/_modules/aimet_torch/defs.html new file mode 100644 index 0000000..4b6b7fd --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/defs.html @@ -0,0 +1,599 @@ + + + + + + + + aimet_torch.defs - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.defs

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2018, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Common type definitions that are used across AIMET """
    +
    +from enum import Enum
    +from typing import List, Optional, Union
    +
    +import torch.utils.data
    +
    +from aimet_common.defs import GreedySelectionParameters, RankSelectScheme
    +
    +
    +class ModuleCompRatioPair:
    +    """
    +    Pair of torch.nn.module and a compression-ratio
    +
    +    :ivar module: Module of type torch.nn.module
    +    :ivar comp_ratio: Compression ratio. Compression ratio is the ratio of cost of compressed model
    +            to cost of the original model.
    +    """
    +
    +    def __init__(self, module: torch.nn.Module, comp_ratio: float):
    +        self.module = module
    +        self.comp_ratio = comp_ratio
    +
    +
    +class OpToIOTensors:
    +    """
    +    Data class to store the input and output tensor names of an operation as a lists.
    +    """
    +    def __init__(self, node_inputs: List[str], node_outputs: List[str]):
    +        """
    +        :param node_inputs: name of inputs to the node
    +        :param node_outputs: name of output from the node
    +        """
    +
    +        self.inputs = node_inputs
    +        self.outputs = node_outputs
    +
    +
    +
    +[docs] +class SpatialSvdParameters: + """ Configuration parameters for spatial svd compression """ + +
    +[docs] + class ManualModeParams: + """ + Configuration parameters for manual-mode spatial svd compression + """ + + def __init__(self, list_of_module_comp_ratio_pairs: List[ModuleCompRatioPair]): + """ + :param list_of_module_comp_ratio_pairs: List of (module, comp-ratio) pairs + """ + self.list_of_module_comp_ratio_pairs = list_of_module_comp_ratio_pairs
    + + +
    +[docs] + class AutoModeParams: + """ + Configuration parameters for auto-mode compression + """ + + def __init__(self, greedy_select_params: GreedySelectionParameters, + modules_to_ignore: Optional[List[torch.nn.Module]] = None): + """ + :param greedy_select_params: Params for greedy comp-ratio selection algorithm + :param modules_to_ignore: List of modules to ignore (None indicates nothing to ignore) + """ + self.greedy_params = greedy_select_params + self.modules_to_ignore = [] if modules_to_ignore is None else modules_to_ignore
    + + +
    +[docs] + class Mode(Enum): + """ Mode enumeration """ + + manual = 1 + """ Manual mode """ + + auto = 2 + """ Auto mode """
    + + + def __init__(self, mode: Mode, params: Union[ManualModeParams, AutoModeParams], multiplicity=1): + """ + :param mode: Either auto mode or manual mode + :param params: Parameters for the mode selected + :param multiplicity: The multiplicity to which ranks/input channels will get rounded. Default: 1 + """ + self.mode = mode + self.mode_params = params + self.multiplicity = multiplicity
    + + + +
    +[docs] +class ChannelPruningParameters: + """ Configuration parameters for channel pruning compression """ + +
    +[docs] + class ManualModeParams: + """ + Configuration parameters for manual-mode channel pruning compression + """ + + def __init__(self, list_of_module_comp_ratio_pairs: List[ModuleCompRatioPair]): + """ + :param list_of_module_comp_ratio_pairs: List of (module, comp-ratio) pairs + """ + self.list_of_module_comp_ratio_pairs = list_of_module_comp_ratio_pairs
    + + +
    +[docs] + class AutoModeParams: + """ + Configuration parameters for auto-mode compression + """ + + def __init__(self, greedy_select_params: GreedySelectionParameters, + modules_to_ignore: Optional[List[torch.nn.Module]] = None): + """ + :param greedy_select_params: Params for greedy comp-ratio selection algorithm + :param modules_to_ignore: List of modules to ignore (None indicates nothing to ignore) + """ + self.greedy_params = greedy_select_params + self.modules_to_ignore = [] if modules_to_ignore is None else modules_to_ignore
    + + +
    +[docs] + class Mode(Enum): + """ Mode enumeration """ + + manual = 1 + """ Manual mode: User specifies comp-ratio per layer """ + + auto = 2 + """ Auto mode: AIMET computes optimal comp-ratio per layer """
    + + + def __init__(self, data_loader: torch.utils.data.DataLoader, num_reconstruction_samples: int, + allow_custom_downsample_ops: bool, + mode: Mode, params: Union[ManualModeParams, AutoModeParams], multiplicity=1): + self.data_loader = data_loader + self.num_reconstruction_samples = num_reconstruction_samples + self.allow_custom_downsample_ops = allow_custom_downsample_ops + self.mode = mode + self.mode_params = params + self.multiplicity = multiplicity
    + + + +
    +[docs] +class WeightSvdParameters: + """ Configuration parameters for weight svd compression """ + +
    +[docs] + class ManualModeParams: + """ + Configuration parameters for manual-mode weight svd compression + """ + + def __init__(self, list_of_module_comp_ratio_pairs: List[ModuleCompRatioPair]): + """ + :param list_of_module_comp_ratio_pairs: List of (module, comp-ratio) pairs + """ + self.list_of_module_comp_ratio_pairs = list_of_module_comp_ratio_pairs
    + + +
    +[docs] + class AutoModeParams: + """ + Configuration parameters for auto-mode compression + """ + + def __init__(self, + rank_select_scheme: RankSelectScheme, + select_params: Union[GreedySelectionParameters, ], + modules_to_ignore: Optional[List[torch.nn.Module]] = None): + """ + :param rank_select_scheme: supports two options greedy and tar + :param select_params: Params for greedy/TAR comp-ratio selection algorithm + :param modules_to_ignore: List of modules to ignore (None indicates nothing to ignore) + """ + self.rank_select_scheme = rank_select_scheme + self.select_params = select_params + self.modules_to_ignore = [] if modules_to_ignore is None else modules_to_ignore
    + + +
    +[docs] + class Mode(Enum): + """ Mode enumeration """ + + manual = 1 + """ Manual mode """ + + auto = 2 + """ Auto mode """
    + + + def __init__(self, mode: Mode, params: Union[ManualModeParams, AutoModeParams], multiplicity=1): + """ + :param mode: Either auto mode or manual mode + :param params: Parameters for the mode selected + :param multiplicity: The multiplicity to which ranks/input channels will get rounded. Default: 1 + """ + self.mode = mode + self.mode_params = params + self.multiplicity = multiplicity
    + + + +class PassThroughOp(torch.nn.Module): + """ + This is a pass-through op, used for purpose of making an op a no-op + """ + # pylint:disable=arguments-differ + @staticmethod + def forward(inputx): + """ + Forward pass for passthrough op + """ + return inputx +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/layer_output_utils.html b/releases/2.0.0/_modules/aimet_torch/layer_output_utils.html new file mode 100644 index 0000000..bad0b17 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/layer_output_utils.html @@ -0,0 +1,746 @@ + + + + + + + + aimet_torch.layer_output_utils - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.layer_output_utils

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" This module contains utilities to capture and save intermediate layer-outputs of a model. """
    +
    +import os
    +from typing import Union, Dict, List, Tuple
    +from enum import Enum
    +import shutil
    +import re
    +
    +import numpy as np
    +import onnx
    +import torch
    +
    +from aimet_common.utils import AimetLogger
    +from aimet_common.layer_output_utils import SaveInputOutput, save_layer_output_names
    +
    +from aimet_torch._base.quantsim import _QuantizedModuleProtocol
    +from aimet_torch import utils
    +from aimet_torch import torchscript_utils
    +from aimet_torch.onnx_utils import OnnxSaver, OnnxExportApiArgs
    +from aimet_torch.v2.nn.base import BaseQuantizationMixin
    +
    +try:
    +    from aimet_torch.v1.qc_quantize_recurrent import QcQuantizeRecurrent
    +    _quantized_module_types = (_QuantizedModuleProtocol, QcQuantizeRecurrent)
    +except ImportError:
    +    _quantized_module_types = (_QuantizedModuleProtocol,)
    +
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.LayerOutputs)
    +
    +
    +
    +[docs] +class NamingScheme(Enum): + """ Enumeration of layer-output naming schemes. """ + + PYTORCH = 1 + """ Names outputs according to exported pytorch model. Layer names are used. """ + ONNX = 2 + """ Names outputs according to exported onnx model. Layer output names are generally numeric. """ + TORCHSCRIPT = 3 + """ Names outputs according to exported torchscript model. Layer output names are generally numeric. """
    + + + +
    +[docs] +class LayerOutputUtil: + """ Implementation to capture and save outputs of intermediate layers of a model (fp32/quantsim). """ + + def __init__(self, model: torch.nn.Module, dir_path: str, naming_scheme: NamingScheme = NamingScheme.PYTORCH, + dummy_input: Union[torch.Tensor, Tuple, List] = None, onnx_export_args: Union[OnnxExportApiArgs, Dict] = None): + """ + Constructor for LayerOutputUtil. + + :param model: Model whose layer-outputs are needed. + :param dir_path: Directory wherein layer-outputs will be saved. + :param naming_scheme: Naming scheme to be followed to name layer-outputs. There are multiple schemes as per + the exported model (pytorch, onnx or torchscript). Refer the NamingScheme enum definition. + :param dummy_input: Dummy input to model. Required if naming_scheme is 'NamingScheme.ONNX' or 'NamingScheme.TORCHSCRIPT'. + :param onnx_export_args: Should be same as that passed to quantsim export API to have consistency between + layer-output names present in exported onnx model and generated layer-outputs. Required if naming_scheme is + 'NamingScheme.ONNX'. + """ + + # Utility to capture layer-outputs + self.layer_output = LayerOutput(model=model, naming_scheme=naming_scheme, dir_path=dir_path, dummy_input=dummy_input, + onnx_export_args=onnx_export_args) + + # Utility to save model inputs and their corresponding layer-outputs + self.save_input_output = SaveInputOutput(dir_path=dir_path, axis_layout='NCHW') + +
    +[docs] + def generate_layer_outputs(self, input_instance: Union[torch.Tensor, List[torch.Tensor], Tuple[torch.Tensor]]): + """ + This method captures output of every layer of a model & saves the single input instance and corresponding layer-outputs to disk. + + :param input_instance: Single input instance for which we want to obtain layer-outputs. + :return: None + """ + + logger.info("Generating layer-outputs for input instance %d", self.save_input_output.input_cntr+1) + + # Obtain layer-output name to output dictionary + layer_output_dict = self.layer_output.get_outputs(input_instance) + + # Place inputs and layer-outputs on CPU + input_instance = LayerOutputUtil._get_input_in_numpy(input_instance) + layer_output_dict = LayerOutputUtil._get_layer_output_in_numpy(layer_output_dict) + + # Save inputs and layer-outputs + self.save_input_output.save(input_instance, layer_output_dict) + + logger.info('Successfully generated layer-outputs for input instance %d', self.save_input_output.input_cntr)
    + + + @staticmethod + def _get_input_in_numpy(input_instance: Union[torch.Tensor, List[torch.Tensor], Tuple[torch.Tensor]]) -> \ + Union[np.ndarray, List[np.ndarray], Tuple[np.ndarray]]: + """ + Coverts the torch tensors into numpy arrays + :param input_instance: Single input instance with torch tensors + :return: Input with numpy arrays + """ + if isinstance(input_instance, (List, Tuple)): + numpy_input = [] + for ith_input in input_instance: + numpy_input.append(ith_input.cpu().numpy()) + return numpy_input + return input_instance.cpu().numpy() + + @staticmethod + def _get_layer_output_in_numpy(layer_output_dict: Dict[str, torch.Tensor]) -> Dict[str, np.ndarray]: + """ + Converts the torch tensors into numpy arrays + :param layer_output_dict: layer output dictionary with torch tensors + :return: layer output dictionary with numpy arrays + """ + layer_output_numpy_dict = {} + for output_name, output_tensor in layer_output_dict.items(): + layer_output_numpy_dict[output_name] = output_tensor.cpu().numpy() + return layer_output_numpy_dict
    + + + +class LayerOutput: + """ + This class creates a layer-output name to layer-output dictionary. The layer-output names are as per the AIMET exported + pytorch/onnx/torchscript model. + """ + def __init__(self, model: torch.nn.Module, dir_path: str, naming_scheme: NamingScheme = NamingScheme.PYTORCH, + dummy_input: Union[torch.Tensor, Tuple, List] = None, onnx_export_args: Union[OnnxExportApiArgs, Dict] = None): + """ + Constructor - It initializes few dictionaries that are required for capturing and naming layer-outputs. + + :param model: Model whose layer-outputs are needed. + :param dir_path: Directory wherein layer-output names arranged in topological order will be saved. It will also + be used to temporarily save onnx/torchscript equivalent of the given model. + :param naming_scheme: Naming scheme to be followed to name layer-outputs. There are multiple schemes as per + the exported model (pytorch, onnx or torchscript). Refer the NamingScheme enum definition. + :param dummy_input: Dummy input to model (required if naming_scheme is 'onnx'). + :param onnx_export_args: Should be same as that passed to quantsim export API to have consistency between + layer-output names present in exported onnx model and generated layer-outputs (required if naming_scheme is + 'onnx'). + """ + self.model = model + self.module_to_name_dict = utils.get_module_to_name_dict(model=model, prefix='') + + # Check whether the given model is quantsim model + self.is_quantsim_model = any(isinstance(module, _quantized_module_types) for module in model.modules()) + + # Obtain layer-name to layer-output name mapping + self.layer_name_to_layer_output_dict = {} + self.layer_name_to_layer_output_name_dict = {} + if naming_scheme == NamingScheme.PYTORCH: + for name, module in model.named_modules(): + if utils.is_leaf_module(module) or isinstance(module, BaseQuantizationMixin): + name = name.replace('._module_to_wrap', '') + self.layer_name_to_layer_output_name_dict[name] = name + else: + self.layer_name_to_layer_output_name_dict = LayerOutput.get_layer_name_to_layer_output_name_map( + self.model, naming_scheme, dummy_input, onnx_export_args, dir_path) + + # Replace any delimiter in layer-output name string with underscore + for layer_name, output_name in self.layer_name_to_layer_output_name_dict.items(): + self.layer_name_to_layer_output_name_dict[layer_name] = re.sub(r'\W+', "_", output_name) + + # Save layer-output names which are in topological order of model graph. This order can be used while comparing layer-outputs. + layer_output_names = list(self.layer_name_to_layer_output_name_dict.values()) + save_layer_output_names(layer_output_names, dir_path) + + def get_outputs(self, input_instance: Union[torch.Tensor, List[torch.Tensor], Tuple[torch.Tensor]]) -> Dict[str, torch.Tensor]: + """ + This function captures layer-outputs and renames them as per the AIMET exported pytorch/onnx/torchscript model. + + :param input_instance: Single input instance for which we want to obtain layer-outputs. + :return: layer-name to layer-output dict + """ + + # Fetch outputs of all the layers + self.layer_name_to_layer_output_dict = {} + if self.is_quantsim_model: + # Apply record-output hook to QuantizeWrapper modules (one node above leaf node in model graph) + utils.run_hook_for_layers_with_given_input(self.model, input_instance, self.record_outputs, + module_type_for_attaching_hook=_quantized_module_types, + leaf_node_only=False) + else: + # Apply record-output hook to Original modules (leaf node in model graph) + utils.run_hook_for_layers_with_given_input(self.model, input_instance, self.record_outputs, leaf_node_only=True) + + # Rename outputs according to pytorch/onnx/torchscript model + layer_output_name_to_layer_output_dict = LayerOutput.rename_layer_outputs(self.layer_name_to_layer_output_dict, + self.layer_name_to_layer_output_name_dict) + + return layer_output_name_to_layer_output_dict + + def record_outputs(self, module: torch.nn.Module, _, output: torch.Tensor): + """ + Hook function to capture output of a layer. + + :param module: Layer-module in consideration. + :param _: Placeholder for the input of the layer-module. + :param output: Output of the layer-module. + :return: None + """ + layer_name = self.module_to_name_dict[module] + if isinstance(output, torch.Tensor): + self.layer_name_to_layer_output_dict[layer_name] = output.clone() + else: + logger.info("Skipping constant scalar output of layer %s", layer_name) + + @staticmethod + def rename_layer_outputs(layer_name_to_layer_output_dict: Dict[str, torch.Tensor], + layer_name_to_layer_output_name_dict: Dict[str, str]) -> Dict[str, torch.Tensor]: + """ + Rename layer-outputs based on the layer-name to layer-output name map + + :param layer_name_to_layer_output_dict: Dict containing layer-outputs + :param layer_name_to_layer_output_name_dict: Dict containing layer-output names + :return: layer_output_name_to_layer_output_dict + """ + layer_names = list(layer_name_to_layer_output_dict.keys()) + + for layer_name in layer_names: + if layer_name in layer_name_to_layer_output_name_dict: + # Rename the layer-output by using layer-output name, instead of layer-name + layer_output_name = layer_name_to_layer_output_name_dict[layer_name] + layer_name_to_layer_output_dict[layer_output_name] = layer_name_to_layer_output_dict.pop(layer_name) + else: + # Delete the layer-output as it doesn't have a name + layer_name_to_layer_output_dict.pop(layer_name) + + return layer_name_to_layer_output_dict + + @staticmethod + def get_layer_name_to_layer_output_name_map(model, naming_scheme: NamingScheme, dummy_input: Union[torch.Tensor, Tuple, List], + onnx_export_args: Union[OnnxExportApiArgs, Dict], dir_path: str) -> Dict[str, str]: + """ + This function produces layer-name to layer-output name map w.r.t the AIMET exported onnx/torchscript model. If a + layer gets expanded into multiple layers in the exported model then the intermediate layers are ignored and + output-name of last layer is used. + + :param model: model + :param naming_scheme: onnx/torchscript + :param dummy_input: dummy input that is used to construct onnx/torchscript model + :param onnx_export_args: OnnxExportApiArgs instance same as that passed to quantsim export API + :param dir_path: directory to temporarily save the constructed onnx/torchscrip model + :return: dictionary of layer-name to layer-output name + """ + # pylint: disable=import-outside-toplevel, cyclic-import + if any(isinstance(module, BaseQuantizationMixin) for module in model.modules()): + from aimet_torch.v2.quantsim import QuantizationSimModel + else: + from aimet_torch.v1.quantsim import QuantizationSimModel + + # Restore original model by removing quantization wrappers if present. + original_model = QuantizationSimModel.get_original_model(model) + + # Set path to store exported onnx/torchscript model. + LayerOutput._validate_dir_path(dir_path) + exported_model_dir = os.path.join(dir_path, 'exported_models') + os.makedirs(exported_model_dir, exist_ok=True) + + # Get node to i/o tensor name map from the onnx/torchscript model + if naming_scheme == NamingScheme.ONNX: + exported_model_node_to_io_tensor_map = LayerOutput.get_onnx_node_to_io_tensor_map( + original_model, exported_model_dir, dummy_input, onnx_export_args) + else: + exported_model_node_to_io_tensor_map = LayerOutput.get_torchscript_node_to_io_tensor_map( + original_model, exported_model_dir, dummy_input) + + layer_names_list = [name for name, module in original_model.named_modules() if utils.is_leaf_module(module)] + layers_missing_in_exported_model = [] + layer_name_to_layer_output_name_map = {} + + # Get mapping between layer names and layer-output names. + logger.info("Layer Name to Layer Output-name Mapping") + # pylint: disable=protected-access + for layer_name in layer_names_list: + if layer_name in exported_model_node_to_io_tensor_map: + # pylint: disable=protected-access, unused-variable + layer_output_names, intermediate_layer_output_names = QuantizationSimModel._get_layer_activation_tensors( + layer_name, exported_model_node_to_io_tensor_map) + layer_name_to_layer_output_name_map[layer_name] = layer_output_names[0] + logger.info("%s -> %s", layer_name, layer_output_names[0]) + else: + layers_missing_in_exported_model.append(layer_name) + + if layers_missing_in_exported_model: + logger.warning("The following layers were not found in the exported model:\n" + "%s\n" + "This can be due to below reason:\n" + "\t- The layer was not seen while exporting using the dummy input provided in sim.export(). " + "Ensure that the dummy input covers all layers.", + layers_missing_in_exported_model) + + # Delete onnx/torchscript models + shutil.rmtree(exported_model_dir, ignore_errors=False, onerror=None) + + return layer_name_to_layer_output_name_map + + @staticmethod + def get_onnx_node_to_io_tensor_map(model: torch.nn.Module, exported_model_dir: str, dummy_input: Union[torch.Tensor, Tuple, List], + onnx_export_args: Union[OnnxExportApiArgs, Dict]) -> Dict[str, Dict]: + """ + This function constructs an onnx model equivalent to the give pytorch model and then generates node-name to i/o + tensor-name map. + :param model: pytorch model without quantization wrappers + :param exported_model_dir: directory to save onnx model + :param dummy_input: dummy input to be used for constructing onnx model + :param onnx_export_args: configurations to generate onnx model + :return: onnx_node_to_io_tensor_map + """ + LayerOutput._validate_dummy_input(dummy_input) + LayerOutput._validate_onnx_export_args(onnx_export_args) + + onnx_path = os.path.join(exported_model_dir, 'model.onnx') + + OnnxSaver.create_onnx_model_with_pytorch_layer_names(onnx_model_path=onnx_path, pytorch_model=model, + dummy_input=dummy_input, onnx_export_args=onnx_export_args) + onnx_model = onnx.load(onnx_path) + onnx_node_to_io_tensor_map, _ = OnnxSaver.get_onnx_node_to_io_tensor_names_map(onnx_model) + + return onnx_node_to_io_tensor_map + + @staticmethod + def get_torchscript_node_to_io_tensor_map(model: torch.nn.Module, exported_model_dir: str, + dummy_input: Union[torch.Tensor, Tuple, List]) -> Dict[str, Dict]: + """ + This function constructs a torchscript model equivalent to the give pytorch model and then generates node-name to i/o + tensor-name map. + :param model: pytorch model without quantization wrappers + :param exported_model_dir: directory to save onnx model + :param dummy_input: dummy input to be used for constructing onnx model + :return: torchscript_node_to_io_tensor_map + """ + LayerOutput._validate_dummy_input(dummy_input) + + ts_path = os.path.join(exported_model_dir, 'model.torchscript.pth') + + with utils.in_eval_mode(model), torch.no_grad(): + torchscript_utils.create_torch_script_model(ts_path, model, dummy_input) + trace = torch.jit.load(ts_path) + torch_script_node_to_io_tensor_map, _ = \ + torchscript_utils.get_node_to_io_tensor_names_map(model, trace, dummy_input) + + return torch_script_node_to_io_tensor_map + + @staticmethod + def _validate_dir_path(dir_path: str): + """ + Validate directory path in which onnx/torchscript models will be temporarily saved + :param dir_path: directory path + :return: + """ + if dir_path is None: + raise ValueError("Missing directory path to save onnx/torchscript models") + + @staticmethod + def _validate_dummy_input(dummy_input: Union[torch.Tensor, Tuple, List]): + """ + Validates dummy input which is used to generate onnx/torchscript model + :param dummy_input: single input instance + :return: + """ + if not isinstance(dummy_input, (torch.Tensor, tuple, list)): + raise ValueError("Invalid dummy_input data-type") + + @staticmethod + def _validate_onnx_export_args(onnx_export_args: Union[OnnxExportApiArgs, Dict]): + """ + Validates export arguments which are used to generate an onnx model + :param onnx_export_args: export arguments + :return: + """ + if onnx_export_args is None: + onnx_export_args = OnnxExportApiArgs() + if not isinstance(onnx_export_args, (OnnxExportApiArgs, dict)): + raise ValueError("Invalid onnx_export_args data-type") +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/model_preparer.html b/releases/2.0.0/_modules/aimet_torch/model_preparer.html new file mode 100644 index 0000000..78423aa --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/model_preparer.html @@ -0,0 +1,1114 @@ + + + + + + + + aimet_torch.model_preparer - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.model_preparer

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2021-2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  From PyTorch:
    +#
    +#  Copyright (c) 2016-     Facebook, Inc            (Adam Paszke)
    +#  Copyright (c) 2014-     Facebook, Inc            (Soumith Chintala)
    +#  Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert)
    +#  Copyright (c) 2012-2014 Deepmind Technologies    (Koray Kavukcuoglu)
    +#  Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu)
    +#  Copyright (c) 2011-2013 NYU                      (Clement Farabet)
    +#  Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston)
    +#  Copyright (c) 2006      Idiap Research Institute (Samy Bengio)
    +#  Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz)
    +#
    +#  From Caffe2:
    +#
    +#  Copyright (c) 2016-present, Facebook Inc. All rights reserved.
    +#
    +#  All contributions by Facebook:
    +#  Copyright (c) 2016 Facebook Inc.
    +#
    +#  All contributions by Google:
    +#  Copyright (c) 2015 Google Inc.
    +#  All rights reserved.
    +#
    +#  All contributions by Yangqing Jia:
    +#  Copyright (c) 2015 Yangqing Jia
    +#  All rights reserved.
    +#
    +#  All contributions by Kakao Brain:
    +#  Copyright 2019-2020 Kakao Brain
    +#
    +#  All contributions by Cruise LLC:
    +#  Copyright (c) 2022 Cruise LLC.
    +#  All rights reserved.
    +#
    +#  All contributions from Caffe:
    +#  Copyright(c) 2013, 2014, 2015, the respective contributors
    +#  All rights reserved.
    +#
    +#  All other contributions:
    +#  Copyright(c) 2015, 2016 the respective contributors
    +#  All rights reserved.
    +#
    +#  Caffe2 uses a copyright model similar to Caffe: each contributor holds
    +#  copyright over their contributions to Caffe2. The project versioning records
    +#  all such contribution and copyright details. If a contributor wants to further
    +#  mark their specific copyright on a particular contribution, they should
    +#  indicate their copyright solely in the commit message of the change when it is
    +#  committed.
    +#
    +#  All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright
    +#     notice, this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright
    +#     notice, this list of conditions and the following disclaimer in the
    +#     documentation and/or other materials provided with the distribution.
    +#
    +#  3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories America
    +#     and IDIAP Research Institute nor the names of its contributors may be
    +#     used to endorse or promote products derived from this software without
    +#     specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Implementation to automatically prepare pytorch models for AIMET features """
    +
    +# --------------------------------------------------------------------------------------------------------
    +# Reference : https://github.com/pytorch/pytorch/blob/main/torch/fx/proxy.py#L26
    +#             https://github.com/pytorch/pytorch/blob/main/torch/fx/proxy.py#L57
    +
    +# Above PyTorch code is used to get node_name_to_scope information by overriding call_module and create_node methods
    +# of torch.fx.Tracer base class:
    +# TODO: node_name_to_scope should be removed and instead use node.meta[] after upgrading to torch 2.0
    +# ----------------------------------------------------------------------------------------------------------
    +
    +import copy
    +import re
    +from typing import Any, Optional, Dict, Union, List, Callable, Tuple
    +import torch
    +import torch.fx
    +from aimet_common.utils import AimetLogger
    +from aimet_torch.utils import in_eval_mode
    +from aimet_torch.utils import replace_modules_of_type1_with_type2
    +import aimet_torch._base.nn.modules.custom as aimet_modules
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.ModelPreparer)
    +
    +# this is a map of torch.nn.functional type to corresponding module type
    +functional_op_to_module_map = {
    +    torch.nn.functional.relu: torch.nn.ReLU,
    +    torch.nn.functional.gelu: torch.nn.GELU
    +}
    +
    +# In this functional --> module map, corresponding model is of type torch.nn and stateful.
    +functional_with_stateful_api = {
    +    'relu'          : torch.nn.ReLU,
    +    'relu6'         : torch.nn.ReLU6,
    +    'hardtanh'      : torch.nn.Hardtanh,
    +    'hardwish'      : torch.nn.Hardswish,
    +    'elu'           : torch.nn.ELU,
    +    'selu'          : torch.nn.SELU,
    +    'celu'          : torch.nn.CELU,
    +    'leaky_relu'    : torch.nn.LeakyReLU,
    +    'prelu'         : torch.nn.PReLU,
    +    'rrelu'         : torch.nn.RReLU,
    +    'glu'           : torch.nn.GLU,
    +    'gelu'          : torch.nn.GELU,
    +    'logsigmoid'    : torch.nn.LogSigmoid,
    +    'hardshrink'    : torch.nn.Hardshrink,
    +    'tanhshrink'    : torch.nn.Tanhshrink,
    +    'softsign'      : torch.nn.Softsign,
    +    'softplus'      : torch.nn.Softplus,
    +    'softmin'       : torch.nn.Softmin,
    +    'softmax'       : torch.nn.Softmax,
    +    'softshrink'    : torch.nn.Softshrink,
    +    'log_softmax'   : torch.nn.LogSoftmax,
    +    'tanh'          : torch.nn.Tanh,
    +    'sigmoid'       : torch.nn.Sigmoid,
    +    'hardsigmoid'   : torch.nn.Hardsigmoid,
    +    'silu'          : torch.nn.SiLU,
    +    'scaled_dot_product_attention': aimet_modules.ScaledDotProductAttention,
    +}
    +
    +
    +# Function that requires special transformation.
    +functional_with_special_handling = {
    +    'cat'           : aimet_modules.Concat,
    +    'conv2d'        : torch.nn.Conv2d
    +}
    +
    +# In this functional --> module map, corresponding custom module is of type torch.nn and uses stateless API.
    +functional_with_stateless_api = {
    +    '_pad'                      : aimet_modules.Pad,
    +    'pad'                       : aimet_modules.Pad,
    +    'sum'                       : aimet_modules.Sum,
    +    'add'                       : aimet_modules.Add,
    +    'subtract'                  : aimet_modules.Subtract,
    +    'sub'                       : aimet_modules.Subtract,
    +    'mul'                       : aimet_modules.Multiply,
    +    'div'                       : aimet_modules.Divide,
    +    'truediv'                   : aimet_modules.Divide,
    +    'floordiv'                  : aimet_modules.FloorDivide,
    +    'matmul'                    : aimet_modules.MatMul,
    +    'exp'                       : aimet_modules.Exponential,
    +    'interpolate'               : aimet_modules.Interpolate,
    +    'max_pool2d'                : aimet_modules.MaxPool2d,
    +    'max_pool2d_with_indices'   : aimet_modules.MaxPool2d,
    +    'adaptive_avg_pool2d'       : aimet_modules.AdaptiveAvgPool2d,
    +    'avg_pool2d'                : aimet_modules.AvgPool2d,
    +    'norm'                      : aimet_modules.Norm,
    +    'batch_norm'                : aimet_modules.BatchNorm,
    +    'group_norm'                : aimet_modules.GroupNorm,
    +    'mean'                      : aimet_modules.Mean,
    +    'pow'                       : aimet_modules.Pow,
    +    'where'                     : aimet_modules.Where,
    +    'addmm'                     : aimet_modules.Addmm,
    +    'bmm'                       : aimet_modules.Bmm,
    +    'baddbmm'                   : aimet_modules.Baddbmm,
    +    'cumsum'                    : aimet_modules.CumSum,
    +    'masked_fill'               : aimet_modules.MaskedFill,
    +    'square'                    : aimet_modules.Square,
    +    'rsqrt'                     : aimet_modules.RSqrt,
    +}
    +
    +
    +class Scope:
    +    """
    +    Code adapted from: https://github.com/pytorch/pytorch/blob/main/torch/fx/proxy.py#L26
    +
    +    Scope object that records the module path and the module type of module.
    +    Scope is used to track the information of the module that contains a Node
    +    in a Graph of GraphModule.
    +    """
    +    def __init__(self, module_path: str, module_type: Any):
    +        super().__init__()
    +        self.module_path = module_path
    +        self.module_type = module_type
    +
    +
    +class ScopeContextManager:
    +    """
    +    Code adapted from: https://github.com/pytorch/pytorch/blob/main/torch/fx/proxy.py#L57
    +
    +    A context manager to track the Scope of Node during symbolic tracing.
    +    When entering a forward function of a Module, we'll update the scope information of
    +    the current module, and when we exit, we'll restore the previous scope information.
    +    """
    +    def __init__(self, scope: Scope, current_scope: Scope):
    +        super().__init__()
    +        # Keep a copy of prev scope.
    +        self._prev_scope = copy.copy(scope)
    +        # Update scope to current scope
    +        scope.module_path = current_scope.module_path
    +        scope.module_type = current_scope.module_type
    +        # Save a reference so, we can restore tracer.scope with prev scope on exit.
    +        self._scope = scope
    +
    +    def __enter__(self):
    +        return
    +
    +    def __exit__(self, *args):
    +        self._scope.module_path = self._prev_scope.module_path
    +        self._scope.module_type = self._prev_scope.module_type
    +
    +
    +def conv2d_create_node(traced_model: torch.fx.GraphModule, module_name: str, node: torch.fx.node) \
    +        -> torch.fx.node:
    +    """
    +    Create the node to be inserted in the graph model.
    +
    +    :param traced_model: Symbolically traced model
    +    :param module_name: Qualified module name in symbolic_traced_model hierarchy corresponding to new node
    +    :param node: Current node in the graph after which new node will be inserted
    +    :return: torch.fx.node to be inserted in the graph
    +    """
    +
    +    n_args = len(node.args)
    +    # input tensors must be passed as args, not kwargs for QcQuantizeWrapper
    +    input_tensor = []
    +    # input and weight is guaranteed to exist, but bias can be None
    +    # Since None cannot be passed as args in QcQuantizeWrapper, do not add it to input_tensor
    +    for index, key in [[0, 'input'], [1, 'weight'], [2, ' bias']]:
    +        value = None
    +        if n_args > index:
    +            value = node.args[index]
    +        elif key in node.kwargs:
    +            value = node.kwargs[key]
    +
    +        if value is not None:
    +            input_tensor.append(value)
    +        else:
    +            break
    +
    +    with traced_model.graph.inserting_after(node):
    +        if check_dynamic_conv2d(traced_model, module_name):
    +            new_node = traced_model.graph.call_module(module_name, args=tuple(input_tensor))
    +        else:
    +            new_node = traced_model.graph.call_module(module_name, args=tuple([input_tensor[0]]))
    +        return new_node
    +
    +
    +def check_dynamic_conv2d(traced_model: torch.fx.GraphModule, module_name: str) -> bool:
    +    """
    +    return True if the module is dynamic conv2d.
    +    """
    +    m = traced_model
    +    for name in module_name.split('.'):
    +        m = getattr(m, name)
    +
    +    return isinstance(m, aimet_modules.DynamicConv2d)
    +
    +
    +def conv2d_create_module(node: torch.fx.node) -> torch.nn.Module:
    +    """
    +    Create the replacement module.
    +
    +    :param node: Current node in the graph after which new node will be inserted
    +    :return: New module.
    +    """
    +
    +    # Get weight and bias from argument
    +    params = merge_args_and_kwargs(node, {1: 'weight', 2: 'bias'})
    +
    +    # Convert F.Conv2D arguments to nn.Conv2D arguments
    +    kwargs = merge_args_and_kwargs(node, {3: 'stride', 4: 'padding', 5: 'dilation', 6: 'groups'})
    +
    +    # If weight or bias is from activation of another layer, use dynamic_conv2d
    +    use_dynamic_conv2d = False
    +    for key, param in params.items():
    +        if param.op != 'get_attr':
    +            use_dynamic_conv2d = True
    +            break
    +
    +    if use_dynamic_conv2d:
    +        module = aimet_modules.DynamicConv2d(**kwargs)
    +    else:
    +        for key, param_node in params.items():
    +            params[key] = get_node_attr(param_node)
    +
    +        # Fetch additional info using parameters
    +        out_channels, in_channels, kernel_size, _ = params['weight'].shape
    +        bias = 'bias' in params
    +
    +        # For Depthwise Conv, multiply in_channels by number of groups
    +        # if groups is not passed as arg, use its default value 1
    +        kwargs['in_channels'] = in_channels * kwargs.get('groups', 1)
    +        kwargs['out_channels'] = out_channels
    +        kwargs['kernel_size'] = kernel_size
    +        kwargs['bias'] = bias
    +
    +        module = torch.nn.Conv2d(**kwargs)
    +        # Replace nn.Conv2D params using F.Conv2D arguments
    +        module.weight = torch.nn.Parameter(params['weight'])
    +        if bias:
    +            module.bias = torch.nn.Parameter(params['bias'])
    +    return module
    +
    +
    +def merge_args_and_kwargs(node: torch.fx.node, arguments_to_fetch: Dict) -> Dict:
    +    """
    +    Merge args and kwargs into a single kwargs and return it
    +    :param node: node to fetch args and kwargs from
    +    :param arguments_to_fetch: dictionary containing arguments' indices in args and keys in kwargs
    +    :return: single merged kwargs
    +    """
    +    n_args = len(node.args)
    +    kwargs = {}
    +    for index, key in arguments_to_fetch.items():
    +        value = None
    +        if n_args > index:
    +            value = node.args[index]
    +        elif key in node.kwargs:
    +            value = node.kwargs[key]
    +
    +        if value is not None:
    +            kwargs[key] = value
    +    return kwargs
    +
    +
    +def get_node_attr(node: torch.fx.node):
    +    """
    +    Codes modified from https://pytorch.org/docs/stable/fx.html#the-interpreter-pattern
    +
    +    :param node: node to fetch data from
    +    :return: value returned from node
    +    """
    +    def fetch_attr(target: str):
    +        target_atoms = target.split('.')
    +        attr_itr = node.graph.owning_module
    +        for i, atom in enumerate(target_atoms):
    +            if not hasattr(attr_itr, atom):
    +                raise RuntimeError(f"Node referenced nonexistant target {'.'.join(target_atoms[:i])}")
    +            attr_itr = getattr(attr_itr, atom)
    +        return attr_itr
    +
    +    assert node.op == 'get_attr'
    +
    +    return fetch_attr(node.target)
    +
    +
    +def concat_create_node(traced_model: torch.fx.GraphModule, module_name: str, node: torch.fx.node) \
    +        -> torch.fx.node:
    +    """
    +    Create the node to be inserted in the graph model.
    +
    +    :param traced_model: Symbolically traced model
    +    :param module_name: Qualified module name in symbolic_traced_model hierarchy corresponding to new node
    +    :param node: Current node in the graph after which new node will be inserted
    +    :return: torch.fx.node to be inserted in the graph
    +    """
    +
    +    with traced_model.graph.inserting_after(node):
    +        # call_module only accepts tuple as args but node.args[0] can be a list. Convert it into a tuple
    +        # If node.args[0] is already a tuple, tuple() will do nothing
    +        new_node = traced_model.graph.call_module(module_name, args=tuple(node.args[0]))
    +        return new_node
    +
    +
    +def concat_create_module(node: torch.fx.node) -> torch.nn.Module:
    +    """
    +    Create the replacement module.
    +
    +    :param node: Current node in the graph after which new node will be inserted
    +    :return: New module.
    +    """
    +
    +    num_args = len(node.args)
    +    if num_args == 1 and 'dim' not in node.kwargs:
    +        # Handle torch.cat being called with default parameter dim
    +        kwargs = node.kwargs
    +        module = aimet_modules.Concat()
    +    else:
    +        axis = node.args[1] if num_args > 1 else node.kwargs['dim']
    +        module = aimet_modules.Concat(axis)
    +        kwargs = {'axis': axis}
    +
    +    for key, value in kwargs.items():
    +        setattr(module, key, value)
    +
    +    return module
    +
    +special_handler_functions = {
    +    # Special handling functions for creating node and module
    +    'cat': {'node_fn': concat_create_node, 'module_fn': concat_create_module},
    +    'conv2d': {'node_fn': conv2d_create_node, 'module_fn': conv2d_create_module}
    +}
    +
    +
    +
    +[docs] +def prepare_model(model: torch.nn.Module, + modules_to_exclude: List[torch.nn.Module] = None, + module_classes_to_exclude: List[Callable] = None, + concrete_args: Optional[Dict[str, Any]] = None) -> torch.fx.GraphModule: + """ + Prepare and modify the pytorch model for AIMET features using torch.FX symbolic tracing API. + + 1. Replace torch.nn.functional by module of type torch.nn.Module + 2. Create new independent torch.nn.Module instances for reused/duplicate module + + :param model: pytorch Model to be modified. + :param modules_to_exclude: List of modules to exclude when tracing. + :param module_classes_to_exclude: List of module classes to exclude when tracing. + :param concrete_args: Allows you to partially specialize your function, whether it's to remove control flow or + data structures. If the model has control flow, torch.fx won't be able to trace the model. Check + torch.fx.symbolic_trace API in detail. + :return: Modified pytorch Model + """ + with in_eval_mode(model): + traced_model, node_name_to_scope = \ + _trace_model(model, modules_to_exclude, module_classes_to_exclude, concrete_args) + + # Prepare model and perform checks to make sure the graph is well-formed. + _prepare_traced_model(traced_model, node_name_to_scope) + return traced_model
    + + + +def _trace_model(model: torch.nn.Module, + modules_to_exclude: Optional[List[torch.nn.Module]], + module_classes_to_exclude: Optional[List[Callable]], + concrete_args: Optional[Dict[str, Any]]) -> [torch.fx.GraphModule, Dict]: + """ + Returns traced model and dictionary of node name to the scope of module which contains the node. + + :param model: pytorch Model to be modified. + :param modules_to_exclude: List of modules to exclude when tracing. + :param module_classes_to_exclude: List of module classes to exclude when tracing. + :param concrete_args: Concrete arguments that should not be treated as Proxies. + :return: (Traced model, node_name_to_scope) + """ + class Tracer(torch.fx.Tracer): + """ + Override is_leaf_module(), call_module() and create_node() methods of parent class. + """ + def __init__(self): + super().__init__() + self.scope = Scope("", None) + self.node_name_to_scope = {} + + def is_leaf_module(self, m: torch.nn.Module, module_qualified_name: str) -> bool: + return ( + modules_to_exclude and m in modules_to_exclude + or module_classes_to_exclude and type(m) in module_classes_to_exclude # pylint: disable=unidiomatic-typecheck + or super().is_leaf_module(m, module_qualified_name) + ) + + def call_module(self, m: torch.nn.Module, forward: Callable[..., Any], args: Tuple[Any, ...], + kwargs: Dict[str, Any]) -> Any: + module_qualified_name = self.path_of_module(m) + with ScopeContextManager(self.scope, Scope(module_qualified_name, type(m))): + return super().call_module(m, forward, args, kwargs) + + def create_node(self, kind: str, target, args, kwargs, name: Optional[str] = None, + type_expr: Optional[Any] = None) -> torch.fx.Node: + node = super().create_node(kind, target, args, kwargs, name, type_expr) + self.node_name_to_scope[node.name] = (self.scope.module_path, self.scope.module_type) + return node + + # Symbolic tracing frontend - captures the semantics of the module + tracer = Tracer() + graph = tracer.trace(model, concrete_args=concrete_args) + traced_model = torch.fx.GraphModule(tracer.root, graph) + return traced_model, tracer.node_name_to_scope + + +def _prepare_traced_model(traced_model: torch.fx.GraphModule, + node_name_to_scope: Dict[str, Tuple[str, type]] = None): + """ + Helper for prepare_model(). This prepares the given traced_model in-place. + + :param traced_model: Symbolically traced model. + :param node_name_to_scope: Mapping from node name to the scope of module which contains the node. + """ + unique_nodes = set() + + # Modify the symbolically traced model by iterating over all the nodes + for node in traced_model.graph.nodes: + + # Create new module for functional nodes + if node.op in ['call_function', 'call_method']: + functional_name = _find_functional_name_for_node(node.name) + if functional_name: + # Instantiate new module for functional node + new_module = _create_module_for_functional_node(node, functional_name) + parent_module, new_module_name, new_module_qualified_name = \ + _get_info_for_functional_node(traced_model, node, node_name_to_scope) + setattr(parent_module, new_module_name, new_module) + # Insert the node for new module in the graph + _insert_node_for_new_module(traced_model, node, new_module_qualified_name, functional_name) + logger.info("Functional : Adding new module for node: {%s} ", new_module_qualified_name) + + # Create new module for reused/duplicate nodes + elif node.target in unique_nodes: + if node.op == 'call_module': + # Instantiate new module for reused node + new_module = _create_module_for_reused_node(node, traced_model) + parent_module, new_module_name, new_module_qualified_name = \ + _get_info_for_reused_node(traced_model, node, node_name_to_scope) + setattr(parent_module, new_module_name, new_module) + # Insert the node for new module in the graph + _insert_node_for_new_module(traced_model, node, new_module_qualified_name) + logger.info("Reused/Duplicate : Adding new module for node: {%s} ", new_module_qualified_name) + else: + unique_nodes.add(node.target) + + _verify_traced_model(traced_model) + + # Replace SiLU with CustomSiLU + replace_modules_of_type1_with_type2(traced_model, torch.nn.SiLU, aimet_modules.CustomSiLU) + + +def _verify_traced_model(traced_model: torch.fx.GraphModule): + """ + Does some checks to make sure the graph is well-formed and recompile the forward() method of symbolic_traced + model from its graph + + :param traced_model: Symbolically traced model + """ + traced_model.graph.lint() + traced_model.recompile() + + +def _insert_node_for_new_module(traced_model: torch.fx.GraphModule, + node: torch.fx.node, + module_qualified_name: str, + functional_name: str = None): + """ + Insert 'call module' node into graph and replace all the uses of 'node' with newly added node and erase the + old node from graph + :param traced_model: Symbolically traced model + :param node: Current node in the graph after which new node will be inserted + :param module_qualified_name: Qualified module name in symbolic_traced_model hierarchy corresponding to new node + :param functional_name: Original functional name + """ + with traced_model.graph.inserting_after(node): + if functional_name: + if functional_name in functional_with_special_handling: + new_node = special_handler_functions[functional_name]['node_fn'](traced_model, module_qualified_name, node) + elif functional_name in functional_with_stateless_api: + new_node = traced_model.graph.call_module(module_qualified_name, args=node.args, kwargs=node.kwargs) + elif functional_name in functional_with_stateful_api: + new_node = traced_model.graph.call_module(module_qualified_name, args=node.args) + else: + raise ValueError("Unsupported module: {}".format(functional_name)) + else: + new_node = traced_model.graph.call_module(module_qualified_name, args=node.args) + + node.replace_all_uses_with(new_node) + traced_model.graph.erase_node(node) + + +def _find_functional_name_for_node(node_name: str) -> Union[str, None]: + """ + For given node name, find corresponding functional name from combined lookup + + :param node_name: torch.fx Node name + :return: corresponding functional name if found, else None + """ + combined_lookup = {**functional_with_stateful_api, **functional_with_special_handling, **functional_with_stateless_api} + + # Functional operations with similar names are differentiated using "_count" suffix + # when symbolically traced. For example, two add operations will have name 'add' and 'add_1'. + # Split given node name by occurrence of pattern. \d is used to match [0-9] followed by '_'. + strings = re.split(pattern=r'_\d', string=node_name) + for string in strings: + if string in combined_lookup.keys(): + return string + + logger.debug("Couldn't find functional: %s in the lookup. If functional op isn't math invariant," + " add an entry in the lookup.", node_name) + return None + + +def _create_module_for_functional_node(node: torch.fx.node, functional_name: str) -> torch.nn.Module: + """ + For given node and functional name, create torch.nn.Module with same parameters as functional node parameters + :param node: torch.fx Node + :param functional_name: Functional name for given node + :return: New module + """ + # Instantiate new module from lookup + if functional_name in functional_with_stateful_api: + module = functional_with_stateful_api[functional_name]() + # Set the parameters for module from node.kwargs + for key, value in node.kwargs.items(): + setattr(module, key, value) + elif functional_name in functional_with_special_handling: + module = special_handler_functions[functional_name]['module_fn'](node) + elif functional_name in functional_with_stateless_api: + module = functional_with_stateless_api[functional_name]() + else: + raise ValueError("Unsupported module: {}".format(functional_name)) + return module + + +def _create_module_for_reused_node(node: torch.fx.node, symbolic_traced_model: torch.fx.GraphModule) ->\ + torch.nn.Module: + """ + For given reused/Duplicate node in symbolically traced model, create new module with same parameters as + original module + :param node: Reused/Duplicate torch.fx Node + :param symbolic_traced_model: Symbolically traced model + :return: New module + """ + # Get the original module and return newly deep copied module + module = _get_module_for_dotted_name(symbolic_traced_model, node.target) + new_module = copy.deepcopy(module) + + return new_module + + +def _get_module_for_dotted_name(module: torch.fx.GraphModule, dotted_name: str) -> torch.nn.Module: + """ + For given dotted name, find the module + :param module: module to be found + :param dotted_name: dotted name of module + :return: module + """ + if '.' in dotted_name: + module_name, _, remainder = dotted_name.partition('.') + return _get_module_for_dotted_name(module._modules[module_name], remainder) # pylint: disable=protected-access + + return getattr(module, dotted_name) + + +def get_module_for_activation_fn(act_fn: torch.nn.functional): + """ + returns module instance for functional tyoe handled within PT transformers for activation functions + :param act_fn: activation function implemented as a functional. + :return: module equivalent for the activation function. + """ + + if act_fn not in functional_op_to_module_map: + logger.error("Unsupported activation function {%s}", act_fn) + return None + module = functional_op_to_module_map[act_fn]() + return module + + +def prepare_pt_transformer_for_quantsim(transformer_model: torch.nn.Module): + """ + Replaces functionals with modules for activation function, updates model in-place + :param transformer_model: model with PyTorch nn.Transformer layer + :return: updated model with modules for activation function. + """ + + for module in transformer_model.modules(): + + # encoder layer or decoder layer type is the leaf level node to be updated within nn.transformer layer + if isinstance(module, torch.nn.TransformerEncoderLayer) and not isinstance(module.activation, torch.nn.Module): + module.activation = get_module_for_activation_fn(module.activation) + + if isinstance(module, torch.nn.TransformerDecoderLayer) and not isinstance(module.activation, torch.nn.Module): + module.activation = get_module_for_activation_fn(module.activation) + + +def _get_info_for_functional_node(traced_model: torch.fx.GraphModule, + node: torch.fx.Node, + node_name_to_scope: Dict[str, Tuple[str, type]])\ + -> Tuple[torch.fx.GraphModule, str, str]: + """ + For functional node, get module which contains the node, corresponding new module's name and fully qualified name. + This information will be used to add new module at either module-level scope or model-level scope. + + NOTE: If node_name_to_scope is not provided, then the corresponding new module will be added at model-level scope. + Also, if exception is raised, new module will be added at model-level scope. + + :param traced_model: Traced model + :param node: torch.fx Node + :param node_name_to_scope: Mapping from node name to the scope of module which contains the node. + :return: (parent_module, new_module_name, new_module_qualified_name) + """ + parent_module = traced_model + new_module_name = "module_" + node.name + new_module_qualified_name = new_module_name + + if node_name_to_scope: + try: + module_path, _ = node_name_to_scope[node.name] + parent_module = traced_model.get_submodule(module_path) + if module_path == "": + new_module_qualified_name = new_module_name + else: + new_module_qualified_name = module_path + "." + new_module_name + except (KeyError, AttributeError): + pass + + return parent_module, new_module_name, new_module_qualified_name + + +def _get_info_for_reused_node(traced_model: torch.fx.GraphModule, + node: torch.fx.Node, + node_name_to_scope: Dict[str, Tuple[str, type]])\ + -> Tuple[torch.fx.GraphModule, str, str]: + """ + For reused node, get module which contains the node, corresponding new module's name and fully qualified name. + This information will be used to add new module at either module-level scope or model-level scope. + + NOTE: If node_name_to_scope is not provided, then the corresponding new module will be added at model-level scope. + Also, if exception is raised, new module will be added at model-level scope. + + :param traced_model: Traced model + :param node: torch.fx Node + :param node_name_to_scope: Mapping from node name to the scope of module which contains the node. + :return: (parent_module, new_module_name, new_module_qualified_name) + """ + parent_module = traced_model + new_module_name = "module_" + node.name + new_module_qualified_name = new_module_name + + if node_name_to_scope: + try: + module_path, _ = node_name_to_scope[node.name] + if "." in module_path: + parent_name, child_name = module_path.rsplit(".", maxsplit=1) + else: + parent_name, child_name = "", module_path + parent_module = traced_model.get_submodule(parent_name) + new_module_name = "module_" + child_name + "_" + node.name.rsplit("_", maxsplit=1)[1] + if parent_name == "": + new_module_qualified_name = new_module_name + else: + new_module_qualified_name = parent_name + "." + new_module_name + except (KeyError, AttributeError): + pass + + return parent_module, new_module_name, new_module_qualified_name +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/model_validator/model_validator.html b/releases/2.0.0/_modules/aimet_torch/model_validator/model_validator.html new file mode 100644 index 0000000..813aa16 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/model_validator/model_validator.html @@ -0,0 +1,434 @@ + + + + + + + + aimet_torch.model_validator.model_validator - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.model_validator.model_validator

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Utility for validating pytorch models prior to using AIMET features """
    +
    +from typing import Tuple, Union, Callable
    +import torch
    +
    +from aimet_common.utils import AimetLogger
    +import aimet_torch.model_validator.validation_checks as val_checks
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.Utils)
    +
    +
    +
    +[docs] +class ModelValidator: + """ + ModelValidator object for validating that AIMET features can be applied on the Pytorch model. + """ + _validation_checks = [ + val_checks.validate_for_reused_modules, + val_checks.validate_for_missing_modules + ] + +
    +[docs] + @staticmethod + def add_check(validation_check: Callable): + """ + Add a validation check function to be used for validating the model. Validation check functions must take the + model, model inputs, and kwargs as inputs. + The validation check must output True if the model passes the check, and False otherwise. + :param validation_check: Validation check function for validating the model. + """ + ModelValidator._validation_checks.append(validation_check)
    + + +
    +[docs] + @staticmethod + def validate_model(model: torch.nn.Module, model_input: Union[torch.Tensor, Tuple], **kwargs) -> bool: + """ + Validate the pytorch model by running all validation check functions and returning True if all pass, False + otherwise. + Keyword arguments can be used to pass specific arguments to particular validation checkers. + Currently supported keyword arguments: + layers_to_exclude: List of torch.nn.Modules to be excluded in the check for missing modules. These layers and + all of their sublayers will not be flagged if they do not have a corresponding Pytorch module. + :param model: Pytorch model to validate + :param model_input: Dummy input to the model + :return True if pytorch model is valid, False otherwise + """ + is_valid_model = True + failed_val_checks = set() + for val_check in ModelValidator._validation_checks: + logger.info('Running validator check %s', val_check) + val_check_result = val_check(model, model_input, **kwargs) + if not val_check_result: + failed_val_checks.add(val_check) + is_valid_model = is_valid_model and val_check_result + if not is_valid_model: + logger.info('The following validator checks failed:') + for val_check in failed_val_checks: + logger.info('\t%s', val_check) + return is_valid_model + + logger.info('All validation checks passed.') + return is_valid_model
    +
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/peft.html b/releases/2.0.0/_modules/aimet_torch/peft.html new file mode 100644 index 0000000..26f9ddb --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/peft.html @@ -0,0 +1,840 @@ + + + + + + + + aimet_torch.peft - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.peft

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Implementation for handling LoRA adapters added using PEFT """
    +from typing import Dict, Type
    +import os
    +import pickle
    +from collections import defaultdict
    +import torch.nn as nn
    +import torch
    +from safetensors.torch import save_file
    +from safetensors import safe_open
    +
    +# pylint: disable=import-error
    +# pylint: disable=no-name-in-module
    +from peft.tuners.lora.layer import LoraLayer as PeftLoraLayer
    +from peft.tuners.lora.layer import Conv2d as PeftConv2d
    +
    +from aimet_torch.utils import replace_modules_of_type1_using_constructor
    +from aimet_torch._base.nn.modules.custom import Add, Multiply
    +from aimet_torch.v2.quantsim import QuantizationSimModel
    +from aimet_torch.v2.quantization.affine import QuantizeDequantize
    +from aimet_torch._base.quantsim import _QuantizedModuleProtocol
    +from aimet_torch.v2.nn import BaseQuantizationMixin
    +
    +
    +class LoraLayer(torch.nn.Module):
    +    """
    +    Quantizable lora layer
    +    """
    +    # pylint: disable=too-many-instance-attributes
    +    def __init__(self, lora_layer: PeftLoraLayer):
    +        """
    +        :param lora_layer: Lora layer we want to replace
    +        """
    +        super().__init__()
    +        self.base_layer = lora_layer.base_layer
    +        self.r = lora_layer.r
    +        self.lora_alpha = lora_layer.lora_alpha
    +        self.scaling = [torch.nn.Parameter(torch.as_tensor(scale), requires_grad=False).to(self.base_layer.weight.device)
    +                        for scale in lora_layer.scaling.values()]
    +        self.lora_dropout = nn.ModuleList({})
    +        self.adapter_name_to_index = {}
    +        self.index_to_adapter_name = {}
    +        self.lora_A = nn.ModuleList([])
    +        self.lora_B = nn.ModuleList([])
    +        self.active_adapters = {}
    +        self._swap_module_dict_with_list(lora_layer)
    +        self.in_features = lora_layer.in_features
    +        self.out_features = lora_layer.out_features
    +        self.add_lora_to_res = Add()
    +        self.mul_scale = Multiply()
    +
    +    def _swap_module_dict_with_list(self, lora_layer):
    +        for index, adapter_name in enumerate(lora_layer.lora_A):
    +            self.lora_A.append(lora_layer.lora_A[adapter_name])
    +            self.lora_B.append(lora_layer.lora_B[adapter_name])
    +            self.lora_dropout.append(lora_layer.lora_dropout[adapter_name])
    +            self.adapter_name_to_index[adapter_name] = index
    +            if adapter_name in lora_layer.active_adapter:
    +                self.active_adapters[adapter_name] = True
    +            else:
    +                self.active_adapters[adapter_name] = False
    +        for adapter_name in self.adapter_name_to_index:
    +            self.index_to_adapter_name[self.adapter_name_to_index[adapter_name]] = adapter_name
    +
    +    def forward(self, x: torch.Tensor, *args, **kwargs) -> torch.Tensor:
    +        """ Forward pass for replaced layer"""
    +        result = self.base_layer(x, *args, **kwargs)
    +        torch_result_dtype = result.dtype
    +        for active_adapter in self.active_adapters:
    +            if active_adapter not in self.adapter_name_to_index:
    +                continue
    +            lora_A = self.lora_A[self.adapter_name_to_index[active_adapter]]
    +            lora_B = self.lora_B[self.adapter_name_to_index[active_adapter]]
    +            dropout = self.lora_dropout[self.adapter_name_to_index[active_adapter]]
    +            scaling = self.scaling[self.adapter_name_to_index[active_adapter]]
    +            x = x.to(lora_A.weight.dtype)
    +
    +            result = self.add_lora_to_res(result, lora_B(self.mul_scale(lora_A(dropout(x)), scaling.detach())))
    +
    +        result = result.to(torch_result_dtype)
    +        return result
    +
    +
    +def replace_lora_layers_with_quantizable_layers(model: torch.nn.Module):
    +    """
    +    Utility to replace lora layers with Quantizable Lora layers
    +
    +    :param model: PEFT model
    +    """
    +    replace_modules_of_type1_using_constructor(model, PeftLoraLayer, LoraLayer)
    +    replace_modules_of_type1_using_constructor(model, PeftConv2d, LoraLayer)
    +
    +
    +
    +[docs] +class AdapterMetaData: + """ + Tracks meta data for lora layers. Tracks names of lora_a & b as well as alpha values + Attributes: + lora_A, lora_B, alpha + """ + def __init__(self): + self.lora_A = [] + self.lora_B = [] + self.alpha = None + self.mul_scale = []
    + + + +def track_lora_meta_data(model: torch.nn.Module, path: str, filename_prefix: str, + replaced_module_type: Type[torch.nn.Module] = None) -> Dict[str, AdapterMetaData]: + """ + Utility to track and save meta data for adapters. The meta data has adapter names and corresponding lora layers & alphas + + :param model: PEFT model + :param path: path where to store model pth and encodings + :param filename_prefix: Prefix to use for filenames + :param replaced_module_type: If lora linear layer is replaced by another torch module, then replaced_module_type + represents the type with which linear layer was replaced. Otherwise pass None + """ + module_to_name_d = {} + + for name, module in model.named_modules(): + module_to_name_d[module] = name + + adapter_name_to_meta_data = defaultdict(AdapterMetaData) + for name, module in model.named_modules(): + if isinstance(module, LoraLayer): + for index, lora_layer in enumerate(module.lora_A): + if replaced_module_type and isinstance(lora_layer, replaced_module_type): + lora_layer = lora_layer.conv2d + adapter_name_to_meta_data[module.index_to_adapter_name[index]].lora_A.append( + module_to_name_d[lora_layer]) + for index, lora_layer in enumerate(module.lora_B): + if replaced_module_type and isinstance(lora_layer, replaced_module_type): + lora_layer = lora_layer.conv2d + adapter_name_to_meta_data[module.index_to_adapter_name[index]].lora_B.append( + module_to_name_d[lora_layer]) + for lora_adapter_name in module.lora_alpha: + adapter_name_to_meta_data[lora_adapter_name].alpha = module.lora_alpha[lora_adapter_name] + adapter_name_to_meta_data[module.index_to_adapter_name[index]].mul_scale.append(module_to_name_d[module.mul_scale]) + + + file_name = os.path.join(path, f"{filename_prefix}.pkl") + with open(file_name, 'wb') as file: + pickle.dump(adapter_name_to_meta_data, file) + return adapter_name_to_meta_data + + +
    +[docs] +class PeftQuantUtils: + """ + Utilities for quantizing peft model + """ + def __init__(self, adapater_name_to_meta_data: Dict[str, AdapterMetaData], name_to_module_dict=None): + """ + Init for Peft utilities for quantization + + :param adapater_name_to_meta_data: Dict mapping adapter name to meta data. Output of track_meta_data + :param name_to_module_dict: PT Name to module prepared model name mapping + """ + self.adapter_name_to_meta_data = adapater_name_to_meta_data + self.lora_layers = self._get_lora_layers() + self.pt_name_to_prepared_name, self.prepared_name_to_pt_name = None, None + self.pt_to_lora_name = dict.fromkeys(self.lora_layers, '') + if name_to_module_dict: + self.pt_name_to_prepared_name, self.prepared_name_to_pt_name = self._get_pytorch_name_to_prepared_name(name_to_module_dict) + self.lora_to_pt_name, self.pt_to_lora_name = self._get_lora_name_to_pytorch_name() + self.mul_names = self._get_prepared_name_for_mul() + + @staticmethod + def _get_pytorch_name_to_prepared_name(name_to_module_dict): + """ + Gets onnx names to pytorch names mapping and vice versa + """ + pt_name_to_onnx_name = {} + onnx_name_to_pt_name = {} + for pytorch_name in name_to_module_dict: + onnx_name = name_to_module_dict[pytorch_name][0] + pt_name_to_onnx_name[pytorch_name] = onnx_name + onnx_name_to_pt_name[onnx_name] = pytorch_name + return pt_name_to_onnx_name, onnx_name_to_pt_name + + def _get_prepared_name_for_mul(self): + """ + Gets onnx names to pytorch names mapping and vice versa + """ + names = set() + for adapter_name in self.adapter_name_to_meta_data: + adapter_data = self.adapter_name_to_meta_data[adapter_name] + for index, _ in enumerate(adapter_data.mul_scale): + lora_prepared_name = self.pt_name_to_prepared_name[self.lora_to_pt_name[adapter_data.lora_A[index]]] + prepared_name = lora_prepared_name[0:lora_prepared_name.find('_lora_A')] + '_mul_scale_Mul' + names.add(prepared_name) + return names + +
    +[docs] + def quantize_lora_scale_with_fixed_range(self, sim, bitwidth, scale_min=0, scale_max=1e-5): + """ + Add input quantizer for scale(alpha/rank) and provide min max values to it + + :param sim: QuantSim model + :param bitwidth: Bitwidth for input quantizer to Mul/ bitwidth for scale + :param scale_min: min value of lora alpha to be used + :param scale_max: max value of lora alpha to be used + """ + + def _create_quantizer(): + quantizer = QuantizeDequantize(shape=(), bitwidth=bitwidth, symmetric=False) + quantizer.set_range(torch.as_tensor(scale_min), torch.as_tensor(scale_max)) + self._freeze_quantizer(quantizer) + return quantizer + + for name, module in sim.model.named_modules(): + if not self.prepared_name_to_pt_name: + if isinstance(module, LoraLayer): + module.mul_scale.input_quantizers[1] = _create_quantizer() + elif name in self.mul_names: + module.input_quantizers[1] = _create_quantizer()
    + + + def _get_lora_name_to_pytorch_name(self): + """ + Gets most similar pytorch name for every lora name + """ + lora_to_pytorch_name = {} + pytorch_to_lora_name = {} + for pt_name in self.pt_name_to_prepared_name: + for lora_name in self.lora_layers: + if pt_name in lora_name: + lora_to_pytorch_name[lora_name] = pt_name + pytorch_to_lora_name[pt_name] = lora_name + return lora_to_pytorch_name, pytorch_to_lora_name + + def _get_lora_layers(self) -> set: + """ + Gets all lora layers + """ + lora_layers = set() + for adapter_name in self.adapter_name_to_meta_data: + for lora_module in self.adapter_name_to_meta_data[adapter_name].lora_A: + lora_layers.add(lora_module) + for lora_module in self.adapter_name_to_meta_data[adapter_name].lora_B: + lora_layers.add(lora_module) + return lora_layers + + @staticmethod + def _freeze_quantizer(quantizer): + """ + Disables compute encodings and gradient update for a quantizer + + :param quantizer: Param, output or Input quantizer + """ + # pylint:disable = protected-access + quantizer._allow_overwrite = False + quantizer.requires_grad_(False) + +
    +[docs] + def freeze_base_model_param_quantizers(self, sim: QuantizationSimModel): + """ + Freeze parameter quantizers of base model + + :param sim: QuantSim model + """ + for module_name, module in sim.model.named_modules(): + module_name = self._get_module_name(module_name) + if isinstance(module, BaseQuantizationMixin) and module_name not in self.pt_to_lora_name: + for _, param_quantizer in module.param_quantizers.items(): + if param_quantizer: + self._freeze_quantizer(param_quantizer)
    + + +
    +[docs] + def freeze_base_model_activation_quantizers(self, sim: QuantizationSimModel): + """ + Freeze activation quantizers of base model + + :param sim: QuantSim model + """ + for module_name, module in sim.model.named_modules(): + module_name = self._get_module_name(module_name) + if isinstance(module, BaseQuantizationMixin) and module_name not in self.pt_to_lora_name: + for input_quantizer, output_quantizer in zip(module.input_quantizers, module.output_quantizers): + if input_quantizer: + self._freeze_quantizer(input_quantizer) + if output_quantizer: + self._freeze_quantizer(output_quantizer)
    + + +
    +[docs] + def freeze_base_model(self, sim: QuantizationSimModel): + """ + Freeze entire base model + + :param sim: QuantSim model + """ + self.freeze_base_model_activation_quantizers(sim) + self.freeze_base_model_param_quantizers(sim)
    + + +
    +[docs] + def set_bitwidth_for_lora_adapters(self, sim: QuantizationSimModel, + output_bw: int, param_bw: int): + """ + Sets output and param bitwidth for all Lora adapters added to the model + + :param sim: QuantSim model + :param output_bw: Output BW + :param param_bw: Parameter BW + """ + for module_name, module in sim.model.named_modules(): + module_name = self._get_module_name(module_name) + if isinstance(module, BaseQuantizationMixin) and module_name in self.pt_to_lora_name: + self._set_bitwidth_for_module(module, output_bw, param_bw)
    + + + def _get_module_name(self, module_name: str) -> str: + """ + Gets module name from prepared model's names if prepared model is being used, else returns the pytorch name + :param module_name: pytorch name + """ + if self.prepared_name_to_pt_name and module_name in self.prepared_name_to_pt_name: + module_name = self.prepared_name_to_pt_name[module_name] + return module_name + +
    +[docs] + def get_quantized_lora_layer(self, sim: QuantizationSimModel): + """ + This function can be used to generate lora quantized layers + Use cases: 1) New quantizers can be created and assigned to lora quantized layer. + New quantizers may be required if changing - Changing dtype, per channel to per tensor + and vice versa + 2) Assign new values to symmetric, bitwidth + + :param sim: QuantSim model + """ + for module_name, module in sim.model.named_modules(): + module_name = self._get_module_name(module_name) + if isinstance(module, BaseQuantizationMixin) and module_name in self.pt_to_lora_name: + yield module_name, module
    + + +
    +[docs] + def get_fp_lora_layer(self, model): + """ + This Function can be used to get lora layers for a model + + :param model: FP32 model + """ + for module_name, module in model.named_modules(): + module_name = self._get_module_name(module_name) + if module_name in self.pt_to_lora_name: + yield module_name, module
    + + + @staticmethod + def _set_bitwidth_for_module(module: BaseQuantizationMixin, output_bw: int, param_bw: int): + """ + Sets bitwidth for a QcQuantizeWrapper module + + :param module: QcQuantize wrapper module + :param output_bw: Output BW + :param param_bw: Parameter BW + """ + for output_quantizer in module.output_quantizers: + output_quantizer.bitwidth = output_bw + for _, param_quantizer in module.param_quantizers.items(): + param_quantizer.bitwidth = param_bw + +
    +[docs] + def export_adapter_weights(self, sim: QuantizationSimModel, path: str, filename_prefix: str): + """ + Exports adapter weights to safetensor format + + :param sim: QuantSim model + :param path: path where to store model pth and encodings + :param filename_prefix: Prefix to use for filenames of the model pth and encodings files + """ + tensors = {} + + for module_name, module in sim.model.named_modules(): + if not isinstance(module, _QuantizedModuleProtocol): + continue + org_name = module_name + pt_name = self._get_module_name(module_name) + if self.prepared_name_to_pt_name and pt_name in self.pt_to_lora_name: + module_name = self.pt_to_lora_name[pt_name] + if module_name in self.lora_layers: + for param_name, param in module.named_parameters(): + if param_name in ['weight', 'bias']: + tensor_name = org_name + '.' + param_name + tensors[tensor_name] = param + filename_prefix = filename_prefix + '.safetensor' + model_params_path = os.path.join(path, filename_prefix) + save_file(tensors, model_params_path)
    + + +
    +[docs] + def enable_adapter_and_load_weights(self, sim: QuantizationSimModel, adapter_weights_path, + use_safetensor: bool = True): + """ + Enables adapter effect on base model by loading weights to model + + :param sim: QuantSim model + :param adapter_weights_path: Path to adapter weights (adapter weights should be either bin file or safetensor) + :param use_safetensor: True if adapter weights path point to a safetensor file. False if points to bin file + """ + tensors = _load_weights(adapter_weights_path, use_safetensor) + lora_layer_names_set = set(self.lora_layers) + onnx_names_tensors = {} + for key in tensors.keys(): + tensor_name = key + temp_key = key[0:key.find('.weight')] + if self.prepared_name_to_pt_name: + tensor_name = self.pt_name_to_prepared_name[self.lora_to_pt_name[temp_key]] + '.weight' + lora_layer_names_set.remove(temp_key) + onnx_names_tensors[tensor_name] = tensors[key] + + if lora_layer_names_set: + raise KeyError("Lora layer weights missing for the following names", lora_layer_names_set) + + sim.model.load_state_dict(onnx_names_tensors, strict=False)
    + + +
    +[docs] + def disable_lora_adapters(self, sim: QuantizationSimModel): + """ + Disables adapter (zero out weights for lora A & B) effect on base model by loading weights to model + + :param sim: QuantSim model + """ + tensors = {} + for module_name, module in sim.model.named_modules(): + org_name = module_name + pt_name = self._get_module_name(module_name) + if self.prepared_name_to_pt_name and pt_name in self.pt_to_lora_name: + module_name = self.pt_to_lora_name[pt_name] + if module_name in self.lora_layers: + for param_name, param in module.named_parameters(): + if param_name in ['weight', 'bias']: + tensor_name = org_name + '.' + param_name + tensors[tensor_name] = torch.zeros_like(param) + + sim.model.load_state_dict(tensors, strict=False)
    +
    + + + +def _load_weights(adapter_weights_path: str, use_safetensor: bool = True) -> Dict: + """ + Util to load weights + + :param adapter_weights_path: Path to adapter weights (adapter weights should be either bin file or safetensor) + :param use_safetensor: True if adapter weights path point to a safetensor file. False if points to bin file + """ + tensors = {} + if use_safetensor: + with safe_open(adapter_weights_path, framework="pt", device=0) as f: + for key in f.keys(): + tensors[key] = f.get_tensor(key) + else: + tensors = torch.load(adapter_weights_path) + + return tensors +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v1/auto_quant.html b/releases/2.0.0/_modules/aimet_torch/v1/auto_quant.html new file mode 100644 index 0000000..936a794 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v1/auto_quant.html @@ -0,0 +1,995 @@ + + + + + + + + aimet_torch.v1.auto_quant - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v1.auto_quant

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +# pylint: disable=too-many-lines, disable=protected-access
    +
    +""" Implementation of AIMET AutoQuantBase and v1 AutoQuant """
    +import copy
    +import functools
    +import itertools
    +import os
    +from unittest.mock import patch
    +from typing import Any, Callable, Dict, List, Optional, Tuple, Union
    +import torch
    +from torch.utils.data import DataLoader
    +
    +from aimet_torch import utils
    +from aimet_torch._base.auto_quant import (
    +    AutoQuantBase,
    +    _EvalManager,
    +    _QuantSchemePair,
    +    _EvalSession,
    +    cache,
    +    _MixedPrecisionArgs,
    +    _MixedPrecisionResult,
    +    ParetoFrontType,
    +)
    +from aimet_torch.v1.adaround.adaround_weight import Adaround
    +from aimet_torch._base.adaround.adaround_weight import AdaroundParameters
    +from aimet_torch.v1.quantsim import QuantizationSimModel
    +from aimet_torch.utils import get_all_quantizers
    +from aimet_torch.onnx_utils import OnnxExportApiArgs
    +from aimet_torch.amp.mixed_precision_algo import GreedyMixedPrecisionAlgo, EvalCallbackFactory, _default_forward_fn
    +
    +from aimet_common.defs import QuantScheme, CallbackFunc, QuantizationDataType
    +from aimet_common.utils import AimetLogger
    +from aimet_common.amp.utils import (
    +    create_sensitivity_plot,
    +    create_pareto_curve,
    +    CANDIDATE_WITH_DTYPE,
    +    AmpCandidate,
    +)
    +
    +
    +__all__ = [
    +    'AutoQuant',
    +    'AutoQuantWithAutoMixedPrecision',
    +]
    +
    +
    +_logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.AutoQuant)
    +
    +
    +class AutoQuant(AutoQuantBase): # pylint: disable=too-many-instance-attributes
    +    """
    +    Integrate and apply post-training quantization techniques.
    +
    +    AutoQuant includes 1) batchnorm folding, 2) cross-layer equalization,
    +    and 3) Adaround.
    +    These techniques will be applied in a best-effort manner until the model
    +    meets the evaluation goal given as allowed_accuracy_drop.
    +    """
    +
    +    @staticmethod
    +    def _get_adaround():
    +        """ returns AdaRound """
    +        return Adaround
    +
    +    @staticmethod
    +    def _get_quantsim(model, dummy_input, **kwargs):
    +        return QuantizationSimModel(model, dummy_input, **kwargs)
    +
    +    def _configure_quantsim(self, # pylint: disable=too-many-arguments
    +                            sim,
    +                            output_bw,
    +                            output_quant_scheme,
    +                            output_percentile,
    +                            param_bw,
    +                            param_quant_scheme,
    +                            param_percentile,
    +                            encoding_path):
    +
    +        param_quantizers, input_quantizers, output_quantizers = utils.get_all_quantizers(sim.model)
    +
    +        # Set input/output quantizers' quant schemes
    +        for quantizer in itertools.chain(input_quantizers, output_quantizers):
    +            quantizer.quant_scheme = output_quant_scheme
    +            if quantizer.quant_scheme == QuantScheme.post_training_percentile and\
    +                    output_percentile is not None:
    +                quantizer.set_percentile_value(output_percentile)
    +
    +        # Set param quantizers' quant schemes
    +        for quantizer in param_quantizers:
    +            quantizer.quant_scheme = param_quant_scheme
    +            if quantizer.quant_scheme == QuantScheme.post_training_percentile and\
    +                    param_percentile is not None:
    +                quantizer.set_percentile_value(param_percentile)
    +
    +        if encoding_path:
    +            sim.set_and_freeze_param_encodings(encoding_path)
    +
    +        param_quantizers, input_quantizers, output_quantizers = utils.get_all_quantizers(sim.model)
    +
    +        # Disable input/output quantizers, using fp32 to simulate int32.
    +        if output_bw == 32:
    +            for quantizer in input_quantizers + output_quantizers:
    +                quantizer.enabled = False
    +
    +        # Disable param quantizers, using fp32 to simulate int32.
    +        if param_bw == 32:
    +            for quantizer in param_quantizers:
    +                quantizer.enabled = False
    +
    +    @staticmethod
    +    def _has_enabled_quantizers(sim):
    +        param_quantizers, input_quantizers, output_quantizers = utils.get_all_quantizers(sim.model)
    +        return any(quantizer.enabled for quantizer in param_quantizers +\
    +                                                      input_quantizers +\
    +                                                      output_quantizers)
    +
    +    @staticmethod
    +    def _disable_activation_quantizers(sim):
    +        _, input_quantizers, output_quantizers = get_all_quantizers(sim.model)
    +        for quantizer in itertools.chain(input_quantizers, output_quantizers):
    +            quantizer.enabled = False
    +
    +
    +
    +# The number of samples to be used for performance evaluation and AMP.
    +# NOTE: None means "all".
    +DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_1 = EvalCallbackFactory._DEFAULT_SQNR_NUM_SAMPLES
    +DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_2 = None
    +
    +
    +
    +[docs] +class AutoQuantWithAutoMixedPrecision: + """ + Integrate and apply post-training quantization techniques. + + AutoQuant includes 1) batchnorm folding, 2) cross-layer equalization, + 3) Adaround, and 4) Automatic Mixed Precision (if enabled). + These techniques will be applied in a best-effort manner until the model + meets the evaluation goal given as allowed_accuracy_drop. + """ + def __init__( # pylint: disable=too-many-arguments, too-many-function-args + self, + model: torch.nn.Module, + dummy_input: Union[torch.Tensor, Tuple], + data_loader: DataLoader, + eval_callback: Callable[[torch.nn.Module], float], + param_bw: int = 8, + output_bw: int = 8, + quant_scheme: QuantScheme = QuantScheme.post_training_tf_enhanced, + rounding_mode: str = 'nearest', + config_file: str = None, + results_dir: str = "/tmp", + cache_id: str = None, + strict_validation: bool = True, + model_prepare_required: bool = True,) -> None: + """ + :param model: Model to be quantized. Assumes model is on the correct device + :param dummy_input: Dummy input for the model. Assumes that dummy_input is on the correct device + :param data_loader: A collection that iterates over an unlabeled dataset, used for computing encodings + :param eval_callback: Function that calculates the evaluation score + :param param_bw: Parameter bitwidth + :param output_bw: Output bitwidth + :param quant_scheme: Quantization scheme + :param rounding_mode: Rounding mode + :param config_file: Path to configuration file for model quantizers + :param results_dir: Directory to save the results of PTQ techniques + :param cache_id: ID associated with cache results + :param strict_validation: Flag set to True by default.hen False, AutoQuant will proceed with execution and handle errors internally if possible. This may produce unideal or unintuitive results. + :param model_prepare_required: Flag set to True by default.If False, AutoQuant will skip model prepare block in the pipeline. + """ + self._auto_quant_base = AutoQuant(model, + dummy_input, + data_loader, + eval_callback, + param_bw, + output_bw, + quant_scheme, + rounding_mode, + config_file, + results_dir, + cache_id, + strict_validation, + model_prepare_required) + self._data_loader = data_loader + self._amp_args = None + +
    +[docs] + def run_inference(self) -> Tuple[QuantizationSimModel, float]: + ''' + Creates a quantization model and performs inference + + :return: QuantizationSimModel, model accuracy as float + ''' + return self._auto_quant_base.run_inference()
    + + +
    +[docs] + def optimize(self, allowed_accuracy_drop: float = 0.0)\ + -> Tuple[torch.nn.Module, float, str, ParetoFrontType]: + """ + Integrate and apply post-training quantization techniques. + + :param allowed_accuracy_drop: Maximum allowed accuracy drop + :return: Tuple of (best model, eval score, encoding path, pareto front). + Pareto front is None if AMP is not enabled or AutoQuant exits + without performing AMP. + """ + html_template_file = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "auto_quant_diagnostics_template_with_amp.html", + ) + with patch.object(_EvalManager, "HTML_TEMPLATE_FILE", html_template_file): + result = self._auto_quant_base._optimize_helper(self._optimize_main, + allowed_accuracy_drop) + return result["model"],\ + result["accuracy"],\ + result["encoding_path"],\ + result["pareto_list"]
    + + +
    +[docs] + def set_adaround_params(self, adaround_params: AdaroundParameters) -> None: + """ + Set Adaround parameters. + If this method is not called explicitly by the user, AutoQuant will use + `data_loader` (passed to `__init__`) for Adaround. + + :param adaround_params: Adaround parameters. + """ + return self._auto_quant_base.set_adaround_params(adaround_params)
    + + +
    +[docs] + def set_export_params(self, + onnx_export_args: OnnxExportApiArgs = -1, + propagate_encodings: bool = None) -> None: + """ + Set parameters for QuantizationSimModel.export. + + :param onnx_export_args: optional export argument with onnx specific overrides + if not provide export via torchscript graph + :param propagate_encodings: If True, encoding entries for intermediate ops + (when one PyTorch ops results in multiple ONNX nodes) are filled with + the same BW and data_type as the output tensor for that series of ops. + """ + return self._auto_quant_base.set_export_params(onnx_export_args, propagate_encodings)
    + + +
    +[docs] + def set_mixed_precision_params( + self, + candidates: List[CANDIDATE_WITH_DTYPE], + num_samples_for_phase_1: Optional[int] = DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_1, + forward_fn: Callable = _default_forward_fn, + num_samples_for_phase_2: Optional[int] = DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_2, + ) -> None: + """ + Set mixed precision parameters. + NOTE: Automatic mixed precision will NOT be enabled unless this method + is explicitly called by the user. + + :param candidates: List of tuples of candidate bitwidths and datatypes. + :param num_samples_for_phase_1: Number of samples to be used for performance + evaluation in AMP phase 1. + :param forward_fn: Function that runs forward pass and returns the output tensor. + which will be used for SQNR compuatation in phase 1. + This function is expected to take 1) a model and 2) a single batch + yielded from the data loader, and return a single torch.Tensor object + which represents the output of the model. + The default forward function is roughly equivalent to + ``lambda model, batch: model(batch)`` + :param num_samples_for_phase_2: Number of samples to be used for performance + evaluation in AMP phase 2. + """ + if len(candidates) < 2: + raise ValueError(f"AMP requires at least two candidates. Got {len(candidates)}.") + + baseline_param_bw = self._auto_quant_base._quantsim_params["param_bw"] + baseline_output_bw = self._auto_quant_base._quantsim_params["output_bw"] + baseline_candidate = ( + (baseline_output_bw, QuantizationDataType.int), + (baseline_param_bw, QuantizationDataType.int), + ) + + if baseline_candidate not in candidates: + raise ValueError( + f"AMP candidate must contain W{baseline_param_bw}A{baseline_output_bw}, " + "which was passed to the constructor of AutoQuant as `param_bw` and `output_bw`." + ) + + for candidate in candidates: + ((output_bw, output_dtype), (param_bw, param_dtype)) = candidate + + if output_dtype != param_dtype: + raise ValueError( + "The data types of parameters and outputs should be the same. " + f"Got {output_dtype} output and {param_dtype} for parameter." + ) + + if output_dtype == QuantizationDataType.float: + continue + + # The param/output_bw passed to the constructor of AutoQuant + # must be the baseline-bitwidth candidate among all AMP candidates. + if output_bw < baseline_output_bw or param_bw < baseline_param_bw: + raise ValueError( + "All AMP candidates should be strictly superior to the baseline " + f"W{baseline_param_bw}A{baseline_output_bw}, which was passed " + "to the constructor of AutoQuant. Please make sure that all the INT candidates " + f"satisfy param_bw >= {baseline_param_bw} and output_bw >= {baseline_param_bw}." + ) + + factory = EvalCallbackFactory(self._data_loader, forward_fn=forward_fn) + sqnr_eval_callback = factory.sqnr(num_samples_for_phase_1) + + candidates = [AmpCandidate(candidate) for candidate in set(candidates)] + + self._amp_args = _MixedPrecisionArgs( + candidates=candidates, + forward_pass_callback=CallbackFunc(self._auto_quant_base.forward_pass_callback, None), + eval_callback_for_phase1=sqnr_eval_callback, + eval_callback_for_phase2=CallbackFunc(self._auto_quant_base.eval_callback, + num_samples_for_phase_2), + )
    + + +
    +[docs] + def set_model_preparer_params( + self, + modules_to_exclude: List[torch.nn.Module] = None, + concrete_args: Optional[Dict[str, Any]] = None, + ): + """ + Set parameters for model preparer. + + :param modules_to_exclude: List of modules to exclude when tracing. + :param concrete_args: Parameter for model preparer. Allows you to partially specialize + your function, whether it's to remove control flow or data structures. If the + model has control flow, torch.fx won't be able to trace the model. Check + torch.fx.symbolic_trace API in detail. + """ + return self._auto_quant_base.set_model_preparer_params(modules_to_exclude, concrete_args)
    + + +
    +[docs] + def get_quant_scheme_candidates(self) -> Tuple[_QuantSchemePair, ...]: + """ + Return the candidates for quant scheme search. + During :meth:`~AutoQuant.optimize`, the candidate with the highest accuracy + will be selected among them. + + :return: Candidates for quant scheme search + """ + return self._auto_quant_base.get_quant_scheme_candidates()
    + + +
    +[docs] + def set_quant_scheme_candidates(self, candidates: Tuple[_QuantSchemePair, ...]): + """ + Set candidates for quant scheme search. + During :meth:`~AutoQuant.optimize`, the candidate with the highest accuracy + will be selected among them. + + :param candidates: Candidates for quant scheme search + """ + return self._auto_quant_base.set_quant_scheme_candidates(candidates)
    + + + @cache.mark("mixed_precision") + def _apply_mixed_precision( + self, + model: torch.nn.Module, + dummy_input: Union[torch.Tensor, Tuple], + target_acc: float, + amp_args: _MixedPrecisionArgs, + results_dir: str, + encoding_path: str = None, + ) -> _MixedPrecisionResult: + """ + Apply mixed-precision and return the highest accuracy. + + NOTE1: Input model is not mutated. + NOTE2: Parameter `clean_start` is always set to True. + + :param model: Model to apply mixed precision. + :param dummy_input: Dummy input to the model. + :param target_acc: Minimum evaluation score required. + :param encoding_path: Path to parameter encodings file. + :param results_dir: Directory to save the results of AdaRound and mixed precision. + :return: MixedPrecisionAlgo object. + """ + if not amp_args: + raise RuntimeError + + sim = self._auto_quant_base._create_quantsim_and_encodings(model, + encoding_path=encoding_path) + + algo = GreedyMixedPrecisionAlgo( + sim, + dummy_input, + amp_args.candidates, + amp_args.eval_callback_for_phase1, + amp_args.eval_callback_for_phase2, + results_dir=results_dir, + clean_start=True, + forward_pass_callback=amp_args.forward_pass_callback + ) + + # Find baseline accuracy and bw corresponding to baseline accuracy + algo.set_baseline(fp32_accuracy=self._auto_quant_base._fp32_acc) + allowed_accuracy_drop = algo.fp32_accuracy - target_acc + + algo.run(allowed_accuracy_drop) + + sensitivity_plot = None + if algo.accuracy_list is not None: + # Visualize quantizer group sensitivity + sensitivity_plot = create_sensitivity_plot(algo.accuracy_list, + algo.baseline_candidate, + algo.fp32_accuracy) + pareto_plot = None + if algo.pareto_list is not None: + # Create pareto list curve + pareto_plot = create_pareto_curve(algo.pareto_list) + + return _MixedPrecisionResult(algo.pareto_list, + algo._sim, + algo._final_eval_score, + sensitivity_plot, + pareto_plot) + + def _optimize_main(self, fp32_model: torch.nn.Module, target_acc: float) -> Dict[str, Any]: + """ + Helper function of apply(). + + :param fp32_model: Model to apply PTQ techniques. + :param target_acc: Target eval score. + :return: The best ptq result as a dictionary. + """ + # pylint: disable=broad-except, too-many-locals, too-many-statements, too-many-branches + + if self._amp_args: + candidates = copy.copy(self._amp_args.candidates) + else: + candidates = [] + + eval_manager = self._auto_quant_base.eval_manager + dummy_input = self._auto_quant_base.dummy_input + results_dir = self._auto_quant_base.results_dir + strict_validation = eval_manager._strict_validation + + sess = eval_manager.session("") + _multiconfig_adaround_fn = _adaround_wrapper(self._auto_quant_base._apply_adaround, + self._auto_quant_base, + candidates, + target_acc, + sess.eval) + sess_eval_fn = _EvalSession.eval + def eval_fn(_, model, param_bw=None, output_bw=None, **kwargs): + if param_bw == 32: + # For W32 evaluation, use the highest output bitwidth + # among all the AMP candidates + output_bitwidths = [ + output_bw for (output_bw, output_dtype), _ in candidates + if output_dtype == QuantizationDataType.int + ] + output_bitwidths.append(self._auto_quant_base._quantsim_params["output_bw"]) + output_bw = max(output_bitwidths) + return sess_eval_fn(_, model, param_bw=param_bw, output_bw=output_bw, **kwargs) + + with patch.object(self._auto_quant_base, "_apply_adaround", _multiconfig_adaround_fn),\ + patch.object(_EvalSession, "eval", eval_fn): + try: + result = self._auto_quant_base._optimize_main(fp32_model, target_acc) + + # Automatic Mixed Precision + result["pareto_list"] = None + + # An empty `result` dict means AutoQuant early-exited + # because W32 eval score didn't meet the target accuracy. + # In this case, do not proceed to AMP and exit immediately. + if result["model"] is None and\ + result["accuracy"] is None and\ + result["encoding_path"] is None and\ + result["applied_techniques"] is None: + return result + + if result["accuracy"] >= target_acc or not self._amp_args: + return result + + if len(candidates) < 2: + _logger.info( + "After Adaround, we have only one Adarond-compatible candidate left for AMP (W%dA%d). " + "Return without proceeding to AMP", candidates[0].param_bw, candidates[0].output_bw + ) + return result + + model = result["model"] + applied_techniques = result["applied_techniques"] + # Freeze weight encoding to adaround weight encoding + encoding_path = result["encoding_path"] if "adaround" in applied_techniques else None + except Exception: + if strict_validation: + raise + result = {} + model = fp32_model + applied_techniques = [] + encoding_path = None + + amp_args = copy.copy(self._amp_args) + if amp_args: + amp_args.candidates = candidates + + with eval_manager.session("Automatic Mixed Precision", ptq=True) as sess: + amp_result = self._apply_mixed_precision( + model, dummy_input, target_acc, amp_args, results_dir, encoding_path=encoding_path + ) + result["pareto_list"] = amp_result.pareto_list + + if amp_result.sensitivity_plot is not None: + sess.diagnostics.add(amp_result.sensitivity_plot) + + if amp_result.pareto_plot is not None: + sess.diagnostics.add(amp_result.pareto_plot) + + sess.set_ptq_result(sim=amp_result.sim, acc=amp_result.final_eval_score, + applied_techniques=[*applied_techniques, "automatic_mixed_precision"]) + + best_result = eval_manager.get_best_ptq_result() + if best_result: + if "automatic_mixed_precision" not in best_result.applied_techniques: + sess.result["effective"] = False + if best_result.accuracy >= target_acc: + sess.result["target_satisfied"] = True + result.update(best_result.as_dict()) + return result + + raise RuntimeError("None of batchnorm folding, CLE, or Adaround " + "has been finished successfully.")
    + + +def _adaround_wrapper(apply_adaround_fn: Callable, + auto_quant: AutoQuantBase, + amp_candidates: List[AmpCandidate], + target_acc: float, + eval_fn: Callable): + @functools.wraps(apply_adaround_fn) + def _apply_adaround_wrapper(*args, **kwargs): # pylint: disable=too-many-locals + # If AMP candidates are empty (i.e. AMP is disabled), + # perform normal (single-round) adaround. + if not amp_candidates: + return apply_adaround_fn(*args, **kwargs) + + def apply_adaround(param_bw: int): + _logger.info("Running Adaround with W%d", param_bw) + + orig_param_bw = auto_quant._quantsim_params["param_bw"] + try: + auto_quant._quantsim_params["param_bw"] = param_bw + return apply_adaround_fn(*args, **kwargs) + finally: + auto_quant._quantsim_params["param_bw"] = orig_param_bw + + int_candidates = [ + candidate for candidate in amp_candidates + if candidate.param_dtype == QuantizationDataType.int + ] + sorted_int_candidates = sorted(int_candidates, + key=lambda candidate: (candidate.param_bw, candidate.output_bw)) + # Run Adaround with the lowest-bitwidth candidate + lowest_candidate = sorted_int_candidates[0] + model, encoding_path = apply_adaround(param_bw=lowest_candidate.param_bw) + + # If the lowest candidate is the only INT candidate, return immediately + if len(sorted_int_candidates) == 1: + return model, encoding_path + + eval_score = eval_fn(model, + param_bw=lowest_candidate.param_bw, + output_bw=lowest_candidate.output_bw, + encoding_path=encoding_path) + _logger.info("W%dA%d eval score after Adaround: %f", + lowest_candidate.param_bw, + lowest_candidate.output_bw, + eval_score) + + # If the lowest candidate satisfy the target accuracy, return immediately + if eval_score >= target_acc: + return model, encoding_path + + # If the lowest candidate fails to meet the target accuracy, + # discard the lowest candidate, apply Adaround to the second-lowest candidate, + # and use it as the baseline for AMP. + second_lowest_candidate = sorted_int_candidates[1] + + if second_lowest_candidate.param_bw != lowest_candidate.param_bw: + model = None + model, encoding_path = apply_adaround(param_bw=second_lowest_candidate.param_bw) + eval_score = eval_fn(model, + param_bw=second_lowest_candidate.param_bw, + output_bw=second_lowest_candidate.output_bw, + encoding_path=encoding_path) + _logger.info("W%dA%d eval score after Adaround: %f", + second_lowest_candidate.param_bw, + second_lowest_candidate.output_bw, + eval_score) + + # Only the candidates that are compatible with adaround can be used for AMP + adaround_compatible_amp_candidates = [ + candidate for candidate in amp_candidates + if candidate.param_bw == second_lowest_candidate.param_bw or\ + candidate.param_dtype == QuantizationDataType.float + ] + + # Fill in AMP candidates with Adaround-compatible candidates only + amp_candidates.clear() + amp_candidates.extend(adaround_compatible_amp_candidates) + + return model, encoding_path + + return _apply_adaround_wrapper +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v1/quant_analyzer.html b/releases/2.0.0/_modules/aimet_torch/v1/quant_analyzer.html new file mode 100644 index 0000000..54980ee --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v1/quant_analyzer.html @@ -0,0 +1,488 @@ + + + + + + + + aimet_torch.v1.quant_analyzer - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v1.quant_analyzer

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Quant Analyzer """
    +
    +import os
    +import contextlib
    +from typing import Tuple, List, Type, Generator
    +
    +from aimet_common.quant_analyzer import export_stats_histogram_plot
    +from aimet_common.utils import AimetLogger
    +from aimet_torch import utils
    +from aimet_torch._base.quant_analyzer import QuantAnalyzerBase
    +from aimet_torch.v1.tensor_quantizer import TensorQuantizer, StaticGridTensorQuantizer
    +from aimet_torch.v1.qc_quantize_op import QcQuantizeWrapper
    +from aimet_torch.v1.qc_quantize_recurrent import QcQuantizeRecurrent
    +from aimet_torch.v1.quantsim import QuantizationSimModel
    +from aimet_torch.v1.batch_norm_fold import fold_all_batch_norms
    +
    +_logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.QuantAnalyzer)
    +
    +DEFAULT_BOKEH_FIGURE_HEIGHT = 300
    +
    +
    +
    +[docs] +class QuantAnalyzer(QuantAnalyzerBase): + """ + QuantAnalyzer tool provides + + 1) model sensitivity to weight and activation quantization + 2) per layer sensitivity analysis + 3) per layer encoding (min - max range) + 4) per PDF analysis and + 5) per layer MSE analysis + """ + + @staticmethod + def _enable_disable_quantizers(quantizers: List[TensorQuantizer], enabled: bool): + """ + For given list of quantizers, set (enable/disable) quantizer's enabled. + + :param quantizers: List of quantizers. + :param enabled: Enabled flag. + """ + for quantizer in quantizers: + quantizer.enabled = enabled + + # pylint: disable=no-self-use + def _create_and_export_stats_histogram_plot(self, + quantizer: StaticGridTensorQuantizer, + results_dir: str, + title: str, + ): + """ + For given quantizer, create and export histogram (PDF) of statistics in html format. + + :param quantizer: Quantizer. + :param results_dir: Directory to save the results. + :param title: Title of the plot. + """ + os.makedirs(results_dir, exist_ok=True) + + histograms = quantizer.get_stats_histogram() + encodings = quantizer.encoding + if not isinstance(encodings, List): + encodings = [encodings] + + for index, (histogram, encoding) in enumerate(zip(histograms, encodings)): + export_stats_histogram_plot(histogram, encoding, results_dir, title=f"{title}_{index}") + + @staticmethod + def patch_quantsim_to_store_histogram(_): + """ + Placeholder function to prevent patching v1 quantsim + """ + + @staticmethod + def _get_quantsim_cls() -> Type[QuantizationSimModel]: + return QuantizationSimModel + + @staticmethod + def _get_quant_wrapper_type() -> Tuple[Type]: + return (QcQuantizeWrapper, QcQuantizeRecurrent) + + @staticmethod + def _is_quantizer_enabled(quantizer: TensorQuantizer): + return quantizer.enabled + + @staticmethod + def _get_quantizer_encodings(quantizer: TensorQuantizer): + if quantizer.encoding and not isinstance(quantizer.encoding, List): + return [quantizer.encoding] + return quantizer.encoding + + @classmethod + @contextlib.contextmanager + def _disable_param_quantizers(cls, sim: QuantizationSimModel): + enabled_param_quantizers = cls._get_enabled_param_quantizers(sim) + cls._enable_disable_quantizers(enabled_param_quantizers, enabled=False) + yield + cls._enable_disable_quantizers(enabled_param_quantizers, enabled=True) + + @classmethod + @contextlib.contextmanager + def _disable_activation_quantizers(cls, sim: QuantizationSimModel): + enabled_activation_quantizers = cls._get_enabled_activation_quantizers(sim) + cls._enable_disable_quantizers(enabled_activation_quantizers, enabled=False) + yield + cls._enable_disable_quantizers(enabled_activation_quantizers, enabled=True) + + @staticmethod + def _disable_quant_wrapper(module: QcQuantizeWrapper): + return utils.disable_all_quantizers(module) + + @staticmethod + def _get_quantized_modules(sim: QuantizationSimModel) -> Generator[QcQuantizeWrapper, None, None]: + for module in sim.model.modules(): + if isinstance(module, (QcQuantizeWrapper, QcQuantizeRecurrent)): + yield module + + @staticmethod + def _fold_all_batch_norms(*args, **kwargs): + return fold_all_batch_norms(*args, **kwargs)
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v1/quantsim.html b/releases/2.0.0/_modules/aimet_torch/v1/quantsim.html new file mode 100644 index 0000000..d3eedcf --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v1/quantsim.html @@ -0,0 +1,1049 @@ + + + + + + + + aimet_torch.v1.quantsim - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v1.quantsim

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2019-2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Implementation for simulating models running on Quantized hardware """
    +import contextlib
    +import os
    +import io
    +import copy
    +from typing import Tuple, List, Union, Dict, Callable, Optional, Any
    +import torch
    +
    +from aimet_common.utils import AimetLogger
    +from aimet_common.defs import QuantScheme, QuantizationDataType
    +from aimet_common.utils import deprecated
    +
    +from aimet_torch.v1.qc_quantize_op import QcQuantizeStandAloneBase, QcQuantizeWrapper, QcQuantizeOpMode, \
    +    StaticGridQuantWrapper, LearnedGridQuantWrapper, NativeTorchQuantWrapper
    +from aimet_torch.v1.tensor_quantizer import initialize_learned_grid_quantizer_attributes
    +from aimet_torch.v1.qc_quantize_op import get_encoding_by_quantizer as _get_encoding_by_quantizer
    +from aimet_torch import utils
    +from aimet_torch.v1.utils import create_encoding_dict
    +from aimet_torch.onnx_utils import OnnxSaver, OnnxExportApiArgs
    +from aimet_torch.v1.qc_quantize_recurrent import QcQuantizeRecurrent
    +from aimet_torch.quantsim_config.builder import LazyQuantizeWrapper
    +from aimet_torch.v1._builder import _V1LazyQuantizeWrapper
    +from aimet_torch._base.quantsim import (
    +    _QuantizationSimModelBase,
    +    _QuantizedModuleProtocol,
    +    unquantizable_modules,
    +    QuantParams,
    +    ExportableQuantModule,
    +    save_checkpoint,
    +    load_checkpoint,
    +    check_accumulator_overflow,
    +)
    +
    +__all__ = [
    +    'QuantizationSimModel',
    +    'QuantParams',
    +    'ExportableQuantModule',
    +    'save_checkpoint',
    +    'load_checkpoint',
    +    'check_accumulator_overflow',
    +    'load_encodings_to_sim',
    +    'compute_encodings_for_sims',
    +]
    +
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.Quant)
    +
    +# If a torch module type is in this dictionary, call the corresponding quantized module constructor instead of wrapping
    +# it with QcQuantizeWrapper.
    +qc_quantize_modules_dict = {
    +    torch.nn.RNN: QcQuantizeRecurrent,
    +    torch.nn.LSTM: QcQuantizeRecurrent,
    +    torch.nn.GRU: QcQuantizeRecurrent
    +}
    +
    +
    +# Types of modules which cannot be quantized
    +quantized_modules = (
    +    QcQuantizeWrapper,
    +    QcQuantizeStandAloneBase,
    +    QcQuantizeRecurrent,
    +    _QuantizedModuleProtocol,
    +    LazyQuantizeWrapper,
    +)
    +
    +
    +
    +[docs] +class QuantizationSimModel(_QuantizationSimModelBase): + """ + Implements mechanism to add quantization simulations ops to a model. This allows for off-target simulation of + inference accuracy. Also allows the model to be fine-tuned to counter the effects of quantization. + """ + # pylint: disable=too-many-arguments, too-many-locals, too-many-public-methods + _quantized_modules = quantized_modules + + def _realize_quant_wrappers_in_model(self, model: torch.nn.Module): + """ + Prepare QuantSim for compute encodings. Resets encodings for each quantizable layer and sets mode to Analysis. + Realize quant wrappers using collected information in LazyQuantWrapper. + + :param model: model containing modules wrapped with LazyQuantWrapper + """ + for module_name, module_ref in model.named_children(): + if isinstance(module_ref, LazyQuantizeWrapper): + quantized_module = module_ref.realize() + setattr(model, module_name, quantized_module) + + elif not utils.is_leaf_module(module_ref): + self._realize_quant_wrappers_in_model(module_ref) + + def __str__(self): + """ + Pretty-printed output indicating where in the model, quantizers have been activated + :return: + """ + + def print_quantizer_state(stream, quantizer, prefix_string): + if quantizer.enabled: + stream.write(f' {prefix_string}: bw={quantizer.bitwidth}, ' + f'encoding-present={bool(quantizer.encoding)}\n') + + if quantizer.encoding: + stream.write(f' {quantizer}') + else: + stream.write(f' {prefix_string}: Not quantized\n') + + stream.write(' -------\n') + + stream = io.StringIO(newline='\n') + stream.write("-------------------------\n") + stream.write("Quantized Model Report\n") + stream.write("-------------------------\n") + + for layer_name, layer in self._get_qc_quantized_layers(self.model): + stream.write('----------------------------------------------------------\n') + stream.write('Layer: {}\n'.format(layer_name)) + + # Inputs + if isinstance(layer.input_quantizers, dict): + for name, quantizer in layer.input_quantizers.items(): + print_quantizer_state(stream, quantizer, prefix_string=f"Input[{name}]") + else: + for index, quantizer in enumerate(layer.input_quantizers): + print_quantizer_state(stream, quantizer, prefix_string=f"Input[{index}]") + + # Params + for param_name, quantizer in layer.param_quantizers.items(): + print_quantizer_state(stream, quantizer, prefix_string=f"Param[{param_name}]") + + # Outputs + if isinstance(layer.output_quantizers, dict): + for name, quantizer in layer.output_quantizers.items(): + print_quantizer_state(stream, quantizer, prefix_string=f"Output[{name}]") + else: + for index, quantizer in enumerate(layer.output_quantizers): + print_quantizer_state(stream, quantizer, prefix_string=f"Output[{index}]") + + return stream.getvalue() + + @staticmethod + def prepare_sim_for_compute_encodings(sim: 'QuantizationSimModel'): + """ + Prepare QuantSim for compute encodings. Resets encodings for each quantizable layer and sets mode to Analysis. + + :param sim: QuantSim to prepare + """ + # pylint: disable=protected-access + quantized_layers = sim._get_qc_quantized_layers(sim.model) + + for _, layer in quantized_layers: + # Clear stats and encodings if they are present + layer.reset_encodings() + + # And set the mode to analysis + layer.set_mode(QcQuantizeOpMode.ANALYSIS) + + for _, layer in quantized_layers: + # call only when quant scheme is percentile + if sim._quant_scheme == QuantScheme.post_training_percentile: + layer.set_percentile_value(sim._percentile_value) + + @staticmethod + def compute_layer_encodings_for_sim(sim: 'QuantizationSimModel'): + """ + Compute encodings for each quantizable layer in sim after forward pass has been called. + + :param sim: QuantSim to compute encodings for + """ + # pylint: disable=protected-access + quantized_layers = sim._get_qc_quantized_layers(sim.model) + # Get the computed per-layer encodings and log them + for name, layer in quantized_layers: + layer.compute_encoding() + + # Before we return we set the mode to active - meaning ready for quantize/de-quantize + # for layers with valid_encoding, otherwise we set to pass through + if isinstance(layer, QcQuantizeRecurrent): + sim.set_mode_for_recurrent_module(layer, name) + else: + # By default we want to set the Quantization wrappers to ACTIVE mode + layer.set_mode(QcQuantizeOpMode.ACTIVE) + + sim.replace_wrappers_for_quantize_dequantize() + +
    +[docs] + def compute_encodings(self, forward_pass_callback, forward_pass_callback_args): # pylint: disable=arguments-differ + """ + Computes encodings for all quantization sim nodes in the model. It is also used to find initial encodings for + Range Learning + + :param forward_pass_callback: A callback function that simply runs forward passes on the model. This callback + function should use representative data for the forward pass, so the calculated encodings work for all + data samples. This callback internally chooses the number of data samples it wants to use for calculating + encodings. + :param forward_pass_callback_args: These argument(s) are passed to the forward_pass_callback as-is. Up to + the user to determine the type of this parameter. E.g. could be simply an integer representing the number + of data samples to use. Or could be a tuple of parameters or an object representing something more complex. + If set to None, forward_pass_callback will be invoked with no parameters. + :return: None + + """ + + QuantizationSimModel.prepare_sim_for_compute_encodings(self) + + # Run forward iterations so we can collect statistics to compute the appropriate encodings + with utils.in_eval_mode(self.model), torch.no_grad(): + _ = forward_pass_callback(self.model, forward_pass_callback_args) + + QuantizationSimModel.compute_layer_encodings_for_sim(self)
    + + + @classmethod + def set_mode_for_recurrent_module(cls, layer: QcQuantizeRecurrent, name: str): + """ + Sets Recurrent module to active or pass through mode based on quantizer state + + :param layer: Qc Quantizer layer for recurrent module + :param name: layer name + :return: True if the encoding is invalid + + """ + for quantizer_name, output_quantizer in layer.output_quantizers.items(): + if output_quantizer.enabled: + if output_quantizer.encoding: + encoding = output_quantizer.encoding + logger.debug("Encoding for %s-%s: min=%f, max=%f, offset=%f. delta=%f, bw=%f", + name, quantizer_name, encoding.min, encoding.max, + encoding.delta, encoding.offset, encoding.bw) + + for quantizer_name, input_quantizer in layer.input_quantizers.items(): + if input_quantizer.enabled: + if input_quantizer.encoding: + encoding = input_quantizer.encoding + logger.debug("Encoding for %s-%s: min=%f, max=%f, offset=%f. delta=%f, bw=%f", + name, quantizer_name, encoding.min, encoding.max, + encoding.delta, encoding.offset, encoding.bw) + + layer.set_mode(QcQuantizeOpMode.ACTIVE) + + def set_percentile_value(self, percentile_value: float): + """ + Set the percentile value to be used while computing encodings + """ + if percentile_value < 90 or percentile_value > 100: + raise ValueError("Percentile value must be in range [90, 100]") + self._percentile_value = percentile_value + + def _replace_quantization_wrapper(self, model, device): + """ + Recursively remove quantization wrappers from all appropriate modules starting with a given module + :param model: model for which PostTrainingWrapper gets replaced with Trainable wrapped module + :param device: device on which model is present + :return: None + """ + for module_name, module_ref in model.named_children(): + + if isinstance(module_ref, StaticGridQuantWrapper): + # Create a Trainable wrapper and copy properties of PostTrainingWrapper to the Trainable wrapper + quantized_module = self._construct_and_initialize_trainable_wrapper(module_ref, device) + setattr(model, module_name, quantized_module) + + elif isinstance(module_ref, QcQuantizeRecurrent): + # Set Recurrent layer for training mode + module_ref.construct_and_initialize_trainable_quantizers(self._quant_scheme) + + # Recursively call children modules if present + if not utils.is_leaf_module(module_ref): + self._replace_quantization_wrapper(module_ref, device) + + def _construct_and_initialize_trainable_wrapper(self, post_training_module: StaticGridQuantWrapper, + device: torch.device) -> LearnedGridQuantWrapper: + """ + Copies following tensor quantizer attributes from StaticGridQuantWrapper to LearnedGridQuantWrapper + to avoid any mismatch. + - enabled + - bitwidth + - encoding + - use_symmetric_encodings + - use_strict_symmetric + - use_unsigned_symmetric + + :param post_training_module: StaticGridQuantWrapper wrapped module + :param device: device on which model is present + :return: trainable_module: QcTrainable wrapper module + """ + + # pylint: disable=protected-access + module = post_training_module._module_to_wrap + + num_inputs = len(post_training_module.input_quantizers) + num_outputs = len(post_training_module.output_quantizers) + + # Creating a LearnedGridQuantWrapper module + trainable_module = LearnedGridQuantWrapper(module, self._default_param_bw, + self._default_output_bw, self._rounding_mode, self._quant_scheme, + device=device, num_inputs=num_inputs, num_outputs=num_outputs, + data_type=QuantizationDataType.int) + # Copy user settable attributes for outputs + for index, quantizer in enumerate(post_training_module.output_quantizers): + initialize_learned_grid_quantizer_attributes(trainable_module.output_quantizers[index], quantizer) + if trainable_module.output_quantizers[index].encoding_min_max_fixed_vals is not None: + trainable_module.output_quantizers[index].freeze_encoding() + # Copy user settable attributes for inputs + for index, quantizer in enumerate(post_training_module.input_quantizers): + initialize_learned_grid_quantizer_attributes(trainable_module.input_quantizers[index], quantizer) + if trainable_module.input_quantizers[index].encoding_min_max_fixed_vals is not None: + trainable_module.input_quantizers[index].freeze_encoding() + # Copy user settable attributes for params + for name, quantizer in post_training_module.param_quantizers.items(): + learned_grid_quantizer = trainable_module.param_quantizers[name] + initialize_learned_grid_quantizer_attributes(learned_grid_quantizer, quantizer) + if learned_grid_quantizer.encoding_min_max_fixed_vals is not None: + learned_grid_quantizer.freeze_encoding() + + return trainable_module + + def replace_wrappers_for_quantize_dequantize(self): + """ + Replaces StaticGridWrapper with LearnedGridWrapper + """ + if self._quant_scheme == QuantScheme.training_range_learning_with_tf_init or self._quant_scheme == \ + QuantScheme.training_range_learning_with_tf_enhanced_init: + try: + device = utils.get_device(self.model) + except StopIteration: + # Model doesn't have any parameter. + # Set device to cpu by default. + device = torch.device('cpu') + + self._replace_quantization_wrapper(self.model, device) + + def _create_quantizer_module(self, module_to_quantize: torch.nn.Module, num_inout_tensors: Dict, + data_type: QuantizationDataType) -> torch.nn.Module: + """Instantiates wrapper based on quant scheme + """ + assert self._quant_scheme in [QuantScheme.post_training_tf, QuantScheme.post_training_tf_enhanced, + QuantScheme.training_range_learning_with_tf_enhanced_init, + QuantScheme.training_range_learning_with_tf_init, + QuantScheme.post_training_percentile] + + # We lookup the number of input and output tensors already determined + # Special case, we are adding a wrapper for a module not in the forward pass: Use default of 1, 1 + num_in_tensors, num_out_tensors = num_inout_tensors.get(module_to_quantize, (1, 1)) + + # Set quantizer to be a module replacer if it is in qc_quantize_modules_dict, otherwise set as + # StaticGridQuantWrapper. + quantizer_wrapper_type = qc_quantize_modules_dict.get(type(module_to_quantize), _V1LazyQuantizeWrapper) + + if issubclass(quantizer_wrapper_type, LazyQuantizeWrapper): + quant_scheme_for_initialization = self._quant_scheme + else: + quant_scheme_for_initialization = utils.get_v1_quant_scheme_for_initialization(self._quant_scheme) + + # TODO add quant_scheme_for_initialization for FP8 case + quantized_module = quantizer_wrapper_type(module_to_quantize, self._default_param_bw, self._default_output_bw, + self._rounding_mode, quant_scheme_for_initialization, num_inputs=num_in_tensors, + num_outputs=num_out_tensors, data_type=data_type) + + return quantized_module + + @classmethod + def _is_quantizable_module(cls, module: torch.nn.Module): + # pylint: disable=unidiomatic-typecheck + return type(module) != torch.nn.Module and\ + not isinstance(module, unquantizable_modules) and\ + not cls._is_quantized_module(module) + + @classmethod + def _is_quantized_module(cls, module: torch.nn.Module): + return isinstance(module, quantized_modules) + + def _add_quantization_wrappers(self, module, num_inout_tensors, default_data_type: QuantizationDataType): + """Recursively add quantization wrappers to all appropriate modules starting with module + """ + if self._is_quantized_module(module): + return + + for module_name, module_ref in module.named_children(): + logger.debug("nn.Module found : %s", module_ref) + + if self._is_quantizable_module(module_ref) and utils.is_leaf_module(module_ref): + # Create a new QcQuantize wrapper module + quantized_module = self._create_quantizer_module(module_ref, num_inout_tensors, default_data_type) + setattr(module, module_name, quantized_module) + else: + self._add_quantization_wrappers(module_ref, num_inout_tensors, default_data_type) + + # pylint: disable=too-many-arguments + @classmethod + def _update_encoding_dicts_for_layer(cls, layer: _QuantizedModuleProtocol, layer_name: str, activation_encodings_onnx: Dict, + activation_encodings_torch: Dict, param_encodings: Dict, + op_to_io_tensor_map: Dict, valid_param_set: set, propagate_encodings: bool, + tensor_to_consumer_map: Dict[str, str], + layers_to_onnx_op_names: Dict[str, str], + tensor_to_quantizer_map: Dict): + """ + Add given layer param and activation encodings to respective dictionaries to be used for exporting encodings + :param layer: layer as torch.nn.Module + :param layer_name: Name of the layer + :param activation_encodings_onnx: dictionary of activation encodings which maps onnx attribute to encodings + :param activation_encodings_torch: dictionary of activation encodings which maps pytorch names to encodings + :param param_encodings: dictionary of param encodings + :param op_to_io_tensor_map: ONNX or Torch Script map of layer name to it's input/output tensors + :param valid_param_set: a set of valid param input names in model + :param propagate_encodings: If True, encoding entries for intermediate ops (when one PyTorch ops results in + multiple ONNX nodes) are filled with the same BW and data_type as the output tensor for that series of + ops. + :param tensor_to_consumer_map: Dictionary mapping tensor names to op names which consume the tensor + :param layers_to_onnx_op_names: Dictionary mapping PyTorch layer names to names of corresponding ONNX ops + """ + if isinstance(layer, QcQuantizeRecurrent): + # Update encodings for Recurrent layers + QuantizationSimModel._update_encoding_dict_for_recurrent_layers(layer, layer_name, op_to_io_tensor_map, + activation_encodings_onnx, + param_encodings, propagate_encodings, + tensor_to_quantizer_map) + else: + super()._update_encoding_dicts_for_layer(layer, layer_name, activation_encodings_onnx, + activation_encodings_torch, + param_encodings, op_to_io_tensor_map, + valid_param_set, propagate_encodings, + tensor_to_consumer_map, layers_to_onnx_op_names, + tensor_to_quantizer_map) + + @staticmethod + def _update_encoding_dict_for_recurrent_layers(layer: torch.nn.Module, layer_name: str, op_to_io_tensor_map: Dict, + activation_encodings_onnx: Dict, param_encodings: Dict, + propagate_encodings: bool, tensor_to_quantizer_map: Dict): + """ + + :param layer: + :param layer_name: + :param op_to_io_tensor_map: + :param activation_encodings_onnx: + :param param_encodings: + :param propagate_encodings: + :return: + """ + + # pylint: disable=too-many-nested-blocks + # pylint: disable=too-many-locals + + onnx_activations_to_quantizers, onnx_params_to_quantizers = \ + layer.get_activation_param_quantizers_for_onnx_tensors(op_to_io_tensor_map[layer_name + + '#root_node']) + # ------------------ + # Activations + # ------------------ + quantizer = None + for tensor, quantizer in onnx_activations_to_quantizers.items(): + quantizer_encoding = _get_encoding_by_quantizer(quantizer) + encoding = create_encoding_dict(quantizer_encoding, quantizer, propagate_encodings=False) + activation_encodings_onnx[tensor] = [encoding] + tensor_to_quantizer_map[tensor] = quantizer + + if propagate_encodings and quantizer: + _, op_names = QuantizationSimModel.find_op_names_for_layer(layer_name, op_to_io_tensor_map, None, None) + for op_name in op_names: + io_tensor_list = op_to_io_tensor_map[op_name] + if not isinstance(io_tensor_list, list): + io_tensor_list = [io_tensor_list] + + for io_tensors in io_tensor_list: + + if io_tensors.outputs: + for output_tensor in io_tensors.outputs: + if output_tensor in onnx_activations_to_quantizers: + continue + quantizer_encoding = _get_encoding_by_quantizer(quantizer) + encoding = create_encoding_dict(quantizer_encoding, quantizer, True) + + activation_encodings_onnx[output_tensor] = [encoding] + tensor_to_quantizer_map[output_tensor] = quantizer + + # ------------------ + # Params + # ------------------ + for tensor, quantizer in onnx_params_to_quantizers.items(): + quantizer_encoding = _get_encoding_by_quantizer(quantizer) + encoding = create_encoding_dict(quantizer_encoding, quantizer, propagate_encodings=False) + param_encodings[tensor] = [encoding] + tensor_to_quantizer_map[tensor] = quantizer + + @staticmethod + def _get_qc_quantized_layers(model) -> List[Tuple[str, QcQuantizeWrapper]]: + quantized_layers = [] + for name, module in model.named_modules(): + if isinstance(module, (QcQuantizeRecurrent, LazyQuantizeWrapper, _QuantizedModuleProtocol)): + quantized_layers.append((name, module)) + return quantized_layers + + @classmethod + def _remove_quantization_wrappers(cls, starting_module, list_of_modules_to_exclude): + """ + Recursively remove quantization wrappers from all appropriate modules starting with a given module + :param starting_module: Module to recursive search downstream from + :param list_of_modules_to_exclude: List of torch modules to remove quantization wrappers from (if present) + :return: None + """ + for module_name, module_ref in starting_module.named_children(): + + # If modules is in the exclude list, remove the wrapper + if module_ref in list_of_modules_to_exclude: + if isinstance(module_ref, (_QuantizedModuleProtocol, QcQuantizeRecurrent)): + orig_module = module_ref.get_original_module() + elif isinstance(module_ref, QcQuantizeStandAloneBase): + orig_module = torch.nn.Identity() + else: + orig_module = None + + if orig_module: + setattr(starting_module, module_name, orig_module) + module_ref = orig_module + + # Recursively call children modules if present + if not utils.is_leaf_module(module_ref): + cls._remove_quantization_wrappers(module_ref, list_of_modules_to_exclude) + + @classmethod + @torch.no_grad() + def _apply_qdq_to_model_parameters(cls, model: torch.nn.Module): + """ + Applies quant-dequant to the parameters of a PyTorch model + to avoid rounding error during weight quantization. + + :param model: The PyTorch model whose parameters will be quant-dequantized. + """ + # pylint: disable=protected-access + for module in model.modules(): + if isinstance(module, (QcQuantizeRecurrent, StaticGridQuantWrapper)): + with utils.in_eval_mode(module): + module._quantize_dequantize_params() + elif isinstance(module, (LearnedGridQuantWrapper)): + with utils.in_eval_mode(module): + module._quantize_params() + cls._update_parameters_by_attr(module._module_to_wrap) + + def named_qmodules(self): + """Generator that yields all quantized modules in the model and their names + """ + for name, module in self.model.named_modules(): + if isinstance(module, (QcQuantizeWrapper, QcQuantizeRecurrent, LazyQuantizeWrapper)): + yield name, module + + quant_wrappers = named_qmodules + + @staticmethod + def _replace_quantization_wrapper_with_native_torch_quantization_nodes(quant_sim_model, device: torch.device): + """ + Recursively remove quantization wrappers from all appropriate modules starting with a given module + :param quant_sim_model: model for which QcQuantizeWrapper gets replaced with wrapped module using + native torch quantization nodes + :param device: device on which model is present + :return: + """ + # Recursively replace quantization wrappers to native torch quantization nodes + for module_name, module_ref in quant_sim_model.named_children(): + # Create a native torch quantization node + if isinstance(module_ref, QcQuantizeWrapper): + embedded_module = NativeTorchQuantWrapper(module_ref, '_module_to_wrap', device) + setattr(quant_sim_model, module_name, embedded_module) + + elif isinstance(module_ref, QcQuantizeRecurrent): + logger.error('Do not support save model embedded native torch quantization nodes using QcQuantizeRecurrent.') + raise AssertionError + + # Recursively call children modules if present + if not utils.is_leaf_module(module_ref): + QuantizationSimModel._replace_quantization_wrapper_with_native_torch_quantization_nodes(module_ref, device) + + @classmethod + def save_model_with_embedded_quantization_nodes(cls, sim_model, path: str, filename_prefix: str, dummy_input: Union[torch.Tensor, Tuple], + onnx_export_args: Optional[Union[OnnxExportApiArgs, Dict]] = None, + export_to_torchscript: bool = False, is_conditional: bool = False): + """ + Export model embedded with native torch quantization nodes. These nodes will be exported + as default onnx or torch script quantized nodes. + :param sim_model: model with the quantsim wrappers + :param path: path where to store model pth and encodings + :param filename_prefix: Prefix to use for filenames of the model pth and encodings files + :param dummy_input: Dummy input to the model. Used to parse model graph + :param onnx_export_args: optional export argument with onnx specific overrides if not provide export via + torchscript graph. Int16 can only be exported by torchscript + :param export_to_torchscript: If True, export to torchscript. Export to onnx otherwise. Defaults to False. + :param is_conditional: True if model is conditional, False otherwise + :return: + """ + def _validate_torchquantizer(quant_sim_model): + # To avoid non 8 bit TorchQuantizer are exported to ONNX + for _, module in quant_sim_model.named_modules(): + if isinstance(module, NativeTorchQuantWrapper): + quantizers = module.input_quantizers + module.output_quantizers + if 'weight' in module.param_quantizers: + quantizers += [module.param_quantizers['weight']] + if 'bias' in module.param_quantizers: + quantizers += [module.param_quantizers['bias']] + + for quantizer in quantizers: + if quantizer.enabled and quantizer.data_type == QuantizationDataType.int and quantizer.bitwidth != 8: + raise ValueError('Only 8 bit quantizers are supported by exporting to ONNX model.' + 'Please enable export_to_torchscript if you want to export non 8 bit quantizers.') + + model_filename = filename_prefix + '_embedded' + '.onnx' + model_path = os.path.join(path, model_filename) + quant_sim_model = copy.deepcopy(sim_model) + + device = utils.get_device(quant_sim_model) + if isinstance(dummy_input, torch.Tensor): + dummy_input = dummy_input.to(device) + else: + dummy_input = tuple([input.to(device) for input in dummy_input]) # pylint: disable=consider-using-generator + QuantizationSimModel._replace_quantization_wrapper_with_native_torch_quantization_nodes(quant_sim_model, device) + + if export_to_torchscript: + with utils.in_eval_mode(quant_sim_model), torch.no_grad(): + trace = torch.jit.trace(quant_sim_model, dummy_input) + ts_path = os.path.join(path, filename_prefix + '_embedded' + '.torchscript.pth') + trace.save(ts_path) + else: + _validate_torchquantizer(quant_sim_model) + OnnxSaver._export_model_to_onnx(quant_sim_model, dummy_input, model_path, is_conditional, onnx_export_args) # pylint: disable=protected-access
    + + + + +@deprecated("Use QuantizationSimModel.load_encodings instead.") +def load_encodings_to_sim(quant_sim_model: _QuantizationSimModelBase, pytorch_encoding_path: str): + """ + Loads the saved encodings to quant sim model. The encoding filename to load should end in _torch.encodings, + generated as part of quantsim export. + + :param quant_sim_model: Quantized model to load encodings for. Note: The model configuration should be the same as + when encodings were exported. + :param pytorch_encoding_path: Path of the encodings file to load. + """ + for module in quant_sim_model.model.modules(): + if isinstance(module, QcQuantizeWrapper): + module.set_mode(QcQuantizeOpMode.ACTIVE) + + quant_sim_model.load_encodings(pytorch_encoding_path, + strict=True, + partial=False, + requires_grad=None, + allow_overwrite=None) + + if isinstance(quant_sim_model, QuantizationSimModel): + # Only for V1 quantsim + quant_sim_model.replace_wrappers_for_quantize_dequantize() + + +def compute_encodings_for_sims(sim_list: List[QuantizationSimModel], forward_pass_callback: Callable, + forward_pass_callback_args: Any): + """ + Compute encodings for a list of QuantSims. + + :param sim_list: List of QuantSims to compute encodings for. + :param forward_pass_callback: A callback function that simply runs forward passes on the models. This callback + function should use representative data for the forward pass, so the calculated encodings work for all + data samples. This callback internally chooses the number of data samples it wants to use for calculating + encodings. + The callback expects exactly two inputs: + - List of models which are involved in the forward pass. The models are taken directly from calling + sim.model for each sim in sim_list, passed in the same order in which the sims appear in sim_list. + - Forward pass callback args + :param forward_pass_callback_args: These argument(s) are passed to the forward_pass_callback as-is. Up to + the user to determine the type of this parameter. E.g. could be simply an integer representing the number + of data samples to use. Or could be a tuple of parameters or an object representing something more complex. + If set to None, forward_pass_callback will be invoked with no parameters. + """ + ctx_managers = [torch.no_grad()] + for sim in sim_list: + ctx_managers.append(utils.in_eval_mode(sim.model)) + QuantizationSimModel.prepare_sim_for_compute_encodings(sim) + + with contextlib.ExitStack() as stack: + for mgr in ctx_managers: + stack.enter_context(mgr) + _ = forward_pass_callback([sim.model for sim in sim_list], forward_pass_callback_args) + + for sim in sim_list: + QuantizationSimModel.compute_layer_encodings_for_sim(sim) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v2/auto_quant.html b/releases/2.0.0/_modules/aimet_torch/v2/auto_quant.html new file mode 100644 index 0000000..29259cf --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v2/auto_quant.html @@ -0,0 +1,1035 @@ + + + + + + + + aimet_torch.v2.auto_quant - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v2.auto_quant

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +# pylint: disable=too-many-lines, disable=protected-access
    +""" Concrete implementation for AIMET AutoQuant using v2 QuantSim """
    +
    +import functools
    +import itertools
    +import copy
    +import os
    +from unittest.mock import patch
    +from typing import Any, Callable, Dict, List, Optional, Tuple, Union
    +import torch
    +from torch.utils.data import DataLoader
    +
    +import aimet_torch.v2.quantization as Q
    +from aimet_torch._base.auto_quant import (
    +    AutoQuantBase,
    +    _EvalManager,
    +    _QuantSchemePair,
    +    _EvalSession,
    +    _MixedPrecisionArgs,
    +    _MixedPrecisionResult,
    +    _logger,
    +    ParetoFrontType,
    +)
    +from aimet_torch._base.adaround.adaround_weight import AdaroundParameters
    +from aimet_torch.v2.adaround import Adaround
    +from aimet_torch.v2.quantsim import QuantizationSimModel
    +from aimet_torch.v2.nn import BaseQuantizationMixin
    +from aimet_torch.v2.quantization import encoding_analyzer
    +from aimet_torch.v2.utils import flatten_nn_module_list
    +from aimet_torch.v2.amp.utils import _mock_v1_quantizers
    +from aimet_torch.amp.mixed_precision_algo import GreedyMixedPrecisionAlgo, EvalCallbackFactory, _default_forward_fn
    +from aimet_torch.onnx_utils import OnnxExportApiArgs
    +from aimet_common.defs import QuantScheme, CallbackFunc, QuantizationDataType
    +from aimet_common.amp.utils import (
    +    create_sensitivity_plot,
    +    create_pareto_curve,
    +    CANDIDATE_WITH_DTYPE,
    +    AmpCandidate,
    +)
    +
    +
    +__all__ = [
    +    'AutoQuant',
    +    'AutoQuantWithAutoMixedPrecision',
    +]
    +
    +_MAP_QSCHEME_TO_ENCODING_ANALYZER = {
    +    QuantScheme.post_training_tf: encoding_analyzer.MinMaxEncodingAnalyzer,
    +    QuantScheme.post_training_percentile: encoding_analyzer.PercentileEncodingAnalyzer,
    +    QuantScheme.post_training_tf_enhanced: encoding_analyzer.SqnrEncodingAnalyzer,
    +    QuantScheme.training_range_learning_with_tf_init: encoding_analyzer.MinMaxEncodingAnalyzer,
    +    QuantScheme.training_range_learning_with_tf_enhanced_init: encoding_analyzer.SqnrEncodingAnalyzer,
    +}
    +
    +
    +class AutoQuant(AutoQuantBase): # pylint: disable=too-many-instance-attributes
    +    """
    +    Integrate and apply post-training quantization techniques.
    +
    +    AutoQuant includes 1) batchnorm folding, 2) cross-layer equalization,
    +    and 3) Adaround.
    +    These techniques will be applied in a best-effort manner until the model
    +    meets the evaluation goal given as allowed_accuracy_drop.
    +    """
    +
    +    @staticmethod
    +    def _get_adaround():
    +        """ returns AdaRound """
    +        return Adaround
    +
    +    @functools.wraps(AutoQuantBase.__init__)
    +    def __init__(self, *args, rounding_mode: str = 'nearest', **kwargs):
    +        if rounding_mode == 'stochastic':
    +            raise ValueError("Stochastic rounding mode is not supported.")
    +        super().__init__(*args, **kwargs)
    +
    +    @staticmethod
    +    def _get_quantsim(model, dummy_input, **kwargs):
    +        return QuantizationSimModel(model, dummy_input, **kwargs)
    +
    +    def _configure_quantsim(self, # pylint: disable=too-many-arguments
    +                            sim,
    +                            output_bw,
    +                            output_quant_scheme,
    +                            output_percentile,
    +                            param_bw,
    +                            param_quant_scheme,
    +                            param_percentile,
    +                            encoding_path):
    +
    +        for module in sim.model.modules():
    +            if isinstance(module, BaseQuantizationMixin):
    +                # Set input/output quantizers' quant schemes
    +                for quantizer in itertools.chain(flatten_nn_module_list(module.input_quantizers),
    +                                                 flatten_nn_module_list(module.output_quantizers)):
    +                    self._set_quantizer_qscheme(quantizer, output_quant_scheme, output_percentile)
    +
    +                # Set param quantizers' quant schemes
    +                for quantizer in module.param_quantizers.values():
    +                    self._set_quantizer_qscheme(quantizer, param_quant_scheme, param_percentile)
    +
    +        if encoding_path:
    +            sim.set_and_freeze_param_encodings(encoding_path)
    +
    +        if output_bw == 32:
    +            self._disable_activation_quantizers(sim)
    +
    +        if param_bw == 32:
    +            self._disable_param_quantizers(sim)
    +
    +
    +    @staticmethod
    +    def _set_quantizer_qscheme(quantizer, quant_scheme, percentile):
    +        if quantizer is None:
    +            return
    +
    +        if quant_scheme in (QuantScheme.post_training_percentile, QuantScheme.post_training_tf,
    +                            QuantScheme.post_training_tf_enhanced):
    +            quantizer.requires_grad_(False)
    +
    +        elif QuantScheme in (QuantScheme.training_range_learning, QuantScheme.training_range_learning_with_tf_init,
    +                             QuantScheme.training_range_learning_with_tf_enhanced_init):
    +            quantizer.requires_grad_(True)
    +
    +        enc_analyzer = _MAP_QSCHEME_TO_ENCODING_ANALYZER[quant_scheme](quantizer.shape)
    +        if isinstance(enc_analyzer, encoding_analyzer.PercentileEncodingAnalyzer) and percentile is not None:
    +            enc_analyzer.set_percentile(percentile)
    +
    +        quantizer.encoding_analyzer = enc_analyzer
    +
    +
    +    @staticmethod
    +    def _has_enabled_quantizers(sim):
    +        for module in sim.model.modules():
    +            if isinstance(module, Q.base.QuantizerBase):
    +                return True
    +        return False
    +
    +    @staticmethod
    +    def _disable_activation_quantizers(sim):
    +        def recursive_disable_quantizers(quantizer_list):
    +            for idx, quantizer in enumerate(quantizer_list):
    +                if isinstance(quantizer, (list, tuple, torch.nn.ModuleList)):
    +                    recursive_disable_quantizers(quantizer)
    +                else:
    +                    quantizer_list[idx] = None
    +
    +        for module in sim.model.modules():
    +            if isinstance(module, BaseQuantizationMixin):
    +                recursive_disable_quantizers(module.input_quantizers)
    +                recursive_disable_quantizers(module.output_quantizers)
    +
    +    @staticmethod
    +    def _disable_param_quantizers(sim):
    +        for module in sim.model.modules():
    +            if isinstance(module, BaseQuantizationMixin):
    +                for name, _ in module.param_quantizers.items():
    +                    module.param_quantizers[name] = None
    +
    +
    +
    +# The number of samples to be used for performance evaluation and AMP.
    +# NOTE: None means "all".
    +DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_1 = EvalCallbackFactory._DEFAULT_SQNR_NUM_SAMPLES
    +DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_2 = None
    +
    +
    +
    +[docs] +class AutoQuantWithAutoMixedPrecision: + """ + Integrate and apply post-training quantization techniques. + + AutoQuant includes 1) batchnorm folding, 2) cross-layer equalization, + 3) Adaround, and 4) Automatic Mixed Precision (if enabled). + These techniques will be applied in a best-effort manner until the model + meets the evaluation goal given as allowed_accuracy_drop. + """ + def __init__( # pylint: disable=too-many-arguments, too-many-function-args + self, + model: torch.nn.Module, + dummy_input: Union[torch.Tensor, Tuple], + data_loader: DataLoader, + eval_callback: Callable[[torch.nn.Module], float], + param_bw: int = 8, + output_bw: int = 8, + quant_scheme: QuantScheme = QuantScheme.post_training_tf_enhanced, + rounding_mode: str = 'nearest', + config_file: str = None, + results_dir: str = "/tmp", + cache_id: str = None, + strict_validation: bool = True, + model_prepare_required: bool = True,) -> None: + """ + :param model: Model to be quantized. Assumes model is on the correct device + :param dummy_input: Dummy input for the model. Assumes that dummy_input is on the correct device + :param data_loader: A collection that iterates over an unlabeled dataset, used for computing encodings + :param eval_callback: Function that calculates the evaluation score + :param param_bw: Parameter bitwidth + :param output_bw: Output bitwidth + :param quant_scheme: Quantization scheme + :param rounding_mode: Rounding mode + :param config_file: Path to configuration file for model quantizers + :param results_dir: Directory to save the results of PTQ techniques + :param cache_id: ID associated with cache results + :param strict_validation: Flag set to True by default.hen False, AutoQuant will proceed with execution and handle errors internally if possible. This may produce unideal or unintuitive results. + :param model_prepare_required: Flag set to True by default.If False, AutoQuant will skip model prepare block in the pipeline. + """ + self._auto_quant_base = AutoQuant(model, + dummy_input, + data_loader, + eval_callback, + param_bw, + output_bw, + quant_scheme, + rounding_mode, + config_file, + results_dir, + cache_id, + strict_validation, + model_prepare_required) + self._data_loader = data_loader + self._amp_args = None + +
    +[docs] + def run_inference(self) -> Tuple[QuantizationSimModel, float]: + ''' + Creates a quantization model and performs inference + + :return: QuantizationSimModel, model accuracy as float + ''' + return self._auto_quant_base.run_inference()
    + + +
    +[docs] + def optimize(self, allowed_accuracy_drop: float = 0.0)\ + -> Tuple[torch.nn.Module, float, str, ParetoFrontType]: + """ + Integrate and apply post-training quantization techniques. + + :param allowed_accuracy_drop: Maximum allowed accuracy drop + :return: Tuple of (best model, eval score, encoding path, pareto front). + Pareto front is None if AMP is not enabled or AutoQuant exits + without performing AMP. + """ + html_template_file = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "auto_quant_diagnostics_template_with_amp.html", + ) + with patch.object(_EvalManager, "HTML_TEMPLATE_FILE", html_template_file): + result = self._auto_quant_base._optimize_helper(self._optimize_main, + allowed_accuracy_drop) + return result["model"],\ + result["accuracy"],\ + result["encoding_path"],\ + result["pareto_list"]
    + + +
    +[docs] + def set_adaround_params(self, adaround_params: AdaroundParameters) -> None: + """ + Set Adaround parameters. + If this method is not called explicitly by the user, AutoQuant will use + `data_loader` (passed to `__init__`) for Adaround. + + :param adaround_params: Adaround parameters. + """ + return self._auto_quant_base.set_adaround_params(adaround_params)
    + + +
    +[docs] + def set_export_params(self, + onnx_export_args: OnnxExportApiArgs = -1, + propagate_encodings: bool = None) -> None: + """ + Set parameters for QuantizationSimModel.export. + + :param onnx_export_args: optional export argument with onnx specific overrides + if not provide export via torchscript graph + :param propagate_encodings: If True, encoding entries for intermediate ops + (when one PyTorch ops results in multiple ONNX nodes) are filled with + the same BW and data_type as the output tensor for that series of ops. + """ + return self._auto_quant_base.set_export_params(onnx_export_args, propagate_encodings)
    + + +
    +[docs] + def set_mixed_precision_params( + self, + candidates: List[CANDIDATE_WITH_DTYPE], + num_samples_for_phase_1: Optional[int] = DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_1, + forward_fn: Callable = _default_forward_fn, + num_samples_for_phase_2: Optional[int] = DEFAULT_NUM_SAMPLES_FOR_AMP_PHASE_2, + ) -> None: + """ + Set mixed precision parameters. + NOTE: Automatic mixed precision will NOT be enabled unless this method + is explicitly called by the user. + + :param candidates: List of tuples of candidate bitwidths and datatypes. + :param num_samples_for_phase_1: Number of samples to be used for performance + evaluation in AMP phase 1. + :param forward_fn: Function that runs forward pass and returns the output tensor. + which will be used for SQNR compuatation in phase 1. + This function is expected to take 1) a model and 2) a single batch + yielded from the data loader, and return a single torch.Tensor object + which represents the output of the model. + The default forward function is roughly equivalent to + ``lambda model, batch: model(batch)`` + :param num_samples_for_phase_2: Number of samples to be used for performance + evaluation in AMP phase 2. + """ + if len(candidates) < 2: + raise ValueError(f"AMP requires at least two candidates. Got {len(candidates)}.") + + baseline_param_bw = self._auto_quant_base._quantsim_params["param_bw"] + baseline_output_bw = self._auto_quant_base._quantsim_params["output_bw"] + baseline_candidate = ( + (baseline_output_bw, QuantizationDataType.int), + (baseline_param_bw, QuantizationDataType.int), + ) + + if baseline_candidate not in candidates: + raise ValueError( + f"AMP candidate must contain W{baseline_param_bw}A{baseline_output_bw}, " + "which was passed to the constructor of AutoQuant as `param_bw` and `output_bw`." + ) + + for candidate in candidates: + ((output_bw, output_dtype), (param_bw, param_dtype)) = candidate + + if output_dtype != param_dtype: + raise ValueError( + "The data types of parameters and outputs should be the same. " + f"Got {output_dtype} output and {param_dtype} for parameter." + ) + + if output_dtype == QuantizationDataType.float: + continue + + # The param/output_bw passed to the constructor of AutoQuant + # must be the baseline-bitwidth candidate among all AMP candidates. + if output_bw < baseline_output_bw or param_bw < baseline_param_bw: + raise ValueError( + "All AMP candidates should be strictly superior to the baseline " + f"W{baseline_param_bw}A{baseline_output_bw}, which was passed " + "to the constructor of AutoQuant. Please make sure that all the INT candidates " + f"satisfy param_bw >= {baseline_param_bw} and output_bw >= {baseline_param_bw}." + ) + + factory = EvalCallbackFactory(self._data_loader, forward_fn=forward_fn) + sqnr_eval_callback = factory.sqnr(num_samples_for_phase_1) + + candidates = [AmpCandidate(candidate) for candidate in set(candidates)] + + self._amp_args = _MixedPrecisionArgs( + candidates=candidates, + forward_pass_callback=CallbackFunc(self._auto_quant_base.forward_pass_callback, None), + eval_callback_for_phase1=sqnr_eval_callback, + eval_callback_for_phase2=CallbackFunc(self._auto_quant_base.eval_callback, + num_samples_for_phase_2), + )
    + + +
    +[docs] + def set_model_preparer_params( + self, + modules_to_exclude: List[torch.nn.Module] = None, + concrete_args: Optional[Dict[str, Any]] = None, + ): + """ + Set parameters for model preparer. + + :param modules_to_exclude: List of modules to exclude when tracing. + :param concrete_args: Parameter for model preparer. Allows you to partially specialize + your function, whether it's to remove control flow or data structures. If the + model has control flow, torch.fx won't be able to trace the model. Check + torch.fx.symbolic_trace API in detail. + """ + return self._auto_quant_base.set_model_preparer_params(modules_to_exclude, concrete_args)
    + + +
    +[docs] + def get_quant_scheme_candidates(self) -> Tuple[_QuantSchemePair, ...]: + """ + Return the candidates for quant scheme search. + During :meth:`~AutoQuant.optimize`, the candidate with the highest accuracy + will be selected among them. + + :return: Candidates for quant scheme search + """ + return self._auto_quant_base.get_quant_scheme_candidates()
    + + +
    +[docs] + def set_quant_scheme_candidates(self, candidates: Tuple[_QuantSchemePair, ...]): + """ + Set candidates for quant scheme search. + During :meth:`~AutoQuant.optimize`, the candidate with the highest accuracy + will be selected among them. + + :param candidates: Candidates for quant scheme search + """ + return self._auto_quant_base.set_quant_scheme_candidates(candidates)
    + + + # @cache.mark("mixed_precision") + def _apply_mixed_precision( + self, + model: torch.nn.Module, + dummy_input: Union[torch.Tensor, Tuple], + target_acc: float, + amp_args: _MixedPrecisionArgs, + results_dir: str, + encoding_path: str = None, + ) -> _MixedPrecisionResult: + """ + Apply mixed-precision and return the highest accuracy. + + NOTE1: Input model is not mutated. + NOTE2: Parameter `clean_start` is always set to True. + + :param model: Model to apply mixed precision. + :param dummy_input: Dummy input to the model. + :param target_acc: Minimum evaluation score required. + :param encoding_path: Path to parameter encodings file. + :param results_dir: Directory to save the results of AdaRound and mixed precision. + :return: MixedPrecisionAlgo object. + """ + if not amp_args: + raise RuntimeError + + sim = self._auto_quant_base._create_quantsim_and_encodings(model, + encoding_path=encoding_path) + + with _mock_v1_quantizers(sim): + algo = GreedyMixedPrecisionAlgo( + sim, + dummy_input, + amp_args.candidates, + amp_args.eval_callback_for_phase1, + amp_args.eval_callback_for_phase2, + results_dir=results_dir, + clean_start=True, + forward_pass_callback=amp_args.forward_pass_callback + ) + + # Find baseline accuracy and bw corresponding to baseline accuracy + algo.set_baseline(fp32_accuracy=self._auto_quant_base._fp32_acc) + allowed_accuracy_drop = algo.fp32_accuracy - target_acc + + algo.run(allowed_accuracy_drop) + + sensitivity_plot = None + if algo.accuracy_list is not None: + # Visualize quantizer group sensitivity + sensitivity_plot = create_sensitivity_plot(algo.accuracy_list, + algo.baseline_candidate, + algo.fp32_accuracy) + pareto_plot = None + if algo.pareto_list is not None: + # Create pareto list curve + pareto_plot = create_pareto_curve(algo.pareto_list) + + return _MixedPrecisionResult(algo.pareto_list, + algo._sim, + algo._final_eval_score, + sensitivity_plot, + pareto_plot) + + def _optimize_main(self, fp32_model: torch.nn.Module, target_acc: float) -> Dict[str, Any]: + """ + Helper function of apply(). + + :param fp32_model: Model to apply PTQ techniques. + :param target_acc: Target eval score. + :return: The best ptq result as a dictionary. + """ + # pylint: disable=broad-except, too-many-locals, too-many-statements, too-many-branches + + if self._amp_args: + candidates = copy.copy(self._amp_args.candidates) + else: + candidates = [] + + eval_manager = self._auto_quant_base.eval_manager + dummy_input = self._auto_quant_base.dummy_input + results_dir = self._auto_quant_base.results_dir + strict_validation = eval_manager._strict_validation + + sess = eval_manager.session("") + _multiconfig_adaround_fn = _adaround_wrapper(self._auto_quant_base._apply_adaround, + self._auto_quant_base, + candidates, + target_acc, + sess.eval) + sess_eval_fn = _EvalSession.eval + def eval_fn(_, model, param_bw=None, output_bw=None, **kwargs): + if param_bw == 32: + # For W32 evaluation, use the highest output bitwidth + # among all the AMP candidates + output_bitwidths = [ + output_bw for (output_bw, output_dtype), _ in candidates + if output_dtype == QuantizationDataType.int + ] + output_bitwidths.append(self._auto_quant_base._quantsim_params["output_bw"]) + output_bw = max(output_bitwidths) + return sess_eval_fn(_, model, param_bw=param_bw, output_bw=output_bw, **kwargs) + + with patch.object(self._auto_quant_base, "_apply_adaround", _multiconfig_adaround_fn),\ + patch.object(_EvalSession, "eval", eval_fn): + try: + result = self._auto_quant_base._optimize_main(fp32_model, target_acc) + + # Automatic Mixed Precision + result["pareto_list"] = None + + # An empty `result` dict means AutoQuant early-exited + # because W32 eval score didn't meet the target accuracy. + # In this case, do not proceed to AMP and exit immediately. + if result["model"] is None and\ + result["accuracy"] is None and\ + result["encoding_path"] is None and\ + result["applied_techniques"] is None: + return result + + if result["accuracy"] >= target_acc or not self._amp_args: + return result + + if len(candidates) < 2: + _logger.info( + "After Adaround, we have only one Adarond-compatible candidate left for AMP (W%dA%d). " + "Return without proceeding to AMP", candidates[0].param_bw, candidates[0].output_bw + ) + return result + + model = result["model"] + applied_techniques = result["applied_techniques"] + # Freeze weight encoding to adaround weight encoding + encoding_path = result["encoding_path"] if "adaround" in applied_techniques else None + except Exception: + if strict_validation: + raise + result = {} + model = fp32_model + applied_techniques = [] + encoding_path = None + + amp_args = copy.copy(self._amp_args) + if amp_args: + amp_args.candidates = candidates + + with eval_manager.session("Automatic Mixed Precision", ptq=True) as sess: + amp_result = self._apply_mixed_precision( + model, dummy_input, target_acc, amp_args, results_dir, encoding_path=encoding_path + ) + result["pareto_list"] = amp_result.pareto_list + + if amp_result.sensitivity_plot is not None: + sess.diagnostics.add(amp_result.sensitivity_plot) + + if amp_result.pareto_plot is not None: + sess.diagnostics.add(amp_result.pareto_plot) + + sess.set_ptq_result(sim=amp_result.sim, acc=amp_result.final_eval_score, + applied_techniques=[*applied_techniques, "automatic_mixed_precision"]) + + best_result = eval_manager.get_best_ptq_result() + if best_result: + if "automatic_mixed_precision" not in best_result.applied_techniques: + sess.result["effective"] = False + if best_result.accuracy >= target_acc: + sess.result["target_satisfied"] = True + result.update(best_result.as_dict()) + return result + + raise RuntimeError("None of batchnorm folding, CLE, or Adaround " + "has been finished successfully.")
    + + + + +def _adaround_wrapper(apply_adaround_fn: Callable, + auto_quant: AutoQuantBase, + amp_candidates: List[AmpCandidate], + target_acc: float, + eval_fn: Callable): + @functools.wraps(apply_adaround_fn) + def _apply_adaround_wrapper(*args, **kwargs): # pylint: disable=too-many-locals + # If AMP candidates are empty (i.e. AMP is disabled), + # perform normal (single-round) adaround. + if not amp_candidates: + return apply_adaround_fn(*args, **kwargs) + + def apply_adaround(param_bw: int): + _logger.info("Running Adaround with W%d", param_bw) + + orig_param_bw = auto_quant._quantsim_params["param_bw"] + try: + auto_quant._quantsim_params["param_bw"] = param_bw + return apply_adaround_fn(*args, **kwargs) + finally: + auto_quant._quantsim_params["param_bw"] = orig_param_bw + + int_candidates = [ + candidate for candidate in amp_candidates + if candidate.param_dtype == QuantizationDataType.int + ] + sorted_int_candidates = sorted(int_candidates, + key=lambda candidate: (candidate.param_bw, candidate.output_bw)) + # Run Adaround with the lowest-bitwidth candidate + lowest_candidate = sorted_int_candidates[0] + model, encoding_path = apply_adaround(param_bw=lowest_candidate.param_bw) + + # If the lowest candidate is the only INT candidate, return immediately + if len(sorted_int_candidates) == 1: + return model, encoding_path + + eval_score = eval_fn(model, + param_bw=lowest_candidate.param_bw, + output_bw=lowest_candidate.output_bw, + encoding_path=encoding_path) + _logger.info("W%dA%d eval score after Adaround: %f", + lowest_candidate.param_bw, + lowest_candidate.output_bw, + eval_score) + + # If the lowest candidate satisfy the target accuracy, return immediately + if eval_score >= target_acc: + return model, encoding_path + + # If the lowest candidate fails to meet the target accuracy, + # discard the lowest candidate, apply Adaround to the second-lowest candidate, + # and use it as the baseline for AMP. + second_lowest_candidate = sorted_int_candidates[1] + + if second_lowest_candidate.param_bw != lowest_candidate.param_bw: + model = None + model, encoding_path = apply_adaround(param_bw=second_lowest_candidate.param_bw) + eval_score = eval_fn(model, + param_bw=second_lowest_candidate.param_bw, + output_bw=second_lowest_candidate.output_bw, + encoding_path=encoding_path) + _logger.info("W%dA%d eval score after Adaround: %f", + second_lowest_candidate.param_bw, + second_lowest_candidate.output_bw, + eval_score) + + # Only the candidates that are compatible with adaround can be used for AMP + adaround_compatible_amp_candidates = [ + candidate for candidate in amp_candidates + if candidate.param_bw == second_lowest_candidate.param_bw or\ + candidate.param_dtype == QuantizationDataType.float + ] + + # Fill in AMP candidates with Adaround-compatible candidates only + amp_candidates.clear() + amp_candidates.extend(adaround_compatible_amp_candidates) + + return model, encoding_path + + return _apply_adaround_wrapper +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v2/mixed_precision.html b/releases/2.0.0/_modules/aimet_torch/v2/mixed_precision.html new file mode 100644 index 0000000..72cb26e --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v2/mixed_precision.html @@ -0,0 +1,383 @@ + + + + + + + + aimet_torch.v2.mixed_precision - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v2.mixed_precision

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +# pylint: disable=all
    +
    +from .manual_mixed_precision import MixedPrecisionConfigurator
    +from .utils import Precision, SupportedDType
    +
    +from aimet_torch._base.mixed_precision import choose_mixed_precision as _choose_mixed_precision
    +from aimet_torch.v2.quantsim import QuantizationSimModel
    +from aimet_torch.v2.amp.utils import _mock_v1_quantizers
    +
    +
    +
    +[docs] +def choose_mixed_precision(sim: QuantizationSimModel, *args, **kwargs): + __doc__ = _choose_mixed_precision.__doc__ # pylint: disable=redefined-builtin, unused-variable + + with _mock_v1_quantizers(sim): + return _choose_mixed_precision(sim, *args, **kwargs)
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v2/mixed_precision/manual_mixed_precision.html b/releases/2.0.0/_modules/aimet_torch/v2/mixed_precision/manual_mixed_precision.html new file mode 100644 index 0000000..862f90c --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v2/mixed_precision/manual_mixed_precision.html @@ -0,0 +1,533 @@ + + + + + + + + aimet_torch.v2.mixed_precision.manual_mixed_precision - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v2.mixed_precision.manual_mixed_precision

    +# /usr/bin/env python
    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +""" Manual mixed precision configurator """
    +
    +from typing import overload, Union, List, Tuple, Dict, get_args, Type, Optional, IO
    +import torch
    +
    +from aimet_common.utils import AimetLogger
    +from aimet_torch.v2.utils import flatten_list
    +from aimet_torch.v2.mixed_precision.utils import UserRequest, RequestType, SupportedDType, ModuleProduct, broadcast_tuples
    +from aimet_torch.v2.mixed_precision.manual_mixed_precision_handler import MpHandler
    +from aimet_torch.v2.quantsim import QuantizationSimModel
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.Quant)
    +
    +
    +
    +[docs] +class MixedPrecisionConfigurator: + """ + Mixed Precision Configurator helps set up a mixed precision profile in the QuantSim object. The user is expected to + follow the below steps to set the sim in Mixed Precision. + + 1. Create QuantSim object + 2. Create the MixedPrecisionConfigurator object by passing in the QuantSim object + 3. Make a series of set_precision/set_model_input_precision/set_model_output_precision calls + 4. Call apply() method by passing in the config file and strict flag + 5. Run compute_encodings on the above QuantSim object + 6. Export the encodings/onnx artifacts + """ + + def __init__(self, sim: QuantizationSimModel): + """ + :param sim: QuantSim object + """ + self._sim = sim + self.user_requests = [] + self.mp_handler = MpHandler(sim) + + def _store_user_request(self, request_type: RequestType, module: Union[torch.nn.Module, Type, ModuleProduct], + activation: Union[List[SupportedDType], SupportedDType] = None, + param: Optional[Dict[str, SupportedDType]] = None): + self.user_requests.append(UserRequest(request_type=request_type, + module=module, + activation=activation, + param=param)) + + @overload + def set_precision(self, module: torch.nn.Module, + activation: Union[List[SupportedDType], SupportedDType], + param: Optional[Dict[str, SupportedDType]] = None): + ... + + @overload + def set_precision(self, module_type: Type[torch.nn.Module], + activation: Union[List[SupportedDType], SupportedDType], + param: Optional[Dict[str, SupportedDType]] = None): + ... + +
    +[docs] + def set_precision(self, arg: Union[torch.nn.Module, Type[torch.nn.Module]], + activation: Union[List[SupportedDType], SupportedDType], + param: Optional[Dict[str, SupportedDType]] = None): + """ + :param arg: Module can be of type torch.nn.Module or the type of the module. + :param activation: A string representing the activation dtype of the module input(s) + :param param: Dict with name of the param as key and its dtype as value + + - If the 'module' is a leaf-module(the module doesnt compose of other torch.nn.module), the specified settings + would be applied to the module. + - If the 'module' is a non-leaf-module (module is composed of other torch.nn.module), the specified settings + would be applied to all the leaf modules in 'module'. + - If the 'module' is Type of module, all the modules in the model which satisfy the specified module type would + be set to the specified activation and param settings + - If the same 'module' is specified through multiple set_precision(...) calls, the latest one will be applied. + + Examples: TODO + + """ + # pylint: disable=too-many-branches + if activation: + if isinstance(activation, List): + for act in activation: + if act not in get_args(SupportedDType): + raise ValueError("Supported inputs for activation are ", get_args(SupportedDType)) + else: + if activation not in get_args(SupportedDType): + raise ValueError("Supported inputs for activation are ", get_args(SupportedDType)) + if param: + for param_name, dtype in param.items(): + if dtype not in get_args(SupportedDType): + raise ValueError(f"Supported inputs for param: {param_name} are ", get_args(SupportedDType)) + + if isinstance(arg, type): + self._store_user_request(RequestType.set_precision_by_module_type, arg, activation, param) + elif isinstance(arg, torch.nn.Module): + if arg in self._sim.model.modules(): + self._store_user_request(RequestType.set_precision_by_module, arg, activation, param) + else: + raise ValueError(f"Specified module {arg} is not part of the sim object") + else: + raise TypeError("arg is neither a torch.nn.Module nor of Type[torch.nn.Module]")
    + + +
    +[docs] + def set_model_input_precision(self, activation: Union[List[Optional[SupportedDType]], Tuple[Optional[SupportedDType]], SupportedDType]): + """ + Activation precision which needs to be set to the model inputs + + :param activation: Activation dtypes for inputs of the model + """ + broadcasted_activations = broadcast_tuples(activation, self.mp_handler.cg_traverser.model_inputs) + for act, model_input in zip(flatten_list(broadcasted_activations), + flatten_list(self.mp_handler.cg_traverser.model_inputs)): + if act: + if act not in get_args(SupportedDType): + raise ValueError("Supported inputs for activation are ", get_args(SupportedDType)) + self._store_user_request(RequestType.set_model_input_precision, model_input, act)
    + + +
    +[docs] + def set_model_output_precision(self, activation: Union[List[Optional[SupportedDType]], Tuple[Optional[SupportedDType]], SupportedDType]): + """ + Activation precision which needs to be set to the model outputs + + :param activation: Activation dtypes for outputs of the model + """ + broadcasted_activations = broadcast_tuples(activation, self.mp_handler.cg_traverser.model_outputs) + for act, model_output in zip(flatten_list(broadcasted_activations), + flatten_list(self.mp_handler.cg_traverser.model_outputs)): + if act: + if act not in get_args(SupportedDType): + raise ValueError("Supported inputs for activation are ", get_args(SupportedDType)) + self._store_user_request(RequestType.set_model_output_precision, model_output, act)
    + + + @overload + def apply(self, log_file: str = './mmp_log.txt', strict: bool = True): + ... + + @overload + def apply(self, log_file: IO, strict: bool = True): + ... + + +
    +[docs] + def apply(self, log_file: Optional[Union[IO, str]] = './mmp_log.txt', strict: bool = True): + """ + Apply the mp settings specified through the set_precision/set_model_input_precision/set_model_output_precision + calls to the QuantSim object + + :param log_file: log_file to store the logs. log_file can either be a string representing the path or the IO + object to write the logs into. + :param strict: Boolean flag to indicate whether to fail (strict=True) on incorrect/conflicting inputs made by + the user or (strict=False) take a best-effort approach to realize the MP settings + """ + if isinstance(log_file, str): + with open(log_file, 'w') as f: + self.mp_handler.apply(f, self.user_requests, strict) + else: + self.mp_handler.apply(log_file, self.user_requests, strict) + + self.user_requests.clear()
    +
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v2/nn/true_quant.html b/releases/2.0.0/_modules/aimet_torch/v2/nn/true_quant.html new file mode 100644 index 0000000..aec4703 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v2/nn/true_quant.html @@ -0,0 +1,2791 @@ + + + + + + + + aimet_torch.v2.nn.true_quant - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v2.nn.true_quant

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +# pylint: disable=too-many-lines, wrong-import-order, redefined-builtin
    +""" Quantized modules"""
    +
    +from packaging import version
    +import contextlib
    +import itertools
    +from inspect import signature
    +from abc import abstractmethod, ABCMeta
    +from collections import OrderedDict
    +from typing import Type, Any, Optional, Callable, Dict
    +from weakref import WeakKeyDictionary
    +import warnings
    +
    +import torch
    +import torch.nn as nn
    +import torch.nn.functional as F
    +from torch import Tensor
    +from torch.overrides import BaseTorchFunctionMode, get_overridable_functions
    +from torch._VF import ( # pylint: disable=no-name-in-module
    +    gru as _gru,
    +    gru_cell as _gru_cell,
    +    lstm as _lstm,
    +    lstm_cell as _lstm_cell,
    +    rnn_relu as _rnn_relu,
    +    rnn_tanh as _rnn_tanh,
    +    rnn_relu_cell as _rnn_relu_cell,
    +    rnn_tanh_cell as _rnn_tanh_cell,
    +)
    +
    +from aimet_torch.v2.quantization.base import QuantizerBase
    +from aimet_torch.v2.quantization.tensor import QuantizedTensorBase
    +from aimet_torch.v2.utils import patch_attr, _ContextManager, allow_recompute
    +from .base import BaseQuantizationMixin # pylint: disable=import-error
    +
    +
    +def _quantize_if_applicable(data: Any, quantizer: Optional[QuantizerBase]):
    +    """
    +    Quantize data if it is a quantizable type and quantize is not None
    +    """
    +    if quantizer and isinstance(data, Tensor) and data.is_floating_point():
    +        if isinstance(data, QuantizedTensorBase):
    +            data = data.dequantize()
    +        return quantizer(data)
    +
    +    if isinstance(data, QuantizedTensorBase):
    +        return data.quantize()
    +
    +    return data
    +
    +
    +def _dequantize_if_applicable(data: torch.Tensor):
    +    return data.dequantize() if isinstance(data, QuantizedTensorBase) else data
    +
    +
    +def _quantize_dequantize_if_applicable(data, quantizer):
    +    if quantizer and isinstance(data, Tensor) and data.is_floating_point():
    +        if isinstance(data, QuantizedTensorBase):
    +            data = data.dequantize()
    +        data = quantizer(data)
    +
    +    if isinstance(data, QuantizedTensorBase):
    +        return data.dequantize()
    +
    +    return data
    +
    +
    +_QUANTIZED_MODULES_UNDER_COMPUTE_ENCODINGS = WeakKeyDictionary()
    +
    +
    +def _is_computing_encodings(qmodule):
    +    return _QUANTIZED_MODULES_UNDER_COMPUTE_ENCODINGS.get(qmodule, 0) > 0
    +
    +
    +def _enter_computing_encodings(qmodule):
    +    if qmodule not in _QUANTIZED_MODULES_UNDER_COMPUTE_ENCODINGS:
    +        _QUANTIZED_MODULES_UNDER_COMPUTE_ENCODINGS[qmodule] = 0
    +    _QUANTIZED_MODULES_UNDER_COMPUTE_ENCODINGS[qmodule] += 1
    +
    +
    +def _exit_compute_encodings(qmodule):
    +    assert _QUANTIZED_MODULES_UNDER_COMPUTE_ENCODINGS[qmodule] > 0
    +    _QUANTIZED_MODULES_UNDER_COMPUTE_ENCODINGS[qmodule] -= 1
    +
    +
    +class QuantizationMixinMeta(ABCMeta):
    +    """Sets :meth:`forward` to :meth:`quantized_forward` if only :meth:`quantized_forward` is defined
    +    """
    +
    +    def __new__(mcs, name, bases, namespace, **kwargs):
    +        if "quantized_forward" in namespace and "forward" not in namespace:
    +            warnings.warn("Support for defining `quantized_forward` in place of `forward` method will be deprecated, "
    +                          "please use `forward` instead.",
    +                          DeprecationWarning, stacklevel=2)
    +            namespace["forward"] = namespace["quantized_forward"]
    +        return super().__new__(mcs, name, bases, namespace, **kwargs)
    +
    +
    +
    +[docs] +class QuantizationMixin(BaseQuantizationMixin, metaclass=QuantizationMixinMeta): # pylint: disable=abstract-method + """Quantization mixin class for torch.nn.Module. + + Specifically, a quantized module will quantize input, output, and parameter tensors with + its held :class:`QuantizerBase` objects during the :meth:`forward` method and use the inherited :class:`torch.nn.Module` + forward method to compute the layer operation. If all input, output, and parameter quantizers are ``None``, a + quantized module will behave exactly the same as its parent :class:`torch.nn.Module`. + + Attributes: + input_quantizers: :class:`torch.nn.ModuleList` containing :class:`QuantizerBase` objects to be applied + to the layer's input tensors + output_quantizers: :class:`torch.nn.ModuleList` containing :class:`QuantizerBase` objects to be applied + to the layer's output tensors + param_quantizers: :class:`torch.nn.ModuleDict` mapping parameter names to associated :class:`QuantizerBase` + objects + + Examples: + + >>> qlinear = QuantizedLinear(in_features=10, out_features=10) + >>> print(qlinear) + QuantizedLinear( + in_features=10, out_features=10, bias=True + (param_quantizers): ModuleDict( + (weight): None + (bias): None + ) + (input_quantizers): ModuleList( + (0): None + ) + (output_quantizers): ModuleList( + (0): None + ) + ) + + """ + + cls_to_qcls = OrderedDict() # quantized class -> original class + qcls_to_cls = OrderedDict() # original class -> quantized class + + _default_kernel: Optional[Callable] = None + _kernels = WeakKeyDictionary() # instance -> instance_kernel + +
    +[docs] + @abstractmethod + def forward(self, *args, **kwargs): + """Computes a quantized version of the parent module's forward method. + + The :meth:`forward` method should perform the following logic in order: + + 1) Apply existing input quantizers to input tensors + 2) Apply existing param quantizers to the layer's parameters + 3) Call the inherited :class:`torch.nn.Module` forward method with quantized inputs and parameters + 4) Apply existing output quantizers to the outputs of the forward method + + If all input, output, and parameter quantizers are ``None``, this method will behave exactly the same as + its parent module's forward pass. + """ + return super().forward(*args, **kwargs)
    + + +
    +[docs] + @classmethod + def set_default_kernel(cls, kernel: Callable): + """Set default kernel for the class. + + In general, this signature will follow the signature of the equivalent :mod:`torch.nn.functional` function, + but should return a :class:`QuantizedTensor` object and take in the additional keyword argument ``output_encodings``. + + Once set, all instances of cls will call into kernel in the forward pass unless: + + 1) The instance is within the :meth:`compute_encodings` context, or + 2) The kernel has been overridden by a :meth:`set_kernel` call + + Args: + kernel: Callable object to be used as the default kernel by all the instances of this class. + + + Example: + + >>> from aimet_torch.v2 import quantization as Q + >>> def int_multiply(a, b, output_encodings=None): + ... encodings = [a.encoding, b.encoding, output_encodings] + ... if not all(enc.mapping == "affine" for enc in encodings): + ... raise NotImplementedError + ... q_output = (a.quantized_repr() + a.encoding.offset) * (b.quantized_repr() + b.encoding.offset) + ... dq_output = q_output * (a.encoding.scale * b.encoding.scale) + ... return Q.QuantizedTensor(output_encodings.quantize(dq_output), encoding=output_encodings) + ... + >>> QuantizedMultiply.set_default_kernel(int_multiply) + >>> qmult = QuantizedMultiply() + >>> qmult.get_kernel() + <function int_multiply at ...> + + """ + cls._default_kernel = kernel
    + + +
    +[docs] + @classmethod + def get_default_kernel(cls) -> Optional[Callable]: + """Return the default kernel of the class + + Returns: + Default kernel of the class. None if the default kernel is not set. + + """ + return cls._default_kernel
    + + +
    +[docs] + def set_kernel(self, kernel: Callable): + """Set kernel for this instance of quantized module. + + In general, this signature will follow the signature of the equivalent :mod:`torch.nn.functional` function, + but should return a :class:`QuantizedTensor` object and take in the additional keyword argument ``output_encodings``. + + Once set, the layer will call into ``kernel`` in the forward pass unless within the :meth:`compute_encodings` + context. + + Args: + kernel: Callable object to be used as the underlying kernel. + + Example: + + >>> from aimet_torch.v2 import quantization as Q + >>> def int_multiply(a, b, output_encodings=None): + ... encodings = [a.encoding, b.encoding, output_encodings] + ... if not all(enc.mapping == "affine" for enc in encodings): + ... raise NotImplementedError + ... q_output = (a.quantized_repr() + a.encoding.offset) * (b.quantized_repr() + b.encoding.offset) + ... dq_output = q_output * (a.encoding.scale * b.encoding.scale) + ... return Q.QuantizedTensor(output_encodings.quantize(dq_output), encoding=output_encodings) + ... + >>> qmult = QuantizedMultiply() + >>> qmult.set_kernel(int_multiply) + + """ + QuantizationMixin._kernels[self] = kernel
    + + +
    +[docs] + def get_kernel(self) -> Optional[Callable]: + """Return the kernel to be used by this instance of quantized module. + + If the current instance does not have any kernel set, it will retrieve the default kernel of the class. + + Returns: + The kernel to be used by this instance. + + """ + if self in QuantizationMixin._kernels: + return QuantizationMixin._kernels[self] + return self.get_default_kernel()
    + + +
    +[docs] + @contextlib.contextmanager + def compute_encodings(self): # pylint: disable=missing-function-docstring + ctx = _ContextManager(action=lambda: _enter_computing_encodings(self), + cleanup=lambda: _exit_compute_encodings(self)) + with super().compute_encodings(), ctx: + yield
    + + + def _patch_dequantized_parameters(self): + stack = contextlib.ExitStack() + for param_name, _ in self.param_quantizers.items(): + qparam = getattr(self, param_name) + ctx = patch_attr(self, param_name, _dequantize_if_applicable(qparam)) + stack.enter_context(ctx) + + return stack + +
    +[docs] + @classmethod + def wrap(cls, module_cls: Type[nn.Module]) -> Type[nn.Module]: + """ + Wrap a regular module class into a quantized module class + """ + if not issubclass(module_cls, nn.Module): + raise ValueError("Expected module_cls to be a subclass of torch.nn.Module. " + f"Got {module_cls}.") + if module_cls in cls.cls_to_qcls: + return cls.cls_to_qcls[module_cls] + + quantized_cls_name = f"Quantized{module_cls.__name__}" + base_classes = (cls, module_cls) + quantized_cls = type(quantized_cls_name, base_classes, {'__module__': __name__}) + return cls.implements(module_cls)(quantized_cls)
    + + +
    +[docs] + @classmethod + def from_module(cls, module: nn.Module): + r"""Create an instance of quantized module from a regular module instance. + + The resulting quantized module contains the same attributes and parameters as the original module, but may + be assigned input, output and parameter quantizers. + + :param module: Floating point module to quantize + :return: Quantized version of the original module + + Example: + + >>> linear = torch.nn.Linear(10, 10) + >>> quantized_linear = QuantizationMixin.from_module(linear) + >>> print(quantized_linear.param_quantizers) + QuantizedLinear( + in_features=10, out_features=10, bias=True + (param_quantizers): ModuleDict( + (weight): None + (bias): None + ) + (input_quantizers): ModuleList( + (0): None + ) + (output_quantizers): ModuleList( + (0): None + ) + ) + >>> print(quantized_linear.weight is linear.weight) + True + """ + return super().from_module(module)
    + + +
    +[docs] + @classmethod + def implements(cls, module_cls): + r""" + Decorator for registering quantized definition of the given base class. + + Even though AIMET supports quantization of all built-in modules in torch.nn subpackage + such as ``torch.nn.Conv2d`` or ``torch.nn.Linear`` that AIMET is already aware of, + :class:`QuantizationSimModel` will throw a runtime error when it encounters custom modules + defined by the users, asking the users to provide the quantized definition of the custom modules + that AIMET doesn't know of. + + To declare the quantized definition of a module, :class:`QuantizationSimModel` requires you + to define a subclass of your module decorated with :meth:`implements`, + in which you will implement ``__quant_init__`` and ``forward`` methods. + + As an example, given a custom module as below:: + + class MaskedAdd(torch.nn.Module): + def forward(self, input: torch.Tensor, mask: torch.Tensor, value: torch.Tensor): + return input + mask * value + + its quantized definition should be declared before creating :class:`QuantizationSimModel`, typically as below:: + + + @QuantizationMixin.implements(MaskedAdd) + class QuantizedMaskedAdd(QuantizationMixin, MaskedAdd): + # The quantized definition of MaskedAdd should be a subclass of + # QuantizationMixin and MaskedAdd (Order matters!) + def __quant_init__(self): + super().__quant_init__() + + # Declare the number of input/output quantizers + self.input_quantizers = torch.nn.ModuleList([None, None, None]) + self.output_quantizers = torch.nn.ModuleList([None]) + + def forward(self, input: torch.Tensor, mask: torch.Tensor, value: torch.Tensor): + input_qtzr = self.input_quantizers[0] + _ = self.input_quantizers[1] # I don't want to quantize the boolean masks! + value_qtzr = self.input_quantizers[2] + output_qtzr = self.output_quantizers[0] + + if input_qtzr is not None: + input = input_qtzr(input) + + if value_qtzr is not None: + value = value_qtzr(value) + + output = super().forward(input, mask, value) + + if output_qtzr is not None: + output = output_qtzr(output) + + return output + """ + return super().implements(module_cls)
    +
    + + + +# pylint: disable=too-many-ancestors + + +_dispatch_table: Dict[Callable, Optional[Callable]] +_dispatch_table = { + torch_fn: None + for torch_fn in itertools.chain(*get_overridable_functions().values()) +} + +# NOTE: ``torch.overrides.get_overridable_functions()`` doesn't include +# F.hardswish, F.hardsigmoid, or Tensor.unflatten, even though +# they are implemented in a perfectly dispatchable manner. +_dispatch_table[F.hardswish] = None +_dispatch_table[F.hardsigmoid] = None +_dispatch_table[Tensor.unflatten] = None + + +class _Dispatcher(BaseTorchFunctionMode): + def __torch_function__(self, func, types, args=(), kwargs=None): + impl = _dispatch_table.get(func, None) + + if impl is None: + impl = func + + return super().__torch_function__(impl, types, args, kwargs) + + +@contextlib.contextmanager +def _dispatch(torch_func: Callable, custom_impl: Callable): + try: + orig = _dispatch_table[torch_func] + except KeyError as e: + raise RuntimeError(f"PyTorch doesn't support overriding {torch_func}") from e + + try: + _dispatch_table[torch_func] = custom_impl + + with _Dispatcher(): + yield + finally: + _dispatch_table[torch_func] = orig + + +class _DispatchMeta(QuantizationMixinMeta): + def __new__(mcs, name, bases, namespace, **kwargs): + """ + Sanity check for class definitions of dispatch-based quantized modules + """ + if '_builtin_torch_fn' in namespace: + torch_fn = namespace['_builtin_torch_fn'] + if torch_fn and torch_fn not in _dispatch_table: + raise RuntimeError(f"PyTorch doesn't support overriding {torch_fn}") + return super().__new__(mcs, name, bases, namespace, **kwargs) + + +class _DispatchMixin(metaclass=_DispatchMeta): + _builtin_torch_fn: Optional[Callable] = None + + def _get_builtin_torch_fn(self): + return type(self)._builtin_torch_fn + + def forward(self, *args, **kwargs): # pylint: disable=missing-function-docstring + kernel = self.get_kernel() + builtin_torch_fn = self._get_builtin_torch_fn() + + if not kernel or _is_computing_encodings(self): + kernel = self._builtin_torch_fn_helper(builtin_torch_fn) + else: + kernel = self._custom_kernel_helper(kernel) + + with self._patch_quantized_parameters(): + with _dispatch(builtin_torch_fn, kernel): + output = super().forward(*args, **kwargs) + + return _dequantize_if_applicable(output) + + def _builtin_torch_fn_helper(self, fn: Callable[..., Tensor]): + def wrapper(*args, **kwargs): + qtzd_args = ( + _quantize_dequantize_if_applicable(x, qtzr) + for x, qtzr in zip(args, self.input_quantizers) + ) + others = ( + _dequantize_if_applicable(x) + for x in args[len(self.input_quantizers):] + ) + kwargs = { + key: _dequantize_if_applicable(value) + for key, value in kwargs.items() + } + + output = fn(*qtzd_args, *others, **kwargs) + + return _quantize_dequantize_if_applicable(output, self.output_quantizers[0]) + + return wrapper + + def _custom_kernel_helper(self, fn: Callable[..., QuantizedTensorBase]): + def wrapper(*args, **kwargs): + qtzd_args = ( + _quantize_if_applicable(x, qtzr) + for x, qtzr in zip(args, self.input_quantizers) + ) + others = args[len(self.input_quantizers):] + + output_encodings = self.output_quantizers[0].get_encodings() if self.output_quantizers[0] else None + kwargs.update(output_encodings=output_encodings) + return fn(*qtzd_args, *others, **kwargs) + + return wrapper + + +def __nullary__(self): + super(type(self), self).__quant_init__() + self.input_quantizers = nn.ModuleList([]) + + +def __unary__(self): + super(type(self), self).__quant_init__() + + +def __binary__(self): + super(type(self), self).__quant_init__() + self.input_quantizers = nn.ModuleList([None, None]) + + +def __ternary__(self): + super(type(self), self).__quant_init__() + self.input_quantizers = nn.ModuleList([None, None, None]) + + +def _generate_docstring(parent_cls): + return \ + f""" + Quantized subclass of torch.nn.{parent_cls.__name__} + + .. method:: forward{str(signature(parent_cls.forward))} + :noindex: + + Quantized forward of torch.nn.{parent_cls.__name__}. + + The input(s), parameter(s) (if any), and output(s) will be quantized with + ``self.input_quantizers``, ``self.param_quantizers``, and ``self.output_quantizers`` respectively. + + For more information, see :class:`QuantizationMixin`. + """ + +
    +[docs] +@QuantizationMixin.implements(nn.AdaptiveAvgPool1d) +class QuantizedAdaptiveAvgPool1d(_DispatchMixin, QuantizationMixin, nn.AdaptiveAvgPool1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(nn.AdaptiveAvgPool1d) + _builtin_torch_fn = F.adaptive_avg_pool1d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.AdaptiveAvgPool2d) +class QuantizedAdaptiveAvgPool2d(_DispatchMixin, QuantizationMixin, nn.AdaptiveAvgPool2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.AdaptiveAvgPool2d) + _builtin_torch_fn = F.adaptive_avg_pool2d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.AdaptiveAvgPool3d) +class QuantizedAdaptiveAvgPool3d(_DispatchMixin, QuantizationMixin, nn.AdaptiveAvgPool3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.AdaptiveAvgPool3d) + _builtin_torch_fn = F.adaptive_avg_pool3d + __quant_init__ = __unary__
    + + + +# @QuantizationMixin.implements(nn.AdaptiveLogSoftmaxWithLoss) +# class QuantizedAdaptiveLogSoftmaxWithLoss(_DispatchMixin, QuantizationMixin, nn.AdaptiveLogSoftmaxWithLoss): +# _builtin_torch_fn = ... + + +
    +[docs] +@QuantizationMixin.implements(nn.AdaptiveMaxPool1d) +class QuantizedAdaptiveMaxPool1d(_DispatchMixin, QuantizationMixin, nn.AdaptiveMaxPool1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.AdaptiveMaxPool1d) + _builtin_torch_fn = F.adaptive_max_pool1d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.AdaptiveMaxPool2d) +class QuantizedAdaptiveMaxPool2d(_DispatchMixin, QuantizationMixin, nn.AdaptiveMaxPool2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.AdaptiveMaxPool2d) + _builtin_torch_fn = F.adaptive_max_pool2d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.AdaptiveMaxPool3d) +class QuantizedAdaptiveMaxPool3d(_DispatchMixin, QuantizationMixin, nn.AdaptiveMaxPool3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.AdaptiveMaxPool3d) + _builtin_torch_fn = F.adaptive_max_pool3d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.AlphaDropout) +class QuantizedAlphaDropout(_DispatchMixin, QuantizationMixin, nn.AlphaDropout): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.AlphaDropout) + _builtin_torch_fn = F.alpha_dropout + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.AvgPool1d) +class QuantizedAvgPool1d(_DispatchMixin, QuantizationMixin, nn.AvgPool1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.AvgPool1d) + _builtin_torch_fn = F.avg_pool1d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.AvgPool2d) +class QuantizedAvgPool2d(_DispatchMixin, QuantizationMixin, nn.AvgPool2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.AvgPool2d) + _builtin_torch_fn = F.avg_pool2d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.AvgPool3d) +class QuantizedAvgPool3d(_DispatchMixin, QuantizationMixin, nn.AvgPool3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.AvgPool3d) + _builtin_torch_fn = F.avg_pool3d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.BCELoss) +class QuantizedBCELoss(_DispatchMixin, QuantizationMixin, nn.BCELoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.BCELoss) + _builtin_torch_fn = F.binary_cross_entropy + __quant_init__ = __binary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.BCEWithLogitsLoss) +class QuantizedBCEWithLogitsLoss(_DispatchMixin, QuantizationMixin, nn.BCEWithLogitsLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.BCEWithLogitsLoss) + _builtin_torch_fn = F.binary_cross_entropy_with_logits + __quant_init__ = __binary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.BatchNorm1d) +class QuantizedBatchNorm1d(_DispatchMixin, QuantizationMixin, nn.BatchNorm1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.BatchNorm1d) + _builtin_torch_fn = F.batch_norm + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.BatchNorm2d) +class QuantizedBatchNorm2d(_DispatchMixin, QuantizationMixin, nn.BatchNorm2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.BatchNorm2d) + _builtin_torch_fn = F.batch_norm + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.BatchNorm3d) +class QuantizedBatchNorm3d(_DispatchMixin, QuantizationMixin, nn.BatchNorm3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.BatchNorm3d) + _builtin_torch_fn = F.batch_norm + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Bilinear) +class QuantizedBilinear(_DispatchMixin, QuantizationMixin, nn.Bilinear): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Bilinear) + _builtin_torch_fn = F.bilinear + __quant_init__ = __binary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.CELU) +class QuantizedCELU(_DispatchMixin, QuantizationMixin, nn.CELU): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.CELU) + _builtin_torch_fn = F.celu + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.CTCLoss) +class QuantizedCTCLoss(_DispatchMixin, QuantizationMixin, nn.CTCLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.CTCLoss) + _builtin_torch_fn = F.ctc_loss + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ChannelShuffle) +class QuantizedChannelShuffle(_DispatchMixin, QuantizationMixin, nn.ChannelShuffle): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ChannelShuffle) + _builtin_torch_fn = F.channel_shuffle + __quant_init__ = __unary__
    + + + +if version.parse(torch.__version__) >= version.parse("2.1.0"): +
    +[docs] + @QuantizationMixin.implements(nn.CircularPad1d) + class QuantizedCircularPad1d(_DispatchMixin, QuantizationMixin, nn.CircularPad1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.CircularPad1d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +
    +[docs] + @QuantizationMixin.implements(nn.CircularPad2d) + class QuantizedCircularPad2d(_DispatchMixin, QuantizationMixin, nn.CircularPad2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.CircularPad2d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +
    +[docs] + @QuantizationMixin.implements(nn.CircularPad3d) + class QuantizedCircularPad3d(_DispatchMixin, QuantizationMixin, nn.CircularPad3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.CircularPad3d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ConstantPad1d) +class QuantizedConstantPad1d(_DispatchMixin, QuantizationMixin, nn.ConstantPad1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ConstantPad2d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ConstantPad2d) +class QuantizedConstantPad2d(_DispatchMixin, QuantizationMixin, nn.ConstantPad2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ConstantPad2d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ConstantPad3d) +class QuantizedConstantPad3d(_DispatchMixin, QuantizationMixin, nn.ConstantPad3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ConstantPad3d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +# @QuantizationMixin.implements(nn.Container) +# class QuantizedContainer(_DispatchMixin, QuantizationMixin, nn.Container): +# _builtin_torch_fn = ... + + +
    +[docs] +@QuantizationMixin.implements(nn.Conv1d) +class QuantizedConv1d(_DispatchMixin, QuantizationMixin, nn.Conv1d): # pylint: disable=too-many-ancestors + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Conv1d) + _builtin_torch_fn = F.conv1d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Conv2d) +class QuantizedConv2d(_DispatchMixin, QuantizationMixin, nn.Conv2d): # pylint: disable=too-many-ancestors + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Conv2d) + _builtin_torch_fn = F.conv2d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Conv3d) +class QuantizedConv3d(_DispatchMixin, QuantizationMixin, nn.Conv3d): # pylint: disable=too-many-ancestors + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Conv3d) + _builtin_torch_fn = F.conv3d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ConvTranspose1d) +class QuantizedConvTranspose1d(_DispatchMixin, QuantizationMixin, nn.ConvTranspose1d): # pylint: disable=too-many-ancestors + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ConvTranspose1d) + _builtin_torch_fn = F.conv_transpose1d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ConvTranspose2d) +class QuantizedConvTranspose2d(_DispatchMixin, QuantizationMixin, nn.ConvTranspose2d): # pylint: disable=too-many-ancestors + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ConvTranspose2d) + _builtin_torch_fn = F.conv_transpose2d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ConvTranspose3d) +class QuantizedConvTranspose3d(_DispatchMixin, QuantizationMixin, nn.ConvTranspose3d): # pylint: disable=too-many-ancestors + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ConvTranspose3d) + _builtin_torch_fn = F.conv_transpose3d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.CosineEmbeddingLoss) +class QuantizedCosineEmbeddingLoss(_DispatchMixin, QuantizationMixin, nn.CosineEmbeddingLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.CosineEmbeddingLoss) + _builtin_torch_fn = F.cosine_embedding_loss + __quant_init__ = __binary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.CosineSimilarity) +class QuantizedCosineSimilarity(_DispatchMixin, QuantizationMixin, nn.CosineSimilarity): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.CosineSimilarity) + _builtin_torch_fn = F.cosine_similarity + __quant_init__ = __binary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.CrossEntropyLoss) +class QuantizedCrossEntropyLoss(_DispatchMixin, QuantizationMixin, nn.CrossEntropyLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.CrossEntropyLoss) + _builtin_torch_fn = F.cross_entropy + __quant_init__ = __binary__
    + + + +# @QuantizationMixin.implements(nn.CrossMapLRN2d) +# class QuantizedCrossMapLRN2d(_DispatchMixin, QuantizationMixin, nn.CrossMapLRN2d): +# _builtin_torch_fn = ... + + +
    +[docs] +@QuantizationMixin.implements(nn.Dropout) +class QuantizedDropout(_DispatchMixin, QuantizationMixin, nn.Dropout): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Dropout) + _builtin_torch_fn = F.dropout + __quant_init__ = __unary__
    + + + +if version.parse(torch.__version__) >= version.parse("1.12.0"): +
    +[docs] + @QuantizationMixin.implements(nn.Dropout1d) + class QuantizedDropout1d(_DispatchMixin, QuantizationMixin, nn.Dropout1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Dropout1d) + _builtin_torch_fn = F.dropout1d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Dropout2d) +class QuantizedDropout2d(_DispatchMixin, QuantizationMixin, nn.Dropout2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Dropout2d) + _builtin_torch_fn = F.dropout2d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Dropout3d) +class QuantizedDropout3d(_DispatchMixin, QuantizationMixin, nn.Dropout3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Dropout3d) + _builtin_torch_fn = F.dropout3d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ELU) +class QuantizedELU(_DispatchMixin, QuantizationMixin, nn.ELU): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ELU) + _builtin_torch_fn = F.elu + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Embedding) +class QuantizedEmbedding(_DispatchMixin, QuantizationMixin, nn.Embedding): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Embedding) + _builtin_torch_fn = F.embedding + __quant_init__ = __nullary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.EmbeddingBag) +class QuantizedEmbeddingBag(_DispatchMixin, QuantizationMixin, nn.EmbeddingBag): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.EmbeddingBag) + _builtin_torch_fn = F.embedding_bag + + def _builtin_torch_fn_helper(self, fn: Callable[..., Tensor]): + def embedding_bag(input: Tensor, # pylint: disable=redefined-builtin, too-many-arguments + weight: Tensor, + offsets: Optional[Tensor] = None, + max_norm: Optional[float] = None, + norm_type: float = 2, + scale_grad_by_freq: bool = False, + mode: str = "mean", + sparse: bool = False, + per_sample_weights: Optional[Tensor] = None, + include_last_offset: bool = False, + padding_idx: Optional[int] = None): + + if per_sample_weights is not None: + qtzr = self.input_quantizers[0] + per_sample_weights = _quantize_dequantize_if_applicable(per_sample_weights, qtzr) + + output = fn(input, + weight, + offsets=offsets, + max_norm=max_norm, + norm_type=norm_type, + scale_grad_by_freq=scale_grad_by_freq, + mode=mode, + sparse=sparse, + per_sample_weights=per_sample_weights, + include_last_offset=include_last_offset, + padding_idx=padding_idx) + + return _quantize_dequantize_if_applicable(output, self.output_quantizers[0]) + + return embedding_bag + + def _custom_kernel_helper(self, fn: Callable[..., QuantizedTensorBase]): + def embedding_bag(input: Tensor, # pylint: disable=redefined-builtin, too-many-arguments + weight: Tensor, + offsets: Optional[Tensor] = None, + max_norm: Optional[float] = None, + norm_type: float = 2, + scale_grad_by_freq: bool = False, + mode: str = "mean", + sparse: bool = False, + per_sample_weights: Optional[Tensor] = None, + include_last_offset: bool = False, + padding_idx: Optional[int] = None): + + if per_sample_weights is not None: + qtzr = self.input_quantizers[0] + per_sample_weights = _quantize_if_applicable(per_sample_weights, qtzr) + + output_encodings = self.output_quantizers[0].get_encodings() if self.output_quantizers[0] else None + + return fn(input, + weight, + offsets=offsets, + max_norm=max_norm, + norm_type=norm_type, + scale_grad_by_freq=scale_grad_by_freq, + mode=mode, + sparse=sparse, + per_sample_weights=per_sample_weights, + include_last_offset=include_last_offset, + padding_idx=padding_idx, + output_encodings=output_encodings) + + return embedding_bag
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.FeatureAlphaDropout) +class QuantizedFeatureAlphaDropout(_DispatchMixin, QuantizationMixin, nn.FeatureAlphaDropout): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.FeatureAlphaDropout) + _builtin_torch_fn = F.feature_alpha_dropout + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Flatten) +class QuantizedFlatten(_DispatchMixin, QuantizationMixin, nn.Flatten): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Flatten) + def _get_builtin_torch_fn(self): + return Tensor.flatten + + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Fold) +class QuantizedFold(_DispatchMixin, QuantizationMixin, nn.Fold): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Fold) + _builtin_torch_fn = F.fold + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.FractionalMaxPool2d) +class QuantizedFractionalMaxPool2d(_DispatchMixin, QuantizationMixin, nn.FractionalMaxPool2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.FractionalMaxPool2d) + _builtin_torch_fn = F.fractional_max_pool2d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.FractionalMaxPool3d) +class QuantizedFractionalMaxPool3d(_DispatchMixin, QuantizationMixin, nn.FractionalMaxPool3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.FractionalMaxPool3d) + _builtin_torch_fn = F.fractional_max_pool3d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.GELU) +class QuantizedGELU(_DispatchMixin, QuantizationMixin, nn.GELU): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.GELU) + _builtin_torch_fn = F.gelu + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.GLU) +class QuantizedGLU(_DispatchMixin, QuantizationMixin, nn.GLU): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.GLU) + _builtin_torch_fn = F.glu + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.GRU) +class QuantizedGRU(_DispatchMixin, QuantizationMixin, nn.GRU): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.GRU) + _builtin_torch_fn = _gru + + def __quant_init__(self): + super().__quant_init__() + # pylint: disable=attribute-defined-outside-init + self.input_quantizers = nn.ModuleList([None, None]) + self.output_quantizers = nn.ModuleList([None, None]) + + def _quantize_inputs(self, args, apply): + if args[1].is_floating_point(): + input, hx, *others = args + batch_sizes = None + else: + input, batch_sizes, hx, *others = args + + input = apply(input, self.input_quantizers[0]) + hx = apply(hx, self.input_quantizers[1]) + + if batch_sizes is None: + return input, hx, *others + return input, batch_sizes, hx, *others + + def _builtin_torch_fn_helper(self, fn: Callable[..., Tensor]): + assert fn == _gru + apply = _quantize_dequantize_if_applicable + + def gru(*args): + args = self._quantize_inputs(args, apply) + output, h_n = fn(*args) + return ( + apply(output, self.output_quantizers[0]), + apply(h_n, self.output_quantizers[1]), + ) + + return gru + + def _custom_kernel_helper(self, fn: Callable[..., QuantizedTensorBase]): + apply = _quantize_if_applicable + + def gru(*args): + args = self._quantize_inputs(args, apply) + output_encodings = tuple(qtzr and qtzr.get_encodings() for qtzr in self.output_quantizers) + return fn(*args, output_encodings=output_encodings) + + return gru
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.GRUCell) +class QuantizedGRUCell(_DispatchMixin, QuantizationMixin, nn.GRUCell): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.GRUCell) + _builtin_torch_fn = _gru_cell + + def __quant_init__(self): + super().__quant_init__() + # pylint: disable=attribute-defined-outside-init + self.input_quantizers = nn.ModuleList([None, None]) + self.output_quantizers = nn.ModuleList([None]) + + def _builtin_torch_fn_helper(self, fn: Callable[..., Tensor]): + assert fn == _gru_cell + apply = _quantize_dequantize_if_applicable + + def gru_cell(input, hx, *args, **kwargs): + input = apply(input, self.input_quantizers[0]) + hx = apply(hx, self.input_quantizers[1]) + output = fn(input, hx, *args, **kwargs) + return apply(output, self.output_quantizers[0]) + + return gru_cell + + def _custom_kernel_helper(self, fn: Callable[..., QuantizedTensorBase]): + apply = _quantize_if_applicable + + def gru_cell(input, hx, *args, **kwargs): + input = apply(input, self.input_quantizers[0]) + hx = apply(hx, self.input_quantizers[1]) + output_encodings = self.output_quantizers[0] and self.output_quantizers[0].get_encodings() + return fn(input, hx, *args, **kwargs, output_encodings=output_encodings) + + return gru_cell
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.GaussianNLLLoss) +class QuantizedGaussianNLLLoss(_DispatchMixin, QuantizationMixin, nn.GaussianNLLLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.GaussianNLLLoss) + _builtin_torch_fn = F.gaussian_nll_loss + __quant_init__ = __ternary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.GroupNorm) +class QuantizedGroupNorm(_DispatchMixin, QuantizationMixin, nn.GroupNorm): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.GroupNorm) + _builtin_torch_fn = F.group_norm + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Hardshrink) +class QuantizedHardshrink(_DispatchMixin, QuantizationMixin, nn.Hardshrink): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Hardshrink) + _builtin_torch_fn = F.hardshrink + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Hardsigmoid) +class QuantizedHardsigmoid(_DispatchMixin, QuantizationMixin, nn.Hardsigmoid): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Hardsigmoid) + _builtin_torch_fn = F.hardsigmoid + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Hardswish) +class QuantizedHardswish(_DispatchMixin, QuantizationMixin, nn.Hardswish): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Hardswish) + _builtin_torch_fn = F.hardswish + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Hardtanh) +class QuantizedHardtanh(_DispatchMixin, QuantizationMixin, nn.Hardtanh): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Hardtanh) + _builtin_torch_fn = F.hardtanh + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.HingeEmbeddingLoss) +class QuantizedHingeEmbeddingLoss(_DispatchMixin, QuantizationMixin, nn.HingeEmbeddingLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.HingeEmbeddingLoss) + _builtin_torch_fn = F.hinge_embedding_loss + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.HuberLoss) +class QuantizedHuberLoss(_DispatchMixin, QuantizationMixin, nn.HuberLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.HuberLoss) + _builtin_torch_fn = F.huber_loss + __quant_init__ = __binary__
    + + + +# @QuantizationMixin.implements(nn.Identity) +# class QuantizedIdentity(_DispatchMixin, QuantizationMixin, nn.Identity): +# _builtin_torch_fn = ... + + +
    +[docs] +@QuantizationMixin.implements(nn.InstanceNorm1d) +class QuantizedInstanceNorm1d(_DispatchMixin, QuantizationMixin, nn.InstanceNorm1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.InstanceNorm1d) + _builtin_torch_fn = F.instance_norm + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.InstanceNorm2d) +class QuantizedInstanceNorm2d(_DispatchMixin, QuantizationMixin, nn.InstanceNorm2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.InstanceNorm2d) + _builtin_torch_fn = F.instance_norm + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.InstanceNorm3d) +class QuantizedInstanceNorm3d(_DispatchMixin, QuantizationMixin, nn.InstanceNorm3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.InstanceNorm3d) + _builtin_torch_fn = F.instance_norm + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.KLDivLoss) +class QuantizedKLDivLoss(_DispatchMixin, QuantizationMixin, nn.KLDivLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.KLDivLoss) + _builtin_torch_fn = F.kl_div + __quant_init__ = __binary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.L1Loss) +class QuantizedL1Loss(_DispatchMixin, QuantizationMixin, nn.L1Loss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.L1Loss) + _builtin_torch_fn = F.l1_loss + __quant_init__ = __binary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.LPPool1d) +class QuantizedLPPool1d(_DispatchMixin, QuantizationMixin, nn.LPPool1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.LPPool1d) + _builtin_torch_fn = F.lp_pool1d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.LPPool2d) +class QuantizedLPPool2d(_DispatchMixin, QuantizationMixin, nn.LPPool2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.LPPool2d) + _builtin_torch_fn = F.lp_pool2d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.LSTM) +class QuantizedLSTM(_DispatchMixin, QuantizationMixin, nn.LSTM): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.LSTM) + _builtin_torch_fn = _lstm + + def __quant_init__(self): + super().__quant_init__() + # pylint: disable=attribute-defined-outside-init + self.input_quantizers = nn.ModuleList([None, None, None]) + self.output_quantizers = nn.ModuleList([None, None, None]) + + def _quantize_inputs(self, args, apply): + if isinstance(args[1], Tensor): + input, batch_sizes, hx, *others = args + else: + input, hx, *others = args + batch_sizes = None + + input = apply(input, self.input_quantizers[0]) + h, c = hx + h_qtzr, c_qtzr = self.input_quantizers[1:] + hx = (apply(h, h_qtzr), apply(c, c_qtzr)) + + if batch_sizes is None: + return input, hx, *others + return input, batch_sizes, hx, *others + + def _builtin_torch_fn_helper(self, fn: Callable[..., Tensor]): + assert fn == _lstm + apply = _quantize_dequantize_if_applicable + + def lstm(*args): + args = self._quantize_inputs(args, apply) + output, h_n, c_n = fn(*args) + return ( + apply(output, self.output_quantizers[0]), + apply(h_n, self.output_quantizers[1]), + apply(c_n, self.output_quantizers[2]), + ) + + return lstm + + def _custom_kernel_helper(self, fn: Callable[..., QuantizedTensorBase]): + apply = _quantize_if_applicable + + def lstm(*args): + args = self._quantize_inputs(args, apply) + output_encodings = tuple(qtzr and qtzr.get_encodings() for qtzr in self.output_quantizers) + return fn(*args, output_encodings=output_encodings) + + return lstm
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.LSTMCell) +class QuantizedLSTMCell(_DispatchMixin, QuantizationMixin, nn.LSTMCell): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.LSTMCell) + _builtin_torch_fn = _lstm_cell + + def __quant_init__(self): + super().__quant_init__() + # pylint: disable=attribute-defined-outside-init + self.input_quantizers = nn.ModuleList([None, None, None]) + self.output_quantizers = nn.ModuleList([None, None]) + + def _builtin_torch_fn_helper(self, fn: Callable[..., Tensor]): + assert fn == _lstm_cell + apply = _quantize_dequantize_if_applicable + + def lstm_cell(input, hx, *args, **kwargs): + input = apply(input, self.input_quantizers[0]) + h, c = hx + h_qtzr, c_qtzr = self.input_quantizers[1:] + hx = (apply(h, h_qtzr), apply(c, c_qtzr)) + + hx, cx = fn(input, hx, *args, **kwargs) + return ( + apply(hx, self.output_quantizers[0]), + apply(cx, self.output_quantizers[1]), + ) + + return lstm_cell + + def _custom_kernel_helper(self, fn: Callable[..., QuantizedTensorBase]): + apply = _quantize_if_applicable + + def lstm_cell(input, hx, *args, **kwargs): + input = apply(input, self.input_quantizers[0]) + h, c = hx + h_qtzr, c_qtzr = self.input_quantizers[1:] + hx = (apply(h, h_qtzr), apply(c, c_qtzr)) + + output_encodings = tuple(qtzr and qtzr.get_encodings() for qtzr in self.output_quantizers) + return fn(input, hx, *args, **kwargs, output_encodings=output_encodings) + + return lstm_cell
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.LayerNorm) +class QuantizedLayerNorm(_DispatchMixin, QuantizationMixin, nn.LayerNorm): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.LayerNorm) + _builtin_torch_fn = F.layer_norm + __quant_init__ = __unary__
    + + + +# @QuantizationMixin.implements(nn.LazyBatchNorm1d) +# class QuantizedLazyBatchNorm1d(_DispatchMixin, QuantizationMixin, nn.LazyBatchNorm1d): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.LazyBatchNorm2d) +# class QuantizedLazyBatchNorm2d(_DispatchMixin, QuantizationMixin, nn.LazyBatchNorm2d): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.LazyBatchNorm3d) +# class QuantizedLazyBatchNorm3d(_DispatchMixin, QuantizationMixin, nn.LazyBatchNorm3d): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.LazyConv1d) +# class QuantizedLazyConv1d(_DispatchMixin, QuantizationMixin, nn.LazyConv1d): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.LazyConv2d) +# class QuantizedLazyConv2d(_DispatchMixin, QuantizationMixin, nn.LazyConv2d): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.LazyConv3d) +# class QuantizedLazyConv3d(_DispatchMixin, QuantizationMixin, nn.LazyConv3d): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.LazyConvTranspose1d) +# class QuantizedLazyConvTranspose1d(_DispatchMixin, QuantizationMixin, nn.LazyConvTranspose1d): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.LazyConvTranspose2d) +# class QuantizedLazyConvTranspose2d(_DispatchMixin, QuantizationMixin, nn.LazyConvTranspose2d): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.LazyConvTranspose3d) +# class QuantizedLazyConvTranspose3d(_DispatchMixin, QuantizationMixin, nn.LazyConvTranspose3d): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.LazyInstanceNorm1d) +# class QuantizedLazyInstanceNorm1d(_DispatchMixin, QuantizationMixin, nn.LazyInstanceNorm1d): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.LazyInstanceNorm2d) +# class QuantizedLazyInstanceNorm2d(_DispatchMixin, QuantizationMixin, nn.LazyInstanceNorm2d): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.LazyInstanceNorm3d) +# class QuantizedLazyInstanceNorm3d(_DispatchMixin, QuantizationMixin, nn.LazyInstanceNorm3d): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.LazyLinear) +# class QuantizedLazyLinear(_DispatchMixin, QuantizationMixin, nn.LazyLinear): +# _builtin_torch_fn = ... + + +
    +[docs] +@QuantizationMixin.implements(nn.LeakyReLU) +class QuantizedLeakyReLU(_DispatchMixin, QuantizationMixin, nn.LeakyReLU): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.LeakyReLU) + _builtin_torch_fn = F.leaky_relu + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Linear) +class QuantizedLinear(_DispatchMixin, QuantizationMixin, nn.Linear): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Linear) + _builtin_torch_fn = F.linear + __quant_init__ = __unary__ + + # Only allow activation recompute (a.k.a activation checkpointing) for QuantizedLinear. + # This is mainly to reduce memory footprint of QAT of large language models. +
    +[docs] + @allow_recompute + def forward(self, *args, **kwargs): + # Workaround for deepspeed. + # Deepspeed zero3 sometimes forcefully mokey-patches F.linear to torch.addmm, + # which collides with the core assumption of our dispatch mechanism + # that nn.Linear invokes F.linear. + # To circumvent this issue, we temporarily restore the original F.linear + # before running forward. + with patch_attr(F, 'linear', type(self)._builtin_torch_fn): + return super().forward(*args, **kwargs)
    +
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.LocalResponseNorm) +class QuantizedLocalResponseNorm(_DispatchMixin, QuantizationMixin, nn.LocalResponseNorm): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.LocalResponseNorm) + _builtin_torch_fn = F.local_response_norm + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.LogSigmoid) +class QuantizedLogSigmoid(_DispatchMixin, QuantizationMixin, nn.LogSigmoid): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.LogSigmoid) + _builtin_torch_fn = F.logsigmoid + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.LogSoftmax) +class QuantizedLogSoftmax(_DispatchMixin, QuantizationMixin, nn.LogSoftmax): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.LogSoftmax) + _builtin_torch_fn = F.log_softmax + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.MSELoss) +class QuantizedMSELoss(_DispatchMixin, QuantizationMixin, nn.MSELoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.MSELoss) + _builtin_torch_fn = F.mse_loss + __quant_init__ = __binary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.MarginRankingLoss) +class QuantizedMarginRankingLoss(_DispatchMixin, QuantizationMixin, nn.MarginRankingLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.MarginRankingLoss) + _builtin_torch_fn = F.margin_ranking_loss + __quant_init__ = __binary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.MaxPool1d) +class QuantizedMaxPool1d(_DispatchMixin, QuantizationMixin, nn.MaxPool1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.MaxPool1d) + _builtin_torch_fn = F.max_pool1d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.MaxPool2d) +class QuantizedMaxPool2d(_DispatchMixin, QuantizationMixin, nn.MaxPool2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.MaxPool2d) + _builtin_torch_fn = F.max_pool2d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.MaxPool3d) +class QuantizedMaxPool3d(_DispatchMixin, QuantizationMixin, nn.MaxPool3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.MaxPool3d) + _builtin_torch_fn = F.max_pool3d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.MaxUnpool1d) +class QuantizedMaxUnpool1d(_DispatchMixin, QuantizationMixin, nn.MaxUnpool1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.MaxUnpool1d) + _builtin_torch_fn = F.max_unpool1d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.MaxUnpool2d) +class QuantizedMaxUnpool2d(_DispatchMixin, QuantizationMixin, nn.MaxUnpool2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.MaxUnpool2d) + _builtin_torch_fn = F.max_unpool2d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.MaxUnpool3d) +class QuantizedMaxUnpool3d(_DispatchMixin, QuantizationMixin, nn.MaxUnpool3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.MaxUnpool3d) + _builtin_torch_fn = F.max_unpool3d + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Mish) +class QuantizedMish(_DispatchMixin, QuantizationMixin, nn.Mish): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Mish) + _builtin_torch_fn = F.mish + __quant_init__ = __unary__
    + + + +# @QuantizationMixin.implements(nn.Module) +# class QuantizedModule(_DispatchMixin, QuantizationMixin, nn.Module): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.ModuleDict) +# class QuantizedModuleDict(_DispatchMixin, QuantizationMixin, nn.ModuleDict): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.ModuleList) +# class QuantizedModuleList(_DispatchMixin, QuantizationMixin, nn.ModuleList): +# _builtin_torch_fn = ... + + +
    +[docs] +@QuantizationMixin.implements(nn.MultiLabelMarginLoss) +class QuantizedMultiLabelMarginLoss(_DispatchMixin, QuantizationMixin, nn.MultiLabelMarginLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.MultiLabelMarginLoss) + _builtin_torch_fn = F.multilabel_margin_loss + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.MultiLabelSoftMarginLoss) +class QuantizedMultiLabelSoftMarginLoss(_DispatchMixin, QuantizationMixin, nn.MultiLabelSoftMarginLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.MultiLabelSoftMarginLoss) + _builtin_torch_fn = F.multilabel_soft_margin_loss + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.MultiMarginLoss) +class QuantizedMultiMarginLoss(_DispatchMixin, QuantizationMixin, nn.MultiMarginLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.MultiMarginLoss) + _builtin_torch_fn = F.multi_margin_loss + __quant_init__ = __unary__
    + + + +# @QuantizationMixin.implements(nn.MultiheadAttention) +# class QuantizedMultiheadAttention(_DispatchMixin, QuantizationMixin, nn.MultiheadAttention): +# _builtin_torch_fn = ... + + +
    +[docs] +@QuantizationMixin.implements(nn.NLLLoss) +class QuantizedNLLLoss(_DispatchMixin, QuantizationMixin, nn.NLLLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.NLLLoss) + _builtin_torch_fn = F.nll_loss + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.NLLLoss2d) +class QuantizedNLLLoss2d(_DispatchMixin, QuantizationMixin, nn.NLLLoss2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.NLLLoss2d) + _builtin_torch_fn = F.nll_loss + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.PReLU) +class QuantizedPReLU(_DispatchMixin, QuantizationMixin, nn.PReLU): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.PReLU) + _builtin_torch_fn = F.prelu + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.PairwiseDistance) +class QuantizedPairwiseDistance(_DispatchMixin, QuantizationMixin, nn.PairwiseDistance): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.PairwiseDistance) + _builtin_torch_fn = F.pairwise_distance + __quant_init__ = __binary__
    + + + +# @QuantizationMixin.implements(nn.ParameterDict) +# class QuantizedParameterDict(_DispatchMixin, QuantizationMixin, nn.ParameterDict): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.ParameterList) +# class QuantizedParameterList(_DispatchMixin, QuantizationMixin, nn.ParameterList): +# _builtin_torch_fn = ... + + +
    +[docs] +@QuantizationMixin.implements(nn.PixelShuffle) +class QuantizedPixelShuffle(_DispatchMixin, QuantizationMixin, nn.PixelShuffle): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.PixelShuffle) + _builtin_torch_fn = F.pixel_shuffle + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.PixelUnshuffle) +class QuantizedPixelUnshuffle(_DispatchMixin, QuantizationMixin, nn.PixelUnshuffle): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.PixelUnshuffle) + _builtin_torch_fn = F.pixel_unshuffle + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.PoissonNLLLoss) +class QuantizedPoissonNLLLoss(_DispatchMixin, QuantizationMixin, nn.PoissonNLLLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.PoissonNLLLoss) + _builtin_torch_fn = F.poisson_nll_loss + __quant_init__ = __binary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.RNN) +class QuantizedRNN(_DispatchMixin, QuantizationMixin, nn.RNN): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.RNN) + def _get_builtin_torch_fn(self): + assert self.mode in ('RNN_TANH', 'RNN_RELU') + if self.mode == 'RNN_TANH': + return _rnn_tanh + return _rnn_relu + + def __quant_init__(self): + super().__quant_init__() + # pylint: disable=attribute-defined-outside-init + self.input_quantizers = nn.ModuleList([None, None]) + self.output_quantizers = nn.ModuleList([None, None]) + + def _quantize_inputs(self, args, apply): + if args[1].is_floating_point(): + input, hx, *others = args + batch_sizes = None + else: + input, batch_sizes, hx, *others = args + + input = apply(input, self.input_quantizers[0]) + hx = apply(hx, self.input_quantizers[1]) + + if batch_sizes is None: + return input, hx, *others + return input, batch_sizes, hx, *others + + def _builtin_torch_fn_helper(self, fn: Callable[..., Tensor]): + assert fn in (_rnn_tanh, _rnn_relu) + apply = _quantize_dequantize_if_applicable + + def rnn(*args): + args = self._quantize_inputs(args, apply) + output, h_n = fn(*args) + return ( + apply(output, self.output_quantizers[0]), + apply(h_n, self.output_quantizers[1]), + ) + + return rnn + + def _custom_kernel_helper(self, fn: Callable[..., QuantizedTensorBase]): + apply = _quantize_if_applicable + + def rnn(*args): + args = self._quantize_inputs(args, apply) + output_encodings = tuple(qtzr and qtzr.get_encodings() for qtzr in self.output_quantizers) + return fn(*args, output_encodings=output_encodings) + + return rnn
    + + + +# @QuantizationMixin.implements(nn.RNNBase) +# class QuantizedRNNBase(_DispatchMixin, QuantizationMixin, nn.RNNBase): +# _builtin_torch_fn = ... + + +
    +[docs] +@QuantizationMixin.implements(nn.RNNCell) +class QuantizedRNNCell(_DispatchMixin, QuantizationMixin, nn.RNNCell): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.RNNCell) + def _get_builtin_torch_fn(self): + assert self.nonlinearity in ("tanh", "relu") + + if self.nonlinearity == "tanh": + return _rnn_tanh_cell + return _rnn_relu_cell + + def __quant_init__(self): + super().__quant_init__() + # pylint: disable=attribute-defined-outside-init + self.input_quantizers = nn.ModuleList([None, None]) + self.output_quantizers = nn.ModuleList([None]) + + def _builtin_torch_fn_helper(self, fn: Callable[..., Tensor]): + assert fn in (_rnn_tanh_cell, _rnn_relu_cell) + apply = _quantize_dequantize_if_applicable + + def rnn_cell(input, hx, *args, **kwargs): + input = apply(input, self.input_quantizers[0]) + hx = apply(hx, self.input_quantizers[1]) + output = fn(input, hx, *args, **kwargs) + return apply(output, self.output_quantizers[0]) + + return rnn_cell + + def _custom_kernel_helper(self, fn: Callable[..., QuantizedTensorBase]): + apply = _quantize_if_applicable + + def rnn_cell(input, hx, *args, **kwargs): + input = apply(input, self.input_quantizers[0]) + hx = apply(hx, self.input_quantizers[1]) + output_encodings = self.output_quantizers[0] and self.output_quantizers[0].get_encodings() + return fn(input, hx, *args, **kwargs, output_encodings=output_encodings) + + return rnn_cell
    + + + +# @QuantizationMixin.implements(nn.RNNCellBase) +# class QuantizedRNNCellBase(_DispatchMixin, QuantizationMixin, nn.RNNCellBase): +# _builtin_torch_fn = ... + + +
    +[docs] +@QuantizationMixin.implements(nn.RReLU) +class QuantizedRReLU(_DispatchMixin, QuantizationMixin, nn.RReLU): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.RReLU) + _builtin_torch_fn = F.rrelu + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ReLU) +class QuantizedReLU(_DispatchMixin, QuantizationMixin, nn.ReLU): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ReLU) + _builtin_torch_fn = F.relu + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ReLU6) +class QuantizedReLU6(_DispatchMixin, QuantizationMixin, nn.ReLU6): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ReLU6) + _builtin_torch_fn = F.hardtanh + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ReflectionPad1d) +class QuantizedReflectionPad1d(_DispatchMixin, QuantizationMixin, nn.ReflectionPad1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ReflectionPad1d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ReflectionPad2d) +class QuantizedReflectionPad2d(_DispatchMixin, QuantizationMixin, nn.ReflectionPad2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ReflectionPad2d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +if version.parse(torch.__version__) >= version.parse("1.10.0"): +
    +[docs] + @QuantizationMixin.implements(nn.ReflectionPad3d) + class QuantizedReflectionPad3d(_DispatchMixin, QuantizationMixin, nn.ReflectionPad3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ReflectionPad3d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ReplicationPad1d) +class QuantizedReplicationPad1d(_DispatchMixin, QuantizationMixin, nn.ReplicationPad1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ReplicationPad1d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ReplicationPad2d) +class QuantizedReplicationPad2d(_DispatchMixin, QuantizationMixin, nn.ReplicationPad2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ReplicationPad2d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ReplicationPad3d) +class QuantizedReplicationPad3d(_DispatchMixin, QuantizationMixin, nn.ReplicationPad3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ReplicationPad3d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.SELU) +class QuantizedSELU(_DispatchMixin, QuantizationMixin, nn.SELU): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.SELU) + _builtin_torch_fn = F.selu + __quant_init__ = __unary__
    + + + +# @QuantizationMixin.implements(nn.Sequential) +# class QuantizedSequential(_DispatchMixin, QuantizationMixin, nn.Sequential): +# _builtin_torch_fn = ... + + +
    +[docs] +@QuantizationMixin.implements(nn.SiLU) +class QuantizedSiLU(_DispatchMixin, QuantizationMixin, nn.SiLU): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.SiLU) + _builtin_torch_fn = F.silu + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Sigmoid) +class QuantizedSigmoid(_DispatchMixin, QuantizationMixin, nn.Sigmoid): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Sigmoid) + _builtin_torch_fn = torch.sigmoid + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.SmoothL1Loss) +class QuantizedSmoothL1Loss(_DispatchMixin, QuantizationMixin, nn.SmoothL1Loss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.SmoothL1Loss) + _builtin_torch_fn = F.smooth_l1_loss + __quant_init__ = __binary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.SoftMarginLoss) +class QuantizedSoftMarginLoss(_DispatchMixin, QuantizationMixin, nn.SoftMarginLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.SoftMarginLoss) + _builtin_torch_fn = F.soft_margin_loss + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Softmax) +class QuantizedSoftmax(_DispatchMixin, QuantizationMixin, nn.Softmax): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Softmax) + _builtin_torch_fn = F.softmax + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Softmax2d) +class QuantizedSoftmax2d(_DispatchMixin, QuantizationMixin, nn.Softmax2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Softmax2d) + _builtin_torch_fn = F.softmax + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Softmin) +class QuantizedSoftmin(_DispatchMixin, QuantizationMixin, nn.Softmin): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Softmin) + _builtin_torch_fn = F.softmin + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Softplus) +class QuantizedSoftplus(_DispatchMixin, QuantizationMixin, nn.Softplus): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Softplus) + _builtin_torch_fn = F.softplus + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Softshrink) +class QuantizedSoftshrink(_DispatchMixin, QuantizationMixin, nn.Softshrink): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Softshrink) + _builtin_torch_fn = F.softshrink + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Softsign) +class QuantizedSoftsign(_DispatchMixin, QuantizationMixin, nn.Softsign): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Softsign) + _builtin_torch_fn = F.softsign + __quant_init__ = __unary__
    + + + +# @QuantizationMixin.implements(nn.SyncBatchNorm) +# class QuantizedSyncBatchNorm(_DispatchMixin, QuantizationMixin, nn.SyncBatchNorm): +# _builtin_torch_fn = ... + + +
    +[docs] +@QuantizationMixin.implements(nn.Tanh) +class QuantizedTanh(_DispatchMixin, QuantizationMixin, nn.Tanh): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Tanh) + _builtin_torch_fn = torch.tanh + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Tanhshrink) +class QuantizedTanhshrink(_DispatchMixin, QuantizationMixin, nn.Tanhshrink): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Tanhshrink) + _builtin_torch_fn = F.tanhshrink + __quant_init__ = __unary__
    + + + +# @QuantizationMixin.implements(nn.Threshold) +
    +[docs] +@QuantizationMixin.implements(nn.Threshold) +class QuantizedThreshold(_DispatchMixin, QuantizationMixin, nn.Threshold): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Threshold) + _builtin_torch_fn = F.threshold + __quant_init__ = __unary__
    + + + +# @QuantizationMixin.implements(nn.Transformer) +# class QuantizedTransformer(_DispatchMixin, QuantizationMixin, nn.Transformer): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.TransformerDecoder) +# class QuantizedTransformerDecoder(_DispatchMixin, QuantizationMixin, nn.TransformerDecoder): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.TransformerDecoderLayer) +# class QuantizedTransformerDecoderLayer(_DispatchMixin, QuantizationMixin, nn.TransformerDecoderLayer): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.TransformerEncoder) +# class QuantizedTransformerEncoder(_DispatchMixin, QuantizationMixin, nn.TransformerEncoder): +# _builtin_torch_fn = ... + + +# @QuantizationMixin.implements(nn.TransformerEncoderLayer) +# class QuantizedTransformerEncoderLayer(_DispatchMixin, QuantizationMixin, nn.TransformerEncoderLayer): +# _builtin_torch_fn = ... + + +
    +[docs] +@QuantizationMixin.implements(nn.TripletMarginLoss) +class QuantizedTripletMarginLoss(_DispatchMixin, QuantizationMixin, nn.TripletMarginLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.TripletMarginLoss) + _builtin_torch_fn = F.triplet_margin_loss + __quant_init__ = __ternary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.TripletMarginWithDistanceLoss) +class QuantizedTripletMarginWithDistanceLoss(_DispatchMixin, QuantizationMixin, nn.TripletMarginWithDistanceLoss): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.TripletMarginWithDistanceLoss) + _builtin_torch_fn = F.triplet_margin_with_distance_loss + __quant_init__ = __ternary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Unflatten) +class QuantizedUnflatten(_DispatchMixin, QuantizationMixin, nn.Unflatten): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Unflatten) + def _get_builtin_torch_fn(self): + return Tensor.unflatten
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Unfold) +class QuantizedUnfold(_DispatchMixin, QuantizationMixin, nn.Unfold): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Unfold) + _builtin_torch_fn = F.unfold + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.Upsample) +class QuantizedUpsample(_DispatchMixin, QuantizationMixin, nn.Upsample): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.Upsample) + _builtin_torch_fn = F.interpolate + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.UpsamplingBilinear2d) +class QuantizedUpsamplingBilinear2d(_DispatchMixin, QuantizationMixin, nn.UpsamplingBilinear2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.UpsamplingBilinear2d) + _builtin_torch_fn = F.interpolate + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.UpsamplingNearest2d) +class QuantizedUpsamplingNearest2d(_DispatchMixin, QuantizationMixin, nn.UpsamplingNearest2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.UpsamplingNearest2d) + _builtin_torch_fn = F.interpolate + __quant_init__ = __unary__
    + + + +if version.parse(torch.__version__) >= version.parse("2.1.0"): +
    +[docs] + @QuantizationMixin.implements(nn.ZeroPad1d) + class QuantizedZeroPad1d(_DispatchMixin, QuantizationMixin, nn.ZeroPad1d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ZeroPad1d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +
    +[docs] +@QuantizationMixin.implements(nn.ZeroPad2d) +class QuantizedZeroPad2d(_DispatchMixin, QuantizationMixin, nn.ZeroPad2d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ZeroPad2d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +if version.parse(torch.__version__) >= version.parse("2.1.0"): +
    +[docs] + @QuantizationMixin.implements(nn.ZeroPad3d) + class QuantizedZeroPad3d(_DispatchMixin, QuantizationMixin, nn.ZeroPad3d): + # pylint: disable=missing-class-docstring + __doc__ = _generate_docstring(parent_cls=nn.ZeroPad3d) + _builtin_torch_fn = F.pad + __quant_init__ = __unary__
    + + + +del __nullary__ +del __unary__ +del __binary__ +del __ternary__ +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v2/quant_analyzer.html b/releases/2.0.0/_modules/aimet_torch/v2/quant_analyzer.html new file mode 100644 index 0000000..48ec50a --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v2/quant_analyzer.html @@ -0,0 +1,503 @@ + + + + + + + + aimet_torch.v2.quant_analyzer - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v2.quant_analyzer

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Quant Analyzer for AIMET v2"""
    +
    +import os
    +import contextlib
    +from collections import namedtuple
    +from typing import Tuple, List, Type, Optional, Generator
    +import torch
    +
    +from aimet_common.quant_analyzer import export_stats_histogram_plot
    +from aimet_torch._base.quant_analyzer import QuantAnalyzerBase
    +from aimet_torch.v2.quantsim import QuantizationSimModel
    +from aimet_torch.v2.nn.base import BaseQuantizationMixin
    +from aimet_torch.v2.quantization.base import QuantizerBase
    +from aimet_torch.v2.quantization.encoding_analyzer import _HistogramObserver, _Histogram
    +from aimet_torch.v2.batch_norm_fold import fold_all_batch_norms
    +
    +
    +V1Encoding = namedtuple('V1Encoding', ['min', 'max'])
    +
    +
    +
    +[docs] +class QuantAnalyzer(QuantAnalyzerBase): + """ + QuantAnalyzer tool provides + + 1) model sensitivity to weight and activation quantization + 2) per layer sensitivity analysis + 3) per layer encoding (min - max range) + 4) per PDF analysis and + 5) per layer MSE analysis + """ + @staticmethod + def _get_quantsim_cls() -> Type[QuantizationSimModel]: + return QuantizationSimModel + + @staticmethod + def _get_quant_wrapper_type() -> Tuple[Type]: + return (BaseQuantizationMixin,) + + # pylint: disable=no-self-use + def _create_and_export_stats_histogram_plot(self, + quantizer: QuantizerBase, + results_dir: str, + title: str, + ): + """ + For given quantizer, create and export histogram (PDF) of statistics in html format. + + :param quantizer: Quantizer. + :param results_dir: Directory to save the results. + :param title: Title of the plot. + """ + os.makedirs(results_dir, exist_ok=True) + + assert isinstance(quantizer.encoding_analyzer.observer, _HistogramObserver) + v2_histograms = quantizer.encoding_analyzer.observer.get_stats() + histograms = self._convert_to_v1_histograms(v2_histograms) + encodings = self._get_quantizer_encodings(quantizer) + + for index, (histogram, encoding) in enumerate(zip(histograms, encodings)): + export_stats_histogram_plot(histogram, encoding, results_dir, title=f"{title}_{index}") + + @staticmethod + def _enable_disable_quantizers(quantizers: List[QuantizerBase], enabled: bool): + """ + For given list of quantizers, set (enable/disable) quantizer's enabled. + + :param quantizers: List of quantizers. + :param enabled: Enabled flag. + """ + raise RuntimeError("Changing enabled attribute is not allowed in quantsim v2") + + @classmethod + def _disable_param_quantizers(cls, sim: QuantizationSimModel): + # pylint: disable=protected-access + ctx = contextlib.ExitStack() + for quant_wrapper in cls._get_quantized_modules(sim): + ctx.enter_context(quant_wrapper._remove_param_quantizers()) + return ctx + + @classmethod + def _disable_activation_quantizers(cls, sim: QuantizationSimModel): + # pylint: disable=protected-access + ctx = contextlib.ExitStack() + for quant_wrapper in cls._get_quantized_modules(sim): + ctx.enter_context(quant_wrapper._remove_activation_quantizers()) + return ctx + + @staticmethod + def _disable_quant_wrapper(module: BaseQuantizationMixin): + # pylint: disable=protected-access + return module._remove_all_quantizers() + + @staticmethod + def _convert_to_v1_histograms(histograms: List[_Histogram]) -> List: + v1_histograms = [] + for hist in histograms: + assert hist is not None, "Cannot find histogram data in quantizer" + hist_sum = torch.sum(hist.histogram).item() + v1_hist = [] + for bin_edge, hist_value in zip(hist.bin_edges, hist.histogram): + v1_hist.append((bin_edge.item(), hist_value.item() / hist_sum)) + v1_histograms.append(v1_hist) + + return v1_histograms + + @staticmethod + def _is_quantizer_enabled(quantizer: Optional[QuantizerBase]): + return quantizer is not None + + @classmethod + def _get_quantizer_encodings(cls, quantizer: QuantizerBase) -> Optional[List]: + v1_encodings = [] + + encoding = quantizer.get_encodings() + if not encoding: + return None + + flatten_min = encoding.min.flatten() + flatten_max = encoding.max.flatten() + + for encoding_min, encoding_max in zip(flatten_min, flatten_max): + v1_encodings.append(V1Encoding(min=encoding_min.item(), max=encoding_max.item())) + + return v1_encodings + + @staticmethod + def _get_quantized_modules(sim: QuantizationSimModel) -> Generator[BaseQuantizationMixin, None, None]: + for module in sim.model.modules(): + if isinstance(module, BaseQuantizationMixin): + yield module + + @staticmethod + def _fold_all_batch_norms(*args, **kwargs): + return fold_all_batch_norms(*args, **kwargs)
    + +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v2/quantization/affine/backends.html b/releases/2.0.0/_modules/aimet_torch/v2/quantization/affine/backends.html new file mode 100644 index 0000000..9af5dfb --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v2/quantization/affine/backends.html @@ -0,0 +1,730 @@ + + + + + + + + aimet_torch.v2.quantization.affine.backends - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v2.quantization.affine.backends

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +# pylint: disable=all
    +
    +import math
    +from itertools import chain, repeat
    +from typing import overload, Union, Tuple, Optional
    +import torch
    +from .utils import *
    +
    +
    +@overload
    +def quantize(tensor: torch.Tensor, scale: torch.Tensor, offset: torch.Tensor,
    +             bitwidth: Union[int, float], signed: bool = False,
    +             block_size: Optional[Tuple[int, ...]] = None):
    +    ...
    +
    +@overload
    +def quantize(tensor: torch.Tensor, scale: torch.Tensor, offset: torch.Tensor, *,
    +             num_steps: int, signed: bool = False, block_size: Optional[Tuple[int, ...]] = None):
    +    ...
    +
    +@overload
    +def quantize(tensor: torch.Tensor, scale: torch.Tensor, offset: torch.Tensor,
    +             qmin: int, qmax: int, block_size: Optional[Tuple[int, ...]] = None):
    +    ...
    +
    +
    +
    +[docs] +def quantize(tensor: torch.Tensor, scale: torch.Tensor, offset: torch.Tensor, + *args, **kwargs): + r""" + Applies quantization to the input. + + Precisely, + + .. math:: + out = clamp\left(\left\lceil\frac{input}{scale}\right\rfloor - offset, qmin, qmax\right) + + If block size :math:`B = \begin{pmatrix} B_0 & B_1 & \cdots & B_{D-1} \end{pmatrix}` is specified, + this equation will be further generalized as + + .. math:: + out_{j_0 \cdots j_{D-1}} & = clamp\left( + \left\lceil\frac{input_{j_0 \cdots j_{D-1}}}{scale_{i_0 \cdots i_{D-1}}}\right\rfloor + - offset_{i_0 \cdots i_{D-1}}, qmin, qmax\right)\\ + + \text{where} \quad \forall_{0 \leq d < D} \quad i_d = \left\lfloor \frac{j_d}{B_d} \right\rfloor + + This function is overloaded with the signatures listed below: + + + .. function:: quantize(tensor, scale, offset, bitwidth, signed=False, block_size=None) + :noindex: + + Equivalent to: + + .. math:: + qmin= + \begin{cases} + -\left\lceil\frac{2^{bitwidth}-1}{2}\right\rceil,& \text{if } signed\\ + 0, & \text{otherwise (default)} + \end{cases} + qmax= + \begin{cases} + \left\lfloor\frac{2^{bitwidth}-1}{2}\right\rfloor,& \text{if } signed\\ + 2^{bitwidth}-1, & \text{otherwise (default)} + \end{cases} + + :param Tensor tensor: Tensor to quantize + :param Tensor scale: Scale for quantization + :param Tensor offset: Offset for quantization + :param int bitwidth: Bitwidth of quantized tensor based on which :math:`qmin` and :math:`qmax` will be derived + :param bool signed: If false, the output will be mapped to positive integers only. + Otherwise, it will range over both positive and negative integers. + :param block_size: Block size + :type block_size: Tuple[int, ...], optional + + .. function:: quantize(tensor, scale, offset, *, num_steps, signed=False, block_size=None) + :noindex: + + Equivalent to: + + .. math:: + qmin= + \begin{cases} + -\left\lceil\frac{num\_steps}{2}\right\rceil,& \text{if } signed\\ + 0, & \text{otherwise (default)} + \end{cases} + qmax= + \begin{cases} + \left\lfloor\frac{num\_steps}{2}\right\rfloor,& \text{if } signed\\ + num\_steps, & \text{otherwise (default)} + \end{cases} + + + :param Tensor tensor: Tensor to quantize + :param Tensor scale: Scale for quantization + :param Tensor offset: Offset for quantization + :param int num_steps: The number of steps in the quantization range based on which :math:`qmin` and :math:`qmax` will be derived + :param bool signed: If false, the output will be mapped to positive integers only. + Otherwise, it will range over both positive and negative integers. + :param block_size: Block size + :type block_size: Tuple[int, ...], optional + + .. function:: quantize(tensor, scale, offset, *, qmin, qmax, block_size=None) + :noindex: + + :param Tensor tensor: Tensor to quantize + :param Tensor scale: Scale for quantization + :param Tensor offset: Offset for quantization + :param int qmin: Minimum value of the quantization range + :param int qmax: Maximum value of the quantization range + :param block_size: Block size + :type block_size: Tuple[int, ...], optional + + + Examples: + + >>> import aimet_torch.v2.quantization as Q + >>> input = torch.arange(start=-0.3, end=1.3, step=0.05) + >>> print(input) + tensor([-3.0000e-01, -2.5000e-01, -2.0000e-01, -1.5000e-01, -1.0000e-01, + -5.0000e-02, -1.1921e-08, 5.0000e-02, 1.0000e-01, 1.5000e-01, + 2.0000e-01, 2.5000e-01, 3.0000e-01, 3.5000e-01, 4.0000e-01, + 4.5000e-01, 5.0000e-01, 5.5000e-01, 6.0000e-01, 6.5000e-01, + 7.0000e-01, 7.5000e-01, 8.0000e-01, 8.5000e-01, 9.0000e-01, + 9.5000e-01, 1.0000e+00, 1.0500e+00, 1.1000e+00, 1.1500e+00, + 1.2000e+00, 1.2500e+00]) + >>> scale = torch.tensor(1/15) + >>> offset = torch.tensor(0.0) + >>> Q.affine.quantize(input, scale, offset, bitwidth=4) + tensor([ 0., 0., 0., 0., 0., 0., -0., 1., 2., 2., 3., 4., 4., 5., + 6., 7., 7., 8., 9., 10., 10., 11., 12., 13., 13., 14., 15., 15., + 15., 15., 15., 15.]) + >>> Q.affine.quantize(input, scale, offset, num_steps=15) + tensor([ 0., 0., 0., 0., 0., 0., -0., 1., 2., 2., 3., 4., 4., 5., + 6., 7., 7., 8., 9., 10., 10., 11., 12., 13., 13., 14., 15., 15., + 15., 15., 15., 15.]) + >>> Q.affine.quantize(input, scale, offset, qmin=0, qmax=15) + tensor([ 0., 0., 0., 0., 0., 0., -0., 1., 2., 2., 3., 4., 4., 5., + 6., 7., 7., 8., 9., 10., 10., 11., 12., 13., 13., 14., 15., 15., + 15., 15., 15., 15.]) + """ + qmin, qmax, block_size = _parse_args(args, kwargs) + return get_backend().quantize(tensor, scale, offset, qmin, qmax, block_size)
    + + + +@overload +def quantize_dequantize(tensor: torch.Tensor, scale: torch.Tensor, offset: torch.Tensor, + bitwidth: Union[int, float], signed: bool = False, + block_size: Optional[Tuple[int, ...]] = None): + ... + +@overload +def quantize_dequantize(tensor: torch.Tensor, scale: torch.Tensor, offset: torch.Tensor, *, + num_steps: int, signed: bool = False, block_size: Optional[Tuple[int, ...]] = None): + ... + +@overload +def quantize_dequantize(tensor: torch.Tensor, scale: torch.Tensor, offset: torch.Tensor, + qmin: int, qmax: int, block_size: Optional[Tuple[int, ...]] = None): + ... + + +
    +[docs] +def quantize_dequantize(tensor: torch.Tensor, scale: torch.Tensor, offset: torch.Tensor, + *args, **kwargs): + r""" + Applies fake-quantization by quantizing and dequantizing the input. + + Precisely, + + .. math:: + out = (\overline{input} + offset) * scale + + where + + .. math:: + \overline{input} = clamp\left(\left\lceil\frac{input}{scale}\right\rfloor - offset, qmin, qmax\right) + + + If block size :math:`B = \begin{pmatrix} B_0 & B_1 & \cdots & B_{D-1} \end{pmatrix}` is specified, + this equation will be further generalized as + + .. math:: + out_{j_0 \cdots j_{D-1}} &= (\overline{input}_{j_0 \cdots j_{D-1}} + offset_{i_0 \cdots i_{D-1}}) * scale_{i_0 \cdots i_{D-1}}\\ + \overline{input}_{j_0 \cdots j_{D-1}} &= clamp\left( + \left\lceil\frac{input_{j_0 \cdots j_{D-1}}}{scale_{i_0 \cdots i_{D-1}}}\right\rfloor + - offset_{i_0 \cdots i_{D-1}}, qmin, qmax\right)\\ + + \text{where } \quad \forall_{0 \leq d < D} \quad i_d = \left\lfloor \frac{j_d}{B_d} \right\rfloor + + + This function is overloaded with the signatures listed below: + + + .. function:: quantize_dequantize(tensor, scale, offset, bitwidth, signed=False, block_size=None) + :noindex: + + Equivalent to: + + .. math:: + qmin= + \begin{cases} + -\left\lceil\frac{2^{bitwidth}-1}{2}\right\rceil,& \text{if } signed\\ + 0, & \text{otherwise (default)} + \end{cases} + qmax= + \begin{cases} + \left\lfloor\frac{2^{bitwidth}-1}{2}\right\rfloor,& \text{if } signed\\ + 2^{bitwidth}-1, & \text{otherwise (default)} + \end{cases} + + :param Tensor tensor: Tensor to quantize + :param Tensor scale: Scale for quantization + :param Tensor offset: Offset for quantization + :param int bitwidth: Bitwidth of quantized tensor based on which :math:`qmin` and :math:`qmax` will be derived + :param bool signed: If false, :math:`\overline{input}` will be mapped to positive integers only. + Otherwise, :math:`\overline{input}` will range over both positive and negative integers. + :param block_size: Block size + :type block_size: Tuple[int, ...], optional + + .. function:: quantize_dequantize(tensor, scale, offset, *, num_steps, signed=False, block_size=None) + :noindex: + + Equivalent to: + + .. math:: + qmin= + \begin{cases} + -\left\lceil\frac{num\_steps}{2}\right\rceil,& \text{if } signed\\ + 0, & \text{otherwise (default)} + \end{cases} + qmax= + \begin{cases} + \left\lfloor\frac{num\_steps}{2}\right\rfloor,& \text{if } signed\\ + num\_steps, & \text{otherwise (default)} + \end{cases} + + + :param Tensor tensor: Tensor to quantize + :param Tensor scale: Scale for quantization + :param Tensor offset: Offset for quantization + :param int num_steps: The number of steps in the quantization range based on which :math:`qmin` and :math:`qmax` will be derived + :param bool signed: If false, :math:`\overline{input}` will be mapped to positive integers only. + Otherwise, :math:`\overline{input}` will range over both positive and negative integers. + :param block_size: Block size + :type block_size: Tuple[int, ...], optional + + .. function:: quantize_dequantize(tensor, scale, offset, *, qmin, qmax, block_size=None) + :noindex: + + :param Tensor tensor: Tensor to quantize + :param Tensor scale: Scale for quantization + :param Tensor offset: Offset for quantization + :param int qmin: Minimum value of the quantization range + :param int qmax: Maximum value of the quantization range + :param block_size: Block size + :type block_size: Tuple[int, ...], optional + + + Examples: + + >>> import aimet_torch.v2.quantization as Q + >>> input = torch.arange(start=-0.3, end=1.3, step=0.05) + >>> print(input) + tensor([-3.0000e-01, -2.5000e-01, -2.0000e-01, -1.5000e-01, -1.0000e-01, + -5.0000e-02, -1.1921e-08, 5.0000e-02, 1.0000e-01, 1.5000e-01, + 2.0000e-01, 2.5000e-01, 3.0000e-01, 3.5000e-01, 4.0000e-01, + 4.5000e-01, 5.0000e-01, 5.5000e-01, 6.0000e-01, 6.5000e-01, + 7.0000e-01, 7.5000e-01, 8.0000e-01, 8.5000e-01, 9.0000e-01, + 9.5000e-01, 1.0000e+00, 1.0500e+00, 1.1000e+00, 1.1500e+00, + 1.2000e+00, 1.2500e+00]) + >>> scale = torch.tensor(1/15) + >>> offset = torch.tensor(0.0) + >>> Q.affine.quantize_dequantize(input, scale, offset, bitwidth=4) + tensor([0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0667, 0.1333, + 0.1333, 0.2000, 0.2667, 0.2667, 0.3333, 0.4000, 0.4667, 0.4667, 0.5333, + 0.6000, 0.6667, 0.6667, 0.7333, 0.8000, 0.8667, 0.8667, 0.9333, 1.0000, + 1.0000, 1.0000, 1.0000, 1.0000, 1.0000]) + >>> Q.affine.quantize_dequantize(input, scale, offset, num_steps=15) + tensor([0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0667, 0.1333, + 0.1333, 0.2000, 0.2667, 0.2667, 0.3333, 0.4000, 0.4667, 0.4667, 0.5333, + 0.6000, 0.6667, 0.6667, 0.7333, 0.8000, 0.8667, 0.8667, 0.9333, 1.0000, + 1.0000, 1.0000, 1.0000, 1.0000, 1.0000]) + >>> Q.affine.quantize_dequantize(input, scale, offset, qmin=0, qmax=15) + tensor([0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0667, 0.1333, + 0.1333, 0.2000, 0.2667, 0.2667, 0.3333, 0.4000, 0.4667, 0.4667, 0.5333, + 0.6000, 0.6667, 0.6667, 0.7333, 0.8000, 0.8667, 0.8667, 0.9333, 1.0000, + 1.0000, 1.0000, 1.0000, 1.0000, 1.0000]) + """ + qmin, qmax, block_size = _parse_args(args, kwargs) + return get_backend().quantize_dequantize(tensor, scale, offset, qmin, qmax, block_size)
    + + + +
    +[docs] +def dequantize(tensor: torch.Tensor, scale: torch.Tensor, offset: torch.Tensor, + block_size: Optional[Tuple[int, ...]] = None): + r""" + Applies dequantization to the input. + + Precisely, + + .. math:: + out = (input + offset) * scale + + If block size :math:`B = \begin{pmatrix} B_0 & B_1 & \cdots & B_{D-1} \end{pmatrix}` is specified, + this equation will be further generalized as + + .. math:: + out_{j_0 \cdots j_{D-1}} & = (input_{j_0 \cdots j_{D-1}} + offset_{i_0 \cdots i_{D-1}}) * scale_{i_0 \cdots i_{D-1}} + + \text{where} \quad \forall_{0 \leq d < D} \quad i_d = \left\lfloor \frac{j_d}{B_d} \right\rfloor + + :param Tensor tensor: Tensor to dequantize + :param Tensor scale: Scale for dequantization + :param Tensor offset: Offset for dequantization + :param block_size: Block size + :type block_size: Tuple[int, ...], optional + """ + return get_backend().dequantize(tensor, scale, offset, block_size)
    + + + +def _parse_args(args, kwargs) -> Tuple[int, int, Optional[Tuple[int, ...]]]: + bitwidth = num_steps = signed = qmin = qmax = None + + # Pad positional args with None's such that len(args) == 3 + args = tuple(chain(args, repeat(None, 3 - len(args)))) + arg0 = kwargs.get('qmin', kwargs.get('bitwidth', args[0])) + arg1 = kwargs.get('qmax', kwargs.get('signed', args[1])) + block_size = kwargs.get('block_size', None) or args[2] + + if arg0 is None: + num_steps = kwargs['num_steps'] + signed = kwargs['signed'] + qmin, qmax = _derive_qmin_qmax(num_steps=num_steps, signed=signed) + elif arg1 is None or isinstance(arg1, bool): + bitwidth, signed = arg0, bool(arg1) + qmin, qmax = _derive_qmin_qmax(bitwidth=bitwidth, signed=signed) + else: + qmin, qmax = arg0, arg1 + + assert qmin is not None + assert qmax is not None + + return qmin, qmax, block_size + + +def _derive_qmin_qmax(*, bitwidth: int = None, num_steps: int = None, signed: bool): + if bitwidth is not None: + num_steps = 2 ** bitwidth - 1 + + if signed: + qmin = -math.ceil(num_steps/2) + qmax = math.floor(num_steps/2) + else: + qmin = 0 + qmax = num_steps + + return qmin, qmax +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v2/quantization/affine/quantizer.html b/releases/2.0.0/_modules/aimet_torch/v2/quantization/affine/quantizer.html new file mode 100644 index 0000000..f128bd6 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v2/quantization/affine/quantizer.html @@ -0,0 +1,1183 @@ + + + + + + + + aimet_torch.v2.quantization.affine.quantizer - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v2.quantization.affine.quantizer

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +# pylint: disable=redefined-builtin
    +""" Affine quantizers """
    +
    +import abc
    +from itertools import chain, repeat
    +from typing import Optional, List, Dict, Tuple, overload
    +import contextlib
    +import functools
    +
    +import torch
    +from torch import nn
    +
    +from aimet_torch.v2.utils import patch_attr, _is_expandable, StatisticsNotFoundError, docstring
    +from aimet_torch.v2.quantization.encoding_analyzer import EncodingAnalyzer, MinMaxEncodingAnalyzer, _flag_extreme_min_max
    +from aimet_torch.v2.quantization.affine import AffineEncoding, GroupedBlockEncoding
    +from aimet_torch.v2.quantization.tensor import QuantizedTensor, DequantizedTensor
    +from aimet_torch.v2.quantization.base import QuantizerBase
    +from aimet_torch.v2.quantization.affine.backends import quantize, quantize_dequantize, torch_builtins, _derive_qmin_qmax
    +from aimet_torch.v2.utils import ste_round
    +from aimet_torch.v2.deepspeed_utils import SafeGatheredParameters
    +from ._utils import _GridMixin, _register_signature # pylint: disable=import-error
    +
    +
    +__all__ = ['AffineQuantizerBase', 'MinMaxQuantizer', 'Quantize', 'QuantizeDequantize',
    +           'GroupedBlockQuantizeDequantize']
    +
    +
    +
    +class AffineQuantizerBase(QuantizerBase, _GridMixin):
    +    """
    +    Base class for linear quantization modules.
    +
    +    Args:
    +        shape (tuple): Shape of the quantization parameters
    +        bitwidth (int): Quantization bitwidth
    +        symmetric (bool): If True, performs symmetric quantization;
    +                          otherwise, performs asymmetric quantization
    +        encoding_analyzer (EncodingAnalyzer, optional): Encoding analyzer for calibrating quantization encodings
    +                                                        (default: absolute min-max encoding analyzer)
    +
    +    """
    +    _init_signatures = []
    +
    +    @overload
    +    @_register_signature(_init_signatures)
    +    def __init__(self, shape, qmin: int, qmax: int, symmetric: bool, encoding_analyzer: EncodingAnalyzer = None,
    +                 block_size: Optional[Tuple[int, ...]] = None):
    +        ...
    +
    +    @overload
    +    @_register_signature(_init_signatures)
    +    def __init__(self, shape, bitwidth: int, symmetric: bool, encoding_analyzer: EncodingAnalyzer = None,
    +                 block_size: Optional[Tuple[int, ...]] = None):
    +        ...
    +
    +    def __init__(self, shape, *args, **kwargs):
    +        super().__init__()
    +        if isinstance(shape, int):
    +            shape = (shape,)
    +        self.shape = tuple(shape)
    +        full_args = (shape, *args)
    +
    +        # Pad positional args with None's such that len(args) == 5
    +        args = tuple(chain(args, repeat(None, 5 - len(args))))
    +        arg0 = kwargs.pop('qmin', kwargs.pop('bitwidth', args[0]))
    +        arg1 = kwargs.pop('qmax', args[1])
    +
    +        if arg1 is not None and not isinstance(arg1, bool):
    +            # (arg0, arg1, arg2) == (qmin, qmax, symmetric)
    +            qmin, qmax = arg0, arg1
    +            symmetric = kwargs.pop('symmetric', args[2])
    +
    +            if (qmin is None) or (qmax is None) or (symmetric is None):
    +                raise self._arg_parsing_error(full_args, kwargs)
    +
    +            encoding_analyzer = kwargs.pop('encoding_analyzer', args[3])
    +            block_size = kwargs.pop('block_size', args[4])
    +        else:
    +            # (arg0, arg1) == (bitwidth, symmetric)
    +            bitwidth = arg0
    +            symmetric = kwargs.pop('symmetric', args[1])
    +
    +            if (bitwidth is None) or (symmetric is None):
    +                raise self._arg_parsing_error(full_args, kwargs)
    +
    +            # We support two quantization modes: (unsigned) asymmetric and signed-symmetric
    +            qmin, qmax = _derive_qmin_qmax(bitwidth=bitwidth, signed=symmetric)
    +            encoding_analyzer = kwargs.pop('encoding_analyzer', args[2])
    +            block_size = kwargs.pop('block_size', args[3])
    +
    +        assert qmin is not None
    +        assert qmax is not None
    +
    +        if kwargs:
    +            cls = type(self).__qualname__
    +            unexpected_keys = ', '.join(kwargs.keys())
    +            raise TypeError(f"{cls}.__init__ got unexpected keyword argument: {unexpected_keys}")
    +
    +        if qmin >= qmax:
    +            raise ValueError(f"qmax should be strictly larger than qmin. Got qmax={qmax}, qmin={qmin}")
    +
    +        self.qmin = qmin
    +        self.qmax = qmax
    +        self._symmetric = symmetric
    +        self.block_size = block_size
    +
    +        self.encoding_analyzer = encoding_analyzer or \
    +                                 MinMaxEncodingAnalyzer(torch_builtins.get_encoding_shape_with_blocks(self.shape,
    +                                                                                                      self.block_size))
    +
    +        if self.block_size is None and not _is_expandable(self.encoding_analyzer.observer.shape, self.shape):
    +            raise RuntimeError(f'Encoding analyzer of shape {self.encoding_analyzer.observer.shape} '
    +                               f'is incompatible with quantizer of shape {self.shape}.')
    +
    +    @abc.abstractmethod
    +    def get_min(self, dtype=None) -> torch.Tensor:
    +        """
    +        Compute quantization min to be used for forward pass.
    +        Return None f the quantizer is not initialized yet.
    +
    +        Args:
    +            dtype (torch.dtype): dtype of the computed min
    +
    +        Returns:
    +            Quantization min
    +
    +        """
    +
    +    @abc.abstractmethod
    +    def get_max(self, dtype=None) -> torch.Tensor:
    +        """
    +        Compute quantization max to be used for forward pass.
    +        Return None f the quantizer is not initialized yet.
    +
    +        Args:
    +            dtype (torch.dtype): dtype of the computed max
    +
    +        Returns:
    +            Quantization max
    +
    +        """
    +
    +    @abc.abstractmethod
    +    def get_scale(self, dtype=None) -> torch.Tensor:
    +        """
    +        Compute quantization scale to be used for forward pass.
    +        Return None f the quantizer is not initialized yet.
    +
    +        Args:
    +            dtype (torch.dtype): dtype of the computed scale
    +
    +        Returns:
    +            Quantization scale
    +
    +        """
    +
    +    @abc.abstractmethod
    +    def get_offset(self, dtype=None) -> torch.Tensor:
    +        """
    +        Compute quantization offset to be used for forward pass.
    +        Return None f the quantizer is not initialized yet.
    +
    +        Args:
    +            dtype (torch.dtype): dtype of the computed offset
    +
    +        Returns:
    +            Quantization offset
    +
    +        """
    +
    +    @abc.abstractmethod
    +    def set_range(self, min: torch.Tensor, max: torch.Tensor):
    +        """
    +        Set quantization parameters to the given min-max range
    +        """
    +
    +    def get_encodings(self) -> Optional[AffineEncoding]:
    +        """
    +        Return the quantizer's encodings as an AffineEncoding object
    +        """
    +        if self.is_initialized():
    +            return AffineEncoding(self.get_scale(dtype=torch.float32),
    +                                  self.get_offset(dtype=torch.float32),
    +                                  self.qmin, self.qmax, self._symmetric, self.block_size)
    +        return None
    +
    +    @torch.no_grad()
    +    def get_legacy_encodings(self) -> Optional[List[Dict]]:
    +        """
    +        Returns a list of encodings, each represented as a List of Dicts
    +        """
    +        # pylint: disable=redefined-builtin, protected-access
    +
    +        if not self.is_initialized():
    +            return None
    +
    +        return self.get_encodings()._to_legacy_format()
    +
    +    @torch.no_grad()
    +    def set_legacy_encodings(self, encodings: List[Dict]):
    +        """
    +        Set encodings represented in the same format as the output of get_legacy_encodings as below:
    +
    +        [
    +            {'min': float, 'max': float, 'scale': float, 'offset': float,
    +                     'bitwidth': int, 'dtype': str, 'is_symmetric': str},
    +            {'min': float, 'max': float, 'scale': float, 'offset': float,
    +                     'bitwidth': int, 'dtype': str, 'is_symmetric': str},
    +            ...
    +        ]
    +        """
    +        def str_to_bool(s: str):
    +            s = s.lower()
    +            if s == "false":
    +                return False
    +            if s == "true":
    +                return True
    +            raise ValueError
    +
    +        bitwidth = encodings[0]['bitwidth']
    +        symmetric = str_to_bool(encodings[0]['is_symmetric'])
    +        # We support two quantization modes: (unsigned) asymmetric and signed-symmetric
    +        self.qmin, self.qmax = _derive_qmin_qmax(bitwidth=bitwidth, signed=symmetric)
    +        self.symmetric = symmetric
    +        # Note: We can only accurately infer signed-ness in the symmetric case, but AIMET uses unsigned for asymmetric
    +        min_ = torch.tensor([e['min'] for e in encodings]).view(self.shape)
    +        max_ = torch.tensor([e['max'] for e in encodings]).view(self.shape)
    +        self.set_range(min_, max_)
    +
    +    def extra_repr(self) -> str:
    +        extra_repr = f'shape={self.shape}'
    +
    +        if self.block_size is not None:
    +            extra_repr += f", block_size={self.block_size}"
    +
    +        extra_repr += f', qmin={self.qmin}, qmax={self.qmax}, symmetric={self.symmetric}'
    +        return extra_repr
    +
    +    @property
    +    def symmetric(self) -> bool:
    +        """
    +        Indicates whether this quantizer uses symmetric quantization
    +        """
    +        return self._symmetric
    +
    +    @symmetric.setter
    +    def symmetric(self, symmetric: bool):
    +        """
    +        Set the quantizer symmetry
    +
    +        :param symmetric: If True, use symmetric encodings. Else, use asymmetric encodings
    +        """
    +        self._symmetric = symmetric
    +
    +    @property
    +    @docstring(_GridMixin._get_bitwidth.__doc__)
    +    def bitwidth(self) -> int: # pylint: disable=missing-function-docstring
    +        return self._get_bitwidth()
    +
    +    @bitwidth.setter
    +    def bitwidth(self, bitwidth: int):
    +        self._set_bitwidth(bitwidth)
    +
    +    @property
    +    @docstring(_GridMixin._get_signed.__doc__)
    +    def signed(self) -> bool: # pylint: disable=missing-function-docstring
    +        return self._get_signed()
    +
    +    @signed.setter
    +    def signed(self, signed: bool):
    +        self._set_signed(signed)
    +
    +
    +class MinMaxQuantizer(AffineQuantizerBase): # pylint: disable=abstract-method
    +    """
    +    Affine quantizer with min-max as trainable parameters
    +    """
    +
    +    min: torch.nn.Parameter
    +    max: torch.nn.Parameter
    +
    +    def __init__(self, *args, **kwargs):
    +        super().__init__(*args, **kwargs)
    +
    +        self.register_quantization_parameter('min', nn.Parameter(-torch.ones(self.shape)))
    +        self.register_quantization_parameter('max', nn.Parameter(torch.ones(self.shape)))
    +
    +    @contextlib.contextmanager
    +    def compute_encodings(self):
    +        """
    +        Observe inputs and update quantization parameters based on the input statistics.
    +        During ``compute_encodings`` is enabled, the quantizer forward pass performs
    +        dynamic quantization using the batch statistics.
    +        """
    +        if not self._allow_overwrite:
    +            yield
    +            return
    +
    +        original_forward = self.forward
    +
    +        @functools.wraps(original_forward)
    +        def forward_wrapper(input):
    +            input = input.as_subclass(torch.Tensor)
    +            expanded_input = torch_builtins.reshape_tensor_for_blocks(input, self.shape, self.block_size)
    +            batch_statistics = self.encoding_analyzer.update_stats(expanded_input)
    +            num_steps = self.qmax - self.qmin
    +            dynamic_min, dynamic_max =\
    +                    self.encoding_analyzer.compute_encodings_from_stats(batch_statistics,
    +                                                                        num_steps,
    +                                                                        self.symmetric)
    +            if self.block_size is not None:
    +                dynamic_min = dynamic_min.view(self.min.shape)
    +                dynamic_max = dynamic_max.view(self.max.shape)
    +            dynamic_min = dynamic_min.to(dtype=self.min.dtype,
    +                                         device=self.min.device).expand_as(self.min)
    +            dynamic_max = dynamic_max.to(dtype=self.max.dtype,
    +                                         device=self.max.device).expand_as(self.max)
    +
    +            with patch_attr(self, 'min', dynamic_min),\
    +                    patch_attr(self, 'max', dynamic_max):
    +                return original_forward(input)
    +
    +        self.encoding_analyzer.reset_stats()
    +
    +        try:
    +            with patch_attr(self, 'forward', forward_wrapper):
    +                yield
    +        except: # pylint: disable=try-except-raise
    +            raise
    +        else:
    +            try:
    +                num_steps = self.qmax - self.qmin
    +                enc_min, enc_max = self.encoding_analyzer.compute_encodings(num_steps, self.symmetric)
    +                if self.block_size is not None:
    +                    enc_min = enc_min.view(self.min.shape)
    +                    enc_max = enc_max.view(self.max.shape)
    +                _flag_extreme_min_max(enc_min, enc_max)
    +
    +            except StatisticsNotFoundError:
    +                return
    +
    +            if enc_min is None or enc_max is None:
    +                return
    +
    +            self.set_range(enc_min, enc_max)
    +
    +    def get_min(self, dtype=None) -> Optional[torch.Tensor]:
    +        """
    +        Compute quantization min to be used for forward pass.
    +
    +        NOTE: self.min may not be equal to self.get_min().
    +              self.get_min() returns slightly recalibrated version of self.min.
    +
    +        :param dtype: dtype of the computed min. Use of self.min.dtype by default.
    +        :return: Quantization min
    +        """
    +        if not self.is_initialized():
    +            return None
    +        return self.get_scale(dtype) * (self.get_offset(dtype) + self.qmin)
    +
    +    def get_max(self, dtype=None) -> Optional[torch.Tensor]:
    +        """
    +        Compute quantization max to be used for forward pass.
    +
    +        NOTE: self.max may not be equal to self.get_max()
    +              self.get_max() returns slightly recalibrated version of self.max.
    +
    +        :param dtype: dtype of the computed max. Use of self.min.dtype by default.
    +        :return: Quantization max
    +        """
    +        if not self.is_initialized():
    +            return None
    +        return self.get_scale(dtype) * (self.get_offset(dtype) + self.qmax)
    +
    +    def get_scale(self, dtype=None) -> Optional[torch.Tensor]:
    +        """
    +        Compute quantization scale to be used for forward pass.
    +
    +        :param dtype: dtype of the computed scale. Use of self.min.dtype by default.
    +        :return: Quantization scale
    +        """
    +        if not self.is_initialized():
    +            return None
    +
    +        dtype = dtype or torch.float32
    +        num_steps = self.qmax - self.qmin
    +
    +        scale = (self.max.to(dtype) - self.min.to(dtype)) / num_steps
    +        return scale.to(dtype)
    +
    +    def get_offset(self, dtype=None) -> Optional[torch.Tensor]:
    +        """
    +        Compute quantization offset to be used for forward pass.
    +
    +        :param dtype: dtype of the computed offset. Use of self.min.dtype by default.
    +        :return: Quantization offset
    +        """
    +        if not self.is_initialized():
    +            return None
    +
    +        dtype = dtype or torch.float32
    +
    +        if self.symmetric:
    +            offset = torch.full_like(self.min,
    +                                     fill_value=-round((self.qmin + self.qmax) / 2),
    +                                     requires_grad=False,
    +                                     dtype=dtype)
    +        else:
    +            offset = ste_round(self.min.to(dtype) / self.get_scale(dtype)) - self.qmin
    +
    +        return offset.to(dtype)
    +
    +    def set_range(self, min: torch.Tensor, max: torch.Tensor):
    +        """
    +        Set quantization parameters to the given min-max range
    +        """
    +        with torch.no_grad(), SafeGatheredParameters(self.parameters(recurse=False), modifier_rank=0):
    +            self.min.copy_(min)
    +            self.max.copy_(max)
    +
    +
    +
    +[docs] +class Quantize(MinMaxQuantizer): + r"""Applies quantization to the input. + + Precisely, + + .. math:: + out = clamp\left(\left\lceil\frac{input}{scale}\right\rfloor - offset, qmin, qmax\right) + + where :math:`scale` and :math:`offset` are derived from learnable parameters + :math:`\theta_{min}` and :math:`\theta_{max}`. + + If block size :math:`B = \begin{pmatrix} B_0 & B_1 & \cdots & B_{D-1} \end{pmatrix}` is specified, + this equation will be further generalized as + + .. math:: + out_{j_0 \cdots j_{D-1}} & = clamp\left( + \left\lceil\frac{input_{j_0 \cdots j_{D-1}}}{scale_{i_0 \cdots i_{D-1}}}\right\rfloor + - offset_{i_0 \cdots i_{D-1}}, qmin, qmax\right)\\ + + \text{where} \quad \forall_{0 \leq d < D} \quad i_d = \left\lfloor \frac{j_d}{B_d} \right\rfloor + + Args: + shape (tuple): Shape of the quantization parameters + bitwidth (int): Quantization bitwidth + symmetric (bool): If True, performs symmetric quantization; + otherwise, performs asymmetric quantization + encoding_analyzer (EncodingAnalyzer, optional): Encoding analyzer for calibrating quantization encodings + (default: absolute min-max encoding analyzer) + block_size (Tuple[int, ...], optional): Block size + + :ivar Tensor min: :math:`\theta_{min}` from which scale and offset will be derived. + :ivar Tensor max: :math:`\theta_{max}` from which scale and offset will be derived. + + .. note:: + :class:`Quantize` cannot run :meth:`forward` until :attr:`min` and :attr:`max` are properly initialized, + which can be done based on input statistics using :meth:`compute_encodings` or + by manually assigning a new value to :attr:`min` and :attr:`max`. + See the examples below. + + Examples: + + >>> import aimet_torch.v2.quantization as Q + >>> input = torch.randn(5, 10) + >>> q = Q.affine.Quantize(shape=(5, 1), bitwidth=8, symmetric=False, block_size=(1, 5)) + >>> q.is_initialized() + False + >>> with q.compute_encodings(): + ... _ = q(input) + ... + >>> q.is_initialized() + True + >>> q(input) + QuantizedTensor([[129., 64., 255., 122., 0., 192., 106., 94., 255., 0.], + [ 0., 145., 181., 255., 144., 255., 194., 0., 74., 86.], + [122., 0., 255., 150., 33., 103., 103., 0., 37., 255.], + [255., 111., 237., 218., 0., 49., 155., 255., 0., 179.], + [ 0., 66., 255., 89., 110., 17., 36., 83., 255., 0.]], + grad_fn=<AliasBackward0>) + + + >>> import aimet_torch.v2.quantization as Q + >>> input = torch.randn(5, 10) + >>> q = Q.affine.Quantize(shape=(5, 1), bitwidth=8, symmetric=False, block_size=(1, 5)) + >>> q.is_initialized() + False + >>> q.min = torch.nn.Parameter(-torch.ones_like(q.min)) + >>> q.max = torch.nn.Parameter(torch.ones_like(q.max)) + >>> q.is_initialized() + True + >>> q(input) + QuantizedTensor([[187., 186., 131., 0., 203., 64., 80., 0., 143., 152.], + [ 16., 0., 255., 0., 0., 150., 0., 255., 32., 255.], + [255., 226., 0., 255., 55., 172., 0., 255., 145., 255.], + [207., 146., 216., 238., 0., 0., 141., 178., 255., 188.], + [ 63., 59., 19., 162., 30., 255., 109., 255., 0., 255.]], + grad_fn=<AliasBackward0>) + """ + # NOTE: Deepspeed has a bug where it will inadvertently patch __init__ method permanently + # unless each leaf class explicitly defines its own __init__ separately. + # As a temporary workaround, we define __init__ to avoid triggering this bug. + # pylint: disable=useless-super-delegation + def __init__(self, shape, *args, **kwargs): + super().__init__(shape, *args, **kwargs) + +
    +[docs] + def forward(self, input: torch.Tensor) -> QuantizedTensor: + """Quantizes the input tensor + + Args: + input (torch.Tensor): Input to quantize + + Returns: + Quantized output + + """ + if not self.is_initialized(): + raise RuntimeError( + 'Failed to run Quantize since quantization parameters are not initialized.' + ' Please initialize the quantization parameters using `compute_encodings()`.' + ) + + encoding = self.get_encodings() + + # Subclasses of torch.Tensor with custom __torch_function__ (in our case, QuantizedTensorBase) + # is known to introduce substantial CPU overhead. + # Cast types of the inputs to plain torch.Tensor for faster execution. + input = input.as_subclass(torch.Tensor) + + output = quantize(input, + encoding.scale, + encoding.offset, + encoding.qmin, + encoding.qmax, + block_size=self.block_size) + output = output.as_subclass(QuantizedTensor) + output.encoding = encoding + return output
    +
    + + + +
    +[docs] +class QuantizeDequantize(MinMaxQuantizer): + r"""Applies fake-quantization by quantizing and dequantizing the input. + + Precisely, + + .. math:: + out = (\overline{input} + offset) * scale + + where + + .. math:: + \overline{input} = clamp\left(\left\lceil\frac{input}{scale}\right\rfloor - offset, qmin, qmax\right) + + and :math:`scale` and :math:`offset` are derived from learnable parameters + :math:`\theta_{min}` and :math:`\theta_{max}`. + + If block size :math:`B = \begin{pmatrix} B_0 & B_1 & \cdots & B_{D-1} \end{pmatrix}` is specified, + this equation will be further generalized as + + .. math:: + out_{j_0 \cdots j_{D-1}} &= (\overline{input}_{j_0 \cdots j_{D-1}} + offset_{i_0 \cdots i_{D-1}}) * scale_{i_0 \cdots i_{D-1}}\\ + \overline{input}_{j_0 \cdots j_{D-1}} &= clamp\left( + \left\lceil\frac{input_{j_0 \cdots j_{D-1}}}{scale_{i_0 \cdots i_{D-1}}}\right\rfloor + - offset_{i_0 \cdots i_{D-1}}, qmin, qmax\right)\\ + + \text{where} \quad \forall_{0 \leq d < D} \quad i_d = \left\lfloor \frac{j_d}{B_d} \right\rfloor + + Args: + shape (tuple): Shape of the quantization parameters + bitwidth (int): Quantization bitwidth + symmetric (bool): If True, performs symmetric quantization; + otherwise, performs asymmetric quantization + encoding_analyzer (EncodingAnalyzer, optional): Encoding analyzer for calibrating quantization encodings + (default: absolute min-max encoding analyzer) + block_size (Tuple[int, ...], optional): Block size + + :ivar Tensor min: :math:`\theta_{min}` from which scale and offset will be derived. + :ivar Tensor max: :math:`\theta_{max}` from which scale and offset will be derived. + + .. note:: + :class:`QuantizeDequantize` cannot run :meth:`forward` until :attr:`min` and :attr:`max` are properly initialized, + which can be done based on input statistics using :meth:`compute_encodings` or + by manually assigning a new value to :attr:`min` and :attr:`max`. + See the examples below. + + Examples: + + >>> import aimet_torch.v2.quantization as Q + >>> input = torch.randn(5, 10) + >>> qdq = Q.affine.QuantizeDequantize(shape=(5, 2), bitwidth=8, symmetric=False, block_size=(1, 5)) + >>> qdq.is_initialized() + False + >>> with qdq.compute_encodings(): + ... _ = qdq(input) + ... + >>> qdq.is_initialized() + True + >>> qdq(input) + DequantizedTensor([[-0.2771, 0.3038, 1.0819, 0.9700, 0.9487, -0.1307, + -1.7894, -0.1709, -0.2212, 0.7741], + [-1.0295, -1.2265, -1.0295, 1.0564, 0.6177, -1.0386, + -0.0176, -2.6054, 1.8836, -0.1232], + [-0.8229, 0.5540, 0.3992, -0.2363, 1.2546, -1.0036, + 0.2355, 0.1741, 1.6079, 0.6247], + [-1.0115, 1.2458, 0.9157, -1.4694, -0.0639, -0.2568, + 0.0680, 1.6695, 0.7932, -0.1889], + [ 0.0158, 0.5695, 0.5220, 0.1977, -1.4475, -0.0424, + -1.1128, -0.8796, -0.1060, 1.5897]], + grad_fn=<AliasBackward0>) + + + >>> import aimet_torch.v2.quantization as Q + >>> input = torch.randn(5, 10) + >>> qdq = Q.affine.QuantizeDequantize(shape=(5, 2), bitwidth=8, symmetric=False, block_size=(1, 5)) + >>> qdq.is_initialized() + False + >>> qdq.min = torch.nn.Parameter(-torch.ones_like(qdq.min)) + >>> qdq.max = torch.nn.Parameter(torch.ones_like(qdq.max)) + >>> qdq.is_initialized() + True + >>> qdq(input) + DequantizedTensor([[-0.6196, -0.9961, 0.0549, -0.6431, 1.0039, -0.8706, + 1.0039, 0.4706, -0.2353, 0.8078], + [ 0.3451, -0.1176, -0.9961, -0.4549, -0.0549, -0.0471, + -0.5255, -0.2353, 1.0039, -0.9961], + [-0.4157, 0.0784, 0.5333, 0.1647, -0.9961, -0.9961, + -0.2118, -0.2196, 0.9176, 0.9490], + [ 1.0039, -0.7765, 0.4784, -0.8706, 1.0039, 0.6039, + -0.4157, -0.2118, -0.9961, 0.3137], + [ 1.0039, 0.3216, -0.2353, -0.7765, -0.9961, 0.8000, + 1.0039, 0.4157, 0.4392, 0.4863]], + grad_fn=<AliasBackward0>) + """ + # NOTE: Deepspeed has a bug where it will inadvertently patch __init__ method permanently + # unless each leaf class explicitly defines its own __init__ separately. + # As a temporary workaround, we define __init__ to avoid triggering this bug. + # pylint: disable=useless-super-delegation + def __init__(self, shape, *args, **kwargs): + super().__init__(shape, *args, **kwargs) + +
    +[docs] + def forward(self, input: torch.Tensor) -> DequantizedTensor: + """Quantizes and dequantizes the input tensor + + Args: + input (torch.Tensor): Input to quantize and dequantize + + Returns: + Quantize-dequantized output + + """ + if not self.is_initialized(): + raise RuntimeError( + 'Failed to run QuantizeDequantize since quantization parameters are not initialized.' + ' Please initialize the quantization parameters using `compute_encodings()`.' + ) + + encoding = self.get_encodings() + + # Subclasses of torch.Tensor with custom __torch_function__ (in our case, QuantizedTensorBase) + # is known to introduce substantial CPU overhead. + # Cast types of the inputs to plain torch.Tensor for faster execution. + input = input.as_subclass(torch.Tensor) + + output = quantize_dequantize(input, + encoding.scale, + encoding.offset, + encoding.qmin, + encoding.qmax, + block_size=self.block_size) + output = output.as_subclass(DequantizedTensor) + output.encoding = encoding + return output
    +
    + + + +class GroupedBlockQuantizeDequantize(QuantizeDequantize): # pylint: disable=too-many-ancestors + """ Class for performing Grouped Block Quantize Dequantize """ + def __init__(self, shape, bitwidth: int, symmetric: bool, decompressed_bw: int, + encoding_analyzer: EncodingAnalyzer = None, block_size: Optional[Tuple[int, ...]] = None, + block_grouping: Optional[Tuple[int, ...]] = None): + """ + Grouped Block Quantize Dequantize constructor. + + :param shape: Shape of the quantization parameters + :type shape: tuple + :param bitwidth: Quantization bitwidth + :type bitwidth: int + :param symmetric: If True, performs symmetric quantization; + otherwise, performs asymmetric quantization + :type symmetric: bool + :param decompressed_bw: Bitwidth used for decompression + :type decompressed_bw: int + :param encoding_analyzer: Encoding analyzer for calibrating quantization encodings + (default: absolute min-max encoding analyzer) + :type encoding_analyzer: EncodingAnalyzer, optional + :param block_size: Block size per dimension. + :type block_size: Tuple + :param block_grouping: Block grouping per dimension. If provided, every set of block_group scales will be + grouped together, and the maximum scale for all blocks in the group will be used to find + the scale in the decompressed_grid to be shared by all blocks in the group. + If no block_grouping is provided, default behavior uses a block group of 1 for all dims, + equivalent to Blockwise Quantization. + A value of -1 for a block group for a dimension is equivalent to grouping all blocks in + the dimension in one group. This is also equivalent to a block group value equal to the + number of blocks for that dimension. + :type block_grouping: Tuple + """ + super().__init__(shape, bitwidth, symmetric, encoding_analyzer, block_size) + self.decompressed_bw = decompressed_bw + self.block_grouping = block_grouping + if self.block_grouping is None: + # Default to BQ behavior with 1 for all block grouping dims if not provided + self.block_grouping = tuple(1 for _ in enumerate(self.shape)) + + if block_grouping is not None: + if len(block_grouping) != len(shape): + raise RuntimeError(f'Length of block grouping {block_grouping} must equal length of shape {shape}.') + for idx, block_group in enumerate(block_grouping): + if block_group != -1 and shape[idx] % block_group != 0: + raise RuntimeError(f'Quantizer shape dimensions must divide evenly with corresponding block ' + f'grouping values for shapes {shape} and block grouping {block_grouping}.') + + if self.decompressed_bw < self.bitwidth: + raise RuntimeError(f'Decompressed bitwidth {decompressed_bw} cannot be smaller than self.bitwidth ' + f'{bitwidth}') + + if not symmetric: + raise RuntimeError('GroupedBlockQuantizeDequantize only supports symmetric quantization.') + + def get_scale(self, dtype=None) -> torch.Tensor: + """ + Compute quantization scale to be used for forward pass. + Overrides QuantizeDequantize self.get_scale() to apply the grouped block algorithm for calculating modified + scales. + + :param dtype: dtype of the computed scale. Use of self.min.dtype by default. + :return: Updated scale + """ + orig_scale = super().get_scale(dtype) + orig_scale_shape = orig_scale.shape + reshaped_scale = orig_scale.view(self.get_expanded_scale_shape()) + max_scale = torch.amax(reshaped_scale, list(range(1, len(orig_scale_shape) * 2, 2)), keepdim=True) + per_channel_scale = max_scale / 2 ** (self.decompressed_bw - self.bitwidth) + updated_scale = quantize_dequantize(reshaped_scale, + scale=per_channel_scale, + offset=torch.zeros_like(per_channel_scale), + qmin=1, + qmax=2 ** (self.decompressed_bw - self.bitwidth)) + return updated_scale.view(orig_scale_shape) + + def get_expanded_scale_shape(self) -> Tuple[int, ...]: + """ + Get expanded scale shape which breaks each scale dimension into a pair of dimensions with sizes + (original_shape / block_grouping, block_grouping). + + :return: Expanded scale shape + """ + expanded_shape = [] + for idx, block_group in enumerate(self.block_grouping): + # Block group of -1 is equivalent to grouping all blocks together + if block_group == -1: + expanded_shape.append(1) + expanded_shape.append(self.shape[idx]) + else: + expanded_shape.append(self.shape[idx] // block_group) + expanded_shape.append(block_group) + return expanded_shape + + def get_per_channel_scale(self, dtype=None) -> torch.Tensor: + """ + Get per channel scale. + + :return: Per channel scale + """ + orig_scale = super().get_scale(dtype) + orig_scale_shape = orig_scale.shape + reshaped_scale = orig_scale.view(self.get_expanded_scale_shape()) + max_scale = torch.amax(reshaped_scale, list(range(1, len(orig_scale_shape) * 2, 2)), keepdim=True) + per_channel_scale = max_scale / 2 ** (self.decompressed_bw - self.bitwidth) + return per_channel_scale + + def get_per_block_integer_scale(self) -> torch.Tensor: + """ + Get per block integer scale. + + :return: Per block integer scale + """ + per_channel_scale = self.get_per_channel_scale() + expanded_scale = self.get_scale().view(self.get_expanded_scale_shape()) + integer_scale = torch.round(expanded_scale / per_channel_scale).int().view(self.get_scale().shape) + return integer_scale + + def get_encodings(self) -> Optional[GroupedBlockEncoding]: + """ + Return the quantizer's encodings as an EncodingBase object + """ + if self.is_initialized(): + return GroupedBlockEncoding(scale=self.get_scale(dtype=torch.float32), + offset=self.get_offset(dtype=torch.float32), + bitwidth=self.bitwidth, + signed=self.signed, + symmetry=self.symmetric, + block_size=self.block_size, + block_grouping=self.block_grouping, + decompressed_bw=self.decompressed_bw, + per_channel_scale=self.get_per_channel_scale(dtype=torch.float32), + per_block_int_scale=self.get_per_block_integer_scale()) + return None +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v2/quantization/float/quantizer.html b/releases/2.0.0/_modules/aimet_torch/v2/quantization/float/quantizer.html new file mode 100644 index 0000000..92c52f7 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v2/quantization/float/quantizer.html @@ -0,0 +1,690 @@ + + + + + + + + aimet_torch.v2.quantization.float.quantizer - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v2.quantization.float.quantizer

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +# pylint: disable=redefined-builtin
    +""" Float quantizers """
    +
    +import contextlib
    +import functools
    +from typing import Optional, List, Dict
    +import math
    +
    +import torch
    +from aimet_torch.v2.quantization.encoding_analyzer import EncodingAnalyzer, _flag_extreme_min_max
    +from aimet_torch.v2.quantization.base import QuantizerBase
    +from aimet_torch.v2.quantization.float import FloatEncoding
    +from aimet_torch.v2.utils import StatisticsNotFoundError, patch_attr
    +from aimet_torch.fp_quantization import fake_cast_to_ieee_float
    +
    +
    +__all__ = ['QuantizeDequantize', 'FloatQuantizeDequantize']
    +
    +
    +def _ieee_float_max_representable_value(exponent_bits, mantissa_bits):
    +    exponent_max = 2 ** exponent_bits - 1
    +    exponent_bias = exponent_max // 2
    +    return (2 - 2**-mantissa_bits) * 2 ** (exponent_max - exponent_bias - 1)
    +
    +
    +_IEEE_FLOAT16_EXPONENT_BITS = 5
    +_IEEE_FLOAT16_MANTISSA_BITS = 10
    +assert _ieee_float_max_representable_value(_IEEE_FLOAT16_EXPONENT_BITS, _IEEE_FLOAT16_MANTISSA_BITS) == \
    +        torch.finfo(torch.float16).max
    +
    +_BFLOAT16_EXPONENT_BITS = 8
    +_BFLOAT16_MANTISSA_BITS = 7
    +assert _ieee_float_max_representable_value(_BFLOAT16_EXPONENT_BITS, _BFLOAT16_MANTISSA_BITS) == \
    +        torch.finfo(torch.bfloat16).max
    +
    +
    +
    +[docs] +class FloatQuantizeDequantize(QuantizerBase): # pylint: disable=abstract-method + r""" + Simulates quantization by fake-casting the input + + If dtype is provided, this is equivalent to + + .. math:: + out = x.to(dtype).to(x.dtype) \\ + + + If the exponent and mantissa bits are provided, this is equivalent to + + .. math:: + out = \left\lceil\frac{x_c}{scale}\right\rfloor * scale + + where + + .. math:: + x_c &= clamp(x, -max, max) \\ + bias &= 2^{exponent} - \log_2(max) + \log_2(2 - 2^{-mantissa}) - 1 \\ + scale &= 2 ^ {\left\lfloor \log_2 |x_c| + bias \right\rfloor - mantissa - bias} \\ + + + The IEEE standard computes the maximum representable value by + + .. math:: + max = (2 - 2^{-mantissa}) * 2^{(\left\lfloor 0.5 * exponent\_max \right\rfloor)} \\ + + where + + .. math:: + exponent\_max = 2^{exponent} - 1 \\ + + Args: + exponent_bits (int): Number of exponent bits to simulate + mantissa_bits (int): Number of mantissa bits to simulate + dtype (torch.dtype): torch.dtype to simulate. This argument is mutually exclusive with exponent_bits and mantissa_bits. + encoding_analyzer (EncodingAnalyzer): If specified, the maximum value to represent will be determined dynamically based on the input statistics for finer precision. + + Examples: + + >>> import aimet_torch.v2.quantization as Q + >>> input = torch.tensor([[ 1.8998, -0.0947],[-1.0891, -0.1727]]) + >>> qdq = Q.float.FloatQuantizeDequantize(mantissa_bits=7, exponent_bits=8) + >>> # Unlike AffineQuantizer, FloatQuantizer is initialized without calling compute_encodings() + >>> qdq.is_initialized() + True + >>> qdq.is_bfloat16() + True + >>> qdq.bitwidth + 16 + >>> qdq(input) + tensor([[ 1.8984, -0.0947], [-1.0859, -0.1729]]) + + >>> from aimet_torch.v2.quantization.encoding_analyzer import MinMaxEncodingAnalyzer + >>> encoding_analyzer = MinMaxEncodingAnalyzer(shape=[]) + >>> qdq = Q.float.FloatQuantizeDequantize(dtype=torch.float16, encoding_analyzer=encoding_analyzer) + >>> qdq.is_float16() + True + >>> qdq.bitwidth + 16 + >>> qdq(input) + tensor([[ 1.8994, -0.0947], [-1.0889, -0.1727]]) + """ + + maxval: torch.Tensor + + def __init__(self, + exponent_bits: int = None, + mantissa_bits: int = None, + dtype: torch.dtype = None, + encoding_analyzer: EncodingAnalyzer = None): + super().__init__() + + if dtype is None: + if exponent_bits is None or mantissa_bits is None: + raise ValueError('Neither "dtype" nor "exponent/mantissa_bits" was specified.') + + if dtype is not None: + if exponent_bits is not None or mantissa_bits is not None: + raise ValueError( + 'Argument "dtype" is mutually exclusive with "exponent/mantissa_bits".') + + if dtype not in (torch.half, torch.float16, torch.bfloat16): + raise ValueError( + f"Float quantizer only supports torch.float16 and torch.bfloat16. Got {dtype}.") + + if dtype in (torch.half, torch.float16): + exponent_bits = _IEEE_FLOAT16_EXPONENT_BITS + mantissa_bits = _IEEE_FLOAT16_MANTISSA_BITS + else: + exponent_bits = _BFLOAT16_EXPONENT_BITS + mantissa_bits = _BFLOAT16_MANTISSA_BITS + + self.exponent_bits = exponent_bits + self.mantissa_bits = mantissa_bits + self.encoding_analyzer = encoding_analyzer + + if self.encoding_analyzer: + shape = self.encoding_analyzer.observer.shape + maxval = _ieee_float_max_representable_value(exponent_bits, mantissa_bits) + self.register_buffer('maxval', torch.full(shape, maxval)) + else: + self.register_buffer('maxval', None) + +
    +[docs] + def get_extra_state(self): + extra_state_dict = {} + extra_state_dict['exponent_bits'] = torch.tensor(self.exponent_bits) + extra_state_dict['mantissa_bits'] = torch.tensor(self.mantissa_bits) + super_extra_state = super().get_extra_state() + extra_state_dict.update(super_extra_state) + return extra_state_dict
    + + +
    +[docs] + def set_extra_state(self, state): + self.exponent_bits = state['exponent_bits'].item() + self.mantissa_bits = state['mantissa_bits'].item() + super().set_extra_state(state)
    + + +
    +[docs] + def load_state_dict(self, state_dict, strict: bool = True): + if 'maxval' in state_dict: + if self.maxval is None: + del self.maxval + self.register_buffer('maxval', state_dict['maxval']) + elif self.maxval is not None: + del self.maxval + self.register_buffer('maxval', None) + + ret = super().load_state_dict(state_dict, strict) + return ret
    + + + @property + def bitwidth(self): + """ + Returns bitwidth of the quantizer + """ + return self.exponent_bits + self.mantissa_bits + 1 + +
    +[docs] + def is_float16(self): + """ + Returns true if current configuration simulates IEEE float16 + """ + return self.exponent_bits == _IEEE_FLOAT16_EXPONENT_BITS and \ + self.mantissa_bits == _IEEE_FLOAT16_MANTISSA_BITS
    + + +
    +[docs] + def is_bfloat16(self): + """ + Returns true if current configuration simulates bfloat16 + """ + return self.exponent_bits == _BFLOAT16_EXPONENT_BITS and \ + self.mantissa_bits == _BFLOAT16_MANTISSA_BITS
    + + + def get_legacy_encodings(self) -> Optional[List[Dict]]: + """ + :meta private: + """ + return [{'bitwidth': self.bitwidth, 'dtype': 'float'}] + + def set_legacy_encodings(self, encodings: List[Dict]): + """ + :meta private: + Set encodings represented in the same format as the output of get_legacy_encodings as below: + + [ + {'bitwidth': int, 'dtype': str}, + ... + ] + """ + if encodings[0]['bitwidth'] != 16: + raise RuntimeError(f"{self.__class__} can only import 16-bit legay encodings.") + self.exponent_bits = 5 + self.mantissa_bits = 10 + +
    +[docs] + def get_encodings(self) -> Optional[FloatEncoding]: + if self.is_initialized(): + return FloatEncoding(self.mantissa_bits, self.exponent_bits, self.maxval) + return None
    + + +
    +[docs] + @contextlib.contextmanager + def compute_encodings(self): + """ + Observe inputs and update quantization parameters based on the input statistics. + During ``compute_encodings`` is enabled, the quantizer forward pass performs + dynamic quantization using the batch statistics. + """ + if not self.encoding_analyzer or not self._allow_overwrite: + yield + return + + original_forward = self.forward + + @functools.wraps(original_forward) + def forward_wrapper(input): + input = input.as_subclass(torch.Tensor) + batch_statistics = self.encoding_analyzer.update_stats(input) + num_steps = math.pow(2, self.bitwidth) - 1 + dynamic_min, dynamic_max =\ + self.encoding_analyzer.compute_encodings_from_stats(batch_statistics, + num_steps, + is_symmetric=False) + dynamic_absmax = torch.maximum(dynamic_min.abs(), dynamic_max.abs()) + dynamic_absmax = dynamic_absmax.to(dtype=self.maxval.dtype, + device=self.maxval.device).expand_as(self.maxval) + + with patch_attr(self, 'maxval', dynamic_absmax): + return original_forward(input) + + self.encoding_analyzer.reset_stats() + + try: + with patch_attr(self, 'forward', forward_wrapper): + yield + except: # pylint: disable=try-except-raise + raise + else: + try: + num_steps = math.pow(2, self.bitwidth) - 1 + min, max = self.encoding_analyzer.compute_encodings(num_steps, + is_symmetric=False) + _flag_extreme_min_max(min, max) + except StatisticsNotFoundError: + return + + if min is None or max is None: + return + + absmax = torch.maximum(min.abs(), max.abs()).expand_as(self.maxval) + with torch.no_grad(): + self.maxval.copy_(absmax)
    + + +
    +[docs] + def forward(self, input: torch.Tensor): + """ + :param input: Input to quantize and dequantize + :return: Quantize-dequantized output + """ + maxval = self.maxval + exponent_bits = self.exponent_bits + mantissa_bits = self.mantissa_bits + + if maxval is None: + if self.is_float16() or self.is_bfloat16(): + # Fast forward using type casting + orig_dtype = input.dtype + dtype = torch.float16 if self.is_float16() else torch.bfloat16 + return input.to(dtype).to(orig_dtype) + + maxval = _ieee_float_max_representable_value(exponent_bits, mantissa_bits) + + # Subclasses of torch.Tensor with custom __torch_function__ (in our case, QuantizedTensorBase) + # is known to introduce substantial CPU overhead. + # Cast types of the inputs to plain torch.Tensor for faster execution. + return fake_cast_to_ieee_float(input.as_subclass(torch.Tensor), maxval, exponent_bits, mantissa_bits)
    + + + def extra_repr(self): + """ + :meta private: + """ + return f'exponent_bits={self.exponent_bits}, mantissa_bits={self.mantissa_bits}'
    + + +class QuantizeDequantize(FloatQuantizeDequantize): + r""" + Alias of FloatQuantizeDequantize + """ +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v2/quantization/tensor.html b/releases/2.0.0/_modules/aimet_torch/v2/quantization/tensor.html new file mode 100644 index 0000000..004bb73 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v2/quantization/tensor.html @@ -0,0 +1,873 @@ + + + + + + + + aimet_torch.v2.quantization.tensor - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v2.quantization.tensor

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +""" Quantized tensor class implementation """
    +
    +import abc
    +import copy
    +
    +import torch
    +from torch.utils._pytree import tree_map
    +
    +from aimet_torch.v2.quantization.base import EncodingBase
    +
    +
    +__all__ = ['QuantizedTensorBase', 'QuantizedTensor', 'DequantizedTensor', 'EncodingError']
    +
    +
    +HANDLED_FUNCTIONS = {}
    +def implements(torch_function):
    +    """
    +    Register an override for QuantizedTensorBase
    +    """
    +    def decorator(func):
    +        HANDLED_FUNCTIONS[torch_function] = func
    +        return func
    +
    +    return decorator
    +
    +
    +
    +[docs] +class QuantizedTensorBase(torch.Tensor): + """ + Abstract base class for quantized tensors. + Represents a quantized or dequantized tensor as a subclass of :class:`torch.Tensor` which also holds the quantization encodings. + This object can be safely quantized or dequantized through the :meth:`quantize` and :meth:`dequantize` methods without + changing the represented data values. + + Example: + + >>> from aimet_torch.v2 import quantization as Q + >>> quantizer = Q.affine.Quantize(shape=(2, 1), bitwidth=8, symmetric=True) + >>> x = torch.tensor([[-1.20, 4.1, -0.21, 2.3], + ... [0.2, 5.6, -1.0, -.1]]) + >>> with quantizer.compute_encodings(): + ... x_q = quantizer(x) + >>> torch.equal(x_q.encoding.scale, quantizer.get_scale()) + True + >>> x_q + QuantizedTensor([[-37., 127., -7., 71.], + [ 5., 127., -23., -2.]]) + >>> x_q.quantized_repr() + tensor([[-37, 127, -7, 71], + [ 5, 127, -23, -2]], dtype=torch.int8) + >>> x_q.dequantize() + DequantizedTensor([[-1.1945, 4.1000, -0.2260, 2.2921], + [ 0.2205, 5.6000, -1.0142, -0.0882]]) + """ + + encoding: EncodingBase + + _attr_descriptors = { + torch.Tensor.dtype.__get__, + torch.Tensor.device.__get__, + torch.Tensor.layout.__get__, + torch.Tensor.shape.__get__, + torch.Tensor.size, + } + + _cast_ops = { + torch.Tensor.half, + torch.Tensor.float, + torch.Tensor.double, + torch.Tensor.char, + torch.Tensor.short, + torch.Tensor.int, + torch.Tensor.long, + torch.Tensor.cuda, + torch.Tensor.cpu, + torch.Tensor.to, + torch.Tensor.type, + torch.Tensor.type_as, + } + + # Operations that an encoding can always pass through + _passthrough_ops = { + torch.Tensor.contiguous, + torch.Tensor.requires_grad_, + torch.Tensor.share_memory_, + } + + # Operations that a per-tensor encoding can pass through + _pertensor_passthrough_ops = { + torch.Tensor.__getitem__, + torch.Tensor.as_strided, + torch.Tensor.broadcast_to, + torch.Tensor.chunk, + torch.Tensor.dsplit, + torch.Tensor.expand, + torch.Tensor.expand_as, + torch.Tensor.flatten, + torch.Tensor.flip, + torch.Tensor.fliplr, + torch.Tensor.flipud, + torch.Tensor.gather, + torch.Tensor.H.__get__, + torch.Tensor.hsplit, + torch.Tensor.index_select, + torch.Tensor.kthvalue, + torch.Tensor.masked_select, + torch.Tensor.mH.__get__, + torch.Tensor.movedim, + torch.Tensor.moveaxis, + torch.Tensor.msort, + torch.Tensor.mT.__get__, + torch.Tensor.narrow, + torch.Tensor.permute, + torch.Tensor.repeat, + torch.Tensor.reshape, + torch.Tensor.reshape_as, + torch.Tensor.resize, + torch.Tensor.resize_, + torch.Tensor.resize_as, + torch.Tensor.resize_as_, + torch.Tensor.select, + torch.Tensor.split, + torch.Tensor.squeeze, + torch.Tensor.squeeze_, + torch.Tensor.swapaxes, + torch.Tensor.swapdims, + torch.Tensor.T.__get__, + torch.Tensor.t, + torch.Tensor.t_, + torch.Tensor.take, + torch.Tensor.take_along_dim, + torch.Tensor.tensor_split, + torch.Tensor.tile, + torch.Tensor.transpose, + torch.Tensor.unflatten, + torch.Tensor.unsqueeze, + torch.Tensor.unsqueeze_, + torch.Tensor.view, + torch.Tensor.view_as, + torch.as_strided, + torch.as_strided_copy, + torch.chunk, + torch.dsplit, + torch.expand_copy, + torch.flatten, + torch.flip, + torch.fliplr, + torch.flipud, + torch.gather, + torch.hsplit, + torch.index_select, + torch.masked_select, + torch.moveaxis, + torch.movedim, + torch.narrow, + torch.narrow_copy, + torch.permute, + torch.permute_copy, + torch.reshape, + torch.select, + torch.split, + torch.squeeze, + torch.squeeze_copy, + torch.swapaxes, + torch.swapdims, + torch.t, + torch.take, + torch.take_along_dim, + torch.tensor_split, + torch.tile, + torch.t_copy, + torch.unbind, + torch.unflatten, + torch.unsqueeze, + torch.unsqueeze_copy, + torch.vsplit, + torch.view_copy, + } + +
    +[docs] + @abc.abstractmethod + def quantize(self) -> "QuantizedTensor": + """ + Quantizes ``self`` with the associated encoding + + .. note:: + This method must be an IDEMPOTENT function. + The result of calling this method multiple times should be equal to calling it only once. + In other words, calling this method multiple times should not result in duplicate quantization. + """ + raise NotImplementedError
    + + +
    +[docs] + @abc.abstractmethod + def dequantize(self) -> "DequantizedTensor": + """ + Dequantizes ``self`` with the associated encoding + + .. note:: + This method must be an IDEMPOTENT function. + The result of calling this method multiple times should be equal to calling it only once. + In other words, calling this method multiple times should not result in duplicate dequantization. + """ + raise NotImplementedError
    + + +
    +[docs] + @abc.abstractmethod + def quantized_repr(self) -> torch.Tensor: + """ + Return the quantized representation of ``self`` as a :class:`torch.Tensor` with data type :attr:`self.encoding.dtype` + + .. note:: + The result of this function may not be able to carry a gradient depending on the quantized data type. + Thus, it may be necessary to call this only within an autograd function to allow for backpropagation. + + Example: + + >>> from aimet_torch.v2 import quantization as Q + >>> quantizer = Q.affine.Quantize(shape=(2, 1), bitwidth=8, symmetric=True) + >>> x = torch.randn((2, 4), requires_grad=True) + >>> with quantizer.compute_encodings(): + ... x_q = quantizer(x) + >>> x_q + QuantizedTensor([[ 11., -57., -128., 38.], + [ 28., -0., -128., -40.]], grad_fn=<AliasBackward0>) + >>> x_q.quantized_repr() + tensor([[ 11, -57, -128, 38], + [ 28, 0, -128, -40]], dtype=torch.int8) + """ + raise NotImplementedError
    + + + @classmethod + def __new__(cls, *args, **kwargs): + encoding = kwargs.pop('encoding', None) + ret = super().__new__(*args, **kwargs) + if not ret.is_floating_point(): + raise RuntimeError(f"Non-floating point dtype `{ret.dtype}` is not allowed for quantized tensors.") + ret.encoding = encoding + return ret + +
    +[docs] + def new_empty(self, size, *, dtype=None, device=None, requires_grad=False, + layout=torch.strided, pin_memory=False, **kwargs) -> "QuantizedTensorBase": + # PyTorch requires subclasses of torch.Tensor to override this method such that + # it returns an instance of the subclass, not a plain torch.Tensor, + # for the subclass to be deep-copyable + encoding = kwargs.pop('encoding', None) + t = super().new_empty(size, dtype=dtype, device=device, requires_grad=requires_grad, + layout=layout, pin_memory=pin_memory, **kwargs).as_subclass(type(self)) + t.encoding = encoding + return t
    + + +
    +[docs] + @implements(torch.clone) + def clone(self, *, memory_format=torch.preserve_format): + """ + Returns a copy of self + + :param memory_format: Desired memory format of the returned tensor (default=torch.preserve_format) + """ + # Note: use encoding.clone() here instead of deepcopy to propagate gradient through operation + encoding_clone = self.encoding and self.encoding._clone() # pylint:disable = protected-access + self_clone = super().clone(memory_format=memory_format).as_subclass(self.__class__) + self_clone.encoding = encoding_clone + return self_clone
    + + +
    +[docs] + @implements(torch.detach) + def detach(self) -> "QuantizedTensorBase": + """ + Returns a new QuantizedTensorBase with data and encoding detached from the current graph + """ + self_detached = super().detach().as_subclass(self.__class__) + self_detached.encoding = self.encoding and self.encoding._detach() # pylint:disable = protected-access + return self_detached
    + + + @classmethod + def __torch_function__(cls, func, types, args=(), kwargs=None): # pylint: disable=too-many-return-statements + if func in HANDLED_FUNCTIONS: + kwargs = kwargs if kwargs is not None else {} + return HANDLED_FUNCTIONS[func](*args, **kwargs) + ret = super().__torch_function__(func, types, args, kwargs) + + if func in cls._attr_descriptors: + return ret + + self, *_ = args + + if not isinstance(self, QuantizedTensorBase): + # If self is not a subclass of QuantizedTensorBase, return a plain torch.Tensor + return tree_map(lambda t: t.as_subclass(torch.Tensor) if isinstance(t, QuantizedTensorBase) else t, ret) + + if func in cls._cast_ops: + if not ret.dtype.is_floating_point: + raise RuntimeError( + f"Type casting to non-floating point dtype `{ret.dtype}` is not allowed for quantized tensors. " + "To cast quantized tensors to integer, use `qtensor.quantzed_repr()`." + ) + + # Outputs of cast ops can inherit the same encoding as its parents + ret.encoding = self.encoding and self.encoding.to(device=ret.device) + return ret + + def propagate_encoding(qtensor, encoding): + if isinstance(qtensor, QuantizedTensorBase): + qtensor.encoding = copy.copy(encoding) + + if func in cls._passthrough_ops: + if self is ret: + return ret + + tree_map(lambda t: propagate_encoding(t, self.encoding), ret) + return ret + + if func in cls._pertensor_passthrough_ops: + if self is ret: + return ret + + if self.encoding and self.encoding.granularity == "pertensor": + # Return a cls object with the same encoding which can later be quantized or dequantized + tree_map(lambda t: propagate_encoding(t, self.encoding), ret) + else: + # Return a cls object with no encoding + # If the user later tries to quantize or dequantize this, an error will be thrown + tree_map(lambda t: propagate_encoding(t, None), ret) + return ret + + if self is ret: + # Non-passthrough in-place functions invalidate the encoding of the input tensor. + # Discard the stale encoding. + ret.encoding = None + return ret + + def set_encoding(qtensor): + if not hasattr(qtensor, 'encoding'): + qtensor.encoding = None + + if qtensor.encoding is None: + # If encoding does not exist, return a plain torch.Tensor + return qtensor.as_subclass(torch.Tensor) + + return qtensor + + return tree_map(lambda t: set_encoding(t) if isinstance(t, cls) else t, ret)
    + + + +
    +[docs] +class QuantizedTensor(QuantizedTensorBase): + """ + Represents a quantized tensor object. The object holds quantized values stored in a floating-point tensor along with + an :class:`EncodingBase` object which holds the information necessary to map the quantized values back to the + real/represented values. + """ + +
    +[docs] + def quantize(self) -> "QuantizedTensor": + """ + Returns ``self`` + """ + return self
    + + +
    +[docs] + def dequantize(self) -> "DequantizedTensor": + """ + Dequantizes ``self`` using :attr:`self.encoding` to produce a :class:`DequantizedTensor` with the same encoding + information. + + Example: + + >>> from aimet_torch.v2.quantization as Q + >>> x = torch.tensor([[2.57, -2.312], + ... [0.153, 0.205]]) + >>> quantizer = Q.affine.Quantize(shape=(), bitwidth=8, symmetric=True) + >>> quantizer.set_range(-128 * 0.1, 127 * 0.1) + >>> x_q = quantizer(x) + >>> x_q + QuantizedTensor([[ 26., -23.], + [ 2., 2.]], grad_fn=<AliasBackward0>) + >>> x_dq = x_q.dequantize() + >>> x_dq + DequantizedTensor([[ 2.6000, -2.3000], + [ 0.2000, 0.2000]], grad_fn=<AliasBackward0>) + >>> torch.equal(x_dq.encoding.scale, x_q.encoding.scale) + True + """ + if self.encoding is None: + raise EncodingError("Encoding does not exist") + + qtensor = self.encoding.dequantize(self.as_subclass(torch.Tensor)) + qtensor = qtensor.as_subclass(DequantizedTensor) + qtensor.encoding = copy.copy(self.encoding) + return qtensor
    + + +
    +[docs] + def quantized_repr(self) -> torch.Tensor: + # FIXME(kyunggeu): This only works for affine encodings. + # Needs to be generalized for any kind of encodings + if self.encoding is None: + raise EncodingError("Encoding does not exist") + return self.quantize().as_subclass(torch.Tensor).to(self.encoding.dtype)
    +
    + + + +
    +[docs] +class DequantizedTensor(QuantizedTensorBase): + """ + Represents a tensor which has been quantized and subsequently dequantized. This object contains real floating point + data as well as an :class:`EncodingBase` object which holds information about the quantization parameters with which + the data was quantized. With this, a :class:`DequantizedTensor` can be converted back to its quantized representation + without further loss in information. + """ + +
    +[docs] + def quantize(self) -> QuantizedTensor: + """ + Quantizes ``self`` using :attr:`self.encoding` to produce a :class:`QuantizedTensor` with the same encoding + information. + + Example: + + >>> import aimet_torch.v2.quantization as Q + >>> x = torch.tensor([[0.39, 51.0], [3.521, 9.41]]) + >>> quant_dequant = Q.affine.QuantizeDequantize(shape=(), bitwidth=8, symmetric=False) + >>> quant_dequant.set_range(-10, 41) + >>> x_qdq = quant_dequant(x) + >>> x_qdq + DequantizedTensor([[ 0.4000, 41.0000], + [ 3.6000, 9.4000]], grad_fn=<AliasBackward0>) + >>> x_qdq.quantize() + QuantizedTensor([[ 52., 255.], + [ 68., 97.]], grad_fn=<AliasBackward0>) + """ + if self.encoding is None: + raise EncodingError("Encoding does not exist") + + qtensor = self.encoding.quantize(self.as_subclass(torch.Tensor)) + qtensor = qtensor.as_subclass(QuantizedTensor) + qtensor.encoding = copy.copy(self.encoding) + return qtensor
    + + +
    +[docs] + def dequantize(self) -> "DequantizedTensor": + """ + Returns ``self`` + """ + return self
    + + +
    +[docs] + def quantized_repr(self) -> torch.Tensor: + """ + Return the quantized representation of ``self`` as a :class:`torch.Tensor` with data type :attr:`self.encoding.dtype`. + + .. note:: + The result of this function may not be able to carry a gradient depending on the quantized data type. + Thus, it may be necessary to call this only within an autograd function to allow for backpropagation. + + Example: + + >>> import aimet_torch.v2.quantization as Q + >>> x = torch.tensor([[0.39, 51.0], [3.521, 9.41]]) + >>> quant_dequant = Q.affine.QuantizeDequantize(shape=(), bitwidth=8, symmetric=False) + >>> quant_dequant.set_range(-10, 41) + >>> x_qdq = quant_dequant(x) + >>> x_qdq + DequantizedTensor([[ 0.4000, 41.0000], + [ 3.6000, 9.4000]], grad_fn=<AliasBackward0>) + >>> x_qdq.quantized_repr() + tensor([[ 52, 255], + [ 68, 97]], dtype=torch.uint8) + """ + # FIXME(kyunggeu): This only works for affine encodings. + # Needs to be generalized for any kind of encodings + if self.encoding is None: + raise EncodingError("Encoding does not exist") + return self.quantize().as_subclass(torch.Tensor).to(self.encoding.dtype)
    +
    + + + +class EncodingError(RuntimeError): + """Error that indicates an encoding is missing or invalid""" +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v2/quantsim/config_utils.html b/releases/2.0.0/_modules/aimet_torch/v2/quantsim/config_utils.html new file mode 100644 index 0000000..342d924 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v2/quantsim/config_utils.html @@ -0,0 +1,790 @@ + + + + + + + + aimet_torch.v2.quantsim.config_utils - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v2.quantsim.config_utils

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +""" Commonly used utilities for configuring quantsim """
    +
    +from typing import overload, Callable, List, Optional, Tuple, Type, Union
    +import torch
    +from aimet_common.utils import AimetLogger
    +from aimet_torch.v2.quantsim.quantsim import QuantizationSimModel
    +from aimet_torch.v2.quantization.affine import QuantizeDequantize, GroupedBlockQuantizeDequantize
    +from aimet_torch.v2.quantization.float import FloatQuantizeDequantize
    +from aimet_torch.utils import get_device
    +
    +logger = AimetLogger.get_area_logger(AimetLogger.LogAreas.Quant)
    +
    +modules_with_in_out_channels = (torch.nn.Linear,
    +                                torch.nn.Conv1d,
    +                                torch.nn.Conv2d,
    +                                torch.nn.Conv3d,
    +                                torch.nn.ConvTranspose1d,
    +                                torch.nn.ConvTranspose2d,
    +                                torch.nn.ConvTranspose3d)
    +
    +def _get_quantizer_device_or_default(quantizer: torch.nn.Module, default_device: Union[str, torch.device]):
    +    """ Get device from quantizer if possible, else return default_device """
    +    try:
    +        device = get_device(quantizer)
    +    except StopIteration:
    +        device = default_device
    +    return device
    +
    +def _get_in_channels_dim(module: torch.nn.Module):
    +    """ Get input channels dimension for the given module """
    +    if not isinstance(module, modules_with_in_out_channels):
    +        raise AssertionError(f'In channels not defined for module of type {type(module)}')
    +    if isinstance(module, (torch.nn.ConvTranspose1d,
    +                           torch.nn.ConvTranspose2d,
    +                           torch.nn.ConvTranspose3d)):
    +        return 0
    +    return 1
    +
    +def _get_out_channels_dim(module: torch.nn.Module):
    +    """ Get input channels dimension for the given module """
    +    if not isinstance(module, modules_with_in_out_channels):
    +        raise AssertionError(f'Out channels not defined for module of type {type(module)}')
    +    if isinstance(module, (torch.nn.ConvTranspose1d,
    +                           torch.nn.ConvTranspose2d,
    +                           torch.nn.ConvTranspose3d)):
    +        return 1
    +    return 0
    +
    +def _get_block_size_array_for_module(module: torch.nn.Module, block_size: Union[int, Tuple[int, ...]]):
    +    """
    +    Return block size array for a module given a single block size value, assuming that the block size value is to be
    +    applied to the in_channels dimension, and the out_channels dimension is per channel.
    +    """
    +    if isinstance(block_size, (tuple, list)):
    +        return block_size
    +
    +    assert isinstance(block_size, int)
    +    if not isinstance(module, modules_with_in_out_channels):
    +        error_msg = f'Single value block size is only supported for modules of types in ' \
    +                    f'config_utils.modules_with_in_out_channels, but got module of type {type(module)}. Update ' \
    +                    f'the argument for identifying modules to set to exclude unsupported types.'
    +        raise RuntimeError(error_msg)
    +    assert hasattr(module, 'weight')
    +
    +    # Initialize block sizes with -1, meaning blocks will span the entire dimension for each axis
    +    block_size_array = [-1] * len(module.weight.shape)
    +
    +    # Set in channels dimension block size to block_size, and set out channels dimension block size to 1 (per channel)
    +    block_size_array[_get_in_channels_dim(module)] = block_size
    +    block_size_array[_get_out_channels_dim(module)] = 1
    +    return block_size_array
    +
    +
    +def _get_block_grouping_array_for_module(module: torch.nn.Module, block_grouping: Union[int, Tuple[int, ...]]):
    +    """
    +    Return block grouping array for a module given a single block grouping value, assuming that the block grouping value
    +    is to be applied to the in_channels dimension.
    +    """
    +    if isinstance(block_grouping, (tuple, list)):
    +        return block_grouping
    +
    +    assert isinstance(block_grouping, int)
    +    if not isinstance(module, modules_with_in_out_channels):
    +        error_msg = f'Single value block grouping is only supported for modules of types in ' \
    +                    f'config_utils.modules_with_in_out_channels, but got module of type {type(module)}. Update ' \
    +                    f'the argument for identifying modules to set to exclude unsupported types.'
    +        raise RuntimeError(error_msg)
    +    assert hasattr(module, 'weight')
    +
    +    # Initialize block grouping with 1, meaning no blocks will be grouped together in each dimension
    +    block_grouping_array = [1] * len(module.weight.shape)
    +
    +    # Set in channels dimension block size to block_grouping
    +    block_grouping_array[_get_in_channels_dim(module)] = block_grouping
    +    return block_grouping_array
    +
    +
    +def _parse_arg_for_condition(arg):
    +    """ Transform the given arg into a corresponding condition expression """
    +    if isinstance(arg, List) and isinstance(arg[0], type) and issubclass(arg[0], torch.nn.Module):
    +        module_type = arg
    +        condition = lambda module: isinstance(module, tuple(module_type))
    +    elif isinstance(arg, List):
    +        if not isinstance(arg[0], torch.nn.Module):
    +            raise RuntimeError('List given as arg must contain either torch.nn.Module types or specific '
    +                               'torch.nn.Module objects.')
    +        qmodules = arg
    +        condition = lambda module: module in qmodules
    +    else:
    +        condition = arg
    +    return condition
    +
    +
    +def _get_weight_quantizer_shape_from_block_size(quant_layer: torch.nn.Module, block_size: Tuple[int, ...]) \
    +        -> Optional[List[int]]:
    +    """ Given a block size, get the corresponding weight quantizer shape """
    +    weight_shape = quant_layer.weight.shape
    +    block_size = _get_block_size_array_for_module(quant_layer, block_size)
    +    assert len(block_size) == len(weight_shape)
    +    quantizer_shape = []
    +    for idx, shape in enumerate(weight_shape):
    +        if block_size[idx] != -1:
    +            if not shape % block_size[idx] == 0:
    +                return None
    +
    +            quantizer_shape.append(shape // block_size[idx])
    +        else:
    +            quantizer_shape.append(1)
    +    return quantizer_shape
    +
    +
    +@overload
    +def set_activation_quantizers_to_float(sim: QuantizationSimModel, module_type: List[Type[torch.nn.Module]],
    +                                       exponent_bits: int = None, mantissa_bits: int = None,
    +                                       dtype: torch.dtype = None):
    +    """ Set activation quantizers of the given module type to float """
    +
    +
    +@overload
    +def set_activation_quantizers_to_float(sim: QuantizationSimModel, qmodules: List[torch.nn.Module],
    +                                       exponent_bits: int = None, mantissa_bits: int = None, dtype: torch.dtype = None):
    +    """ Set activation quantizers of the given qmodules to float """
    +
    +
    +@overload
    +def set_activation_quantizers_to_float(sim: QuantizationSimModel, condition: Callable[[torch.nn.Module], bool],
    +                                       exponent_bits: int = None, mantissa_bits: int = None, dtype: torch.dtype = None):
    +    """ Set activation quantizers of all the modules that satisfy the given condition to float. """
    +
    +
    +
    +[docs] +def set_activation_quantizers_to_float(sim: QuantizationSimModel, arg, exponent_bits: int = None, + mantissa_bits: int = None, dtype: torch.dtype = None): + """ + Set activation quantizers of modules to float. + + :param sim: Quantsim to set activation quantizers for + :param arg: Argument determining which modules to set. This can consist of either: + + 1. A list of torch.nn.Module types, in which case all modules whose type is in the list will be set + + 2. A list of torch.nn.Modules, in which case all modules in the list will be set + + 3. A callable function which takes a torch.nn.Module as input and returns True if the module is to be set, False + otherwise + :param exponent_bits: Number of exponent bits to simulate + :param mantissa_bits: Number of mantissa bits to simulate + :param dtype: torch.dtype to simulate. This argument is mutually exclusive with exponent_bits and mantissa_bits. + + Examples: + + >>> # Assume 'sim' is a QuantizationSimModel object imported from aimet_torch.v2.quantsim + >>> # Allows setting of all Linear and Conv output quantizers to floating point activation quantization: + >>> set_activation_quantizers_to_float(sim=sim, + ... arg=[torch.nn.Linear, torch.nn.Conv2d], + ... dtype=torch.float16) + >>> # Allows setting of specific model layers' output quantizers to floating point activation quantization: + >>> set_activation_quantizers_to_float(sim=sim, + ... arg=[sim.model.conv2, sim.model.linear1], + ... dtype=torch.float16) + >>> # Allows setting of only Convolution layers with input channels dim == 128 to floating point activation quantization: + >>> set_activation_quantizers_to_float(sim=sim, + ... arg=lambda module: isinstance(module, torch.nn.Conv2d) and module.weight.shape[1] == 128, + ... dtype=torch.float16) + """ + + condition = _parse_arg_for_condition(arg) + _set_activation_quantizers_to_float(sim, condition, exponent_bits, mantissa_bits, dtype)
    + + + +def _set_activation_quantizers_to_float(sim: QuantizationSimModel, condition: Callable[[torch.nn.Module], bool], + exponent_bits: int = None, mantissa_bits: int = None, + dtype: torch.dtype = None): + """ Set activation quantizers of all the modules that satisfy the given condition to float. """ + model_device = get_device(sim.model) + for _, quant_layer in sim.named_qmodules(): + if condition(quant_layer): + for idx, quantizer in enumerate(quant_layer.input_quantizers): + if quantizer is not None: + device = _get_quantizer_device_or_default(quantizer, model_device) + quant_layer.input_quantizers[idx] = FloatQuantizeDequantize(exponent_bits, mantissa_bits, dtype).to(device) + + for idx, quantizer in enumerate(quant_layer.output_quantizers): + if quantizer is not None: + device = _get_quantizer_device_or_default(quantizer, model_device) + quant_layer.output_quantizers[idx] = FloatQuantizeDequantize(exponent_bits, mantissa_bits, dtype).to(device) + + +@overload +def set_blockwise_quantization_for_weights(sim: QuantizationSimModel, module_type: List[Type[torch.nn.Module]], + bitwidth: int, symmetric: bool, block_size: Union[int, Tuple[int, ...]]): + """ Set weight parameter quantizers of the given module type to blockwise """ + + +@overload +def set_blockwise_quantization_for_weights(sim: QuantizationSimModel, qmodules: List[torch.nn.Module], bitwidth: int, + symmetric: bool, block_size: Union[int, Tuple[int, ...]]): + """ Set weight parameter quantizers of the given modules to blockwise """ + + +@overload +def set_blockwise_quantization_for_weights(sim: QuantizationSimModel, condition: Callable[[torch.nn.Module], bool], + bitwidth: int, symmetric: bool, block_size: Union[int, Tuple[int, ...]]): + """ Set weight parameter quantizers of modules that satisfy the given condition to blockwise """ + + +
    +[docs] +def set_blockwise_quantization_for_weights(sim: QuantizationSimModel, arg, bitwidth: int, symmetric: bool, + block_size: Union[int, Tuple[int, ...]]): + """ + Set weight parameter quantizers of modules to blockwise. + + :param sim: Quantsim to set weight quantizers for + :param arg: Argument determining which modules to set. This can consist of either: + + 1. A list of torch.nn.Module types, in which case all modules whose type is in the list will be set + + 2. A list of torch.nn.Modules, in which case all modules in the list will be set + + 3. A callable function which takes a torch.nn.Module as input and returns True if the module is to be set, False + otherwise + :param bitwidth: Bitwidth for affine quantization + :param symmetric: True if affine quantization is symmetric, False otherwise + :param block_size: Block size for affine quantization. This can be an array in which case all layers identified + by arg must have weight shapes compatible with the array length, or can be an integer value, in which case the + block size will be applied to the weight's in_channels dimension, and per channel will be used for the weight's + out_channels dimension. + + A block size value of -1 for a particular dimension is equivalent to a block size equal + to the size of that particular dimension. + + Examples: + + >>> # Assume 'sim' is a QuantizationSimModel object imported from aimet_torch.v2.quantsim + >>> # Allows setting of all Linear and Conv weight quantizers to block_size 64 in the input_channels dimension: + >>> set_blockwise_quantization_for_weights(sim=sim, + ... arg=[torch.nn.Linear, torch.nn.Conv2d], + ... bitwidth=4, + ... symmetric=True, + ... block_size=64) + >>> # Allows setting of specific model layers' weight quantizer block_size to 64 in the input_channels dimension: + >>> set_blockwise_quantization_for_weights(sim=sim, + ... arg=[sim.model.conv2, sim.model.linear1], + ... bitwidth=4, + ... symmetric=True, + ... block_size=64) + >>> # Allows setting of only Convolution layers with input channels dim == 128 to block_size 64 in the input_channels dimension + >>> set_blockwise_quantization_for_weights(sim=sim, + ... arg=lambda module: isinstance(module, torch.nn.Conv2d) and module.weight.shape[1] == 128, + ... bitwidth=4, + ... symmetric=True, + ... block_size=64) + """ + condition = _parse_arg_for_condition(arg) + _set_blockwise_quantization_for_weights(sim, condition, bitwidth, symmetric, block_size)
    + + + +def _get_layers_to_quantizer_shapes_for_block_size(sim, condition, block_size): + layer_to_quantizer_shape_dict = {} + invalid_layers_for_block_size = [] + for name, quant_layer in sim.named_qmodules(): + if condition(quant_layer) and 'weight' in quant_layer.param_quantizers and \ + quant_layer.param_quantizers['weight'] is not None: + assert hasattr(quant_layer, 'weight') + layer_to_quantizer_shape_dict[quant_layer] = \ + _get_weight_quantizer_shape_from_block_size(quant_layer, block_size) + if layer_to_quantizer_shape_dict[quant_layer] is None: + invalid_layers_for_block_size.append((name, quant_layer.weight.shape)) + + if invalid_layers_for_block_size: + for name, shape in invalid_layers_for_block_size: + error_str = f"Quant layer {name} has shape {shape} which does not align with block_size {block_size}. " \ + f"Each dimension's shape must divide evenly with the corresponding block size." + logger.error(error_str) + raise RuntimeError('Quant layers found whose weights do not align with block size.') + + return layer_to_quantizer_shape_dict + + +def _set_blockwise_quantization_for_weights(sim: QuantizationSimModel, condition: Callable[[torch.nn.Module], bool], + bitwidth: int, symmetric: bool, block_size: Union[int, Tuple[int, ...]]): + """ Set weight parameter quantizers of modules that satisfy the given condition to blockwise """ + model_device = get_device(sim.model) + layer_to_quantizer_shape_dict = _get_layers_to_quantizer_shapes_for_block_size(sim, condition, block_size) + for layer, quantizer_shape in layer_to_quantizer_shape_dict.items(): + layer_block_size = _get_block_size_array_for_module(layer, block_size) + device = _get_quantizer_device_or_default(layer.param_quantizers['weight'], model_device) + layer.param_quantizers['weight'] = QuantizeDequantize(quantizer_shape, bitwidth, symmetric, None, + layer_block_size).to(device) + + +@overload +def set_grouped_blockwise_quantization_for_weights(sim: QuantizationSimModel, module_type: List[Type[torch.nn.Module]], + bitwidth: int, symmetric: bool, decompressed_bw: int, + block_size: Union[int, Tuple[int, ...]], + block_grouping: Union[int, Tuple[int, ...]] = -1): + """ Set weight parameter quantizers of the given module type to grouped blockwise """ + + +@overload +def set_grouped_blockwise_quantization_for_weights(sim: QuantizationSimModel, qmodules: List[torch.nn.Module], + bitwidth: int, symmetric: bool, decompressed_bw: int, + block_size: Union[int, Tuple[int, ...]], + block_grouping: Union[int, Tuple[int, ...]] = -1): + """ Set weight parameter quantizers of the given modules to grouped blockwise """ + + +@overload +def set_grouped_blockwise_quantization_for_weights(sim: QuantizationSimModel, + condition: Callable[[torch.nn.Module], bool], + bitwidth: int, symmetric: bool, decompressed_bw: int, + block_size: Union[int, Tuple[int, ...]], + block_grouping: Union[int, Tuple[int, ...]] = -1): + """ Set weight parameter quantizers of modules that satisfy the given condition to grouped blockwise """ + + +
    +[docs] +def set_grouped_blockwise_quantization_for_weights(sim: QuantizationSimModel, arg, + bitwidth: int, symmetric: bool, decompressed_bw: int, + block_size: Union[int, Tuple[int, ...]], + block_grouping: Union[int, Tuple[int, ...]] = -1): + """ + Set weight parameter quantizers of modules to grouped blockwise. + + :param sim: Quantsim to set weight quantizers for + :param arg: Argument determining which modules to set. This can consist of either: + + 1. A list of torch.nn.Module types, in which case all modules whose type is in the list will be set + + 2. A list of torch.nn.Modules, in which case all modules in the list will be set + + 3. A callable function which takes a torch.nn.Module as input and returns True if the module is to be set, False + otherwise + :param bitwidth: Bitwidth for affine quantization + :param symmetric: True if affine quantization is symmetric, False otherwise + :param decompressed_bw: Decompressed bw for grouped block quantization + :param block_size: Block size for affine quantization. This can be an array in which case all layers identified + by arg must have weight shapes compatible with the array length, or can be an integer value, in which case the + block size will be applied to the weight's in_channels dimension and per channel will be used for the weight's + out_channels dimension. + + A block size value of -1 for a particular dimension is equivalent to a block size equal + to the size of that particular dimension. + :param block_grouping: Block grouping for grouped block quantization. This can be an array in which case all layers + identified by arg must have weight shapes compatible with the array length, or can be an integer value, in which + case the block grouping will be applied to the weight's in_channels dimension, and no other dimensions will + experience block grouping. + + A block grouping value of -1 for a particular dimension is equivalent to a block + grouping equal to the number of blocks for that particular dimension. + + Examples: + + >>> # Assume 'sim' is a QuantizationSimModel object imported from aimet_torch.v2.quantsim + >>> # Allows setting of all Linear and Conv weight quantizers to LPBQ with block_size 64 in the input_channels dimension: + >>> set_grouped_blockwise_quantization_for_weights(sim=sim, + ... arg=[torch.nn.Linear, torch.nn.Conv2d], + ... bitwidth=4, + ... symmetric=True, + ... decompressed_bw=8, + ... block_size=64, + ... block_grouping=-1) + >>> # Allows setting of specific model layers' weight quantizer to LPBQ with block_size 64 in the input_channels dimension: + >>> set_grouped_blockwise_quantization_for_weights(sim=sim, + ... arg=[sim.model.conv2, sim.model.linear1], + ... bitwidth=4, + ... symmetric=True, + ... decompressed_bw=8, + ... block_size=64, + ... block_grouping=-1) + >>> # Allows setting of only Convolution layers with input channels dim == 128 to LPBQ with block_size 64 in the input_channels dimension: + >>> set_grouped_blockwise_quantization_for_weights(sim=sim, + ... arg=lambda module: isinstance(module, torch.nn.Conv2d) and module.weight.shape[1] == 128, + ... bitwidth=4, + ... symmetric=True, + ... decompressed_bw=8, + ... block_size=64, + ... block_grouping=-1) + """ + condition = _parse_arg_for_condition(arg) + _set_grouped_blockwise_quantization_for_weights(sim, condition, bitwidth, symmetric, decompressed_bw, block_size, + block_grouping)
    + + + +def _set_grouped_blockwise_quantization_for_weights(sim: QuantizationSimModel, + condition: Callable[[torch.nn.Module], bool], + bitwidth: int, symmetric: bool, decompressed_bw: int, + block_size: Union[int, Tuple[int, ...]], + block_grouping: Union[int, Tuple[int, ...]]): + """ Set weight parameter quantizers of modules that satisfy the given condition to grouped blockwise """ + model_device = get_device(sim.model) + layer_to_quantizer_shape_dict = _get_layers_to_quantizer_shapes_for_block_size(sim, condition, block_size) + for layer, quantizer_shape in layer_to_quantizer_shape_dict.items(): + layer_block_size = _get_block_size_array_for_module(layer, block_size) + layer_block_grouping = _get_block_grouping_array_for_module(layer, block_grouping) + device = _get_quantizer_device_or_default(layer.param_quantizers['weight'], model_device) + layer.param_quantizers['weight'] = GroupedBlockQuantizeDequantize(quantizer_shape, bitwidth, symmetric, + decompressed_bw, None, layer_block_size, + layer_block_grouping).to(device) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v2/quantsim/quantsim.html b/releases/2.0.0/_modules/aimet_torch/v2/quantsim/quantsim.html new file mode 100644 index 0000000..708f562 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v2/quantsim/quantsim.html @@ -0,0 +1,938 @@ + + + + + + + + aimet_torch.v2.quantsim.quantsim - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v2.quantsim.quantsim

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +""" Top level API for performing quantization simulation of a pytorch model """
    +
    +import copy
    +from typing import Union, Tuple, Optional, Sequence, TypeVar, Any, Callable, overload
    +import warnings
    +import itertools
    +import io
    +import contextlib
    +import torch
    +
    +from aimet_common.defs import QuantScheme, QuantizationDataType
    +from aimet_torch._base.quantsim import (
    +    _QuantizationSimModelBase,
    +    logger,
    +    unquantizable_modules,
    +    QuantParams,
    +    ExportableQuantModule,
    +    save_checkpoint,
    +    load_checkpoint,
    +    check_accumulator_overflow,
    +)
    +from aimet_torch.v2 import nn as aimet_nn
    +from aimet_torch.v2.nn import BaseQuantizationMixin, QuantizationMixin
    +from aimet_torch.v2.nn.fake_quant import _legacy_impl
    +from aimet_torch.v2._builder import _V2LazyQuantizeWrapper
    +from aimet_torch.v2.quantization.base import QuantizerBase
    +from aimet_torch.v2.quantization.affine import AffineQuantizerBase
    +from aimet_torch.v2.quantization.encoding_analyzer import PercentileEncodingAnalyzer
    +from aimet_torch.v2.utils import patch_attr
    +from aimet_torch import utils
    +from aimet_torch.utils import deprecated, _red
    +from aimet_torch.v2.deepspeed_utils import _register_zero3_forward_hooks
    +
    +__all__ = [
    +    'QuantizationSimModel',
    +    'QuantParams',
    +    'ExportableQuantModule',
    +    'save_checkpoint',
    +    'load_checkpoint',
    +    'check_accumulator_overflow',
    +    'load_encodings_to_sim',
    +    'compute_encodings_for_sims',
    +]
    +
    +unquantizable_modules = (QuantizerBase, *unquantizable_modules)
    +quantized_modules = (BaseQuantizationMixin, _V2LazyQuantizeWrapper)
    +containers = (
    +    torch.nn.Container,
    +    torch.nn.Sequential,
    +    torch.nn.ModuleList,
    +    torch.nn.ModuleDict,
    +    torch.nn.ParameterList,
    +    torch.nn.ParameterDict,
    +)
    +
    +
    +class _NOT_SPECIFIED:
    +    pass
    +
    +
    +def _convert_to_qmodule(module: torch.nn.Module):
    +    """
    +    Helper function to convert all modules to quantized aimet.nn modules.
    +    """
    +    if not isinstance(module, (*quantized_modules, *unquantizable_modules, *containers)):
    +        try:
    +            module = QuantizationMixin.from_module(module)
    +        except RuntimeError as e:
    +            try:
    +                module = _legacy_impl.FakeQuantizationMixin.from_module(module)
    +            except RuntimeError:
    +                if not tuple(module.children()):
    +                    raise e # pylint: disable=raise-missing-from
    +
    +    for name, child in module.named_children():
    +        setattr(module, name, _convert_to_qmodule(child))
    +
    +    return module
    +
    +
    +
    +[docs] +class QuantizationSimModel(_QuantizationSimModelBase): + """ + Class that simulates the quantized model execution on a target hardware backend. + + QuantizationSimModel simulates quantization of a given model by converting + all PyTorch modules into :ref:`quantized modules<api-torch-quantized-modules>` + with input/output/parameter :ref:`quantizers<api-torch-quantizers>` as necessary. + + Example: + + >>> model = torchvision.models.resnet18() + >>> dummy_input = torch.randn(1, 3, 224, 224) + >>> sim = QuantizationSimModel(model, dummy_input) + >>> print(model) + ResNet( + (conv1): Conv2d( + 3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False + ) + ... + ) + >>> print(sim.model) + ResNet( + (conv1): QuantizedConv2d( + 3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False + (param_quantizers): ModuleDict( + (weight): QuantizeDequantize(shape=(), qmin=-128, qmax=127, symmetric=True) + ) + (input_quantizers): ModuleList( + (0): QuantizeDequantize(shape=(), qmin=0, qmax=255, symmetric=False) + ) + (output_quantizers): ModuleList( + (0): None + ) + ) + ... + ) + """ + _quantized_modules = quantized_modules + + def __init__(self, # pylint: disable=too-many-arguments, too-many-locals, too-many-branches + model: torch.nn.Module, + dummy_input: Union[torch.Tensor, Sequence[torch.Tensor]], + quant_scheme: Union[str, QuantScheme] = None, # NOTE: Planned to be deprecated + rounding_mode: Optional[str] = None, # NOTE: Planned to be deprecated + default_output_bw: int = 8, + default_param_bw: int = 8, + in_place: bool = False, + config_file: Optional[str] = None, + default_data_type: QuantizationDataType = QuantizationDataType.int): + """ + .. warning:: + `rounding_mode` parameter is deprecated. + Passing `rounding_mode` will throw runtime error in >=1.35. + + .. warning:: + The default value of `quant_scheme` will change + from `QuantScheme.post_training_tf_enhanced` to `QuantScheme.training_range_learning_with_tf_init` + in the future versions, and will be deprecated in the longer term. + + Args: + model (torch.nn.Module): Model to simulate the quantized execution of + dummy_input (Tensor | Sequence[Tensor]): Dummy input to be used to capture + the computational graph of the model. All input tensors are expected to be + already placed on the appropriate devices to run forward pass of the model. + quant_scheme (QuantScheme, optional): Quantization scheme that indicates + how to observe and calibrate the quantization encodings (Default: `QuantScheme.post_training_tf_enhanced`) + rounding_mode: Deprecated + default_output_bw (int, optional): Default bitwidth (4-31) to use for quantizing all layer inputs and outputs + unless otherwise specified in the config file. (Default: 8) + default_param_bw (int, optional): Default bitwidth (4-31) to use for quantizing all layer parameters + unless otherwise specified in the config file. (Default: 8) + in_place (bool, optional): If True, then the given model is modified in-place into a quantized model. (Default: `False`) + config_file (str, optional): Path to the quantization simulation config file (Default: `None`) + default_data_type (QuantizationDataType, optional): Default data type to use for quantizing all + inputs, outputs and parameters unless otherwise specified in the config file. + Possible options are QuantizationDataType.int and QuantizationDataType.float. + Note that the mode default_data_type=QuantizationDataType.float is only supported with + default_output_bw=16 or 32 and default_param_bw=16 or 32. (Default: `QuantizationDataType.int`) + """ + if not quant_scheme: + old_default = QuantScheme.post_training_tf_enhanced + new_default = QuantScheme.training_range_learning_with_tf_init + msg = _red(f"The default value of 'quant_scheme' has changed from '{old_default}' " + f"to '{new_default}' since aimet-torch==2.0.0. " + "If you wish to maintain the legacy default behavior, " + f"please explicitly pass 'quant_scheme={old_default}'") + warnings.warn(msg, DeprecationWarning, stacklevel=2) + quant_scheme = new_default + + if rounding_mode: + if rounding_mode == 'nearest': + warnings.warn(_red("Passing rounding_mode='nearest' is no longer needed "\ + "and will be deprecated soon in the later versions."), + DeprecationWarning, stacklevel=2) + else: + raise TypeError("'rounding_mode' parameter is no longer supported.") + + qmodules = { + name: module for name, module in model.named_modules() + if isinstance(module, BaseQuantizationMixin) + } + quantizers = { + name: module for name, module in model.named_modules() + if isinstance(module, QuantizerBase) + } + + if isinstance(model, BaseQuantizationMixin): + problem = f"the model itself is already a quantized module of type {type(model)}." + elif isinstance(model, QuantizerBase): + problem = f"the model itself is already a quantizer object of type {type(model)}." + elif qmodules: + problem = f"the model already contains quantized modules: {', '.join(qmodules.keys())}." + elif quantizers: + problem = f"the model already contains quantizers: {', '.join(quantizers.keys())}." + else: + problem = None + + if problem: + raise RuntimeError( + "QuantizationSimModel can only take base models WITHOUT quantized modules or quantizers, " + "but " + problem + ) + + if not in_place: + model = copy.deepcopy(model) + in_place = True + + model = _convert_to_qmodule(model) + + with _register_zero3_forward_hooks(model, use_dummy_params=True): + # NOTE: Register for the model is pre-partitioned by deepspeed zero3 or zero3-offload. + # Pre-partitioned models aren't runnable as-is, but are needed to to be initialized + # with `deepspeed.initialize` before running forward pass. + # However, `deepspeed.initialize` can only come after quantsim is created, since + # quantsim will add additional learnable parameters to the model which also need + # to be initialized by deepspeed. + # Since quantsim constructor relies on torch.jit tracing which involves running + # forward pass of the model, here we register a temporary hook to make + # uninitialized but pre-partitioned models runnable. + super().__init__(model, dummy_input, quant_scheme, + rounding_mode='nearest', + default_output_bw=default_output_bw, + default_param_bw=default_param_bw, + in_place=in_place, + config_file=config_file, + default_data_type=default_data_type) + + # Quantization parameters are placed on cpu by default. + # Move them to cuda device as necessary + + default_device = torch.device('cpu') + + for param_or_buffer in itertools.chain(self.model.parameters(), self.model.buffers()): + if param_or_buffer.device.type != 'cpu': + # Use the first non-cpu device as default device. + # Default device is necessary for the input/output quantizers of + # modules without any parameters such as ReLU + default_device = param_or_buffer.device + break + + for module in self.model.modules(): + if not isinstance(module, BaseQuantizationMixin): + continue + + try: + # Find the device of the first parameter of the orignal module + param_or_buffer = next(iter(itertools.chain(module.parameters(recurse=False), + module.buffers(recurse=False)))) + device = param_or_buffer.device + except StopIteration: + # If the original module has no parameter, use default device + device = default_device + + # Set quantization parameters to the device of the original module + module.to(device=device) + + @overload + def compute_encodings(self, forward_pass_callback: Callable[[torch.nn.Module], Any]): # pylint: disable=arguments-differ + ... + + T = TypeVar('T') + + @overload + def compute_encodings(self, # pylint: disable=arguments-differ + forward_pass_callback: Callable[[torch.nn.Module, T], Any], + forward_pass_callback_args: T): + ... + + del T + + # pylint: disable=arguments-differ +
    +[docs] + def compute_encodings(self, forward_pass_callback, forward_pass_callback_args=_NOT_SPECIFIED): + r""" + Computes encodings for all quantizers in the model. + + This API will invoke `forward_pass_callback`, a function written by the user that runs + forward pass(es) of the quantized model with a small, representative subset of the training dataset. + By doing so, the quantizers in the quantized model will observe the inputs and initialize + their quantization encodings according to the observed input statistics. + + This function is overloaded with the following signatures: + + .. function:: compute_encodings(forward_pass_callback) + :noindex: + + :param forward_pass_callback_: A function that takes a quantized model and runs forward passes + with a small, representative subset of training dataset + :type forward_pass_callback_: Callable[[torch.nn.Module], Any] + + .. function:: compute_encodings(forward_pass_callback, forward_pass_callback_args) + :noindex: + + :param forward_pass_callback_: A function that takes a quantized model and runs forward passes + with a small, representative subset of training dataset + :type forward_pass_callback_: Callable[[torch.nn.Module, T], Any] + :param T forward_pass_callback_args: The second argument to `forward_pass_callback`. + + Example: + + >>> sim = QuantizationSimModel(...) + >>> _ = sim.model(input) # Can't run forward until quantizer encodings are initialized + RuntimeError: Failed to run QuantizeDequantize since quantization parameters are not initialized. + Please initialize the quantization parameters using `compute_encodings()`. + >>> def run_forward_pass(quantized_model: torch.nn.Module): + ... for input in train_dataloader: + ... with torch.no_grad(): + ... _ = quantized_model(input) + ... + >>> sim.compute_encodings(run_forward_pass) + >>> _ = sim.model(input) # Now runs successfully! + """ + + if forward_pass_callback_args is _NOT_SPECIFIED: + args = (self.model,) + else: + args = (self.model, forward_pass_callback_args) + + # Run forward iterations so we can collect statistics to compute the appropriate encodings + with utils.in_eval_mode(self.model), torch.no_grad(): + with aimet_nn.compute_encodings(self.model): + _ = forward_pass_callback(*args)
    + + +
    +[docs] + def export(self, path: str, filename_prefix: str, dummy_input: Union[torch.Tensor, Tuple], + *args, **kwargs): + if isinstance(dummy_input, torch.Tensor): + dummy_input = (dummy_input,) + + @torch.no_grad() + def concretize_block_size(qtzr, inp): + """ + Fill in block sizes for dimensions with block size -1 + """ + inp, = inp + dims = len(qtzr.block_size) + input_shape = inp.shape[-dims:] + scale_shape = qtzr.get_scale().shape[-dims:] + block_size = qtzr.block_size + + concrete_block_size = tuple(inp_size//scale_size if blk_size == -1 else blk_size + for inp_size, scale_size, blk_size + in zip(input_shape, scale_shape, block_size)) + ctx = patch_attr(qtzr, 'block_size', concrete_block_size) + stack.enter_context(ctx) + + handles = [] + + try: + with contextlib.ExitStack() as stack: + for qtzr in self.model.modules(): + if not isinstance(qtzr, AffineQuantizerBase): + continue + + if qtzr.block_size and any(size == -1 for size in qtzr.block_size): + h = qtzr.register_forward_pre_hook(concretize_block_size) + handles.append(h) + + if handles: + with utils.in_eval_mode(self.model), torch.no_grad(): + _ = self.model(*dummy_input) + + return super().export(path, filename_prefix, dummy_input, *args, **kwargs) + + finally: + for h in handles: + h.remove()
    + + + def set_percentile_value(self, percentile_value: float): + """ + Set the percentile value to be used while computing encodings + """ + self._percentile_value = percentile_value + for module in self.model.modules(): + if isinstance(module, QuantizerBase): + if isinstance(module.encoding_analyzer, PercentileEncodingAnalyzer): + module.encoding_analyzer.set_percentile(percentile_value) + + def __str__(self): + stream = io.StringIO(newline='\n') + stream.write("-------------------------\n") + stream.write("Quantized Model Report\n") + stream.write("-------------------------\n") + stream.write(f"{self.model}\n") + return stream.getvalue() + + def exclude_param_from_quantization(self, param_name_to_exclude: str): + """ + Excludes all parameters matching 'param_name' from quantization + :param param_name_to_exclude: Name of the parameter to exclude + :return: None + """ + super().exclude_param_from_quantization(param_name_to_exclude) + for module in self.model.modules(): + if isinstance(module, BaseQuantizationMixin): + if param_name_to_exclude in module.param_quantizers: + module.param_quantizers[param_name_to_exclude] = None + + # pylint: disable=missing-function-docstring + @staticmethod + def compute_layer_encodings_for_sim(sim: 'QuantizationSimModel'): + raise NotImplementedError("QuantizationSimModel.compute_layer_encodings_for_sim has been removed.") + + # pylint: disable=missing-function-docstring, unused-argument + @staticmethod + def prepare_sim_for_compute_encodings(sim: 'QuantizationSimModel'): + logger.warning("QuantizationSimModel.prepare_sim_for_compute_encodings has been deprecated and is no longer necessary. " + "Any calls can be safely removed.") + + # pylint: disable=missing-function-docstring + @classmethod + def set_mode_for_recurrent_module(cls, layer, name: str): + raise NotImplementedError("QuantizationSimModel.set_mode_for_recurrent_module has been removed.") + + @staticmethod + def save_model_with_embedded_quantization_nodes(sim_model, path: str, filename_prefix: str, + dummy_input, onnx_export_args=None, + export_to_torchscript=False, is_conditional=False): + raise NotImplementedError("QuantizationSimModel.save_model_with_embedded_quantization_nodes has been removed.") + + @staticmethod + def _replace_quantization_wrapper_with_native_torch_quantization_nodes(quant_sim_model, device: torch.device): + raise NotImplementedError() + + @classmethod + @torch.no_grad() + def _apply_qdq_to_model_parameters(cls, model: torch.nn.Module): + """ + Applies quant-dequant to the parameters of a PyTorch model + to avoid rounding error during weight quantization. + + :param model: The PyTorch model whose parameters will be quant-dequantized. + """ + for module in model.modules(): + if isinstance(module, BaseQuantizationMixin): + # pylint: disable=protected-access + module._patch_quantized_parameters() + if isinstance(module, QuantizationMixin): + module._patch_dequantized_parameters() + cls._update_parameters_by_attr(module) + + def named_qmodules(self): + """Generator that yields all quantized modules in the model and their names + """ + for name, module in self.model.named_modules(): + if isinstance(module, (BaseQuantizationMixin, _V2LazyQuantizeWrapper)): + yield name, module + + @deprecated(f'Use {named_qmodules.__qualname__} instead.') + def quant_wrappers(self): # pylint: disable=missing-docstring + return self.named_qmodules() + + # Overrides V1QuantizationSimModel._add_quantization_wrappers + def _add_quantization_wrappers(self, module, num_inout_tensors, default_data_type): + # pylint: disable=protected-access + for name, child in module.named_children(): + if isinstance(child, BaseQuantizationMixin): + child_wrapper = self._create_quantizer_module(child, num_inout_tensors, default_data_type) + setattr(module, name, child_wrapper) + child = child_wrapper._module_to_wrap + self._add_quantization_wrappers(child, num_inout_tensors, default_data_type) + + def _realize_quant_wrappers_in_model(self, model: torch.nn.Module): + for name, child in model.named_children(): + if isinstance(child, _V2LazyQuantizeWrapper): + child = child.realize() + setattr(model, name, child) + self._realize_quant_wrappers_in_model(child) + + def _create_quantizer_module(self, module_to_quantize: torch.nn.Module, num_inout_tensors, + data_type: QuantizationDataType) -> torch.nn.Module: + """Instantiates wrapper based on quant scheme + """ + # We lookup the number of input and output tensors already determined + # Special case, we are adding a wrapper for a module not in the forward pass: Use default of 1, 1 + num_in_tensors, num_out_tensors = num_inout_tensors.get(module_to_quantize, (1, 1)) + quantized_module = _V2LazyQuantizeWrapper(module_to_quantize, self._default_param_bw, self._default_output_bw, + self._rounding_mode, self._quant_scheme, num_inputs=num_in_tensors, + num_outputs=num_out_tensors, data_type=data_type) + return quantized_module + + @classmethod + def _remove_quantization_wrappers(cls, starting_module, list_of_modules_to_exclude): + """ + Recursively remove quantization wrappers from all appropriate modules starting with a given module + :param starting_module: Module to recursive search downstream from + :param list_of_modules_to_exclude: List of torch modules to remove quantization wrappers from (if present) + :return: None + """ + for name, module in starting_module.named_children(): + if module in list_of_modules_to_exclude: + if isinstance(module, BaseQuantizationMixin): + orig_module = module.get_original_module() + setattr(starting_module, name, orig_module) + module = orig_module + # Recursively call children modules if present + if not utils.is_leaf_module(module): + cls._remove_quantization_wrappers(module, list_of_modules_to_exclude)
    + + + +@deprecated(""" +Use QuantizationSimModel.load_encodings with the following keyword arguments instead: +``` +sim.load_encodings(encoding_path + strict=True, + partial=False, + requires_grad=None, + allow_overwrite=None) +``` +""" +) +def load_encodings_to_sim(quant_sim_model: _QuantizationSimModelBase, pytorch_encoding_path: str): + """ + Loads the saved encodings to quant sim model. The encoding filename to load should end in _torch.encodings, + generated as part of quantsim export. + + :param quant_sim_model: Quantized model to load encodings for. Note: The model configuration should be the same as + when encodings were exported. + :param pytorch_encoding_path: Path of the encodings file to load. + """ + quant_sim_model.load_encodings(pytorch_encoding_path, + strict=True, + partial=False, + requires_grad=None, + allow_overwrite=None) + + +@deprecated(r""" +Use aimet_torch.nn.compute_encodings contextmanager on each sim.model instead. For example: +``` +with torch.no_grad(), \ + aimet_torch.v2.nn.compute_encodings(sim_0.model), \ + aimet_torch.v2.nn.compute_encodings(sim_1.model), \ + aimet_torch.v2.nn.compute_encodings(sim_2.model): + # Run forward pass with calibration dataset +``` +""" +) +def compute_encodings_for_sims(sim_list: Sequence[QuantizationSimModel], forward_pass_callback: Callable, + forward_pass_callback_args: Any): + """ + Compute encodings for a list of QuantSims. + + :param sim_list: List of QuantSims to compute encodings for. + :param forward_pass_callback: A callback function that simply runs forward passes on the models. This callback + function should use representative data for the forward pass, so the calculated encodings work for all + data samples. This callback internally chooses the number of data samples it wants to use for calculating + encodings. + The callback expects exactly two inputs: + - List of models which are involved in the forward pass. The models are taken directly from calling + sim.model for each sim in sim_list, passed in the same order in which the sims appear in sim_list. + - Forward pass callback args + :param forward_pass_callback_args: These argument(s) are passed to the forward_pass_callback as-is. Up to + the user to determine the type of this parameter. E.g. could be simply an integer representing the number + of data samples to use. Or could be a tuple of parameters or an object representing something more complex. + If set to None, forward_pass_callback will be invoked with no parameters. + """ + ctx_managers = [torch.no_grad()] + for sim in sim_list: + ctx_managers.append(utils.in_eval_mode(sim.model)) + ctx_managers.append(aimet_nn.compute_encodings(sim.model)) + + with contextlib.ExitStack() as stack: + for mgr in ctx_managers: + stack.enter_context(mgr) + _ = forward_pass_callback([sim.model for sim in sim_list], forward_pass_callback_args) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/aimet_torch/v2/visualization_tools/quant_stats_visualization.html b/releases/2.0.0/_modules/aimet_torch/v2/visualization_tools/quant_stats_visualization.html new file mode 100644 index 0000000..1c4c352 --- /dev/null +++ b/releases/2.0.0/_modules/aimet_torch/v2/visualization_tools/quant_stats_visualization.html @@ -0,0 +1,1173 @@ + + + + + + + + aimet_torch.v2.visualization_tools.quant_stats_visualization - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    Source code for aimet_torch.v2.visualization_tools.quant_stats_visualization

    +# -*- mode: python -*-
    +# =============================================================================
    +#  @@-COPYRIGHT-START-@@
    +#
    +#  Copyright (c) 2023-2023, Qualcomm Innovation Center, Inc. All rights reserved.
    +#
    +#  Redistribution and use in source and binary forms, with or without
    +#  modification, are permitted provided that the following conditions are met:
    +#
    +#  1. Redistributions of source code must retain the above copyright notice,
    +#     this list of conditions and the following disclaimer.
    +#
    +#  2. Redistributions in binary form must reproduce the above copyright notice,
    +#     this list of conditions and the following disclaimer in the documentation
    +#     and/or other materials provided with the distribution.
    +#
    +#  3. Neither the name of the copyright holder nor the names of its contributors
    +#     may be used to endorse or promote products derived from this software
    +#     without specific prior written permission.
    +#
    +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    +#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    +#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    +#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    +#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    +#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    +#  POSSIBILITY OF SUCH DAMAGE.
    +#
    +#  SPDX-License-Identifier: BSD-3-Clause
    +#
    +#  @@-COPYRIGHT-END-@@
    +# =============================================================================
    +
    +""" Tool to visualize min and max activations/weights of quantized modules in a given model"""
    +
    +
    +import os
    +from pathlib import Path
    +import torch
    +from bokeh.events import DocumentReady, Reset
    +from bokeh.layouts import row, column
    +from bokeh.models import ColumnDataSource, TextInput, CustomJS, Range1d, HoverTool, CustomJSHover, Div, \
    +    BooleanFilter, CDSView, Spacer, DataTable, StringFormatter, ScientificFormatter, TableColumn, Tooltip, Select, \
    +    Whisker, FactorRange
    +from bokeh.models.tools import ResetTool
    +from bokeh.models.dom import HTML
    +from bokeh.plotting import figure, save, curdoc
    +from aimet_torch.v2.quantsim import QuantizationSimModel
    +from aimet_torch.utils import get_ordered_list_of_modules
    +from aimet_torch.v2.quantization.base import QuantizerBase
    +from aimet_torch.v2.quantization.encoding_analyzer import _MinMaxObserver, _HistogramObserver
    +
    +
    +def _visualize(sim: QuantizationSimModel, dummy_input, mode: str, save_path: str = "./quant_stats_visualization.html", percentile_list: list = None) -> None:
    +    """
    +    Helper function for the visualization APIs.
    +
    +    :param sim: Calibrated QuantSim Object.
    +    :param dummy_input: Dummy Input.
    +    :param mode: Whether to plot basic or advanced stats.
    +    :param save_path: Path for saving the visualization. Format is 'path_to_dir/file_name.html'. Default is './quant_stats_visualization.html'.
    +    :param percentile_list: Percentiles to be extracted and used.
    +    """
    +
    +    # Ensure that sim is an instance of QuantizationSimModel
    +    if not isinstance(sim, QuantizationSimModel):
    +        raise TypeError(f"Expected type 'aimet_torch.v2.quantsim.QuantizationSimModel', got '{type(sim)}'.")
    +
    +    if percentile_list is None:
    +        raise ValueError("percentile_list cannot be None. Consider providing an empty percentile_list if needed.")
    +
    +    # Ensure that the save path is valid
    +    _check_path(save_path)
    +
    +    # Topologically sort the quantized modules into an ordered list for easier indexing in the plots
    +    ordered_list = get_ordered_list_of_modules(sim.model, dummy_input)
    +    stats_list = []
    +
    +    # Collect stats from observers
    +    for i in ordered_list:
    +        module_stats = _get_observer_stats(i, percentile_list=percentile_list)
    +        if module_stats is not None:
    +            stats_list.append(module_stats)
    +
    +    # Raise an error if no stats were found
    +    if len(stats_list) == 0:
    +        raise RuntimeError(
    +            "No stats found to plot. Either there were no quantized modules, or calibration was not performed before calling this function, or no observers of type _MinMaxObserver or _HistogramObserver were present.")
    +
    +
    +    stats_dict = dict()
    +    keys_list = ["name", 0, 100] + percentile_list
    +    stats_dict["idx"] = list(range(len(stats_list)))
    +    for i in keys_list:
    +        stats_dict[i] = [None] * len(stats_list)
    +    for idx, stats in enumerate(stats_list):
    +        for i in keys_list:
    +            stats_dict[i][idx] = stats[i]
    +
    +    if mode == "advanced":
    +        _get_additional_boxplot_stats(stats_dict)
    +
    +    visualizer = QuantStatsVisualizer(stats_dict, percentile_list)
    +
    +    # Save an interactive bokeh plot as a standalone html
    +    visualizer.export_plot_as_html(save_path, mode)
    +
    +
    +
    +[docs] +def visualize_stats(sim: QuantizationSimModel, dummy_input, save_path: str = "./quant_stats_visualization.html") -> None: + """Produces an interactive html to view the stats collected by each quantizer during calibration + + .. note:: + + The QuantizationSimModel input is expected to have been calibrated before using this function. Stats will only + be plotted for activations/parameters with quantizers containing calibration statistics. + + Creates an interactive visualization of min and max activations/weights of all quantized modules in the input + QuantSim object. The features include: + + - Adjustable threshold values to flag layers whose min or max activations/weights exceed the set thresholds + - Tables containing names and ranges for layers exceeding threshold values + + Saves the visualization as a .html at the given path. + + Example: + + >>> sim = aimet_torch.v2.quantsim.QuantizationSimModel(model, dummy_input, quant_scheme=QuantScheme.post_training_tf) + >>> with aimet_torch.v2.nn.compute_encodings(sim.model): + ... for data, _ in data_loader: + ... sim.model(data) + ... + >>> visualize_stats(sim, dummy_input, save_path="./quant_stats_visualization.html") + + :param sim: Calibrated QuantizationSimModel + :param dummy_input: Sample input used to trace the model + :param save_path: Path for saving the visualization. Default is "./quant_stats_visualization.html" + """ + + percentile_list = [] + _visualize(sim, dummy_input, mode="basic", save_path=save_path, percentile_list=percentile_list)
    + + + +def visualize_advanced_stats(sim: QuantizationSimModel, dummy_input, save_path: str = "./quant_advanced_stats_visualization.html", additional_percentiles: tuple = (1, 99)) -> None: + """Produces an interactive html to view the advanced stats collected by each quantizer during calibration + + .. note:: + + The QuantizationSimModel input is expected to have been calibrated before using this function. Stats will only + be plotted for activations/parameters with quantizers containing calibration statistics. + + .. note:: + + For plotting advanced stats, the quantizer encoding analyzers should have observers of type + :class:`_HistogramObserver`. If observers are of the type + :class:`_MinMaxObserver`, then advanced stats cannot be extracted and only the min and max values are + shown in the boxplots. + + .. note:: + + In case of Per-channel or Blockwise quantizers, + percentiles are not extracted due to the presence of multiple histograms. For these + quantizers, only min and max values are shown in the boxplots. + + Creates an interactive visualization of min and max activations/weights of all quantized modules in the input + QuantSim object. The features include: + + - Adjustable threshold values to flag layers whose min or max activations/weights exceed the set thresholds + - Table containing names and ranges for layers exceeding threshold values + - Select different views of the table to group layers exceeding threshold values + - Filter layers listed in the table by name + - Select one or more layers from the table for viewing their boxplots and highlighting them in the main plot + + Saves the visualization as a .html at the given path. + + Example: + + >>> sim = aimet_torch.v2.quantsim.QuantizationSimModel(model, dummy_input, quant_scheme=QuantScheme.post_training_tf_enhanced) + >>> with aimet_torch.v2.nn.compute_encodings(sim.model): + ... for data, _ in data_loader: + ... sim.model(data) + ... + >>> visualize_advanced_stats(sim, dummy_input, save_path="./quant_advanced_stats_visualization.html", additional_percentiles=(1, 99)) + + :param sim: Calibrated QuantizationSimModel + :param dummy_input: Sample input used to trace the model + :param save_path: Path for saving the visualization. Default is "./quant_advanced_stats_visualization.html" + :param additional_percentiles: Percentiles other than those related to the boxplot (25, 50, 75) to be shown. + """ + + percentile_list = _add_key_percentiles(additional_percentiles) + percentile_list = sorted(percentile_list) + _visualize(sim, dummy_input, mode="advanced", save_path=save_path, percentile_list=percentile_list) + + +def _check_path(path: str): + """ Function for sanity check on the given path """ + path_to_directory = os.path.dirname(path) + if path_to_directory != '' and not os.path.exists(path_to_directory): + raise NotADirectoryError(f"'{path_to_directory}' is not a directory.") + if not path.endswith('.html'): + raise ValueError("'save_path' must end with '.html'.") + + +def _get_observer_stats(module, percentile_list): + """ + Function to extract stats from an observer. + Handles observers of types _MinMaxObserver, _HistogramObserver. + """ + module_name, module_quantizer = module[0], module[1] + if isinstance(module_quantizer, QuantizerBase): + if isinstance(module_quantizer.encoding_analyzer.observer, _MinMaxObserver): + rng = module_quantizer.encoding_analyzer.observer.get_stats() + if rng.min is not None: + stats = dict() + stats["name"] = module_name + stats[0] = torch.min(rng.min).item() + stats[100] = torch.max(rng.max).item() + for p in percentile_list: + stats[p] = None + return stats + + elif isinstance(module_quantizer.encoding_analyzer.observer, _HistogramObserver): + histogram_list = module_quantizer.encoding_analyzer.observer.get_stats() + if len(histogram_list) == 1: + histogram = histogram_list[0] + if histogram.min is not None: + stats = dict() + stats["name"] = module_name + stats[0] = histogram.min.item() + stats[100] = histogram.max.item() + _get_advanced_stats_from_histogram(histogram, stats, percentile_list) + return stats + elif len(histogram_list) > 1: + stats = dict() + stats["name"] = module_name + curmin = float("inf") + curmax = float("-inf") + for histogram in histogram_list: + if histogram.min is not None: + curmin = min(curmin, histogram.min.item()) + curmax = max(curmax, histogram.max.item()) + if curmin < float("inf"): + stats[0] = curmin + stats[100] = curmax + for p in percentile_list: + stats[p] = None + return stats + + return None + + +def _add_key_percentiles(percentiles: tuple): + """ Add percentiles required for boxplot if not already present """ + percentile_list = list(percentiles) + for p in [25, 50, 75]: + if p not in percentile_list: + percentile_list.append(p) + return percentile_list + + +def _get_advanced_stats_from_histogram(histogram, stats, percentile_list): + """ High level function to extract advanced stats from a histogram object """ + if len(percentile_list) > 0: + percentile_stats = _get_percentile_stats_from_histogram(histogram, percentile_list) + for i, percentile in enumerate(percentile_list): + stats[percentile] = percentile_stats[i] + + +def _get_percentile_stats_from_histogram(histogram, percentile_list): + """ Function to extract percentile stats from a histogram object """ + if len(percentile_list) == 0: + raise RuntimeError("'percentile_list' cannot be empty.'") + if not _is_sorted(percentile_list): + raise RuntimeError("'percentile_list' must be sorted before calling this function.") + + n = torch.sum(histogram.histogram).item() + cum_f = 0 + idx = 0 + percentile_stats = [] + for i in range(len(histogram.histogram)): + f = histogram.histogram[i].item() + if f > 0: + bin_low = histogram.bin_edges[i].item() + bin_high = histogram.bin_edges[i + 1].item() + while True: + if (cum_f + f) / n >= percentile_list[idx] / 100: + percentile_stats.append(bin_low + ((n * percentile_list[idx] / 100 - cum_f) / f) * (bin_high - bin_low)) + idx += 1 + if idx == len(percentile_list): + return percentile_stats + else: + break + cum_f += f + + return None + + +def _get_additional_boxplot_stats(stats_dict: dict): + """ Get additional values required to plot a boxplot""" + stats_dict["stridx"] = [] + stats_dict["boxplot_upper"] = [] + stats_dict["boxplot_lower"] = [] + for i in range(len(stats_dict["idx"])): + stats_dict["stridx"].append(str(stats_dict["idx"][i])) + if (stats_dict[25][i] is not None) and (stats_dict[75][i] is not None): + inter_quantile_range = stats_dict[75][i] - stats_dict[25][i] + stats_dict["boxplot_upper"].append(stats_dict[75][i] + 1.5 * inter_quantile_range) + stats_dict["boxplot_lower"].append(stats_dict[25][i] - 1.5 * inter_quantile_range) + else: + stats_dict["boxplot_upper"].append(None) + stats_dict["boxplot_lower"].append(None) + + +def _is_sorted(arr: list): + for i in range(len(arr) - 1): + if arr[i] > arr[i + 1]: + return False + return True + + +class DataSources: + """ + Class to hold the Bokeh ColumnDataSource objects needed in the visualization. + """ + + def __init__(self, + stats_dict: dict, + plot: figure, + default_values: dict, + percentiles: list + ): + self.data_source = ColumnDataSource( + data=dict(idx=stats_dict["idx"], + namelist=stats_dict["name"], + minlist=stats_dict[0], + min_namelist=["Min"] * len(stats_dict["idx"]), + maxlist=stats_dict[100], + max_namelist=["Max"] * len(stats_dict["idx"]), + marker_yminlist=[default_values['default_ymin']] * len(stats_dict["idx"]), + marker_ymaxlist=[default_values['default_ymax']] * len(stats_dict["idx"]), + selected=[False] * len(stats_dict["idx"]))) + if "stridx" in stats_dict.keys(): + self.data_source.add(data=stats_dict["stridx"], name="stridx") + if "boxplot_upper" in stats_dict.keys(): + self.data_source.add(data=stats_dict["boxplot_upper"], name="boxplot_upper_list") + if "boxplot_lower" in stats_dict.keys(): + self.data_source.add(data=stats_dict["boxplot_lower"], name="boxplot_lower_list") + for key in [25, 50, 75]: + if key in stats_dict: + self.data_source.add(data=stats_dict[key], name=str(key) + "%ilelist") + for key in percentiles: + self.data_source.add(data=stats_dict[key], name=str(key) + "%ilelist") + self.data_source.add(data=[str(key)+" %ile" for _ in range(len(stats_dict["idx"]))], name=str(key) + "%ile_namelist") + + self.default_values_source = ColumnDataSource( + data=dict(default_ymax=[default_values['default_ymax']], + default_ymin=[default_values['default_ymin']], + default_maxclip=[default_values['default_maxclip']], + default_minclip=[default_values['default_minclip']], + default_xmax=[default_values['default_xmax']], + default_xmin=[default_values['default_xmin']])) + + self.limits_source = ColumnDataSource( + data=dict(ymax=[default_values['default_ymax']], ymin=[default_values['default_ymin']], + xmin=[plot.x_range.start], xmax=[plot.x_range.end], + minclip=[default_values['default_minclip']], + maxclip=[default_values['default_maxclip']])) + + self.table_data_source = ColumnDataSource( + data=dict(idx=[], namelist=[], minlist=[], maxlist=[])) + + self.selected_data_source = ColumnDataSource( + data=dict(idx=[], namelist=[], floor=[], ceil=[], minlist=[], min_namelist=[], maxlist=[], max_namelist=[]) + ) + if "stridx" in stats_dict.keys(): + self.selected_data_source.add(data=[], name="stridx") + if "boxplot_upper" in stats_dict.keys(): + self.selected_data_source.add(data=[], name="boxplot_upper_list") + if "boxplot_lower" in stats_dict.keys(): + self.selected_data_source.add(data=[], name="boxplot_lower_list") + for key in [25, 50, 75]: + if key in stats_dict: + self.selected_data_source.add(data=[], name=str(key) + "%ilelist") + for key in percentiles: + self.selected_data_source.add(data=[], name=str(key) + "%ilelist") + self.selected_data_source.add(data=[], name=str(key) + "%ile_namelist") + + +class TableFilters: + """ + Class for holding data filters. + """ + + def __init__(self, data_sources: DataSources): + self.name_filter = BooleanFilter() + self.name_filter.booleans = [True for _ in range(len(data_sources.data_source.data['idx']))] + self.min_thresh_filter = BooleanFilter() + self.min_thresh_filter.booleans = [True for _ in range(len(data_sources.data_source.data['idx']))] + self.max_thresh_filter = BooleanFilter() + self.max_thresh_filter.booleans = [True for _ in range(len(data_sources.data_source.data['idx']))] + + +class TableViews: + """ + Class for holding views of the data sources. + """ + + def __init__(self, tablefilters: TableFilters): + self.min_thresh_view = CDSView(filter=tablefilters.min_thresh_filter) + self.max_thresh_view = CDSView(filter=tablefilters.max_thresh_filter) + + +class TableObjects: + """ + Class for holding various objects related to the table elements in the visualization. + """ + + def __init__(self, datasources: DataSources): + self.filters = TableFilters(datasources) + self.views = TableViews(self.filters) + + columns = [ + TableColumn(field="idx", title="Layer Index", + width=QuantStatsVisualizer.table_column_widths["Layer Index"]), + TableColumn(field="namelist", title="Layer Name", + formatter=StringFormatter(font_style="bold"), + width=QuantStatsVisualizer.table_column_widths["Layer Name"]), + TableColumn(field="minlist", title="Min Activation", + formatter=ScientificFormatter(precision=3), + width=QuantStatsVisualizer.table_column_widths["Min Activation"]), + TableColumn(field="maxlist", title="Max Activation", + formatter=ScientificFormatter(precision=3), + width=QuantStatsVisualizer.table_column_widths["Max Activation"]), + ] + + self.data_table = DataTable(source=datasources.table_data_source, columns=columns, + sortable=True, width=QuantStatsVisualizer.plot_dims["table_width"], + selectable="checkbox", + index_position=None, + ) + + +class InputWidgets: + """ + Class to hold various input widgets. + """ + + def __init__(self, default_values: dict): + self.ymin_input = TextInput(value=str(default_values['default_ymin']), + title="Enter lower display limit of the plot") + self.ymax_input = TextInput(value=str(default_values['default_ymax']), + title="Enter upper display limit of the plot") + self.minclip_input = TextInput(value=str(default_values['default_minclip']), + title="Enter lower threshold value for activations/weights") + self.maxclip_input = TextInput(value=str(default_values['default_maxclip']), + title="Enter upper threshold value for activations/weights") + + self.name_input = TextInput(value="", title="Enter Name Filter") + + tooltip_table_mode = Tooltip(content=HTML(""" + <h3> Select Table View </h3> + <p> Following table views are available </p> + <ol> + <li> <b> All: </b> All quantized layers </li> + <li> <b> Min: </b> Quantized layers with min activation below lower threshold value </li> + <li> <b> Max: </b> Quantized layers with max activation above upper threshold value </li> + <li> <b> Min | Max: </b> Union of Min and Max </li> + <li> <b> Min & Max: </b> Intersection of Min and Max </li> + </ol> + """), + position="right") + self.table_view_select = Select(title="Select Table View", + value="Min | Max", + options=["All", "Min", "Max", "Min | Max", "Min & Max"], + width=200, + description=tooltip_table_mode + ) + + +class CustomCallbacks: + """ + Class to hold Custom JavaScript Callbacks for interactivity in the visualization. + """ + + def __init__(self): + self.limit_change_callback = None + self.reset_callback = None + self.name_filter_callback = None + self.select_table_view_callback = None + self.table_selection_callback = None + + +class QuantStatsVisualizer: + """ + Class for constructing the visualization with functionality to export the plot as + + :param stats_dict: Dictionary containing the module names, indices, and other extracted statistics + """ + + # Class level constants + plot_dims = {"plot_width": 700, + "plot_height": 400, + "table_width": 800, + "boxplot_unit_width": 150, + "boxplot_height": 400, + "whisker_head": 20, + "boxplot_vbar_width": 0.7, + "boxplot_text_font_size": "10px"} + initial_vals = {"default_ymin": -1e5, "default_ymax": 1e5} + spacer_dims = {"sp1_width": 50, "sp1_height": 40, "sp2_width": 100} + table_column_widths = {"Layer Index": 100, + "Layer Name": 400, + "Min Activation": 100, + "Max Activation": 100} + + def __init__(self, stats_dict: dict, percentile_list: list): + self.stats_dict = stats_dict + self.plot = figure( + title="Min Max Activations/Weights of quantized modules for given model", + x_axis_label="Layer index", + y_axis_label="Activation/Weight", + tools="pan,wheel_zoom,box_zoom") + self.boxplot = figure( + x_range=FactorRange(), + title="Boxplots of selected layers", + x_axis_label="Layer index", + y_axis_label="Activation/Weight", + tools="pan,wheel_zoom,box_zoom") + self.default_values = dict() + self.percentiles = [] + for percentile in percentile_list: + if percentile not in [25, 50, 75]: + self.percentiles.append(percentile) + + def _add_plot_lines(self, datasources: DataSources): + self.plot.segment(x0='xmin', x1='xmax', y0='ymin', y1='ymin', line_width=4, line_color='black', + source=datasources.limits_source) + self.plot.segment(x0='xmin', x1='xmax', y0='ymax', y1='ymax', line_width=4, line_color='black', + source=datasources.limits_source) + self.plot.segment(x0='xmin', x1='xmax', y0='minclip', y1='minclip', line_width=2, line_color='black', + line_dash='dashed', + source=datasources.limits_source) + self.plot.segment(x0='xmin', x1='xmax', y0='maxclip', y1='maxclip', line_width=2, line_color='black', + line_dash='dashed', + source=datasources.limits_source) + self.plot.line('idx', 'maxlist', source=datasources.data_source, legend_label="Max Activation", line_width=2, + line_color="red") + self.plot.line('idx', 'minlist', source=datasources.data_source, legend_label="Min Activation", line_width=2, + line_color="blue") + selections = self.plot.segment(x0='idx', x1='idx', y0='floor', y1='ceil', line_width=2, line_color='goldenrod', + line_alpha=0.5, source=datasources.selected_data_source) + + return selections + + def _add_min_max_markers(self, datasources: DataSources, tableobjects: TableObjects): + min_markers = self.plot.circle_x('idx', 'marker_yminlist', source=datasources.data_source, size=10, + color='orange', + line_color="navy") + min_markers.view = tableobjects.views.min_thresh_view + max_markers = self.plot.circle_x('idx', 'marker_ymaxlist', source=datasources.data_source, size=10, + color='orange', + line_color="navy") + max_markers.view = tableobjects.views.max_thresh_view + + return min_markers, max_markers + + def _add_boxplots(self, datasources: DataSources): + whisker = Whisker(base="stridx", upper="boxplot_upper_list", lower="boxplot_lower_list", source=datasources.selected_data_source) + whisker.upper_head.size = whisker.lower_head.size = QuantStatsVisualizer.plot_dims["whisker_head"] + self.boxplot.add_layout(whisker) + self.boxplot.vbar("stridx", QuantStatsVisualizer.plot_dims["boxplot_vbar_width"], "50%ilelist", "75%ilelist", source=datasources.selected_data_source, line_color="black") + self.boxplot.vbar("stridx", QuantStatsVisualizer.plot_dims["boxplot_vbar_width"], "25%ilelist", "50%ilelist", source=datasources.selected_data_source, line_color="black") + self.boxplot.circle(x="stridx", y="minlist", source=datasources.selected_data_source, + name="min_points", color="orange") + self.boxplot.text(x="stridx", y="minlist", text="min_namelist", + source=datasources.selected_data_source, + x_offset=5, y_offset=5, + text_font_size=QuantStatsVisualizer.plot_dims["boxplot_text_font_size"], + name="min_labels") + self.boxplot.circle(x="stridx", y="maxlist", source=datasources.selected_data_source, + name="max_points", color="orange") + self.boxplot.text(x="stridx", y="maxlist", text="max_namelist", + source=datasources.selected_data_source, + x_offset=5, y_offset=5, + text_font_size=QuantStatsVisualizer.plot_dims["boxplot_text_font_size"], + name="max_labels") + for percentile in self.percentiles: + self.boxplot.circle(x="stridx", y=str(percentile)+"%ilelist", source=datasources.selected_data_source, name=str(percentile) + "_" + "points", color="orange") + self.boxplot.text(x="stridx", y=str(percentile)+"%ilelist", text=str(percentile)+"%ile_namelist", source=datasources.selected_data_source, + x_offset=5, y_offset=5, text_font_size=QuantStatsVisualizer.plot_dims["boxplot_text_font_size"], name=str(percentile) + "_" + "labels") + + @staticmethod + def _get_marker_hovertool(min_markers, max_markers): + format_code = """ + if (Math.abs(value) < 1e-3 || Math.abs(value) > 1e5) { + return value.toExponential(3); + } else { + return value.toFixed(3); + } + """ + + format_hover = CustomJSHover(code=format_code) + + marker_hover = HoverTool(renderers=[min_markers, max_markers], tooltips=[ + ("Layer Index", "@idx"), + ("Name", "@namelist"), + ("Max Activation", "@maxlist{custom}"), + ("Min Activation", "@minlist{custom}"), + ], formatters={ + "@minlist": format_hover, + "@maxlist": format_hover, + }) + + return marker_hover + + @staticmethod + def _get_selection_hovertool(selections): + format_code = """ + if (Math.abs(value) < 1e-3 || Math.abs(value) > 1e5) { + return value.toExponential(3); + } else { + return value.toFixed(3); + } + """ + + format_hover = CustomJSHover(code=format_code) + + selection_hover = HoverTool(renderers=[selections], tooltips=[ + ("Layer Index", "@idx"), + ("Name", "@namelist"), + ("Max Activation", "@maxlist{custom}"), + ("Min Activation", "@minlist{custom}"), + ], formatters={ + "@minlist": format_hover, + "@maxlist": format_hover, + }) + + return selection_hover + + def _define_callbacks(self, datasources, tableobjects, inputwidgets, mode): + customcallbacks = CustomCallbacks() + + table_columns = ["idx", "namelist", "minlist", "maxlist"] + selection_columns = [] + + if mode == "basic": + selection_columns += ["idx", "namelist", "minlist", "min_namelist", "maxlist", "max_namelist"] + elif mode == "advanced": + selection_columns += ["idx", "namelist", "minlist", "min_namelist", "maxlist", "max_namelist", "stridx", "boxplot_upper_list", "boxplot_lower_list", "25%ilelist", "50%ilelist", "75%ilelist"] + for percentile in self.percentiles: + selection_columns.append(str(percentile) + "%ilelist") + selection_columns.append(str(percentile) + "%ile_namelist") + + customcallbacks.limit_change_callback = CustomJS(args=dict( + limits_source=datasources.limits_source, + data_source=datasources.data_source, + table_data_source=datasources.table_data_source, + selected_data_source=datasources.selected_data_source, + min_marker_source=datasources.data_source, + max_marker_source=datasources.data_source, + ymax_input=inputwidgets.ymax_input, + ymin_input=inputwidgets.ymin_input, + maxclip_input=inputwidgets.maxclip_input, + minclip_input=inputwidgets.minclip_input, + plot=self.plot, + min_thresh_filter=tableobjects.filters.min_thresh_filter, + max_thresh_filter=tableobjects.filters.max_thresh_filter, + name_filter=tableobjects.filters.name_filter, + select=inputwidgets.table_view_select, + table_columns=table_columns, + ), code=(Path(__file__).parent / "quant_stats_visualization_JS_code/utils.js").read_text("utf8") + (Path(__file__).parent / "quant_stats_visualization_JS_code/limit_change_callback.js").read_text("utf8")) + + customcallbacks.reset_callback = CustomJS(args=dict( + limits_source=datasources.limits_source, + data_source=datasources.data_source, + table_data_source=datasources.table_data_source, + selected_data_source=datasources.selected_data_source, + default_values_source=datasources.default_values_source, + min_marker_source=datasources.data_source, + max_marker_source=datasources.data_source, + ymax_input=inputwidgets.ymax_input, + ymin_input=inputwidgets.ymin_input, + maxclip_input=inputwidgets.maxclip_input, + minclip_input=inputwidgets.minclip_input, + select=inputwidgets.table_view_select, + name_input=inputwidgets.name_input, + plot=self.plot, + boxplot=self.boxplot, + min_thresh_filter=tableobjects.filters.min_thresh_filter, + max_thresh_filter=tableobjects.filters.max_thresh_filter, + name_filter=tableobjects.filters.name_filter, + selection_columns=selection_columns, + table_columns=table_columns, + mode=mode, + boxplot_unit_width=QuantStatsVisualizer.plot_dims["boxplot_unit_width"], + ), code=(Path(__file__).parent / "quant_stats_visualization_JS_code/utils.js").read_text("utf8") + (Path(__file__).parent / "quant_stats_visualization_JS_code/reset_callback.js").read_text("utf8")) + + customcallbacks.name_filter_callback = CustomJS(args=dict( + data_source=datasources.data_source, + table_data_source=datasources.table_data_source, + limits_source=datasources.limits_source, + min_thresh_filter=tableobjects.filters.min_thresh_filter, + max_thresh_filter=tableobjects.filters.max_thresh_filter, + name_filter=tableobjects.filters.name_filter, + select=inputwidgets.table_view_select, + table_columns=table_columns, + ), code=(Path(__file__).parent / "quant_stats_visualization_JS_code/utils.js").read_text("utf8") + (Path(__file__).parent / "quant_stats_visualization_JS_code/name_filter_callback.js").read_text("utf8")) + + customcallbacks.select_table_view_callback = CustomJS(args=dict( + data_source=datasources.data_source, + table_data_source=datasources.table_data_source, + select=inputwidgets.table_view_select, + min_thresh_filter=tableobjects.filters.min_thresh_filter, + max_thresh_filter=tableobjects.filters.max_thresh_filter, + name_filter=tableobjects.filters.name_filter, + table=tableobjects.data_table, + table_columns=table_columns, + ), code=(Path(__file__).parent / "quant_stats_visualization_JS_code/utils.js").read_text("utf8") + (Path(__file__).parent / "quant_stats_visualization_JS_code/select_table_view_callback.js").read_text("utf8")) + + customcallbacks.table_selection_callback = CustomJS(args=dict( + data_source=datasources.data_source, + table_data_source=datasources.table_data_source, + selected_data_source=datasources.selected_data_source, + limits_source=datasources.limits_source, + boxplot=self.boxplot, + selection_columns=selection_columns, + mode=mode, + boxplot_unit_width=QuantStatsVisualizer.plot_dims["boxplot_unit_width"], + ), code=(Path(__file__).parent / "quant_stats_visualization_JS_code/utils.js").read_text("utf8") + (Path(__file__).parent / "quant_stats_visualization_JS_code/table_selection_callback.js").read_text("utf8")) + + return customcallbacks + + def _attach_callbacks(self, datasources, inputwidgets, customcallbacks): + self.plot.js_on_event(Reset, customcallbacks.reset_callback) + inputwidgets.ymax_input.js_on_change('value', customcallbacks.limit_change_callback) + inputwidgets.ymin_input.js_on_change('value', customcallbacks.limit_change_callback) + inputwidgets.maxclip_input.js_on_change('value', customcallbacks.limit_change_callback) + inputwidgets.minclip_input.js_on_change('value', customcallbacks.limit_change_callback) + inputwidgets.name_input.js_on_change("value", customcallbacks.name_filter_callback) + inputwidgets.table_view_select.js_on_change('value', customcallbacks.select_table_view_callback) + datasources.table_data_source.selected.js_on_change('indices', customcallbacks.table_selection_callback) + + def _create_layout(self, inputwidgets, tableobjects, mode): + heading_1 = Div(text="<h2>Quant Stats Visualizer</h2>") + heading_2 = Div(text="<h2>Quant Stats Data Table</h2>") + + sp1 = Spacer(width=QuantStatsVisualizer.spacer_dims["sp1_width"], + height=QuantStatsVisualizer.spacer_dims["sp1_height"]) + row1 = row(inputwidgets.ymin_input, inputwidgets.ymax_input) + row2 = row(inputwidgets.minclip_input, inputwidgets.maxclip_input) + inputs1 = column(row1, row2) + if mode == "basic": + layout = column(heading_1, inputs1, sp1, self.plot, + column(heading_2, row(inputwidgets.table_view_select, inputwidgets.name_input), + tableobjects.data_table)) + elif mode == "advanced": + sp2 = Spacer(width=QuantStatsVisualizer.spacer_dims["sp2_width"], + height=QuantStatsVisualizer.plot_dims["boxplot_height"]) + layout = column(heading_1, inputs1, sp1, row(self.plot, sp2, self.boxplot), + column(heading_2, row(inputwidgets.table_view_select, inputwidgets.name_input), + tableobjects.data_table)) + else: + raise ValueError(f"Expected mode to be 'basic' or 'advanced', got '{mode}'.") + + return layout + + def export_plot_as_html(self, save_path: str, mode: str) -> None: + """ + Method for constructing the visualization and saving it to the given path. + + :param save_path: Path for saving the visualization. + :param mode: Whether to plot basic or advanced stats. + """ + + curdoc().theme = 'light_minimal' + + self.plot.width = QuantStatsVisualizer.plot_dims["plot_width"] + self.plot.height = QuantStatsVisualizer.plot_dims["plot_height"] + + # Defining the default values of plotting parameters + self.default_values['default_ymax'] = QuantStatsVisualizer.initial_vals["default_ymax"] + self.default_values['default_ymin'] = QuantStatsVisualizer.initial_vals["default_ymin"] + self.default_values['default_xmax'] = len(self.stats_dict["idx"]) - 1 + self.default_values['default_xmin'] = 0 + self.default_values['default_maxclip'] = self.default_values['default_ymax'] / 2 + self.default_values['default_minclip'] = self.default_values['default_ymin'] / 2 + + self.plot.x_range = Range1d(0, len(self.stats_dict["idx"])) + self.plot.y_range = Range1d(self.default_values['default_ymax'] * 1.05, + self.default_values['default_ymin'] * 1.05) + + # Creating and adding a reset tool + rt = ResetTool() + self.plot.add_tools(rt) + + # Defining Bokeh ColumnDataSources + datasources = DataSources(stats_dict=self.stats_dict, + plot=self.plot, + default_values=self.default_values, + percentiles=self.percentiles + ) + + # Creating plot objects + selections = self._add_plot_lines(datasources) + + if mode == "advanced": + self.boxplot.width = 5 * QuantStatsVisualizer.plot_dims["boxplot_unit_width"] + self.boxplot.height = QuantStatsVisualizer.plot_dims["boxplot_height"] + self.boxplot.y_range = Range1d() + self._add_boxplots(datasources) + + # Defining the table objects and name filter views + tableobjects = TableObjects(datasources) + + # Marker points to see which layers cross the thresholds + min_markers, max_markers = self._add_min_max_markers(datasources, tableobjects) + + # Defining a hover functionality to see layer details on hovering on the marker points and selections + marker_hover = self._get_marker_hovertool(min_markers, max_markers) + selection_hover = self._get_selection_hovertool(selections) + self.plot.add_tools(marker_hover, selection_hover) + + # Creating the input widgets + inputwidgets = InputWidgets(self.default_values) + + # Defining Custom JavaScript callbacks + customcallbacks = self._define_callbacks(datasources, tableobjects, inputwidgets, mode) + + # Attach events to corresponding callbacks + curdoc().js_on_event(DocumentReady, customcallbacks.reset_callback) + self._attach_callbacks(datasources, inputwidgets, customcallbacks) + + # Define the formatting + layout = self._create_layout(inputwidgets, tableobjects, mode) + + # Save as standalone html + save(layout, save_path) +
    +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_modules/index.html b/releases/2.0.0/_modules/index.html new file mode 100644 index 0000000..2edb247 --- /dev/null +++ b/releases/2.0.0/_modules/index.html @@ -0,0 +1,382 @@ + + + + + + + + Overview: module code - AIMET + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
    +
    +
    + +
    +
    +
    AIMET
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    +
    + +
    + +
    +
    +

    All modules for which code is available

    + +
    +
    +
    + + +
    +
    + + Made with Sphinx and @pradyunsg's + + Furo + +
    +
    +
    + + + + + + +
    +
    +
    + +
    +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/releases/2.0.0/_sphinx_design_static/design-tabs.js b/releases/2.0.0/_sphinx_design_static/design-tabs.js new file mode 100644 index 0000000..b25bd6a --- /dev/null +++ b/releases/2.0.0/_sphinx_design_static/design-tabs.js @@ -0,0 +1,101 @@ +// @ts-check + +// Extra JS capability for selected tabs to be synced +// The selection is stored in local storage so that it persists across page loads. + +/** + * @type {Record} + */ +let sd_id_to_elements = {}; +const storageKeyPrefix = "sphinx-design-tab-id-"; + +/** + * Create a key for a tab element. + * @param {HTMLElement} el - The tab element. + * @returns {[string, string, string] | null} - The key. + * + */ +function create_key(el) { + let syncId = el.getAttribute("data-sync-id"); + let syncGroup = el.getAttribute("data-sync-group"); + if (!syncId || !syncGroup) return null; + return [syncGroup, syncId, syncGroup + "--" + syncId]; +} + +/** + * Initialize the tab selection. + * + */ +function ready() { + // Find all tabs with sync data + + /** @type {string[]} */ + let groups = []; + + document.querySelectorAll(".sd-tab-label").forEach((label) => { + if (label instanceof HTMLElement) { + let data = create_key(label); + if (data) { + let [group, id, key] = data; + + // add click event listener + // @ts-ignore + label.onclick = onSDLabelClick; + + // store map of key to elements + if (!sd_id_to_elements[key]) { + sd_id_to_elements[key] = []; + } + sd_id_to_elements[key].push(label); + + if (groups.indexOf(group) === -1) { + groups.push(group); + // Check if a specific tab has been selected via URL parameter + const tabParam = new URLSearchParams(window.location.search).get( + group + ); + if (tabParam) { + console.log( + "sphinx-design: Selecting tab id for group '" + + group + + "' from URL parameter: " + + tabParam + ); + window.sessionStorage.setItem(storageKeyPrefix + group, tabParam); + } + } + + // Check is a specific tab has been selected previously + let previousId = window.sessionStorage.getItem( + storageKeyPrefix + group + ); + if (previousId === id) { + // console.log( + // "sphinx-design: Selecting tab from session storage: " + id + // ); + // @ts-ignore + label.previousElementSibling.checked = true; + } + } + } + }); +} + +/** + * Activate other tabs with the same sync id. + * + * @this {HTMLElement} - The element that was clicked. + */ +function onSDLabelClick() { + let data = create_key(this); + if (!data) return; + let [group, id, key] = data; + for (const label of sd_id_to_elements[key]) { + if (label === this) continue; + // @ts-ignore + label.previousElementSibling.checked = true; + } + window.sessionStorage.setItem(storageKeyPrefix + group, id); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/releases/2.0.0/_sphinx_design_static/sphinx-design.min.css b/releases/2.0.0/_sphinx_design_static/sphinx-design.min.css new file mode 100644 index 0000000..860c36d --- /dev/null +++ b/releases/2.0.0/_sphinx_design_static/sphinx-design.min.css @@ -0,0 +1 @@ +.sd-bg-primary{background-color:var(--sd-color-primary) !important}.sd-bg-text-primary{color:var(--sd-color-primary-text) !important}button.sd-bg-primary:focus,button.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}a.sd-bg-primary:focus,a.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}.sd-bg-secondary{background-color:var(--sd-color-secondary) !important}.sd-bg-text-secondary{color:var(--sd-color-secondary-text) !important}button.sd-bg-secondary:focus,button.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}a.sd-bg-secondary:focus,a.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}.sd-bg-success{background-color:var(--sd-color-success) !important}.sd-bg-text-success{color:var(--sd-color-success-text) !important}button.sd-bg-success:focus,button.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}a.sd-bg-success:focus,a.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}.sd-bg-info{background-color:var(--sd-color-info) !important}.sd-bg-text-info{color:var(--sd-color-info-text) !important}button.sd-bg-info:focus,button.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}a.sd-bg-info:focus,a.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}.sd-bg-warning{background-color:var(--sd-color-warning) !important}.sd-bg-text-warning{color:var(--sd-color-warning-text) !important}button.sd-bg-warning:focus,button.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}a.sd-bg-warning:focus,a.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}.sd-bg-danger{background-color:var(--sd-color-danger) !important}.sd-bg-text-danger{color:var(--sd-color-danger-text) !important}button.sd-bg-danger:focus,button.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}a.sd-bg-danger:focus,a.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}.sd-bg-light{background-color:var(--sd-color-light) !important}.sd-bg-text-light{color:var(--sd-color-light-text) !important}button.sd-bg-light:focus,button.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}a.sd-bg-light:focus,a.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}.sd-bg-muted{background-color:var(--sd-color-muted) !important}.sd-bg-text-muted{color:var(--sd-color-muted-text) !important}button.sd-bg-muted:focus,button.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}a.sd-bg-muted:focus,a.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}.sd-bg-dark{background-color:var(--sd-color-dark) !important}.sd-bg-text-dark{color:var(--sd-color-dark-text) !important}button.sd-bg-dark:focus,button.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}a.sd-bg-dark:focus,a.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}.sd-bg-black{background-color:var(--sd-color-black) !important}.sd-bg-text-black{color:var(--sd-color-black-text) !important}button.sd-bg-black:focus,button.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}a.sd-bg-black:focus,a.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}.sd-bg-white{background-color:var(--sd-color-white) !important}.sd-bg-text-white{color:var(--sd-color-white-text) !important}button.sd-bg-white:focus,button.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}a.sd-bg-white:focus,a.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}.sd-text-primary,.sd-text-primary>p{color:var(--sd-color-primary) !important}a.sd-text-primary:focus,a.sd-text-primary:hover{color:var(--sd-color-primary-highlight) !important}.sd-text-secondary,.sd-text-secondary>p{color:var(--sd-color-secondary) !important}a.sd-text-secondary:focus,a.sd-text-secondary:hover{color:var(--sd-color-secondary-highlight) !important}.sd-text-success,.sd-text-success>p{color:var(--sd-color-success) !important}a.sd-text-success:focus,a.sd-text-success:hover{color:var(--sd-color-success-highlight) !important}.sd-text-info,.sd-text-info>p{color:var(--sd-color-info) !important}a.sd-text-info:focus,a.sd-text-info:hover{color:var(--sd-color-info-highlight) !important}.sd-text-warning,.sd-text-warning>p{color:var(--sd-color-warning) !important}a.sd-text-warning:focus,a.sd-text-warning:hover{color:var(--sd-color-warning-highlight) !important}.sd-text-danger,.sd-text-danger>p{color:var(--sd-color-danger) !important}a.sd-text-danger:focus,a.sd-text-danger:hover{color:var(--sd-color-danger-highlight) !important}.sd-text-light,.sd-text-light>p{color:var(--sd-color-light) !important}a.sd-text-light:focus,a.sd-text-light:hover{color:var(--sd-color-light-highlight) !important}.sd-text-muted,.sd-text-muted>p{color:var(--sd-color-muted) !important}a.sd-text-muted:focus,a.sd-text-muted:hover{color:var(--sd-color-muted-highlight) !important}.sd-text-dark,.sd-text-dark>p{color:var(--sd-color-dark) !important}a.sd-text-dark:focus,a.sd-text-dark:hover{color:var(--sd-color-dark-highlight) !important}.sd-text-black,.sd-text-black>p{color:var(--sd-color-black) !important}a.sd-text-black:focus,a.sd-text-black:hover{color:var(--sd-color-black-highlight) !important}.sd-text-white,.sd-text-white>p{color:var(--sd-color-white) !important}a.sd-text-white:focus,a.sd-text-white:hover{color:var(--sd-color-white-highlight) !important}.sd-outline-primary{border-color:var(--sd-color-primary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-primary:focus,a.sd-outline-primary:hover{border-color:var(--sd-color-primary-highlight) !important}.sd-outline-secondary{border-color:var(--sd-color-secondary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-secondary:focus,a.sd-outline-secondary:hover{border-color:var(--sd-color-secondary-highlight) !important}.sd-outline-success{border-color:var(--sd-color-success) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-success:focus,a.sd-outline-success:hover{border-color:var(--sd-color-success-highlight) !important}.sd-outline-info{border-color:var(--sd-color-info) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-info:focus,a.sd-outline-info:hover{border-color:var(--sd-color-info-highlight) !important}.sd-outline-warning{border-color:var(--sd-color-warning) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-warning:focus,a.sd-outline-warning:hover{border-color:var(--sd-color-warning-highlight) !important}.sd-outline-danger{border-color:var(--sd-color-danger) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-danger:focus,a.sd-outline-danger:hover{border-color:var(--sd-color-danger-highlight) !important}.sd-outline-light{border-color:var(--sd-color-light) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-light:focus,a.sd-outline-light:hover{border-color:var(--sd-color-light-highlight) !important}.sd-outline-muted{border-color:var(--sd-color-muted) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-muted:focus,a.sd-outline-muted:hover{border-color:var(--sd-color-muted-highlight) !important}.sd-outline-dark{border-color:var(--sd-color-dark) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-dark:focus,a.sd-outline-dark:hover{border-color:var(--sd-color-dark-highlight) !important}.sd-outline-black{border-color:var(--sd-color-black) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-black:focus,a.sd-outline-black:hover{border-color:var(--sd-color-black-highlight) !important}.sd-outline-white{border-color:var(--sd-color-white) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-white:focus,a.sd-outline-white:hover{border-color:var(--sd-color-white-highlight) !important}.sd-bg-transparent{background-color:transparent !important}.sd-outline-transparent{border-color:transparent !important}.sd-text-transparent{color:transparent !important}.sd-p-0{padding:0 !important}.sd-pt-0,.sd-py-0{padding-top:0 !important}.sd-pr-0,.sd-px-0{padding-right:0 !important}.sd-pb-0,.sd-py-0{padding-bottom:0 !important}.sd-pl-0,.sd-px-0{padding-left:0 !important}.sd-p-1{padding:.25rem !important}.sd-pt-1,.sd-py-1{padding-top:.25rem !important}.sd-pr-1,.sd-px-1{padding-right:.25rem !important}.sd-pb-1,.sd-py-1{padding-bottom:.25rem !important}.sd-pl-1,.sd-px-1{padding-left:.25rem !important}.sd-p-2{padding:.5rem !important}.sd-pt-2,.sd-py-2{padding-top:.5rem !important}.sd-pr-2,.sd-px-2{padding-right:.5rem !important}.sd-pb-2,.sd-py-2{padding-bottom:.5rem !important}.sd-pl-2,.sd-px-2{padding-left:.5rem !important}.sd-p-3{padding:1rem !important}.sd-pt-3,.sd-py-3{padding-top:1rem !important}.sd-pr-3,.sd-px-3{padding-right:1rem !important}.sd-pb-3,.sd-py-3{padding-bottom:1rem !important}.sd-pl-3,.sd-px-3{padding-left:1rem !important}.sd-p-4{padding:1.5rem !important}.sd-pt-4,.sd-py-4{padding-top:1.5rem !important}.sd-pr-4,.sd-px-4{padding-right:1.5rem !important}.sd-pb-4,.sd-py-4{padding-bottom:1.5rem !important}.sd-pl-4,.sd-px-4{padding-left:1.5rem !important}.sd-p-5{padding:3rem !important}.sd-pt-5,.sd-py-5{padding-top:3rem !important}.sd-pr-5,.sd-px-5{padding-right:3rem !important}.sd-pb-5,.sd-py-5{padding-bottom:3rem !important}.sd-pl-5,.sd-px-5{padding-left:3rem !important}.sd-m-auto{margin:auto !important}.sd-mt-auto,.sd-my-auto{margin-top:auto !important}.sd-mr-auto,.sd-mx-auto{margin-right:auto !important}.sd-mb-auto,.sd-my-auto{margin-bottom:auto !important}.sd-ml-auto,.sd-mx-auto{margin-left:auto !important}.sd-m-0{margin:0 !important}.sd-mt-0,.sd-my-0{margin-top:0 !important}.sd-mr-0,.sd-mx-0{margin-right:0 !important}.sd-mb-0,.sd-my-0{margin-bottom:0 !important}.sd-ml-0,.sd-mx-0{margin-left:0 !important}.sd-m-1{margin:.25rem !important}.sd-mt-1,.sd-my-1{margin-top:.25rem !important}.sd-mr-1,.sd-mx-1{margin-right:.25rem !important}.sd-mb-1,.sd-my-1{margin-bottom:.25rem !important}.sd-ml-1,.sd-mx-1{margin-left:.25rem !important}.sd-m-2{margin:.5rem !important}.sd-mt-2,.sd-my-2{margin-top:.5rem !important}.sd-mr-2,.sd-mx-2{margin-right:.5rem !important}.sd-mb-2,.sd-my-2{margin-bottom:.5rem !important}.sd-ml-2,.sd-mx-2{margin-left:.5rem !important}.sd-m-3{margin:1rem !important}.sd-mt-3,.sd-my-3{margin-top:1rem !important}.sd-mr-3,.sd-mx-3{margin-right:1rem !important}.sd-mb-3,.sd-my-3{margin-bottom:1rem !important}.sd-ml-3,.sd-mx-3{margin-left:1rem !important}.sd-m-4{margin:1.5rem !important}.sd-mt-4,.sd-my-4{margin-top:1.5rem !important}.sd-mr-4,.sd-mx-4{margin-right:1.5rem !important}.sd-mb-4,.sd-my-4{margin-bottom:1.5rem !important}.sd-ml-4,.sd-mx-4{margin-left:1.5rem !important}.sd-m-5{margin:3rem !important}.sd-mt-5,.sd-my-5{margin-top:3rem !important}.sd-mr-5,.sd-mx-5{margin-right:3rem !important}.sd-mb-5,.sd-my-5{margin-bottom:3rem !important}.sd-ml-5,.sd-mx-5{margin-left:3rem !important}.sd-w-25{width:25% !important}.sd-w-50{width:50% !important}.sd-w-75{width:75% !important}.sd-w-100{width:100% !important}.sd-w-auto{width:auto !important}.sd-h-25{height:25% !important}.sd-h-50{height:50% !important}.sd-h-75{height:75% !important}.sd-h-100{height:100% !important}.sd-h-auto{height:auto !important}.sd-d-none{display:none !important}.sd-d-inline{display:inline !important}.sd-d-inline-block{display:inline-block !important}.sd-d-block{display:block !important}.sd-d-grid{display:grid !important}.sd-d-flex-row{display:-ms-flexbox !important;display:flex !important;flex-direction:row !important}.sd-d-flex-column{display:-ms-flexbox !important;display:flex !important;flex-direction:column !important}.sd-d-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}@media(min-width: 576px){.sd-d-sm-none{display:none !important}.sd-d-sm-inline{display:inline !important}.sd-d-sm-inline-block{display:inline-block !important}.sd-d-sm-block{display:block !important}.sd-d-sm-grid{display:grid !important}.sd-d-sm-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-sm-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 768px){.sd-d-md-none{display:none !important}.sd-d-md-inline{display:inline !important}.sd-d-md-inline-block{display:inline-block !important}.sd-d-md-block{display:block !important}.sd-d-md-grid{display:grid !important}.sd-d-md-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-md-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 992px){.sd-d-lg-none{display:none !important}.sd-d-lg-inline{display:inline !important}.sd-d-lg-inline-block{display:inline-block !important}.sd-d-lg-block{display:block !important}.sd-d-lg-grid{display:grid !important}.sd-d-lg-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-lg-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 1200px){.sd-d-xl-none{display:none !important}.sd-d-xl-inline{display:inline !important}.sd-d-xl-inline-block{display:inline-block !important}.sd-d-xl-block{display:block !important}.sd-d-xl-grid{display:grid !important}.sd-d-xl-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-xl-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}.sd-align-major-start{justify-content:flex-start !important}.sd-align-major-end{justify-content:flex-end !important}.sd-align-major-center{justify-content:center !important}.sd-align-major-justify{justify-content:space-between !important}.sd-align-major-spaced{justify-content:space-evenly !important}.sd-align-minor-start{align-items:flex-start !important}.sd-align-minor-end{align-items:flex-end !important}.sd-align-minor-center{align-items:center !important}.sd-align-minor-stretch{align-items:stretch !important}.sd-text-justify{text-align:justify !important}.sd-text-left{text-align:left !important}.sd-text-right{text-align:right !important}.sd-text-center{text-align:center !important}.sd-font-weight-light{font-weight:300 !important}.sd-font-weight-lighter{font-weight:lighter !important}.sd-font-weight-normal{font-weight:400 !important}.sd-font-weight-bold{font-weight:700 !important}.sd-font-weight-bolder{font-weight:bolder !important}.sd-font-italic{font-style:italic !important}.sd-text-decoration-none{text-decoration:none !important}.sd-text-lowercase{text-transform:lowercase !important}.sd-text-uppercase{text-transform:uppercase !important}.sd-text-capitalize{text-transform:capitalize !important}.sd-text-wrap{white-space:normal !important}.sd-text-nowrap{white-space:nowrap !important}.sd-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-fs-1,.sd-fs-1>p{font-size:calc(1.375rem + 1.5vw) !important;line-height:unset !important}.sd-fs-2,.sd-fs-2>p{font-size:calc(1.325rem + 0.9vw) !important;line-height:unset !important}.sd-fs-3,.sd-fs-3>p{font-size:calc(1.3rem + 0.6vw) !important;line-height:unset !important}.sd-fs-4,.sd-fs-4>p{font-size:calc(1.275rem + 0.3vw) !important;line-height:unset !important}.sd-fs-5,.sd-fs-5>p{font-size:1.25rem !important;line-height:unset !important}.sd-fs-6,.sd-fs-6>p{font-size:1rem !important;line-height:unset !important}.sd-border-0{border:0 solid !important}.sd-border-top-0{border-top:0 solid !important}.sd-border-bottom-0{border-bottom:0 solid !important}.sd-border-right-0{border-right:0 solid !important}.sd-border-left-0{border-left:0 solid !important}.sd-border-1{border:1px solid !important}.sd-border-top-1{border-top:1px solid !important}.sd-border-bottom-1{border-bottom:1px solid !important}.sd-border-right-1{border-right:1px solid !important}.sd-border-left-1{border-left:1px solid !important}.sd-border-2{border:2px solid !important}.sd-border-top-2{border-top:2px solid !important}.sd-border-bottom-2{border-bottom:2px solid !important}.sd-border-right-2{border-right:2px solid !important}.sd-border-left-2{border-left:2px solid !important}.sd-border-3{border:3px solid !important}.sd-border-top-3{border-top:3px solid !important}.sd-border-bottom-3{border-bottom:3px solid !important}.sd-border-right-3{border-right:3px solid !important}.sd-border-left-3{border-left:3px solid !important}.sd-border-4{border:4px solid !important}.sd-border-top-4{border-top:4px solid !important}.sd-border-bottom-4{border-bottom:4px solid !important}.sd-border-right-4{border-right:4px solid !important}.sd-border-left-4{border-left:4px solid !important}.sd-border-5{border:5px solid !important}.sd-border-top-5{border-top:5px solid !important}.sd-border-bottom-5{border-bottom:5px solid !important}.sd-border-right-5{border-right:5px solid !important}.sd-border-left-5{border-left:5px solid !important}.sd-rounded-0{border-radius:0 !important}.sd-rounded-1{border-radius:.2rem !important}.sd-rounded-2{border-radius:.3rem !important}.sd-rounded-3{border-radius:.5rem !important}.sd-rounded-pill{border-radius:50rem !important}.sd-rounded-circle{border-radius:50% !important}.shadow-none{box-shadow:none !important}.sd-shadow-sm{box-shadow:0 .125rem .25rem var(--sd-color-shadow) !important}.sd-shadow-md{box-shadow:0 .5rem 1rem var(--sd-color-shadow) !important}.sd-shadow-lg{box-shadow:0 1rem 3rem var(--sd-color-shadow) !important}@keyframes sd-slide-from-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes sd-slide-from-right{0%{transform:translateX(200%)}100%{transform:translateX(0)}}@keyframes sd-grow100{0%{transform:scale(0);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50{0%{transform:scale(0.5);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50-rot20{0%{transform:scale(0.5) rotateZ(-20deg);opacity:.5}75%{transform:scale(1) rotateZ(5deg);opacity:1}95%{transform:scale(1) rotateZ(-1deg);opacity:1}100%{transform:scale(1) rotateZ(0);opacity:1}}.sd-animate-slide-from-left{animation:1s ease-out 0s 1 normal none running sd-slide-from-left}.sd-animate-slide-from-right{animation:1s ease-out 0s 1 normal none running sd-slide-from-right}.sd-animate-grow100{animation:1s ease-out 0s 1 normal none running sd-grow100}.sd-animate-grow50{animation:1s ease-out 0s 1 normal none running sd-grow50}.sd-animate-grow50-rot20{animation:1s ease-out 0s 1 normal none running sd-grow50-rot20}.sd-badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.sd-badge:empty{display:none}a.sd-badge{text-decoration:none}.sd-btn .sd-badge{position:relative;top:-1px}.sd-btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;cursor:pointer;display:inline-block;font-weight:400;font-size:1rem;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:middle;user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none}.sd-btn:hover{text-decoration:none}@media(prefers-reduced-motion: reduce){.sd-btn{transition:none}}.sd-btn-primary,.sd-btn-outline-primary:hover,.sd-btn-outline-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-primary:hover,.sd-btn-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary-highlight) !important;border-color:var(--sd-color-primary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-primary{color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary,.sd-btn-outline-secondary:hover,.sd-btn-outline-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary:hover,.sd-btn-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary-highlight) !important;border-color:var(--sd-color-secondary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-secondary{color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success,.sd-btn-outline-success:hover,.sd-btn-outline-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success:hover,.sd-btn-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success-highlight) !important;border-color:var(--sd-color-success-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-success{color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info,.sd-btn-outline-info:hover,.sd-btn-outline-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info:hover,.sd-btn-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info-highlight) !important;border-color:var(--sd-color-info-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-info{color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning,.sd-btn-outline-warning:hover,.sd-btn-outline-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning:hover,.sd-btn-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning-highlight) !important;border-color:var(--sd-color-warning-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-warning{color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger,.sd-btn-outline-danger:hover,.sd-btn-outline-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger:hover,.sd-btn-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger-highlight) !important;border-color:var(--sd-color-danger-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-danger{color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light,.sd-btn-outline-light:hover,.sd-btn-outline-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light:hover,.sd-btn-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light-highlight) !important;border-color:var(--sd-color-light-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-light{color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted,.sd-btn-outline-muted:hover,.sd-btn-outline-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted:hover,.sd-btn-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted-highlight) !important;border-color:var(--sd-color-muted-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-muted{color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark,.sd-btn-outline-dark:hover,.sd-btn-outline-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark:hover,.sd-btn-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark-highlight) !important;border-color:var(--sd-color-dark-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-dark{color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black,.sd-btn-outline-black:hover,.sd-btn-outline-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black:hover,.sd-btn-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black-highlight) !important;border-color:var(--sd-color-black-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-black{color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white,.sd-btn-outline-white:hover,.sd-btn-outline-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white:hover,.sd-btn-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white-highlight) !important;border-color:var(--sd-color-white-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-white{color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.sd-hide-link-text{font-size:0}.sd-octicon,.sd-material-icon{display:inline-block;fill:currentColor;vertical-align:middle}.sd-avatar-xs{border-radius:50%;object-fit:cover;object-position:center;width:1rem;height:1rem}.sd-avatar-sm{border-radius:50%;object-fit:cover;object-position:center;width:3rem;height:3rem}.sd-avatar-md{border-radius:50%;object-fit:cover;object-position:center;width:5rem;height:5rem}.sd-avatar-lg{border-radius:50%;object-fit:cover;object-position:center;width:7rem;height:7rem}.sd-avatar-xl{border-radius:50%;object-fit:cover;object-position:center;width:10rem;height:10rem}.sd-avatar-inherit{border-radius:50%;object-fit:cover;object-position:center;width:inherit;height:inherit}.sd-avatar-initial{border-radius:50%;object-fit:cover;object-position:center;width:initial;height:initial}.sd-card{background-clip:border-box;background-color:var(--sd-color-card-background);border:1px solid var(--sd-color-card-border);border-radius:.25rem;color:var(--sd-color-card-text);display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.sd-card>hr{margin-left:0;margin-right:0}.sd-card-hover:hover{border-color:var(--sd-color-card-border-hover);transform:scale(1.01)}.sd-card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem 1rem}.sd-card-title{margin-bottom:.5rem}.sd-card-subtitle{margin-top:-0.25rem;margin-bottom:0}.sd-card-text:last-child{margin-bottom:0}.sd-card-link:hover{text-decoration:none}.sd-card-link+.card-link{margin-left:1rem}.sd-card-header{padding:.5rem 1rem;margin-bottom:0;background-color:var(--sd-color-card-header);border-bottom:1px solid var(--sd-color-card-border)}.sd-card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.sd-card-footer{padding:.5rem 1rem;background-color:var(--sd-color-card-footer);border-top:1px solid var(--sd-color-card-border)}.sd-card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.sd-card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.sd-card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.sd-card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom,.sd-card-img-top{width:100%}.sd-card-img,.sd-card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom{border-bottom-left-radius:calc(0.25rem - 1px);border-bottom-right-radius:calc(0.25rem - 1px)}.sd-cards-carousel{width:100%;display:flex;flex-wrap:nowrap;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;scroll-snap-type:x mandatory}.sd-cards-carousel.sd-show-scrollbar{overflow-x:auto}.sd-cards-carousel:hover,.sd-cards-carousel:focus{overflow-x:auto}.sd-cards-carousel>.sd-card{flex-shrink:0;scroll-snap-align:start}.sd-cards-carousel>.sd-card:not(:last-child){margin-right:3px}.sd-card-cols-1>.sd-card{width:90%}.sd-card-cols-2>.sd-card{width:45%}.sd-card-cols-3>.sd-card{width:30%}.sd-card-cols-4>.sd-card{width:22.5%}.sd-card-cols-5>.sd-card{width:18%}.sd-card-cols-6>.sd-card{width:15%}.sd-card-cols-7>.sd-card{width:12.8571428571%}.sd-card-cols-8>.sd-card{width:11.25%}.sd-card-cols-9>.sd-card{width:10%}.sd-card-cols-10>.sd-card{width:9%}.sd-card-cols-11>.sd-card{width:8.1818181818%}.sd-card-cols-12>.sd-card{width:7.5%}.sd-container,.sd-container-fluid,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container-xl{margin-left:auto;margin-right:auto;padding-left:var(--sd-gutter-x, 0.75rem);padding-right:var(--sd-gutter-x, 0.75rem);width:100%}@media(min-width: 576px){.sd-container-sm,.sd-container{max-width:540px}}@media(min-width: 768px){.sd-container-md,.sd-container-sm,.sd-container{max-width:720px}}@media(min-width: 992px){.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:960px}}@media(min-width: 1200px){.sd-container-xl,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:1140px}}.sd-row{--sd-gutter-x: 1.5rem;--sd-gutter-y: 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:calc(var(--sd-gutter-y) * -1);margin-right:calc(var(--sd-gutter-x) * -0.5);margin-left:calc(var(--sd-gutter-x) * -0.5)}.sd-row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--sd-gutter-x) * 0.5);padding-left:calc(var(--sd-gutter-x) * 0.5);margin-top:var(--sd-gutter-y)}.sd-col{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-auto>*{flex:0 0 auto;width:auto}.sd-row-cols-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}@media(min-width: 576px){.sd-col-sm{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-sm-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-sm-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-sm-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-sm-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-sm-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-sm-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-sm-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-sm-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-sm-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-sm-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-sm-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-sm-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-sm-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 768px){.sd-col-md{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-md-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-md-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-md-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-md-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-md-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-md-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-md-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-md-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-md-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-md-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-md-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-md-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-md-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 992px){.sd-col-lg{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-lg-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-lg-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-lg-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-lg-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-lg-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-lg-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-lg-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-lg-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-lg-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-lg-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-lg-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-lg-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-lg-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 1200px){.sd-col-xl{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-xl-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-xl-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-xl-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-xl-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-xl-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-xl-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-xl-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-xl-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-xl-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-xl-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-xl-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-xl-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-xl-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}.sd-col-auto{flex:0 0 auto;-ms-flex:0 0 auto;width:auto}.sd-col-1{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}.sd-col-2{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-col-3{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-col-4{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-col-5{flex:0 0 auto;-ms-flex:0 0 auto;width:41.6666666667%}.sd-col-6{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-col-7{flex:0 0 auto;-ms-flex:0 0 auto;width:58.3333333333%}.sd-col-8{flex:0 0 auto;-ms-flex:0 0 auto;width:66.6666666667%}.sd-col-9{flex:0 0 auto;-ms-flex:0 0 auto;width:75%}.sd-col-10{flex:0 0 auto;-ms-flex:0 0 auto;width:83.3333333333%}.sd-col-11{flex:0 0 auto;-ms-flex:0 0 auto;width:91.6666666667%}.sd-col-12{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-g-0,.sd-gy-0{--sd-gutter-y: 0}.sd-g-0,.sd-gx-0{--sd-gutter-x: 0}.sd-g-1,.sd-gy-1{--sd-gutter-y: 0.25rem}.sd-g-1,.sd-gx-1{--sd-gutter-x: 0.25rem}.sd-g-2,.sd-gy-2{--sd-gutter-y: 0.5rem}.sd-g-2,.sd-gx-2{--sd-gutter-x: 0.5rem}.sd-g-3,.sd-gy-3{--sd-gutter-y: 1rem}.sd-g-3,.sd-gx-3{--sd-gutter-x: 1rem}.sd-g-4,.sd-gy-4{--sd-gutter-y: 1.5rem}.sd-g-4,.sd-gx-4{--sd-gutter-x: 1.5rem}.sd-g-5,.sd-gy-5{--sd-gutter-y: 3rem}.sd-g-5,.sd-gx-5{--sd-gutter-x: 3rem}@media(min-width: 576px){.sd-col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-sm-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-sm-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-sm-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-sm-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-sm-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-sm-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-sm-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-sm-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-sm-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-sm-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-sm-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-sm-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-sm-0,.sd-gy-sm-0{--sd-gutter-y: 0}.sd-g-sm-0,.sd-gx-sm-0{--sd-gutter-x: 0}.sd-g-sm-1,.sd-gy-sm-1{--sd-gutter-y: 0.25rem}.sd-g-sm-1,.sd-gx-sm-1{--sd-gutter-x: 0.25rem}.sd-g-sm-2,.sd-gy-sm-2{--sd-gutter-y: 0.5rem}.sd-g-sm-2,.sd-gx-sm-2{--sd-gutter-x: 0.5rem}.sd-g-sm-3,.sd-gy-sm-3{--sd-gutter-y: 1rem}.sd-g-sm-3,.sd-gx-sm-3{--sd-gutter-x: 1rem}.sd-g-sm-4,.sd-gy-sm-4{--sd-gutter-y: 1.5rem}.sd-g-sm-4,.sd-gx-sm-4{--sd-gutter-x: 1.5rem}.sd-g-sm-5,.sd-gy-sm-5{--sd-gutter-y: 3rem}.sd-g-sm-5,.sd-gx-sm-5{--sd-gutter-x: 3rem}}@media(min-width: 768px){.sd-col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-md-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-md-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-md-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-md-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-md-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-md-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-md-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-md-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-md-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-md-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-md-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-md-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-md-0,.sd-gy-md-0{--sd-gutter-y: 0}.sd-g-md-0,.sd-gx-md-0{--sd-gutter-x: 0}.sd-g-md-1,.sd-gy-md-1{--sd-gutter-y: 0.25rem}.sd-g-md-1,.sd-gx-md-1{--sd-gutter-x: 0.25rem}.sd-g-md-2,.sd-gy-md-2{--sd-gutter-y: 0.5rem}.sd-g-md-2,.sd-gx-md-2{--sd-gutter-x: 0.5rem}.sd-g-md-3,.sd-gy-md-3{--sd-gutter-y: 1rem}.sd-g-md-3,.sd-gx-md-3{--sd-gutter-x: 1rem}.sd-g-md-4,.sd-gy-md-4{--sd-gutter-y: 1.5rem}.sd-g-md-4,.sd-gx-md-4{--sd-gutter-x: 1.5rem}.sd-g-md-5,.sd-gy-md-5{--sd-gutter-y: 3rem}.sd-g-md-5,.sd-gx-md-5{--sd-gutter-x: 3rem}}@media(min-width: 992px){.sd-col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-lg-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-lg-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-lg-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-lg-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-lg-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-lg-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-lg-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-lg-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-lg-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-lg-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-lg-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-lg-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-lg-0,.sd-gy-lg-0{--sd-gutter-y: 0}.sd-g-lg-0,.sd-gx-lg-0{--sd-gutter-x: 0}.sd-g-lg-1,.sd-gy-lg-1{--sd-gutter-y: 0.25rem}.sd-g-lg-1,.sd-gx-lg-1{--sd-gutter-x: 0.25rem}.sd-g-lg-2,.sd-gy-lg-2{--sd-gutter-y: 0.5rem}.sd-g-lg-2,.sd-gx-lg-2{--sd-gutter-x: 0.5rem}.sd-g-lg-3,.sd-gy-lg-3{--sd-gutter-y: 1rem}.sd-g-lg-3,.sd-gx-lg-3{--sd-gutter-x: 1rem}.sd-g-lg-4,.sd-gy-lg-4{--sd-gutter-y: 1.5rem}.sd-g-lg-4,.sd-gx-lg-4{--sd-gutter-x: 1.5rem}.sd-g-lg-5,.sd-gy-lg-5{--sd-gutter-y: 3rem}.sd-g-lg-5,.sd-gx-lg-5{--sd-gutter-x: 3rem}}@media(min-width: 1200px){.sd-col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-xl-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-xl-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-xl-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-xl-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-xl-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-xl-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-xl-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-xl-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-xl-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-xl-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-xl-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-xl-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-xl-0,.sd-gy-xl-0{--sd-gutter-y: 0}.sd-g-xl-0,.sd-gx-xl-0{--sd-gutter-x: 0}.sd-g-xl-1,.sd-gy-xl-1{--sd-gutter-y: 0.25rem}.sd-g-xl-1,.sd-gx-xl-1{--sd-gutter-x: 0.25rem}.sd-g-xl-2,.sd-gy-xl-2{--sd-gutter-y: 0.5rem}.sd-g-xl-2,.sd-gx-xl-2{--sd-gutter-x: 0.5rem}.sd-g-xl-3,.sd-gy-xl-3{--sd-gutter-y: 1rem}.sd-g-xl-3,.sd-gx-xl-3{--sd-gutter-x: 1rem}.sd-g-xl-4,.sd-gy-xl-4{--sd-gutter-y: 1.5rem}.sd-g-xl-4,.sd-gx-xl-4{--sd-gutter-x: 1.5rem}.sd-g-xl-5,.sd-gy-xl-5{--sd-gutter-y: 3rem}.sd-g-xl-5,.sd-gx-xl-5{--sd-gutter-x: 3rem}}.sd-flex-row-reverse{flex-direction:row-reverse !important}details.sd-dropdown{position:relative;font-size:var(--sd-fontsize-dropdown)}details.sd-dropdown:hover{cursor:pointer}details.sd-dropdown .sd-summary-content{cursor:default}details.sd-dropdown summary.sd-summary-title{padding:.5em .6em .5em 1em;font-size:var(--sd-fontsize-dropdown-title);font-weight:var(--sd-fontweight-dropdown-title);user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;list-style:none;display:inline-flex;justify-content:space-between}details.sd-dropdown summary.sd-summary-title::-webkit-details-marker{display:none}details.sd-dropdown summary.sd-summary-title:focus{outline:none}details.sd-dropdown summary.sd-summary-title .sd-summary-icon{margin-right:.6em;display:inline-flex;align-items:center}details.sd-dropdown summary.sd-summary-title .sd-summary-icon svg{opacity:.8}details.sd-dropdown summary.sd-summary-title .sd-summary-text{flex-grow:1;line-height:1.5;padding-right:.5rem}details.sd-dropdown summary.sd-summary-title .sd-summary-state-marker{pointer-events:none;display:inline-flex;align-items:center}details.sd-dropdown summary.sd-summary-title .sd-summary-state-marker svg{opacity:.6}details.sd-dropdown summary.sd-summary-title:hover .sd-summary-state-marker svg{opacity:1;transform:scale(1.1)}details.sd-dropdown[open] summary .sd-octicon.no-title{visibility:hidden}details.sd-dropdown .sd-summary-chevron-right{transition:.25s}details.sd-dropdown[open]>.sd-summary-title .sd-summary-chevron-right{transform:rotate(90deg)}details.sd-dropdown[open]>.sd-summary-title .sd-summary-chevron-down{transform:rotate(180deg)}details.sd-dropdown:not([open]).sd-card{border:none}details.sd-dropdown:not([open])>.sd-card-header{border:1px solid var(--sd-color-card-border);border-radius:.25rem}details.sd-dropdown.sd-fade-in[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out;animation:sd-fade-in .5s ease-in-out}details.sd-dropdown.sd-fade-in-slide-down[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out}.sd-col>.sd-dropdown{width:100%}.sd-summary-content>.sd-tab-set:first-child{margin-top:0}@keyframes sd-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes sd-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.sd-tab-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.sd-tab-set>input{opacity:0;position:absolute}.sd-tab-set>input:checked+label{border-color:var(--sd-color-tabs-underline-active);color:var(--sd-color-tabs-label-active)}.sd-tab-set>input:checked+label+.sd-tab-content{display:block}.sd-tab-set>input:not(:checked)+label:hover{color:var(--sd-color-tabs-label-hover);border-color:var(--sd-color-tabs-underline-hover)}.sd-tab-set>input:focus+label{outline-style:auto}.sd-tab-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.sd-tab-set>label{border-bottom:.125rem solid transparent;margin-bottom:0;color:var(--sd-color-tabs-label-inactive);border-color:var(--sd-color-tabs-underline-inactive);cursor:pointer;font-size:var(--sd-fontsize-tabs-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .sd-tab-set>label:hover{color:var(--sd-color-tabs-label-active)}.sd-col>.sd-tab-set{width:100%}.sd-tab-content{box-shadow:0 -0.0625rem var(--sd-color-tabs-overline),0 .0625rem var(--sd-color-tabs-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.sd-tab-content>:first-child{margin-top:0 !important}.sd-tab-content>:last-child{margin-bottom:0 !important}.sd-tab-content>.sd-tab-set{margin:0}.sd-sphinx-override,.sd-sphinx-override *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sd-sphinx-override p{margin-top:0}:root{--sd-color-primary: #0071bc;--sd-color-secondary: #6c757d;--sd-color-success: #28a745;--sd-color-info: #17a2b8;--sd-color-warning: #f0b37e;--sd-color-danger: #dc3545;--sd-color-light: #f8f9fa;--sd-color-muted: #6c757d;--sd-color-dark: #212529;--sd-color-black: black;--sd-color-white: white;--sd-color-primary-highlight: #0060a0;--sd-color-secondary-highlight: #5c636a;--sd-color-success-highlight: #228e3b;--sd-color-info-highlight: #148a9c;--sd-color-warning-highlight: #cc986b;--sd-color-danger-highlight: #bb2d3b;--sd-color-light-highlight: #d3d4d5;--sd-color-muted-highlight: #5c636a;--sd-color-dark-highlight: #1c1f23;--sd-color-black-highlight: black;--sd-color-white-highlight: #d9d9d9;--sd-color-primary-bg: rgba(0, 113, 188, 0.2);--sd-color-secondary-bg: rgba(108, 117, 125, 0.2);--sd-color-success-bg: rgba(40, 167, 69, 0.2);--sd-color-info-bg: rgba(23, 162, 184, 0.2);--sd-color-warning-bg: rgba(240, 179, 126, 0.2);--sd-color-danger-bg: rgba(220, 53, 69, 0.2);--sd-color-light-bg: rgba(248, 249, 250, 0.2);--sd-color-muted-bg: rgba(108, 117, 125, 0.2);--sd-color-dark-bg: rgba(33, 37, 41, 0.2);--sd-color-black-bg: rgba(0, 0, 0, 0.2);--sd-color-white-bg: rgba(255, 255, 255, 0.2);--sd-color-primary-text: #fff;--sd-color-secondary-text: #fff;--sd-color-success-text: #fff;--sd-color-info-text: #fff;--sd-color-warning-text: #212529;--sd-color-danger-text: #fff;--sd-color-light-text: #212529;--sd-color-muted-text: #fff;--sd-color-dark-text: #fff;--sd-color-black-text: #fff;--sd-color-white-text: #212529;--sd-color-shadow: rgba(0, 0, 0, 0.15);--sd-color-card-border: rgba(0, 0, 0, 0.125);--sd-color-card-border-hover: hsla(231, 99%, 66%, 1);--sd-color-card-background: transparent;--sd-color-card-text: inherit;--sd-color-card-header: transparent;--sd-color-card-footer: transparent;--sd-color-tabs-label-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-hover: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-inactive: hsl(0, 0%, 66%);--sd-color-tabs-underline-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-underline-hover: rgba(178, 206, 245, 0.62);--sd-color-tabs-underline-inactive: transparent;--sd-color-tabs-overline: rgb(222, 222, 222);--sd-color-tabs-underline: rgb(222, 222, 222);--sd-fontsize-tabs-label: 1rem;--sd-fontsize-dropdown: inherit;--sd-fontsize-dropdown-title: 1rem;--sd-fontweight-dropdown-title: 700} diff --git a/releases/2.0.0/_static/aimet-furo.css b/releases/2.0.0/_static/aimet-furo.css new file mode 100644 index 0000000..624bcdf --- /dev/null +++ b/releases/2.0.0/_static/aimet-furo.css @@ -0,0 +1,98 @@ +/* + * AIMET color palette + */ +:root { + --aimet-blue: #3253dc; + --aimet-dark-blue: #0000ff; + --aimet-white: #ffffff; + --aimet-border-grey: #e0e0e0; + --aimet-menu-hover: #e3efff; + --aimet-menu-font-active: #0058ff; + --aimet-code-grey: #fafafa; + --aimet-light-blue: #e7f2fa; + } + + aside.toc-drawer ul ul ul ul { + display: none; +} + +.toctree-l3 { + display: none; +} + +[for^="toctree-checkbox-"], [id^="toctree-checkbox-"] { + visibility: hidden; +} + +/* + * Configure the appearance of code output box. + * Values are based on sphinx-gallery configuration +*/ +.script-output { + color: black; + display: flex; + gap: 0.5em; +} + +.script-output::before { + content: "Out:"; + line-height: 1.4; + padding-top: 10px; +} + +.script-output .highlight { + background: transparent; + flex-grow: 1; + overflow: auto; + /* Allow output block to take up maximum 25 lines */ + max-height: 25em; +} + +*.highlight pre, pre.literal-block { + background-color: var(--aimet-code-grey); +} + +/* + * Glossary formatting +*/ +[id^="term-"] { + font-weight: bold; +} + +/* + * Heading formatting + */ + +h1 { + font-size:2.5em; + margin-top:1.75rem; + margin-bottom:1rem; +} + +h2 { + font-size:2em; + margin-top:1.75rem; + margin-bottom:1.25rem; + font-weight: normal; +} + +h3 { + font-size:1.5em; + margin-top:1.25rem; + margin-bottom:1.25rem; + font-weight: normal; +} + +h4 { + font-size:1.25em; + margin-top:1.25rem; + margin-bottom:1.25rem; + font-weight: normal; +} + +h5 { + font-size:1.125em; + margin-top:1.25rem; + margin-bottom:1.25rem; + font-weight: normal; +} \ No newline at end of file diff --git a/releases/2.0.0/_static/basic.css b/releases/2.0.0/_static/basic.css new file mode 100644 index 0000000..7ebbd6d --- /dev/null +++ b/releases/2.0.0/_static/basic.css @@ -0,0 +1,914 @@ +/* + * Sphinx stylesheet -- basic theme. + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin-top: 10px; +} + +ul.search li { + padding: 5px 0; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/releases/2.0.0/_static/check-solid.svg b/releases/2.0.0/_static/check-solid.svg new file mode 100644 index 0000000..92fad4b --- /dev/null +++ b/releases/2.0.0/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/releases/2.0.0/_static/clipboard.min.js b/releases/2.0.0/_static/clipboard.min.js new file mode 100644 index 0000000..54b3c46 --- /dev/null +++ b/releases/2.0.0/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/releases/2.0.0/_static/copybutton.css b/releases/2.0.0/_static/copybutton.css new file mode 100644 index 0000000..f1916ec --- /dev/null +++ b/releases/2.0.0/_static/copybutton.css @@ -0,0 +1,94 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +/* Show the copybutton */ +.highlight:hover button.copybtn, button.copybtn.success { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

    Short

    + */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/releases/2.0.0/_static/copybutton.js b/releases/2.0.0/_static/copybutton.js new file mode 100644 index 0000000..2ea7ff3 --- /dev/null +++ b/releases/2.0.0/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/releases/2.0.0/_static/copybutton_funcs.js b/releases/2.0.0/_static/copybutton_funcs.js new file mode 100644 index 0000000..dbe1aaa --- /dev/null +++ b/releases/2.0.0/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/releases/2.0.0/_static/debug.css b/releases/2.0.0/_static/debug.css new file mode 100644 index 0000000..74d4aec --- /dev/null +++ b/releases/2.0.0/_static/debug.css @@ -0,0 +1,69 @@ +/* + This CSS file should be overridden by the theme authors. It's + meant for debugging and developing the skeleton that this theme provides. +*/ +body { + font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji"; + background: lavender; +} +.sb-announcement { + background: rgb(131, 131, 131); +} +.sb-announcement__inner { + background: black; + color: white; +} +.sb-header { + background: lightskyblue; +} +.sb-header__inner { + background: royalblue; + color: white; +} +.sb-header-secondary { + background: lightcyan; +} +.sb-header-secondary__inner { + background: cornflowerblue; + color: white; +} +.sb-sidebar-primary { + background: lightgreen; +} +.sb-main { + background: blanchedalmond; +} +.sb-main__inner { + background: antiquewhite; +} +.sb-header-article { + background: lightsteelblue; +} +.sb-article-container { + background: snow; +} +.sb-article-main { + background: white; +} +.sb-footer-article { + background: lightpink; +} +.sb-sidebar-secondary { + background: lightgoldenrodyellow; +} +.sb-footer-content { + background: plum; +} +.sb-footer-content__inner { + background: palevioletred; +} +.sb-footer { + background: pink; +} +.sb-footer__inner { + background: salmon; +} +.sb-article { + background: white; +} diff --git a/releases/2.0.0/_static/design-tabs.js b/releases/2.0.0/_static/design-tabs.js new file mode 100644 index 0000000..b25bd6a --- /dev/null +++ b/releases/2.0.0/_static/design-tabs.js @@ -0,0 +1,101 @@ +// @ts-check + +// Extra JS capability for selected tabs to be synced +// The selection is stored in local storage so that it persists across page loads. + +/** + * @type {Record} + */ +let sd_id_to_elements = {}; +const storageKeyPrefix = "sphinx-design-tab-id-"; + +/** + * Create a key for a tab element. + * @param {HTMLElement} el - The tab element. + * @returns {[string, string, string] | null} - The key. + * + */ +function create_key(el) { + let syncId = el.getAttribute("data-sync-id"); + let syncGroup = el.getAttribute("data-sync-group"); + if (!syncId || !syncGroup) return null; + return [syncGroup, syncId, syncGroup + "--" + syncId]; +} + +/** + * Initialize the tab selection. + * + */ +function ready() { + // Find all tabs with sync data + + /** @type {string[]} */ + let groups = []; + + document.querySelectorAll(".sd-tab-label").forEach((label) => { + if (label instanceof HTMLElement) { + let data = create_key(label); + if (data) { + let [group, id, key] = data; + + // add click event listener + // @ts-ignore + label.onclick = onSDLabelClick; + + // store map of key to elements + if (!sd_id_to_elements[key]) { + sd_id_to_elements[key] = []; + } + sd_id_to_elements[key].push(label); + + if (groups.indexOf(group) === -1) { + groups.push(group); + // Check if a specific tab has been selected via URL parameter + const tabParam = new URLSearchParams(window.location.search).get( + group + ); + if (tabParam) { + console.log( + "sphinx-design: Selecting tab id for group '" + + group + + "' from URL parameter: " + + tabParam + ); + window.sessionStorage.setItem(storageKeyPrefix + group, tabParam); + } + } + + // Check is a specific tab has been selected previously + let previousId = window.sessionStorage.getItem( + storageKeyPrefix + group + ); + if (previousId === id) { + // console.log( + // "sphinx-design: Selecting tab from session storage: " + id + // ); + // @ts-ignore + label.previousElementSibling.checked = true; + } + } + } + }); +} + +/** + * Activate other tabs with the same sync id. + * + * @this {HTMLElement} - The element that was clicked. + */ +function onSDLabelClick() { + let data = create_key(this); + if (!data) return; + let [group, id, key] = data; + for (const label of sd_id_to_elements[key]) { + if (label === this) continue; + // @ts-ignore + label.previousElementSibling.checked = true; + } + window.sessionStorage.setItem(storageKeyPrefix + group, id); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/releases/2.0.0/_static/doctools.js b/releases/2.0.0/_static/doctools.js new file mode 100644 index 0000000..0398ebb --- /dev/null +++ b/releases/2.0.0/_static/doctools.js @@ -0,0 +1,149 @@ +/* + * Base JavaScript utilities for all Sphinx HTML documentation. + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/releases/2.0.0/_static/documentation_options.js b/releases/2.0.0/_static/documentation_options.js new file mode 100644 index 0000000..f38abe9 --- /dev/null +++ b/releases/2.0.0/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: true, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/releases/2.0.0/_static/file.png b/releases/2.0.0/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_static/language_data.js b/releases/2.0.0/_static/language_data.js new file mode 100644 index 0000000..c7fe6c6 --- /dev/null +++ b/releases/2.0.0/_static/language_data.js @@ -0,0 +1,192 @@ +/* + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, if available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/releases/2.0.0/_static/minus.png b/releases/2.0.0/_static/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..d96755fdaf8bb2214971e0db9c1fd3077d7c419d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu=nj kDsEF_5m^0CR;1wuP-*O&G^0G}KYk!hp00i_>zopr08q^qX#fBK literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_static/nbsphinx-broken-thumbnail.svg b/releases/2.0.0/_static/nbsphinx-broken-thumbnail.svg new file mode 100644 index 0000000..4919ca8 --- /dev/null +++ b/releases/2.0.0/_static/nbsphinx-broken-thumbnail.svg @@ -0,0 +1,9 @@ + + + + diff --git a/releases/2.0.0/_static/nbsphinx-code-cells.css b/releases/2.0.0/_static/nbsphinx-code-cells.css new file mode 100644 index 0000000..a3fb27c --- /dev/null +++ b/releases/2.0.0/_static/nbsphinx-code-cells.css @@ -0,0 +1,259 @@ +/* remove conflicting styling from Sphinx themes */ +div.nbinput.container div.prompt *, +div.nboutput.container div.prompt *, +div.nbinput.container div.input_area pre, +div.nboutput.container div.output_area pre, +div.nbinput.container div.input_area .highlight, +div.nboutput.container div.output_area .highlight { + border: none; + padding: 0; + margin: 0; + box-shadow: none; +} + +div.nbinput.container > div[class*=highlight], +div.nboutput.container > div[class*=highlight] { + margin: 0; +} + +div.nbinput.container div.prompt *, +div.nboutput.container div.prompt * { + background: none; +} + +div.nboutput.container div.output_area .highlight, +div.nboutput.container div.output_area pre { + background: unset; +} + +div.nboutput.container div.output_area div.highlight { + color: unset; /* override Pygments text color */ +} + +/* avoid gaps between output lines */ +div.nboutput.container div[class*=highlight] pre { + line-height: normal; +} + +/* input/output containers */ +div.nbinput.container, +div.nboutput.container { + display: -webkit-flex; + display: flex; + align-items: flex-start; + margin: 0; + width: 100%; +} +@media (max-width: 540px) { + div.nbinput.container, + div.nboutput.container { + flex-direction: column; + } +} + +/* input container */ +div.nbinput.container { + padding-top: 5px; +} + +/* last container */ +div.nblast.container { + padding-bottom: 5px; +} + +/* input prompt */ +div.nbinput.container div.prompt pre, +/* for sphinx_immaterial theme: */ +div.nbinput.container div.prompt pre > code { + color: #307FC1; +} + +/* output prompt */ +div.nboutput.container div.prompt pre, +/* for sphinx_immaterial theme: */ +div.nboutput.container div.prompt pre > code { + color: #BF5B3D; +} + +/* all prompts */ +div.nbinput.container div.prompt, +div.nboutput.container div.prompt { + width: 4.5ex; + padding-top: 5px; + position: relative; + user-select: none; +} + +div.nbinput.container div.prompt > div, +div.nboutput.container div.prompt > div { + position: absolute; + right: 0; + margin-right: 0.3ex; +} + +@media (max-width: 540px) { + div.nbinput.container div.prompt, + div.nboutput.container div.prompt { + width: unset; + text-align: left; + padding: 0.4em; + } + div.nboutput.container div.prompt.empty { + padding: 0; + } + + div.nbinput.container div.prompt > div, + div.nboutput.container div.prompt > div { + position: unset; + } +} + +/* disable scrollbars and line breaks on prompts */ +div.nbinput.container div.prompt pre, +div.nboutput.container div.prompt pre { + overflow: hidden; + white-space: pre; +} + +/* input/output area */ +div.nbinput.container div.input_area, +div.nboutput.container div.output_area { + -webkit-flex: 1; + flex: 1; + overflow: auto; +} +@media (max-width: 540px) { + div.nbinput.container div.input_area, + div.nboutput.container div.output_area { + width: 100%; + } +} + +/* input area */ +div.nbinput.container div.input_area { + border: 1px solid #e0e0e0; + border-radius: 2px; + /*background: #f5f5f5;*/ +} + +/* override MathJax center alignment in output cells */ +div.nboutput.container div[class*=MathJax] { + text-align: left !important; +} + +/* override sphinx.ext.imgmath center alignment in output cells */ +div.nboutput.container div.math p { + text-align: left; +} + +/* standard error */ +div.nboutput.container div.output_area.stderr { + background: #fdd; +} + +/* ANSI colors */ +.ansi-black-fg { color: #3E424D; } +.ansi-black-bg { background-color: #3E424D; } +.ansi-black-intense-fg { color: #282C36; } +.ansi-black-intense-bg { background-color: #282C36; } +.ansi-red-fg { color: #E75C58; } +.ansi-red-bg { background-color: #E75C58; } +.ansi-red-intense-fg { color: #B22B31; } +.ansi-red-intense-bg { background-color: #B22B31; } +.ansi-green-fg { color: #00A250; } +.ansi-green-bg { background-color: #00A250; } +.ansi-green-intense-fg { color: #007427; } +.ansi-green-intense-bg { background-color: #007427; } +.ansi-yellow-fg { color: #DDB62B; } +.ansi-yellow-bg { background-color: #DDB62B; } +.ansi-yellow-intense-fg { color: #B27D12; } +.ansi-yellow-intense-bg { background-color: #B27D12; } +.ansi-blue-fg { color: #208FFB; } +.ansi-blue-bg { background-color: #208FFB; } +.ansi-blue-intense-fg { color: #0065CA; } +.ansi-blue-intense-bg { background-color: #0065CA; } +.ansi-magenta-fg { color: #D160C4; } +.ansi-magenta-bg { background-color: #D160C4; } +.ansi-magenta-intense-fg { color: #A03196; } +.ansi-magenta-intense-bg { background-color: #A03196; } +.ansi-cyan-fg { color: #60C6C8; } +.ansi-cyan-bg { background-color: #60C6C8; } +.ansi-cyan-intense-fg { color: #258F8F; } +.ansi-cyan-intense-bg { background-color: #258F8F; } +.ansi-white-fg { color: #C5C1B4; } +.ansi-white-bg { background-color: #C5C1B4; } +.ansi-white-intense-fg { color: #A1A6B2; } +.ansi-white-intense-bg { background-color: #A1A6B2; } + +.ansi-default-inverse-fg { color: #FFFFFF; } +.ansi-default-inverse-bg { background-color: #000000; } + +.ansi-bold { font-weight: bold; } +.ansi-underline { text-decoration: underline; } + + +div.nbinput.container div.input_area div[class*=highlight] > pre, +div.nboutput.container div.output_area div[class*=highlight] > pre, +div.nboutput.container div.output_area div[class*=highlight].math, +div.nboutput.container div.output_area.rendered_html, +div.nboutput.container div.output_area > div.output_javascript, +div.nboutput.container div.output_area:not(.rendered_html) > img{ + padding: 5px; + margin: 0; +} + +/* fix copybtn overflow problem in chromium (needed for 'sphinx_copybutton') */ +div.nbinput.container div.input_area > div[class^='highlight'], +div.nboutput.container div.output_area > div[class^='highlight']{ + overflow-y: hidden; +} + +/* hide copy button on prompts for 'sphinx_copybutton' extension ... */ +.prompt .copybtn, +/* ... and 'sphinx_immaterial' theme */ +.prompt .md-clipboard.md-icon { + display: none; +} + +/* Some additional styling taken form the Jupyter notebook CSS */ +.jp-RenderedHTMLCommon table, +div.rendered_html table { + border: none; + border-collapse: collapse; + border-spacing: 0; + color: black; + font-size: 12px; + table-layout: fixed; +} +.jp-RenderedHTMLCommon thead, +div.rendered_html thead { + border-bottom: 1px solid black; + vertical-align: bottom; +} +.jp-RenderedHTMLCommon tr, +.jp-RenderedHTMLCommon th, +.jp-RenderedHTMLCommon td, +div.rendered_html tr, +div.rendered_html th, +div.rendered_html td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} +.jp-RenderedHTMLCommon th, +div.rendered_html th { + font-weight: bold; +} +.jp-RenderedHTMLCommon tbody tr:nth-child(odd), +div.rendered_html tbody tr:nth-child(odd) { + background: #f5f5f5; +} +.jp-RenderedHTMLCommon tbody tr:hover, +div.rendered_html tbody tr:hover { + background: rgba(66, 165, 245, 0.2); +} + diff --git a/releases/2.0.0/_static/nbsphinx-gallery.css b/releases/2.0.0/_static/nbsphinx-gallery.css new file mode 100644 index 0000000..365c27a --- /dev/null +++ b/releases/2.0.0/_static/nbsphinx-gallery.css @@ -0,0 +1,31 @@ +.nbsphinx-gallery { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + gap: 5px; + margin-top: 1em; + margin-bottom: 1em; +} + +.nbsphinx-gallery > a { + padding: 5px; + border: 1px dotted currentColor; + border-radius: 2px; + text-align: center; +} + +.nbsphinx-gallery > a:hover { + border-style: solid; +} + +.nbsphinx-gallery img { + max-width: 100%; + max-height: 100%; +} + +.nbsphinx-gallery > a > div:first-child { + display: flex; + align-items: start; + justify-content: center; + height: 120px; + margin-bottom: 5px; +} diff --git a/releases/2.0.0/_static/nbsphinx-no-thumbnail.svg b/releases/2.0.0/_static/nbsphinx-no-thumbnail.svg new file mode 100644 index 0000000..9dca758 --- /dev/null +++ b/releases/2.0.0/_static/nbsphinx-no-thumbnail.svg @@ -0,0 +1,9 @@ + + + + diff --git a/releases/2.0.0/_static/plus.png b/releases/2.0.0/_static/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..7107cec93a979b9a5f64843235a16651d563ce2d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu>-2 m3q%Vub%g%s<8sJhVPMczOq}xhg9DJoz~JfX=d#Wzp$Pyb1r*Kz literal 0 HcmV?d00001 diff --git a/releases/2.0.0/_static/pygments.css b/releases/2.0.0/_static/pygments.css new file mode 100644 index 0000000..cb16a42 --- /dev/null +++ b/releases/2.0.0/_static/pygments.css @@ -0,0 +1,249 @@ +.highlight pre { line-height: 125%; } +.highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +.highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +.highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #F00 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #FFF0F0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #F00 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333 } /* Generic.Output */ +.highlight .gp { color: #C65D09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #04D } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070A0 } /* Literal.String */ +.highlight .na { color: #4070A0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0E84B5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60ADD5 } /* Name.Constant */ +.highlight .nd { color: #555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #D55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287E } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0E84B5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #BB60D5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #BBB } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070A0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070A0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070A0 } /* Literal.String.Char */ +.highlight .dl { color: #4070A0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070A0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070A0 } /* Literal.String.Double */ +.highlight .se { color: #4070A0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070A0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70A0D0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #C65D09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070A0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287E } /* Name.Function.Magic */ +.highlight .vc { color: #BB60D5 } /* Name.Variable.Class */ +.highlight .vg { color: #BB60D5 } /* Name.Variable.Global */ +.highlight .vi { color: #BB60D5 } /* Name.Variable.Instance */ +.highlight .vm { color: #BB60D5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ +@media not print { +body[data-theme="dark"] .highlight pre { line-height: 125%; } +body[data-theme="dark"] .highlight td.linenos .normal { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight span.linenos { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight .hll { background-color: #404040 } +body[data-theme="dark"] .highlight { background: #202020; color: #D0D0D0 } +body[data-theme="dark"] .highlight .c { color: #ABABAB; font-style: italic } /* Comment */ +body[data-theme="dark"] .highlight .err { color: #A61717; background-color: #E3D2D2 } /* Error */ +body[data-theme="dark"] .highlight .esc { color: #D0D0D0 } /* Escape */ +body[data-theme="dark"] .highlight .g { color: #D0D0D0 } /* Generic */ +body[data-theme="dark"] .highlight .k { color: #6EBF26; font-weight: bold } /* Keyword */ +body[data-theme="dark"] .highlight .l { color: #D0D0D0 } /* Literal */ +body[data-theme="dark"] .highlight .n { color: #D0D0D0 } /* Name */ +body[data-theme="dark"] .highlight .o { color: #D0D0D0 } /* Operator */ +body[data-theme="dark"] .highlight .x { color: #D0D0D0 } /* Other */ +body[data-theme="dark"] .highlight .p { color: #D0D0D0 } /* Punctuation */ +body[data-theme="dark"] .highlight .ch { color: #ABABAB; font-style: italic } /* Comment.Hashbang */ +body[data-theme="dark"] .highlight .cm { color: #ABABAB; font-style: italic } /* Comment.Multiline */ +body[data-theme="dark"] .highlight .cp { color: #FF3A3A; font-weight: bold } /* Comment.Preproc */ +body[data-theme="dark"] .highlight .cpf { color: #ABABAB; font-style: italic } /* Comment.PreprocFile */ +body[data-theme="dark"] .highlight .c1 { color: #ABABAB; font-style: italic } /* Comment.Single */ +body[data-theme="dark"] .highlight .cs { color: #E50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +body[data-theme="dark"] .highlight .gd { color: #FF3A3A } /* Generic.Deleted */ +body[data-theme="dark"] .highlight .ge { color: #D0D0D0; font-style: italic } /* Generic.Emph */ +body[data-theme="dark"] .highlight .ges { color: #D0D0D0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +body[data-theme="dark"] .highlight .gr { color: #FF3A3A } /* Generic.Error */ +body[data-theme="dark"] .highlight .gh { color: #FFF; font-weight: bold } /* Generic.Heading */ +body[data-theme="dark"] .highlight .gi { color: #589819 } /* Generic.Inserted */ +body[data-theme="dark"] .highlight .go { color: #CCC } /* Generic.Output */ +body[data-theme="dark"] .highlight .gp { color: #AAA } /* Generic.Prompt */ +body[data-theme="dark"] .highlight .gs { color: #D0D0D0; font-weight: bold } /* Generic.Strong */ +body[data-theme="dark"] .highlight .gu { color: #FFF; text-decoration: underline } /* Generic.Subheading */ +body[data-theme="dark"] .highlight .gt { color: #FF3A3A } /* Generic.Traceback */ +body[data-theme="dark"] .highlight .kc { color: #6EBF26; font-weight: bold } /* Keyword.Constant */ +body[data-theme="dark"] .highlight .kd { color: #6EBF26; font-weight: bold } /* Keyword.Declaration */ +body[data-theme="dark"] .highlight .kn { color: #6EBF26; font-weight: bold } /* Keyword.Namespace */ +body[data-theme="dark"] .highlight .kp { color: #6EBF26 } /* Keyword.Pseudo */ +body[data-theme="dark"] .highlight .kr { color: #6EBF26; font-weight: bold } /* Keyword.Reserved */ +body[data-theme="dark"] .highlight .kt { color: #6EBF26; font-weight: bold } /* Keyword.Type */ +body[data-theme="dark"] .highlight .ld { color: #D0D0D0 } /* Literal.Date */ +body[data-theme="dark"] .highlight .m { color: #51B2FD } /* Literal.Number */ +body[data-theme="dark"] .highlight .s { color: #ED9D13 } /* Literal.String */ +body[data-theme="dark"] .highlight .na { color: #BBB } /* Name.Attribute */ +body[data-theme="dark"] .highlight .nb { color: #2FBCCD } /* Name.Builtin */ +body[data-theme="dark"] .highlight .nc { color: #71ADFF; text-decoration: underline } /* Name.Class */ +body[data-theme="dark"] .highlight .no { color: #40FFFF } /* Name.Constant */ +body[data-theme="dark"] .highlight .nd { color: #FFA500 } /* Name.Decorator */ +body[data-theme="dark"] .highlight .ni { color: #D0D0D0 } /* Name.Entity */ +body[data-theme="dark"] .highlight .ne { color: #BBB } /* Name.Exception */ +body[data-theme="dark"] .highlight .nf { color: #71ADFF } /* Name.Function */ +body[data-theme="dark"] .highlight .nl { color: #D0D0D0 } /* Name.Label */ +body[data-theme="dark"] .highlight .nn { color: #71ADFF; text-decoration: underline } /* Name.Namespace */ +body[data-theme="dark"] .highlight .nx { color: #D0D0D0 } /* Name.Other */ +body[data-theme="dark"] .highlight .py { color: #D0D0D0 } /* Name.Property */ +body[data-theme="dark"] .highlight .nt { color: #6EBF26; font-weight: bold } /* Name.Tag */ +body[data-theme="dark"] .highlight .nv { color: #40FFFF } /* Name.Variable */ +body[data-theme="dark"] .highlight .ow { color: #6EBF26; font-weight: bold } /* Operator.Word */ +body[data-theme="dark"] .highlight .pm { color: #D0D0D0 } /* Punctuation.Marker */ +body[data-theme="dark"] .highlight .w { color: #666 } /* Text.Whitespace */ +body[data-theme="dark"] .highlight .mb { color: #51B2FD } /* Literal.Number.Bin */ +body[data-theme="dark"] .highlight .mf { color: #51B2FD } /* Literal.Number.Float */ +body[data-theme="dark"] .highlight .mh { color: #51B2FD } /* Literal.Number.Hex */ +body[data-theme="dark"] .highlight .mi { color: #51B2FD } /* Literal.Number.Integer */ +body[data-theme="dark"] .highlight .mo { color: #51B2FD } /* Literal.Number.Oct */ +body[data-theme="dark"] .highlight .sa { color: #ED9D13 } /* Literal.String.Affix */ +body[data-theme="dark"] .highlight .sb { color: #ED9D13 } /* Literal.String.Backtick */ +body[data-theme="dark"] .highlight .sc { color: #ED9D13 } /* Literal.String.Char */ +body[data-theme="dark"] .highlight .dl { color: #ED9D13 } /* Literal.String.Delimiter */ +body[data-theme="dark"] .highlight .sd { color: #ED9D13 } /* Literal.String.Doc */ +body[data-theme="dark"] .highlight .s2 { color: #ED9D13 } /* Literal.String.Double */ +body[data-theme="dark"] .highlight .se { color: #ED9D13 } /* Literal.String.Escape */ +body[data-theme="dark"] .highlight .sh { color: #ED9D13 } /* Literal.String.Heredoc */ +body[data-theme="dark"] .highlight .si { color: #ED9D13 } /* Literal.String.Interpol */ +body[data-theme="dark"] .highlight .sx { color: #FFA500 } /* Literal.String.Other */ +body[data-theme="dark"] .highlight .sr { color: #ED9D13 } /* Literal.String.Regex */ +body[data-theme="dark"] .highlight .s1 { color: #ED9D13 } /* Literal.String.Single */ +body[data-theme="dark"] .highlight .ss { color: #ED9D13 } /* Literal.String.Symbol */ +body[data-theme="dark"] .highlight .bp { color: #2FBCCD } /* Name.Builtin.Pseudo */ +body[data-theme="dark"] .highlight .fm { color: #71ADFF } /* Name.Function.Magic */ +body[data-theme="dark"] .highlight .vc { color: #40FFFF } /* Name.Variable.Class */ +body[data-theme="dark"] .highlight .vg { color: #40FFFF } /* Name.Variable.Global */ +body[data-theme="dark"] .highlight .vi { color: #40FFFF } /* Name.Variable.Instance */ +body[data-theme="dark"] .highlight .vm { color: #40FFFF } /* Name.Variable.Magic */ +body[data-theme="dark"] .highlight .il { color: #51B2FD } /* Literal.Number.Integer.Long */ +@media (prefers-color-scheme: dark) { +body:not([data-theme="light"]) .highlight pre { line-height: 125%; } +body:not([data-theme="light"]) .highlight td.linenos .normal { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight span.linenos { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight .hll { background-color: #404040 } +body:not([data-theme="light"]) .highlight { background: #202020; color: #D0D0D0 } +body:not([data-theme="light"]) .highlight .c { color: #ABABAB; font-style: italic } /* Comment */ +body:not([data-theme="light"]) .highlight .err { color: #A61717; background-color: #E3D2D2 } /* Error */ +body:not([data-theme="light"]) .highlight .esc { color: #D0D0D0 } /* Escape */ +body:not([data-theme="light"]) .highlight .g { color: #D0D0D0 } /* Generic */ +body:not([data-theme="light"]) .highlight .k { color: #6EBF26; font-weight: bold } /* Keyword */ +body:not([data-theme="light"]) .highlight .l { color: #D0D0D0 } /* Literal */ +body:not([data-theme="light"]) .highlight .n { color: #D0D0D0 } /* Name */ +body:not([data-theme="light"]) .highlight .o { color: #D0D0D0 } /* Operator */ +body:not([data-theme="light"]) .highlight .x { color: #D0D0D0 } /* Other */ +body:not([data-theme="light"]) .highlight .p { color: #D0D0D0 } /* Punctuation */ +body:not([data-theme="light"]) .highlight .ch { color: #ABABAB; font-style: italic } /* Comment.Hashbang */ +body:not([data-theme="light"]) .highlight .cm { color: #ABABAB; font-style: italic } /* Comment.Multiline */ +body:not([data-theme="light"]) .highlight .cp { color: #FF3A3A; font-weight: bold } /* Comment.Preproc */ +body:not([data-theme="light"]) .highlight .cpf { color: #ABABAB; font-style: italic } /* Comment.PreprocFile */ +body:not([data-theme="light"]) .highlight .c1 { color: #ABABAB; font-style: italic } /* Comment.Single */ +body:not([data-theme="light"]) .highlight .cs { color: #E50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +body:not([data-theme="light"]) .highlight .gd { color: #FF3A3A } /* Generic.Deleted */ +body:not([data-theme="light"]) .highlight .ge { color: #D0D0D0; font-style: italic } /* Generic.Emph */ +body:not([data-theme="light"]) .highlight .ges { color: #D0D0D0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +body:not([data-theme="light"]) .highlight .gr { color: #FF3A3A } /* Generic.Error */ +body:not([data-theme="light"]) .highlight .gh { color: #FFF; font-weight: bold } /* Generic.Heading */ +body:not([data-theme="light"]) .highlight .gi { color: #589819 } /* Generic.Inserted */ +body:not([data-theme="light"]) .highlight .go { color: #CCC } /* Generic.Output */ +body:not([data-theme="light"]) .highlight .gp { color: #AAA } /* Generic.Prompt */ +body:not([data-theme="light"]) .highlight .gs { color: #D0D0D0; font-weight: bold } /* Generic.Strong */ +body:not([data-theme="light"]) .highlight .gu { color: #FFF; text-decoration: underline } /* Generic.Subheading */ +body:not([data-theme="light"]) .highlight .gt { color: #FF3A3A } /* Generic.Traceback */ +body:not([data-theme="light"]) .highlight .kc { color: #6EBF26; font-weight: bold } /* Keyword.Constant */ +body:not([data-theme="light"]) .highlight .kd { color: #6EBF26; font-weight: bold } /* Keyword.Declaration */ +body:not([data-theme="light"]) .highlight .kn { color: #6EBF26; font-weight: bold } /* Keyword.Namespace */ +body:not([data-theme="light"]) .highlight .kp { color: #6EBF26 } /* Keyword.Pseudo */ +body:not([data-theme="light"]) .highlight .kr { color: #6EBF26; font-weight: bold } /* Keyword.Reserved */ +body:not([data-theme="light"]) .highlight .kt { color: #6EBF26; font-weight: bold } /* Keyword.Type */ +body:not([data-theme="light"]) .highlight .ld { color: #D0D0D0 } /* Literal.Date */ +body:not([data-theme="light"]) .highlight .m { color: #51B2FD } /* Literal.Number */ +body:not([data-theme="light"]) .highlight .s { color: #ED9D13 } /* Literal.String */ +body:not([data-theme="light"]) .highlight .na { color: #BBB } /* Name.Attribute */ +body:not([data-theme="light"]) .highlight .nb { color: #2FBCCD } /* Name.Builtin */ +body:not([data-theme="light"]) .highlight .nc { color: #71ADFF; text-decoration: underline } /* Name.Class */ +body:not([data-theme="light"]) .highlight .no { color: #40FFFF } /* Name.Constant */ +body:not([data-theme="light"]) .highlight .nd { color: #FFA500 } /* Name.Decorator */ +body:not([data-theme="light"]) .highlight .ni { color: #D0D0D0 } /* Name.Entity */ +body:not([data-theme="light"]) .highlight .ne { color: #BBB } /* Name.Exception */ +body:not([data-theme="light"]) .highlight .nf { color: #71ADFF } /* Name.Function */ +body:not([data-theme="light"]) .highlight .nl { color: #D0D0D0 } /* Name.Label */ +body:not([data-theme="light"]) .highlight .nn { color: #71ADFF; text-decoration: underline } /* Name.Namespace */ +body:not([data-theme="light"]) .highlight .nx { color: #D0D0D0 } /* Name.Other */ +body:not([data-theme="light"]) .highlight .py { color: #D0D0D0 } /* Name.Property */ +body:not([data-theme="light"]) .highlight .nt { color: #6EBF26; font-weight: bold } /* Name.Tag */ +body:not([data-theme="light"]) .highlight .nv { color: #40FFFF } /* Name.Variable */ +body:not([data-theme="light"]) .highlight .ow { color: #6EBF26; font-weight: bold } /* Operator.Word */ +body:not([data-theme="light"]) .highlight .pm { color: #D0D0D0 } /* Punctuation.Marker */ +body:not([data-theme="light"]) .highlight .w { color: #666 } /* Text.Whitespace */ +body:not([data-theme="light"]) .highlight .mb { color: #51B2FD } /* Literal.Number.Bin */ +body:not([data-theme="light"]) .highlight .mf { color: #51B2FD } /* Literal.Number.Float */ +body:not([data-theme="light"]) .highlight .mh { color: #51B2FD } /* Literal.Number.Hex */ +body:not([data-theme="light"]) .highlight .mi { color: #51B2FD } /* Literal.Number.Integer */ +body:not([data-theme="light"]) .highlight .mo { color: #51B2FD } /* Literal.Number.Oct */ +body:not([data-theme="light"]) .highlight .sa { color: #ED9D13 } /* Literal.String.Affix */ +body:not([data-theme="light"]) .highlight .sb { color: #ED9D13 } /* Literal.String.Backtick */ +body:not([data-theme="light"]) .highlight .sc { color: #ED9D13 } /* Literal.String.Char */ +body:not([data-theme="light"]) .highlight .dl { color: #ED9D13 } /* Literal.String.Delimiter */ +body:not([data-theme="light"]) .highlight .sd { color: #ED9D13 } /* Literal.String.Doc */ +body:not([data-theme="light"]) .highlight .s2 { color: #ED9D13 } /* Literal.String.Double */ +body:not([data-theme="light"]) .highlight .se { color: #ED9D13 } /* Literal.String.Escape */ +body:not([data-theme="light"]) .highlight .sh { color: #ED9D13 } /* Literal.String.Heredoc */ +body:not([data-theme="light"]) .highlight .si { color: #ED9D13 } /* Literal.String.Interpol */ +body:not([data-theme="light"]) .highlight .sx { color: #FFA500 } /* Literal.String.Other */ +body:not([data-theme="light"]) .highlight .sr { color: #ED9D13 } /* Literal.String.Regex */ +body:not([data-theme="light"]) .highlight .s1 { color: #ED9D13 } /* Literal.String.Single */ +body:not([data-theme="light"]) .highlight .ss { color: #ED9D13 } /* Literal.String.Symbol */ +body:not([data-theme="light"]) .highlight .bp { color: #2FBCCD } /* Name.Builtin.Pseudo */ +body:not([data-theme="light"]) .highlight .fm { color: #71ADFF } /* Name.Function.Magic */ +body:not([data-theme="light"]) .highlight .vc { color: #40FFFF } /* Name.Variable.Class */ +body:not([data-theme="light"]) .highlight .vg { color: #40FFFF } /* Name.Variable.Global */ +body:not([data-theme="light"]) .highlight .vi { color: #40FFFF } /* Name.Variable.Instance */ +body:not([data-theme="light"]) .highlight .vm { color: #40FFFF } /* Name.Variable.Magic */ +body:not([data-theme="light"]) .highlight .il { color: #51B2FD } /* Literal.Number.Integer.Long */ +} +} \ No newline at end of file diff --git a/releases/2.0.0/_static/scripts/furo-extensions.js b/releases/2.0.0/_static/scripts/furo-extensions.js new file mode 100644 index 0000000..e69de29 diff --git a/releases/2.0.0/_static/scripts/furo.js b/releases/2.0.0/_static/scripts/furo.js new file mode 100644 index 0000000..0abb2af --- /dev/null +++ b/releases/2.0.0/_static/scripts/furo.js @@ -0,0 +1,3 @@ +/*! For license information please see furo.js.LICENSE.txt */ +(()=>{var t={856:function(t,e,n){var o,r;r=void 0!==n.g?n.g:"undefined"!=typeof window?window:this,o=function(){return function(t){"use strict";var e={navClass:"active",contentClass:"active",nested:!1,nestedClass:"active",offset:0,reflow:!1,events:!0},n=function(t,e,n){if(n.settings.events){var o=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n});e.dispatchEvent(o)}},o=function(t){var e=0;if(t.offsetParent)for(;t;)e+=t.offsetTop,t=t.offsetParent;return e>=0?e:0},r=function(t){t&&t.sort((function(t,e){return o(t.content)=Math.max(document.body.scrollHeight,document.documentElement.scrollHeight,document.body.offsetHeight,document.documentElement.offsetHeight,document.body.clientHeight,document.documentElement.clientHeight)},l=function(t,e){var n=t[t.length-1];if(function(t,e){return!(!s()||!c(t.content,e,!0))}(n,e))return n;for(var o=t.length-1;o>=0;o--)if(c(t[o].content,e))return t[o]},a=function(t,e){if(e.nested&&t.parentNode){var n=t.parentNode.closest("li");n&&(n.classList.remove(e.nestedClass),a(n,e))}},i=function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.remove(e.navClass),t.content.classList.remove(e.contentClass),a(o,e),n("gumshoeDeactivate",o,{link:t.nav,content:t.content,settings:e}))}},u=function(t,e){if(e.nested){var n=t.parentNode.closest("li");n&&(n.classList.add(e.nestedClass),u(n,e))}};return function(o,c){var s,a,d,f,m,v={setup:function(){s=document.querySelectorAll(o),a=[],Array.prototype.forEach.call(s,(function(t){var e=document.getElementById(decodeURIComponent(t.hash.substr(1)));e&&a.push({nav:t,content:e})})),r(a)},detect:function(){var t=l(a,m);t?d&&t.content===d.content||(i(d,m),function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.add(e.navClass),t.content.classList.add(e.contentClass),u(o,e),n("gumshoeActivate",o,{link:t.nav,content:t.content,settings:e}))}}(t,m),d=t):d&&(i(d,m),d=null)}},h=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame(v.detect)},g=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame((function(){r(a),v.detect()}))};return v.destroy=function(){d&&i(d,m),t.removeEventListener("scroll",h,!1),m.reflow&&t.removeEventListener("resize",g,!1),a=null,s=null,d=null,f=null,m=null},m=function(){var t={};return Array.prototype.forEach.call(arguments,(function(e){for(var n in e){if(!e.hasOwnProperty(n))return;t[n]=e[n]}})),t}(e,c||{}),v.setup(),v.detect(),t.addEventListener("scroll",h,!1),m.reflow&&t.addEventListener("resize",g,!1),v}}(r)}.apply(e,[]),void 0===o||(t.exports=o)}},e={};function n(o){var r=e[o];if(void 0!==r)return r.exports;var c=e[o]={exports:{}};return t[o].call(c.exports,c,c.exports,n),c.exports}n.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return n.d(e,{a:e}),e},n.d=(t,e)=>{for(var o in e)n.o(e,o)&&!n.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),(()=>{"use strict";var t=n(856),e=n.n(t),o=null,r=null,c=document.documentElement.scrollTop;const s=64;function l(){const t=localStorage.getItem("theme")||"auto";var e;"light"!==(e=window.matchMedia("(prefers-color-scheme: dark)").matches?"auto"===t?"light":"light"==t?"dark":"auto":"auto"===t?"dark":"dark"==t?"light":"auto")&&"dark"!==e&&"auto"!==e&&(console.error(`Got invalid theme mode: ${e}. Resetting to auto.`),e="auto"),document.body.dataset.theme=e,localStorage.setItem("theme",e),console.log(`Changed to ${e} mode.`)}function a(){!function(){const t=document.getElementsByClassName("theme-toggle");Array.from(t).forEach((t=>{t.addEventListener("click",l)}))}(),function(){let t=0,e=!1;window.addEventListener("scroll",(function(n){t=window.scrollY,e||(window.requestAnimationFrame((function(){var n;(function(t){const e=Math.floor(r.getBoundingClientRect().top);console.log(`headerTop: ${e}`),0==e&&t!=e?r.classList.add("scrolled"):r.classList.remove("scrolled")})(n=t),function(t){tc&&document.documentElement.classList.remove("show-back-to-top"),c=t}(n),function(t){null!==o&&(0==t?o.scrollTo(0,0):Math.ceil(t)>=Math.floor(document.documentElement.scrollHeight-window.innerHeight)?o.scrollTo(0,o.scrollHeight):document.querySelector(".scroll-current"))}(n),e=!1})),e=!0)})),window.scroll()}(),null!==o&&new(e())(".toc-tree a",{reflow:!0,recursive:!0,navClass:"scroll-current",offset:()=>{let t=parseFloat(getComputedStyle(document.documentElement).fontSize);return r.getBoundingClientRect().height+2.5*t+1}})}document.addEventListener("DOMContentLoaded",(function(){document.body.parentNode.classList.remove("no-js"),r=document.querySelector("header"),o=document.querySelector(".toc-scroll"),a()}))})()})(); +//# sourceMappingURL=furo.js.map \ No newline at end of file diff --git a/releases/2.0.0/_static/scripts/furo.js.LICENSE.txt b/releases/2.0.0/_static/scripts/furo.js.LICENSE.txt new file mode 100644 index 0000000..1632189 --- /dev/null +++ b/releases/2.0.0/_static/scripts/furo.js.LICENSE.txt @@ -0,0 +1,7 @@ +/*! + * gumshoejs v5.1.2 (patched by @pradyunsg) + * A simple, framework-agnostic scrollspy script. + * (c) 2019 Chris Ferdinandi + * MIT License + * http://github.com/cferdinandi/gumshoe + */ diff --git a/releases/2.0.0/_static/scripts/furo.js.map b/releases/2.0.0/_static/scripts/furo.js.map new file mode 100644 index 0000000..80ea12b --- /dev/null +++ b/releases/2.0.0/_static/scripts/furo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"scripts/furo.js","mappings":";iCAAA,MAQWA,SAWS,IAAX,EAAAC,EACH,EAAAA,EACkB,oBAAXC,OACLA,OACAC,KAbO,EAAF,WACP,OAaJ,SAAUD,GACR,aAMA,IAAIE,EAAW,CAEbC,SAAU,SACVC,aAAc,SAGdC,QAAQ,EACRC,YAAa,SAGbC,OAAQ,EACRC,QAAQ,EAGRC,QAAQ,GA6BNC,EAAY,SAAUC,EAAMC,EAAMC,GAEpC,GAAKA,EAAOC,SAASL,OAArB,CAGA,IAAIM,EAAQ,IAAIC,YAAYL,EAAM,CAChCM,SAAS,EACTC,YAAY,EACZL,OAAQA,IAIVD,EAAKO,cAAcJ,EAVgB,CAWrC,EAOIK,EAAe,SAAUR,GAC3B,IAAIS,EAAW,EACf,GAAIT,EAAKU,aACP,KAAOV,GACLS,GAAYT,EAAKW,UACjBX,EAAOA,EAAKU,aAGhB,OAAOD,GAAY,EAAIA,EAAW,CACpC,EAMIG,EAAe,SAAUC,GACvBA,GACFA,EAASC,MAAK,SAAUC,EAAOC,GAG7B,OAFcR,EAAaO,EAAME,SACnBT,EAAaQ,EAAMC,UACF,EACxB,CACT,GAEJ,EAwCIC,EAAW,SAAUlB,EAAME,EAAUiB,GACvC,IAAIC,EAASpB,EAAKqB,wBACd1B,EAnCU,SAAUO,GAExB,MAA+B,mBAApBA,EAASP,OACX2B,WAAWpB,EAASP,UAItB2B,WAAWpB,EAASP,OAC7B,CA2Be4B,CAAUrB,GACvB,OAAIiB,EAEAK,SAASJ,EAAOD,OAAQ,KACvB/B,EAAOqC,aAAeC,SAASC,gBAAgBC,cAG7CJ,SAASJ,EAAOS,IAAK,KAAOlC,CACrC,EAMImC,EAAa,WACf,OACEC,KAAKC,KAAK5C,EAAOqC,YAAcrC,EAAO6C,cAnCjCF,KAAKG,IACVR,SAASS,KAAKC,aACdV,SAASC,gBAAgBS,aACzBV,SAASS,KAAKE,aACdX,SAASC,gBAAgBU,aACzBX,SAASS,KAAKP,aACdF,SAASC,gBAAgBC,aAkC7B,EAmBIU,EAAY,SAAUzB,EAAUX,GAClC,IAAIqC,EAAO1B,EAASA,EAAS2B,OAAS,GACtC,GAbgB,SAAUC,EAAMvC,GAChC,SAAI4B,MAAgBZ,EAASuB,EAAKxB,QAASf,GAAU,GAEvD,CAUMwC,CAAYH,EAAMrC,GAAW,OAAOqC,EACxC,IAAK,IAAII,EAAI9B,EAAS2B,OAAS,EAAGG,GAAK,EAAGA,IACxC,GAAIzB,EAASL,EAAS8B,GAAG1B,QAASf,GAAW,OAAOW,EAAS8B,EAEjE,EAOIC,EAAmB,SAAUC,EAAK3C,GAEpC,GAAKA,EAAST,QAAWoD,EAAIC,WAA7B,CAGA,IAAIC,EAAKF,EAAIC,WAAWE,QAAQ,MAC3BD,IAGLA,EAAGE,UAAUC,OAAOhD,EAASR,aAG7BkD,EAAiBG,EAAI7C,GAV0B,CAWjD,EAOIiD,EAAa,SAAUC,EAAOlD,GAEhC,GAAKkD,EAAL,CAGA,IAAIL,EAAKK,EAAMP,IAAIG,QAAQ,MACtBD,IAGLA,EAAGE,UAAUC,OAAOhD,EAASX,UAC7B6D,EAAMnC,QAAQgC,UAAUC,OAAOhD,EAASV,cAGxCoD,EAAiBG,EAAI7C,GAGrBJ,EAAU,oBAAqBiD,EAAI,CACjCM,KAAMD,EAAMP,IACZ5B,QAASmC,EAAMnC,QACff,SAAUA,IAjBM,CAmBpB,EAOIoD,EAAiB,SAAUT,EAAK3C,GAElC,GAAKA,EAAST,OAAd,CAGA,IAAIsD,EAAKF,EAAIC,WAAWE,QAAQ,MAC3BD,IAGLA,EAAGE,UAAUM,IAAIrD,EAASR,aAG1B4D,EAAeP,EAAI7C,GAVS,CAW9B,EA6LA,OA1JkB,SAAUsD,EAAUC,GAKpC,IACIC,EAAU7C,EAAU8C,EAASC,EAAS1D,EADtC2D,EAAa,CAUjBA,MAAmB,WAEjBH,EAAWhC,SAASoC,iBAAiBN,GAGrC3C,EAAW,GAGXkD,MAAMC,UAAUC,QAAQC,KAAKR,GAAU,SAAUjB,GAE/C,IAAIxB,EAAUS,SAASyC,eACrBC,mBAAmB3B,EAAK4B,KAAKC,OAAO,KAEjCrD,GAGLJ,EAAS0D,KAAK,CACZ1B,IAAKJ,EACLxB,QAASA,GAEb,IAGAL,EAAaC,EACf,EAKAgD,OAAoB,WAElB,IAAIW,EAASlC,EAAUzB,EAAUX,GAG5BsE,EASDb,GAAWa,EAAOvD,UAAY0C,EAAQ1C,UAG1CkC,EAAWQ,EAASzD,GAzFT,SAAUkD,EAAOlD,GAE9B,GAAKkD,EAAL,CAGA,IAAIL,EAAKK,EAAMP,IAAIG,QAAQ,MACtBD,IAGLA,EAAGE,UAAUM,IAAIrD,EAASX,UAC1B6D,EAAMnC,QAAQgC,UAAUM,IAAIrD,EAASV,cAGrC8D,EAAeP,EAAI7C,GAGnBJ,EAAU,kBAAmBiD,EAAI,CAC/BM,KAAMD,EAAMP,IACZ5B,QAASmC,EAAMnC,QACff,SAAUA,IAjBM,CAmBpB,CAqEIuE,CAASD,EAAQtE,GAGjByD,EAAUa,GAfJb,IACFR,EAAWQ,EAASzD,GACpByD,EAAU,KAchB,GAMIe,EAAgB,SAAUvE,GAExByD,GACFxE,EAAOuF,qBAAqBf,GAI9BA,EAAUxE,EAAOwF,sBAAsBf,EAAWgB,OACpD,EAMIC,EAAgB,SAAU3E,GAExByD,GACFxE,EAAOuF,qBAAqBf,GAI9BA,EAAUxE,EAAOwF,uBAAsB,WACrChE,EAAaC,GACbgD,EAAWgB,QACb,GACF,EAkDA,OA7CAhB,EAAWkB,QAAU,WAEfpB,GACFR,EAAWQ,EAASzD,GAItBd,EAAO4F,oBAAoB,SAAUN,GAAe,GAChDxE,EAASN,QACXR,EAAO4F,oBAAoB,SAAUF,GAAe,GAItDjE,EAAW,KACX6C,EAAW,KACXC,EAAU,KACVC,EAAU,KACV1D,EAAW,IACb,EAOEA,EA3XS,WACX,IAAI+E,EAAS,CAAC,EAOd,OANAlB,MAAMC,UAAUC,QAAQC,KAAKgB,WAAW,SAAUC,GAChD,IAAK,IAAIC,KAAOD,EAAK,CACnB,IAAKA,EAAIE,eAAeD,GAAM,OAC9BH,EAAOG,GAAOD,EAAIC,EACpB,CACF,IACOH,CACT,CAkXeK,CAAOhG,EAAUmE,GAAW,CAAC,GAGxCI,EAAW0B,QAGX1B,EAAWgB,SAGXzF,EAAOoG,iBAAiB,SAAUd,GAAe,GAC7CxE,EAASN,QACXR,EAAOoG,iBAAiB,SAAUV,GAAe,GAS9CjB,CACT,CAOF,CArcW4B,CAAQvG,EAChB,UAFM,SAEN,uBCXDwG,EAA2B,CAAC,EAGhC,SAASC,EAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqBE,IAAjBD,EACH,OAAOA,EAAaE,QAGrB,IAAIC,EAASN,EAAyBE,GAAY,CAGjDG,QAAS,CAAC,GAOX,OAHAE,EAAoBL,GAAU1B,KAAK8B,EAAOD,QAASC,EAAQA,EAAOD,QAASJ,GAGpEK,EAAOD,OACf,CCrBAJ,EAAoBO,EAAKF,IACxB,IAAIG,EAASH,GAAUA,EAAOI,WAC7B,IAAOJ,EAAiB,QACxB,IAAM,EAEP,OADAL,EAAoBU,EAAEF,EAAQ,CAAEG,EAAGH,IAC5BA,CAAM,ECLdR,EAAoBU,EAAI,CAACN,EAASQ,KACjC,IAAI,IAAInB,KAAOmB,EACXZ,EAAoBa,EAAED,EAAYnB,KAASO,EAAoBa,EAAET,EAASX,IAC5EqB,OAAOC,eAAeX,EAASX,EAAK,CAAEuB,YAAY,EAAMC,IAAKL,EAAWnB,IAE1E,ECNDO,EAAoBxG,EAAI,WACvB,GAA0B,iBAAf0H,WAAyB,OAAOA,WAC3C,IACC,OAAOxH,MAAQ,IAAIyH,SAAS,cAAb,EAChB,CAAE,MAAOC,GACR,GAAsB,iBAAX3H,OAAqB,OAAOA,MACxC,CACA,CAPuB,GCAxBuG,EAAoBa,EAAI,CAACrB,EAAK6B,IAAUP,OAAOzC,UAAUqB,eAAenB,KAAKiB,EAAK6B,4CCK9EC,EAAY,KACZC,EAAS,KACTC,EAAgBzF,SAASC,gBAAgByF,UAC7C,MAAMC,EAAmB,GA8EzB,SAASC,IACP,MAAMC,EAAeC,aAAaC,QAAQ,UAAY,OAZxD,IAAkBC,EACH,WADGA,EAaItI,OAAOuI,WAAW,gCAAgCC,QAI/C,SAAjBL,EACO,QACgB,SAAhBA,EACA,OAEA,OAIU,SAAjBA,EACO,OACgB,QAAhBA,EACA,QAEA,SA9BoB,SAATG,GAA4B,SAATA,IACzCG,QAAQC,MAAM,2BAA2BJ,yBACzCA,EAAO,QAGThG,SAASS,KAAK4F,QAAQC,MAAQN,EAC9BF,aAAaS,QAAQ,QAASP,GAC9BG,QAAQK,IAAI,cAAcR,UA0B5B,CAkDA,SAASnC,KART,WAEE,MAAM4C,EAAUzG,SAAS0G,uBAAuB,gBAChDrE,MAAMsE,KAAKF,GAASlE,SAASqE,IAC3BA,EAAI9C,iBAAiB,QAAS8B,EAAe,GAEjD,CAGEiB,GA9CF,WAEE,IAAIC,EAA6B,EAC7BC,GAAU,EAEdrJ,OAAOoG,iBAAiB,UAAU,SAAUuB,GAC1CyB,EAA6BpJ,OAAOsJ,QAE/BD,IACHrJ,OAAOwF,uBAAsB,WAzDnC,IAAuB+D,GAxDvB,SAAgCA,GAC9B,MAAMC,EAAY7G,KAAK8G,MAAM3B,EAAO7F,wBAAwBQ,KAE5DgG,QAAQK,IAAI,cAAcU,KACT,GAAbA,GAAkBD,GAAaC,EACjC1B,EAAOjE,UAAUM,IAAI,YAErB2D,EAAOjE,UAAUC,OAAO,WAE5B,EAgDE4F,CADqBH,EA0DDH,GAvGtB,SAAmCG,GAC7BA,EAAYtB,EACd3F,SAASC,gBAAgBsB,UAAUC,OAAO,oBAEtCyF,EAAYxB,EACdzF,SAASC,gBAAgBsB,UAAUM,IAAI,oBAC9BoF,EAAYxB,GACrBzF,SAASC,gBAAgBsB,UAAUC,OAAO,oBAG9CiE,EAAgBwB,CAClB,CAoCEI,CAA0BJ,GAlC5B,SAA6BA,GACT,OAAd1B,IAKa,GAAb0B,EACF1B,EAAU+B,SAAS,EAAG,GAGtBjH,KAAKC,KAAK2G,IACV5G,KAAK8G,MAAMnH,SAASC,gBAAgBS,aAAehD,OAAOqC,aAE1DwF,EAAU+B,SAAS,EAAG/B,EAAU7E,cAGhBV,SAASuH,cAAc,mBAc3C,CAKEC,CAAoBP,GAwDdF,GAAU,CACZ,IAEAA,GAAU,EAEd,IACArJ,OAAO+J,QACT,CA6BEC,GA1BkB,OAAdnC,GAKJ,IAAI,IAAJ,CAAY,cAAe,CACzBrH,QAAQ,EACRyJ,WAAW,EACX9J,SAAU,iBACVI,OAAQ,KACN,IAAI2J,EAAMhI,WAAWiI,iBAAiB7H,SAASC,iBAAiB6H,UAChE,OAAOtC,EAAO7F,wBAAwBoI,OAAS,IAAMH,EAAM,CAAC,GAiBlE,CAcA5H,SAAS8D,iBAAiB,oBAT1B,WACE9D,SAASS,KAAKW,WAAWG,UAAUC,OAAO,SAE1CgE,EAASxF,SAASuH,cAAc,UAChChC,EAAYvF,SAASuH,cAAc,eAEnC1D,GACF","sources":["webpack:///./src/furo/assets/scripts/gumshoe-patched.js","webpack:///webpack/bootstrap","webpack:///webpack/runtime/compat get default export","webpack:///webpack/runtime/define property getters","webpack:///webpack/runtime/global","webpack:///webpack/runtime/hasOwnProperty shorthand","webpack:///./src/furo/assets/scripts/furo.js"],"sourcesContent":["/*!\n * gumshoejs v5.1.2 (patched by @pradyunsg)\n * A simple, framework-agnostic scrollspy script.\n * (c) 2019 Chris Ferdinandi\n * MIT License\n * http://github.com/cferdinandi/gumshoe\n */\n\n(function (root, factory) {\n if (typeof define === \"function\" && define.amd) {\n define([], function () {\n return factory(root);\n });\n } else if (typeof exports === \"object\") {\n module.exports = factory(root);\n } else {\n root.Gumshoe = factory(root);\n }\n})(\n typeof global !== \"undefined\"\n ? global\n : typeof window !== \"undefined\"\n ? window\n : this,\n function (window) {\n \"use strict\";\n\n //\n // Defaults\n //\n\n var defaults = {\n // Active classes\n navClass: \"active\",\n contentClass: \"active\",\n\n // Nested navigation\n nested: false,\n nestedClass: \"active\",\n\n // Offset & reflow\n offset: 0,\n reflow: false,\n\n // Event support\n events: true,\n };\n\n //\n // Methods\n //\n\n /**\n * Merge two or more objects together.\n * @param {Object} objects The objects to merge together\n * @returns {Object} Merged values of defaults and options\n */\n var extend = function () {\n var merged = {};\n Array.prototype.forEach.call(arguments, function (obj) {\n for (var key in obj) {\n if (!obj.hasOwnProperty(key)) return;\n merged[key] = obj[key];\n }\n });\n return merged;\n };\n\n /**\n * Emit a custom event\n * @param {String} type The event type\n * @param {Node} elem The element to attach the event to\n * @param {Object} detail Any details to pass along with the event\n */\n var emitEvent = function (type, elem, detail) {\n // Make sure events are enabled\n if (!detail.settings.events) return;\n\n // Create a new event\n var event = new CustomEvent(type, {\n bubbles: true,\n cancelable: true,\n detail: detail,\n });\n\n // Dispatch the event\n elem.dispatchEvent(event);\n };\n\n /**\n * Get an element's distance from the top of the Document.\n * @param {Node} elem The element\n * @return {Number} Distance from the top in pixels\n */\n var getOffsetTop = function (elem) {\n var location = 0;\n if (elem.offsetParent) {\n while (elem) {\n location += elem.offsetTop;\n elem = elem.offsetParent;\n }\n }\n return location >= 0 ? location : 0;\n };\n\n /**\n * Sort content from first to last in the DOM\n * @param {Array} contents The content areas\n */\n var sortContents = function (contents) {\n if (contents) {\n contents.sort(function (item1, item2) {\n var offset1 = getOffsetTop(item1.content);\n var offset2 = getOffsetTop(item2.content);\n if (offset1 < offset2) return -1;\n return 1;\n });\n }\n };\n\n /**\n * Get the offset to use for calculating position\n * @param {Object} settings The settings for this instantiation\n * @return {Float} The number of pixels to offset the calculations\n */\n var getOffset = function (settings) {\n // if the offset is a function run it\n if (typeof settings.offset === \"function\") {\n return parseFloat(settings.offset());\n }\n\n // Otherwise, return it as-is\n return parseFloat(settings.offset);\n };\n\n /**\n * Get the document element's height\n * @private\n * @returns {Number}\n */\n var getDocumentHeight = function () {\n return Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight,\n document.body.offsetHeight,\n document.documentElement.offsetHeight,\n document.body.clientHeight,\n document.documentElement.clientHeight,\n );\n };\n\n /**\n * Determine if an element is in view\n * @param {Node} elem The element\n * @param {Object} settings The settings for this instantiation\n * @param {Boolean} bottom If true, check if element is above bottom of viewport instead\n * @return {Boolean} Returns true if element is in the viewport\n */\n var isInView = function (elem, settings, bottom) {\n var bounds = elem.getBoundingClientRect();\n var offset = getOffset(settings);\n if (bottom) {\n return (\n parseInt(bounds.bottom, 10) <\n (window.innerHeight || document.documentElement.clientHeight)\n );\n }\n return parseInt(bounds.top, 10) <= offset;\n };\n\n /**\n * Check if at the bottom of the viewport\n * @return {Boolean} If true, page is at the bottom of the viewport\n */\n var isAtBottom = function () {\n if (\n Math.ceil(window.innerHeight + window.pageYOffset) >=\n getDocumentHeight()\n )\n return true;\n return false;\n };\n\n /**\n * Check if the last item should be used (even if not at the top of the page)\n * @param {Object} item The last item\n * @param {Object} settings The settings for this instantiation\n * @return {Boolean} If true, use the last item\n */\n var useLastItem = function (item, settings) {\n if (isAtBottom() && isInView(item.content, settings, true)) return true;\n return false;\n };\n\n /**\n * Get the active content\n * @param {Array} contents The content areas\n * @param {Object} settings The settings for this instantiation\n * @return {Object} The content area and matching navigation link\n */\n var getActive = function (contents, settings) {\n var last = contents[contents.length - 1];\n if (useLastItem(last, settings)) return last;\n for (var i = contents.length - 1; i >= 0; i--) {\n if (isInView(contents[i].content, settings)) return contents[i];\n }\n };\n\n /**\n * Deactivate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var deactivateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested || !nav.parentNode) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Remove the active class\n li.classList.remove(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n deactivateNested(li, settings);\n };\n\n /**\n * Deactivate a nav and content area\n * @param {Object} items The nav item and content to deactivate\n * @param {Object} settings The settings for this instantiation\n */\n var deactivate = function (items, settings) {\n // Make sure there are items to deactivate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Remove the active class from the nav and content\n li.classList.remove(settings.navClass);\n items.content.classList.remove(settings.contentClass);\n\n // Deactivate any parent navs in a nested navigation\n deactivateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeDeactivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Activate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var activateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Add the active class\n li.classList.add(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n activateNested(li, settings);\n };\n\n /**\n * Activate a nav and content area\n * @param {Object} items The nav item and content to activate\n * @param {Object} settings The settings for this instantiation\n */\n var activate = function (items, settings) {\n // Make sure there are items to activate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Add the active class to the nav and content\n li.classList.add(settings.navClass);\n items.content.classList.add(settings.contentClass);\n\n // Activate any parent navs in a nested navigation\n activateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeActivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Create the Constructor object\n * @param {String} selector The selector to use for navigation items\n * @param {Object} options User options and settings\n */\n var Constructor = function (selector, options) {\n //\n // Variables\n //\n\n var publicAPIs = {};\n var navItems, contents, current, timeout, settings;\n\n //\n // Methods\n //\n\n /**\n * Set variables from DOM elements\n */\n publicAPIs.setup = function () {\n // Get all nav items\n navItems = document.querySelectorAll(selector);\n\n // Create contents array\n contents = [];\n\n // Loop through each item, get it's matching content, and push to the array\n Array.prototype.forEach.call(navItems, function (item) {\n // Get the content for the nav item\n var content = document.getElementById(\n decodeURIComponent(item.hash.substr(1)),\n );\n if (!content) return;\n\n // Push to the contents array\n contents.push({\n nav: item,\n content: content,\n });\n });\n\n // Sort contents by the order they appear in the DOM\n sortContents(contents);\n };\n\n /**\n * Detect which content is currently active\n */\n publicAPIs.detect = function () {\n // Get the active content\n var active = getActive(contents, settings);\n\n // if there's no active content, deactivate and bail\n if (!active) {\n if (current) {\n deactivate(current, settings);\n current = null;\n }\n return;\n }\n\n // If the active content is the one currently active, do nothing\n if (current && active.content === current.content) return;\n\n // Deactivate the current content and activate the new content\n deactivate(current, settings);\n activate(active, settings);\n\n // Update the currently active content\n current = active;\n };\n\n /**\n * Detect the active content on scroll\n * Debounced for performance\n */\n var scrollHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(publicAPIs.detect);\n };\n\n /**\n * Update content sorting on resize\n * Debounced for performance\n */\n var resizeHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(function () {\n sortContents(contents);\n publicAPIs.detect();\n });\n };\n\n /**\n * Destroy the current instantiation\n */\n publicAPIs.destroy = function () {\n // Undo DOM changes\n if (current) {\n deactivate(current, settings);\n }\n\n // Remove event listeners\n window.removeEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.removeEventListener(\"resize\", resizeHandler, false);\n }\n\n // Reset variables\n contents = null;\n navItems = null;\n current = null;\n timeout = null;\n settings = null;\n };\n\n /**\n * Initialize the current instantiation\n */\n var init = function () {\n // Merge user options into defaults\n settings = extend(defaults, options || {});\n\n // Setup variables based on the current DOM\n publicAPIs.setup();\n\n // Find the currently active content\n publicAPIs.detect();\n\n // Setup event listeners\n window.addEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.addEventListener(\"resize\", resizeHandler, false);\n }\n };\n\n //\n // Initialize and return the public APIs\n //\n\n init();\n return publicAPIs;\n };\n\n //\n // Return the Constructor\n //\n\n return Constructor;\n },\n);\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","import Gumshoe from \"./gumshoe-patched.js\";\n\n////////////////////////////////////////////////////////////////////////////////\n// Scroll Handling\n////////////////////////////////////////////////////////////////////////////////\nvar tocScroll = null;\nvar header = null;\nvar lastScrollTop = document.documentElement.scrollTop;\nconst GO_TO_TOP_OFFSET = 64;\n\nfunction scrollHandlerForHeader(positionY) {\n const headerTop = Math.floor(header.getBoundingClientRect().top);\n\n console.log(`headerTop: ${headerTop}`);\n if (headerTop == 0 && positionY != headerTop) {\n header.classList.add(\"scrolled\");\n } else {\n header.classList.remove(\"scrolled\");\n }\n}\n\nfunction scrollHandlerForBackToTop(positionY) {\n if (positionY < GO_TO_TOP_OFFSET) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n } else {\n if (positionY < lastScrollTop) {\n document.documentElement.classList.add(\"show-back-to-top\");\n } else if (positionY > lastScrollTop) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n }\n }\n lastScrollTop = positionY;\n}\n\nfunction scrollHandlerForTOC(positionY) {\n if (tocScroll === null) {\n return;\n }\n\n // top of page.\n if (positionY == 0) {\n tocScroll.scrollTo(0, 0);\n } else if (\n // bottom of page.\n Math.ceil(positionY) >=\n Math.floor(document.documentElement.scrollHeight - window.innerHeight)\n ) {\n tocScroll.scrollTo(0, tocScroll.scrollHeight);\n } else {\n // somewhere in the middle.\n const current = document.querySelector(\".scroll-current\");\n if (current == null) {\n return;\n }\n\n // https://github.com/pypa/pip/issues/9159 This breaks scroll behaviours.\n // // scroll the currently \"active\" heading in toc, into view.\n // const rect = current.getBoundingClientRect();\n // if (0 > rect.top) {\n // current.scrollIntoView(true); // the argument is \"alignTop\"\n // } else if (rect.bottom > window.innerHeight) {\n // current.scrollIntoView(false);\n // }\n }\n}\n\nfunction scrollHandler(positionY) {\n scrollHandlerForHeader(positionY);\n scrollHandlerForBackToTop(positionY);\n scrollHandlerForTOC(positionY);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Theme Toggle\n////////////////////////////////////////////////////////////////////////////////\nfunction setTheme(mode) {\n if (mode !== \"light\" && mode !== \"dark\" && mode !== \"auto\") {\n console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`);\n mode = \"auto\";\n }\n\n document.body.dataset.theme = mode;\n localStorage.setItem(\"theme\", mode);\n console.log(`Changed to ${mode} mode.`);\n}\n\nfunction cycleThemeOnce() {\n const currentTheme = localStorage.getItem(\"theme\") || \"auto\";\n const prefersDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n\n if (prefersDark) {\n // Auto (dark) -> Light -> Dark\n if (currentTheme === \"auto\") {\n setTheme(\"light\");\n } else if (currentTheme == \"light\") {\n setTheme(\"dark\");\n } else {\n setTheme(\"auto\");\n }\n } else {\n // Auto (light) -> Dark -> Light\n if (currentTheme === \"auto\") {\n setTheme(\"dark\");\n } else if (currentTheme == \"dark\") {\n setTheme(\"light\");\n } else {\n setTheme(\"auto\");\n }\n }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Setup\n////////////////////////////////////////////////////////////////////////////////\nfunction setupScrollHandler() {\n // Taken from https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event\n let last_known_scroll_position = 0;\n let ticking = false;\n\n window.addEventListener(\"scroll\", function (e) {\n last_known_scroll_position = window.scrollY;\n\n if (!ticking) {\n window.requestAnimationFrame(function () {\n scrollHandler(last_known_scroll_position);\n ticking = false;\n });\n\n ticking = true;\n }\n });\n window.scroll();\n}\n\nfunction setupScrollSpy() {\n if (tocScroll === null) {\n return;\n }\n\n // Scrollspy -- highlight table on contents, based on scroll\n new Gumshoe(\".toc-tree a\", {\n reflow: true,\n recursive: true,\n navClass: \"scroll-current\",\n offset: () => {\n let rem = parseFloat(getComputedStyle(document.documentElement).fontSize);\n return header.getBoundingClientRect().height + 2.5 * rem + 1;\n },\n });\n}\n\nfunction setupTheme() {\n // Attach event handlers for toggling themes\n const buttons = document.getElementsByClassName(\"theme-toggle\");\n Array.from(buttons).forEach((btn) => {\n btn.addEventListener(\"click\", cycleThemeOnce);\n });\n}\n\nfunction setup() {\n setupTheme();\n setupScrollHandler();\n setupScrollSpy();\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Main entrypoint\n////////////////////////////////////////////////////////////////////////////////\nfunction main() {\n document.body.parentNode.classList.remove(\"no-js\");\n\n header = document.querySelector(\"header\");\n tocScroll = document.querySelector(\".toc-scroll\");\n\n setup();\n}\n\ndocument.addEventListener(\"DOMContentLoaded\", main);\n"],"names":["root","g","window","this","defaults","navClass","contentClass","nested","nestedClass","offset","reflow","events","emitEvent","type","elem","detail","settings","event","CustomEvent","bubbles","cancelable","dispatchEvent","getOffsetTop","location","offsetParent","offsetTop","sortContents","contents","sort","item1","item2","content","isInView","bottom","bounds","getBoundingClientRect","parseFloat","getOffset","parseInt","innerHeight","document","documentElement","clientHeight","top","isAtBottom","Math","ceil","pageYOffset","max","body","scrollHeight","offsetHeight","getActive","last","length","item","useLastItem","i","deactivateNested","nav","parentNode","li","closest","classList","remove","deactivate","items","link","activateNested","add","selector","options","navItems","current","timeout","publicAPIs","querySelectorAll","Array","prototype","forEach","call","getElementById","decodeURIComponent","hash","substr","push","active","activate","scrollHandler","cancelAnimationFrame","requestAnimationFrame","detect","resizeHandler","destroy","removeEventListener","merged","arguments","obj","key","hasOwnProperty","extend","setup","addEventListener","factory","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","exports","module","__webpack_modules__","n","getter","__esModule","d","a","definition","o","Object","defineProperty","enumerable","get","globalThis","Function","e","prop","tocScroll","header","lastScrollTop","scrollTop","GO_TO_TOP_OFFSET","cycleThemeOnce","currentTheme","localStorage","getItem","mode","matchMedia","matches","console","error","dataset","theme","setItem","log","buttons","getElementsByClassName","from","btn","setupTheme","last_known_scroll_position","ticking","scrollY","positionY","headerTop","floor","scrollHandlerForHeader","scrollHandlerForBackToTop","scrollTo","querySelector","scrollHandlerForTOC","scroll","setupScrollHandler","recursive","rem","getComputedStyle","fontSize","height"],"sourceRoot":""} \ No newline at end of file diff --git a/releases/2.0.0/_static/searchtools.js b/releases/2.0.0/_static/searchtools.js new file mode 100644 index 0000000..2c774d1 --- /dev/null +++ b/releases/2.0.0/_static/searchtools.js @@ -0,0 +1,632 @@ +/* + * Sphinx JavaScript utilities for the full-text search. + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename, kind] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +// Global search result kind enum, used by themes to style search results. +class SearchResultKind { + static get index() { return "index"; } + static get object() { return "object"; } + static get text() { return "text"; } + static get title() { return "title"; } +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename, kind] = item; + + let listItem = document.createElement("li"); + // Add a class representing the item's type: + // can be used by a theme's CSS selector for styling + // See SearchResultKind for the class names. + listItem.classList.add(`kind-${kind}`); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms, anchor) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = Documentation.ngettext( + "Search finished, found one page matching the search query.", + "Search finished, found ${resultCount} pages matching the search query.", + resultCount, + ).replace('${resultCount}', resultCount); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename, kind]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString, anchor) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + for (const removalQuery of [".headerlink", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` + ); + } + + // if anchor not specified or not found, fall back to main content + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent) return docContent.textContent; + + console.warn( + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.setAttribute("role", "list"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + _parseQuery: (query) => { + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename, kind]. + const normalResults = []; + const nonMainIndexResults = []; + + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase().trim(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + const score = Math.round(Scorer.title * queryLower.length / title.length); + const boost = titles[file] === title ? 1 : 0; // add a boost for document titles + normalResults.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score + boost, + filenames[file], + SearchResultKind.title, + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id, isMain] of foundEntries) { + const score = Math.round(100 * queryLower.length / entry.length); + const result = [ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + SearchResultKind.index, + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } + } + } + } + + // lookup as object + objectTerms.forEach((term) => + normalResults.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + return results.reverse(); + }, + + query: (query) => { + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + SearchResultKind.object, + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + SearchResultKind.text, + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/releases/2.0.0/_static/skeleton.css b/releases/2.0.0/_static/skeleton.css new file mode 100644 index 0000000..467c878 --- /dev/null +++ b/releases/2.0.0/_static/skeleton.css @@ -0,0 +1,296 @@ +/* Some sane resets. */ +html { + height: 100%; +} + +body { + margin: 0; + min-height: 100%; +} + +/* All the flexbox magic! */ +body, +.sb-announcement, +.sb-content, +.sb-main, +.sb-container, +.sb-container__inner, +.sb-article-container, +.sb-footer-content, +.sb-header, +.sb-header-secondary, +.sb-footer { + display: flex; +} + +/* These order things vertically */ +body, +.sb-main, +.sb-article-container { + flex-direction: column; +} + +/* Put elements in the center */ +.sb-header, +.sb-header-secondary, +.sb-container, +.sb-content, +.sb-footer, +.sb-footer-content { + justify-content: center; +} +/* Put elements at the ends */ +.sb-article-container { + justify-content: space-between; +} + +/* These elements grow. */ +.sb-main, +.sb-content, +.sb-container, +article { + flex-grow: 1; +} + +/* Because padding making this wider is not fun */ +article { + box-sizing: border-box; +} + +/* The announcements element should never be wider than the page. */ +.sb-announcement { + max-width: 100%; +} + +.sb-sidebar-primary, +.sb-sidebar-secondary { + flex-shrink: 0; + width: 17rem; +} + +.sb-announcement__inner { + justify-content: center; + + box-sizing: border-box; + height: 3rem; + + overflow-x: auto; + white-space: nowrap; +} + +/* Sidebars, with checkbox-based toggle */ +.sb-sidebar-primary, +.sb-sidebar-secondary { + position: fixed; + height: 100%; + top: 0; +} + +.sb-sidebar-primary { + left: -17rem; + transition: left 250ms ease-in-out; +} +.sb-sidebar-secondary { + right: -17rem; + transition: right 250ms ease-in-out; +} + +.sb-sidebar-toggle { + display: none; +} +.sb-sidebar-overlay { + position: fixed; + top: 0; + width: 0; + height: 0; + + transition: width 0ms ease 250ms, height 0ms ease 250ms, opacity 250ms ease; + + opacity: 0; + background-color: rgba(0, 0, 0, 0.54); +} + +#sb-sidebar-toggle--primary:checked + ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--primary"], +#sb-sidebar-toggle--secondary:checked + ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--secondary"] { + width: 100%; + height: 100%; + opacity: 1; + transition: width 0ms ease, height 0ms ease, opacity 250ms ease; +} + +#sb-sidebar-toggle--primary:checked ~ .sb-container .sb-sidebar-primary { + left: 0; +} +#sb-sidebar-toggle--secondary:checked ~ .sb-container .sb-sidebar-secondary { + right: 0; +} + +/* Full-width mode */ +.drop-secondary-sidebar-for-full-width-content + .hide-when-secondary-sidebar-shown { + display: none !important; +} +.drop-secondary-sidebar-for-full-width-content .sb-sidebar-secondary { + display: none !important; +} + +/* Mobile views */ +.sb-page-width { + width: 100%; +} + +.sb-article-container, +.sb-footer-content__inner, +.drop-secondary-sidebar-for-full-width-content .sb-article, +.drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 100vw; +} + +.sb-article, +.match-content-width { + padding: 0 1rem; + box-sizing: border-box; +} + +@media (min-width: 32rem) { + .sb-article, + .match-content-width { + padding: 0 2rem; + } +} + +/* Tablet views */ +@media (min-width: 42rem) { + .sb-article-container { + width: auto; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 42rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} +@media (min-width: 46rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 46rem; + } + .sb-article, + .match-content-width { + width: 46rem; + } +} +@media (min-width: 50rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 50rem; + } + .sb-article, + .match-content-width { + width: 50rem; + } +} + +/* Tablet views */ +@media (min-width: 59rem) { + .sb-sidebar-secondary { + position: static; + } + .hide-when-secondary-sidebar-shown { + display: none !important; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 59rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} +@media (min-width: 63rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 63rem; + } + .sb-article, + .match-content-width { + width: 46rem; + } +} +@media (min-width: 67rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } + .sb-article, + .match-content-width { + width: 50rem; + } +} + +/* Desktop views */ +@media (min-width: 76rem) { + .sb-sidebar-primary { + position: static; + } + .hide-when-primary-sidebar-shown { + display: none !important; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 59rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} + +/* Full desktop views */ +@media (min-width: 80rem) { + .sb-article, + .match-content-width { + width: 46rem; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 63rem; + } +} + +@media (min-width: 84rem) { + .sb-article, + .match-content-width { + width: 50rem; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } +} + +@media (min-width: 88rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } + .sb-page-width { + width: 88rem; + } +} diff --git a/releases/2.0.0/_static/sphinx-design.min.css b/releases/2.0.0/_static/sphinx-design.min.css new file mode 100644 index 0000000..860c36d --- /dev/null +++ b/releases/2.0.0/_static/sphinx-design.min.css @@ -0,0 +1 @@ +.sd-bg-primary{background-color:var(--sd-color-primary) !important}.sd-bg-text-primary{color:var(--sd-color-primary-text) !important}button.sd-bg-primary:focus,button.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}a.sd-bg-primary:focus,a.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}.sd-bg-secondary{background-color:var(--sd-color-secondary) !important}.sd-bg-text-secondary{color:var(--sd-color-secondary-text) !important}button.sd-bg-secondary:focus,button.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}a.sd-bg-secondary:focus,a.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}.sd-bg-success{background-color:var(--sd-color-success) !important}.sd-bg-text-success{color:var(--sd-color-success-text) !important}button.sd-bg-success:focus,button.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}a.sd-bg-success:focus,a.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}.sd-bg-info{background-color:var(--sd-color-info) !important}.sd-bg-text-info{color:var(--sd-color-info-text) !important}button.sd-bg-info:focus,button.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}a.sd-bg-info:focus,a.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}.sd-bg-warning{background-color:var(--sd-color-warning) !important}.sd-bg-text-warning{color:var(--sd-color-warning-text) !important}button.sd-bg-warning:focus,button.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}a.sd-bg-warning:focus,a.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}.sd-bg-danger{background-color:var(--sd-color-danger) !important}.sd-bg-text-danger{color:var(--sd-color-danger-text) !important}button.sd-bg-danger:focus,button.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}a.sd-bg-danger:focus,a.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}.sd-bg-light{background-color:var(--sd-color-light) !important}.sd-bg-text-light{color:var(--sd-color-light-text) !important}button.sd-bg-light:focus,button.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}a.sd-bg-light:focus,a.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}.sd-bg-muted{background-color:var(--sd-color-muted) !important}.sd-bg-text-muted{color:var(--sd-color-muted-text) !important}button.sd-bg-muted:focus,button.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}a.sd-bg-muted:focus,a.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}.sd-bg-dark{background-color:var(--sd-color-dark) !important}.sd-bg-text-dark{color:var(--sd-color-dark-text) !important}button.sd-bg-dark:focus,button.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}a.sd-bg-dark:focus,a.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}.sd-bg-black{background-color:var(--sd-color-black) !important}.sd-bg-text-black{color:var(--sd-color-black-text) !important}button.sd-bg-black:focus,button.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}a.sd-bg-black:focus,a.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}.sd-bg-white{background-color:var(--sd-color-white) !important}.sd-bg-text-white{color:var(--sd-color-white-text) !important}button.sd-bg-white:focus,button.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}a.sd-bg-white:focus,a.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}.sd-text-primary,.sd-text-primary>p{color:var(--sd-color-primary) !important}a.sd-text-primary:focus,a.sd-text-primary:hover{color:var(--sd-color-primary-highlight) !important}.sd-text-secondary,.sd-text-secondary>p{color:var(--sd-color-secondary) !important}a.sd-text-secondary:focus,a.sd-text-secondary:hover{color:var(--sd-color-secondary-highlight) !important}.sd-text-success,.sd-text-success>p{color:var(--sd-color-success) !important}a.sd-text-success:focus,a.sd-text-success:hover{color:var(--sd-color-success-highlight) !important}.sd-text-info,.sd-text-info>p{color:var(--sd-color-info) !important}a.sd-text-info:focus,a.sd-text-info:hover{color:var(--sd-color-info-highlight) !important}.sd-text-warning,.sd-text-warning>p{color:var(--sd-color-warning) !important}a.sd-text-warning:focus,a.sd-text-warning:hover{color:var(--sd-color-warning-highlight) !important}.sd-text-danger,.sd-text-danger>p{color:var(--sd-color-danger) !important}a.sd-text-danger:focus,a.sd-text-danger:hover{color:var(--sd-color-danger-highlight) !important}.sd-text-light,.sd-text-light>p{color:var(--sd-color-light) !important}a.sd-text-light:focus,a.sd-text-light:hover{color:var(--sd-color-light-highlight) !important}.sd-text-muted,.sd-text-muted>p{color:var(--sd-color-muted) !important}a.sd-text-muted:focus,a.sd-text-muted:hover{color:var(--sd-color-muted-highlight) !important}.sd-text-dark,.sd-text-dark>p{color:var(--sd-color-dark) !important}a.sd-text-dark:focus,a.sd-text-dark:hover{color:var(--sd-color-dark-highlight) !important}.sd-text-black,.sd-text-black>p{color:var(--sd-color-black) !important}a.sd-text-black:focus,a.sd-text-black:hover{color:var(--sd-color-black-highlight) !important}.sd-text-white,.sd-text-white>p{color:var(--sd-color-white) !important}a.sd-text-white:focus,a.sd-text-white:hover{color:var(--sd-color-white-highlight) !important}.sd-outline-primary{border-color:var(--sd-color-primary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-primary:focus,a.sd-outline-primary:hover{border-color:var(--sd-color-primary-highlight) !important}.sd-outline-secondary{border-color:var(--sd-color-secondary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-secondary:focus,a.sd-outline-secondary:hover{border-color:var(--sd-color-secondary-highlight) !important}.sd-outline-success{border-color:var(--sd-color-success) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-success:focus,a.sd-outline-success:hover{border-color:var(--sd-color-success-highlight) !important}.sd-outline-info{border-color:var(--sd-color-info) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-info:focus,a.sd-outline-info:hover{border-color:var(--sd-color-info-highlight) !important}.sd-outline-warning{border-color:var(--sd-color-warning) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-warning:focus,a.sd-outline-warning:hover{border-color:var(--sd-color-warning-highlight) !important}.sd-outline-danger{border-color:var(--sd-color-danger) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-danger:focus,a.sd-outline-danger:hover{border-color:var(--sd-color-danger-highlight) !important}.sd-outline-light{border-color:var(--sd-color-light) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-light:focus,a.sd-outline-light:hover{border-color:var(--sd-color-light-highlight) !important}.sd-outline-muted{border-color:var(--sd-color-muted) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-muted:focus,a.sd-outline-muted:hover{border-color:var(--sd-color-muted-highlight) !important}.sd-outline-dark{border-color:var(--sd-color-dark) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-dark:focus,a.sd-outline-dark:hover{border-color:var(--sd-color-dark-highlight) !important}.sd-outline-black{border-color:var(--sd-color-black) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-black:focus,a.sd-outline-black:hover{border-color:var(--sd-color-black-highlight) !important}.sd-outline-white{border-color:var(--sd-color-white) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-white:focus,a.sd-outline-white:hover{border-color:var(--sd-color-white-highlight) !important}.sd-bg-transparent{background-color:transparent !important}.sd-outline-transparent{border-color:transparent !important}.sd-text-transparent{color:transparent !important}.sd-p-0{padding:0 !important}.sd-pt-0,.sd-py-0{padding-top:0 !important}.sd-pr-0,.sd-px-0{padding-right:0 !important}.sd-pb-0,.sd-py-0{padding-bottom:0 !important}.sd-pl-0,.sd-px-0{padding-left:0 !important}.sd-p-1{padding:.25rem !important}.sd-pt-1,.sd-py-1{padding-top:.25rem !important}.sd-pr-1,.sd-px-1{padding-right:.25rem !important}.sd-pb-1,.sd-py-1{padding-bottom:.25rem !important}.sd-pl-1,.sd-px-1{padding-left:.25rem !important}.sd-p-2{padding:.5rem !important}.sd-pt-2,.sd-py-2{padding-top:.5rem !important}.sd-pr-2,.sd-px-2{padding-right:.5rem !important}.sd-pb-2,.sd-py-2{padding-bottom:.5rem !important}.sd-pl-2,.sd-px-2{padding-left:.5rem !important}.sd-p-3{padding:1rem !important}.sd-pt-3,.sd-py-3{padding-top:1rem !important}.sd-pr-3,.sd-px-3{padding-right:1rem !important}.sd-pb-3,.sd-py-3{padding-bottom:1rem !important}.sd-pl-3,.sd-px-3{padding-left:1rem !important}.sd-p-4{padding:1.5rem !important}.sd-pt-4,.sd-py-4{padding-top:1.5rem !important}.sd-pr-4,.sd-px-4{padding-right:1.5rem !important}.sd-pb-4,.sd-py-4{padding-bottom:1.5rem !important}.sd-pl-4,.sd-px-4{padding-left:1.5rem !important}.sd-p-5{padding:3rem !important}.sd-pt-5,.sd-py-5{padding-top:3rem !important}.sd-pr-5,.sd-px-5{padding-right:3rem !important}.sd-pb-5,.sd-py-5{padding-bottom:3rem !important}.sd-pl-5,.sd-px-5{padding-left:3rem !important}.sd-m-auto{margin:auto !important}.sd-mt-auto,.sd-my-auto{margin-top:auto !important}.sd-mr-auto,.sd-mx-auto{margin-right:auto !important}.sd-mb-auto,.sd-my-auto{margin-bottom:auto !important}.sd-ml-auto,.sd-mx-auto{margin-left:auto !important}.sd-m-0{margin:0 !important}.sd-mt-0,.sd-my-0{margin-top:0 !important}.sd-mr-0,.sd-mx-0{margin-right:0 !important}.sd-mb-0,.sd-my-0{margin-bottom:0 !important}.sd-ml-0,.sd-mx-0{margin-left:0 !important}.sd-m-1{margin:.25rem !important}.sd-mt-1,.sd-my-1{margin-top:.25rem !important}.sd-mr-1,.sd-mx-1{margin-right:.25rem !important}.sd-mb-1,.sd-my-1{margin-bottom:.25rem !important}.sd-ml-1,.sd-mx-1{margin-left:.25rem !important}.sd-m-2{margin:.5rem !important}.sd-mt-2,.sd-my-2{margin-top:.5rem !important}.sd-mr-2,.sd-mx-2{margin-right:.5rem !important}.sd-mb-2,.sd-my-2{margin-bottom:.5rem !important}.sd-ml-2,.sd-mx-2{margin-left:.5rem !important}.sd-m-3{margin:1rem !important}.sd-mt-3,.sd-my-3{margin-top:1rem !important}.sd-mr-3,.sd-mx-3{margin-right:1rem !important}.sd-mb-3,.sd-my-3{margin-bottom:1rem !important}.sd-ml-3,.sd-mx-3{margin-left:1rem !important}.sd-m-4{margin:1.5rem !important}.sd-mt-4,.sd-my-4{margin-top:1.5rem !important}.sd-mr-4,.sd-mx-4{margin-right:1.5rem !important}.sd-mb-4,.sd-my-4{margin-bottom:1.5rem !important}.sd-ml-4,.sd-mx-4{margin-left:1.5rem !important}.sd-m-5{margin:3rem !important}.sd-mt-5,.sd-my-5{margin-top:3rem !important}.sd-mr-5,.sd-mx-5{margin-right:3rem !important}.sd-mb-5,.sd-my-5{margin-bottom:3rem !important}.sd-ml-5,.sd-mx-5{margin-left:3rem !important}.sd-w-25{width:25% !important}.sd-w-50{width:50% !important}.sd-w-75{width:75% !important}.sd-w-100{width:100% !important}.sd-w-auto{width:auto !important}.sd-h-25{height:25% !important}.sd-h-50{height:50% !important}.sd-h-75{height:75% !important}.sd-h-100{height:100% !important}.sd-h-auto{height:auto !important}.sd-d-none{display:none !important}.sd-d-inline{display:inline !important}.sd-d-inline-block{display:inline-block !important}.sd-d-block{display:block !important}.sd-d-grid{display:grid !important}.sd-d-flex-row{display:-ms-flexbox !important;display:flex !important;flex-direction:row !important}.sd-d-flex-column{display:-ms-flexbox !important;display:flex !important;flex-direction:column !important}.sd-d-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}@media(min-width: 576px){.sd-d-sm-none{display:none !important}.sd-d-sm-inline{display:inline !important}.sd-d-sm-inline-block{display:inline-block !important}.sd-d-sm-block{display:block !important}.sd-d-sm-grid{display:grid !important}.sd-d-sm-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-sm-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 768px){.sd-d-md-none{display:none !important}.sd-d-md-inline{display:inline !important}.sd-d-md-inline-block{display:inline-block !important}.sd-d-md-block{display:block !important}.sd-d-md-grid{display:grid !important}.sd-d-md-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-md-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 992px){.sd-d-lg-none{display:none !important}.sd-d-lg-inline{display:inline !important}.sd-d-lg-inline-block{display:inline-block !important}.sd-d-lg-block{display:block !important}.sd-d-lg-grid{display:grid !important}.sd-d-lg-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-lg-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 1200px){.sd-d-xl-none{display:none !important}.sd-d-xl-inline{display:inline !important}.sd-d-xl-inline-block{display:inline-block !important}.sd-d-xl-block{display:block !important}.sd-d-xl-grid{display:grid !important}.sd-d-xl-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-xl-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}.sd-align-major-start{justify-content:flex-start !important}.sd-align-major-end{justify-content:flex-end !important}.sd-align-major-center{justify-content:center !important}.sd-align-major-justify{justify-content:space-between !important}.sd-align-major-spaced{justify-content:space-evenly !important}.sd-align-minor-start{align-items:flex-start !important}.sd-align-minor-end{align-items:flex-end !important}.sd-align-minor-center{align-items:center !important}.sd-align-minor-stretch{align-items:stretch !important}.sd-text-justify{text-align:justify !important}.sd-text-left{text-align:left !important}.sd-text-right{text-align:right !important}.sd-text-center{text-align:center !important}.sd-font-weight-light{font-weight:300 !important}.sd-font-weight-lighter{font-weight:lighter !important}.sd-font-weight-normal{font-weight:400 !important}.sd-font-weight-bold{font-weight:700 !important}.sd-font-weight-bolder{font-weight:bolder !important}.sd-font-italic{font-style:italic !important}.sd-text-decoration-none{text-decoration:none !important}.sd-text-lowercase{text-transform:lowercase !important}.sd-text-uppercase{text-transform:uppercase !important}.sd-text-capitalize{text-transform:capitalize !important}.sd-text-wrap{white-space:normal !important}.sd-text-nowrap{white-space:nowrap !important}.sd-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-fs-1,.sd-fs-1>p{font-size:calc(1.375rem + 1.5vw) !important;line-height:unset !important}.sd-fs-2,.sd-fs-2>p{font-size:calc(1.325rem + 0.9vw) !important;line-height:unset !important}.sd-fs-3,.sd-fs-3>p{font-size:calc(1.3rem + 0.6vw) !important;line-height:unset !important}.sd-fs-4,.sd-fs-4>p{font-size:calc(1.275rem + 0.3vw) !important;line-height:unset !important}.sd-fs-5,.sd-fs-5>p{font-size:1.25rem !important;line-height:unset !important}.sd-fs-6,.sd-fs-6>p{font-size:1rem !important;line-height:unset !important}.sd-border-0{border:0 solid !important}.sd-border-top-0{border-top:0 solid !important}.sd-border-bottom-0{border-bottom:0 solid !important}.sd-border-right-0{border-right:0 solid !important}.sd-border-left-0{border-left:0 solid !important}.sd-border-1{border:1px solid !important}.sd-border-top-1{border-top:1px solid !important}.sd-border-bottom-1{border-bottom:1px solid !important}.sd-border-right-1{border-right:1px solid !important}.sd-border-left-1{border-left:1px solid !important}.sd-border-2{border:2px solid !important}.sd-border-top-2{border-top:2px solid !important}.sd-border-bottom-2{border-bottom:2px solid !important}.sd-border-right-2{border-right:2px solid !important}.sd-border-left-2{border-left:2px solid !important}.sd-border-3{border:3px solid !important}.sd-border-top-3{border-top:3px solid !important}.sd-border-bottom-3{border-bottom:3px solid !important}.sd-border-right-3{border-right:3px solid !important}.sd-border-left-3{border-left:3px solid !important}.sd-border-4{border:4px solid !important}.sd-border-top-4{border-top:4px solid !important}.sd-border-bottom-4{border-bottom:4px solid !important}.sd-border-right-4{border-right:4px solid !important}.sd-border-left-4{border-left:4px solid !important}.sd-border-5{border:5px solid !important}.sd-border-top-5{border-top:5px solid !important}.sd-border-bottom-5{border-bottom:5px solid !important}.sd-border-right-5{border-right:5px solid !important}.sd-border-left-5{border-left:5px solid !important}.sd-rounded-0{border-radius:0 !important}.sd-rounded-1{border-radius:.2rem !important}.sd-rounded-2{border-radius:.3rem !important}.sd-rounded-3{border-radius:.5rem !important}.sd-rounded-pill{border-radius:50rem !important}.sd-rounded-circle{border-radius:50% !important}.shadow-none{box-shadow:none !important}.sd-shadow-sm{box-shadow:0 .125rem .25rem var(--sd-color-shadow) !important}.sd-shadow-md{box-shadow:0 .5rem 1rem var(--sd-color-shadow) !important}.sd-shadow-lg{box-shadow:0 1rem 3rem var(--sd-color-shadow) !important}@keyframes sd-slide-from-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes sd-slide-from-right{0%{transform:translateX(200%)}100%{transform:translateX(0)}}@keyframes sd-grow100{0%{transform:scale(0);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50{0%{transform:scale(0.5);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50-rot20{0%{transform:scale(0.5) rotateZ(-20deg);opacity:.5}75%{transform:scale(1) rotateZ(5deg);opacity:1}95%{transform:scale(1) rotateZ(-1deg);opacity:1}100%{transform:scale(1) rotateZ(0);opacity:1}}.sd-animate-slide-from-left{animation:1s ease-out 0s 1 normal none running sd-slide-from-left}.sd-animate-slide-from-right{animation:1s ease-out 0s 1 normal none running sd-slide-from-right}.sd-animate-grow100{animation:1s ease-out 0s 1 normal none running sd-grow100}.sd-animate-grow50{animation:1s ease-out 0s 1 normal none running sd-grow50}.sd-animate-grow50-rot20{animation:1s ease-out 0s 1 normal none running sd-grow50-rot20}.sd-badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.sd-badge:empty{display:none}a.sd-badge{text-decoration:none}.sd-btn .sd-badge{position:relative;top:-1px}.sd-btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;cursor:pointer;display:inline-block;font-weight:400;font-size:1rem;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:middle;user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none}.sd-btn:hover{text-decoration:none}@media(prefers-reduced-motion: reduce){.sd-btn{transition:none}}.sd-btn-primary,.sd-btn-outline-primary:hover,.sd-btn-outline-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-primary:hover,.sd-btn-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary-highlight) !important;border-color:var(--sd-color-primary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-primary{color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary,.sd-btn-outline-secondary:hover,.sd-btn-outline-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary:hover,.sd-btn-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary-highlight) !important;border-color:var(--sd-color-secondary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-secondary{color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success,.sd-btn-outline-success:hover,.sd-btn-outline-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success:hover,.sd-btn-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success-highlight) !important;border-color:var(--sd-color-success-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-success{color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info,.sd-btn-outline-info:hover,.sd-btn-outline-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info:hover,.sd-btn-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info-highlight) !important;border-color:var(--sd-color-info-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-info{color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning,.sd-btn-outline-warning:hover,.sd-btn-outline-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning:hover,.sd-btn-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning-highlight) !important;border-color:var(--sd-color-warning-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-warning{color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger,.sd-btn-outline-danger:hover,.sd-btn-outline-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger:hover,.sd-btn-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger-highlight) !important;border-color:var(--sd-color-danger-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-danger{color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light,.sd-btn-outline-light:hover,.sd-btn-outline-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light:hover,.sd-btn-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light-highlight) !important;border-color:var(--sd-color-light-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-light{color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted,.sd-btn-outline-muted:hover,.sd-btn-outline-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted:hover,.sd-btn-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted-highlight) !important;border-color:var(--sd-color-muted-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-muted{color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark,.sd-btn-outline-dark:hover,.sd-btn-outline-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark:hover,.sd-btn-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark-highlight) !important;border-color:var(--sd-color-dark-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-dark{color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black,.sd-btn-outline-black:hover,.sd-btn-outline-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black:hover,.sd-btn-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black-highlight) !important;border-color:var(--sd-color-black-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-black{color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white,.sd-btn-outline-white:hover,.sd-btn-outline-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white:hover,.sd-btn-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white-highlight) !important;border-color:var(--sd-color-white-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-white{color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.sd-hide-link-text{font-size:0}.sd-octicon,.sd-material-icon{display:inline-block;fill:currentColor;vertical-align:middle}.sd-avatar-xs{border-radius:50%;object-fit:cover;object-position:center;width:1rem;height:1rem}.sd-avatar-sm{border-radius:50%;object-fit:cover;object-position:center;width:3rem;height:3rem}.sd-avatar-md{border-radius:50%;object-fit:cover;object-position:center;width:5rem;height:5rem}.sd-avatar-lg{border-radius:50%;object-fit:cover;object-position:center;width:7rem;height:7rem}.sd-avatar-xl{border-radius:50%;object-fit:cover;object-position:center;width:10rem;height:10rem}.sd-avatar-inherit{border-radius:50%;object-fit:cover;object-position:center;width:inherit;height:inherit}.sd-avatar-initial{border-radius:50%;object-fit:cover;object-position:center;width:initial;height:initial}.sd-card{background-clip:border-box;background-color:var(--sd-color-card-background);border:1px solid var(--sd-color-card-border);border-radius:.25rem;color:var(--sd-color-card-text);display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.sd-card>hr{margin-left:0;margin-right:0}.sd-card-hover:hover{border-color:var(--sd-color-card-border-hover);transform:scale(1.01)}.sd-card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem 1rem}.sd-card-title{margin-bottom:.5rem}.sd-card-subtitle{margin-top:-0.25rem;margin-bottom:0}.sd-card-text:last-child{margin-bottom:0}.sd-card-link:hover{text-decoration:none}.sd-card-link+.card-link{margin-left:1rem}.sd-card-header{padding:.5rem 1rem;margin-bottom:0;background-color:var(--sd-color-card-header);border-bottom:1px solid var(--sd-color-card-border)}.sd-card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.sd-card-footer{padding:.5rem 1rem;background-color:var(--sd-color-card-footer);border-top:1px solid var(--sd-color-card-border)}.sd-card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.sd-card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.sd-card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.sd-card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom,.sd-card-img-top{width:100%}.sd-card-img,.sd-card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom{border-bottom-left-radius:calc(0.25rem - 1px);border-bottom-right-radius:calc(0.25rem - 1px)}.sd-cards-carousel{width:100%;display:flex;flex-wrap:nowrap;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;scroll-snap-type:x mandatory}.sd-cards-carousel.sd-show-scrollbar{overflow-x:auto}.sd-cards-carousel:hover,.sd-cards-carousel:focus{overflow-x:auto}.sd-cards-carousel>.sd-card{flex-shrink:0;scroll-snap-align:start}.sd-cards-carousel>.sd-card:not(:last-child){margin-right:3px}.sd-card-cols-1>.sd-card{width:90%}.sd-card-cols-2>.sd-card{width:45%}.sd-card-cols-3>.sd-card{width:30%}.sd-card-cols-4>.sd-card{width:22.5%}.sd-card-cols-5>.sd-card{width:18%}.sd-card-cols-6>.sd-card{width:15%}.sd-card-cols-7>.sd-card{width:12.8571428571%}.sd-card-cols-8>.sd-card{width:11.25%}.sd-card-cols-9>.sd-card{width:10%}.sd-card-cols-10>.sd-card{width:9%}.sd-card-cols-11>.sd-card{width:8.1818181818%}.sd-card-cols-12>.sd-card{width:7.5%}.sd-container,.sd-container-fluid,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container-xl{margin-left:auto;margin-right:auto;padding-left:var(--sd-gutter-x, 0.75rem);padding-right:var(--sd-gutter-x, 0.75rem);width:100%}@media(min-width: 576px){.sd-container-sm,.sd-container{max-width:540px}}@media(min-width: 768px){.sd-container-md,.sd-container-sm,.sd-container{max-width:720px}}@media(min-width: 992px){.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:960px}}@media(min-width: 1200px){.sd-container-xl,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:1140px}}.sd-row{--sd-gutter-x: 1.5rem;--sd-gutter-y: 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:calc(var(--sd-gutter-y) * -1);margin-right:calc(var(--sd-gutter-x) * -0.5);margin-left:calc(var(--sd-gutter-x) * -0.5)}.sd-row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--sd-gutter-x) * 0.5);padding-left:calc(var(--sd-gutter-x) * 0.5);margin-top:var(--sd-gutter-y)}.sd-col{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-auto>*{flex:0 0 auto;width:auto}.sd-row-cols-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}@media(min-width: 576px){.sd-col-sm{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-sm-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-sm-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-sm-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-sm-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-sm-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-sm-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-sm-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-sm-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-sm-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-sm-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-sm-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-sm-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-sm-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 768px){.sd-col-md{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-md-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-md-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-md-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-md-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-md-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-md-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-md-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-md-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-md-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-md-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-md-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-md-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-md-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 992px){.sd-col-lg{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-lg-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-lg-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-lg-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-lg-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-lg-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-lg-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-lg-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-lg-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-lg-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-lg-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-lg-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-lg-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-lg-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 1200px){.sd-col-xl{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-xl-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-xl-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-xl-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-xl-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-xl-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-xl-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-xl-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-xl-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-xl-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-xl-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-xl-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-xl-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-xl-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}.sd-col-auto{flex:0 0 auto;-ms-flex:0 0 auto;width:auto}.sd-col-1{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}.sd-col-2{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-col-3{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-col-4{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-col-5{flex:0 0 auto;-ms-flex:0 0 auto;width:41.6666666667%}.sd-col-6{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-col-7{flex:0 0 auto;-ms-flex:0 0 auto;width:58.3333333333%}.sd-col-8{flex:0 0 auto;-ms-flex:0 0 auto;width:66.6666666667%}.sd-col-9{flex:0 0 auto;-ms-flex:0 0 auto;width:75%}.sd-col-10{flex:0 0 auto;-ms-flex:0 0 auto;width:83.3333333333%}.sd-col-11{flex:0 0 auto;-ms-flex:0 0 auto;width:91.6666666667%}.sd-col-12{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-g-0,.sd-gy-0{--sd-gutter-y: 0}.sd-g-0,.sd-gx-0{--sd-gutter-x: 0}.sd-g-1,.sd-gy-1{--sd-gutter-y: 0.25rem}.sd-g-1,.sd-gx-1{--sd-gutter-x: 0.25rem}.sd-g-2,.sd-gy-2{--sd-gutter-y: 0.5rem}.sd-g-2,.sd-gx-2{--sd-gutter-x: 0.5rem}.sd-g-3,.sd-gy-3{--sd-gutter-y: 1rem}.sd-g-3,.sd-gx-3{--sd-gutter-x: 1rem}.sd-g-4,.sd-gy-4{--sd-gutter-y: 1.5rem}.sd-g-4,.sd-gx-4{--sd-gutter-x: 1.5rem}.sd-g-5,.sd-gy-5{--sd-gutter-y: 3rem}.sd-g-5,.sd-gx-5{--sd-gutter-x: 3rem}@media(min-width: 576px){.sd-col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-sm-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-sm-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-sm-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-sm-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-sm-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-sm-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-sm-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-sm-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-sm-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-sm-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-sm-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-sm-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-sm-0,.sd-gy-sm-0{--sd-gutter-y: 0}.sd-g-sm-0,.sd-gx-sm-0{--sd-gutter-x: 0}.sd-g-sm-1,.sd-gy-sm-1{--sd-gutter-y: 0.25rem}.sd-g-sm-1,.sd-gx-sm-1{--sd-gutter-x: 0.25rem}.sd-g-sm-2,.sd-gy-sm-2{--sd-gutter-y: 0.5rem}.sd-g-sm-2,.sd-gx-sm-2{--sd-gutter-x: 0.5rem}.sd-g-sm-3,.sd-gy-sm-3{--sd-gutter-y: 1rem}.sd-g-sm-3,.sd-gx-sm-3{--sd-gutter-x: 1rem}.sd-g-sm-4,.sd-gy-sm-4{--sd-gutter-y: 1.5rem}.sd-g-sm-4,.sd-gx-sm-4{--sd-gutter-x: 1.5rem}.sd-g-sm-5,.sd-gy-sm-5{--sd-gutter-y: 3rem}.sd-g-sm-5,.sd-gx-sm-5{--sd-gutter-x: 3rem}}@media(min-width: 768px){.sd-col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-md-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-md-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-md-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-md-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-md-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-md-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-md-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-md-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-md-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-md-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-md-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-md-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-md-0,.sd-gy-md-0{--sd-gutter-y: 0}.sd-g-md-0,.sd-gx-md-0{--sd-gutter-x: 0}.sd-g-md-1,.sd-gy-md-1{--sd-gutter-y: 0.25rem}.sd-g-md-1,.sd-gx-md-1{--sd-gutter-x: 0.25rem}.sd-g-md-2,.sd-gy-md-2{--sd-gutter-y: 0.5rem}.sd-g-md-2,.sd-gx-md-2{--sd-gutter-x: 0.5rem}.sd-g-md-3,.sd-gy-md-3{--sd-gutter-y: 1rem}.sd-g-md-3,.sd-gx-md-3{--sd-gutter-x: 1rem}.sd-g-md-4,.sd-gy-md-4{--sd-gutter-y: 1.5rem}.sd-g-md-4,.sd-gx-md-4{--sd-gutter-x: 1.5rem}.sd-g-md-5,.sd-gy-md-5{--sd-gutter-y: 3rem}.sd-g-md-5,.sd-gx-md-5{--sd-gutter-x: 3rem}}@media(min-width: 992px){.sd-col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-lg-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-lg-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-lg-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-lg-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-lg-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-lg-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-lg-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-lg-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-lg-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-lg-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-lg-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-lg-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-lg-0,.sd-gy-lg-0{--sd-gutter-y: 0}.sd-g-lg-0,.sd-gx-lg-0{--sd-gutter-x: 0}.sd-g-lg-1,.sd-gy-lg-1{--sd-gutter-y: 0.25rem}.sd-g-lg-1,.sd-gx-lg-1{--sd-gutter-x: 0.25rem}.sd-g-lg-2,.sd-gy-lg-2{--sd-gutter-y: 0.5rem}.sd-g-lg-2,.sd-gx-lg-2{--sd-gutter-x: 0.5rem}.sd-g-lg-3,.sd-gy-lg-3{--sd-gutter-y: 1rem}.sd-g-lg-3,.sd-gx-lg-3{--sd-gutter-x: 1rem}.sd-g-lg-4,.sd-gy-lg-4{--sd-gutter-y: 1.5rem}.sd-g-lg-4,.sd-gx-lg-4{--sd-gutter-x: 1.5rem}.sd-g-lg-5,.sd-gy-lg-5{--sd-gutter-y: 3rem}.sd-g-lg-5,.sd-gx-lg-5{--sd-gutter-x: 3rem}}@media(min-width: 1200px){.sd-col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-xl-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-xl-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-xl-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-xl-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-xl-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-xl-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-xl-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-xl-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-xl-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-xl-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-xl-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-xl-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-xl-0,.sd-gy-xl-0{--sd-gutter-y: 0}.sd-g-xl-0,.sd-gx-xl-0{--sd-gutter-x: 0}.sd-g-xl-1,.sd-gy-xl-1{--sd-gutter-y: 0.25rem}.sd-g-xl-1,.sd-gx-xl-1{--sd-gutter-x: 0.25rem}.sd-g-xl-2,.sd-gy-xl-2{--sd-gutter-y: 0.5rem}.sd-g-xl-2,.sd-gx-xl-2{--sd-gutter-x: 0.5rem}.sd-g-xl-3,.sd-gy-xl-3{--sd-gutter-y: 1rem}.sd-g-xl-3,.sd-gx-xl-3{--sd-gutter-x: 1rem}.sd-g-xl-4,.sd-gy-xl-4{--sd-gutter-y: 1.5rem}.sd-g-xl-4,.sd-gx-xl-4{--sd-gutter-x: 1.5rem}.sd-g-xl-5,.sd-gy-xl-5{--sd-gutter-y: 3rem}.sd-g-xl-5,.sd-gx-xl-5{--sd-gutter-x: 3rem}}.sd-flex-row-reverse{flex-direction:row-reverse !important}details.sd-dropdown{position:relative;font-size:var(--sd-fontsize-dropdown)}details.sd-dropdown:hover{cursor:pointer}details.sd-dropdown .sd-summary-content{cursor:default}details.sd-dropdown summary.sd-summary-title{padding:.5em .6em .5em 1em;font-size:var(--sd-fontsize-dropdown-title);font-weight:var(--sd-fontweight-dropdown-title);user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;list-style:none;display:inline-flex;justify-content:space-between}details.sd-dropdown summary.sd-summary-title::-webkit-details-marker{display:none}details.sd-dropdown summary.sd-summary-title:focus{outline:none}details.sd-dropdown summary.sd-summary-title .sd-summary-icon{margin-right:.6em;display:inline-flex;align-items:center}details.sd-dropdown summary.sd-summary-title .sd-summary-icon svg{opacity:.8}details.sd-dropdown summary.sd-summary-title .sd-summary-text{flex-grow:1;line-height:1.5;padding-right:.5rem}details.sd-dropdown summary.sd-summary-title .sd-summary-state-marker{pointer-events:none;display:inline-flex;align-items:center}details.sd-dropdown summary.sd-summary-title .sd-summary-state-marker svg{opacity:.6}details.sd-dropdown summary.sd-summary-title:hover .sd-summary-state-marker svg{opacity:1;transform:scale(1.1)}details.sd-dropdown[open] summary .sd-octicon.no-title{visibility:hidden}details.sd-dropdown .sd-summary-chevron-right{transition:.25s}details.sd-dropdown[open]>.sd-summary-title .sd-summary-chevron-right{transform:rotate(90deg)}details.sd-dropdown[open]>.sd-summary-title .sd-summary-chevron-down{transform:rotate(180deg)}details.sd-dropdown:not([open]).sd-card{border:none}details.sd-dropdown:not([open])>.sd-card-header{border:1px solid var(--sd-color-card-border);border-radius:.25rem}details.sd-dropdown.sd-fade-in[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out;animation:sd-fade-in .5s ease-in-out}details.sd-dropdown.sd-fade-in-slide-down[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out}.sd-col>.sd-dropdown{width:100%}.sd-summary-content>.sd-tab-set:first-child{margin-top:0}@keyframes sd-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes sd-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.sd-tab-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.sd-tab-set>input{opacity:0;position:absolute}.sd-tab-set>input:checked+label{border-color:var(--sd-color-tabs-underline-active);color:var(--sd-color-tabs-label-active)}.sd-tab-set>input:checked+label+.sd-tab-content{display:block}.sd-tab-set>input:not(:checked)+label:hover{color:var(--sd-color-tabs-label-hover);border-color:var(--sd-color-tabs-underline-hover)}.sd-tab-set>input:focus+label{outline-style:auto}.sd-tab-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.sd-tab-set>label{border-bottom:.125rem solid transparent;margin-bottom:0;color:var(--sd-color-tabs-label-inactive);border-color:var(--sd-color-tabs-underline-inactive);cursor:pointer;font-size:var(--sd-fontsize-tabs-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .sd-tab-set>label:hover{color:var(--sd-color-tabs-label-active)}.sd-col>.sd-tab-set{width:100%}.sd-tab-content{box-shadow:0 -0.0625rem var(--sd-color-tabs-overline),0 .0625rem var(--sd-color-tabs-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.sd-tab-content>:first-child{margin-top:0 !important}.sd-tab-content>:last-child{margin-bottom:0 !important}.sd-tab-content>.sd-tab-set{margin:0}.sd-sphinx-override,.sd-sphinx-override *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sd-sphinx-override p{margin-top:0}:root{--sd-color-primary: #0071bc;--sd-color-secondary: #6c757d;--sd-color-success: #28a745;--sd-color-info: #17a2b8;--sd-color-warning: #f0b37e;--sd-color-danger: #dc3545;--sd-color-light: #f8f9fa;--sd-color-muted: #6c757d;--sd-color-dark: #212529;--sd-color-black: black;--sd-color-white: white;--sd-color-primary-highlight: #0060a0;--sd-color-secondary-highlight: #5c636a;--sd-color-success-highlight: #228e3b;--sd-color-info-highlight: #148a9c;--sd-color-warning-highlight: #cc986b;--sd-color-danger-highlight: #bb2d3b;--sd-color-light-highlight: #d3d4d5;--sd-color-muted-highlight: #5c636a;--sd-color-dark-highlight: #1c1f23;--sd-color-black-highlight: black;--sd-color-white-highlight: #d9d9d9;--sd-color-primary-bg: rgba(0, 113, 188, 0.2);--sd-color-secondary-bg: rgba(108, 117, 125, 0.2);--sd-color-success-bg: rgba(40, 167, 69, 0.2);--sd-color-info-bg: rgba(23, 162, 184, 0.2);--sd-color-warning-bg: rgba(240, 179, 126, 0.2);--sd-color-danger-bg: rgba(220, 53, 69, 0.2);--sd-color-light-bg: rgba(248, 249, 250, 0.2);--sd-color-muted-bg: rgba(108, 117, 125, 0.2);--sd-color-dark-bg: rgba(33, 37, 41, 0.2);--sd-color-black-bg: rgba(0, 0, 0, 0.2);--sd-color-white-bg: rgba(255, 255, 255, 0.2);--sd-color-primary-text: #fff;--sd-color-secondary-text: #fff;--sd-color-success-text: #fff;--sd-color-info-text: #fff;--sd-color-warning-text: #212529;--sd-color-danger-text: #fff;--sd-color-light-text: #212529;--sd-color-muted-text: #fff;--sd-color-dark-text: #fff;--sd-color-black-text: #fff;--sd-color-white-text: #212529;--sd-color-shadow: rgba(0, 0, 0, 0.15);--sd-color-card-border: rgba(0, 0, 0, 0.125);--sd-color-card-border-hover: hsla(231, 99%, 66%, 1);--sd-color-card-background: transparent;--sd-color-card-text: inherit;--sd-color-card-header: transparent;--sd-color-card-footer: transparent;--sd-color-tabs-label-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-hover: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-inactive: hsl(0, 0%, 66%);--sd-color-tabs-underline-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-underline-hover: rgba(178, 206, 245, 0.62);--sd-color-tabs-underline-inactive: transparent;--sd-color-tabs-overline: rgb(222, 222, 222);--sd-color-tabs-underline: rgb(222, 222, 222);--sd-fontsize-tabs-label: 1rem;--sd-fontsize-dropdown: inherit;--sd-fontsize-dropdown-title: 1rem;--sd-fontweight-dropdown-title: 700} diff --git a/releases/2.0.0/_static/sphinx_highlight.js b/releases/2.0.0/_static/sphinx_highlight.js new file mode 100644 index 0000000..8a96c69 --- /dev/null +++ b/releases/2.0.0/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/releases/2.0.0/_static/styles/furo-extensions.css b/releases/2.0.0/_static/styles/furo-extensions.css new file mode 100644 index 0000000..8229587 --- /dev/null +++ b/releases/2.0.0/_static/styles/furo-extensions.css @@ -0,0 +1,2 @@ +#furo-sidebar-ad-placement{padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)}#furo-sidebar-ad-placement .ethical-sidebar{background:var(--color-background-secondary);border:none;box-shadow:none}#furo-sidebar-ad-placement .ethical-sidebar:hover{background:var(--color-background-hover)}#furo-sidebar-ad-placement .ethical-sidebar a{color:var(--color-foreground-primary)}#furo-sidebar-ad-placement .ethical-callout a{color:var(--color-foreground-secondary)!important}#furo-readthedocs-versions{background:transparent;display:block;position:static;width:100%}#furo-readthedocs-versions .rst-versions{background:#1a1c1e}#furo-readthedocs-versions .rst-current-version{background:var(--color-sidebar-item-background);cursor:unset}#furo-readthedocs-versions .rst-current-version:hover{background:var(--color-sidebar-item-background)}#furo-readthedocs-versions .rst-current-version .fa-book{color:var(--color-foreground-primary)}#furo-readthedocs-versions>.rst-other-versions{padding:0}#furo-readthedocs-versions>.rst-other-versions small{opacity:1}#furo-readthedocs-versions .injected .rst-versions{position:unset}#furo-readthedocs-versions:focus-within,#furo-readthedocs-versions:hover{box-shadow:0 0 0 1px var(--color-sidebar-background-border)}#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:hover .rst-current-version{background:#1a1c1e;font-size:inherit;height:auto;line-height:inherit;padding:12px;text-align:right}#furo-readthedocs-versions:focus-within .rst-current-version .fa-book,#furo-readthedocs-versions:hover .rst-current-version .fa-book{color:#fff;float:left}#furo-readthedocs-versions:focus-within .fa-caret-down,#furo-readthedocs-versions:hover .fa-caret-down{display:none}#furo-readthedocs-versions:focus-within .injected,#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:focus-within .rst-other-versions,#furo-readthedocs-versions:hover .injected,#furo-readthedocs-versions:hover .rst-current-version,#furo-readthedocs-versions:hover .rst-other-versions{display:block}#furo-readthedocs-versions:focus-within>.rst-current-version,#furo-readthedocs-versions:hover>.rst-current-version{display:none}.highlight:hover button.copybtn{color:var(--color-code-foreground)}.highlight button.copybtn{align-items:center;background-color:var(--color-code-background);border:none;color:var(--color-background-item);cursor:pointer;height:1.25em;right:.5rem;top:.625rem;transition:color .3s,opacity .3s;width:1.25em}.highlight button.copybtn:hover{background-color:var(--color-code-background);color:var(--color-brand-content)}.highlight button.copybtn:after{background-color:transparent;color:var(--color-code-foreground);display:none}.highlight button.copybtn.success{color:#22863a;transition:color 0ms}.highlight button.copybtn.success:after{display:block}.highlight button.copybtn svg{padding:0}body{--sd-color-primary:var(--color-brand-primary);--sd-color-primary-highlight:var(--color-brand-content);--sd-color-primary-text:var(--color-background-primary);--sd-color-shadow:rgba(0,0,0,.05);--sd-color-card-border:var(--color-card-border);--sd-color-card-border-hover:var(--color-brand-content);--sd-color-card-background:var(--color-card-background);--sd-color-card-text:var(--color-foreground-primary);--sd-color-card-header:var(--color-card-marginals-background);--sd-color-card-footer:var(--color-card-marginals-background);--sd-color-tabs-label-active:var(--color-brand-content);--sd-color-tabs-label-hover:var(--color-foreground-muted);--sd-color-tabs-label-inactive:var(--color-foreground-muted);--sd-color-tabs-underline-active:var(--color-brand-content);--sd-color-tabs-underline-hover:var(--color-foreground-border);--sd-color-tabs-underline-inactive:var(--color-background-border);--sd-color-tabs-overline:var(--color-background-border);--sd-color-tabs-underline:var(--color-background-border)}.sd-tab-content{box-shadow:0 -2px var(--sd-color-tabs-overline),0 1px var(--sd-color-tabs-underline)}.sd-card{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)}.sd-shadow-sm{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-md{box-shadow:0 .3rem .75rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-lg{box-shadow:0 .6rem 1.5rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-card-hover:hover{transform:none}.sd-cards-carousel{gap:.25rem;padding:.25rem}body{--tabs--label-text:var(--color-foreground-muted);--tabs--label-text--hover:var(--color-foreground-muted);--tabs--label-text--active:var(--color-brand-content);--tabs--label-text--active--hover:var(--color-brand-content);--tabs--label-background:transparent;--tabs--label-background--hover:transparent;--tabs--label-background--active:transparent;--tabs--label-background--active--hover:transparent;--tabs--padding-x:0.25em;--tabs--margin-x:1em;--tabs--border:var(--color-background-border);--tabs--label-border:transparent;--tabs--label-border--hover:var(--color-foreground-muted);--tabs--label-border--active:var(--color-brand-content);--tabs--label-border--active--hover:var(--color-brand-content)}[role=main] .container{max-width:none;padding-left:0;padding-right:0}.shadow.docutils{border:none;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)!important}.sphinx-bs .card{background-color:var(--color-background-secondary);color:var(--color-foreground)} +/*# sourceMappingURL=furo-extensions.css.map*/ \ No newline at end of file diff --git a/releases/2.0.0/_static/styles/furo-extensions.css.map b/releases/2.0.0/_static/styles/furo-extensions.css.map new file mode 100644 index 0000000..c26eac7 --- /dev/null +++ b/releases/2.0.0/_static/styles/furo-extensions.css.map @@ -0,0 +1 @@ +{"version":3,"file":"styles/furo-extensions.css","mappings":"AAGA,2BACE,oFACA,4CAKE,6CAHA,YACA,eAEA,CACA,kDACE,yCAEF,8CACE,sCAEJ,8CACE,kDAEJ,2BAGE,uBACA,cAHA,gBACA,UAEA,CAGA,yCACE,mBAEF,gDAEE,gDADA,YACA,CACA,sDACE,gDACF,yDACE,sCAEJ,+CACE,UACA,qDACE,UAGF,mDACE,eAEJ,yEAEE,4DAEA,mHASE,mBAPA,kBAEA,YADA,oBAGA,aADA,gBAIA,CAEA,qIAEE,WADA,UACA,CAEJ,uGACE,aAEF,iUAGE,cAEF,mHACE,aC1EJ,gCACE,mCAEF,0BAEE,mBAUA,8CACA,YAFA,mCAKA,eAZA,cAIA,YADA,YAYA,iCAdA,YAcA,CAEA,gCAEE,8CADA,gCACA,CAEF,gCAGE,6BADA,mCADA,YAEA,CAEF,kCAEE,cADA,oBACA,CACA,wCACE,cAEJ,8BACE,UCzCN,KAEE,6CAA8C,CAC9C,uDAAwD,CACxD,uDAAwD,CAGxD,iCAAsC,CAGtC,+CAAgD,CAChD,uDAAwD,CACxD,uDAAwD,CACxD,oDAAqD,CACrD,6DAA8D,CAC9D,6DAA8D,CAG9D,uDAAwD,CACxD,yDAA0D,CAC1D,4DAA6D,CAC7D,2DAA4D,CAC5D,8DAA+D,CAC/D,iEAAkE,CAClE,uDAAwD,CACxD,wDAAyD,CAG3D,gBACE,qFAGF,SACE,6EAEF,cACE,uFAEF,cACE,uFAEF,cACE,uFAGF,qBACE,eAEF,mBACE,WACA,eChDF,KACE,gDAAiD,CACjD,uDAAwD,CACxD,qDAAsD,CACtD,4DAA6D,CAC7D,oCAAqC,CACrC,2CAA4C,CAC5C,4CAA6C,CAC7C,mDAAoD,CACpD,wBAAyB,CACzB,oBAAqB,CACrB,6CAA8C,CAC9C,gCAAiC,CACjC,yDAA0D,CAC1D,uDAAwD,CACxD,8DAA+D,CCbjE,uBACE,eACA,eACA,gBAGF,iBACE,YACA,+EAGF,iBACE,mDACA","sources":["webpack:///./src/furo/assets/styles/extensions/_readthedocs.sass","webpack:///./src/furo/assets/styles/extensions/_copybutton.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-design.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-inline-tabs.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-panels.sass"],"sourcesContent":["// This file contains the styles used for tweaking how ReadTheDoc's embedded\n// contents would show up inside the theme.\n\n#furo-sidebar-ad-placement\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n .ethical-sidebar\n // Remove the border and box-shadow.\n border: none\n box-shadow: none\n // Manage the background colors.\n background: var(--color-background-secondary)\n &:hover\n background: var(--color-background-hover)\n // Ensure the text is legible.\n a\n color: var(--color-foreground-primary)\n\n .ethical-callout a\n color: var(--color-foreground-secondary) !important\n\n#furo-readthedocs-versions\n position: static\n width: 100%\n background: transparent\n display: block\n\n // Make the background color fit with the theme's aesthetic.\n .rst-versions\n background: rgb(26, 28, 30)\n\n .rst-current-version\n cursor: unset\n background: var(--color-sidebar-item-background)\n &:hover\n background: var(--color-sidebar-item-background)\n .fa-book\n color: var(--color-foreground-primary)\n\n > .rst-other-versions\n padding: 0\n small\n opacity: 1\n\n .injected\n .rst-versions\n position: unset\n\n &:hover,\n &:focus-within\n box-shadow: 0 0 0 1px var(--color-sidebar-background-border)\n\n .rst-current-version\n // Undo the tweaks done in RTD's CSS\n font-size: inherit\n line-height: inherit\n height: auto\n text-align: right\n padding: 12px\n\n // Match the rest of the body\n background: #1a1c1e\n\n .fa-book\n float: left\n color: white\n\n .fa-caret-down\n display: none\n\n .rst-current-version,\n .rst-other-versions,\n .injected\n display: block\n\n > .rst-current-version\n display: none\n",".highlight\n &:hover button.copybtn\n color: var(--color-code-foreground)\n\n button.copybtn\n // Align things correctly\n align-items: center\n\n height: 1.25em\n width: 1.25em\n\n top: 0.625rem // $code-spacing-vertical\n right: 0.5rem\n\n // Make it look better\n color: var(--color-background-item)\n background-color: var(--color-code-background)\n border: none\n\n // Change to cursor to make it obvious that you can click on it\n cursor: pointer\n\n // Transition smoothly, for aesthetics\n transition: color 300ms, opacity 300ms\n\n &:hover\n color: var(--color-brand-content)\n background-color: var(--color-code-background)\n\n &::after\n display: none\n color: var(--color-code-foreground)\n background-color: transparent\n\n &.success\n transition: color 0ms\n color: #22863a\n &::after\n display: block\n\n svg\n padding: 0\n","body\n // Colors\n --sd-color-primary: var(--color-brand-primary)\n --sd-color-primary-highlight: var(--color-brand-content)\n --sd-color-primary-text: var(--color-background-primary)\n\n // Shadows\n --sd-color-shadow: rgba(0, 0, 0, 0.05)\n\n // Cards\n --sd-color-card-border: var(--color-card-border)\n --sd-color-card-border-hover: var(--color-brand-content)\n --sd-color-card-background: var(--color-card-background)\n --sd-color-card-text: var(--color-foreground-primary)\n --sd-color-card-header: var(--color-card-marginals-background)\n --sd-color-card-footer: var(--color-card-marginals-background)\n\n // Tabs\n --sd-color-tabs-label-active: var(--color-brand-content)\n --sd-color-tabs-label-hover: var(--color-foreground-muted)\n --sd-color-tabs-label-inactive: var(--color-foreground-muted)\n --sd-color-tabs-underline-active: var(--color-brand-content)\n --sd-color-tabs-underline-hover: var(--color-foreground-border)\n --sd-color-tabs-underline-inactive: var(--color-background-border)\n --sd-color-tabs-overline: var(--color-background-border)\n --sd-color-tabs-underline: var(--color-background-border)\n\n// Tabs\n.sd-tab-content\n box-shadow: 0 -2px var(--sd-color-tabs-overline), 0 1px var(--sd-color-tabs-underline)\n\n// Shadows\n.sd-card // Have a shadow by default\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n.sd-shadow-sm\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-md\n box-shadow: 0 0.3rem 0.75rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-lg\n box-shadow: 0 0.6rem 1.5rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Cards\n.sd-card-hover:hover // Don't change scale on hover\n transform: none\n\n.sd-cards-carousel // Have a bit of gap in the carousel by default\n gap: 0.25rem\n padding: 0.25rem\n","// This file contains styles to tweak sphinx-inline-tabs to work well with Furo.\n\nbody\n --tabs--label-text: var(--color-foreground-muted)\n --tabs--label-text--hover: var(--color-foreground-muted)\n --tabs--label-text--active: var(--color-brand-content)\n --tabs--label-text--active--hover: var(--color-brand-content)\n --tabs--label-background: transparent\n --tabs--label-background--hover: transparent\n --tabs--label-background--active: transparent\n --tabs--label-background--active--hover: transparent\n --tabs--padding-x: 0.25em\n --tabs--margin-x: 1em\n --tabs--border: var(--color-background-border)\n --tabs--label-border: transparent\n --tabs--label-border--hover: var(--color-foreground-muted)\n --tabs--label-border--active: var(--color-brand-content)\n --tabs--label-border--active--hover: var(--color-brand-content)\n","// This file contains styles to tweak sphinx-panels to work well with Furo.\n\n// sphinx-panels includes Bootstrap 4, which uses .container which can conflict\n// with docutils' `.. container::` directive.\n[role=\"main\"] .container\n max-width: initial\n padding-left: initial\n padding-right: initial\n\n// Make the panels look nicer!\n.shadow.docutils\n border: none\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Make panel colors respond to dark mode\n.sphinx-bs .card\n background-color: var(--color-background-secondary)\n color: var(--color-foreground)\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/releases/2.0.0/_static/styles/furo.css b/releases/2.0.0/_static/styles/furo.css new file mode 100644 index 0000000..05a56b1 --- /dev/null +++ b/releases/2.0.0/_static/styles/furo.css @@ -0,0 +1,2 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}@media print{.content-icon-container,.headerlink,.mobile-header,.related-pages{display:none!important}.highlight{border:.1pt solid var(--color-foreground-border)}a,blockquote,dl,ol,p,pre,table,ul{page-break-inside:avoid}caption,figure,h1,h2,h3,h4,h5,h6,img{page-break-after:avoid;page-break-inside:avoid}dl,ol,ul{page-break-before:avoid}}.visually-hidden{height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;clip:rect(0,0,0,0)!important;background:var(--color-background-primary);border:0!important;color:var(--color-foreground-primary);white-space:nowrap!important}:-moz-focusring{outline:auto}body{--font-stack:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;--font-stack--monospace:"SFMono-Regular",Menlo,Consolas,Monaco,Liberation Mono,Lucida Console,monospace;--font-stack--headings:var(--font-stack);--font-size--normal:100%;--font-size--small:87.5%;--font-size--small--2:81.25%;--font-size--small--3:75%;--font-size--small--4:62.5%;--sidebar-caption-font-size:var(--font-size--small--2);--sidebar-item-font-size:var(--font-size--small);--sidebar-search-input-font-size:var(--font-size--small);--toc-font-size:var(--font-size--small--3);--toc-font-size--mobile:var(--font-size--normal);--toc-title-font-size:var(--font-size--small--4);--admonition-font-size:0.8125rem;--admonition-title-font-size:0.8125rem;--code-font-size:var(--font-size--small--2);--api-font-size:var(--font-size--small);--header-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*4);--header-padding:0.5rem;--sidebar-tree-space-above:1.5rem;--sidebar-caption-space-above:1rem;--sidebar-item-line-height:1rem;--sidebar-item-spacing-vertical:0.5rem;--sidebar-item-spacing-horizontal:1rem;--sidebar-item-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*2);--sidebar-expander-width:var(--sidebar-item-height);--sidebar-search-space-above:0.5rem;--sidebar-search-input-spacing-vertical:0.5rem;--sidebar-search-input-spacing-horizontal:0.5rem;--sidebar-search-input-height:1rem;--sidebar-search-icon-size:var(--sidebar-search-input-height);--toc-title-padding:0.25rem 0;--toc-spacing-vertical:1.5rem;--toc-spacing-horizontal:1.5rem;--toc-item-spacing-vertical:0.4rem;--toc-item-spacing-horizontal:1rem;--icon-search:url('data:image/svg+xml;charset=utf-8,');--icon-pencil:url('data:image/svg+xml;charset=utf-8,');--icon-abstract:url('data:image/svg+xml;charset=utf-8,');--icon-info:url('data:image/svg+xml;charset=utf-8,');--icon-flame:url('data:image/svg+xml;charset=utf-8,');--icon-question:url('data:image/svg+xml;charset=utf-8,');--icon-warning:url('data:image/svg+xml;charset=utf-8,');--icon-failure:url('data:image/svg+xml;charset=utf-8,');--icon-spark:url('data:image/svg+xml;charset=utf-8,');--color-admonition-title--caution:#ff9100;--color-admonition-title-background--caution:rgba(255,145,0,.2);--color-admonition-title--warning:#ff9100;--color-admonition-title-background--warning:rgba(255,145,0,.2);--color-admonition-title--danger:#ff5252;--color-admonition-title-background--danger:rgba(255,82,82,.2);--color-admonition-title--attention:#ff5252;--color-admonition-title-background--attention:rgba(255,82,82,.2);--color-admonition-title--error:#ff5252;--color-admonition-title-background--error:rgba(255,82,82,.2);--color-admonition-title--hint:#00c852;--color-admonition-title-background--hint:rgba(0,200,82,.2);--color-admonition-title--tip:#00c852;--color-admonition-title-background--tip:rgba(0,200,82,.2);--color-admonition-title--important:#00bfa5;--color-admonition-title-background--important:rgba(0,191,165,.2);--color-admonition-title--note:#00b0ff;--color-admonition-title-background--note:rgba(0,176,255,.2);--color-admonition-title--seealso:#448aff;--color-admonition-title-background--seealso:rgba(68,138,255,.2);--color-admonition-title--admonition-todo:grey;--color-admonition-title-background--admonition-todo:hsla(0,0%,50%,.2);--color-admonition-title:#651fff;--color-admonition-title-background:rgba(101,31,255,.2);--icon-admonition-default:var(--icon-abstract);--color-topic-title:#14b8a6;--color-topic-title-background:rgba(20,184,166,.2);--icon-topic-default:var(--icon-pencil);--color-problematic:#b30000;--color-foreground-primary:#000;--color-foreground-secondary:#5a5c63;--color-foreground-muted:#6b6f76;--color-foreground-border:#878787;--color-background-primary:#fff;--color-background-secondary:#f8f9fb;--color-background-hover:#efeff4;--color-background-hover--transparent:#efeff400;--color-background-border:#eeebee;--color-background-item:#ccc;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#0a4bff;--color-brand-content:#2757dd;--color-brand-visited:#872ee0;--color-api-background:var(--color-background-hover--transparent);--color-api-background-hover:var(--color-background-hover);--color-api-overall:var(--color-foreground-secondary);--color-api-name:var(--color-problematic);--color-api-pre-name:var(--color-problematic);--color-api-paren:var(--color-foreground-secondary);--color-api-keyword:var(--color-foreground-primary);--color-api-added:#21632c;--color-api-added-border:#38a84d;--color-api-changed:#046172;--color-api-changed-border:#06a1bc;--color-api-deprecated:#605706;--color-api-deprecated-border:#f0d90f;--color-api-removed:#b30000;--color-api-removed-border:#ff5c5c;--color-highlight-on-target:#ffc;--color-inline-code-background:var(--color-background-secondary);--color-highlighted-background:#def;--color-highlighted-text:var(--color-foreground-primary);--color-guilabel-background:#ddeeff80;--color-guilabel-border:#bedaf580;--color-guilabel-text:var(--color-foreground-primary);--color-admonition-background:transparent;--color-table-header-background:var(--color-background-secondary);--color-table-border:var(--color-background-border);--color-card-border:var(--color-background-secondary);--color-card-background:transparent;--color-card-marginals-background:var(--color-background-secondary);--color-header-background:var(--color-background-primary);--color-header-border:var(--color-background-border);--color-header-text:var(--color-foreground-primary);--color-sidebar-background:var(--color-background-secondary);--color-sidebar-background-border:var(--color-background-border);--color-sidebar-brand-text:var(--color-foreground-primary);--color-sidebar-caption-text:var(--color-foreground-muted);--color-sidebar-link-text:var(--color-foreground-secondary);--color-sidebar-link-text--top-level:var(--color-brand-primary);--color-sidebar-item-background:var(--color-sidebar-background);--color-sidebar-item-background--current:var( --color-sidebar-item-background );--color-sidebar-item-background--hover:linear-gradient(90deg,var(--color-background-hover--transparent) 0%,var(--color-background-hover) var(--sidebar-item-spacing-horizontal),var(--color-background-hover) 100%);--color-sidebar-item-expander-background:transparent;--color-sidebar-item-expander-background--hover:var( --color-background-hover );--color-sidebar-search-text:var(--color-foreground-primary);--color-sidebar-search-background:var(--color-background-secondary);--color-sidebar-search-background--focus:var(--color-background-primary);--color-sidebar-search-border:var(--color-background-border);--color-sidebar-search-icon:var(--color-foreground-muted);--color-toc-background:var(--color-background-primary);--color-toc-title-text:var(--color-foreground-muted);--color-toc-item-text:var(--color-foreground-secondary);--color-toc-item-text--hover:var(--color-foreground-primary);--color-toc-item-text--active:var(--color-brand-primary);--color-content-foreground:var(--color-foreground-primary);--color-content-background:transparent;--color-link:var(--color-brand-content);--color-link-underline:var(--color-background-border);--color-link--hover:var(--color-brand-content);--color-link-underline--hover:var(--color-foreground-border);--color-link--visited:var(--color-brand-visited);--color-link-underline--visited:var(--color-background-border);--color-link--visited--hover:var(--color-brand-visited);--color-link-underline--visited--hover:var(--color-foreground-border)}.only-light{display:block!important}html body .only-dark{display:none!important}@media not print{body[data-theme=dark]{--color-problematic:#ee5151;--color-foreground-primary:#cfd0d0;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#3d94ff;--color-brand-content:#5ca5ff;--color-brand-visited:#b27aeb;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-api-added:#3db854;--color-api-added-border:#267334;--color-api-changed:#09b0ce;--color-api-changed-border:#056d80;--color-api-deprecated:#b1a10b;--color-api-deprecated-border:#6e6407;--color-api-removed:#ff7575;--color-api-removed-border:#b03b3b;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body[data-theme=dark] .only-light{display:none!important}body[data-theme=dark] .only-dark{display:block!important}@media(prefers-color-scheme:dark){body:not([data-theme=light]){--color-problematic:#ee5151;--color-foreground-primary:#cfd0d0;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#3d94ff;--color-brand-content:#5ca5ff;--color-brand-visited:#b27aeb;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-api-added:#3db854;--color-api-added-border:#267334;--color-api-changed:#09b0ce;--color-api-changed-border:#056d80;--color-api-deprecated:#b1a10b;--color-api-deprecated-border:#6e6407;--color-api-removed:#ff7575;--color-api-removed-border:#b03b3b;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body:not([data-theme=light]) .only-light{display:none!important}body:not([data-theme=light]) .only-dark{display:block!important}}}body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-light{display:block}@media(prefers-color-scheme:dark){body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-dark{display:block}body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-light{display:none}}body[data-theme=dark] .theme-toggle svg.theme-icon-when-dark,body[data-theme=light] .theme-toggle svg.theme-icon-when-light{display:block}body{font-family:var(--font-stack)}code,kbd,pre,samp{font-family:var(--font-stack--monospace)}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}article{line-height:1.5}h1,h2,h3,h4,h5,h6{border-radius:.5rem;font-family:var(--font-stack--headings);font-weight:700;line-height:1.25;margin:.5rem -.5rem;padding-left:.5rem;padding-right:.5rem}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p{margin-top:0}h1{font-size:2.5em;margin-bottom:1rem}h1,h2{margin-top:1.75rem}h2{font-size:2em}h3{font-size:1.5em}h4{font-size:1.25em}h5{font-size:1.125em}h6{font-size:1em}small{font-size:80%;opacity:75%}p{margin-bottom:.75rem;margin-top:.5rem}hr.docutils{background-color:var(--color-background-border);border:0;height:1px;margin:2rem 0;padding:0}.centered{text-align:center}a{color:var(--color-link);text-decoration:underline;text-decoration-color:var(--color-link-underline)}a:visited{color:var(--color-link--visited);text-decoration-color:var(--color-link-underline--visited)}a:visited:hover{color:var(--color-link--visited--hover);text-decoration-color:var(--color-link-underline--visited--hover)}a:hover{color:var(--color-link--hover);text-decoration-color:var(--color-link-underline--hover)}a.muted-link{color:inherit}a.muted-link:hover{color:var(--color-link--hover);text-decoration-color:var(--color-link-underline--hover)}a.muted-link:hover:visited{color:var(--color-link--visited--hover);text-decoration-color:var(--color-link-underline--visited--hover)}html{overflow-x:hidden;overflow-y:scroll;scroll-behavior:smooth}.sidebar-scroll,.toc-scroll,article[role=main] *{scrollbar-color:var(--color-foreground-border) transparent;scrollbar-width:thin}.sidebar-scroll::-webkit-scrollbar,.toc-scroll::-webkit-scrollbar,article[role=main] ::-webkit-scrollbar{height:.25rem;width:.25rem}.sidebar-scroll::-webkit-scrollbar-thumb,.toc-scroll::-webkit-scrollbar-thumb,article[role=main] ::-webkit-scrollbar-thumb{background-color:var(--color-foreground-border);border-radius:.125rem}body,html{height:100%}.skip-to-content,body,html{background:var(--color-background-primary);color:var(--color-foreground-primary)}.skip-to-content{border-radius:1rem;left:.25rem;padding:1rem;position:fixed;top:.25rem;transform:translateY(-200%);transition:transform .3s ease-in-out;z-index:40}.skip-to-content:focus-within{transform:translateY(0)}article{background:var(--color-content-background);color:var(--color-content-foreground);overflow-wrap:break-word}.page{display:flex;min-height:100%}.mobile-header{background-color:var(--color-header-background);border-bottom:1px solid var(--color-header-border);color:var(--color-header-text);display:none;height:var(--header-height);width:100%;z-index:10}.mobile-header.scrolled{border-bottom:none;box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2)}.mobile-header .header-center a{color:var(--color-header-text);text-decoration:none}.main{display:flex;flex:1}.sidebar-drawer{background:var(--color-sidebar-background);border-right:1px solid var(--color-sidebar-background-border);box-sizing:border-box;display:flex;justify-content:flex-end;min-width:15em;width:calc(50% - 26em)}.sidebar-container,.toc-drawer{box-sizing:border-box;width:15em}.toc-drawer{background:var(--color-toc-background);padding-right:1rem}.sidebar-sticky,.toc-sticky{display:flex;flex-direction:column;height:min(100%,100vh);height:100vh;position:sticky;top:0}.sidebar-scroll,.toc-scroll{flex-grow:1;flex-shrink:1;overflow:auto;scroll-behavior:smooth}.content{display:flex;flex-direction:column;justify-content:space-between;padding:0 3em;width:46em}.icon{display:inline-block;height:1rem;width:1rem}.icon svg{height:100%;width:100%}.announcement{align-items:center;background-color:var(--color-announcement-background);color:var(--color-announcement-text);display:flex;height:var(--header-height);overflow-x:auto}.announcement+.page{min-height:calc(100% - var(--header-height))}.announcement-content{box-sizing:border-box;min-width:100%;padding:.5rem;text-align:center;white-space:nowrap}.announcement-content a{color:var(--color-announcement-text);text-decoration-color:var(--color-announcement-text)}.announcement-content a:hover{color:var(--color-announcement-text);text-decoration-color:var(--color-link--hover)}.no-js .theme-toggle-container{display:none}.theme-toggle-container{display:flex}.theme-toggle{background:transparent;border:none;cursor:pointer;display:flex;padding:0}.theme-toggle svg{color:var(--color-foreground-primary);display:none;height:1.25rem;width:1.25rem}.theme-toggle-header{align-items:center;display:flex;justify-content:center}.nav-overlay-icon,.toc-overlay-icon{cursor:pointer;display:none}.nav-overlay-icon .icon,.toc-overlay-icon .icon{color:var(--color-foreground-secondary);height:1.5rem;width:1.5rem}.nav-overlay-icon,.toc-header-icon{align-items:center;justify-content:center}.toc-content-icon{height:1.5rem;width:1.5rem}.content-icon-container{display:flex;float:right;gap:.5rem;margin-bottom:1rem;margin-left:1rem;margin-top:1.5rem}.content-icon-container .edit-this-page svg,.content-icon-container .view-this-page svg{color:inherit;height:1.25rem;width:1.25rem}.sidebar-toggle{display:none;position:absolute}.sidebar-toggle[name=__toc]{left:20px}.sidebar-toggle:checked{left:40px}.overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms,height 0ms,opacity .25s ease-out;width:0}.sidebar-overlay{z-index:20}.toc-overlay{z-index:40}.sidebar-drawer{transition:left .25s ease-in-out;z-index:30}.toc-drawer{transition:right .25s ease-in-out;z-index:50}#__navigation:checked~.sidebar-overlay{height:100%;opacity:1;width:100%}#__navigation:checked~.page .sidebar-drawer{left:0;top:0}#__toc:checked~.toc-overlay{height:100%;opacity:1;width:100%}#__toc:checked~.page .toc-drawer{right:0;top:0}.back-to-top{background:var(--color-background-primary);border-radius:1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 1px 0 hsla(220,9%,46%,.502);display:none;font-size:.8125rem;left:0;margin-left:50%;padding:.5rem .75rem .5rem .5rem;position:fixed;text-decoration:none;top:1rem;transform:translateX(-50%);z-index:10}.back-to-top svg{height:1rem;width:1rem;fill:currentColor;display:inline-block}.back-to-top span{margin-left:.25rem}.show-back-to-top .back-to-top{align-items:center;display:flex}@media(min-width:97em){html{font-size:110%}}@media(max-width:82em){.toc-content-icon{display:flex}.toc-drawer{border-left:1px solid var(--color-background-muted);height:100vh;position:fixed;right:-15em;top:0}.toc-tree{border-left:none;font-size:var(--toc-font-size--mobile)}.sidebar-drawer{width:calc(50% - 18.5em)}}@media(max-width:67em){.content{margin-left:auto;margin-right:auto;padding:0 1em}}@media(max-width:63em){.nav-overlay-icon{display:flex}.sidebar-drawer{height:100vh;left:-15em;position:fixed;top:0;width:15em}.theme-toggle-header,.toc-header-icon{display:flex}.theme-toggle-content,.toc-content-icon{display:none}.mobile-header{align-items:center;display:flex;justify-content:space-between;position:sticky;top:0}.mobile-header .header-left,.mobile-header .header-right{display:flex;height:var(--header-height);padding:0 var(--header-padding)}.mobile-header .header-left label,.mobile-header .header-right label{height:100%;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.nav-overlay-icon .icon,.theme-toggle svg{height:1.5rem;width:1.5rem}:target{scroll-margin-top:calc(var(--header-height) + 2.5rem)}.back-to-top{top:calc(var(--header-height) + .5rem)}.page{flex-direction:column;justify-content:center}}@media(max-width:48em){.content{overflow-x:auto;width:100%}}@media(max-width:46em){article[role=main] aside.sidebar{float:none;margin:1rem 0;width:100%}}.admonition,.topic{background:var(--color-admonition-background);border-radius:.2rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1);font-size:var(--admonition-font-size);margin:1rem auto;overflow:hidden;padding:0 .5rem .5rem;page-break-inside:avoid}.admonition>:nth-child(2),.topic>:nth-child(2){margin-top:0}.admonition>:last-child,.topic>:last-child{margin-bottom:0}.admonition p.admonition-title,p.topic-title{font-size:var(--admonition-title-font-size);font-weight:500;line-height:1.3;margin:0 -.5rem .5rem;padding:.4rem .5rem .4rem 2rem;position:relative}.admonition p.admonition-title:before,p.topic-title:before{content:"";height:1rem;left:.5rem;position:absolute;width:1rem}p.admonition-title{background-color:var(--color-admonition-title-background)}p.admonition-title:before{background-color:var(--color-admonition-title);-webkit-mask-image:var(--icon-admonition-default);mask-image:var(--icon-admonition-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}p.topic-title{background-color:var(--color-topic-title-background)}p.topic-title:before{background-color:var(--color-topic-title);-webkit-mask-image:var(--icon-topic-default);mask-image:var(--icon-topic-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.admonition{border-left:.2rem solid var(--color-admonition-title)}.admonition.caution{border-left-color:var(--color-admonition-title--caution)}.admonition.caution>.admonition-title{background-color:var(--color-admonition-title-background--caution)}.admonition.caution>.admonition-title:before{background-color:var(--color-admonition-title--caution);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.warning{border-left-color:var(--color-admonition-title--warning)}.admonition.warning>.admonition-title{background-color:var(--color-admonition-title-background--warning)}.admonition.warning>.admonition-title:before{background-color:var(--color-admonition-title--warning);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.danger{border-left-color:var(--color-admonition-title--danger)}.admonition.danger>.admonition-title{background-color:var(--color-admonition-title-background--danger)}.admonition.danger>.admonition-title:before{background-color:var(--color-admonition-title--danger);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.attention{border-left-color:var(--color-admonition-title--attention)}.admonition.attention>.admonition-title{background-color:var(--color-admonition-title-background--attention)}.admonition.attention>.admonition-title:before{background-color:var(--color-admonition-title--attention);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.error{border-left-color:var(--color-admonition-title--error)}.admonition.error>.admonition-title{background-color:var(--color-admonition-title-background--error)}.admonition.error>.admonition-title:before{background-color:var(--color-admonition-title--error);-webkit-mask-image:var(--icon-failure);mask-image:var(--icon-failure)}.admonition.hint{border-left-color:var(--color-admonition-title--hint)}.admonition.hint>.admonition-title{background-color:var(--color-admonition-title-background--hint)}.admonition.hint>.admonition-title:before{background-color:var(--color-admonition-title--hint);-webkit-mask-image:var(--icon-question);mask-image:var(--icon-question)}.admonition.tip{border-left-color:var(--color-admonition-title--tip)}.admonition.tip>.admonition-title{background-color:var(--color-admonition-title-background--tip)}.admonition.tip>.admonition-title:before{background-color:var(--color-admonition-title--tip);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.important{border-left-color:var(--color-admonition-title--important)}.admonition.important>.admonition-title{background-color:var(--color-admonition-title-background--important)}.admonition.important>.admonition-title:before{background-color:var(--color-admonition-title--important);-webkit-mask-image:var(--icon-flame);mask-image:var(--icon-flame)}.admonition.note{border-left-color:var(--color-admonition-title--note)}.admonition.note>.admonition-title{background-color:var(--color-admonition-title-background--note)}.admonition.note>.admonition-title:before{background-color:var(--color-admonition-title--note);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition.seealso{border-left-color:var(--color-admonition-title--seealso)}.admonition.seealso>.admonition-title{background-color:var(--color-admonition-title-background--seealso)}.admonition.seealso>.admonition-title:before{background-color:var(--color-admonition-title--seealso);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.admonition-todo{border-left-color:var(--color-admonition-title--admonition-todo)}.admonition.admonition-todo>.admonition-title{background-color:var(--color-admonition-title-background--admonition-todo)}.admonition.admonition-todo>.admonition-title:before{background-color:var(--color-admonition-title--admonition-todo);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition-todo>.admonition-title{text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd{margin-left:2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:first-child{margin-top:.125rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list,dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:last-child{margin-bottom:.75rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list>dt{font-size:var(--font-size--small);text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd:empty{margin-bottom:.5rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul{margin-left:-1.2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p:nth-child(2){margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p+p:last-child:empty{margin-bottom:0;margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt{color:var(--color-api-overall)}.sig:not(.sig-inline){background:var(--color-api-background);border-radius:.25rem;font-family:var(--font-stack--monospace);font-size:var(--api-font-size);font-weight:700;margin-left:-.25rem;margin-right:-.25rem;padding:.25rem .5rem .25rem 3em;text-indent:-2.5em;transition:background .1s ease-out}.sig:not(.sig-inline):hover{background:var(--color-api-background-hover)}.sig:not(.sig-inline) a.reference .viewcode-link{font-weight:400;width:4.25rem}em.property{font-style:normal}em.property:first-child{color:var(--color-api-keyword)}.sig-name{color:var(--color-api-name)}.sig-prename{color:var(--color-api-pre-name);font-weight:400}.sig-paren{color:var(--color-api-paren)}.sig-param{font-style:normal}div.deprecated,div.versionadded,div.versionchanged,div.versionremoved{border-left:.1875rem solid;border-radius:.125rem;padding-left:.75rem}div.deprecated p,div.versionadded p,div.versionchanged p,div.versionremoved p{margin-bottom:.125rem;margin-top:.125rem}div.versionadded{border-color:var(--color-api-added-border)}div.versionadded .versionmodified{color:var(--color-api-added)}div.versionchanged{border-color:var(--color-api-changed-border)}div.versionchanged .versionmodified{color:var(--color-api-changed)}div.deprecated{border-color:var(--color-api-deprecated-border)}div.deprecated .versionmodified{color:var(--color-api-deprecated)}div.versionremoved{border-color:var(--color-api-removed-border)}div.versionremoved .versionmodified{color:var(--color-api-removed)}.viewcode-back,.viewcode-link{float:right;text-align:right}.line-block{margin-bottom:.75rem;margin-top:.5rem}.line-block .line-block{margin-bottom:0;margin-top:0;padding-left:1rem}.code-block-caption,article p.caption,table>caption{font-size:var(--font-size--small);text-align:center}.toctree-wrapper.compound .caption,.toctree-wrapper.compound :not(.caption)>.caption-text{font-size:var(--font-size--small);margin-bottom:0;text-align:initial;text-transform:uppercase}.toctree-wrapper.compound>ul{margin-bottom:0;margin-top:0}.sig-inline,code.literal{background:var(--color-inline-code-background);border-radius:.2em;font-size:var(--font-size--small--2);padding:.1em .2em}pre.literal-block .sig-inline,pre.literal-block code.literal{font-size:inherit;padding:0}p .sig-inline,p code.literal{border:1px solid var(--color-background-border)}.sig-inline{font-family:var(--font-stack--monospace)}div[class*=" highlight-"],div[class^=highlight-]{display:flex;margin:1em 0}div[class*=" highlight-"] .table-wrapper,div[class^=highlight-] .table-wrapper,pre{margin:0;padding:0}pre{overflow:auto}article[role=main] .highlight pre{line-height:1.5}.highlight pre,pre.literal-block{font-size:var(--code-font-size);padding:.625rem .875rem}pre.literal-block{background-color:var(--color-code-background);border-radius:.2rem;color:var(--color-code-foreground);margin-bottom:1rem;margin-top:1rem}.highlight{border-radius:.2rem;width:100%}.highlight .gp,.highlight span.linenos{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.highlight .hll{display:block;margin-left:-.875rem;margin-right:-.875rem;padding-left:.875rem;padding-right:.875rem}.code-block-caption{background-color:var(--color-code-background);border-bottom:1px solid;border-radius:.25rem;border-bottom-left-radius:0;border-bottom-right-radius:0;border-color:var(--color-background-border);color:var(--color-code-foreground);display:flex;font-weight:300;padding:.625rem .875rem}.code-block-caption+div[class]{margin-top:0}.code-block-caption+div[class] pre{border-top-left-radius:0;border-top-right-radius:0}.highlighttable{display:block;width:100%}.highlighttable tbody{display:block}.highlighttable tr{display:flex}.highlighttable td.linenos{background-color:var(--color-code-background);border-bottom-left-radius:.2rem;border-top-left-radius:.2rem;color:var(--color-code-foreground);padding:.625rem 0 .625rem .875rem}.highlighttable .linenodiv{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;font-size:var(--code-font-size);padding-right:.875rem}.highlighttable td.code{display:block;flex:1;overflow:hidden;padding:0}.highlighttable td.code .highlight{border-bottom-left-radius:0;border-top-left-radius:0}.highlight span.linenos{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;display:inline-block;margin-right:.875rem;padding-left:0;padding-right:.875rem}.footnote-reference{font-size:var(--font-size--small--4);vertical-align:super}dl.footnote.brackets{color:var(--color-foreground-secondary);display:grid;font-size:var(--font-size--small);grid-template-columns:max-content auto}dl.footnote.brackets dt{margin:0}dl.footnote.brackets dt>.fn-backref{margin-left:.25rem}dl.footnote.brackets dt:after{content:":"}dl.footnote.brackets dt .brackets:before{content:"["}dl.footnote.brackets dt .brackets:after{content:"]"}dl.footnote.brackets dd{margin:0;padding:0 1rem}aside.footnote{color:var(--color-foreground-secondary);font-size:var(--font-size--small)}aside.footnote>span,div.citation>span{float:left;font-weight:500;padding-right:.25rem}aside.footnote>:not(span),div.citation>p{margin-left:2rem}img{box-sizing:border-box;height:auto;max-width:100%}article .figure,article figure{border-radius:.2rem;margin:0}article .figure :last-child,article figure :last-child{margin-bottom:0}article .align-left{clear:left;float:left;margin:0 1rem 1rem}article .align-right{clear:right;float:right;margin:0 1rem 1rem}article .align-center,article .align-default{display:block;margin-left:auto;margin-right:auto;text-align:center}article table.align-default{display:table;text-align:initial}.domainindex-jumpbox,.genindex-jumpbox{border-bottom:1px solid var(--color-background-border);border-top:1px solid var(--color-background-border);padding:.25rem}.domainindex-section h2,.genindex-section h2{margin-bottom:.5rem;margin-top:.75rem}.domainindex-section ul,.genindex-section ul{margin-bottom:0;margin-top:0}ol,ul{margin-bottom:1rem;margin-top:1rem;padding-left:1.2rem}ol li>p:first-child,ul li>p:first-child{margin-bottom:.25rem;margin-top:.25rem}ol li>p:last-child,ul li>p:last-child{margin-top:.25rem}ol li>ol,ol li>ul,ul li>ol,ul li>ul{margin-bottom:.5rem;margin-top:.5rem}ol.arabic{list-style:decimal}ol.loweralpha{list-style:lower-alpha}ol.upperalpha{list-style:upper-alpha}ol.lowerroman{list-style:lower-roman}ol.upperroman{list-style:upper-roman}.simple li>ol,.simple li>ul,.toctree-wrapper li>ol,.toctree-wrapper li>ul{margin-bottom:0;margin-top:0}.field-list dt,.option-list dt,dl.footnote dt,dl.glossary dt,dl.simple dt,dl:not([class]) dt{font-weight:500;margin-top:.25rem}.field-list dt+dt,.option-list dt+dt,dl.footnote dt+dt,dl.glossary dt+dt,dl.simple dt+dt,dl:not([class]) dt+dt{margin-top:0}.field-list dt .classifier:before,.option-list dt .classifier:before,dl.footnote dt .classifier:before,dl.glossary dt .classifier:before,dl.simple dt .classifier:before,dl:not([class]) dt .classifier:before{content:":";margin-left:.2rem;margin-right:.2rem}.field-list dd ul,.field-list dd>p:first-child,.option-list dd ul,.option-list dd>p:first-child,dl.footnote dd ul,dl.footnote dd>p:first-child,dl.glossary dd ul,dl.glossary dd>p:first-child,dl.simple dd ul,dl.simple dd>p:first-child,dl:not([class]) dd ul,dl:not([class]) dd>p:first-child{margin-top:.125rem}.field-list dd ul,.option-list dd ul,dl.footnote dd ul,dl.glossary dd ul,dl.simple dd ul,dl:not([class]) dd ul{margin-bottom:.125rem}.math-wrapper{overflow-x:auto;width:100%}div.math{position:relative;text-align:center}div.math .headerlink,div.math:focus .headerlink{display:none}div.math:hover .headerlink{display:inline-block}div.math span.eqno{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);z-index:1}abbr[title]{cursor:help}.problematic{color:var(--color-problematic)}kbd:not(.compound){background-color:var(--color-background-secondary);border:1px solid var(--color-foreground-border);border-radius:.2rem;box-shadow:0 .0625rem 0 rgba(0,0,0,.2),inset 0 0 0 .125rem var(--color-background-primary);color:var(--color-foreground-primary);display:inline-block;font-size:var(--font-size--small--3);margin:0 .2rem;padding:0 .2rem;vertical-align:text-bottom}blockquote{background:var(--color-background-secondary);border-left:4px solid var(--color-background-border);margin-left:0;margin-right:0;padding:.5rem 1rem}blockquote .attribution{font-weight:600;text-align:right}blockquote.highlights,blockquote.pull-quote{font-size:1.25em}blockquote.epigraph,blockquote.pull-quote{border-left-width:0;border-radius:.5rem}blockquote.highlights{background:transparent;border-left-width:0}p .reference img{vertical-align:middle}p.rubric{font-size:1.125em;font-weight:700;line-height:1.25}dd p.rubric{font-size:var(--font-size--small);font-weight:inherit;line-height:inherit;text-transform:uppercase}article .sidebar{background-color:var(--color-background-secondary);border:1px solid var(--color-background-border);border-radius:.2rem;clear:right;float:right;margin-left:1rem;margin-right:0;width:30%}article .sidebar>*{padding-left:1rem;padding-right:1rem}article .sidebar>ol,article .sidebar>ul{padding-left:2.2rem}article .sidebar .sidebar-title{border-bottom:1px solid var(--color-background-border);font-weight:500;margin:0;padding:.5rem 1rem}[role=main] .table-wrapper.container{margin-bottom:.5rem;margin-top:1rem;overflow-x:auto;padding:.2rem .2rem .75rem;width:100%}table.docutils{border-collapse:collapse;border-radius:.2rem;border-spacing:0;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)}table.docutils th{background:var(--color-table-header-background)}table.docutils td,table.docutils th{border-bottom:1px solid var(--color-table-border);border-left:1px solid var(--color-table-border);border-right:1px solid var(--color-table-border);padding:0 .25rem}table.docutils td p,table.docutils th p{margin:.25rem}table.docutils td:first-child,table.docutils th:first-child{border-left:none}table.docutils td:last-child,table.docutils th:last-child{border-right:none}table.docutils td.text-left,table.docutils th.text-left{text-align:left}table.docutils td.text-right,table.docutils th.text-right{text-align:right}table.docutils td.text-center,table.docutils th.text-center{text-align:center}:target{scroll-margin-top:2.5rem}@media(max-width:67em){:target{scroll-margin-top:calc(2.5rem + var(--header-height))}section>span:target{scroll-margin-top:calc(2.8rem + var(--header-height))}}.headerlink{font-weight:100;-webkit-user-select:none;-moz-user-select:none;user-select:none}.code-block-caption>.headerlink,dl dt>.headerlink,figcaption p>.headerlink,h1>.headerlink,h2>.headerlink,h3>.headerlink,h4>.headerlink,h5>.headerlink,h6>.headerlink,p.caption>.headerlink,table>caption>.headerlink{margin-left:.5rem;visibility:hidden}.code-block-caption:hover>.headerlink,dl dt:hover>.headerlink,figcaption p:hover>.headerlink,h1:hover>.headerlink,h2:hover>.headerlink,h3:hover>.headerlink,h4:hover>.headerlink,h5:hover>.headerlink,h6:hover>.headerlink,p.caption:hover>.headerlink,table>caption:hover>.headerlink{visibility:visible}.code-block-caption>.toc-backref,dl dt>.toc-backref,figcaption p>.toc-backref,h1>.toc-backref,h2>.toc-backref,h3>.toc-backref,h4>.toc-backref,h5>.toc-backref,h6>.toc-backref,p.caption>.toc-backref,table>caption>.toc-backref{color:inherit;text-decoration-line:none}figure:hover>figcaption>p>.headerlink,table:hover>caption>.headerlink{visibility:visible}:target>h1:first-of-type,:target>h2:first-of-type,:target>h3:first-of-type,:target>h4:first-of-type,:target>h5:first-of-type,:target>h6:first-of-type,span:target~h1:first-of-type,span:target~h2:first-of-type,span:target~h3:first-of-type,span:target~h4:first-of-type,span:target~h5:first-of-type,span:target~h6:first-of-type{background-color:var(--color-highlight-on-target)}:target>h1:first-of-type code.literal,:target>h2:first-of-type code.literal,:target>h3:first-of-type code.literal,:target>h4:first-of-type code.literal,:target>h5:first-of-type code.literal,:target>h6:first-of-type code.literal,span:target~h1:first-of-type code.literal,span:target~h2:first-of-type code.literal,span:target~h3:first-of-type code.literal,span:target~h4:first-of-type code.literal,span:target~h5:first-of-type code.literal,span:target~h6:first-of-type code.literal{background-color:transparent}.literal-block-wrapper:target .code-block-caption,.this-will-duplicate-information-and-it-is-still-useful-here li :target,figure:target,table:target>caption{background-color:var(--color-highlight-on-target)}dt:target{background-color:var(--color-highlight-on-target)!important}.footnote-reference:target,.footnote>dt:target+dd{background-color:var(--color-highlight-on-target)}.guilabel{background-color:var(--color-guilabel-background);border:1px solid var(--color-guilabel-border);border-radius:.5em;color:var(--color-guilabel-text);font-size:.9em;padding:0 .3em}footer{display:flex;flex-direction:column;font-size:var(--font-size--small);margin-top:2rem}.bottom-of-page{align-items:center;border-top:1px solid var(--color-background-border);color:var(--color-foreground-secondary);display:flex;justify-content:space-between;line-height:1.5;margin-top:1rem;padding-bottom:1rem;padding-top:1rem}@media(max-width:46em){.bottom-of-page{flex-direction:column-reverse;gap:.25rem;text-align:center}}.bottom-of-page .left-details{font-size:var(--font-size--small)}.bottom-of-page .right-details{display:flex;flex-direction:column;gap:.25rem;text-align:right}.bottom-of-page .icons{display:flex;font-size:1rem;gap:.25rem;justify-content:flex-end}.bottom-of-page .icons a{text-decoration:none}.bottom-of-page .icons img,.bottom-of-page .icons svg{font-size:1.125rem;height:1em;width:1em}.related-pages a{align-items:center;display:flex;text-decoration:none}.related-pages a:hover .page-info .title{color:var(--color-link);text-decoration:underline;text-decoration-color:var(--color-link-underline)}.related-pages a svg.furo-related-icon,.related-pages a svg.furo-related-icon>use{color:var(--color-foreground-border);flex-shrink:0;height:.75rem;margin:0 .5rem;width:.75rem}.related-pages a.next-page{clear:right;float:right;max-width:50%;text-align:right}.related-pages a.prev-page{clear:left;float:left;max-width:50%}.related-pages a.prev-page svg{transform:rotate(180deg)}.page-info{display:flex;flex-direction:column;overflow-wrap:anywhere}.next-page .page-info{align-items:flex-end}.page-info .context{align-items:center;color:var(--color-foreground-muted);display:flex;font-size:var(--font-size--small);padding-bottom:.1rem;text-decoration:none}ul.search{list-style:none;padding-left:0}ul.search li{border-bottom:1px solid var(--color-background-border);padding:1rem 0}[role=main] .highlighted{background-color:var(--color-highlighted-background);color:var(--color-highlighted-text)}.sidebar-brand{display:flex;flex-direction:column;flex-shrink:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none}.sidebar-brand-text{color:var(--color-sidebar-brand-text);font-size:1.5rem;overflow-wrap:break-word}.sidebar-brand-text,.sidebar-logo-container{margin:var(--sidebar-item-spacing-vertical) 0}.sidebar-logo{display:block;margin:0 auto;max-width:100%}.sidebar-search-container{align-items:center;background:var(--color-sidebar-search-background);display:flex;margin-top:var(--sidebar-search-space-above);position:relative}.sidebar-search-container:focus-within,.sidebar-search-container:hover{background:var(--color-sidebar-search-background--focus)}.sidebar-search-container:before{background-color:var(--color-sidebar-search-icon);content:"";height:var(--sidebar-search-icon-size);left:var(--sidebar-item-spacing-horizontal);-webkit-mask-image:var(--icon-search);mask-image:var(--icon-search);position:absolute;width:var(--sidebar-search-icon-size)}.sidebar-search{background:transparent;border:none;border-bottom:1px solid var(--color-sidebar-search-border);border-top:1px solid var(--color-sidebar-search-border);box-sizing:border-box;color:var(--color-sidebar-search-foreground);padding:var(--sidebar-search-input-spacing-vertical) var(--sidebar-search-input-spacing-horizontal) var(--sidebar-search-input-spacing-vertical) calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size));width:100%;z-index:10}.sidebar-search:focus{outline:none}.sidebar-search::-moz-placeholder{font-size:var(--sidebar-search-input-font-size)}.sidebar-search::placeholder{font-size:var(--sidebar-search-input-font-size)}#searchbox .highlight-link{margin:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0;text-align:center}#searchbox .highlight-link a{color:var(--color-sidebar-search-icon);font-size:var(--font-size--small--2)}.sidebar-tree{font-size:var(--sidebar-item-font-size);margin-bottom:var(--sidebar-item-spacing-vertical);margin-top:var(--sidebar-tree-space-above)}.sidebar-tree ul{display:flex;flex-direction:column;list-style:none;margin-bottom:0;margin-top:0;padding:0}.sidebar-tree li{margin:0;position:relative}.sidebar-tree li>ul{margin-left:var(--sidebar-item-spacing-horizontal)}.sidebar-tree .icon,.sidebar-tree .reference{color:var(--color-sidebar-link-text)}.sidebar-tree .reference{box-sizing:border-box;display:inline-block;height:100%;line-height:var(--sidebar-item-line-height);overflow-wrap:anywhere;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none;width:100%}.sidebar-tree .reference:hover{background:var(--color-sidebar-item-background--hover);color:var(--color-sidebar-link-text)}.sidebar-tree .reference.external:after{color:var(--color-sidebar-link-text);content:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23607D8B' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' viewBox='0 0 24 24'%3E%3Cpath stroke='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M11 7H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-5M10 14 20 4M15 4h5v5'/%3E%3C/svg%3E");margin:0 .25rem;vertical-align:middle}.sidebar-tree .current-page>.reference{font-weight:700}.sidebar-tree label{align-items:center;cursor:pointer;display:flex;height:var(--sidebar-item-height);justify-content:center;position:absolute;right:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:var(--sidebar-expander-width)}.sidebar-tree .caption,.sidebar-tree :not(.caption)>.caption-text{color:var(--color-sidebar-caption-text);font-size:var(--sidebar-caption-font-size);font-weight:700;margin:var(--sidebar-caption-space-above) 0 0 0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-transform:uppercase}.sidebar-tree li.has-children>.reference{padding-right:var(--sidebar-expander-width)}.sidebar-tree .toctree-l1>.reference,.sidebar-tree .toctree-l1>label .icon{color:var(--color-sidebar-link-text--top-level)}.sidebar-tree label{background:var(--color-sidebar-item-expander-background)}.sidebar-tree label:hover{background:var(--color-sidebar-item-expander-background--hover)}.sidebar-tree .current>.reference{background:var(--color-sidebar-item-background--current)}.sidebar-tree .current>.reference:hover{background:var(--color-sidebar-item-background--hover)}.toctree-checkbox{display:none;position:absolute}.toctree-checkbox~ul{display:none}.toctree-checkbox~label .icon svg{transform:rotate(90deg)}.toctree-checkbox:checked~ul{display:block}.toctree-checkbox:checked~label .icon svg{transform:rotate(-90deg)}.toc-title-container{padding:var(--toc-title-padding);padding-top:var(--toc-spacing-vertical)}.toc-title{color:var(--color-toc-title-text);font-size:var(--toc-title-font-size);padding-left:var(--toc-spacing-horizontal);text-transform:uppercase}.no-toc{display:none}.toc-tree-container{padding-bottom:var(--toc-spacing-vertical)}.toc-tree{border-left:1px solid var(--color-background-border);font-size:var(--toc-font-size);line-height:1.3;padding-left:calc(var(--toc-spacing-horizontal) - var(--toc-item-spacing-horizontal))}.toc-tree>ul>li:first-child{padding-top:0}.toc-tree>ul>li:first-child>ul{padding-left:0}.toc-tree>ul>li:first-child>a{display:none}.toc-tree ul{list-style-type:none;margin-bottom:0;margin-top:0;padding-left:var(--toc-item-spacing-horizontal)}.toc-tree li{padding-top:var(--toc-item-spacing-vertical)}.toc-tree li.scroll-current>.reference{color:var(--color-toc-item-text--active);font-weight:700}.toc-tree a.reference{color:var(--color-toc-item-text);overflow-wrap:anywhere;text-decoration:none}.toc-scroll{max-height:100vh;overflow-y:scroll}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here){background:rgba(255,0,0,.25);color:var(--color-problematic)}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here):before{content:"ERROR: Adding a table of contents in Furo-based documentation is unnecessary, and does not work well with existing styling. Add a 'this-will-duplicate-information-and-it-is-still-useful-here' class, if you want an escape hatch."}.text-align\:left>p{text-align:left}.text-align\:center>p{text-align:center}.text-align\:right>p{text-align:right} +/*# sourceMappingURL=furo.css.map*/ \ No newline at end of file diff --git a/releases/2.0.0/_static/styles/furo.css.map b/releases/2.0.0/_static/styles/furo.css.map new file mode 100644 index 0000000..3ecc371 --- /dev/null +++ b/releases/2.0.0/_static/styles/furo.css.map @@ -0,0 +1 @@ +{"version":3,"file":"styles/furo.css","mappings":"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sCAIA,aADF,WACE,CAKF,SACE,CAHJ,kBAEE,CAJE,gBAEJ,CAHI,iBAMA,yFAKA,aACA,eACA,cElbJ,iBAEE,aADA,iBACA,6BAEA,kCAEA,SACA,UAIA,gCACA,CALA,SAEA,SAEA,CAJA,0EAEA,CAFA,OAKA,CAGA,mDACE,iBAGF,gCACE,CADF,UACE,aAEJ,iCAEE,CAFF,UAEE,wCAEA,WACA,WADA,UACA,CACA,4CAGA,MACA,CADA,KACA,wCACA,UAGA,CAJA,UAIA,6DAUA,0CACE,CAFF,mBAEE,wEACA,CAVA,YACA,CAMF,mBAJE,OAOA,gBAJJ,gCACE,CANE,cACA,CAHA,oBACA,CAGA,QAGJ,CAII,0BACA,CADA,UACA,wCAEJ,kBACE,0DACA,gCACE,kBACA,CADA,YACA,oEACA,2CAMF,mDAII,CALN,YACE,CANE,cAKJ,CACE,iBAII,kEACA,yCACE,kDACA,yDACE,+CACA,uBANN,CAMM,+BANN,uCACE,qDACA,4BAEE,mBADA,0CACA,CADA,qBACA,0DACE,wCACA,sGALJ,oCACA,sBACE,kBAFF,UAEE,2CACA,wFACE,cACA,kEANN,uBACE,iDACA,CADA,UACA,0DACE,wDAEE,iEACA,qEANN,sCACE,CAGE,iBAHF,gBAGE,qBACE,CAJJ,uBACA,gDACE,wDACA,6DAHF,2CACA,CADA,gBACA,eACE,CAGE,sBANN,8BACE,CAII,iBAFF,4DACA,WACE,YADF,uCACE,6EACA,2BANN,8CACE,kDACA,0CACE,8BACA,yFACE,sBACA,sFALJ,mEACA,sBACE,kEACA,6EACE,uCACA,kEALJ,qGAEE,kEACA,6EACE,uCACA,kEALJ,8CACA,uDACE,sEACA,2EACE,sCACA,iEALJ,mGACA,qCACE,oDACA,0DACE,6GACA,gDAGR,yDCrEA,sEACE,CACA,6GACE,gEACF,iGAIF,wFACE,qDAGA,mGAEE,2CAEF,4FACE,gCACF,wGACE,8DAEE,6FAIA,iJAKN,6GACE,gDAKF,yDACA,qCAGA,6BACA,kBACA,qDAKA,oCAEA,+DAGA,2CAGE,oDAIA,oEAEE,qBAGJ,wDAEE,uCAEF,kE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","sources":["webpack:///./node_modules/normalize.css/normalize.css","webpack:///./src/furo/assets/styles/base/_print.sass","webpack:///./src/furo/assets/styles/base/_screen-readers.sass","webpack:///./src/furo/assets/styles/base/_theme.sass","webpack:///./src/furo/assets/styles/variables/_fonts.scss","webpack:///./src/furo/assets/styles/variables/_spacing.scss","webpack:///./src/furo/assets/styles/variables/_icons.scss","webpack:///./src/furo/assets/styles/variables/_admonitions.scss","webpack:///./src/furo/assets/styles/variables/_colors.scss","webpack:///./src/furo/assets/styles/base/_typography.sass","webpack:///./src/furo/assets/styles/_scaffold.sass","webpack:///./src/furo/assets/styles/variables/_layout.scss","webpack:///./src/furo/assets/styles/content/_admonitions.sass","webpack:///./src/furo/assets/styles/content/_api.sass","webpack:///./src/furo/assets/styles/content/_blocks.sass","webpack:///./src/furo/assets/styles/content/_captions.sass","webpack:///./src/furo/assets/styles/content/_code.sass","webpack:///./src/furo/assets/styles/content/_footnotes.sass","webpack:///./src/furo/assets/styles/content/_images.sass","webpack:///./src/furo/assets/styles/content/_indexes.sass","webpack:///./src/furo/assets/styles/content/_lists.sass","webpack:///./src/furo/assets/styles/content/_math.sass","webpack:///./src/furo/assets/styles/content/_misc.sass","webpack:///./src/furo/assets/styles/content/_rubrics.sass","webpack:///./src/furo/assets/styles/content/_sidebar.sass","webpack:///./src/furo/assets/styles/content/_tables.sass","webpack:///./src/furo/assets/styles/content/_target.sass","webpack:///./src/furo/assets/styles/content/_gui-labels.sass","webpack:///./src/furo/assets/styles/components/_footer.sass","webpack:///./src/furo/assets/styles/components/_sidebar.sass","webpack:///./src/furo/assets/styles/components/_table_of_contents.sass","webpack:///./src/furo/assets/styles/_shame.sass"],"sourcesContent":["/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */\n\n/* Document\n ========================================================================== */\n\n/**\n * 1. Correct the line height in all browsers.\n * 2. Prevent adjustments of font size after orientation changes in iOS.\n */\n\nhtml {\n line-height: 1.15; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/* Sections\n ========================================================================== */\n\n/**\n * Remove the margin in all browsers.\n */\n\nbody {\n margin: 0;\n}\n\n/**\n * Render the `main` element consistently in IE.\n */\n\nmain {\n display: block;\n}\n\n/**\n * Correct the font size and margin on `h1` elements within `section` and\n * `article` contexts in Chrome, Firefox, and Safari.\n */\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n/* Grouping content\n ========================================================================== */\n\n/**\n * 1. Add the correct box sizing in Firefox.\n * 2. Show the overflow in Edge and IE.\n */\n\nhr {\n box-sizing: content-box; /* 1 */\n height: 0; /* 1 */\n overflow: visible; /* 2 */\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\npre {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/* Text-level semantics\n ========================================================================== */\n\n/**\n * Remove the gray background on active links in IE 10.\n */\n\na {\n background-color: transparent;\n}\n\n/**\n * 1. Remove the bottom border in Chrome 57-\n * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n */\n\nabbr[title] {\n border-bottom: none; /* 1 */\n text-decoration: underline; /* 2 */\n text-decoration: underline dotted; /* 2 */\n}\n\n/**\n * Add the correct font weight in Chrome, Edge, and Safari.\n */\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/**\n * Add the correct font size in all browsers.\n */\n\nsmall {\n font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` elements from affecting the line height in\n * all browsers.\n */\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/* Embedded content\n ========================================================================== */\n\n/**\n * Remove the border on images inside links in IE 10.\n */\n\nimg {\n border-style: none;\n}\n\n/* Forms\n ========================================================================== */\n\n/**\n * 1. Change the font styles in all browsers.\n * 2. Remove the margin in Firefox and Safari.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n line-height: 1.15; /* 1 */\n margin: 0; /* 2 */\n}\n\n/**\n * Show the overflow in IE.\n * 1. Show the overflow in Edge.\n */\n\nbutton,\ninput { /* 1 */\n overflow: visible;\n}\n\n/**\n * Remove the inheritance of text transform in Edge, Firefox, and IE.\n * 1. Remove the inheritance of text transform in Firefox.\n */\n\nbutton,\nselect { /* 1 */\n text-transform: none;\n}\n\n/**\n * Correct the inability to style clickable types in iOS and Safari.\n */\n\nbutton,\n[type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\n/**\n * Remove the inner border and padding in Firefox.\n */\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n border-style: none;\n padding: 0;\n}\n\n/**\n * Restore the focus styles unset by the previous rule.\n */\n\nbutton:-moz-focusring,\n[type=\"button\"]:-moz-focusring,\n[type=\"reset\"]:-moz-focusring,\n[type=\"submit\"]:-moz-focusring {\n outline: 1px dotted ButtonText;\n}\n\n/**\n * Correct the padding in Firefox.\n */\n\nfieldset {\n padding: 0.35em 0.75em 0.625em;\n}\n\n/**\n * 1. Correct the text wrapping in Edge and IE.\n * 2. Correct the color inheritance from `fieldset` elements in IE.\n * 3. Remove the padding so developers are not caught out when they zero out\n * `fieldset` elements in all browsers.\n */\n\nlegend {\n box-sizing: border-box; /* 1 */\n color: inherit; /* 2 */\n display: table; /* 1 */\n max-width: 100%; /* 1 */\n padding: 0; /* 3 */\n white-space: normal; /* 1 */\n}\n\n/**\n * Add the correct vertical alignment in Chrome, Firefox, and Opera.\n */\n\nprogress {\n vertical-align: baseline;\n}\n\n/**\n * Remove the default vertical scrollbar in IE 10+.\n */\n\ntextarea {\n overflow: auto;\n}\n\n/**\n * 1. Add the correct box sizing in IE 10.\n * 2. Remove the padding in IE 10.\n */\n\n[type=\"checkbox\"],\n[type=\"radio\"] {\n box-sizing: border-box; /* 1 */\n padding: 0; /* 2 */\n}\n\n/**\n * Correct the cursor style of increment and decrement buttons in Chrome.\n */\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n/**\n * 1. Correct the odd appearance in Chrome and Safari.\n * 2. Correct the outline style in Safari.\n */\n\n[type=\"search\"] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/**\n * Remove the inner padding in Chrome and Safari on macOS.\n */\n\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n/**\n * 1. Correct the inability to style clickable types in iOS and Safari.\n * 2. Change font properties to `inherit` in Safari.\n */\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n}\n\n/* Interactive\n ========================================================================== */\n\n/*\n * Add the correct display in Edge, IE 10+, and Firefox.\n */\n\ndetails {\n display: block;\n}\n\n/*\n * Add the correct display in all browsers.\n */\n\nsummary {\n display: list-item;\n}\n\n/* Misc\n ========================================================================== */\n\n/**\n * Add the correct display in IE 10+.\n */\n\ntemplate {\n display: none;\n}\n\n/**\n * Add the correct display in IE 10.\n */\n\n[hidden] {\n display: none;\n}\n","// This file contains styles for managing print media.\n\n////////////////////////////////////////////////////////////////////////////////\n// Hide elements not relevant to print media.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Hide icon container.\n .content-icon-container\n display: none !important\n\n // Hide showing header links if hovering over when printing.\n .headerlink\n display: none !important\n\n // Hide mobile header.\n .mobile-header\n display: none !important\n\n // Hide navigation links.\n .related-pages\n display: none !important\n\n////////////////////////////////////////////////////////////////////////////////\n// Tweaks related to decolorization.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Apply a border around code which no longer have a color background.\n .highlight\n border: 0.1pt solid var(--color-foreground-border)\n\n////////////////////////////////////////////////////////////////////////////////\n// Avoid page break in some relevant cases.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n ul, ol, dl, a, table, pre, blockquote, p\n page-break-inside: avoid\n\n h1, h2, h3, h4, h5, h6, img, figure, caption\n page-break-inside: avoid\n page-break-after: avoid\n\n ul, ol, dl\n page-break-before: avoid\n",".visually-hidden\n position: absolute !important\n width: 1px !important\n height: 1px !important\n padding: 0 !important\n margin: -1px !important\n overflow: hidden !important\n clip: rect(0,0,0,0) !important\n white-space: nowrap !important\n border: 0 !important\n color: var(--color-foreground-primary)\n background: var(--color-background-primary)\n\n:-moz-focusring\n outline: auto\n","// This file serves as the \"skeleton\" of the theming logic.\n//\n// This contains the bulk of the logic for handling dark mode, color scheme\n// toggling and the handling of color-scheme-specific hiding of elements.\n\nbody\n @include fonts\n @include spacing\n @include icons\n @include admonitions\n @include default-admonition(#651fff, \"abstract\")\n @include default-topic(#14B8A6, \"pencil\")\n\n @include colors\n\n.only-light\n display: block !important\nhtml body .only-dark\n display: none !important\n\n// Ignore dark-mode hints if print media.\n@media not print\n // Enable dark-mode, if requested.\n body[data-theme=\"dark\"]\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n // Enable dark mode, unless explicitly told to avoid.\n @media (prefers-color-scheme: dark)\n body:not([data-theme=\"light\"])\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n//\n// Theme toggle presentation\n//\nbody[data-theme=\"auto\"]\n .theme-toggle svg.theme-icon-when-auto-light\n display: block\n\n @media (prefers-color-scheme: dark)\n .theme-toggle svg.theme-icon-when-auto-dark\n display: block\n .theme-toggle svg.theme-icon-when-auto-light\n display: none\n\nbody[data-theme=\"dark\"]\n .theme-toggle svg.theme-icon-when-dark\n display: block\n\nbody[data-theme=\"light\"]\n .theme-toggle svg.theme-icon-when-light\n display: block\n","// Fonts used by this theme.\n//\n// There are basically two things here -- using the system font stack and\n// defining sizes for various elements in %ages. We could have also used `em`\n// but %age is easier to reason about for me.\n\n@mixin fonts {\n // These are adapted from https://systemfontstack.com/\n --font-stack: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,\n sans-serif, Apple Color Emoji, Segoe UI Emoji;\n --font-stack--monospace: \"SFMono-Regular\", Menlo, Consolas, Monaco,\n Liberation Mono, Lucida Console, monospace;\n --font-stack--headings: var(--font-stack);\n\n --font-size--normal: 100%;\n --font-size--small: 87.5%;\n --font-size--small--2: 81.25%;\n --font-size--small--3: 75%;\n --font-size--small--4: 62.5%;\n\n // Sidebar\n --sidebar-caption-font-size: var(--font-size--small--2);\n --sidebar-item-font-size: var(--font-size--small);\n --sidebar-search-input-font-size: var(--font-size--small);\n\n // Table of Contents\n --toc-font-size: var(--font-size--small--3);\n --toc-font-size--mobile: var(--font-size--normal);\n --toc-title-font-size: var(--font-size--small--4);\n\n // Admonitions\n //\n // These aren't defined in terms of %ages, since nesting these is permitted.\n --admonition-font-size: 0.8125rem;\n --admonition-title-font-size: 0.8125rem;\n\n // Code\n --code-font-size: var(--font-size--small--2);\n\n // API\n --api-font-size: var(--font-size--small);\n}\n","// Spacing for various elements on the page\n//\n// If the user wants to tweak things in a certain way, they are permitted to.\n// They also have to deal with the consequences though!\n\n@mixin spacing {\n // Header!\n --header-height: calc(\n var(--sidebar-item-line-height) + 4 * #{var(--sidebar-item-spacing-vertical)}\n );\n --header-padding: 0.5rem;\n\n // Sidebar\n --sidebar-tree-space-above: 1.5rem;\n --sidebar-caption-space-above: 1rem;\n\n --sidebar-item-line-height: 1rem;\n --sidebar-item-spacing-vertical: 0.5rem;\n --sidebar-item-spacing-horizontal: 1rem;\n --sidebar-item-height: calc(\n var(--sidebar-item-line-height) + 2 *#{var(--sidebar-item-spacing-vertical)}\n );\n\n --sidebar-expander-width: var(--sidebar-item-height); // be square\n\n --sidebar-search-space-above: 0.5rem;\n --sidebar-search-input-spacing-vertical: 0.5rem;\n --sidebar-search-input-spacing-horizontal: 0.5rem;\n --sidebar-search-input-height: 1rem;\n --sidebar-search-icon-size: var(--sidebar-search-input-height);\n\n // Table of Contents\n --toc-title-padding: 0.25rem 0;\n --toc-spacing-vertical: 1.5rem;\n --toc-spacing-horizontal: 1.5rem;\n --toc-item-spacing-vertical: 0.4rem;\n --toc-item-spacing-horizontal: 1rem;\n}\n","// Expose theme icons as CSS variables.\n\n$icons: (\n // Adapted from tabler-icons\n // url: https://tablericons.com/\n \"search\":\n url('data:image/svg+xml;charset=utf-8,'),\n // Factored out from mkdocs-material on 24-Aug-2020.\n // url: https://squidfunk.github.io/mkdocs-material/reference/admonitions/\n \"pencil\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"abstract\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"info\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"flame\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"question\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"warning\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"failure\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"spark\":\n url('data:image/svg+xml;charset=utf-8,')\n);\n\n@mixin icons {\n @each $name, $glyph in $icons {\n --icon-#{$name}: #{$glyph};\n }\n}\n","// Admonitions\n\n// Structure of these is:\n// admonition-class: color \"icon-name\";\n//\n// The colors are translated into CSS variables below. The icons are\n// used directly in the main declarations to set the `mask-image` in\n// the title.\n\n// prettier-ignore\n$admonitions: (\n // Each of these has an reST directives for it.\n \"caution\": #ff9100 \"spark\",\n \"warning\": #ff9100 \"warning\",\n \"danger\": #ff5252 \"spark\",\n \"attention\": #ff5252 \"warning\",\n \"error\": #ff5252 \"failure\",\n \"hint\": #00c852 \"question\",\n \"tip\": #00c852 \"info\",\n \"important\": #00bfa5 \"flame\",\n \"note\": #00b0ff \"pencil\",\n \"seealso\": #448aff \"info\",\n \"admonition-todo\": #808080 \"pencil\"\n);\n\n@mixin default-admonition($color, $icon-name) {\n --color-admonition-title: #{$color};\n --color-admonition-title-background: #{rgba($color, 0.2)};\n\n --icon-admonition-default: var(--icon-#{$icon-name});\n}\n\n@mixin default-topic($color, $icon-name) {\n --color-topic-title: #{$color};\n --color-topic-title-background: #{rgba($color, 0.2)};\n\n --icon-topic-default: var(--icon-#{$icon-name});\n}\n\n@mixin admonitions {\n @each $name, $values in $admonitions {\n --color-admonition-title--#{$name}: #{nth($values, 1)};\n --color-admonition-title-background--#{$name}: #{rgba(\n nth($values, 1),\n 0.2\n )};\n }\n}\n","// Colors used throughout this theme.\n//\n// The aim is to give the user more control. Thus, instead of hard-coding colors\n// in various parts of the stylesheet, the approach taken is to define all\n// colors as CSS variables and reusing them in all the places.\n//\n// `colors-dark` depends on `colors` being included at a lower specificity.\n\n@mixin colors {\n --color-problematic: #b30000;\n\n // Base Colors\n --color-foreground-primary: black; // for main text and headings\n --color-foreground-secondary: #5a5c63; // for secondary text\n --color-foreground-muted: #6b6f76; // for muted text\n --color-foreground-border: #878787; // for content borders\n\n --color-background-primary: white; // for content\n --color-background-secondary: #f8f9fb; // for navigation + ToC\n --color-background-hover: #efeff4ff; // for navigation-item hover\n --color-background-hover--transparent: #efeff400;\n --color-background-border: #eeebee; // for UI borders\n --color-background-item: #ccc; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #0a4bff;\n --color-brand-content: #2757dd;\n --color-brand-visited: #872ee0;\n\n // API documentation\n --color-api-background: var(--color-background-hover--transparent);\n --color-api-background-hover: var(--color-background-hover);\n --color-api-overall: var(--color-foreground-secondary);\n --color-api-name: var(--color-problematic);\n --color-api-pre-name: var(--color-problematic);\n --color-api-paren: var(--color-foreground-secondary);\n --color-api-keyword: var(--color-foreground-primary);\n\n --color-api-added: #21632c;\n --color-api-added-border: #38a84d;\n --color-api-changed: #046172;\n --color-api-changed-border: #06a1bc;\n --color-api-deprecated: #605706;\n --color-api-deprecated-border: #f0d90f;\n --color-api-removed: #b30000;\n --color-api-removed-border: #ff5c5c;\n\n --color-highlight-on-target: #ffffcc;\n\n // Inline code background\n --color-inline-code-background: var(--color-background-secondary);\n\n // Highlighted text (search)\n --color-highlighted-background: #ddeeff;\n --color-highlighted-text: var(--color-foreground-primary);\n\n // GUI Labels\n --color-guilabel-background: #ddeeff80;\n --color-guilabel-border: #bedaf580;\n --color-guilabel-text: var(--color-foreground-primary);\n\n // Admonitions!\n --color-admonition-background: transparent;\n\n //////////////////////////////////////////////////////////////////////////////\n // Everything below this should be one of:\n // - var(...)\n // - *-gradient(...)\n // - special literal values (eg: transparent, none)\n //////////////////////////////////////////////////////////////////////////////\n\n // Tables\n --color-table-header-background: var(--color-background-secondary);\n --color-table-border: var(--color-background-border);\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: transparent;\n --color-card-marginals-background: var(--color-background-secondary);\n\n // Header\n --color-header-background: var(--color-background-primary);\n --color-header-border: var(--color-background-border);\n --color-header-text: var(--color-foreground-primary);\n\n // Sidebar (left)\n --color-sidebar-background: var(--color-background-secondary);\n --color-sidebar-background-border: var(--color-background-border);\n\n --color-sidebar-brand-text: var(--color-foreground-primary);\n --color-sidebar-caption-text: var(--color-foreground-muted);\n --color-sidebar-link-text: var(--color-foreground-secondary);\n --color-sidebar-link-text--top-level: var(--color-brand-primary);\n\n --color-sidebar-item-background: var(--color-sidebar-background);\n --color-sidebar-item-background--current: var(\n --color-sidebar-item-background\n );\n --color-sidebar-item-background--hover: linear-gradient(\n 90deg,\n var(--color-background-hover--transparent) 0%,\n var(--color-background-hover) var(--sidebar-item-spacing-horizontal),\n var(--color-background-hover) 100%\n );\n\n --color-sidebar-item-expander-background: transparent;\n --color-sidebar-item-expander-background--hover: var(\n --color-background-hover\n );\n\n --color-sidebar-search-text: var(--color-foreground-primary);\n --color-sidebar-search-background: var(--color-background-secondary);\n --color-sidebar-search-background--focus: var(--color-background-primary);\n --color-sidebar-search-border: var(--color-background-border);\n --color-sidebar-search-icon: var(--color-foreground-muted);\n\n // Table of Contents (right)\n --color-toc-background: var(--color-background-primary);\n --color-toc-title-text: var(--color-foreground-muted);\n --color-toc-item-text: var(--color-foreground-secondary);\n --color-toc-item-text--hover: var(--color-foreground-primary);\n --color-toc-item-text--active: var(--color-brand-primary);\n\n // Actual page contents\n --color-content-foreground: var(--color-foreground-primary);\n --color-content-background: transparent;\n\n // Links\n --color-link: var(--color-brand-content);\n --color-link-underline: var(--color-background-border);\n --color-link--hover: var(--color-brand-content);\n --color-link-underline--hover: var(--color-foreground-border);\n\n --color-link--visited: var(--color-brand-visited);\n --color-link-underline--visited: var(--color-background-border);\n --color-link--visited--hover: var(--color-brand-visited);\n --color-link-underline--visited--hover: var(--color-foreground-border);\n}\n\n@mixin colors-dark {\n --color-problematic: #ee5151;\n\n // Base Colors\n --color-foreground-primary: #cfd0d0; // for main text and headings\n --color-foreground-secondary: #9ca0a5; // for secondary text\n --color-foreground-muted: #81868d; // for muted text\n --color-foreground-border: #666666; // for content borders\n\n --color-background-primary: #131416; // for content\n --color-background-secondary: #1a1c1e; // for navigation + ToC\n --color-background-hover: #1e2124ff; // for navigation-item hover\n --color-background-hover--transparent: #1e212400;\n --color-background-border: #303335; // for UI borders\n --color-background-item: #444; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #3d94ff;\n --color-brand-content: #5ca5ff;\n --color-brand-visited: #b27aeb;\n\n // Highlighted text (search)\n --color-highlighted-background: #083563;\n\n // GUI Labels\n --color-guilabel-background: #08356380;\n --color-guilabel-border: #13395f80;\n\n // API documentation\n --color-api-keyword: var(--color-foreground-secondary);\n --color-highlight-on-target: #333300;\n\n --color-api-added: #3db854;\n --color-api-added-border: #267334;\n --color-api-changed: #09b0ce;\n --color-api-changed-border: #056d80;\n --color-api-deprecated: #b1a10b;\n --color-api-deprecated-border: #6e6407;\n --color-api-removed: #ff7575;\n --color-api-removed-border: #b03b3b;\n\n // Admonitions\n --color-admonition-background: #18181a;\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: #18181a;\n --color-card-marginals-background: var(--color-background-hover);\n}\n","// This file contains the styling for making the content throughout the page,\n// including fonts, paragraphs, headings and spacing among these elements.\n\nbody\n font-family: var(--font-stack)\npre,\ncode,\nkbd,\nsamp\n font-family: var(--font-stack--monospace)\n\n// Make fonts look slightly nicer.\nbody\n -webkit-font-smoothing: antialiased\n -moz-osx-font-smoothing: grayscale\n\n// Line height from Bootstrap 4.1\narticle\n line-height: 1.5\n\n//\n// Headings\n//\nh1,\nh2,\nh3,\nh4,\nh5,\nh6\n line-height: 1.25\n font-family: var(--font-stack--headings)\n font-weight: bold\n\n border-radius: 0.5rem\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n margin-left: -0.5rem\n margin-right: -0.5rem\n padding-left: 0.5rem\n padding-right: 0.5rem\n\n + p\n margin-top: 0\n\nh1\n font-size: 2.5em\n margin-top: 1.75rem\n margin-bottom: 1rem\nh2\n font-size: 2em\n margin-top: 1.75rem\nh3\n font-size: 1.5em\nh4\n font-size: 1.25em\nh5\n font-size: 1.125em\nh6\n font-size: 1em\n\nsmall\n opacity: 75%\n font-size: 80%\n\n// Paragraph\np\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n\n// Horizontal rules\nhr.docutils\n height: 1px\n padding: 0\n margin: 2rem 0\n background-color: var(--color-background-border)\n border: 0\n\n.centered\n text-align: center\n\n// Links\na\n text-decoration: underline\n\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n &:visited\n color: var(--color-link--visited)\n text-decoration-color: var(--color-link-underline--visited)\n &:hover\n color: var(--color-link--visited--hover)\n text-decoration-color: var(--color-link-underline--visited--hover)\n\n &:hover\n color: var(--color-link--hover)\n text-decoration-color: var(--color-link-underline--hover)\n &.muted-link\n color: inherit\n &:hover\n color: var(--color-link--hover)\n text-decoration-color: var(--color-link-underline--hover)\n &:visited\n color: var(--color-link--visited--hover)\n text-decoration-color: var(--color-link-underline--visited--hover)\n","// This file contains the styles for the overall layouting of the documentation\n// skeleton, including the responsive changes as well as sidebar toggles.\n//\n// This is implemented as a mobile-last design, which isn't ideal, but it is\n// reasonably good-enough and I got pretty tired by the time I'd finished this\n// to move the rules around to fix this. Shouldn't take more than 3-4 hours,\n// if you know what you're doing tho.\n\n// HACK: Not all browsers account for the scrollbar width in media queries.\n// This results in horizontal scrollbars in the breakpoint where we go\n// from displaying everything to hiding the ToC. We accomodate for this by\n// adding a bit of padding to the TOC drawer, disabling the horizontal\n// scrollbar and allowing the scrollbars to cover the padding.\n// https://www.456bereastreet.com/archive/201301/media_query_width_and_vertical_scrollbars/\n\n// HACK: Always having the scrollbar visible, prevents certain browsers from\n// causing the content to stutter horizontally between taller-than-viewport and\n// not-taller-than-viewport pages.\n\nhtml\n overflow-x: hidden\n overflow-y: scroll\n scroll-behavior: smooth\n\n.sidebar-scroll, .toc-scroll, article[role=main] *\n // Override Firefox scrollbar style\n scrollbar-width: thin\n scrollbar-color: var(--color-foreground-border) transparent\n\n // Override Chrome scrollbar styles\n &::-webkit-scrollbar\n width: 0.25rem\n height: 0.25rem\n &::-webkit-scrollbar-thumb\n background-color: var(--color-foreground-border)\n border-radius: 0.125rem\n\n//\n// Overalls\n//\nhtml,\nbody\n height: 100%\n color: var(--color-foreground-primary)\n background: var(--color-background-primary)\n\n.skip-to-content\n position: fixed\n padding: 1rem\n border-radius: 1rem\n left: 0.25rem\n top: 0.25rem\n z-index: 40\n background: var(--color-background-primary)\n color: var(--color-foreground-primary)\n\n transform: translateY(-200%)\n transition: transform 300ms ease-in-out\n\n &:focus-within\n transform: translateY(0%)\n\narticle\n color: var(--color-content-foreground)\n background: var(--color-content-background)\n overflow-wrap: break-word\n\n.page\n display: flex\n // fill the viewport for pages with little content.\n min-height: 100%\n\n.mobile-header\n width: 100%\n height: var(--header-height)\n background-color: var(--color-header-background)\n color: var(--color-header-text)\n border-bottom: 1px solid var(--color-header-border)\n\n // Looks like sub-script/super-script have this, and we need this to\n // be \"on top\" of those.\n z-index: 10\n\n // We don't show the header on large screens.\n display: none\n\n // Add shadow when scrolled\n &.scrolled\n border-bottom: none\n box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.4rem rgba(0, 0, 0, 0.2)\n\n .header-center\n a\n color: var(--color-header-text)\n text-decoration: none\n\n.main\n display: flex\n flex: 1\n\n// Sidebar (left) also covers the entire left portion of screen.\n.sidebar-drawer\n box-sizing: border-box\n\n border-right: 1px solid var(--color-sidebar-background-border)\n background: var(--color-sidebar-background)\n\n display: flex\n justify-content: flex-end\n // These next two lines took me two days to figure out.\n width: calc((100% - #{$full-width}) / 2 + #{$sidebar-width})\n min-width: $sidebar-width\n\n// Scroll-along sidebars\n.sidebar-container,\n.toc-drawer\n box-sizing: border-box\n width: $sidebar-width\n\n.toc-drawer\n background: var(--color-toc-background)\n // See HACK described on top of this document\n padding-right: 1rem\n\n.sidebar-sticky,\n.toc-sticky\n position: sticky\n top: 0\n height: min(100%, 100vh)\n height: 100vh\n\n display: flex\n flex-direction: column\n\n.sidebar-scroll,\n.toc-scroll\n flex-grow: 1\n flex-shrink: 1\n\n overflow: auto\n scroll-behavior: smooth\n\n// Central items.\n.content\n padding: 0 $content-padding\n width: $content-width\n\n display: flex\n flex-direction: column\n justify-content: space-between\n\n.icon\n display: inline-block\n height: 1rem\n width: 1rem\n svg\n width: 100%\n height: 100%\n\n//\n// Accommodate announcement banner\n//\n.announcement\n background-color: var(--color-announcement-background)\n color: var(--color-announcement-text)\n\n height: var(--header-height)\n display: flex\n align-items: center\n overflow-x: auto\n & + .page\n min-height: calc(100% - var(--header-height))\n\n.announcement-content\n box-sizing: border-box\n padding: 0.5rem\n min-width: 100%\n white-space: nowrap\n text-align: center\n\n a\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-announcement-text)\n\n &:hover\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-link--hover)\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for theme\n////////////////////////////////////////////////////////////////////////////////\n.no-js .theme-toggle-container // don't show theme toggle if there's no JS\n display: none\n\n.theme-toggle-container\n display: flex\n\n.theme-toggle\n display: flex\n cursor: pointer\n border: none\n padding: 0\n background: transparent\n\n.theme-toggle svg\n height: 1.25rem\n width: 1.25rem\n color: var(--color-foreground-primary)\n display: none\n\n.theme-toggle-header\n display: flex\n align-items: center\n justify-content: center\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for elements\n////////////////////////////////////////////////////////////////////////////////\n.toc-overlay-icon, .nav-overlay-icon\n display: none\n cursor: pointer\n\n .icon\n color: var(--color-foreground-secondary)\n height: 1.5rem\n width: 1.5rem\n\n.toc-header-icon, .nav-overlay-icon\n // for when we set display: flex\n justify-content: center\n align-items: center\n\n.toc-content-icon\n height: 1.5rem\n width: 1.5rem\n\n.content-icon-container\n float: right\n display: flex\n margin-top: 1.5rem\n margin-left: 1rem\n margin-bottom: 1rem\n gap: 0.5rem\n\n .edit-this-page, .view-this-page\n svg\n color: inherit\n height: 1.25rem\n width: 1.25rem\n\n.sidebar-toggle\n position: absolute\n display: none\n// \n.sidebar-toggle[name=\"__toc\"]\n left: 20px\n.sidebar-toggle:checked\n left: 40px\n// \n\n.overlay\n position: fixed\n top: 0\n width: 0\n height: 0\n\n transition: width 0ms, height 0ms, opacity 250ms ease-out\n\n opacity: 0\n background-color: rgba(0, 0, 0, 0.54)\n.sidebar-overlay\n z-index: 20\n.toc-overlay\n z-index: 40\n\n// Keep things on top and smooth.\n.sidebar-drawer\n z-index: 30\n transition: left 250ms ease-in-out\n.toc-drawer\n z-index: 50\n transition: right 250ms ease-in-out\n\n// Show the Sidebar\n#__navigation:checked\n & ~ .sidebar-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .sidebar-drawer\n top: 0\n left: 0\n // Show the toc sidebar\n#__toc:checked\n & ~ .toc-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .toc-drawer\n top: 0\n right: 0\n\n////////////////////////////////////////////////////////////////////////////////\n// Back to top\n////////////////////////////////////////////////////////////////////////////////\n.back-to-top\n text-decoration: none\n\n display: none\n position: fixed\n left: 0\n top: 1rem\n padding: 0.5rem\n padding-right: 0.75rem\n border-radius: 1rem\n font-size: 0.8125rem\n\n background: var(--color-background-primary)\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), #6b728080 0px 0px 1px 0px\n\n z-index: 10\n\n margin-left: 50%\n transform: translateX(-50%)\n svg\n height: 1rem\n width: 1rem\n fill: currentColor\n display: inline-block\n\n span\n margin-left: 0.25rem\n\n .show-back-to-top &\n display: flex\n align-items: center\n\n////////////////////////////////////////////////////////////////////////////////\n// Responsive layouting\n////////////////////////////////////////////////////////////////////////////////\n// Make things a bit bigger on bigger screens.\n@media (min-width: $full-width + $sidebar-width)\n html\n font-size: 110%\n\n@media (max-width: $full-width)\n // Collapse \"toc\" into the icon.\n .toc-content-icon\n display: flex\n .toc-drawer\n position: fixed\n height: 100vh\n top: 0\n right: -$sidebar-width\n border-left: 1px solid var(--color-background-muted)\n .toc-tree\n border-left: none\n font-size: var(--toc-font-size--mobile)\n\n // Accomodate for a changed content width.\n .sidebar-drawer\n width: calc((100% - #{$full-width - $sidebar-width}) / 2 + #{$sidebar-width})\n\n@media (max-width: $content-padded-width + $sidebar-width)\n // Center the page\n .content\n margin-left: auto\n margin-right: auto\n padding: 0 $content-padding--small\n\n@media (max-width: $content-padded-width--small + $sidebar-width)\n // Collapse \"navigation\".\n .nav-overlay-icon\n display: flex\n .sidebar-drawer\n position: fixed\n height: 100vh\n width: $sidebar-width\n\n top: 0\n left: -$sidebar-width\n\n // Swap which icon is visible.\n .toc-header-icon, .theme-toggle-header\n display: flex\n .toc-content-icon, .theme-toggle-content\n display: none\n\n // Show the header.\n .mobile-header\n position: sticky\n top: 0\n display: flex\n justify-content: space-between\n align-items: center\n\n .header-left,\n .header-right\n display: flex\n height: var(--header-height)\n padding: 0 var(--header-padding)\n label\n height: 100%\n width: 100%\n user-select: none\n\n .nav-overlay-icon .icon,\n .theme-toggle svg\n height: 1.5rem\n width: 1.5rem\n\n // Add a scroll margin for the content\n :target\n scroll-margin-top: calc(var(--header-height) + 2.5rem)\n\n // Show back-to-top below the header\n .back-to-top\n top: calc(var(--header-height) + 0.5rem)\n\n // Accommodate for the header.\n .page\n flex-direction: column\n justify-content: center\n\n@media (max-width: $content-width + 2* $content-padding--small)\n // Content should respect window limits.\n .content\n width: 100%\n overflow-x: auto\n\n@media (max-width: $content-width)\n article[role=main] aside.sidebar\n float: none\n width: 100%\n margin: 1rem 0\n","// Overall Layout Variables\n//\n// Because CSS variables can't be used in media queries. The fact that this\n// makes the layout non-user-configurable is a good thing.\n$content-padding: 3em;\n$content-padding--small: 1em;\n$content-width: 46em;\n$sidebar-width: 15em;\n$content-padded-width: $content-width + 2 * $content-padding;\n$content-padded-width--small: $content-width + 2 * $content-padding--small;\n$full-width: $content-padded-width + 2 * $sidebar-width;\n","//\n// The design here is strongly inspired by mkdocs-material.\n.admonition, .topic\n margin: 1rem auto\n padding: 0 0.5rem 0.5rem 0.5rem\n\n background: var(--color-admonition-background)\n\n border-radius: 0.2rem\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n font-size: var(--admonition-font-size)\n\n overflow: hidden\n page-break-inside: avoid\n\n // First element should have no margin, since the title has it.\n > :nth-child(2)\n margin-top: 0\n\n // Last item should have no margin, since we'll control that w/ padding\n > :last-child\n margin-bottom: 0\n\n.admonition p.admonition-title,\np.topic-title\n position: relative\n margin: 0 -0.5rem 0.5rem\n padding-left: 2rem\n padding-right: .5rem\n padding-top: .4rem\n padding-bottom: .4rem\n\n font-weight: 500\n font-size: var(--admonition-title-font-size)\n line-height: 1.3\n\n // Our fancy icon\n &::before\n content: \"\"\n position: absolute\n left: 0.5rem\n width: 1rem\n height: 1rem\n\n// Default styles\np.admonition-title\n background-color: var(--color-admonition-title-background)\n &::before\n background-color: var(--color-admonition-title)\n mask-image: var(--icon-admonition-default)\n mask-repeat: no-repeat\n\np.topic-title\n background-color: var(--color-topic-title-background)\n &::before\n background-color: var(--color-topic-title)\n mask-image: var(--icon-topic-default)\n mask-repeat: no-repeat\n\n//\n// Variants\n//\n.admonition\n border-left: 0.2rem solid var(--color-admonition-title)\n\n @each $type, $value in $admonitions\n &.#{$type}\n border-left-color: var(--color-admonition-title--#{$type})\n > .admonition-title\n background-color: var(--color-admonition-title-background--#{$type})\n &::before\n background-color: var(--color-admonition-title--#{$type})\n mask-image: var(--icon-#{nth($value, 2)})\n\n.admonition-todo > .admonition-title\n text-transform: uppercase\n","// This file stylizes the API documentation (stuff generated by autodoc). It's\n// deeply nested due to how autodoc structures the HTML without enough classes\n// to select the relevant items.\n\n// API docs!\ndl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)\n // Tweak the spacing of all the things!\n dd\n margin-left: 2rem\n > :first-child\n margin-top: 0.125rem\n > :last-child\n margin-bottom: 0.75rem\n\n // This is used for the arguments\n .field-list\n margin-bottom: 0.75rem\n\n // \"Headings\" (like \"Parameters\" and \"Return\")\n > dt\n text-transform: uppercase\n font-size: var(--font-size--small)\n\n dd:empty\n margin-bottom: 0.5rem\n dd > ul\n margin-left: -1.2rem\n > li\n > p:nth-child(2)\n margin-top: 0\n // When the last-empty-paragraph follows a paragraph, it doesn't need\n // to augument the existing spacing.\n > p + p:last-child:empty\n margin-top: 0\n margin-bottom: 0\n\n // Colorize the elements\n > dt\n color: var(--color-api-overall)\n\n.sig:not(.sig-inline)\n font-weight: bold\n\n font-size: var(--api-font-size)\n font-family: var(--font-stack--monospace)\n\n margin-left: -0.25rem\n margin-right: -0.25rem\n padding-top: 0.25rem\n padding-bottom: 0.25rem\n padding-right: 0.5rem\n\n // These are intentionally em, to properly match the font size.\n padding-left: 3em\n text-indent: -2.5em\n\n border-radius: 0.25rem\n\n background: var(--color-api-background)\n transition: background 100ms ease-out\n\n &:hover\n background: var(--color-api-background-hover)\n\n // adjust the size of the [source] link on the right.\n a.reference\n .viewcode-link\n font-weight: normal\n width: 4.25rem\n\nem.property\n font-style: normal\n &:first-child\n color: var(--color-api-keyword)\n.sig-name\n color: var(--color-api-name)\n.sig-prename\n font-weight: normal\n color: var(--color-api-pre-name)\n.sig-paren\n color: var(--color-api-paren)\n.sig-param\n font-style: normal\n\ndiv.versionadded,\ndiv.versionchanged,\ndiv.deprecated,\ndiv.versionremoved\n border-left: 0.1875rem solid\n border-radius: 0.125rem\n\n padding-left: 0.75rem\n\n p\n margin-top: 0.125rem\n margin-bottom: 0.125rem\n\ndiv.versionadded\n border-color: var(--color-api-added-border)\n .versionmodified\n color: var(--color-api-added)\n\ndiv.versionchanged\n border-color: var(--color-api-changed-border)\n .versionmodified\n color: var(--color-api-changed)\n\ndiv.deprecated\n border-color: var(--color-api-deprecated-border)\n .versionmodified\n color: var(--color-api-deprecated)\n\ndiv.versionremoved\n border-color: var(--color-api-removed-border)\n .versionmodified\n color: var(--color-api-removed)\n\n// Align the [docs] and [source] to the right.\n.viewcode-link, .viewcode-back\n float: right\n text-align: right\n",".line-block\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n .line-block\n margin-top: 0rem\n margin-bottom: 0rem\n padding-left: 1rem\n","// Captions\narticle p.caption,\ntable > caption,\n.code-block-caption\n font-size: var(--font-size--small)\n text-align: center\n\n// Caption above a TOCTree\n.toctree-wrapper.compound\n .caption, :not(.caption) > .caption-text\n font-size: var(--font-size--small)\n text-transform: uppercase\n\n text-align: initial\n margin-bottom: 0\n\n > ul\n margin-top: 0\n margin-bottom: 0\n","// Inline code\ncode.literal, .sig-inline\n background: var(--color-inline-code-background)\n border-radius: 0.2em\n // Make the font smaller, and use padding to recover.\n font-size: var(--font-size--small--2)\n padding: 0.1em 0.2em\n\n pre.literal-block &\n font-size: inherit\n padding: 0\n\n p &\n border: 1px solid var(--color-background-border)\n\n.sig-inline\n font-family: var(--font-stack--monospace)\n\n// Code and Literal Blocks\n$code-spacing-vertical: 0.625rem\n$code-spacing-horizontal: 0.875rem\n\n// Wraps every literal block + line numbers.\ndiv[class*=\" highlight-\"],\ndiv[class^=\"highlight-\"]\n margin: 1em 0\n display: flex\n\n .table-wrapper\n margin: 0\n padding: 0\n\npre\n margin: 0\n padding: 0\n overflow: auto\n\n // Needed to have more specificity than pygments' \"pre\" selector. :(\n article[role=\"main\"] .highlight &\n line-height: 1.5\n\n &.literal-block,\n .highlight &\n font-size: var(--code-font-size)\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n // Make it look like all the other blocks.\n &.literal-block\n margin-top: 1rem\n margin-bottom: 1rem\n\n border-radius: 0.2rem\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n\n// All code is always contained in this.\n.highlight\n width: 100%\n border-radius: 0.2rem\n\n // Make line numbers and prompts un-selectable.\n .gp, span.linenos\n user-select: none\n pointer-events: none\n\n // Expand the line-highlighting.\n .hll\n display: block\n margin-left: -$code-spacing-horizontal\n margin-right: -$code-spacing-horizontal\n padding-left: $code-spacing-horizontal\n padding-right: $code-spacing-horizontal\n\n/* Make code block captions be nicely integrated */\n.code-block-caption\n display: flex\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n border-radius: 0.25rem\n border-bottom-left-radius: 0\n border-bottom-right-radius: 0\n font-weight: 300\n border-bottom: 1px solid\n\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n border-color: var(--color-background-border)\n\n + div[class]\n margin-top: 0\n pre\n border-top-left-radius: 0\n border-top-right-radius: 0\n\n// When `html_codeblock_linenos_style` is table.\n.highlighttable\n width: 100%\n display: block\n tbody\n display: block\n\n tr\n display: flex\n\n // Line numbers\n td.linenos\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n padding: $code-spacing-vertical $code-spacing-horizontal\n padding-right: 0\n border-top-left-radius: 0.2rem\n border-bottom-left-radius: 0.2rem\n\n .linenodiv\n padding-right: $code-spacing-horizontal\n font-size: var(--code-font-size)\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n\n // Actual code\n td.code\n padding: 0\n display: block\n flex: 1\n overflow: hidden\n\n .highlight\n border-top-left-radius: 0\n border-bottom-left-radius: 0\n\n// When `html_codeblock_linenos_style` is inline.\n.highlight\n span.linenos\n display: inline-block\n padding-left: 0\n padding-right: $code-spacing-horizontal\n margin-right: $code-spacing-horizontal\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n","// Inline Footnote Reference\n.footnote-reference\n font-size: var(--font-size--small--4)\n vertical-align: super\n\n// Definition list, listing the content of each note.\n// docutils <= 0.17\ndl.footnote.brackets\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\n display: grid\n grid-template-columns: max-content auto\n dt\n margin: 0\n > .fn-backref\n margin-left: 0.25rem\n\n &:after\n content: \":\"\n\n .brackets\n &:before\n content: \"[\"\n &:after\n content: \"]\"\n\n dd\n margin: 0\n padding: 0 1rem\n\n// docutils >= 0.18\naside.footnote\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\naside.footnote > span,\ndiv.citation > span\n float: left\n font-weight: 500\n padding-right: 0.25rem\n\naside.footnote > *:not(span),\ndiv.citation > p\n margin-left: 2rem\n","//\n// Figures\n//\nimg\n box-sizing: border-box\n max-width: 100%\n height: auto\n\narticle\n figure, .figure\n border-radius: 0.2rem\n\n margin: 0\n :last-child\n margin-bottom: 0\n\n .align-left\n float: left\n clear: left\n margin: 0 1rem 1rem\n\n .align-right\n float: right\n clear: right\n margin: 0 1rem 1rem\n\n .align-default,\n .align-center\n display: block\n text-align: center\n margin-left: auto\n margin-right: auto\n\n // WELL, table needs to be stylised like a table.\n table.align-default\n display: table\n text-align: initial\n",".genindex-jumpbox, .domainindex-jumpbox\n border-top: 1px solid var(--color-background-border)\n border-bottom: 1px solid var(--color-background-border)\n padding: 0.25rem\n\n.genindex-section, .domainindex-section\n h2\n margin-top: 0.75rem\n margin-bottom: 0.5rem\n ul\n margin-top: 0\n margin-bottom: 0\n","ul,\nol\n padding-left: 1.2rem\n\n // Space lists out like paragraphs\n margin-top: 1rem\n margin-bottom: 1rem\n // reduce margins within li.\n li\n > p:first-child\n margin-top: 0.25rem\n margin-bottom: 0.25rem\n\n > p:last-child\n margin-top: 0.25rem\n\n > ul,\n > ol\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n\nol\n &.arabic\n list-style: decimal\n &.loweralpha\n list-style: lower-alpha\n &.upperalpha\n list-style: upper-alpha\n &.lowerroman\n list-style: lower-roman\n &.upperroman\n list-style: upper-roman\n\n// Don't space lists out when they're \"simple\" or in a `.. toctree::`\n.simple,\n.toctree-wrapper\n li\n > ul,\n > ol\n margin-top: 0\n margin-bottom: 0\n\n// Definition Lists\n.field-list,\n.option-list,\ndl:not([class]),\ndl.simple,\ndl.footnote,\ndl.glossary\n dt\n font-weight: 500\n margin-top: 0.25rem\n + dt\n margin-top: 0\n\n .classifier::before\n content: \":\"\n margin-left: 0.2rem\n margin-right: 0.2rem\n\n dd\n > p:first-child,\n ul\n margin-top: 0.125rem\n\n ul\n margin-bottom: 0.125rem\n",".math-wrapper\n width: 100%\n overflow-x: auto\n\ndiv.math\n position: relative\n text-align: center\n\n .headerlink,\n &:focus .headerlink\n display: none\n\n &:hover .headerlink\n display: inline-block\n\n span.eqno\n position: absolute\n right: 0.5rem\n top: 50%\n transform: translate(0, -50%)\n z-index: 1\n","// Abbreviations\nabbr[title]\n cursor: help\n\n// \"Problematic\" content, as identified by Sphinx\n.problematic\n color: var(--color-problematic)\n\n// Keyboard / Mouse \"instructions\"\nkbd:not(.compound)\n margin: 0 0.2rem\n padding: 0 0.2rem\n border-radius: 0.2rem\n border: 1px solid var(--color-foreground-border)\n color: var(--color-foreground-primary)\n vertical-align: text-bottom\n\n font-size: var(--font-size--small--3)\n display: inline-block\n\n box-shadow: 0 0.0625rem 0 rgba(0, 0, 0, 0.2), inset 0 0 0 0.125rem var(--color-background-primary)\n\n background-color: var(--color-background-secondary)\n\n// Blockquote\nblockquote\n border-left: 4px solid var(--color-background-border)\n background: var(--color-background-secondary)\n\n margin-left: 0\n margin-right: 0\n padding: 0.5rem 1rem\n\n .attribution\n font-weight: 600\n text-align: right\n\n &.pull-quote,\n &.highlights\n font-size: 1.25em\n\n &.epigraph,\n &.pull-quote\n border-left-width: 0\n border-radius: 0.5rem\n\n &.highlights\n border-left-width: 0\n background: transparent\n\n// Center align embedded-in-text images\np .reference img\n vertical-align: middle\n","p.rubric\n line-height: 1.25\n font-weight: bold\n font-size: 1.125em\n\n // For Numpy-style documentation that's got rubrics within it.\n // https://github.com/pradyunsg/furo/discussions/505\n dd &\n line-height: inherit\n font-weight: inherit\n\n font-size: var(--font-size--small)\n text-transform: uppercase\n","article .sidebar\n float: right\n clear: right\n width: 30%\n\n margin-left: 1rem\n margin-right: 0\n\n border-radius: 0.2rem\n background-color: var(--color-background-secondary)\n border: var(--color-background-border) 1px solid\n\n > *\n padding-left: 1rem\n padding-right: 1rem\n\n > ul, > ol // lists need additional padding, because bullets.\n padding-left: 2.2rem\n\n .sidebar-title\n margin: 0\n padding: 0.5rem 1rem\n border-bottom: var(--color-background-border) 1px solid\n\n font-weight: 500\n\n// TODO: subtitle\n// TODO: dedicated variables?\n","[role=main] .table-wrapper.container\n width: 100%\n overflow-x: auto\n margin-top: 1rem\n margin-bottom: 0.5rem\n padding: 0.2rem 0.2rem 0.75rem\n\ntable.docutils\n border-radius: 0.2rem\n border-spacing: 0\n border-collapse: collapse\n\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n th\n background: var(--color-table-header-background)\n\n td,\n th\n // Space things out properly\n padding: 0 0.25rem\n\n // Get the borders looking just-right.\n border-left: 1px solid var(--color-table-border)\n border-right: 1px solid var(--color-table-border)\n border-bottom: 1px solid var(--color-table-border)\n\n p\n margin: 0.25rem\n\n &:first-child\n border-left: none\n &:last-child\n border-right: none\n\n // MyST-parser tables set these classes for control of column alignment\n &.text-left\n text-align: left\n &.text-right\n text-align: right\n &.text-center\n text-align: center\n",":target\n scroll-margin-top: 2.5rem\n\n@media (max-width: $full-width - $sidebar-width)\n :target\n scroll-margin-top: calc(2.5rem + var(--header-height))\n\n // When a heading is selected\n section > span:target\n scroll-margin-top: calc(2.8rem + var(--header-height))\n\n// Permalinks\n.headerlink\n font-weight: 100\n user-select: none\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\ndl dt,\np.caption,\nfigcaption p,\ntable > caption,\n.code-block-caption\n > .headerlink\n margin-left: 0.5rem\n visibility: hidden\n &:hover > .headerlink\n visibility: visible\n\n // Don't change to link-like, if someone adds the contents directive.\n > .toc-backref\n color: inherit\n text-decoration-line: none\n\n// Figure and table captions are special.\nfigure:hover > figcaption > p > .headerlink,\ntable:hover > caption > .headerlink\n visibility: visible\n\n:target >, // Regular section[id] style anchors\nspan:target ~ // Non-regular span[id] style \"extra\" anchors\n h1,\n h2,\n h3,\n h4,\n h5,\n h6\n &:nth-of-type(1)\n background-color: var(--color-highlight-on-target)\n // .headerlink\n // visibility: visible\n code.literal\n background-color: transparent\n\ntable:target > caption,\nfigure:target\n background-color: var(--color-highlight-on-target)\n\n// Inline page contents\n.this-will-duplicate-information-and-it-is-still-useful-here li :target\n background-color: var(--color-highlight-on-target)\n\n// Code block permalinks\n.literal-block-wrapper:target .code-block-caption\n background-color: var(--color-highlight-on-target)\n\n// When a definition list item is selected\n//\n// There isn't really an alternative to !important here, due to the\n// high-specificity of API documentation's selector.\ndt:target\n background-color: var(--color-highlight-on-target) !important\n\n// When a footnote reference is selected\n.footnote > dt:target + dd,\n.footnote-reference:target\n background-color: var(--color-highlight-on-target)\n",".guilabel\n background-color: var(--color-guilabel-background)\n border: 1px solid var(--color-guilabel-border)\n color: var(--color-guilabel-text)\n\n padding: 0 0.3em\n border-radius: 0.5em\n font-size: 0.9em\n","// This file contains the styles used for stylizing the footer that's shown\n// below the content.\n\nfooter\n font-size: var(--font-size--small)\n display: flex\n flex-direction: column\n\n margin-top: 2rem\n\n// Bottom of page information\n.bottom-of-page\n display: flex\n align-items: center\n justify-content: space-between\n\n margin-top: 1rem\n padding-top: 1rem\n padding-bottom: 1rem\n\n color: var(--color-foreground-secondary)\n border-top: 1px solid var(--color-background-border)\n\n line-height: 1.5\n\n @media (max-width: $content-width)\n text-align: center\n flex-direction: column-reverse\n gap: 0.25rem\n\n .left-details\n font-size: var(--font-size--small)\n\n .right-details\n display: flex\n flex-direction: column\n gap: 0.25rem\n text-align: right\n\n .icons\n display: flex\n justify-content: flex-end\n gap: 0.25rem\n font-size: 1rem\n\n a\n text-decoration: none\n\n svg,\n img\n font-size: 1.125rem\n height: 1em\n width: 1em\n\n// Next/Prev page information\n.related-pages\n a\n display: flex\n align-items: center\n\n text-decoration: none\n &:hover .page-info .title\n text-decoration: underline\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n svg.furo-related-icon,\n svg.furo-related-icon > use\n flex-shrink: 0\n\n color: var(--color-foreground-border)\n\n width: 0.75rem\n height: 0.75rem\n margin: 0 0.5rem\n\n &.next-page\n max-width: 50%\n\n float: right\n clear: right\n text-align: right\n\n &.prev-page\n max-width: 50%\n\n float: left\n clear: left\n\n svg\n transform: rotate(180deg)\n\n.page-info\n display: flex\n flex-direction: column\n overflow-wrap: anywhere\n\n .next-page &\n align-items: flex-end\n\n .context\n display: flex\n align-items: center\n\n padding-bottom: 0.1rem\n\n color: var(--color-foreground-muted)\n font-size: var(--font-size--small)\n text-decoration: none\n","// This file contains the styles for the contents of the left sidebar, which\n// contains the navigation tree, logo, search etc.\n\n////////////////////////////////////////////////////////////////////////////////\n// Brand on top of the scrollable tree.\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-brand\n display: flex\n flex-direction: column\n flex-shrink: 0\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n text-decoration: none\n\n.sidebar-brand-text\n color: var(--color-sidebar-brand-text)\n overflow-wrap: break-word\n margin: var(--sidebar-item-spacing-vertical) 0\n font-size: 1.5rem\n\n.sidebar-logo-container\n margin: var(--sidebar-item-spacing-vertical) 0\n\n.sidebar-logo\n margin: 0 auto\n display: block\n max-width: 100%\n\n////////////////////////////////////////////////////////////////////////////////\n// Search\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-search-container\n display: flex\n align-items: center\n margin-top: var(--sidebar-search-space-above)\n\n position: relative\n\n background: var(--color-sidebar-search-background)\n &:hover,\n &:focus-within\n background: var(--color-sidebar-search-background--focus)\n\n &::before\n content: \"\"\n position: absolute\n left: var(--sidebar-item-spacing-horizontal)\n width: var(--sidebar-search-icon-size)\n height: var(--sidebar-search-icon-size)\n\n background-color: var(--color-sidebar-search-icon)\n mask-image: var(--icon-search)\n\n.sidebar-search\n box-sizing: border-box\n\n border: none\n border-top: 1px solid var(--color-sidebar-search-border)\n border-bottom: 1px solid var(--color-sidebar-search-border)\n\n padding-top: var(--sidebar-search-input-spacing-vertical)\n padding-bottom: var(--sidebar-search-input-spacing-vertical)\n padding-right: var(--sidebar-search-input-spacing-horizontal)\n padding-left: calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size))\n\n width: 100%\n\n color: var(--color-sidebar-search-foreground)\n background: transparent\n z-index: 10\n\n &:focus\n outline: none\n\n &::placeholder\n font-size: var(--sidebar-search-input-font-size)\n\n//\n// Hide Search Matches link\n//\n#searchbox .highlight-link\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0\n margin: 0\n text-align: center\n\n a\n color: var(--color-sidebar-search-icon)\n font-size: var(--font-size--small--2)\n\n////////////////////////////////////////////////////////////////////////////////\n// Structure/Skeleton of the navigation tree (left)\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-tree\n font-size: var(--sidebar-item-font-size)\n margin-top: var(--sidebar-tree-space-above)\n margin-bottom: var(--sidebar-item-spacing-vertical)\n\n ul\n padding: 0\n margin-top: 0\n margin-bottom: 0\n\n display: flex\n flex-direction: column\n\n list-style: none\n\n li\n position: relative\n margin: 0\n\n > ul\n margin-left: var(--sidebar-item-spacing-horizontal)\n\n .icon\n color: var(--color-sidebar-link-text)\n\n .reference\n box-sizing: border-box\n color: var(--color-sidebar-link-text)\n\n // Fill the parent.\n display: inline-block\n line-height: var(--sidebar-item-line-height)\n text-decoration: none\n\n // Don't allow long words to cause wrapping.\n overflow-wrap: anywhere\n\n height: 100%\n width: 100%\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n &:hover\n color: var(--color-sidebar-link-text)\n background: var(--color-sidebar-item-background--hover)\n\n // Add a nice little \"external-link\" arrow here.\n &.external::after\n content: url('data:image/svg+xml,')\n margin: 0 0.25rem\n vertical-align: middle\n color: var(--color-sidebar-link-text)\n\n // Make the current page reference bold.\n .current-page > .reference\n font-weight: bold\n\n label\n position: absolute\n top: 0\n right: 0\n height: var(--sidebar-item-height)\n width: var(--sidebar-expander-width)\n\n cursor: pointer\n user-select: none\n\n display: flex\n justify-content: center\n align-items: center\n\n .caption, :not(.caption) > .caption-text\n font-size: var(--sidebar-caption-font-size)\n color: var(--color-sidebar-caption-text)\n\n font-weight: bold\n text-transform: uppercase\n\n margin: var(--sidebar-caption-space-above) 0 0 0\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n // If it has children, add a bit more padding to wrap the content to avoid\n // overlapping with the

    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�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