Lecture3剪枝蒸馏

剪枝

剪枝流程

1.剪枝是指在神经网络中移除不必要或对模型性能影响较小的权重(synapses)或神经元(neurons)。通过减少网络的复杂性,可以提高推理速度,减少内存占用,同时在某些情况下还能减少过拟合。
2.那么我们如何确立剪枝的粒度呢?这一步是确定剪枝应该在何种层次上进行,比如剪枝神经元连接(权重)还是整个神经元。剪枝的粒度决定了模型如何简化以及简化的程度。例如,可以针对单独的连接进行稀疏化,或者移除整个神经元层级。
剪枝神经元连接:删除了一部分神经元之间的连接,使得网络变得更加稀疏,减少计算量。
剪枝神经元:删除了不重要或贡献较小的神经元,使网络规模变小,进一步减少了计算和存储需求。
在这里插入图片描述
3.剪枝的标准决定了哪些权重或神经元将被移除。常见的剪枝标准有权重值较小的连接(低影响权重)或贡献较小的神经元。通常使用某些启发式或评估标准来确定最适合剪枝的部分。

4.剪枝比例指的是在每一层中目标的稀疏性。即需要移除多少权重或神经元。剪枝比例的选择对模型性能和效率有很大影响。高剪枝比例可以大幅减少模型复杂度,但也可能导致性能下降。

5.剪枝后,网络通常需要重新训练或微调,以恢复或接近原始的模型性能。这个步骤旨在提高剪枝后模型的准确性和稳定性。

所以剪枝的大致流程是:

  • 确定剪枝的粒度
  • 确定剪枝标准
  • 确定剪枝比例
  • 微调/训练剪枝后的神经网络
    在这里插入图片描述
    对于更通俗的一个流程就是神经网络经过常规的训练过程,学习到各层神经元之间的连接权重。接下来,通过剪枝移除一些不重要的连接或者神经元,从而减少网络的复杂性。这个过程通常基于剪枝标准,例如权重值的大小。剪枝后,为了恢复或维持模型的性能,通常会进行重新训练或微调,以重新优化剩余的权重。。也就是训练连接->剪枝训练->训练权重。
    上图展示了剪枝比例(x轴)与精度损失(Accuracy Loss)(y轴)的关系。两条曲线展示了不同的策略:
  • 紫色虚线(Pruning):只进行剪枝,不进行后续的微调。可以看到,随着剪枝比例的增加,模型的精度迅速下降,尤其当剪枝比例超过50%时,损失显著。
  • 绿色实线(Pruning + Finetuning):在剪枝后进行了微调的模型。精度损失在剪枝初期非常小,甚至可以保持精度不变,直到剪枝比例超过80%才开始明显下降。这表明微调可以有效缓解剪枝带来的性能损失。

这些蓝色的柱状图展示了不同剪枝比例下权重的分布。随着剪枝比例增加,权重的分布变得更加稀疏,这说明大部分的权重都被移除了,网络变得更加稀疏和简单。

剪枝的数学定义

剪枝问题的目标是通过保留尽可能少的权重( W P W_P WP​)来最小化网络的损失函数 L ( x ; W P ) L(x;W_P) L(x;WP),具体形式如下:

  • a r g m i n L ( x ; W P ) arg min L(x;W_P) argminL(x;WP):这个公式表示我们希望在剪枝后的权重 W P W_P WP​ 下最小化损失函数 L,即保证模型的预测误差尽可能小。
  • s u b j e c t t o ∣ ∣ W p ∣ ∣ 0 ​ < N subject to ||W_p||_0 ​<N subjectto∣∣Wp0<N:这是剪枝的约束条件,要求剪枝后的权重 W p W_p Wp 中的非零元素个数(即剩下的权重数量)不能超过 N。 ∣ ∣ W p ∣ ∣ 0 ||W_p||_0 ∣∣Wp0 L 0 L_0 L0​ 范数,它表示权重中非零值的数量。

