首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >initial_sparsity参数在基于sparsity.PolynomialDecay() TensorFlow 2.0量级的权重剪枝中的应用

initial_sparsity参数在基于sparsity.PolynomialDecay() TensorFlow 2.0量级的权重剪枝中的应用
EN

Stack Overflow用户
提问于 2020-01-31 14:32:52
回答 1查看 1.2K关注 0票数 6

我正在尝试教程基于TensorFlow 2.0量值的Keras权重剪枝,并遇到了参数initial_sparsity。

代码语言:javascript
复制
import tensorflow_model_optimization as tfmot
from tensorflow_model_optimization.sparsity import keras as sparsity
import numpy as np

epochs = 12
num_train_samples = x_train.shape[0]
end_step = np.ceil(1.0 * num_train_samples / batch_size).astype(np.int32) * epochs
print('End step: ' + str(end_step))

pruning_params = {
      'pruning_schedule': sparsity.PolynomialDecay(initial_sparsity=0.50,
                                                   final_sparsity=0.90,
                                                   begin_step=2000,
                                                   end_step=end_step,
                                                   frequency=100)
}

该教程说:

此处使用的参数意味着: 在整个训练过程中都使用了Spar力度 PolynomialDecay。我们从50%的稀疏水平开始,逐步训练达到90%的稀疏度。X%稀疏意味着,重量张量的X%将被剪除。

我的问题是,你不应该从0%的initial_sparsity开始,然后剪短90%的重量吗?

从50%的initial_sparsity开始是什么意思?这是否意味着50%的重量从一开始就被修剪,然后实现了90%的稀疏性修剪?

另外,对于tfmot.sparsity.keras.ConstantSparsity,,API如下所示:

代码语言:javascript
复制
pruning_params_unpruned = {
    'pruning_schedule': sparsity.ConstantSparsity(
        target_sparsity=0.0, begin_step=0,
        end_step = 0, frequency=100
    )
}

初始化具有恒定稀疏性的剪枝计划。 稀疏性应用于区间begin_step、end_step的每一频率步。在每一个适用的步骤中,稀疏性(%)是恒定的。

这是否意味着,如果神经网络模型已经处于50%的稀疏水平,但target_sparsity = 0.5,那么剪枝计划是否会这样做:

  1. 没有修剪,因为模型已经被修剪到50%的水平。
  2. 它进一步修剪了已有(50%修剪)模型的50%的重量。

你可以在PolynomialDecayConstantSparsity上读到它。

谢谢

EN

回答 1

Stack Overflow用户

发布于 2020-05-26 18:54:20

因此,我还发现Tensorflow关于重量剪枝的文档非常稀疏,所以我花了一些时间在调试器上了解所有的事情是如何工作的。

剪枝时间表是如何工作的

在最基本的层次上,剪枝计划只是一个函数,它将步骤作为输入并生成稀疏百分比。然后,该稀疏值用于生成一个掩码,该掩码用于用绝对值小于绝对值权重分布和稀疏百分比给出的k-1值修剪出权重。

PolynomialDecay

类定义:Github链接

上面的类定义中包含的注释帮助我理解了PolynomialDecay调度器的工作方式。

修剪速率从initial_sparsity开始快速增长,然后缓慢稳定到目标稀疏。 应用的功能是 current_sparsity = final_sparsity + (initial_sparsity - final_sparsity) * (1 -(阶跃- begin_step)/(end_step - begin_step)) ^指数

由上面的方程,当step == begin_step然后current_sparsity = initial_sparsity。因此,在由initial_sparsity参数指定的步骤中,权重将被修剪到begin_step

我同意你的评估,因为你通常会想要开始修剪一个低于50%的稀疏,但我没有任何发表的研究,我可以引用来支持这一说法。您可能会在中找到更多与PolynomialDecay类定义一起引用的信息,尽管我没有机会亲自阅读它。

ConstantSparsity

类定义:Github链接

此调度程序的用途似乎相当有限。对于每一个有效的剪枝步骤,都会返回target_sparsity。因此,多个剪枝步骤是非常多余的。此计划程序的用例似乎是在训练期间进行一次修剪。使用此调度程序多次修剪的功能是将其与其父抽象类和其他剪枝调度程序对齐。

创建自己的剪枝计划程序

如果上面两个调度器不浮动您的船,抽象类PruningSchedule会公开一个端点,这使得创建您自己的剪枝调度程序变得非常容易,尽管它可能是复杂的。下面是我自己创造的一个例子。

免责声明:这个调度程序是一个19岁的大学生想象力的创造,在任何出版的文献中都没有根据。

代码语言:javascript
复制
PruningSchedule = tfmot.sparsity.keras.PruningSchedule

class ExponentialPruning(PruningSchedule):
def __init__(self, rate=0.01, begin_step=0, frequency=100, max_sparsity=0.9):
    self.rate = rate
    self.begin_step = begin_step
    self.frequency = frequency
    self.max_sparsity = max_sparsity

    # Validation functions provided by the parent class
    # The -1 parameter is for the end_step
    # as this pruning schedule does not have one
    # The last true value is a boolean flag which says it is okay
    # to have no end_step
    self._validate_step(self.begin_step, -1, self.frequency, True)
    self._validate_sparsity(self.max_sparsity, 'Max Sparsity')

def __call__(self, step):
    # Sparsity calculation endpoint

    # step is a integer tensor

    # The sparsity returned by __call__ must be a tensor
    # of dtype=tf.float32, so tf.math is required.

    # In the logic below, you can assume that a valid
    # pruning step is passed.

    p = tf.math.divide(
        tf.cast(step - self.begin_step, tf.float32),
        tf.constant(self.frequency, dtype=tf.float32)
    )
    sparsity = tf.math.subtract(
        tf.constant(1, dtype=tf.float32),
        tf.math.pow(
            tf.constant(1 - self.rate, dtype=tf.float32),
            p
        )
    )

    sparsity = tf.cond(
        tf.math.greater(sparsity, tf.constant(self.max_sparsity, dtype=tf.float32)),
        lambda: tf.constant(self.max_sparsity, dtype=tf.float32),
        lambda: sparsity
    )

    # This function returns a tuple of length 2
    # The first value determines if pruning should occur on this step
    # I recommend using the parent class function below for this purpose
    # The negative one value denotes no end_step
    # The second value is the sparsity to prune to
    return (self._should_prune_in_step(step, self.begin_step, -1, self.frequency),
            sparsity)

def get_config(self):
    # A function required by the parent class
    # return the class_name and the input parameters as
    # done below
    return {
        'class_name': self.__class__.__name__,
        'config': {
            'rate': self.rate,
            'begin_step': self.begin_step,
            'frequency': self.frequency,
            'max_sparsity': self.max_sparsity
        }
    }

使用剪枝调度器

如果您只希望某些层被修剪,而不是所有可剪切层,那么您可以在添加到模型中的一个层上调用prune_low_magnitude函数。

代码语言:javascript
复制
prune_low_magnitude = tfmot.sparsity.keras.prune_low_magnitude
model = keras.models.Sequential()
...
model.add(prune_low_magnitude(keras.layers.Dense(8, activation='relu', kernel_regularizer=keras.regularizers.l1(0.0001)),
  ExponentialPruning(rate=1/8)))

还要确保将一个UpdatePruningStep实例传递给训练回调:

代码语言:javascript
复制
m.fit(train_input, train_labels, epochs=epochs, validation_data=[test_input, test_labels],
  callbacks=[UpdatePruningStep()])
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60005900

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档