NVlabs/tiny-cuda-nn

Issue with second derivatives using tiny-cuda-nn hash encoding

jfrausto7 opened this issue · 2 comments

Hi there! I'm having trouble using tiny-cuda-nn's hash encoding when computing a Hessian matrix. As mentioned in other open & closed issues, second derivatives are not supported by tiny-cuda-nn's neural networks. I'm building on top of a repository that uses tiny-cuda-nn (torch-ngp), and I'm trying to compose the hash encoding (tcnn.Encoding) in a network with a simple MLP as shown below (link to full code here):

class MLP(nn.Module):
    def __init__(self, dim_in, dim_out, dim_hidden, num_layers, bias=True):
        super().__init__()
        self.dim_in = dim_in
        self.dim_out = dim_out
        self.dim_hidden = dim_hidden
        self.num_layers = num_layers

        net = []
        for l in range(num_layers):
            net.append(nn.Linear(self.dim_in if l == 0 else self.dim_hidden, self.dim_out if l == num_layers - 1 else self.dim_hidden, bias=bias))

        self.net = nn.ModuleList(net)
    
    def forward(self, x):
        for l in range(self.num_layers):
            x = self.net[l](x)
            if l != self.num_layers - 1:
                x = F.relu(x, inplace=True)
        return x

class NeRFNetwork(NeRFRenderer):
    def __init__(self,
                 encoding="HashGrid",
                 encoding_dir="SphericalHarmonics",
                 num_layers=2,
                 hidden_dim=64,
                 geo_feat_dim=15,
                 num_layers_color=3,
                 hidden_dim_color=64,
                 bound=1,
                 **kwargs
                 ):
        super().__init__(bound, **kwargs)

        # sigma network
        self.num_layers = num_layers
        self.hidden_dim = hidden_dim
        self.geo_feat_dim = geo_feat_dim

        per_level_scale = np.exp2(np.log2(2048 * bound / 16) / (16 - 1))

        self.encoder = tcnn.Encoding(
            n_input_dims=3,
            encoding_config={
                "otype": "HashGrid",
                "n_levels": 16,
                "n_features_per_level": 2,
                "log2_hashmap_size": 19,
                "base_resolution": 16,
                "per_level_scale": per_level_scale,
            },
        )

        self.sigma_net = MLP(dim_in=32, dim_out=1 + self.geo_feat_dim, dim_hidden=self.hidden_dim, num_layers=self.num_layers)

        # color network
        self.num_layers_color = num_layers_color        
        self.hidden_dim_color = hidden_dim_color

        self.encoder_dir = tcnn.Encoding(
            n_input_dims=3,
            encoding_config={
                "otype": "SphericalHarmonics",
                "degree": 4,
            },
        )

        self.in_dim_color = self.encoder_dir.n_output_dims + self.geo_feat_dim

        self.color_net = MLP(dim_in=self.in_dim_color, dim_out=3, dim_hidden=self.hidden_dim_color, num_layers=self.num_layers_color)

    
    def forward(self, x, d):
        # x: [N, 3], in [-bound, bound]
        # d: [N, 3], nomalized in [-1, 1]


        # sigma
        x = (x + self.bound) / (2 * self.bound) # to [0, 1]
        x = self.encoder(x)
        h = self.sigma_net(x)

        #sigma = F.relu(h[..., 0])
        sigma = trunc_exp(h[..., 0])
        geo_feat = h[..., 1:]

        # color
        d = (d + 1) / 2 # tcnn SH encoding requires inputs to be in [0, 1]
        d = self.encoder_dir(d)

        #p = torch.zeros_like(geo_feat[..., :1]) # manual input padding
        h = torch.cat([d, geo_feat], dim=-1)
        h = self.color_net(h)
        
        # sigmoid activation for rgb
        color = torch.sigmoid(h)

        return sigma, color

Even after replacing all instances of `tcnn.Network' with an MLP and rebuilding/training, I still get the following error:

Traceback (most recent call last): File "/home/jfrausto/nerf-navigation/simulate.py", line 350, in <module> simulate(planner_cfg, agent_cfg, filter_cfg, extra_cfg, density_fn, render_fn, get_rays_fn) File "/home/jfrausto/nerf-navigation/simulate.py", line 88, in simulate state_est = filter.estimate_state(gt_img, true_pose, action) File "/home/jfrausto/nerf-navigation/nav/estimator_helpers.py", line 384, in estimate_state hess = torch.autograd.functional.hessian(lambda x: self.measurement_fn(x, self.xt.clone().detach(), sig_prop, self.target, self.batch), xt.clone().detach()) File "/home/jfrausto/.local/lib/python3.10/site-packages/torch/autograd/functional.py", line 812, in hessian res = jacobian(jac_func, inputs, create_graph=create_graph, strict=strict, vectorize=vectorize, File "/home/jfrausto/.local/lib/python3.10/site-packages/torch/autograd/functional.py", line 673, in jacobian vj = _autograd_grad((out.reshape(-1)[j],), inputs, File "/home/jfrausto/.local/lib/python3.10/site-packages/torch/autograd/functional.py", line 159, in _autograd_grad return torch.autograd.grad(new_outputs, inputs, new_grad_outputs, allow_unused=True, File "/home/jfrausto/.local/lib/python3.10/site-packages/torch/autograd/__init__.py", line 300, in grad return Variable._execution_engine.run_backward( # Calls into the C++ engine to run the backward pass File "/home/jfrausto/.local/lib/python3.10/site-packages/torch/autograd/function.py", line 267, in apply return user_fn(self, *args) File "/home/jfrausto/.local/lib/python3.10/site-packages/tinycudann/modules.py", line 145, in backward doutput_grad, params_grad, input_grad = ctx.ctx_fwd.native_tcnn_module.bwd_bwd_input( RuntimeError: DifferentiableObject::backward_backward_input_impl: not implemented error

I'm not sure what I'm doing wrong here, but this seems to still be an issue with tiny-cuda-nn. Would really appreciate any advice. Thanks!

Similar problem. Have you solved it?

@HelloRicky123 As it turns out, I discovered that tiny-cuda-nn does not support the computation of second-order derivatives. I discovered I had to do either one of two things:

  • Use the identity matrix instead of the Hessian
  • Approximate the Hessian with some sort of optimization algorithm