Multi-resolution Hash Encoding(多分辨率哈希编码)
输入:$\mathbf{x} = [x, y]$,一个 2D weight tensor 归一化的坐标(后续会进行插值)。
输出:在 Instant-NGP 的架构中,训练过程实际上是在优化两部分:
- 显式特征(Explicit Features):存储在哈希表(Hash Table)中的 $L \times T$ 个特征向量。
- 隐式映射(Implicit Mapping):后端小型 MLP 的权重。
Multi-resolution Hash Encoding 分为四个步骤:
- 系统预设 $L$ 个不同精度的网格(从粗糙到精细)。粗层捕捉大轮廓,细层捕捉微小细节。
- 网格顶点索引与哈希 (Hashing):在每一层,坐标 $\mathbf{x}$ 会落在某个小格子(Voxel)里。计算该格子 4 个顶点的索引(三维空间 8 个顶点,二维空间 4 个顶点)。为了节省空间,如果顶点数超过预设大小 $T$,则使用空间哈希函数将坐标映射到固定大小的哈希表中: $$h(\mathbf{x}) = (\bigoplus_{i=1}^d x_i \pi_i) \mod T$$ 这里 $d=4$ 是顶点数,$x$ 是坐标,$\pi$ 是一个很大的质数,为了让坐标的每一维在计算时都能产生巨大的差异,从而打乱空间顺序,减少'空间聚集性'导致的冲突(就是哈希的原理),$\bigoplus$ 是按位异或。
- 双线性插值 (Interpolation):根据 $\mathbf{x}$ 在当前格子内的相对位置,对 4 个顶点的哈希特征向量进行线性插值,得到该层分辨率下的特征。
- 特征拼接 (Concatenation):将所有 $L$ 层得到的特征向量拼接在一起,输入给一个非常小的 MLP(通常只有 2 层)解码回图像像素值。
下面分步骤讲解代码实现:
双线性插值
class Image(torch.nn.Module):
def __init__(self, filename, device):
# ... load a tensor/image
pass
def forward(self, xs):
with torch.no_grad():
# Bilinearly filtered lookup from the image. Not super fast,
# but less than ~20% of the overall runtime of this example.
shape = self.shape
xs
# ... remaining logic


