尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

HAMP-LIC:用Hessian感知混合精度量化压缩学习图像压缩模型

HAMP-LIC:用Hessian感知混合精度量化压缩学习图像压缩模型 学习图像压缩Learned Image CompressionLIC近年来的表现可以说相当亮眼。无论是 PSNR、MS-SSIM 还是码率控制基于深度学习的方案已经逐步追平甚至超越了传统编码标准。但真到了部署阶段很多工程师会碰到一个很现实的问题模型太大、推理太重。一个移动端 App 要内置这套压缩模型不仅要考虑存储空间还要考虑每张图压缩时的耗电和时延。这里就引出了今天的主角HAMP-LIC。它做的事情可以一句话说清——用 Hessian 感知的混合精度量化把学习图像压缩模型压缩到更小、更快同时尽量不损失编码性能。这篇文章我从三个层面展开先讲清楚为什么 LIC 模型这么难量化再拆解 HAMP-LIC 的核心思路也就是 Hessian 信息如何指导比特分配最后给出可落地的伪代码和工程建议。如果你正在做 LIC 模型的端侧部署、模型压缩或者只是对“训练后量化为什么需要二阶信息”感兴趣这篇文章值得读完。1. 学习图像压缩模型到底卡在哪里先回到 LIC 模型的基本结构。现在的主流方案基本都是基于自编码器架构编码器将图像映射为潜变量latent representation量化后经过熵编码压缩成比特流解码器再从比特流重建图像。为了让码率尽量低模型里还有一个熵模型entropy model通常是超先验加自回归上下文的结构用来估计潜变量的概率分布。这套设计带来了两个让量化变得棘手的特点。第一整个链路对误差高度敏感。量化会引入误差而误差会沿着编码器、熵模型、解码器层层传导。尤其熵模型输出的概率估计如果出现偏差熵编码的码率就会失控解码器的重建质量也会因为累积误差明显下降。第二不同模块对数值精度要求完全不同。如果通篇用 8-bit 量化可能模型体积是变小了但重建图像开始出现肉眼可见的块效应和纹理丢失如果通篇用 4-bit 量化情况更糟甚至会出现编码失败或解码结果完全不可用的情况。这里真正需要的是“该省的地方省该保的地方保”。混合精度量化正是这个思路让关键层保留较高比特位宽对不敏感的层果断用更低比特位宽从而在模型大小、推理速度和重建质量之间找到平衡点。但问题来了哪一层是关键层怎么判断很多人的第一反应是用参数量或激活值大小来判断敏感度。这其实是一种直觉性误区。一个层参数量大不代表它对量化误差敏感激活值大的层也可能在损失函数层面影响很小。真正决定量化误差对整体性能影响程度的是损失函数对这一层参数的“曲率”。也就是说判断敏感度要找对数学工具而 Hessian 矩阵就是描述这种曲率的标准工具。2. 量化基础均匀量化、训练后量化和混合精度在深入 HAMP-LIC 之前先把量化相关的几个概念捋清楚。这些概念本身不难但理清边界能避免后续混淆。2.1 均匀量化量化就是把连续的浮点数值映射到有限的离散整数集合。权重由 FP32 变成 INT8意味着原来 32 位表示的数现在只能有 256 个取值。最常见的就是均匀量化q round(r / s) z其中r是原始浮点值q是量化后的整数s是缩放因子z是零点。反量化则是r_hat (q - z) * s这里的s和z是量化参数决定了一个张量如何从浮点空间映射到整数空间。均匀量化的优点是实现简单、硬件支持好缺点是对所有数值一视同仁。如果一个层的数值分布范围很广或者有离群点量化误差就会变得很大。实际工程中经常用 per-channel 或 per-tensor 的粒度来缓解这个问题但这属于量化粒度的调整和混合精度是两个维度。2.2 训练后量化训练后量化Post-Training QuantizationPTQ的意思是模型已经训练好了我不再动它的权重只是利用一小部分校准数据统计激活值的分布范围然后直接做量化。相比量化感知训练Quantization-Aware TrainingQATPTQ 不需要重新训练模型也不需要完整训练集所以成本低、速度快特别适合那些没有原始训练数据、或者训练流程复杂的场景。缺点也很明显没有梯度反传来“纠正”量化误差一旦量化误差超出模型容错范围性能下降会比较明显。所以 PTQ 要想效果好必须在“如何降低量化误差”上做文章。这也是 Hessian 信息能发挥作用的地方。2.3 混合精度量化混合精度量化不是给每个层都分配相同的位宽而是为不同层或不同权张量分配不同的比特数。比如某些层保持 8-bit某些层降到 6-bit少数高敏感层甚至保持 12-bit 或 16-bit。混合精度带来的收益很直接在相同的平均比特数预算下找到更优的“精度-冗余”分配可以在更小的模型体积下保持更高的性能。但混合精度有两个难点搜索空间巨大。假设有 100 层每层有 4 种位宽选择组合数就是 4 的 100 次方靠穷举不现实。敏感度难以量化。不同层的敏感度不是均匀的需要用合适的方法度量。传统的做法是用层权重的 L2 范数或梯度范数来近似敏感度但这些方法只考虑一阶信息。HAMP-LIC 的做法更直接——用 Hessian 矩阵来刻画每一层对最终损失的敏感程度再基于这个敏感度做比特分配。3. HAMP-LIC 的核心Hessian 矩阵3.1 什么是 Hessian 矩阵如果你对数学细节不熟可以先把它理解为一个“曲率矩阵”。损失函数L(w)对参数w的梯度g ∂L/∂w给出的是当前位置的下降方向这是一阶信息。而 Hessian 矩阵H ∂²L/∂w²给出了损失函数曲面在当前点“弯曲得多厉害”这是二阶信息。想象你在山路上下坡梯度告诉你哪个方向最陡Hessian 则告诉你脚下的坡度会不会突然变陡或者变平。在量化场景中Hessian 告诉你如果这个参数被扰动一点点损失函数会变大多少。3.2 为什么 Hessian 对量化有意义量化本质上就是对参数施加了一个扰动Δw。把损失函数在训练好的权重点w*附近做泰勒展开L(w* Δw) ≈ L(w*) g^T Δw 1/2 Δw^T H Δw因为模型已经训练好在极值点附近梯度g很小甚至可以近似为 0。这时候损失变化主要由二阶项决定L(w* Δw) - L(w*) ≈ 1/2 Δw^T H Δw这个式子意味着什么如果某层的 Hessian 很大哪怕量化引起的权重扰动Δw很小损失变化也可能非常大。反过来如果 Hessian 很小即曲线很平坦即使权重被扰动得厉害损失也不会有明显变化。所以 Hessian 信息比参数大小、梯度大小更能反映量化敏感度。这也是 HAMP-LIC 采用 Hessian 作为敏感度度量标准的理论动机。3.3 从完整 Hessian 到 Hessian 迹完整计算 Hessian 矩阵对现代深度学习模型来说是不现实的。一个 100 万参数的模型Hessian 矩阵就有 10 的 12 次方个元素存储和计算都不现实。所以实际工程中做 Hessian 近似通常是计算 Hessian 的迹trace也就是对角线元素之和Tr(H) sum(H_ii)Hessian 的对角线元素表示每个参数对损失曲率的局部贡献。Hessian 的迹则给出了整体的“曲率强度”是一个标量计算和比较都很方便。更简化一点还可以用 Hutchinson 方法做迹估计。这种方法用随机向量z多次采样计算z^T H z的期望来逼近Tr(H)。这样连 Hessian 矩阵都无需显式构造只需要利用 PyTorch 的自动微分机制每次计算一个标量z^T ∇L再对参数求一次梯度就行。4. HAMP-LIC 方法拆解从敏感度到比特分配理解 HAMP-LIC 的整体流程可以从四个阶段来看。4.1 阶段一收集训练好的 LIC 模型和校准数据HAMP-LIC 是训练后量化方法所以它假设你已经有一个完成训练的 LIC 模型。校准数据一般是从训练集或验证集中抽一批有代表性的图像不需要带标签只需要覆盖多样化的内容场景。这里有个值得注意的点LIC 模型的训练目标是率-失真损失不只是重建损失。所以校准阶段不仅要关注重建质量还要关注码率估计的准确性。如果熵模型的概率估计被量化打乱码率会上升或解码失败。4.2 阶段二对模型分组并估计各组的 Hessian 信息不是逐参数做敏感度分析而是把模型分成若干组。分组可以按层也可以按更细的粒度。HAMP-LIC 的思想是把模型划分成多个模块每个模块用 Hessian 迹作为敏感度指标。具体做法是前向传播计算当前模块输出用重构误差或率-失真损失构造目标函数对目标函数取梯度再用 Hutchinson 方法估计各模块的 Hessian 迹。这一步计算量虽然比单次前向传播大一些但因为不需要反向传播到整个网络重建完整的 Hessian整体成本仍然远低于重新训练。4.3 阶段三基于敏感度做混合精度比特分配拿到每组参数的 Hessian 迹之后核心问题变成在总比特数预算的约束下如何让每组参数的位宽分配最优。这是一个典型的组合优化问题可以用动态规划或贪心策略求解。贪心策略的思路非常直白先将所有组设为默认低比特位宽计算每组位宽提升一档带来的“敏感度降低收益”与“体积增加成本”的比值每次选收益率最高的一组提升位宽直到总比特预算用尽。换句话说HAMP-LIC 的核心是把比特预算当作一种“资源”来分配让高敏感度层拿到更多比特低敏感度层保持低位宽。从资源分配的角度来理解这样的设计很直观。4.4 阶段四量化重写和校验分配完位宽后用标准 PTQ 流程把模型量化成混合精度版本。这一步通常需要校准集来确定各层缩放因子和零点然后做一次量化模拟quantization simulation比较量化前后模型的率-失真指标变化。如果在校验中发现某些组的重建质量退化明显可以回头调整该组的比特分配。这是一个迭代过程但实际跑起来通常不超过两三轮整体成本远低于 QAT。5. 与传统敏感度分析方法的对比方法敏感度度量是否考虑层间交互计算成本适用场景参数范数权重大小否极低快速粗筛精度一般梯度范数一阶导数否低近似敏感度忽略曲率逐层 MSE 消融逐层量化误差部分高小模型可尝试Hessian 迹二阶曲率是中适合 PTQ 精准分配从这张表能看出Hessian 方法最大的价值在于“考虑了损失曲率”而不仅仅看参数本身。这也是它在理论上更精准的原因。不过需要注意并没有免费午餐。Hessian 近似也有自身问题它依赖校准集校准集分布和真实数据分布偏差太大会导致敏感度评估失真而且 Hessian 是局部信息如果量化后的权重偏移离原始工作点太远局部近似的可靠性就会下降。所以 HAMP-LIC 在实际使用时仍然需要保留一个“校验-修正”环节。6. 伪代码与工程落地思路下面给出一套基于 PyTorch 概念验证的代码示例。需要说明的是这不是论文作者的官方实现而是帮助你理解整个流程的最小示例。生产环境需要根据你的模型结构做适配。6.1 用 Hutchinson 方法估计 Hessian 迹import torch def hutchinson_trace(model, loss_fn, data_batch, num_samples10): 使用 Hutchinson 方法估计模型参数 Hessian 的迹。 这里的 loss_fn 接收 model 的中间输出并计算损失。 model.eval() trace_sum 0.0 num_params sum(p.numel() for p in model.parameters()) # 计算损失对参数的梯度g dL/dw loss loss_fn(model, data_batch) grads torch.autograd.grad(loss, model.parameters(), create_graphTrue) for _ in range(num_samples): # 生成与参数同形状的随机向量 z z [torch.randn_like(p) for p in model.parameters()] # 计算 z^T * grad得到标量 z_grad sum((zi * gi).sum() for zi, gi in zip(z, grads)) # 对标量再求梯度d(z_grad)/dw即近似 H*z hz torch.autograd.grad(z_grad, model.parameters(), retain_graphTrue) # 计算 z^T * (H*z) 并累加 trace_sum sum((zi * hzi).sum() for zi, hzi in zip(z, hz)) return trace_sum / num_samples这段代码的关键逻辑是第一次autograd.grad得到的是梯度g因为设置了create_graphTrue所以可以继续对梯度求导。随机向量z与梯度做点积得到标量后再对该标量求参数梯度就得到了H.z的方向导数近似。反复采样并取平均实现Tr(H) ≈ E[z^T H z]。注意这个示例对全模型参数做估计实际使用时更推荐按层或按模块分组分别估计每组参数的 Hessian 迹。6.2 分组 Hessian 敏感度估计def estimate_group_sensitivity(model, group_list, calib_loader, num_samples5): 对每个参数组层/模块估计 Hessian 迹作为敏感度指标。 group_list: 例如 [model.encoder, model.hyperprior, model.decoder] sensitivities {} for name, group in group_list.items(): trace_val hutchinson_trace_for_group(group, calib_loader, num_samples) sensitivities[name] trace_val return sensitivities实际工程中hutchinson_trace_for_group的核心思想是对某个组的参数估计 Hessian 迹时尽量冻结其他组参数让梯度只流经目标组。这样可以避免不同组的曲率信息互相混淆。6.3 基于敏感度的贪心比特分配def greedy_bit_allocation(sensitivities, bit_options, bit_budget): 贪心策略分配比特 sensitivities: {组名: Hessian迹值} bit_options: 可选位宽列表例如 [4, 6, 8, 12] bit_budget: 总比特预算相对大小 groups list(sensitivities.keys()) # 初始化所有组为最低位宽 current_bits {g: min(bit_options) for g in groups} total_bits sum(current_bits.values()) # 计算每个组从低到高提升位宽的“收益-成本比” while total_bits bit_budget: best_gain -float(inf) best_group None best_next_bit None for g in groups: cur_bit current_bits[g] valid_next [b for b in bit_options if b cur_bit] if not valid_next: continue next_bit min(valid_next) # 收益近似为敏感度提升的比例成本为位宽增量 gain sensitivities[g] * (next_bit - cur_bit) / (next_bit - cur_bit) if gain best_gain: best_gain gain best_group g best_next_bit next_bit if best_group is None: break total_bits (best_next_bit - current_bits[best_group]) current_bits[best_group] best_next_bit return current_bits这段示例的gain计算其实是一个简化版本实际使用时可以换成更合理的度量比如“Hessian 迹 × 量化扰动减少量”除以“位宽增量”。不过核心思想是明确的优先给高敏感度组分配更高的位宽。到这里你会看到HAMP-LIC 的工程实现并不复杂难的是把 Hessian 轨迹估计做准、把分组粒度选好、把比特预算设置得符合部署需求。7. 实验验证与效果分析关于实验部分我没有进行实际复现所以下面只基于论文公开信息做客观描述不编造具体测得的数值。从论文标题和摘要传达的信息来看HAMP-LIC 主要展示了以下几点第一在码率-失真性能保持方面HAMP-LIC 相比均匀位宽量化有明显优势。这符合直觉均匀量化要么把资源浪费在不敏感的层上要么让高敏感层精度损失过大。混合精度方案则规避了这两类问题。第二Hessian 信息确实比一阶信息梯度范数更适合指导比特分配。原因是训练好的模型已经处于损失曲面较平坦的区域一阶梯度很小区分度有限二阶信息才能更好地区分“敏感但平坦”和“不敏感且平坦”的参数。第三作为 PTQ 方法HAMP-LIC 将量化成本控制在了可接受范围内。相比 QAT 动辄需要重新训练数个 epoch 的代价PTQ 只依赖少量校准数据和几次前向反向传播对没有 GPU 训练资源的团队更友好。如果要自己复现验证建议关注以下指标量化前后 PSNR 和 MS-SSIM 的变化量化前后 BD-Rate 的变化每个模块最终分配的位宽分布模型体积压缩率和端侧推理时延的提升。8. 常见误区与工程建议8.1 误区Hessian 越大层越重要应该分配更高位宽这是最常见的误解。Hessian 大代表的是“这层对量化扰动敏感”并不一定代表这层在任务中更“重要”。如果一层的 Hessian 很大但它的量化参数非常稳定比如分布范围很固定那么即使它敏感也可能因为校准集选得好而没有太大问题。反过来有些层虽然 Hessian 小但一旦量化误差累积到下游影响反而很大。正确的理解是Hessian 给出的是局部扰动影响不是全局重要性。最终分配位宽时还需要结合具体部署目标和量化误差的实际传播情况。8.2 误区混合精度量化后模型一定比均匀量化更好这取决于比特预算的设置。如果总比特预算足够高均匀量化也能保持不错的效果如果预算定得太低混合精度也只是把质量下降推给某些低敏感层并没有真正消除误差。混合精度的价值在于相同预算下的效率提升而不是“免费午餐”。8.3 工程建议校准集一定要多样化。Hessian 估计依赖校准集如果校准集只有风景图部署时遇到人像或文字截图量化误差可能明显增加。建议校准集覆盖人像、风景、文字、屏幕截图、低光图像等类型。分组粒度要权衡。按层分组计算量小但精度不如按模块细粒度分组按通道分组效果好但计算成本和索引开销更高。建议先按层分组跑通流程再逐步细化。保留原始模型用于校验。量化后的模型性能下降是否可接受必须和原始模型逐图对比。建议脚本化这个对比过程确保任何位宽调整都可以快速验证。关注熵编码的耦合。LIC 模型量化后熵模型输出的概率分布可能变化导致熵编码的码率统计失真。量化后要实测码率而不是只看重建质量指标。考虑硬件位宽支持。分配位宽时要提前确认目标硬件的算子库支持哪些位宽。比如有的移动端推理引擎只支持 INT8 和 INT16你分配 INT12 可能反而会引入反量化开销。9. 总结与后续学习方向HAMP-LIC 这work最有价值的点不在于它发明了什么全新网络结构而在于它找到了一个更合理的量化决策依据——用 Hessian 信息指导混合精度比特分配。这件事放在学习图像压缩场景下尤其有意义因为 LIC 模型对量化误差天生敏感而每个模块的敏感度又差异极大。用二阶信息做分配理论上就比用参数量、梯度范数这类一阶方法更贴近问题的本质。如果你想继续深入建议按照这条路线走先跑通一个最小 LIC 模型比如基于超先验架构的简易实现在模型上做一个最简单的均匀 INT8 量化体会量化误差对重建质量和码率的影响再按本文的伪代码实现分组 Hessian 迹估计和贪心比特分配对比不同分配方案在真实编码任务上的表现记录 PSNR、MS-SSIM 和码率变化。最后提醒一点量化是一个系统工程模型结构、校准集、位宽分配、硬件支持、熵编码耦合都会影响最终效果。HAMP-LIC 解决了“敏感度度量”这一环但它不替代完整的部署验证。建议在项目早期就把量化验证纳入模型迭代流程而不是等模型训练完再临时抱佛脚。这样一旦发现量化后性能不可接受可以及时调整模型参数或结构设计而不是在部署阶段被迫返工。
返回列表