NVlabs / tiny-cuda-nn

Lightning fast C++/CUDA neural network framework
Other
3.75k stars 454 forks source link

HashGrid params size #338

Open iszihan opened 1 year ago

iszihan commented 1 year ago

Hello,

I'm in the middle of trying to export the hashmap used in a training experiment. When I load in the checkpoint, I can see the parameter corresponding to the hash grid has a size of

_model.field.mlp_base.0.tcnn_encoding.params
tensor([-0.1878,  2.0033, -1.8618,  ...,  0.7501,  2.0120,  1.2352])
torch.Size([12196240])

The config for this hash grid is

 encoding_config = {
              "otype": "HashGrid",
              "n_levels": 16,
              "n_features_per_level": 2,
              "log2_hashmap_size": 19,
              "base_resolution": 16,
              "per_level_scale": np.exp((np.log(1024) - np.log(16)) / (16 - 1)),
          }

From my understanding of hashgrid, this hash map should have a size of 2^19 16 2 which is not 12196240. Would someone know why is the difference here?

StarsTesla commented 1 year ago

Same question here.

StarsTesla commented 1 year ago

@iszihan Hi,I just push the tcnn code (grid.h) to GPT,and also I give a input to it, here is the calculation method it give me: `import math

N_FEATURES_PER_LEVEL = 2 N_POS_DIMS = 3 grid_type = "hash" log2_hashmap_size = 19 per_level_scale = 1.5 base_resolution = 16 n_features = 13

m_n_levels = 16#math.ceil(n_features / N_FEATURES_PER_LEVEL) offset = 0

for i in range(m_n_levels): resolution = base_resolution * (per_level_scale i) params_in_level = resolution N_POS_DIMS params_in_level = min(params_in_level, 2 * log2_hashmap_size) params_in_level = math.ceil(params_in_level / 8) 8 # Make sure memory accesses will be aligned offset += params_in_level

m_n_params = offset * N_FEATURES_PER_LEVEL

print(m_n_params)`

the output 13026992 is right, you could test it with tcnn api. Maybe, we should call GPT him/her, instead of it.

HongruiZhao commented 2 months ago

Lines 684~730 in grid.h are how tinycudann computes params size. I have turned it into python code (I used the notations from the instantNGP paper):

import math import numpy as np F = 2 d = 3 T = 2**16 N_max = 725 N_min = 16 L = 16 b = np.exp2(np.log2(N_max / N_min) / (L - 1)) offset = 0 def next_multiple(val, divisor): div_round_up = (val+divisor-1) // divisor return div_round_up * divisor for l in range(L): N_l = math.ceil(b**l * N_min - 1) + 1 # this is different from how N_l is calculated in the paper params_in_level = N_l**d params_in_level = next_multiple(params_in_level, 8) # to make sure memory accesses will be aligned, this will lead to non-integer cube root params_in_level = min(params_in_level, T) offset += params_in_level print(f'N_{l} = {N_l}, vertices in level= {params_in_level}') total_params = offset * F print(f'total number of params = {total_params}')