mit-han-lab / torchsparse

[MICRO'23, MLSys'22] TorchSparse: Efficient Training and Inference Framework for Sparse Convolution on GPUs.
https://torchsparse.mit.edu
MIT License
1.17k stars 138 forks source link

spnn.Conv3dTranspose #317

Closed kai0416s closed 1 month ago

kai0416s commented 1 month ago

Thank you for your excellent work. I have a question for you. In MinkowskiEngine, they have ME.MinkowskiConvolutionTranspose, but in Torchsparsev2.1, how can I implement Con3DTranspose? I think the documentation doesn't mention it.

Example: from torchsparse import SparseTensor from torchsparse import nn as spnn class SparseBlock(nn.Module): def init(self, in_channels, out_channels, kernel_size=3, stride=1, use_bias=True): super().init() self.use_res = use_res self.main = nn.Sequential( spnn.Conv3d(in_channels, out_channels, kernel_size, stride=stride, bias=use_bias), spnn.BatchNorm(out_channels), spnn.ReLU(True), spnn.Conv3d(out_channels, out_channels, kernel_size, stride=stride, bias=use_bias), spnn.BatchNorm(out_channels) ) self.relu = spnn.ReLU(True)

Looking forward to your reply.

francotheengineer commented 1 month ago

spnn.Conv3d(..., transposed=True, ...)

kai0416s commented 1 month ago

spnn.Conv3d(..., transposed=True, ...)

Thanks. But another question is how to replace MinkowskiEngine SparseTensor in Torchsparse? For example: MinkowskiEngine have coordinate_map_key how to handle this? https://github.com/NVIDIA/MinkowskiEngine/blob/02fc608bea4c0549b0a7b00ca1bf15dee4a0b228/MinkowskiEngine/MinkowskiSparseTensor.py#L128

francotheengineer commented 1 month ago

It's not essential to provide a coordinate_map_key when making a sparse tensor in torchsparse. You could do something like:


x_A = torchsparse.SparseTensor(feats=feats, coords=coords_A)
x_B = torchsparse.SparseTensor(feats=feats, coords=coords_B)
y = nn.conv(...)(x_A)
y.C = x_B.C

This would allow you set the coords of y to those of x_B.

kai0416s commented 1 month ago

It's not essential to provide a coordinate_map_key when making a sparse tensor in ME. You could do something like:


x_A = torchsparse.SparseTensor(feats=feats, coords=coords_A)
x_B = torchsparse.SparseTensor(feats=feats, coords=coords_B)
y = nn.conv(...)(x_A)
y.C = x_B.C

This would allow you set the coords of y to those of x_B.

Thanks a lot.

kai0416s commented 1 month ago

@francotheengineer Sorry to bother you again. Do you know how to implement MinkowskiSumPooling in torchsparse++? It seems I couldn't find it. Looking forward to your reply. Thank you.

francotheengineer commented 1 month ago

@francotheengineer Sorry to bother you again. Do you know how to implement MinkowskiSumPooling in torchsparse++? It seems I couldn't find it. Looking forward to your reply. Thank you.

Not off the top of my head. You might want to take the features, and sum them in the last dimensions. Or you could convert a TorchSparse tensor, to a Minkowski Tensor, run SumPooling, the, convert to TorchSparse Tensor.

francotheengineer commented 1 month ago

@kai0416s Perhaps rewrite the global_avg_pool code, and replace the torch.mean with a torch.sum:

def global_avg_pool(inputs: SparseTensor) -> torch.Tensor:
    batch_size = torch.max(inputs.coords[:, 0]).item() + 1
    outputs = []
    for k in range(batch_size):
        input = inputs.feats[inputs.coords[:, 0] == k]
        output = torch.mean(input, dim=0)
        outputs.append(output)
    outputs = torch.stack(outputs, dim=0)
    return outputs

such that:

def global_avg_pool(inputs: SparseTensor) -> torch.Tensor:
    batch_size = torch.max(inputs.coords[:, 0]).item() + 1
    outputs = []
    for k in range(batch_size):
        input = inputs.feats[inputs.coords[:, 0] == k]
        output = torch.sum(input, dim=0)
        outputs.append(output)
    outputs = torch.stack(outputs, dim=0)
    return outputs