如何实施神经网络修剪



我在凯拉斯(Keras(训练了一个模型,我正在考虑修剪完全连接的网络。我对如何修剪图层有些迷失。

'学习权重和连接以提高效率的作者神经网络说,它们为层的阈值重量添加了口罩。我可以尝试做同样的事情,并微调训练有素的模型。但是,它如何降低模型大小和计算#?

根据评论中的讨论,这是一种修剪神经网络的层(重量矩阵(的方法。该方法实质上的作用是根据其标准选择k%最小的权重(矩阵的元素(,并将其设置为零。这样,相应的矩阵可以被视为稀疏矩阵,我们可以执行密集的矩阵乘数,如果修剪足够的权重,可以更快。

def weight_pruning(w: tf.Variable, k: float) -> tf.Variable:
    """Performs pruning on a weight matrix w in the following way:
    - The absolute value of all elements in the weight matrix are computed.
    - The indices of the smallest k% elements based on their absolute values are selected.
    - All elements with the matching indices are set to 0.
    Args:
        w: The weight matrix.
        k: The percentage of values (units) that should be pruned from the matrix.
    Returns:
        The unit pruned weight matrix.
    """
    k = tf.cast(tf.round(tf.size(w, out_type=tf.float32) * tf.constant(k)), dtype=tf.int32)
    w_reshaped = tf.reshape(w, [-1])
    _, indices = tf.nn.top_k(tf.negative(tf.abs(w_reshaped)), k, sorted=True, name=None)
    mask = tf.scatter_nd_update(tf.Variable(tf.ones_like(w_reshaped, dtype=tf.float32), name="mask", trainable=False), tf.reshape(indices, [-1, 1]), tf.zeros([k], tf.float32))
    return w.assign(tf.reshape(w_reshaped * mask, tf.shape(w)))

虽然上面的方法会修剪单个连接(重量(,但下面的方法从重量矩阵中修剪整个神经元。也就是说,该方法基于欧几里得规范选择k%最小的神经元(重量矩阵的列(,然后将它们设置为零。

def unit_pruning(w: tf.Variable, k: float) -> tf.Variable:
    """Performs pruning on a weight matrix w in the following way:
    - The euclidean norm of each column is computed.
    - The indices of smallest k% columns based on their euclidean norms are selected.
    - All elements in the columns that have the matching indices are set to 0.
    Args:
        w: The weight matrix.
        k: The percentage of columns that should be pruned from the matrix.
    Returns:
        The weight pruned weight matrix.
    """
    k = tf.cast(
        tf.round(tf.cast(tf.shape(w)[1], tf.float32) * tf.constant(k)), dtype=tf.int32
    )
    norm = tf.norm(w, axis=0)
    row_indices = tf.tile(tf.range(tf.shape(w)[0]), [k])
    _, col_indices = tf.nn.top_k(tf.negative(norm), k, sorted=True, name=None)
    col_indices = tf.reshape(
        tf.tile(tf.reshape(col_indices, [-1, 1]), [1, tf.shape(w)[0]]), [-1]
    )
    indices = tf.stack([row_indices, col_indices], axis=1)
    return w.assign(
        tf.scatter_nd_update(w, indices, tf.zeros(tf.shape(w)[0] * k, tf.float32))
    )

最后,此GitHub存储库通过此处解释的修剪方法,并在MNIST数据集上执行实验。

如果添加蒙版,则只有一个体重的子集将有助于计算,因此您的模型将被修剪。例如,自回家模型使用掩码来掩盖涉及未来数据的权重,以便在时间时输出sptep t仅取决于时间步长0, 1, ..., t-1

在您的情况下,由于您具有简单的完全连接层,因此最好使用辍学。它在每个迭代步骤中随机关闭一些神经元,以降低计算复杂性。但是,发明辍学的主要原因是要解决过度拟合:通过随机关闭一些神经元,您可以减少神经元的共依赖性,即避免有些神经元依靠其他神经元。此外,在每次迭代中,您的模型都会有所不同(活动神经元的不同数量的不同数量(,因此,您的最终模型可以解释为几种二元模型的诱因(集合(,每个模型都在了解输入空间的特定子集。

最新更新