| import torch |
| from test_model import tiny_config |
|
|
| from objectmodel_v1.losses import ObjectModelCriterion |
|
|
|
|
| def reference_dense_targets(criterion, logits, targets, level_index): |
| batch, _, height, width = logits.shape |
| target_logits = torch.zeros_like(logits) |
| target_boxes = torch.zeros(batch, 4, height, width, device=logits.device) |
| positive = torch.zeros(batch, height, width, device=logits.device) |
| for batch_index, target in enumerate(targets): |
| if target["labels"].numel() == 0: |
| continue |
| centers = target["boxes"][:, :2] |
| grid = (centers * torch.tensor([width, height], device=centers.device)).long() |
| grid[:, 0].clamp_(0, width - 1) |
| grid[:, 1].clamp_(0, height - 1) |
| areas = target["boxes"][:, 2] * target["boxes"][:, 3] |
| target_levels = torch.where(areas < 0.02, 0, torch.where(areas < 0.15, 1, 2)) |
| for target_index in torch.where(target_levels == level_index)[0]: |
| center_x, center_y = grid[target_index] |
| label = target["labels"][target_index] |
| candidates = [] |
| for dy in (-1, 0, 1): |
| for dx in (-1, 0, 1): |
| x = int((center_x + dx).clamp(0, width - 1)) |
| y = int((center_y + dy).clamp(0, height - 1)) |
| candidates.append((dx * dx + dy * dy, x, y)) |
| for _, x, y in sorted(candidates)[: criterion.dense_topk]: |
| target_logits[batch_index, label, y, x] = 1.0 |
| target_boxes[batch_index, :, y, x] = target["boxes"][target_index] |
| positive[batch_index, y, x] = 1.0 |
| return target_logits, target_boxes, positive |
|
|
|
|
| def test_dense_targets_match_reference_with_boundaries_and_collisions(): |
| criterion = ObjectModelCriterion(tiny_config()) |
| logits = torch.randn(2, 5, 8, 8) |
| targets = [ |
| { |
| "boxes": torch.tensor( |
| [ |
| [0.01, 0.01, 0.10, 0.10], |
| [0.02, 0.02, 0.11, 0.11], |
| [0.99, 0.99, 0.50, 0.50], |
| ] |
| ), |
| "labels": torch.tensor([1, 2, 3]), |
| }, |
| {"boxes": torch.empty(0, 4), "labels": torch.empty(0, dtype=torch.long)}, |
| ] |
|
|
| for level_index in range(3): |
| expected = reference_dense_targets(criterion, logits, targets, level_index) |
| actual = criterion._dense_targets(logits, targets, level_index) |
| for expected_tensor, actual_tensor in zip(expected, actual, strict=True): |
| assert torch.equal(expected_tensor, actual_tensor) |
|
|
|
|
| def test_dense_targets_match_reference_for_production_topk(): |
| config = tiny_config() |
| config["loss"]["dense_topk"] = 5 |
| criterion = ObjectModelCriterion(config) |
| logits = torch.randn(2, 5, 12, 10) |
| targets = [ |
| {"boxes": torch.rand(9, 4), "labels": torch.randint(0, 5, (9,))}, |
| {"boxes": torch.rand(4, 4), "labels": torch.randint(0, 5, (4,))}, |
| ] |
|
|
| for level_index in range(3): |
| expected = reference_dense_targets(criterion, logits, targets, level_index) |
| actual = criterion._dense_targets(logits, targets, level_index) |
| for expected_tensor, actual_tensor in zip(expected, actual, strict=True): |
| assert torch.equal(expected_tensor, actual_tensor) |
|
|