在这里插入图片描述
左图:表示未剪枝的神经网络。其目标是通过优化权重矩阵 W 来最小化损失函数 L(x;W)。
右图:表示剪枝后的神经网络。剪枝后,目标是通过优化剪枝后的权重矩阵 WP​,在约束条件(保留少量非零权重)下,最小化损失函数 L(x;WP)。
剪枝问题可以被视为一个受限优化问题,在保持性能的前提下,通过减少权重的数量来简化网络。通过引入 L0​ 范数约束,确保网络在剪枝后保持指定的稀疏性(非零权重数量受限)。
剪枝的核心目标是在减少计算资源和模型复杂度的同时,尽可能减少模型的性能损失。

剪枝粒度

矩阵层面剪枝

在这里插入图片描述

  1. Fine-grained/Unstructured(细粒度/非结构化剪枝):

    左边的矩阵表示细粒度剪枝,其中红色的方块表示保留的权重,白色的方块表示被剪掉的权重。这种方式可以自由地选择权重矩阵中任意的元素进行剪枝,不需要遵循某种特定的结构,因此称为非结构化。
    特点:
    更灵活的剪枝选择:由于是任意剪枝,能够在权重矩阵中自由选择要保留或删除的元素,因此可以根据每个权重的影响力进行精确控制。
    难以加速:因为非结构化的剪枝会导致权重矩阵的稀疏性呈现不规则的分布,使得在硬件上进行高效加速变得困难。例如,处理器可能难以有效地利用内存缓存或进行并行化操作。

  2. Coarse-grained/Structured(粗粒度/结构化剪枝):

    右边的矩阵展示了粗粒度剪枝,其中保留的权重呈现结构化的块状。这意味着剪枝按照一定的规则进行,比如剪掉整行或整列,或者是固定大小的块,这种方式被称为结构化剪枝。
    特点:
    剪枝选择不如细粒度灵活:由于剪枝遵循特定的规则,比如成块或者成行剪掉权重,因此不能像细粒度剪枝那样灵活地选择要保留的部分。
    更容易加速:结构化剪枝使得矩阵的稀疏性呈现规则性,从而可以更容易地进行硬件加速。在处理器或加速器上,这种结构化的稀疏矩阵可以更高效地计算,且容易优化内存访问。

    细粒度剪枝提供了更高的灵活性,可以基于模型性能的精确需求进行权重移除,但由于其不规则性,难以在硬件上加速。
    粗粒度剪枝相对不如细粒度灵活,但其规则化结构使得其在硬件上的计算更容易优化,适合加速计算。

卷积层面剪枝

卷积剪枝

卷积有四个维度 batch channel height,width
所以我们可以有如下剪枝方式:
在这里插入图片描述1. Fine-grained Pruning(细粒度剪枝):
细粒度剪枝是在权重矩阵的任意位置剪掉一些权重。每个权重都是独立评估的,不需要遵循特定模式。
特点:剪枝位置非常灵活,选择性高,但这种不规则的剪枝很难在硬件上优化计算,效率较低
2.Pattern-based Pruning(模式剪枝):
基于特定的模式进行剪枝,保留或剪掉的权重按照预定的图案排列。这种方式比细粒度剪枝更有规律,但仍然存在一定的不规则性。
特点:有规律的剪枝模式使得硬件加速相对容易,但依然不如完全规则的剪枝。

3.Vector-level Pruning(向量级剪枝):
在向量级别上进行剪枝,通常是沿着某个方向对连续的权重进行剪枝,如一行或一列。特点:相比前两种方法,剪枝更加规则,且更容易进行硬件加速。.
4.Kernel-level Pruning(卷积核级剪枝):
剪枝时以整个卷积核为单位。每个卷积核要么全部保留,要么全部剪掉。这意味着输出通道内的所有卷积核都要一起处理。
特点:这种剪枝方式更有规律,卷积核级别的剪枝非常适合硬件优化,尤其是在卷积运算中可以节省大量计算。

