资讯动态

Deep Compression解析:剪枝、量化与霍夫曼编码如何实现50倍模型压缩

发布时间:2026/9/30 9:40:35 来源:尧图企业网站定制
1. 为什么我会去啃这篇2016年的老论文如果你现在打开各大模型厂商的技术博客看到稀疏化、权重量化、模型压缩这些词大概率不会觉得陌生。但你可能不知道把这些技术系统性地组合在一起、并给出完整工程落地方案的起点正是这篇发表于ICLR 2016并获得最佳论文奖的《Deep Compression》。我第一次接触这篇论文并不是因为追热点而是因为一个很实际的困境当时我在做移动端的图像分类模型一个标准的ResNet-50权重文件大约98MB压缩成浮点模型放到手机里光加载就要好几秒更别提推理时的带宽消耗。换轻量网络精度又掉得厉害。反复调参无果之后前辈甩给我一句去看Deep Compression方向比调参重要。读完原论文之后我最大的感受是这篇论文真正厉害的地方不在于它发明了什么全新算法而在于它像一位经验丰富的工程师把三个早已存在的方法——剪枝、量化、霍夫曼编码——按正确的顺序组装起来环环相扣地把模型从原本的体积里拧了出来。AlexNet被它从240MB压到6.9MBVGG-16从552MB压到11.3MB压缩比接近50倍而精度几乎无损。这个数字在今天看来依然能打放在2016年简直像魔术。这篇随笔我想按自己的阅读思路来梳理这篇论文它要解决什么问题三个步骤各自怎么工作、为什么必须按这个顺序实验结果说明了什么以及结合我后来实操压缩模型时踩过的坑谈谈这篇论文里真正值得反复咀嚼的细节。如果你是做端侧部署、模型优化、或者对神经网络底层原理感兴趣的开发者这篇随笔应该能给你一些教科书之外的东西。2. 论文瞄准的痛点精度和体积鱼和熊掌不可兼得要理解Deep Compression的价值得先回到2015年前后的时代背景。那会儿深度学习刚在ImageNet上大杀四方但学术圈的兴奋和工业界的痛苦是并行的——模型越大精度越高但这几乎是铁律。2.1 大模型为什么让部署团队头疼以AlexNet为例它有6000万参数浮点权重存储下来约240MB。VGG-16更夸张1.38亿参数552MB。什么概念当时主流iPhone的存储空间是16GB或32GB装一个VGG-16模型就耗掉三十分之一而且内存根本扛不住推理时的中间激活值。更大的问题在带宽。移动端的推理引擎跑在ARM CPU或GPU上内存带宽远不如服务器端。模型每做一次前向推理都要把权重从内存搬到计算单元。权重文件越大搬运耗时越长功耗越高。模型太大带来的不只是装不下而是跑不动和电耗不起。如果你没做过端侧部署可以这样理解模型权重有点像你搬家时的行李。行李多搬家公司肯定能搬但每趟搬完都要歇半天油钱也受不了。Deep Compression做的事情就是把这些行李压缩成几小箱而且保证到了新家之后所有东西还是原样摆好。2.2 已有压缩方法为什么不够给力在Deep Compression之前学术界不是没做过压缩。常见的思路有几条低秩分解把权重矩阵分解成两个小矩阵相乘用SVD之类的数学工具降维。缺点是对卷积层效果有限而且分解后矩阵乘法反而变慢。剪枝早期剪枝研究只针对全连接层压缩比不高而且存储格式没有配套优化稀疏计算带来的收益被索引开销抵消。量化当时主流做法是直接把浮点权重转成8bit整数。简单粗暴但精度损失明显尤其是对较小的模型量化误差会直接吃掉模型的表达能力。Deep Compression的聪明之处在于它不赌单一技术而是打组合拳先用剪枝减少参数量再用量化减少每个参数的存储位数最后用霍夫曼编码榨干最后一点统计冗余。三个步骤的着力点互不重叠组合起来的效果远大于任何单一步骤。我后来在实操中也有这种体会单一优化方法做到头往往收益有限但把两个正交方法叠加在一起往往能突破瓶颈。这篇论文算是这句话的最佳注脚。3. 第一步修剪掉不重要的连接反直觉地保留精度剪枝是Deep Compression的第一层压缩也是参数数量削减的大头。它能做到什么程度论文里AlexNet的参数总量直接被砍掉到原来的约1/9——卷积层参数减少至1/3全连接层参数从5800万直接降到670万。3.1 剪枝为什么会有效从直觉上说一个已经训练好的神经网络并不是每个权重都是不可或缺的。训练过程的本质是在一个高维参数空间里找一个最优解区域。但最终收敛到的那个点附近许多权重的取值其实处于冗余状态删除它对网络输出的影响微乎其微。论文的做法很直接先正常训练一个模型然后设置一个阈值凡是绝对值低于阈值的权重统统置零接着把得到的新网络重新训练微调让保留下来的权重重新调整去弥补被删掉的部分功能。这个过程叫训练-剪枝-微调本质上是把网络当作一个庞大的、可修复的机器——先拆掉生锈的零件再重新校准剩下的齿轮。这里的反直觉之处在于我们对智力的习惯认知是越复杂的系统越精密、越不能轻易减配。但实验结果反复证明深度神经网络中绝大部分参数都是高度冗余的后训练阶段保留10%的连接就能维持原精度。这就好比你写了一篇冗长的文章真正承载核心信息的句子其实只有几段其余都是重复表达和铺垫。3.2 剪枝粒度从整层删除到单个权重论文里还比较了不同剪枝粒度的效果权重级剪枝每个weight独立判断去留。效果最好因为可以精准地删掉不重要的单个参数但会导致稀疏不规则存储格式要求高。通道级/核级剪枝把整个卷积核或通道全部删除。稀疏规则但精度牺牲大因为会误伤还有用的参数。Deep Compression用的是权重级剪枝这也是论文能在精度上做到无损的关键。不过代价是压缩后的稀疏矩阵没法用规则的方式存储必须启用CSR/CSC这类稀疏存储格式。3.3 存储格式里的门道剪枝省了参数索引没少花剪枝完之后模型从稠密矩阵变成了稀疏矩阵。你虽然把90%的权重值省了但你得记录哪些位置还有值。论文用了标准的CSRCompressed Sparse Row格式存储非零权重值value、每行的列索引index、以及每行起始指针pointer。CSR的精妙之处在于它把二维稀疏矩阵用三个一维数组表示。你存取数据时不需要扫整个矩阵直接跳着访问有效位置。论文里AlexNet剪枝后的非零参数约470万个如果用CSR存储权重值占19.6MB精度的4字节乘以470万索引占大约一半的存储量。有一个细节值得注意剪枝幅度过大时索引的存储占比会上升最终压缩比反而降低。论文里CNN层和全连接层都取了相对温和的剪枝幅度因为后接的量化步骤还能继续压权重值的位数但索引是没办法量化的——这就是为什么论文强调每个环节的收益要考虑与后续步骤的配合。我当时第一次看这个细节时有点意外原来剪枝并非越狠越好是和其他压缩步骤全局联动的。技巧在做剪枝时记得把索引存储开销算进最终文件大小而不是只看参数个数减少百分比。不然你在实验环境里沾沾自喜落地部署时才发现文件没小多少。3.4 全连接层是剪枝的重头论文里的统计数据很清楚AlexNet的6000万参数里约5800万在三个全连接层卷积层加起来只有230万。剪枝的主要收益来自全连接层——它们被压缩掉约90%以上。这也顺势解释了为什么后来的MobileNet、SqueezeNet等架构流行用全局平均池化更小的全连接层设计不仅是减少计算量更是从结构上消灭压缩难度最大的参数密集区。在我的实操经验里对全连接层剪到10%保留率基本不会有精度问题但卷积层的剪枝要保守得多一般保留50%-70%就已经会让精度出现波动。如果看到精度掉太多优先把卷积层的剪枝阈值调低而不是盲目微调学习率。4. 第二步权重量化让每一块存储物尽其用剪枝把参数数量砍到了约1/10但这部分参数仍然用32位浮点存储体积还是有压缩空间。Deep Compression的第二层压缩是权重量化核心手段是权重共享和K-means聚类。4.1 权重共享把相似的权重归为一类只存代表值量化最朴素的做法是把每个浮点权重直接近似成一个低精度整数例如8bit。这种方法简单但容易累积误差。Deep Compression采用了另一种思路权重聚类。把网络中所有的权重值看成一大包散落的点用K-means算法把它们分成k个簇每个簇求一个中心值——这个中心值就是这个簇里所有权重的共享权重。存储时你不需要保存每个权重本身只需要保存它属于哪个簇也就是一个索引号。举个例子假设某层有100万个权重我们用8bit量化即聚类数k256。那这层权重存储时只有100万个8bit索引共0.95MB外加256个浮点中心值共1KB。相比原来4MB的浮点权重压缩了约4倍。这里有个关键数学事实K-means聚类的误差用簇中心近似簇内全部值是模型精度损失的来源。簇的数量越多量化越细腻但存储量也越大。Deep Compression的做法是按层分配位宽——卷基层用8bit全连接层用5bit因为不同层对量化误差的敏感度不一样。4.2 为什么量化精度损失比想象中小直觉上把上百万个不同的权重值压缩成256个代表值网络精度早就该崩了。但实验结果恰恰相反在剪枝之后做量化精度几乎不掉。原因是多方面的第一神经网络本身对权重扰动有一定容错能力。只要样本量足够大、网络有冗余结构轻微的权重变化会被后续的激活函数和批归一化吸收。第二K-means聚类是数据驱动的中心值落在权重分布密集的地方换句话说大多数权重值本来就接近你只是把它们的中位数拿出来代表它们而已误差是二阶的。第三论文在量化之后还做了一次微调retraining更新的是每个簇的中心值而不是每个原始权重。这等于给了网络一次校正的机会误差被进一步压低。4.3 量化位宽分配卷基层8bit全连接层5bit的秘密Deep Compression论文里有一张非常出名的表格对比了不同位宽配置下的精度。结论是对AlexNet卷积层量化到8bit、全连接层量化到5bit时与原始模型相比精度差异最小再压到4bit精度损失开始变明显特别是卷积层。为什么卷积层更挑量化位宽我的理解是卷积层的权重数量少、但每个权重都被大量输入像素重复使用——一个3×3卷积核会在特征图的每个位置滑动做乘加。它的一点误差会被空间重复计算放大。而全连接层的权重虽然参数量大但每个权重只被使用一次且全连接层在网络末端的特征已经高度抽象少量扰动影响有限。实操中我后来做量化感知训练时也有同样的感受给第一层卷积和最后一层全连接分配更高的位宽中间层可以放宽到低位宽。这不是论文里的标准答案但确实是从这个分析中延伸出的有效策略。4.4 量化后的存储结构索引加中心值表量化后的存储结构很清晰你需要保存一张码本也就是每个簇的中心值以及每个权重对应的索引。读取时先用索引查表得到中心值再进行计算。因为压缩后的矩阵已经稀疏论文把稀疏存储和量化存储做了融合索引的排列也做了重排让相同簇索引尽量连续方便后续霍夫曼编码更高效。这部分的启发是压缩不光要考虑每个参数用什么位数还要考虑你压缩完之后的数据排布是否利于下一步操作。论文在工程层面做得相当细致每一个存储布局都是为了下一次压缩继续打开空间。5. 第三步霍夫曼编码把最后一点统计冗余榨出来剪枝和量化已经把模型从240MB压缩到了大约6.9MB这已经是35倍的压缩了。为什么还要做霍夫曼编码因为量化之后的权重分布并不是均匀的——大多数权重值集中在少数几个聚类中心附近这意味着索引值的出现频率差异极大。对高频出现的索引用短编码对低频出现的索引用长编码。整体平均编码长度就能显著小于定长编码。5.1 霍夫曼编码的原理一个类比霍夫曼编码的原理不复杂但要理解它为什么在这里适用最好用一个例子。假设有四个索引值A、B、C、D分别出现概率是0.5、0.25、0.125、0.125。如果按定长编码每个索引需要2bit100个索引占200bit。如果用霍夫曼编码给高频的A分配1bit、B分配2bit、C分配3bit、D分配3bit那100个索引的期望总长度是50×1 25×2 12.5×3 12.5×3 175bit。省了12.5%。在剪枝和量化之后索引的分布往往高度偏斜——很多权重值收敛到非常接近的数对应同一个聚类中心这进一步拉大了频率差异。论文报告霍夫曼编码在AlexNet上为全连接层省了约20%-30%的空间整体模型从9.9MB降到了6.9MB。5.2 为什么编码对整个流程是锦上添花你在实操中如果自己做过模型压缩会发现在量化之后做熵编码收益往往比理论预估略低因为真实分布并不是理想的偏斜分布。但Deep Compression证明了一个重要的工程原则压缩是流水线每一层的冗余都要处理干净不能留死角。除此之外论文作者还做了一个有意思的观察网络中权重分布经过剪枝和量化后有相当一部分权重值精确等于0剪枝置零的部分而0又是一个极高频值用一个很短的码字即可所以霍夫曼编码的收益比想象中更大。5.3 编码过程需要注意的坑霍夫曼编码虽然是无损压缩但解码时需要额外存储码表。模型文件体积不大时码表的开销占比不能忽略。论文里实测下来码表带来的开销在总体积的1%以内可以接受。如果你自己动手做记得把码表存成紧凑格式别直接存字符串映射否则字节数会膨胀。另外霍夫曼编码对压缩后的数据是按层还是全局做论文的做法是按层构建码表因为每层的权重分布差异很大分开编码能获得更高的压缩率。这个细节也提示一个通用经验对分布差异大的数据段分而治之地做统计编码往往比全局编码更优。6. 三管齐下的实验结果从AlexNet到VGG-16压缩比为何这么高论文的实验部分是我每读一次都忍不住细看的章节。它不仅给出了压到多小的数字更拆解了每一层贡献了多少压缩。6.1 关键数据回顾用表格整理一下论文的核心结论模型原始体积压缩后体积压缩比精度变化AlexNet240MB6.9MB35xTop-1从57.2%到57.2%无损VGG-16552MB11.3MB49xTop-1几乎无损LeNet约1.7MB约40KB40x几乎无损这份表格精彩之处在于压缩比差异VGG-16压缩比高于AlexNet。原因在于VGG-16的全连接层占比更大而全连接层正是剪枝和量化收益最集中的区域。这给了我们一个启示模型压缩的效果上限很大程度上取决于模型的结构。全连接层越多、越大Deep Compression的收益越明显。6.2 三层的收益拆解以AlexNet为例我按论文的表格重新算了一遍剪枝将参数量从6000万降到约630万体积从240MB降到约33MB。量化权重从32bit降到平均约5.3bit体积进一步降到约9.9MB。霍夫曼编码对索引和码表做二次压缩体积降到最终的6.9MB。三层压缩比的乘积约为35倍。剥开看每一层的贡献剪枝约7倍量化约3.3倍编码约1.4倍。如果只做量化不做剪枝压缩比大约只有4倍只做剪枝不做量化大约8倍。三者相乘才达到35倍。这解释了为什么后来很多工作尝试做端到端的联合优化效果却难以超越这篇论文——因为这三个步骤的误差来源不同耦合方式精巧缺一环效果都会大打折扣。6.3 精度为什么能守住一个我非常关注的细节是论文里的精度对比是在压缩后再微调的基础上进行的。也就是说每个环节后都做了重训练来恢复精度。剪枝后微调、量化后微调。这不是魔术而是深度学习模型优化的一般规律稀疏和量化后的网络仍然可训练误差可以被优化算法修正。同时论文还在实验部分展示了不同剪枝比例下的精度变化曲线结论是前50%的参数被剪掉时精度几乎一动不动到90%剪枝率时才出现轻微下降。这个现象的启发是网络容量的实际冗余远大于大多数人的直觉而这种冗余来自深度网络高速学习和独立特征表达的叠加效应。7. 论文之外Deep Compression引发的连锁反应与我的实操体会一篇顶会论文的影响力从来不只停留在论文本身。Deep Compression之后深度模型压缩和加速迅速成为独立的研究方向后续的很多重量级工作都能看到它的影子。7.1 从软件算法到硬件加速器的延伸论文作者团队后来紧跟着发表了EIEEfficient Inference Engine专门为Deep Compression后的稀疏量化模型设计硬件加速器。EIE的核心洞察是既然模型已经稀疏又量化那么硬件上就可以跳过零权重、用等位宽的低精度乘法器去算从而把计算效率和能效比拉高一个数量级。为什么这对工业界重要因为模型压缩有两种收益第一种是省存储第二种是省计算。Deep Compression的存储收益是显而易见的但稀疏矩阵在通用处理器上计算并不会自动变快——处理器依然要遍历所有位置只是跳过值而已。只有在硬件层面针对稀疏性做设计才能真正把压缩变成加速。这个思路对我后来的工作方式影响很大每当做一个模型压缩方案我都会先想清楚优化目标到底是减小包体还是降低推理时延还是降低功耗。不同目标对应的技术路线完全不同混在一起做只会两头不讨好。7.2 为什么后续无法简单照搬我在实际项目中尝试复现Deep Compression时也踩过一些后者论文里没有明说的坑第一个坑是剪枝阈值的选择。论文里用固定阈值删除权重但实际场景中不同层的权重分布方差差异很大固定阈值很容易让某些层被过度剪枝、另一些层几乎没剪。我后来改用按层设定目标稀疏率通过排序取分位数来自适应确定阈值效果好很多。这一点论文没写但你在复现时大概率会遇到同样的问题。第二个坑是量化中心的初始化方式。K-means的初始簇中心会影响最终的聚类结果和精度表现。论文里对比了三种初始化方法包括随机初始化、按权重密度分布初始化、线性初始化结论是线性初始化在较大位宽下表现最好但如果你用的模型结构不同这个结论不一定成立。建议按自己的网络实测一下。第三个坑是微调的学习率。剪枝和量化后的微调网络已经被改变原本的学习率往往偏大容易破坏已保留的权重。把学习率设成原来的1/10到1/20是我多次实验后的经验稳妥且精度回弹快。第四个坑是批归一化层的处理。如果你的模型里有BN层压缩后再微调时必须固定BN层的running mean和running variance或者用训练集重新统计。否则小批量训练时统计量抖动会引发精度大幅波动这个现象在稀疏模型中比稠密模型更明显。7.3 论文里被低估的三个洞察每读一遍论文我都能发现一些第一次没注意到的细节。这里挑三个印象最深刻的第一压缩比例不是越多越好。论文虽然展示了最高49倍的压缩比但同时也大方地展示了精度-压缩比曲线。当压缩比翻倍之后精度开始出现缓慢下降到极限压缩比时精度损失接近2%-3%。这对工业应用是值得斟酌的——你为了把模型再压小20%可能要牺牲2%的精度对某些任务比如医学影像是不可接受的。所以实际落地时目标压缩比最好设置在有安全余量的区间。第二全连接层和卷积层的压缩潜力不对称。论文反复强调全连接层贡献了大部分压缩。从另一个角度解读这等于指明了模型结构设计的方向如果你的模型注定要在端侧运行在设计网络架构时就该少用大全连接层把参数集中在卷积层。后来MobileNet那一脉工作其实正是这个思路的极致化。第三稀疏量化的联合存储格式本身就是一种架构设计。论文花了不少篇幅描述如何把剪枝后的稀疏索引、量化后的聚类索引和数值存储融合在一个紧凑的文件格式里。现在很多工业界的模型压缩框架仍然在使用类似思路但很多人没有意识到存储格式设计其实是压缩和硬件加速之间的桥梁——格式定得好后续无论是加载、解码还是稀疏计算都能少踩坑。7.4 和当下的模型压缩工具链怎么衔接放到今天的视角看Deep Compression的核心思想已经内化到各类开源框架中。PyTorch的torch.prune提供了灵活的剪枝APITensorFlow Lite的post-training quantization是量化的工业级标准实现MNN、NCNN这些端侧推理引擎也原生支持量化模型。但理解Deep Compression的原理依然对用好这些工具有不可替代的价值。举个例子你用TensorFlow Lite做训练后量化发现模型精度掉了报错信息只告诉你某些ops不支持量化却不会告诉你该怎么调整。如果你熟悉Deep Compression里层敏感度分析的思想你就能想到把敏感层单独保留浮点其余层量化精度就能回来。这种经验不是在工具文档里能学到的。再比如你手头有一个训练好的模型想做剪枝直接用框架里的自动剪枝工具结果精度崩了。框架不会告诉你微调时学习率要调低、BN层统计量要固定。这些坑读完这篇论文再去操作你会有心理预期遇到问题也更容易判断是哪个环节出的错。7.5 如果再给我一次重读的机会我会重点看什么如果让我重新读这篇论文我会把注意力放在三类信息上第一实验表格里的微小细节。比如不同位宽下的精度差、不同剪枝比例下的精度差这些数字直接告诉你操作时的安全边界。很多读者只记住了35倍和49倍这两个最终数字反而漏掉了最有工程价值的那部分数据。第二存储格式的图。论文里有几张稀疏矩阵存储格式的示意图第一次看可能觉得枯燥但后来你在设计自己的模型文件格式时会发现这些图几乎就是最佳实践的模板。第三作者对为什么有效的论述。论文写得很克制但在实验分析部分给出了一些解释。这些解释未必是严格的数学证明但能帮你建立正确的直觉——而正确的直觉在日后调试模型时比任何公式都管用。8. 写在最后一次阅读带来的长期影响从第一次读这篇论文到现在我的工作重心已经变成了端侧AI模型的优化和部署。回头看Deep Compression教给我的远不只是剪枝和量化的具体操作而是一种思维定式优化一个复杂系统时与其追求一个大而全的魔法方法不如冷静拆解系统的冗余来源把已有技术按正确的顺序、以正确的接口组合起来反复打磨每个环节。这套方法论后来出现在我做过的几乎所有优化项目里哪怕不是模型压缩而是推理延迟优化、内存占用控制我都会先问自己一个问题——现在系统里最大的浪费在哪一环去掉这个浪费需要付出什么代价怎么把代价降到最低这种拆冗余的思路其实就是Deep Compression在2016年做过的事而它放在今天依然适用。最后分享一个小技巧如果你也想完整地吃透一篇论文建议像我这次一样不只读正文还要把每张表格里的数字自己算一遍。比如论文说AlexNet压缩到6.9MB你就试着用剪枝比例、量化位宽、稀疏存储开销这些参数自己推演一遍。推演出来的数字也许和论文略有出入但这个过程会让你真正理解每个环节的贡献而不是仅仅记住一个结论。知易行难这篇随笔就当是陪你做了一次这样的推演。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