Compute instance graph and per-edge affinity scores. :param edge_index: Tensor of size [2, num_edges] Edges connecting the clusters in of the instance graph. The output instance graph will be a trimmed version of this graph, where only (i, j) edges with (
(
self,
edge_index: torch.Tensor,
num_classes: int = None,
smooth_affinity: bool = True
)
| 349 | return obj_pos, obj_idx |
| 350 | |
| 351 | def instance_graph( |
| 352 | self, |
| 353 | edge_index: torch.Tensor, |
| 354 | num_classes: int = None, |
| 355 | smooth_affinity: bool = True |
| 356 | ) -> Tuple[torch.Tensor, torch.Tensor]: |
| 357 | """Compute instance graph and per-edge affinity scores. |
| 358 | |
| 359 | :param edge_index: Tensor of size [2, num_edges] |
| 360 | Edges connecting the clusters in of the instance graph. The |
| 361 | output instance graph will be a trimmed version of this |
| 362 | graph, where only (i, j) edges with (i < j) are preserved. |
| 363 | :param num_classes: int |
| 364 | Number of classes in the dataset. Specifying `num_classes` |
| 365 | allows identifying 'void' labels. By convention, we assume |
| 366 | `y ∈ [0, self.num_classes-1]` ARE ALL VALID LABELS (i.e. not |
| 367 | 'ignored', 'void', 'unknown', etc), while `y < 0` AND |
| 368 | `y >= self.num_classes` ARE VOID LABELS. Void data is dealt |
| 369 | with following https://arxiv.org/abs/1801.00868 and |
| 370 | https://arxiv.org/abs/1905.01220 |
| 371 | :param smooth_affinity: bool |
| 372 | If True, the affinity score computed for each edge will |
| 373 | follow the 'smooth' formulation: |
| 374 | `(overlap_i_obj_j / size_i + overlap_j_obj_i / size_j) / 2` |
| 375 | for the edge `(i, j)`, where `obj_i` designates the target |
| 376 | instance of `i`. If False, the affinity will be computed |
| 377 | with the simpler formulation: `obj_i == obj_j` |
| 378 | |
| 379 | :return obj_edge_index, obj_edge_affinity |
| 380 | obj_edge_index: Tensor of size [2, num_trimmed_edges] |
| 381 | Edges of the trimmed instance graph |
| 382 | obj_edge_affinity: Tensor |
| 383 | Affinity for each edge |
| 384 | """ |
| 385 | # In order to save compute and memory, and because the |
| 386 | # cut-pursuit partition algorithm considers edges to be |
| 387 | # non-oriented, we do not need to express both (i, j) and (j, i) |
| 388 | # edges in the instance graph. So we start by trimming the input |
| 389 | # edges to only have unique (i, j) edges with i < j. |
| 390 | # Importantly, this operation also removes self-loops, which is |
| 391 | # what we want here |
| 392 | obj_edge_index = to_trimmed(edge_index.to(self.device)) |
| 393 | |
| 394 | # Return here if the graph is empty |
| 395 | if obj_edge_index.numel() == 0: |
| 396 | return obj_edge_index, torch.zeros(0, device=self.device) |
| 397 | |
| 398 | # Find the target instance for each cluster: the instance it has |
| 399 | # the biggest overlap with |
| 400 | sp_obj_idx = self.major(num_classes=num_classes)[0] |
| 401 | |
| 402 | # Propagate the instance object to the edges' source and target |
| 403 | # clusters |
| 404 | i_obj_idx = sp_obj_idx[obj_edge_index[0]] |
| 405 | j_obj_idx = sp_obj_idx[obj_edge_index[1]] |
| 406 | |
| 407 | # In case smooth affinity computation is not required, the |
| 408 | # affinity is directly calculated by `obj_i == obj_j` |
no test coverage detected