面试官:模型剪枝了解吗?解释一下结构化剪枝与非结构化剪枝

66 阅读4分钟

📚推荐阅读

面试官:Transformer如何优化到线性级?

面试官:模型的量化了解吗?解释一下非对称量化与对称量化

面试官:“剪枝了解吗?那你能说说结构化剪枝和非结构化剪枝的区别吗?”
剪枝虽然是老话题,但如果你真能讲清楚它的核心思想 + 工程取舍,那还是比较难的,所以今天我们就来彻底梳理一下这个问题。

所有相关源码示例、流程图、模型配置与知识库构建技巧,我也将持续更新在Github:AIHub,欢迎关注收藏!

一、为什么要剪枝?

剪枝通过移除模型中冗余或不重要的权重/神经元,减少参数量和计算量。比如一个 ResNet 可能有上千万个参数,但真正决定输出结果的那部分其实占比并不高。所以我们可以通过剪枝去掉这些“冗余权重”,在几乎不掉精度的情况下,让模型计算量更少、速度更快。

剪枝包括:

  • 非结构化剪枝:移除单个权重(稀疏化矩阵),压缩率高但硬件利用率低。
  • 结构化剪枝:移除整个通道/卷积核/注意力头,硬件加速友好。

剪枝能直接减少模型参数量和计算量(FLOPs),并且可以与量化结合,进一步压缩。

二、剪枝的核心逻辑

剪枝通常有两步:

  1. 评估重要性(哪些参数重要、哪些可删);
  2. 删除不重要的部分,并微调恢复精度。

而“哪些部分”要删,就决定了我们剪枝的粒度,也就是今天的重点:结构化剪枝(Structured Pruning)非结构化剪枝(Unstructured Pruning)

三、非结构化剪枝(Unstructured Pruning)

非结构化剪枝,也叫“稀疏剪枝(Sparse Pruning)”。它是最自由、最细粒度的剪枝方式。

思想很简单,就是对每个参数单独评估,觉得小的就砍。

比如:image

如果我们设定一个阈值 0.01,小于这个值的参数就直接剪掉变成 0:image

非结构化剪枝精度损失小(因为只删不重要的参数),控制精细,理论上稀疏率越高,模型越小。但是由于硬件不擅长处理稀疏矩阵,实际加速效果差,并且存储时需要额外记录索引,带来开销。

所以非结构化剪枝更像是数学上变稀疏,而不是真正变快。适合研究或轻量化探索,不太适合直接部署。

四、结构化剪枝(Structured Pruning)

结构化剪枝更接近“工程落地”的思路,思想是直接剪掉整个卷积核、通道、甚至层结构。

比如我们在 CNN 中:

  • 剪通道(Channel Pruning):删掉一整列 feature map;
  • 剪卷积核(Filter Pruning):删除整个 filter;
  • 剪层(Layer Pruning):直接去掉某些层。

这时候模型的结构会真正变小,计算图也简化了,剪完后模型不仅参数变少,推理速度也会显著提升

结构化剪枝可以实现真正的加速,并且部署简单(不需要特殊稀疏硬件),和 TensorRT、OpenVINO、ONNX 等框架兼容性好。

缺点就是粒度大,删多了容易掉精度,剪完结构变动大,微调成本高。
结构化剪枝就比较适合部署导向的优化,比如在边缘设备、移动端上跑 CNN。

面试如果还追问你“那你知道有哪些剪枝策略吗”,可以简单提一下:

  • 基于权重(Magnitude Pruning):删掉权值小的参数;
  • 基于BN通道(BN Scaling Pruning):看 BatchNorm 的缩放系数;
  • 基于梯度或敏感度:看参数对损失的贡献;
  • 基于L1/L2正则:通过约束让模型自己“变稀疏”;
  • 动态剪枝(Dynamic Pruning):在推理时动态决定是否剪掉某些路径。

不需要细讲,只要提到思路 + 分类,面试官就知道你有体系。

五、工程实践

在工程实践中,剪枝的步骤通常为:

  1. 训练完整模型;
  2. 根据权重或通道重要性剪枝;
  3. 微调恢复精度;
  4. 导出 ONNX → TensorRT 部署。

比如 PyTorch 就内置了 torch.nn.utils.prune 模块:

import torch.nn.utils.prune as prune

# 对卷积层进行非结构化剪枝
prune.l1_unstructured(model.conv1, name='weight', amount=0.3)

# 对卷积层进行结构化剪枝(按通道)
prune.ln_structured(model.conv1, name='weight', amount=0.3, n=2, dim=0)

结构化剪枝出来的模型直接可以导出推理,非结构化的要么稀疏化存储,要么重新稠密化。

关于深度学习和大模型相关的知识和前沿技术更新,请关注公众号 coting