"git@developer.sourcefind.cn:gaoqiong/migraphx.git" did not exist on "af7e6eaae561b3e72ad277b6f8d4540b2423708f"
Unverified Commit 91d9a797 authored by Yuge Zhang's avatar Yuge Zhang Committed by GitHub
Browse files

Adopt symbolic links in Chinese documentation (#4345)


Co-authored-by: default avatarjiahangxu <jiahangxu@microsoft.com>
parent 0e0ee86d
.. role:: raw-html(raw)
:format: html
并行化顺序算法:TPE
========================================
为了利用多个计算节点,TPE 方法是异步运行的,这样能避免浪费时间等待 Trial 评估的完成。 TPE 方法使用了叫做 constant liar 的方法:每次候选点 x* 生成时,会临时分配一个假的评估结果 y。在评估完成后,用返回的真实损失值 f(x*) 来替换假的评估结果。
介绍和问题
-------------------------
基于顺序模型的全局优化
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
基于顺序模型的全局优化(SMBO)算法已经用于许多应用中,但适应度函数的评估成本比较高。 在应用中,真实的适应度函数 f: X → R 评估成本较高,通过采用基于模型算法近似的 f 来替代,可降低其评估成本。 通常,在 SMBO 算法内层循环是用数值优化或其它转换方式来替代。 点 x* 最大化的替代项(或它的转换形式)作为真实函数 f 评估的替代值。 这种类似于主动学习的算法模板总结如下。 SMBO 算法的不同之处在于,给定一个 f 的模型(或替代项)的情况下,获得 x* 的优化的标准,以及通过观察历史 H 来模拟 f。
.. image:: ../../img/parallel_tpe_search4.PNG
:target: ../../img/parallel_tpe_search4.PNG
:alt:
本算法优化了预期改进(Expected Improvement,EI)的标准。 其它建议的标准包括,概率改进(Probability of Improvement)、预期改进(Expected Improvement)最小化条件熵(minimizing the Conditional Entropy of the Minimizer)、以及 bandit-based 的标准。 在 TPE 中考虑到直观,选择了 EI,其在多种设置下都展示了较好的效果。 预期改进(EI)是在模型 M 下,当 f(x) (负向)超过某个阈值 y* 时,对 f 的预期:X → RN。
.. image:: ../../img/parallel_tpe_search_ei.PNG
:target: ../../img/parallel_tpe_search_ei.PNG
:alt:
由于 p(y|x) 计算成本较高,TPE 通过 p(x|y) 和 p(y) 来为 p(y|x) 建模。TPE 通过下列两个密度来定义 p(x|y):
.. image:: ../../img/parallel_tpe_search_tpe.PNG
:target: ../../img/parallel_tpe_search_tpe.PNG
:alt:
l(x) 是通过观察 {x(i)} 来形成的密度,使得相应的损失 f(x(i)) 小于 y∗,
而 g(x) 是使用剩余的观测值来形成的密度。 TPE 算法取决于 y∗ 大于观测到的最好的 f(x),这样可以使用一些点来形成 l(x)。 TPE 算法选择了 y* 来作为一些观测值 y 的分位数 γ,因此 p(y<\ ``y∗``\ ) = γ,但不需要为特定的 p(y) 建模。 l 和 g 的树形结构使得根据 l 来计算多个候选项变得容易,可根据 g(x)/l(x) 来进行评估。 在每次迭代中,算法返回了具有最大 EI 的候选 x*。
这是 TPE 算法在二维搜索空间上的模拟。 不同的背景色表示了不同的值。 可以看出,TPE 在探索(exploration)和挖掘(exploitation)方面的表现都很好。 (黑色表示此轮样本的点,黄色表示历史点。)
.. image:: ../../img/parallel_tpe_search1.gif
:target: ../../img/parallel_tpe_search1.gif
:alt:
**由于 EI 是连续函数,因此 EI 的最高 x 在某个状态下是确定的 。** 如下图所示,蓝色三角形表示在当前状态下最有可能进行采样的点。
.. image:: ../../img/parallel_tpe_search_ei2.PNG
:target: ../../img/parallel_tpe_search_ei2.PNG
:alt:
TPE 在顺序执行时表现很好,但当并发性较大时,会 **在相同的 EI 状态下产生大量的点**,过于集中的点会减少 Tuner 探索的能力,造成了资源的浪费。
这是当 ``concurrency=60`` 时的模拟图,这种现象非常明显。
.. image:: ../../img/parallel_tpe_search2.gif
:target: ../../img/parallel_tpe_search2.gif
:alt:
研究的解决方案
-----------------
近似 q-EI 最大化
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
下面介绍的多点标准的新的 Experiment 设计一步解决此优化问题。
.. image:: ../../img/parallel_tpe_search_qEI.PNG
:target: ../../img/parallel_tpe_search_qEI.PNG
:alt:
但是,当 q 增加时,q-EI 的计算变得很密集。 研究发现,四种流行的贪心策略可在解决此问题时,减少计算成本。
方案 1: Believing the OK Predictor: KB(Kriging Believer) 启发式策略
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Kriging Believer 策略用等价于 Kriging 预测期望值的确定性值替换在最后一次迭代中选择的位置的响应的条件知识。 保持与上次相同的记号,此策略可归纳如下:
.. image:: ../../img/parallel_tpe_search_kb.PNG
:target: ../../img/parallel_tpe_search_kb.PNG
:alt:
这种顺序策略使用了 q-points 设计,在计算量上是可承受的,因为它依赖于分析已知的 EI,在 d 维上进行了优化。 但此方法有失败的风险,因为相信 OK Predictor 可以预测超过观察到的数据,可能导致多轮迭代中的序列会陷入非最优区域。 第二种策略可降低这种风险。
方案 2: CL(Constant Liar) 启发式策略
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
考虑一种顺序策略,在每次迭代时会更新元模型(但不会重新估计超参),其中值 L 来自外部固定值,称为”lie(谎言)”。 Constant Liar 策略在每次迭代时使用相同的值 L:最大化 EI(即找到 xn+1),将模型实现为 y(xn+1) = L, 始终使用 L∈R:
.. image:: ../../img/parallel_tpe_search_cl.PNG
:target: ../../img/parallel_tpe_search_cl.PNG
:alt:
L 应在逻辑上根据 y 在 X 处获取的值来确定,可考虑使用的三个值:min{Y}, mean{Y}, 以及 max{Y}。 **L 越大,算法的探索性就越大,反之亦然。**
根据上述方法进行模拟。 下图显示了使用均值 liar,来最大化 q-EI。 能看到这些点开始分散了。
.. image:: ../../img/parallel_tpe_search3.gif
:target: ../../img/parallel_tpe_search3.gif
:alt:
实验
----------
Branin-Hoo
^^^^^^^^^^
最后一章介绍的四种优化方法通过 Branin-Hoo 函数进行了比较,这是全局优化中的经典测试用例。
.. image:: ../../img/parallel_tpe_search_branin.PNG
:target: ../../img/parallel_tpe_search_branin.PNG
:alt:
a, b, c, r, s 以及 t 的推荐值分别为:a = 1, b = 5.1 ⁄ (4π2), c = 5 ⁄ π, r = 6, s = 10, t = 1 ⁄ (8π)。 此函数有三个全局最小值点 (-3.14, 12.27), (3.14, 2.27), (9.42, 2.47)。
下表为给定 constant liar 策略(最小、最大值)下,比较了前 q 个点(q ∈ [1,10])。每个 q 绘制 2000 个 q 点,这 2000 个 q 点随机采用 LHS。
.. image:: ../../img/parallel_tpe_search_result.PNG
:target: ../../img/parallel_tpe_search_result.PNG
:alt:
正如图中所见,,CL[max] 和 CL[min] 与随机相比,产生了更好的 q-EI 结果,尤其是 q 值很小时。
高斯混合模型函数(Gaussian Mixed Model function)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
以下比较了使用和不使用并行优化的情况。 二维多模的高斯混合分布的模拟结果如下:
.. list-table::
:header-rows: 1
:widths: auto
* -
- concurrency=80
- concurrency=60
- concurrency=40
- concurrency=20
- concurrency=10
* - 未使用并行优化
- avg = 0.4841 :raw-html:`<br>` var = 0.1953
- avg = 0.5155 :raw-html:`<br>` var = 0.2219
- avg = 0.5773 :raw-html:`<br>` var = 0.2570
- avg = 0.4680 :raw-html:`<br>` var = 0.1994
- avg = 0.2774 :raw-html:`<br>` var = 0.1217
* - 未使用并行优化
- avg = 0.2132 :raw-html:`<br>` var = 0.0700
- avg = 0.2177\ :raw-html:`<br>`\ var = 0.0796
- avg = 0.1835 :raw-html:`<br>` var = 0.0533
- avg = 0.1671 :raw-html:`<br>` var = 0.0413
- avg = 0.1918 :raw-html:`<br>` var = 0.0697
注意:每次测试的样本总数为 240(确保成本相等)。 每种形式下的 Trial 重复了 1000 次,表中值为 1000 个 Trial 中最好结果的平均值和方差。
参考
----------
[1] James Bergstra, Remi Bardenet, Yoshua Bengio, Balazs Kegl. `Algorithms for Hyper-Parameter Optimization. <https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf>`__
[2] Meng-Hiot Lim, Yew-Soon Ong. `Computational Intelligence in Expensive Optimization Problems. <https://link.springer.com/content/pdf/10.1007%2F978-3-642-10701-6.pdf>`__
[3] M. Jordan, J. Kleinberg, B. Scho¨lkopf. `Pattern Recognition and Machine Learning. <http://users.isr.ist.utl.pt/~wurmd/Livros/school/Bishop%20-%20Pattern%20Recognition%20And%20Machine%20Learning%20-%20Springer%20%202006.pdf>`__
../../en_US/CommunitySharings/ParallelizingTpeSearch.rst
\ No newline at end of file
自动调优 SVD(在推荐系统中使用 NNI)
==============================================
本教程中,会首先介绍 GitHub 存储库:`推荐系统 <https://github.com/Microsoft/Recommenders>`__。 它使用 Jupyter Notebook 提供了构建推荐系统的一些示例和实践技巧。 其中大量的模型被广泛的应用于推荐系统中。 为了提供完整的体验,每个示例都通过以下五个关键任务中展示:
* `准备数据 <https://github.com/microsoft/recommenders/tree/master/examples/01_prepare_data>`__\ : 为每个算法准备并读取数据。
* 模型(`协同过滤算法 <https://github.com/microsoft/recommenders/tree/master/examples/02_model_collaborative_filtering>`__\ , `基于内容的过滤算法 <https://github.com/microsoft/recommenders/tree/master/examples/02_model_content_based_filtering>`__\ , `混合算法 <https://github.com/microsoft/recommenders/tree/master/examples/02_model_hybrid>`__\ ): 使用多种经典的和深度学习推荐算法来构建模型,比如 Alternating Least Squares (\ `ALS <https://spark.apache.org/docs/latest/api/python/_modules/pyspark/ml/recommendation.html#ALS>`__\ ) 或者 eXtreme Deep Factorization Machines (\ `xDeepFM <https://arxiv.org/abs/1803.05170>`__\ ).
* `评估 <https://github.com/microsoft/recommenders/tree/master/examples/03_evaluate>`__\ :使用离线指标来评估算法。
* `模型选择和优化 <https://github.com/microsoft/recommenders/tree/master/examples/04_model_select_and_optimize>`__\:为推荐算法模型调优超参。
* `运营 <https://github.com/microsoft/recommenders/tree/master/examples/05_operationalize>`__\ :在 Azure 的生产环境上运行模型。
在第四项调优模型超参的任务上,NNI 可以发挥作用。 在 NNI 上调优推荐模型的具体示例,采用了 `SVD <https://github.com/microsoft/recommenders/blob/master/examples/02_model_collaborative_filtering/surprise_svd_deep_dive.ipynb>`__\ 算法,以及数据集 Movielens100k。 此模型有超过 10 个超参需要调优。
由 Recommenders 提供的 `Jupyter notebook <https://github.com/microsoft/recommenders/blob/master/examples/04_model_select_and_optimize/nni_surprise_svd.ipynb>`__ 中有非常详细的一步步的教程。 其中使用了不同的调优函数,包括 ``Annealing``\ , ``SMAC``\ , ``Random Search``\ , ``TPE``\ , ``Hyperband``\ , ``Metis`` 和 ``Evolution``。 最后比较了不同调优算法的结果。 请参考此 Notebook,来学习如何使用 NNI 调优 SVD 模型,并可以继续使用 NNI 来调优 Recommenders 中的其它模型。
../../en_US/CommunitySharings/RecommendersSvd.rst
\ No newline at end of file
使用 NNI 为 SPTAG 自动调参
===================================
`SPTAG <https://github.com/microsoft/SPTAG>`__ (Space Partition Tree And Graph) 是大规模向量的最近邻搜索的工具,由 `微软研究院 (MSR) <https://www.msra.cn/>`__ 和 `微软必应团队 <https://www.bing.com/>`__ 联合发布。
此工具假设样本可以表示为向量,并且能通过 L2 或余弦算法来比较距离。 输入一个查询向量,会返回与其 L2 或余弦距离最小的一组向量。
SPTAG 提供了两种方法:kd-tree 与其的相关近邻图 (SPTAG-KDT),以及平衡 k-means 树与其的相关近邻图 (SPTAG-BKT)。 SPTAG-KDT 在索引构建效率上较好,而 SPTAG-BKT 在搜索高维度数据的精度上较好。
在 SPTAG中,有几十个参数可以根据特定的场景或数据集进行调优。 NNI 是用来自动化调优这些参数的绝佳工具。 SPTAG 的作者尝试了使用 NNI 来进行自动调优,并轻松找到了性能较好的参数组合,并在 SPTAG `文档 <https://github.com/microsoft/SPTAG/blob/master/docs/Parameters.md>`__ 中进行了分享。 参考此文档了解详细教程。
../../en_US/CommunitySharings/SptagAutoTune.rst
\ No newline at end of file
.. 21be18c35dee2702eb1c7a805dcfd939
######################
自动模型调优
######################
......
.. e0791b39c8c362669300ce55b42e997b
#######################
自动系统调优
#######################
......
#######################
用例与解决方案
#######################
与文档其他部分中展示功能用法的教程和示例不同,本部分主要介绍端到端方案和用例,以帮助用户进一步了解NNI如何为他们提供帮助。 NNI 可广泛应用于各种场景。 除了官方的教程和示例之外,也支持社区贡献者分享自己的自动机器学习实践经验,特别是使用 NNI 的实践经验。
用例与解决方案
=======================
.. toctree::
:maxdepth: 2
自动模型调优(HPO/NAS)<automodel>
自动系统调优(AutoSys)<autosys>
模型压缩<model_compression>
特征工程<feature_engineering>
性能测量,比较和分析<perf_compare>
在 Google Colab 中使用 NNI <NNI_colab_support>
自动补全 nnictl 命令 <AutoCompletion>
外部代码库
====================================
经作者许可的一些 NNI 用法示例和相关文档。
外部代码库
=====================
* 使用 NNI 的 `矩阵分解超参调优 <https://github.com/microsoft/recommenders/blob/master/examples/04_model_select_and_optimize/nni_surprise_svd.ipynb>`__ 。
* `使用 NNI 为 scikit-learn 开发的超参搜索 - 2019年11月6日 <https://towardsdatascience.com/find-thy-hyper-parameters-for-scikit-learn-pipelines-using-microsoft-nni-f1015b1224c1>`__
相关文章
=================
* `使用AdaptDL 和 NNI进行经济高效的超参调优 - 2021年2月23日 <https://medium.com/casl-project/cost-effective-hyper-parameter-tuning-using-adaptdl-with-nni-e55642888761>`__
* `(中文博客)NNI v2.0 新功能概述 - 2021年1月21日 <https://www.msra.cn/zh-cn/news/features/nni-2>`__
* `(中文博客)2019年 NNI 新功能概览 - 2019年12月26日 <https://mp.weixin.qq.com/s/7_KRT-rRojQbNuJzkjFMuA>`__
* 使用 NNI 为 scikit-learn 开发的超参搜索 `scikit-nni <https://github.com/ksachdeva/scikit-nni>`__ 。
* `(中文博客)自动机器学习工具(Advisor、NNI 和 Google Vizier)对比 - 2019年8月5日 <http://gaocegege.com/Blog/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/katib-new#%E6%80%BB%E7%BB%93%E4%B8%8E%E5%88%86%E6%9E%90>`__
* `超参优化的对比 <./HpoComparison.rst>`__
* `神经网络架构搜索对比 <./NasComparison.rst>`__
* `TPE 并行化顺序算法 <./ParallelizingTpeSearch.rst>`__
* `自动调优 SVD(在推荐系统中使用 NNI ) <./RecommendersSvd.rst>`__
* `使用 NNI 为 SPTAG 自动调参 <./SptagAutoTune.rst>`__
../../en_US/CommunitySharings/community_sharings.rst
\ No newline at end of file
.. 6b887244cf8fbace30971173f8c6fe8a
###################
特征工程
###################
......
.. 8a4c54c8127199ad4c95e20247e33fe2
#################
模型压缩
#################
......
.. 7d625bd21018f53834e9db08a619c494
################################################
性能测量,比较和分析
################################################
......
使用 NNI Experiment 自动压缩
================================================
如果你想压缩你的模型,但不知道该选择什么压缩算法,或者不知道什么稀疏度适合你的模型,或者只是想尝试更多的可能性,自动压缩可能会帮助你。
用户可以选择不同的压缩算法,并定义算法的搜索空间,然后自动压缩将启动一个 NNI 实验,并自动尝试不同稀疏度的压缩算法。
当然,除了稀疏度之外,用户还可以在搜索空间中引入其他相关参数。
如果你不知道什么是搜索空间或如何编写搜索空间,可以参考 `此教程 <./Tutorial/SearchSpaceSpec.rst>`__ 。
在 Python 中使用自动压缩与 NNI Experiment 很相似。
主要区别如下:
* 使用生成器帮助生成搜索空间对象
* 需要提供要压缩的模型,并且模型应该已经过预训练
* 不需要设置 ``trial_command``,需要额外设置 ``auto_compress_module`` 作为 ``AutoCompressionExperiment`` 的输入。
生成搜索空间
---------------------
由于大量使用嵌套搜索空间,我们建议使用生成器来配置搜索空间。
示例如下: 使用 ``add_config()`` 增加子配置,然后 ``dumps()`` 搜索空间字典。
.. code-block:: python
from nni.algorithms.compression.pytorch.auto_compress import AutoCompressionSearchSpaceGenerator
generator = AutoCompressionSearchSpaceGenerator()
generator.add_config('level', [
{
"sparsity": {
"_type": "uniform",
"_value": [0.01, 0.99]
},
'op_types': ['default']
}
])
generator.add_config('qat', [
{
'quant_types': ['weight', 'output'],
'quant_bits': {
'weight': 8,
'output': 8
},
'op_types': ['Conv2d', 'Linear']
}])
search_space = generator.dumps()
目前我们支持以下 Pruner 和 Quantizer:
.. code-block:: python
PRUNER_DICT = {
'level': LevelPruner,
'slim': SlimPruner,
'l1': L1FilterPruner,
'l2': L2FilterPruner,
'fpgm': FPGMPruner,
'taylorfo': TaylorFOWeightFilterPruner,
'apoz': ActivationAPoZRankFilterPruner,
'mean_activation': ActivationMeanRankFilterPruner
}
QUANTIZER_DICT = {
'naive': NaiveQuantizer,
'qat': QAT_Quantizer,
'dorefa': DoReFaQuantizer,
'bnn': BNNQuantizer
}
提供用户模型进行压缩
----------------------------------------------
用户需要继承 ``AbstractAutoCompressionModule`` 并重写抽象类的函数。
.. code-block:: python
from nni.algorithms.compression.pytorch.auto_compress import AbstractAutoCompressionModule
class AutoCompressionModule(AbstractAutoCompressionModule):
@classmethod
def model(cls) -> nn.Module:
...
return _model
@classmethod
def evaluator(cls) -> Callable[[nn.Module], float]:
...
return _evaluator
用户至少需要实现 ``model()`` 和 ``evaluator()``。
如果使用迭代 Pruner,则需要额外实现 ``optimizer_factory()``, ``criterion()`` 和 ``sparsifying_trainer()``。
如果要在压缩后对模型进行微调,则需要实现 ``optimizer_factory()``, ``criterion()``, ``post_compress_finetuning_trainer()`` 和 ``post_compress_finetuning_epochs()``。
``optimizer_factory()`` 应该返回一个工厂函数,输入是一个可迭代变量,即, 你的 ``model.parameters()``,输出是 optimizer 实例。
这两种 ``trainer()`` 应该返回一个输出为 ``model, optimizer, criterion, current_epoch`` 的 Trainer。
完整的抽象接口在 :githublink:`interface.py <nni/algorithms/compression/pytorch/auto_compress/interface.py>`。
``AutoCompressionModule`` 实施的例子参考 :githublink:`auto_compress_module.py <examples/model_compress/auto_compress/torch/auto_compress_module.py>`。
发起 NNI Experiment
---------------------
类似于从 python 启动,区别是不需要设置 ``trial_command`` 并把用户提供的 ``AutoCompressionModule`` 作为 ``AutoCompressionExperiment`` 的输入。
.. code-block:: python
from pathlib import Path
from nni.algorithms.compression.pytorch.auto_compress import AutoCompressionExperiment
from auto_compress_module import AutoCompressionModule
experiment = AutoCompressionExperiment(AutoCompressionModule, 'local')
experiment.config.experiment_name = 'auto compression torch example'
experiment.config.trial_concurrency = 1
experiment.config.max_trial_number = 10
experiment.config.search_space = search_space
experiment.config.trial_code_directory = Path(__file__).parent
experiment.config.tuner.name = 'TPE'
experiment.config.tuner.class_args['optimize_mode'] = 'maximize'
experiment.config.training_service.use_active_gpu = True
experiment.run(8088)
../../en_US/Compression/AutoCompression.rst
\ No newline at end of file
模型压缩 API 参考
=============================================
.. contents::
Compressors
-----------
Compressor
^^^^^^^^^^
.. autoclass:: nni.compression.pytorch.compressor.Compressor
:members:
.. autoclass:: nni.compression.pytorch.compressor.Pruner
:members:
.. autoclass:: nni.compression.pytorch.compressor.Quantizer
:members:
Module 的包装
^^^^^^^^^^^^^^
.. autoclass:: nni.compression.pytorch.compressor.PrunerModuleWrapper
:members:
.. autoclass:: nni.compression.pytorch.compressor.QuantizerModuleWrapper
:members:
权重掩码
^^^^^^^^^^^^^
.. autoclass:: nni.algorithms.compression.pytorch.pruning.weight_masker.WeightMasker
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.structured_pruning_masker.StructuredWeightMasker
:members:
Pruners
^^^^^^^
.. autoclass:: nni.algorithms.compression.pytorch.pruning.sensitivity_pruner.SensitivityPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.one_shot_pruner.OneshotPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.one_shot_pruner.LevelPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.one_shot_pruner.L1FilterPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.one_shot_pruner.L2FilterPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.one_shot_pruner.FPGMPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.iterative_pruner.IterativePruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.iterative_pruner.SlimPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.iterative_pruner.TaylorFOWeightFilterPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.iterative_pruner.ActivationAPoZRankFilterPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.iterative_pruner.ActivationMeanRankFilterPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.iterative_pruner.AGPPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.iterative_pruner.ADMMPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.auto_compress_pruner.AutoCompressPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.net_adapt_pruner.NetAdaptPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.simulated_annealing_pruner.SimulatedAnnealingPruner
:members:
.. autoclass:: nni.algorithms.compression.pytorch.pruning.lottery_ticket.LotteryTicketPruner
:members:
Quantizers
^^^^^^^^^^
.. autoclass:: nni.algorithms.compression.pytorch.quantization.quantizers.NaiveQuantizer
:members:
.. autoclass:: nni.algorithms.compression.pytorch.quantization.quantizers.QAT_Quantizer
:members:
.. autoclass:: nni.algorithms.compression.pytorch.quantization.quantizers.DoReFaQuantizer
:members:
.. autoclass:: nni.algorithms.compression.pytorch.quantization.quantizers.BNNQuantizer
:members:
模型加速
-------------
量化模型加速
^^^^^^^^^^^^^^^^^^^^
.. autoclass:: nni.compression.pytorch.quantization_speedup.backend.BaseModelSpeedup
:members:
.. autoclass:: nni.compression.pytorch.quantization_speedup.integrated_tensorrt.ModelSpeedupTensorRT
:members:
.. autoclass:: nni.compression.pytorch.quantization_speedup.calibrator.Calibrator
:members:
压缩工具
---------------------
灵敏度工具
^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: nni.compression.pytorch.utils.sensitivity_analysis.SensitivityAnalysis
:members:
拓扑结构工具
^^^^^^^^^^^^^^^^^^
.. autoclass:: nni.compression.pytorch.utils.shape_dependency.ChannelDependency
:members:
.. autoclass:: nni.compression.pytorch.utils.shape_dependency.GroupDependency
:members:
.. autoclass:: nni.compression.pytorch.utils.mask_conflict.CatMaskPadding
:members:
.. autoclass:: nni.compression.pytorch.utils.mask_conflict.GroupMaskConflict
:members:
.. autoclass:: nni.compression.pytorch.utils.mask_conflict.ChannelMaskConflict
:members:
模型 FLOPs 和参数计数器
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. autofunction:: nni.compression.pytorch.utils.counter.count_flops_params
\ No newline at end of file
../../en_US/Compression/CompressionReference.rst
\ No newline at end of file
模型压缩分析工具
====================================
.. contents::
NNI 提供了几种易于使用的工具,在压缩时用于分析模型。
灵敏度分析
--------------------
首先提供的是灵敏度分析工具 ( **SensitivityAnalysis** ),用于分析模型中每个卷积层的灵敏度。 具体来说,SensitiviyAnalysis 会为每层逐渐剪枝,同时测试模型的精度变化。 注意,敏感度分析一次只会对一层进行剪枝,其它层会使用它们原始的权重。 根据不同稀疏度下不同卷积层的精度,可以很容易的找出模型精度对哪些层的变化更敏感。
用法
^^^^^
下列代码是 SensitivityAnalysis 的基本用法。
.. code-block:: python
from nni.compression.pytorch.utils.sensitivity_analysis import SensitivityAnalysis
def val(model):
model.eval()
total = 0
correct = 0
with torch.no_grad():
for batchid, (data, label) in enumerate(val_loader):
data, label = data.cuda(), label.cuda()
out = model(data)
_, predicted = out.max(1)
total += data.size(0)
correct += predicted.eq(label).sum().item()
return correct / total
s_analyzer = SensitivityAnalysis(model=net, val_func=val)
sensitivity = s_analyzer.analysis(val_args=[net])
os.makedir(outdir)
s_analyzer.export(os.path.join(outdir, filename))
SensitivityAnalysis 的两个重要参数是 ``model`` 和 ``val_func``。 ``model`` 是要分析的神经网络,``val_func`` 是返回验证数据集的精度、损失或其它指标的验证函数。 根据不同的场景,可能需要不同的方法来计算损失和精度,因此用户需要定义能返回模型精度、损失的函数,并传给 SensitivityAnalysis。
上面的示例也展示了如何用 SensitivityAnalysis 将敏感度结果导出为 csv 文件。
除此之外,还可以使用可选参数 ``sparsities`` 来为每一层设置稀疏度值。
.. code-block:: python
s_analyzer = SensitivityAnalysis(model=net, val_func=val, sparsities=[0.25, 0.5, 0.75])
SensitivityAnalysis 会为每一层逐渐剪枝 25% 50% 75% 的权重,并同时记录模型精度 (SensitivityAnalysis 一次只修建一层,其他层会使用原始权重)。 如果没有设置稀疏度,SensitivityAnalysis 会将 numpy.arange(0.1, 1.0, 0.1) 作为默认的稀疏度值。
还可以通过 early_stop_mode 和 early_stop_value 选项来加快灵敏度分析。 默认情况下,SensitivityAnalysis 会为每一层测试所有的稀疏度值下的精度。 而设置了 early_stop_mode 和 early_stop_value 后,当精度或损失值到了 early_stop_value 所设置的阈值时,会停止灵敏度分析。 支持的提前终止模式包括:minimize, maximize, dropped, raised。
minimize: 当 val_func 的返回值低于 ``early_stop_value`` 时,会停止分析。
maximize: 当 val_func 的返回值大于 ``early_stop_value`` 时,会停止分析。
dropped: 当验证指标下降 ``early_stop_value`` 时,会停止分析。
raised: 当验证指标增加 ``early_stop_value`` 时,会停止分析。
.. code-block:: python
s_analyzer = SensitivityAnalysis(model=net, val_func=val, sparsities=[0.25, 0.5, 0.75], early_stop_mode='dropped', early_stop_value=0.1)
如果只想分析部分卷积层,可在分析函数中通过 ``specified_layers`` 指定。 ``specified_layers`` 是卷积层的 Pytorch 模块名称。 例如:
.. code-block:: python
sensitivity = s_analyzer.analysis(val_args=[net], specified_layers=['Conv1'])
在此例中,只会分析 ``Conv1`` 层。 另外,也可以通过并行启动多个进程,将同一个模型的不同层分给每个进程来加速。
输出示例
^^^^^^^^^^^^^^
下面是从 SensitivityAnalysis 中导出的 csv 文件示例。 第一行由 'layername' 和稀疏度值的列表组成。 稀疏度值表示 SensitivityAnalysis 为每一层剪枝的权重比例。 每行表示某层在不同稀疏度下的模型精度。 注意,根据 early_stop 选项,
某些层可能不会有所有稀疏度下的精度或损失值。比如,精度下降的值超过了定义的阈值。
.. code-block:: bash
layername,0.05,0.1,0.2,0.3,0.4,0.5,0.7,0.85,0.95
features.0,0.54566,0.46308,0.06978,0.0374,0.03024,0.01512,0.00866,0.00492,0.00184
features.3,0.54878,0.51184,0.37978,0.19814,0.07178,0.02114,0.00438,0.00442,0.00142
features.6,0.55128,0.53566,0.4887,0.4167,0.31178,0.19152,0.08612,0.01258,0.00236
features.8,0.55696,0.54194,0.48892,0.42986,0.33048,0.2266,0.09566,0.02348,0.0056
features.10,0.55468,0.5394,0.49576,0.4291,0.3591,0.28138,0.14256,0.05446,0.01578
拓扑结构分析
-----------------
NNI 还提供了在模型压缩过程中,进行模型拓扑分析的工具。 这些工具可帮助用户更好的压缩模型。 压缩模型时,因为网络结构的复杂性,经常需要花时间检查压缩配置是否合理。 因此,NNI 提供了这些工具用于模型拓扑分析,来减轻用户负担。
通道依赖
^^^^^^^^^^^^^^^^^
复杂模型中还会有残差或连接的操作。 对这些模型剪枝时,需要小心卷积层之间通道数量的依赖关系。 以 resnet18 中残差模块为例。 ``layer2.0.conv2`` 和 ``layer2.0.downsample.0`` 层输出的特征会加到一起,所以 ``layer2.0.conv2`` 和 ``layer2.0.downsample.0`` 的输出通道数量必须一样,否则会有 Tensor 形状的冲突。
.. image:: ../../img/channel_dependency_example.jpg
:target: ../../img/channel_dependency_example.jpg
:alt:
如果有通道依赖的图层,被分配了不同的稀疏度 (此处仅讨论 L1FilterPruner/L2FilterPruner 的结构化剪枝),就会造成形状冲突。 即使剪枝后的掩码模型也能正常使用,剪枝后的模型也因为模型在加和、连接这些层的输出时有冲突,不能在设备上加速。 此工具可用于查找有通道依赖的层,帮助更好的剪枝模型。
用法
^^^^^
.. code-block:: python
from nni.compression.pytorch.utils.shape_dependency import ChannelDependency
data = torch.ones(1, 3, 224, 224).cuda()
channel_depen = ChannelDependency(net, data)
channel_depen.export('dependency.csv')
输出示例
^^^^^^^^^^^^^^
下列代码是 由 ChannelDependency 导出的 torchvision.models.resnet18 示例。 每行上,有相互依赖的输出通道。 例如,layer1.1.conv2, conv1 和 layer1.0.conv2 相互间有输出依赖。这表示这三个层的输出通道(滤波器)数量需要一致,否则模型会产生形状冲突。
.. code-block:: bash
Dependency Set,Convolutional Layers
Set 1,layer1.1.conv2,layer1.0.conv2,conv1
Set 2,layer1.0.conv1
Set 3,layer1.1.conv1
Set 4,layer2.0.conv1
Set 5,layer2.1.conv2,layer2.0.conv2,layer2.0.downsample.0
Set 6,layer2.1.conv1
Set 7,layer3.0.conv1
Set 8,layer3.0.downsample.0,layer3.1.conv2,layer3.0.conv2
Set 9,layer3.1.conv1
Set 10,layer4.0.conv1
Set 11,layer4.0.downsample.0,layer4.1.conv2,layer4.0.conv2
Set 12,layer4.1.conv1
掩码冲突
^^^^^^^^^^^^
当不同层的掩码有冲突时,(例如,为通道依赖的层设置了不同的稀疏度),可通过 MaskConflict 来修复。 即,MaskConflict 可加载由 (L1FilterPruner, 等) 导出的掩码,并检查是否有掩码冲突。如果有 MaskConflict 会将冲突的掩码设置为相同的值。
.. code-block:: bash
from nni.compression.pytorch.utils.mask_conflict import fix_mask_conflict
fixed_mask = fix_mask_conflict('./resnet18_mask', net, data)
模型 FLOPs 和参数计数器
------------------------------
NNI 提供了模型计数器,用于计算模型的 FLOPs 和参数。 此计数器支持计算没有掩码模型的 FLOPs、参数,也可以计算有掩码模型的 FLOPs、参数,这有助于在模型压缩过程中检查模型的复杂度。 注意,对于结构化的剪枝,仅根据掩码来标识保留的滤波器,不会考虑剪枝的输入通道,因此,计算出的 FLOPs 会比实际数值要大(即,模型加速后的计算值)。
我们支持两种模式来收集模块信息。 第一种是 ``default`` 模式,它只采集卷积操作和线性操作的信息。 第二种是 ``full`` 模式,它还会收集其他操作的信息。 用户可以轻松地使用我们收集的 ``results`` 进行进一步的分析。
用法
^^^^^
.. code-block:: python
from nni.compression.pytorch.utils.counter import count_flops_params
# 给定的输入大小 (1, 1, 28, 28)
flops, params, results = count_flops_params(model, (1, 1, 28, 28))
# 给定大小为 (1, 1, 28, 28) 的张量,切换成 full 模式
x = torch.randn(1, 1, 28, 28)
flops, params, results = count_flops_params(model, (x,) mode='full') # tuple of tensor as input
# 格式化输出大小为M(例如,10^6)
print(f'FLOPs: {flops/1e6:.3f}M, Params: {params/1e6:.3f}M)
print(results)
{
'conv': {'flops': [60], 'params': [20], 'weight_size': [(5, 3, 1, 1)], 'input_size': [(1, 3, 2, 2)], 'output_size': [(1, 5, 2, 2)], 'module_type': ['Conv2d']},
'conv2': {'flops': [100], 'params': [30], 'weight_size': [(5, 5, 1, 1)], 'input_size': [(1, 5, 2, 2)], 'output_size': [(1, 5, 2, 2)], 'module_type': ['Conv2d']}
}
../../en_US/Compression/CompressionUtils.rst
\ No newline at end of file
自定义压缩算法
===================================
.. contents::
为了简化实现新压缩算法的过程,NNI 设计了简单灵活,同时支持剪枝和量化的接口。 首先会介绍如何自定义新的剪枝算法,然后介绍如何自定义新的量化算法。
**重要说明**,为了更好的理解如何定制新的剪枝、量化算法,应先了解 NNI 中支持各种剪枝算法的框架。 参考 `模型压缩框架概述 <../Compression/Framework.rst>`__。
自定义剪枝算法
---------------------------------
要实现新的剪枝算法,需要实现 ``权重掩码`` 类,它是 ``WeightMasker`` 的子类,以及 ``Pruner`` 类,它是 ``Pruner`` 的子类。
``权重掩码`` 的实现如下:
.. code-block:: python
class MyMasker(WeightMasker):
def __init__(self, model, pruner):
super().__init__(model, pruner)
# 此处可初始化,如为算法收集计算权重所需要的统计信息。
# 如果你的算法需要计算掩码
def calc_mask(self, sparsity, wrapper, wrapper_idx=None):
# 根据 wrapper.weight, 和 sparsity,
# 及其它信息来计算掩码
# mask = ...
return {'weight_mask': mask}
参考 NNI 提供的 :githublink:`权重掩码 <nni/algorithms/compression/pytorch/pruning/structured_pruning.py>` 来实现自己的权重掩码。
基础的 ``Pruner`` 如下所示:
.. code-block:: python
class MyPruner(Pruner):
def __init__(self, model, config_list, optimizer):
super().__init__(model, config_list, optimizer)
self.set_wrappers_attribute("if_calculated", False)
# 创建权重掩码实例
self.masker = MyMasker(model, self)
def calc_mask(self, wrapper, wrapper_idx=None):
sparsity = wrapper.config['sparsity']
if wrapper.if_calculated:
# 如果是一次性剪枝算法,不需要再次剪枝
return None
else:
# 调用掩码函数来实际计算当前层的掩码
masks = self.masker.calc_mask(sparsity=sparsity, wrapper=wrapper, wrapper_idx=wrapper_idx)
wrapper.if_calculated = True
return masks
参考 NNI 提供的 :githublink:`Pruner <nni/algorithms/compression/pytorch/pruning/one_shot.py>` 来实现自己的 Pruner。
----
自定义量化算法
--------------------------------------
要实现新的量化算法,需要继承 ``nni.compression.pytorch.Quantizer``。 然后,根据算法逻辑来重写成员函数。 需要重载的成员函数是 ``quantize_weight``。 ``quantize_weight`` 直接返回量化后的权重,而不是 mask。这是因为对于量化算法,量化后的权重不能通过应用 mask 来获得。
.. code-block:: python
from nni.compression.pytorch import Quantizer
class YourQuantizer(Quantizer):
def __init__(self, model, config_list):
"""
建议使用 NNI 定义的规范来配置
"""
super().__init__(model, config_list)
def quantize_weight(self, weight, config, **kwargs):
"""
quantize 需要重载此方法来为权重提供掩码
此方法挂载于模型的 :meth:`forward`。
参数
----------
weight : Tensor
要被量化的权重
config : dict
输出量化的配置
"""
# 此处逻辑生成 `new_weight`
return new_weight
def quantize_output(self, output, config, **kwargs):
"""
重载此方法量化输入
此方法挂载于模型的 `:meth:`forward`。
参数量
----------
output : Tensor
需要被量化的输出
config : dict
输出量化的配置
"""
# 生成 `new_output` 的代码
return new_output
def quantize_input(self, *inputs, config, **kwargs):
"""
重载此方法量化输入
此方法挂载于模型的 :meth:`forward`。
参数量
----------
inputs : Tensor
需要被量化的张量
config : dict
输入量化的配置
"""
# 生成 `new_input` 的代码
return new_input
def update_epoch(self, epoch_num):
pass
def step(self):
"""
根据 bind_model 函数传入的模型或权重
进行一些处理
"""
pass
定制 backward 函数
^^^^^^^^^^^^^^^^^^^^^^^^^^^
有时,量化操作必须自定义 backward 函数,例如 `Straight-Through Estimator <https://stackoverflow.com/questions/38361314/the-concept-of-straight-through-estimator-ste>`__\ ,可如下定制 backward 函数:
.. code-block:: python
from nni.compression.pytorch.compressor import Quantizer, QuantGrad, QuantType
class ClipGrad(QuantGrad):
@staticmethod
def quant_backward(tensor, grad_output, quant_type):
"""
此方法应被子类重载来提供定制的 backward 函数,
默认实现是 Straight-Through Estimator
Parameters
----------
tensor : Tensor
量化操作的输入
grad_output : Tensor
量化操作输出的梯度
quant_type : QuantType
量化类型,可被定义为 `QuantType.QUANT_INPUT`, `QuantType.QUANT_WEIGHT`, `QuantType.QUANT_OUTPUT`,
可为不同的类型定义不同的行为。
Returns
-------
tensor
量化输入的梯度
"""
# 对于 quant_output 函数,如果张量的绝对值大于 1,则将梯度设置为 0
if quant_type == QuantType.QUANT_OUTPUT:
grad_output[torch.abs(tensor) > 1] = 0
return grad_output
class YourQuantizer(Quantizer):
def __init__(self, model, config_list):
super().__init__(model, config_list)
# 定制 backward 函数来重载默认的 backward 函数
self.quant_grad = ClipGrad
如果不定制 ``QuantGrad``,默认的 backward 为 Straight-Through Estimator。
*编写中*……
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment