code: def forward(
      ctx,
      inputs,
      embeddings,
      offsets,
      per_level_scale,
      base_resolution,
      calc_grad_inputs=False,
      gridtype=0,
      align_corners=False,
      interpolation=0,
      max_level=None,
  ):
      # inputs: [B, D], float in [0, 1]
      # embeddings: [sO, C], float
      # offsets: [L + 1], int
      # RETURN: [B, F], float
  
      inputs = inputs.contiguous()
  
      B, D = inputs.shape  # batch size, coord dim
      L = offsets.shape[0] - 1  # level
      C = embeddings.shape[1]  # embedding dim for each level
      S = np.log2(
          per_level_scale
      )  # resolution multiplier at each level, apply log2 for later CUDA exp2f
      H = base_resolution  # base resolution
  
      max_level = (
          L
          if max_level is None
          else max(min(int(math.ceil(max_level * L)), L), 1)
      )
  
      # manually handle autocast (only use half precision embeddings, inputs must be float for enough precision)
      # if C % 2 != 0, force float, since half for atomicAdd is very slow.
      if torch.is_autocast_enabled() and C % 2 == 0:
          embeddings = embeddings.to(torch.half)
  
      # L first, optimize cache for cuda kernel, but needs an extra permute later
      outputs = torch.empty(
          L, B, C, device=inputs.device, dtype=embeddings.dtype
      )
  
      # zero init if we only calculate partial levels
      if max_level < L:
          outputs.zero_()
  
      if calc_grad_inputs:
          dy_dx = torch.empty(
              B, L * D * C, device=inputs.device, dtype=embeddings.dtype
          )
          if max_level < L:
              dy_dx.zero_()
      else:
          dy_dx = None
  
      _backend.grid_encode_forward(
          inputs,
          embeddings,
          offsets,
          outputs,
          B,
          D,
          C,
          L,
          max_level,
          S,
          H,
          dy_dx,
          gridtype,
          align_corners,
          interpolation,
      )
  
      # permute back to [B, L * C]
      outputs = outputs.permute(1, 0, 2).reshape(B, L * C)
  
      ctx.save_for_backward(inputs, embeddings, offsets, dy_dx)
      ctx.dims = [B, D, C, L, S, H, gridtype, interpolation, max_level]
      ctx.align_corners = align_corners
  
      return outputs
  
file_path: NeMo/nemo/collections/multimodal/modules/nerf/utils/torch_ngp/gridencoder.py
imports: import math
  import _gridencoder
  import numpy
  import torch
  import torch.nn
  from torch.autograd import Function
  from torch.cuda.amp import custom_bwd, custom_fwd
label_desc: Use image node_id 1 for calling the _grid_encode obj's underlying member method code with example usage: obj.forward(ctx, inputs, embeddings, offsets, per_level_scale, base_resolution, calc_grad_inputs, gridtype, align_corners, interpolation, max_level) and returns: outputs