Skip to content

pointnet

Parametrized PointNet.

GeneralizedIterativePointNet

Bases: Module

Generalized Iterative PointNet composed of multiple IterativePointNet instances.

This is a sequence of iterative pointnets, where the initial input will be concatenated to each input, e.g., out = IterativePointNet1(in) out = IterativePointNet2(concat(out, in)) out = IterativePointNet3(concat(out, in)) ...

Source code in sdfest/initialization/pointnet.py
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
class GeneralizedIterativePointNet(nn.Module):
    """Generalized Iterative PointNet composed of multiple IterativePointNet instances.

    This is a sequence of iterative pointnets, where the initial input will be
    concatenated to each input, e.g.,
        out = IterativePointNet1(in)
        out = IterativePointNet2(concat(out, in))
        out = IterativePointNet3(concat(out, in))
        ...
    """

    def __init__(
        self, list_concat: list, in_size: int, list_mlp_out_sizes: list, batchnorm: bool
    ) -> None:
        """Initialize GeneralizedIterativePointnet module.

        Args:
            list_concat:
                List of concatenations for each MLP.
            in_size: Dimension of the input points.
            list_mlp_out_sizes:
                List of Output sizes of each linear layer.
                It is a List of Lists.
            batchnorm: Whether to use batchnorm or not.
        """
        super().__init__()

        init_in_size = in_size
        self.iterative_pointnet_list = torch.nn.ModuleList([])
        temp_iterative_pointnet = IterativePointNet(
            list_concat[0], in_size, list_mlp_out_sizes[0], batchnorm
        )
        self.iterative_pointnet_list.append(temp_iterative_pointnet)
        for iterative_pointnet_num in range(1, len(list_mlp_out_sizes)):
            # the input size to new MLP should be the output size of the previous MLP
            # plus previous input size
            in_size = list_mlp_out_sizes[iterative_pointnet_num - 1][-1] + init_in_size
            temp_iterative_pointnet = IterativePointNet(
                list_concat[iterative_pointnet_num],
                in_size,
                list_mlp_out_sizes[iterative_pointnet_num],
                batchnorm,
            )
            self.iterative_pointnet_list.append(temp_iterative_pointnet)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """Forward pass.

        Input has dimension NxMxC, where N is the batch size, M the number of points
        per set, and C the number of channels per point.

        Args:
            x: batch of point sets
        """
        set_size = x.shape[1]
        init_x = x
        for iterative_pointnet in self.iterative_pointnet_list:
            out = iterative_pointnet(x)  # shape (batch_size, num_outputs)
            # repeat output vector across 2nd dimension
            x = out.unsqueeze(1).repeat(1, set_size, 1)
            x = torch.cat((x, init_x), 2)
        return out

__init__(list_concat, in_size, list_mlp_out_sizes, batchnorm)

Initialize GeneralizedIterativePointnet module.

Parameters:

Name Type Description Default
list_concat list

List of concatenations for each MLP.

required
in_size int

Dimension of the input points.

required
list_mlp_out_sizes list

List of Output sizes of each linear layer. It is a List of Lists.

required
batchnorm bool

Whether to use batchnorm or not.

required
Source code in sdfest/initialization/pointnet.py
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
def __init__(
    self, list_concat: list, in_size: int, list_mlp_out_sizes: list, batchnorm: bool
) -> None:
    """Initialize GeneralizedIterativePointnet module.

    Args:
        list_concat:
            List of concatenations for each MLP.
        in_size: Dimension of the input points.
        list_mlp_out_sizes:
            List of Output sizes of each linear layer.
            It is a List of Lists.
        batchnorm: Whether to use batchnorm or not.
    """
    super().__init__()

    init_in_size = in_size
    self.iterative_pointnet_list = torch.nn.ModuleList([])
    temp_iterative_pointnet = IterativePointNet(
        list_concat[0], in_size, list_mlp_out_sizes[0], batchnorm
    )
    self.iterative_pointnet_list.append(temp_iterative_pointnet)
    for iterative_pointnet_num in range(1, len(list_mlp_out_sizes)):
        # the input size to new MLP should be the output size of the previous MLP
        # plus previous input size
        in_size = list_mlp_out_sizes[iterative_pointnet_num - 1][-1] + init_in_size
        temp_iterative_pointnet = IterativePointNet(
            list_concat[iterative_pointnet_num],
            in_size,
            list_mlp_out_sizes[iterative_pointnet_num],
            batchnorm,
        )
        self.iterative_pointnet_list.append(temp_iterative_pointnet)

forward(x)

Forward pass.

Input has dimension NxMxC, where N is the batch size, M the number of points per set, and C the number of channels per point.

Parameters:

Name Type Description Default
x Tensor

batch of point sets

required
Source code in sdfest/initialization/pointnet.py
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def forward(self, x: torch.Tensor) -> torch.Tensor:
    """Forward pass.

    Input has dimension NxMxC, where N is the batch size, M the number of points
    per set, and C the number of channels per point.

    Args:
        x: batch of point sets
    """
    set_size = x.shape[1]
    init_x = x
    for iterative_pointnet in self.iterative_pointnet_list:
        out = iterative_pointnet(x)  # shape (batch_size, num_outputs)
        # repeat output vector across 2nd dimension
        x = out.unsqueeze(1).repeat(1, set_size, 1)
        x = torch.cat((x, init_x), 2)
    return out

IterativePointNet

Bases: Module

Iterative PointNet which concatenates input.

This is composed of 2 PointNets, where the first PointNet is applied once, the second PointNet a number of times, i.e., out = PointNet1(in) for i in range(num_concat): out = PointNet2( concat( out, in ) )

Source code in sdfest/initialization/pointnet.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
class IterativePointNet(nn.Module):
    """Iterative PointNet which concatenates input.

    This is composed of 2 PointNets, where the first PointNet is applied once, the
    second PointNet a number of times, i.e.,
        out = PointNet1(in)
        for i in range(num_concat):
            out = PointNet2( concat( out, in ) )
    """

    def __init__(
        self, num_concat: int, in_size: int, mlp_out_sizes: List, batchnorm: bool
    ) -> None:
        """Initialize the IterativePointNet module.

        Args:
            num_concat:
                Number of concatenations of input and previous iteration.
                If 0 this module is the same as VanillaPointNet.
            in_size: Dimension of the input points.
            mlp_out_sizes: Output sizes of each linear layer.
            batchnorm: Whether to use batchnorm or not.
        """
        super().__init__()
        self.num_concat = num_concat
        # create 1st pointnet for taking points of channel = in_size
        self.pointnet_1 = VanillaPointNet(in_size, mlp_out_sizes, batchnorm)
        # create 2nd pointnet for taking points of channel = size of concatenated vector
        self.pointnet_2 = VanillaPointNet(
            in_size + mlp_out_sizes[-1], mlp_out_sizes, batchnorm
        )

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """Forward pass.

        Input has dimension NxMxC, where N is the batch size, M the number of points
        per set, and C the number of channels per point.

        Args:
            x: batch of point sets
        """
        # apply 1st pointnet to input
        out = self.pointnet_1(x)  # shape (batch_size, num_outputs)
        set_size = x.shape[1]
        for _ in range(self.num_concat):
            # repeat output vector across 2nd dimension
            repeated_out = out.unsqueeze(1).repeat(1, set_size, 1)
            # concatenate input vector and repeated_out
            modified_x = torch.cat((repeated_out, x), 2)
            out = self.pointnet_2(modified_x)
        return out

__init__(num_concat, in_size, mlp_out_sizes, batchnorm)

Initialize the IterativePointNet module.

Parameters:

Name Type Description Default
num_concat int

Number of concatenations of input and previous iteration. If 0 this module is the same as VanillaPointNet.

required
in_size int

Dimension of the input points.

required
mlp_out_sizes List

Output sizes of each linear layer.

required
batchnorm bool

Whether to use batchnorm or not.

required
Source code in sdfest/initialization/pointnet.py
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
def __init__(
    self, num_concat: int, in_size: int, mlp_out_sizes: List, batchnorm: bool
) -> None:
    """Initialize the IterativePointNet module.

    Args:
        num_concat:
            Number of concatenations of input and previous iteration.
            If 0 this module is the same as VanillaPointNet.
        in_size: Dimension of the input points.
        mlp_out_sizes: Output sizes of each linear layer.
        batchnorm: Whether to use batchnorm or not.
    """
    super().__init__()
    self.num_concat = num_concat
    # create 1st pointnet for taking points of channel = in_size
    self.pointnet_1 = VanillaPointNet(in_size, mlp_out_sizes, batchnorm)
    # create 2nd pointnet for taking points of channel = size of concatenated vector
    self.pointnet_2 = VanillaPointNet(
        in_size + mlp_out_sizes[-1], mlp_out_sizes, batchnorm
    )

forward(x)

Forward pass.

Input has dimension NxMxC, where N is the batch size, M the number of points per set, and C the number of channels per point.

Parameters:

Name Type Description Default
x Tensor

batch of point sets

required
Source code in sdfest/initialization/pointnet.py
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
def forward(self, x: torch.Tensor) -> torch.Tensor:
    """Forward pass.

    Input has dimension NxMxC, where N is the batch size, M the number of points
    per set, and C the number of channels per point.

    Args:
        x: batch of point sets
    """
    # apply 1st pointnet to input
    out = self.pointnet_1(x)  # shape (batch_size, num_outputs)
    set_size = x.shape[1]
    for _ in range(self.num_concat):
        # repeat output vector across 2nd dimension
        repeated_out = out.unsqueeze(1).repeat(1, set_size, 1)
        # concatenate input vector and repeated_out
        modified_x = torch.cat((repeated_out, x), 2)
        out = self.pointnet_2(modified_x)
    return out

VanillaPointNet

Bases: Module

Parametrized PointNet without transformation layers (no T-nets).

Generally following

PointNet Deep Learning on Point Sets for 3D Classification and Segmentation Qi, 2017

Source code in sdfest/initialization/pointnet.py
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
class VanillaPointNet(nn.Module):
    """Parametrized PointNet without transformation layers (no T-nets).

    Generally following:
        PointNet Deep Learning on Point Sets for 3D Classification and Segmentation
        Qi, 2017
    """

    def __init__(
        self,
        in_size: int,
        mlp_out_sizes: List,
        batchnorm: bool,
        residual: bool = False,
        dense: bool = False,
    ) -> None:
        """Initialize the VanillaPointNet module.

        This module will only implements the MLP + MaxPooling part of the pointnet.

        It still requires a task specific head.

        Args:
            in_size:        dimension of the input points
            mlp_out_sizes:  output sizes of each linear layer
            batchnorm:      whether to use batchnorm or not
        """
        super().__init__()

        self._in_size = in_size
        self._mlp_out_sizes = mlp_out_sizes
        self._batchnorm = batchnorm
        self._residual = residual
        self._dense = dense

        # define layers
        self._linear_layers = torch.nn.ModuleList([])
        for i, out_size in enumerate(mlp_out_sizes):
            if i == 0:
                self._linear_layers.append(nn.Linear(self._in_size, out_size))
            else:
                if dense:
                    self._linear_layers.append(
                        nn.Linear(2 * mlp_out_sizes[i - 1], out_size)
                    )
                else:
                    self._linear_layers.append(
                        nn.Linear(mlp_out_sizes[i - 1], out_size)
                    )

        self._bn_layers = torch.nn.ModuleList([])
        if self._batchnorm:
            for out_size in mlp_out_sizes:
                self._bn_layers.append(nn.BatchNorm1d(out_size))

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """Forward pass of the module.

        Input has dimension NxMxC, where N is the batch size, M the number of points per
        set, and C the number of channels per point.

        Args:
            x: batch of point sets
        """
        set_size = x.shape[1]
        out = prev_out = x
        for i, linear_layer in enumerate(self._linear_layers):
            out = linear_layer(out)
            if self._batchnorm:
                # BN over channels across all points and sets
                pts_per_set = out.shape[1]
                out_view = out.view(-1, self._mlp_out_sizes[i])
                out = self._bn_layers[i](out_view)
                out = out.view(-1, pts_per_set, self._mlp_out_sizes[i])
            out = nn.functional.relu(out)

            if self._dense:
                out_max, _ = torch.max(out, 1, keepdim=True)
                if i != len(self._linear_layers) - 1:
                    out = torch.cat((out, out_max.expand(-1, set_size, -1)), dim=2)

            if self._residual:
                if prev_out.shape == out.shape:
                    out = prev_out + out
            prev_out = out

        # Maximum over points in same set
        out, _ = torch.max(out, 1)

        return out

__init__(in_size, mlp_out_sizes, batchnorm, residual=False, dense=False)

Initialize the VanillaPointNet module.

This module will only implements the MLP + MaxPooling part of the pointnet.

It still requires a task specific head.

Parameters:

Name Type Description Default
in_size int

dimension of the input points

required
mlp_out_sizes List

output sizes of each linear layer

required
batchnorm bool

whether to use batchnorm or not

required
Source code in sdfest/initialization/pointnet.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def __init__(
    self,
    in_size: int,
    mlp_out_sizes: List,
    batchnorm: bool,
    residual: bool = False,
    dense: bool = False,
) -> None:
    """Initialize the VanillaPointNet module.

    This module will only implements the MLP + MaxPooling part of the pointnet.

    It still requires a task specific head.

    Args:
        in_size:        dimension of the input points
        mlp_out_sizes:  output sizes of each linear layer
        batchnorm:      whether to use batchnorm or not
    """
    super().__init__()

    self._in_size = in_size
    self._mlp_out_sizes = mlp_out_sizes
    self._batchnorm = batchnorm
    self._residual = residual
    self._dense = dense

    # define layers
    self._linear_layers = torch.nn.ModuleList([])
    for i, out_size in enumerate(mlp_out_sizes):
        if i == 0:
            self._linear_layers.append(nn.Linear(self._in_size, out_size))
        else:
            if dense:
                self._linear_layers.append(
                    nn.Linear(2 * mlp_out_sizes[i - 1], out_size)
                )
            else:
                self._linear_layers.append(
                    nn.Linear(mlp_out_sizes[i - 1], out_size)
                )

    self._bn_layers = torch.nn.ModuleList([])
    if self._batchnorm:
        for out_size in mlp_out_sizes:
            self._bn_layers.append(nn.BatchNorm1d(out_size))

forward(x)

Forward pass of the module.

Input has dimension NxMxC, where N is the batch size, M the number of points per set, and C the number of channels per point.

Parameters:

Name Type Description Default
x Tensor

batch of point sets

required
Source code in sdfest/initialization/pointnet.py
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def forward(self, x: torch.Tensor) -> torch.Tensor:
    """Forward pass of the module.

    Input has dimension NxMxC, where N is the batch size, M the number of points per
    set, and C the number of channels per point.

    Args:
        x: batch of point sets
    """
    set_size = x.shape[1]
    out = prev_out = x
    for i, linear_layer in enumerate(self._linear_layers):
        out = linear_layer(out)
        if self._batchnorm:
            # BN over channels across all points and sets
            pts_per_set = out.shape[1]
            out_view = out.view(-1, self._mlp_out_sizes[i])
            out = self._bn_layers[i](out_view)
            out = out.view(-1, pts_per_set, self._mlp_out_sizes[i])
        out = nn.functional.relu(out)

        if self._dense:
            out_max, _ = torch.max(out, 1, keepdim=True)
            if i != len(self._linear_layers) - 1:
                out = torch.cat((out, out_max.expand(-1, set_size, -1)), dim=2)

        if self._residual:
            if prev_out.shape == out.shape:
                out = prev_out + out
        prev_out = out

    # Maximum over points in same set
    out, _ = torch.max(out, 1)

    return out