NVlabs / tiny-cuda-nn

Lightning fast C++/CUDA neural network framework
Other
3.76k stars 456 forks source link

grid_resolution in "encoding/grid.h" #149

Open ZHN2ZHN opened 2 years ago

ZHN2ZHN commented 2 years ago

Hey! in "encoding/grid.h"

__global__ void kernel_grid(
    const uint32_t num_elements,
    const uint32_t num_grid_features,
    const GridOffsetTable offset_table,
    const uint32_t base_resolution,
    const float log2_per_level_scale,
    const float quantize_threshold,
    float max_level,
    const float* __restrict__ max_level_gpu,
    const InterpolationType interpolation_type,
    const GridType grid_type,
    const T* __restrict__ grid,
    MatrixView<const float> positions_in,
    T* __restrict__ encoded_positions,
    float* __restrict__ dy_dx
){
//......
    const float scale = exp2f(level * log2_per_level_scale) * base_resolution - 1.0f;
    const uint32_t grid_resolution = ((uint32_t)ceil(scale) + 1);
//......
}

image From paper "Instant Neural Graphics Primitives with a Multiresolution Hash Encoding", when level = 0, base_resolution N0 = 2, means scale = 1 and grid_resolution = 2 ; But the number of vertices in a row seems likes 3. so here should

    const uint32_t grid_resolution = ((uint32_t)ceil(scale) + 2);

thinks!!!

ZHN2ZHN commented 2 years ago

and i want to know in "commin_device.h"

__device__ inline void pos_fract(const float input, float* pos, uint32_t* pos_grid, float scale, F interpolation_fun) {
    *pos = input * scale + 0.5f;
    int tmp = floorf(*pos);
    *pos_grid = (uint32_t)tmp;
    *pos -= (float)tmp;
    *pos = interpolation_fun(*pos);
}

here pos = input scale + 0.5f, Why add 0.5 here? think you!!!

Tom94 commented 2 years ago

Hi, the slight difference to the paper is intentional: the number of vertices in the code is N_i rather than N_i+1 such that the lower levels of dense grids are stored in nice power-of-two-sized arrays whose indexing code can be shared with the hash table lookups.

As for the second question: the offset of 0.5 helps break alignment of the multi-resolution grids when per_level_scale happens to be a rational power of 2. (This is mostly relevant when desiring higher-order smoothness, as the alignment of grids would enforce undesired zero-derivatives -- there's a sentence about it in Appendix A.)

Cheers!

ZHN2ZHN commented 2 years ago

@Tom94 Thank you!!!

And here I have another question, during N-linear interpolation,

for (uint32_t dim = 0; dim < N_POS_DIMS; ++dim) {
  if ((idx & (1<<dim)) == 0) {
    weight *= 1 - pos[dim];
    pos_grid_local[dim] = pos_grid[dim];
  } else {
    weight *= pos[dim];
    pos_grid_local[dim] = pos_grid[dim] + 1;
  }
}

At level 1, b=1.5, N1=3, scale = 2, grid_resolution = 3, and with number of vertices = 3 in the code;

For two points(0.95, 0.05),(0.05, 0.55) after pos_fract(), pos(2.4, 0.6) and pos2(0.6, 1.6), with dim=2, to interpolate,

pos(2.4, 0.6) need 4 vertices (2,0),(2,1), (3,0), (3,1);

and pos2(0.6, 1.6) need vertices (0,2),(0,1), (1,1), (1,2);

grid_val( (3,0) ) = 3 + grid_resolution 0 = 3 and grid_val( (0,1) ) = 0 + grid_resolution 1 =3

so different vertices have same index = 3 in grid(the fourth vertex), it is conflicted. Although vertices in the code is set N_i , but the operation that offset of 0.5 in pos_fract() and pos_grid_local[dim] = pos_grid[dim] + 1, may try to obtain N_i+1 which out of range.

Tom94 commented 2 years ago

Ah, that's a good point -- the 0.5-offset does indeed cause wrap-around (and thus a weird type of collision) in the dense lower-level grids. I haven't experienced any issues caused by this, because the outermost cells are generally not relevant to the reconstruction, but I agree that it'd be great to have this fixed.

I can take a stab at improving the behavior next time I get the chance to iterate on the code.

ZHN2ZHN commented 2 years ago

@Tom94 Anticipates your good news!!!!!!