Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about spherical initialzation and training #22

Closed
ryunuri opened this issue Nov 28, 2022 · 3 comments
Closed

Question about spherical initialzation and training #22

ryunuri opened this issue Nov 28, 2022 · 3 comments

Comments

@ryunuri
Copy link

ryunuri commented Nov 28, 2022

Hi, thanks for sharing your code.

I've been trying out several things and found something weird.
When using sphere initialization of the vanilla MLP, I expected the initial shape to be a sphere.
If you render the outputs of the initialized model by setting val_check_interval=1, the images (rgb, normal, depth) indeed resemble a sphere.

it1-0

However, the marching cubes fail with the following error message

vmin, vmax = mesh_coarse['v_pos'].amin(dim=0), mesh_coarse['v_pos'].amax(dim=0)
IndexError: amin(): Expected reduction dim 0 to have non-zero size.

I guess this means that the aabb cube is empty.

When I looked into the code, I found that the VanillaMLP does not initialize the constants of the layers, which is different from the initialization of the paper "SAL: Sign Agnostic Learning of Shapes from Raw Data".

I think the make_linear function should be as follows

def make_linear(self, dim_in, dim_out, bias, is_first, is_last):
    layer = nn.Linear(dim_in, dim_out)
    if self.sphere_init:
        if is_last:
            torch.nn.init.constant_(layer.bias, -bias)
            torch.nn.init.normal_(layer.weight, mean=math.sqrt(math.pi) / math.sqrt(dim_in), std=0.0001)
        elif is_first:
            torch.nn.init.constant_(layer.bias, 0.0)
            torch.nn.init.constant_(layer.weight[:, 3:], 0.0)
            torch.nn.init.normal_(layer.weight[:, :3], 0.0, math.sqrt(2) / math.sqrt(dim_out))
        else:
            torch.nn.init.constant_(layer.bias, 0.0)
            torch.nn.init.normal_(layer.weight, 0.0, math.sqrt(2) / math.sqrt(dim_out))
    else:
        torch.nn.init.kaiming_uniform_(layer.weight, nonlinearity='relu')
    
    if self.weight_norm:
        layer = nn.utils.weight_norm(layer)
    return layer   

Also, from forward and forward_level methods in class VolumeSDF

if 'sdf_activation' in self.config:
            sdf = get_activation(self.config.sdf_activation)(sdf + float(self.config.sdf_bias))

The if statement is True even when you simply set sdf_activation to None in the config, since it's still in the config. I found that this leads the sdf values to be all positive at the start of training. I just removed the sdf_activation in the config.

After changing this part and setting the bias of the SDF to 0.6, the initial model output is as follows:
it1-0

And the result of marching cubes is indeed a sphere.
snapshot00

However, I found that by changing the model like this results in very poor training results.

After 1000 iterations,
it1000-0

Also, the mesh is completely broken
snapshot02

So, I guess you had a reason for this design choice? Otherwise, I think this might be the reason why training the model on my custom dataset fails.

bennyguo added a commit that referenced this issue Nov 30, 2022
@bennyguo
Copy link
Owner

bennyguo commented Nov 30, 2022

Hi, thanks for the valuable comments!

About the initialization of bias in linear layers, I think the current implementation achieves the same effect as the original code you mentioned, as the bias is set to 0 in intermediate layers and set to -bias in the last layer which is done by sdf_bias in our implementation. The only difference is that I set sdf_bias=0 instead of sdf_bias=-0.5 in the original setting, which leads to a smaller sphere.

I also found that setting sdf_bias=-0.6 could result in bad training results as you showed. It seems like a training instability problem and could be solved by adopting learning rate warm-up like in the original NeuS implementation. I already updated the config file to support such a warm-up strategy, please have a try!

@bennyguo
Copy link
Owner

Here I compare sdf_bias=0, w/o warm-up and sdf_bias=-0.5, w/ warm-up on the Lego scene. It seems that the latter achieves higher quality:

sdf_bias=0, w/o warm-up

image

sdf_bias=-0.5, w/ warm-up

image

@ryunuri
Copy link
Author

ryunuri commented Dec 1, 2022

Thanks for your feedback!

I tried out the warm-up strategy and the quality was quite improved on my custom dataset.
However, I'm still having some difficulties on extracting a high quality mesh out of it.
I guess I'll try out some more experiments and share the results if I see some improvements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants