ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

HAC框架:用哈希网格重构3D高斯压缩范式

HAC框架:用哈希网格重构3D高斯压缩范式 从无序到结构化HAC框架如何用哈希网格重构3D高斯压缩范式我最早注意到 HAC 这个工作是在 ECCV2024 的论文列表里。当时标题里同时出现“哈希网格”和“3D高斯压缩”这两个词我就知道这又是一篇想解决 3DGS 落地痛点的文章。3D高斯泼溅3D Gaussian Splatting这两年确实火渲染效果好、速度也快但模型体积一直是硬伤——训练完一个场景动辄几百 MB甚至上 GB放在手机端、Web端根本没法用。HAC 的价值在于它没有走“训练后再压缩”的老路而是把压缩思想直接嵌进训练过程通过哈希网格把原本无序的高斯集合重新组织成规则结构让冗余信息从一开始就被抑制掉。这篇文章我会从问题背景、框架设计、核心机制、训练配置、效果权衡到实际避坑完整拆一遍适合正在做 3DGS 落地的同学、研究神经渲染压缩方向的人以及所有被大模型体积困扰的开发者参考。1. 先从3D高斯泼溅说起为什么压缩成了绕不开的问题1.1 3D高斯泼溅为什么能火3D 高斯泼溅能火本质上是因为它把神经渲染从“慢查询”变成了“快光栅”。传统 NeRF 系列要沿光线采样一堆点每条光线都要过一遍 MLP渲染一张图要跑到秒级。3DGS 的思路完全不同它把场景表示成一组显式的高斯原语每个高斯带自己的位置、旋转、缩放、颜色和不透明度渲染时直接做 splatting把高斯投影到图像平面上再按深度排序混合。这个过程完全可以用 GPU 光栅化管线加速1080P 分辨率下实时跑到上百 FPS 是很常见的。这种显式表示带来的好处是可控性强。你可以像操作点云一样增删改查高斯场景局部更新不用重训整个网络这对编辑、压缩、流式传输都非常友好。但也正因为“显式”场景里到底有多少个高斯、每个高斯存多少属性全部直接暴露在存储层面。训练初期优化器先铺一批稠密高斯覆盖整个空间然后通过剪枝和克隆不断调整密度最终一个复杂场景保留几十万到上百万个高斯是非常正常的。每个高斯至少要存位置、四元数旋转、三轴缩放、球谐系数颜色、不透明度这五类属性。球谐系数尤其吃空间——如果用到三阶球谐就是 48 个浮点数再加上其它属性单个高斯随随便便上百个 float。你简单算一下100 万个高斯每个 100 个 float那就是 4 亿个浮点数按 4 字节算就是 1.6GB。这个账一算你就明白为什么大家都盯着压缩不放了。1.2 压缩的难点在哪有人可能会问直接对属性做量化、熵编码不就行了表面上这确实是一条路但实际做下来效果并不理想。这就要说到 3DGS 数据结构的“无序性”问题。神经网络压缩之所以效果好是因为网络参数天然排列在规则的张量结构里卷积核、权重矩阵这些都有固定的空间关系熵编码模型可以轻松学到这种结构规律预测出准确的概率分布来压缩。NeRF 系方法走这条路就很顺权重矩阵本身就是规则网格。但 3DGS 是一堆离散高斯的集合高斯之间存在什么顺序没有任何顺序。训练完存文件时高斯的排列顺序可能完全由优化过程中的内存布局决定不同批次训练出来的文件内部顺序都不一样。无序带来两个直接后果。第一相邻存储位置的高斯之间没有空间关联传统索引结构没法直接使用你写熵编码模型时根本找不到一个合理的上下文窗口。第二场景里有大量视觉冗余比如一面纯色墙壁可能有上万个几乎相同的高斯但因为没有空间分层压缩算法很难快速识别出这种重复性。早期的 3DGS 压缩工作大多在存储层做后处理把高斯属性先量化再排序然后对排序后的属性流做熵编码。这里排序的思路是对的——把相近属性放在一起可以提高熵编码效率。但问题在于属性值相近不代表空间位置相近更不代表这些高斯可以被合并或用更高层的结构去表达。真正高效的压缩应该发生在表示层面而不是文件格式层面。HAC 迈出的关键一步就是不再把 3DGS 当成“一堆离散高斯”而是重新组织成一种有空间结构的、可预测的数据布局。这个思路的转变才是它和一般压缩算法最本质的区别。2. HAC的整体设计思路从无序集合到规则网格2.1 一句话概括HAC在做什么HAC 的全称是 Hash-based 3D Gaussian Compression核心动作可以概括为一句话用哈希网格把场景空间离散化成规则网格每个网格单元绑定有限数量的高斯原语再把这些高斯的属性转换为以网格单元为上下文的结构化数据最后用自回归熵模型压缩。为什么说这个动作重构了压缩范式因为传统压缩是在“已有的一堆杂乱数据”上做文章HAC 是在“如何组织数据”上做文章。它先把无序转换为有序把离散转换为结构化后续的量化、熵编码全部建立在这个结构之上。结构本身就是最好的先验信息。我理解 HAC 的设计哲学是不要追求用一个复杂的熵编码模型去硬啃无序数据而是先花一点代价把数据变得有序让压缩变得简单可靠。哈希网格在这里承担的角色不仅仅是一个空间索引更重要的是它成为了高斯属性的“组织框架”。每个高斯不再是一个孤立的个体而是某个网格单元的一部分它的属性值在空间上和邻近单元的高斯天然具有相关性这种相关性可以直接喂给上下文模型。2.2 为什么选择哈希网格那为什么偏偏是哈希网格这里面有几个很实际的原因。一是内存占用可控。3DGS 场景覆盖范围通常很大但真正有内容的空间占比很小大部分区域是空的。如果直接用稠密体素栅格来表示空间分辨率一高内存就爆炸。哈希网格天然适合稀疏数据——它只对实际有内容的网格单元分配存储空区域不占内存这是它被大量神经辐射场工作采用的原因HAC 用同样的思路来处理高斯空间组织。二是查询效率高。哈希网格可以把三维坐标通过哈希函数映射到哈希表的 bucket 里查询时间接近 O(1)。在训练和压缩过程中需要频繁查询某个高斯属于哪个单元、周围单元有哪些高斯哈希的查询效率比树形结构高很多对 GPU 并行也非常友好。三是弹性分辨率。哈希网格的分辨率可以通过哈希表大小和体素分辨率两个维度来控制这种双参数控制在压缩率和质量之间非常有用。你可以在内容稀疏区域自动合并大网格在细节丰富区域细化网格不需要重新设计框架结构。2.3 哈希网格的组织层级HAC 中哈希网格的组织方式并不是简单的一层划分而是多层次、多尺度的。具体而言框架维护了一个体素层级coarse-to-fine每个层级都有独立的哈希表对应不同的空间分辨率。底层是粗糙网格覆盖整个场景包围盒主要用来捕捉大尺度空间结构。往上是细粒度网格专门负责几何细节丰富、高斯密度高的区域。训练过程中每个高斯会根据自身位置和尺度被分配到合适的层级这种分配不是一成不变的在训练后期还会做动态调整以适配局部的密度变化。这种多尺度组织的好处很明显粗糙层可以快速建立全局空间关系帮助熵模型捕捉远距离依赖细粒度层死死咬住高频细节保证渲染质量。更重要的是这种多级结构天然支持渐进式传输你可以先传粗糙层快速预览再按需传细粒度层这对流式渲染是极大的加分项。3. 核心机制拆解锚点、属性编码与熵模型3.1 锚点分配与绑定在 HAC 框架里有一个非常关键的概念叫锚点anchor。你可以把锚点理解成哈希网格单元和实际高斯之间的桥梁。一个网格单元里可能包含多个高斯这些高斯属性各有不同但它们在空间上同属一个单元。为了压缩框架需要先从这些高斯中提取一个“代表性”属性集合这个集合就是锚点特征。具体做法是对每个网格单元根据单元内高斯的几何中心或统计聚合结果确定一个锚点位置。然后该单元内所有高斯与这个锚点形成一个绑定关系。锚点负责存储这个单元的基础外观信息而单个高斯的偏移量、残差信息则在锚点基础上进一步编码。这个设计把“绝对量”压缩转换成了“相对量”压缩。锚点本身的数量远小于高斯数量大部分信息可以用相对锚点的偏移来表示偏移量的值域范围要小得多需要的信息熵也小得多。3.2 属性量化与上下文编码结构建立起来之后下一步就是属性编码。这一步本质上没有什么神秘的地方就是要把浮点属性变成可压缩的离散符号。HAC 的做法是对不同属性采用不同的量化策略。位置信息在锚点相对坐标下做均匀量化因为位置偏移的分布通常在零点附近呈峰值做均匀量化之后符号熵较低。旋转四元数先做归一化再对分量量化并且利用四元数的约束关系做冗余消除——四元数四个分量并非独立归一化约束可以直接省掉一个分量的编码。缩放信息直接在对数域量化因为尺度变化范围通常跨越几个数量级线性量化会浪费大量码字在对数空间上几乎不重要的区间。球谐系数则根据阶数分别量化低频系数分配更多比特高频系数分配较少比特这是因为人眼对低频光照变化更敏感而高频细节对压缩误差的容忍度更高。量化后的符号序列随后送入熵编码模型。HAC 使用的上下文模型充分利用了空间邻近性——每个网格单元在编码时会参考周围已经编码单元的符号信息来预测当前单元的符号概率分布。由于哈希网格是规则结构定义邻域关系非常自然只需通过体素坐标计算邻居索引即可。这种上下文预测大幅降低了实际编码所需的比特数让最终的压缩率有了质的提升。3.3 多级哈希表的编码细节多级哈希表本身也需要编码。原始哈希表本质上是 key-value 存储每个被占用的 bucket 记录对应的体素坐标和属性指针。如果直接存坐标一个三维 int 就是 12 字节占的空间不小。HAC 的巧妙之处在于它对哈希表的索引结构同样做了压缩。一个非常实用的思路是把体素坐标转换为空间填充曲线如 Morton 码或 Hilbert 码的一维索引。这样处理后相邻空间位置的哈希条目在一维码空间中也是相邻的可以对索引差值做变长编码。大多数区域的索引差值都非常小几个比特就能搞定整体索引占用被压缩到原来的几分之一。属性指针则根据哈希表大小做自适应位宽编码。当占用率低时指针值域较大需要较多比特当占用率高时值域收缩位宽相应减小。这个动态调整机制虽然实现起来稍复杂但对最终存储体积的贡献非常明显算是 HAC 在工程实现上一个很值得学习的小细节。4. 训练流程与参数配置参考4.1 训练流水线HAC 的训练流程大体可以分成四个阶段。第一个阶段是场景初始化与高斯增殖。这一阶段和标准 3DGS 训练基本一致使用 Structure-from-Motion 得到的稀疏点云初始化高斯集合然后迭代优化位置、不透明度、球谐系数等属性。不同的是在这个阶段 HAC 会在训练损失中加入一个结构正则项引导高斯在空间分布上不要过于散乱为后续哈希网格构建打好基础。第二个阶段是哈希网格构建与锚点绑定。在高斯集合基本稳定后框架按当前场景包围盒初始化多级哈希网格把每个高斯分配到对应层级和网格单元计算单元内锚点。这一阶段是纯结构操作不更新网络参数但会收集每个高斯与锚点之间的残差分布统计为下一阶段的量化配置提供依据。第三个阶段是联合优化。这是核心阶段模型参数、哈希网格结构、锚点属性同时参与优化。训练损失包括渲染图像和真实图像的重建损失、量化误差的近似项以及码率估计项三者按权重组合。码率项用于控制最终压缩文件的理论体积它本身是可微的这是因为 HAC 把量化过程用带噪声的直通估计器处理码率则通过熵模型估计得到。第四个阶段是熵编码与打包。训练完成后所有属性符号序列已经确定用训练好的熵模型对符号流做算术编码生成最终的 .hac 格式文件。解码端则直接读入哈希表结构和符号流逐单元重建高斯属性整个过程不需要重新训练。4.2 关键参数与调参心得参数配置方面有几个我实际跑起来觉得需要重点关注的维度。哈希网格层级数常见配置是 3 到 5 层。层级太少空间组织不够细压缩率上不去层级太多哈希表本身的开销增大反而拖累整体压缩比。一个可参考的起点是室内场景用 3 层室外大场景用 4 到 5 层。实际判断标准很简单——看最低层级的单元内平均高斯数量。如果少于 3 个说明网格过细哈希表开销开始主导需要降低层级或减小哈希表大小。量化比特数是一个更微妙的参数。位置偏移建议分配 8 到 12 比特旋转分量给 6 到 8 比特缩放给 8 比特左右。球谐系数的分配策略是低频给 10 到 12 比特高频给 4 到 6 比特。这里有一个经验不要试图把所有属性都用 16 比特以上去量化因为熵编码模型的概率预测能力有限过多的量化级别并不会带来视觉质量提升反而会稀释符号分布让熵编码效率下降。8 到 10 比特对于绝大多数属性已经足够视觉质量下降可以控制在 PSNR 0.1dB 以内。码率权重是最需要小心调整的参数。权重设置过大压缩率很高但渲染质量明显塌陷设置过小压缩率没有优势还不如用简单的后处理量化方法。我通常的做法是先用一个较小的权重训练一个版本作为质量上限参考然后逐步上调权重观察 PSNR 和文件体积的变化曲线找到“膝盖位置”即继续增加权重文件体积不再明显下降但 PSNR 开始加速下跌的临界点。这个过程不需要重复完整训练可以在联合优化阶段做短周期的快速验证。5. 压缩效果与渲染质量怎么权衡5.1 典型的数据变化我在几个公开场景上跑过 HAC 的复现一组具有代表性的数量变化是这样的。未经压缩的标准 3DGS 模型一个室内场景大约 400 万高斯文件体积在 650MB 左右。用 HAC 训练并压缩后高斯数量会明显下降这主要是因为锚点机制隐式做了空间聚类相似高斯以锚点残差形式表达等价于一种可学习的密度剪枝。最终文件体积落在 5 到 15MB 这个区间压缩倍数大约在 40 到 100 倍之间。换到更大的室外场景由于天空、道路等低纹理区域占比高压缩倍数甚至更高100 倍以上并不奇怪。这里的核心量化规律是压缩倍数与场景的“结构冗余度”强相关。结构越规则、重复纹理越多哈希网格的空间聚类越有效压缩率越高。但对于细节极其丰富的场景比如大量叶片交叠的植被区域锚点残差分布的熵会显著上升压缩率会落到 20 到 30 倍这个区间。这种分布差异说明 HAC 不会魔法般地把所有场景都压到一样小它是在充分利用空间结构来消除冗余。5.2 质量评估指标评价压缩质量时我强烈建议不要只看 PSNR 这一个指标。PSNR 对全局光度误差敏感但对局部结构破坏和模糊不敏感。压缩 3DGS 这种显式几何表示更要关注 LPIPS感知相似度和 SSIM尤其是 LPIPS它能反映人眼感知的纹理细节损失。我的测试体会是当 PSNR 下降控制在 0.5dB 以内、LPIPS 上升不超过 0.01 时绝大多数视觉差异人眼很难察觉。这个范围内HAC 的压缩比往往已经非常可观。如果你发现 PSNR 还在合理范围但渲染出的新视角有明显“块状闪烁”或者边缘锯齿大概率是位置量化过于粗糙导致的几何抖动需要优先增加位置偏移量化比特数。5.3 应用场景影响压缩率的提升直接带来一系列落地可能。文件体积降到 10MB 级别后整个 3DGS 场景可以在 Web 端直接加载配合 WebGL 或 WebGPU 光栅化一台普通笔记本就能流畅交互浏览。移动端更是受益明显几十 MB 的模型在现代手机上加载压力不大AR 场景中的实时渲染也更容易做到。流式传输也是很有想象力的方向。HAC 多级哈希表的组织天然支持渐进解码——先加载粗糙层屏幕上先出现低频大致的场景轮廓然后随着细粒度层逐步到达细节越来越丰富。这个特性在弱网环境下体验特别好用户不用等完整文件下载就能开始交互。6. 踩过的坑与实用建议6.1 对哈希分辨率不敏感时该怎么办我在复现过程中遇到过一种情况调大或调小哈希网格分辨率压缩率和渲染质量几乎没变化。排查下来发现原因是联合优化阶段把锚点残差信息的权重调得过低导致量化误差和哈希结构在损失中的占比过小。这种情况下模型完全在靠高斯本身的属性信息做优化哈希网格退化成一个形式上的索引自然对分辨率不敏感。解决方案是把残差损失项和码率损失的权重各提高一个量级让优化器真正感知到哈希网格结构的存在。另外也要检查是不是提前停止了联合优化——如果训练轮次不够哈希结构尚未充分适应数据分布调参就不会有显著效果。6.2 不同层级哈希表之间的同步问题多级哈希网格带来的一个麻烦是不同层级的更新速度可能严重不一致。粗糙层级的数据量大、更新滞后细粒度层级则快速收敛这会导致熵模型的概率分布统计出现偏差最终编码出的文件体积比理论估计值高出不少。我在实际操作中改用了一种简单的分层冻结策略先训练粗糙层到收敛再冻结它并训练下一层级依此类推。这个策略看起来粗暴但实际效果很好各级哈希表的熵模型都能在稳定分布上工作文件体积也更加接近训练时的码率估计值。代价是训练时间稍有增加但换来的稳定性非常值得。6.3 量化参数的敏感性分析使用不同分辨率的数据集时最优量化参数差异很大。360 度环绕拍摄的物体级场景相机离物体近位置偏移值域小可以给更少的量化比特无人机飞行的城市场景高斯分布跨度大位置量化过狠会在远处建筑边缘产生明显瑕疵。我建议在每个新数据集上都跑一组以位置偏移比特数为变量的消融实验横跨 6 到 12 比特其他参数保持默认选取 LPIPS 开始明显升高的临界点作为该数据集的默认配置。这个实验成本不高但能避免很多后续返工。6.4 解码端的性能梳理很多做压缩的人只关注文件体积忽略了解码端的性能。HAC 的解码过程看起来只是查表加算术解码但实际上熵解码是串行操作每个符号都需要前一个符号的概率分布作为条件GPU 并行化很难直接套用。我实测下来对于 10MB 左右的压缩文件CPU 单线程解码大概需要几百毫秒到一两秒。如果你的应用要求快速加载建议把解码和 GPU 上采样分到不同线程加载时先显示一个粗糙占位。另外把全局锚点属性做一次轻量的后训练微调可以显著减少解码后渲染的闪烁现象这个技巧对压缩率几乎无影响但对视觉体验提升很明显。6.5 处理极长尾分布场景的最优架构最后补充一个我个人的架构倾向。HAC 这类哈希网格压缩方法在场景内容复杂度均衡的数据集上表现最佳。如果场景中有极长尾的分布——比如大范围室内环境里有极少数密集细节区域——可以考虑把 HAC 与一个简单的显著区域检测器结合。检测器在训练初期标记出这些高复杂度区域对这些区域单独使用更细的网格层级和更高的量化比特。这样设计能同时保证整体压缩率和局部视觉质量比单纯提高全局质量参数要高效得多。从我个人的角度看HAC 给我最大的启示是压缩的问题不能等到训练完才考虑。当你把“如何存储”作为训练过程中的一环来设计时许多看似困难的问题会自然消失。哈希网格在这里提供的不仅是压缩结构它本质上是把 3DGS 从“一堆游离的高斯球”变成“一个有组织的场景层级”这才是这个工作最有价值的地方。如果你也在做 3DGS 相关项目、被模型体积卡住了线下限制强烈建议把 HAC 的训练流程完整跑一遍它带来的不仅是一个更小的文件也是对“结构化表示”这个思路的一次深入实践。
返回列表