5.Channel-level Pruning(通道级剪枝):
基于输入或输出通道进行剪枝。整个输入通道或输出通道中的所有权重都被剪掉或保留。
特点:这是最规则的剪枝方式,可以极大减少模型的计算复杂度,并且容易加速。对于硬件加速器和计算框架来说,通道级剪枝是最容易实现的。

不规则剪枝(如细粒度和模式剪枝)有更多的灵活性,但硬件优化难度大。
规则剪枝(如卷积核级和通道级剪枝)虽然灵活性较低,但易于在硬件上实现高效加速,适合需要提高推理速度和减少计算资源的应用场景。

启发式剪枝
在这里插入图片描述
这个方法认为权重的绝对值越大,其在神经网络中的作用就越大,越重要。因此,在进行剪枝时,通常保留那些绝对值较大的权重,而剪除那些绝对值较小的权重。
在这里插入图片描述
当然还可以进行额外的操作,例如进行row-wise pruning 行级剪枝。在行级剪枝中,通过计算一整行权重的L1范数(即绝对值的和)来确定每一行的重要性。
在这里插入图片描述

LAB1

1.Fine grained Purning

使用fine grained Puring 方法进行剪枝
稀疏率= W 0 / W W_0/W W0/W 也就是矩阵中非0值和全部元素个数的比值。
而后我们需要计算权重,权重这里是通过他们的绝对值来衡量的(也是最简单的一种方法)
而后我们确定剪枝的阈值-kthvalue
这个阈值就是根据我们的稀疏系数来决定的,比如我们这里的稀疏率是0.4,那么我们把小于0.4的参数都给赋值为0.。

threshold = torch.kthvalue(importance.view(-1),num_zeros).values.item()

最后生成二进制剪枝掩码
返回一个布尔张量,表示哪些权重大于阈值。gt 是 “greater than” 的缩写,所以该操作会返回一个与 importance 相同形状的张量,值为 True 的位置表示保留,False 表示移除。
.float():将布尔张量转换为浮点张量,True 转换为 1.0,False 转换为 0.0。最终的掩码张量 mask 中,1 表示该位置的权重会被保留,0 表示该位置的权重会被剪除。

应用剪枝掩码:
tensor.mul_(mask)
通过 tensor.mul_(mask),将掩码与原始张量逐元素相乘。因为掩码是 1 或 0,掩码值为 1 的位置保持原权重,掩码值为 0 的位置则将权重乘以 0,从而达到剪枝效果。

def fine_grained_prune(tensor: torch.Tensor, sparsity : float) -> torch.Tensor:
    """
    magnitude-based pruning for single tensor
    :param tensor: torch.(cuda.)Tensor, weight of conv/fc layer
    :param sparsity: float, pruning sparsity
        sparsity = #zeros / #elements = 1 - #nonzeros / #elements
    :return:
        torch.(cuda.)Tensor, mask for zeros
    """
    sparsity = min(max(0.0, sparsity), 1.0)
    if sparsity == 1.0:
        tensor.zero_()
        return torch.zeros_like(tensor)
    elif sparsity == 0.0:
        return torch.ones_like(tensor)
    num_elements = tensor.numel()
    ##################### YOUR CODE STARTS HERE #####################
    # Step 1: calculate the #zeros (please use round())
    num_zeros = round(sparsity * tensor.numel())
    # Step 2: calculate the importance of weight
    importance = torch.abs(tensor)
    # Step 3: calculate the pruning threshold
    # threshold = torch.kthvalue(importance.view(-1),num_zero).values.item()
    #把importance展成一维,方便用kthvalue函数
    threshold = torch.kthvalue(importance.view(-1), num_zeros).values.item()
    # Step 4: get binary mask (1 for nonzeros, 0 for zeros)
    #生成剪枝掩码
    mask = torch.gt(importance,threshold).float()
    ##################### YOUR CODE ENDS HERE #######################
    # Step 5: apply mask to prune the tensor
    tensor.mul_(mask)
    return mask

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值