Skip to content

Commit e03e56a

Browse files
committed
tests for pipeline added
1 parent dda89d1 commit e03e56a

File tree

9 files changed

+87
-42
lines changed

9 files changed

+87
-42
lines changed

configs/default_config.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
data = dict(
22
root="./data",
33
resize=(224,224),
4-
train_batch_size=64,
4+
train_batch_size=128,
55
val_batch_size=32,
6-
max_epochs=200,
7-
num_workers=4,
6+
max_epochs=1,
7+
num_workers=6,
88
category_list='all',
99
normalization=dict(mean=[0.5931, 0.4690, 0.4229],
1010
std=[0.2471, 0.2214, 0.2157])
1111
)
1212

13-
model = dict(name='mobilenetv3_large', pretrained=True, num_classes=1, load_weights='')
13+
model = dict(name='mobilenetv3_large', pretrained=False, num_classes=9, load_weights='')
1414

1515
data_parallel = dict(use_parallel=True,
1616
parallel_params=dict(device_ids=[0], output_device=0))
1717

1818
optim = dict(name='adam', lr=0.001, momentum=0.9, wd=1e-4, betas=(0.9, 0.999), rho=0.9, alpha=0.99, nesterov=True)
1919

20-
scheduler = dict(name='exp', gamma=0.1, exp_gamma=0.975, steps=[50])
20+
scheduler = dict(name='cosine', gamma=0.1, exp_gamma=0.975, steps=[50])
2121

22-
loss=dict(names=['mse', 'add_loss'], coeffs=([1., .1],[]), smoothl1_beta=0.2, alwa=dict(use=False, lam_cls=1., lam_reg=1., C=100, compute_std=True))
22+
loss=dict(names=['smoothl1', 'cross_entropy'], coeffs=([1.],[1.]), smoothl1_beta=0.2, alwa=dict(use=False, lam_cls=1., lam_reg=1., C=100, compute_std=True))
2323

24-
utils=dict(debug_mode = False, random_seeds=5, save_freq=10, print_freq=20, debug_steps=20)
24+
output_dir = './output/log'
2525

26-
output_dir = './output/exp_0'
26+
utils=dict(debug_mode = False, random_seeds=5, save_freq=10, print_freq=20, debug_steps=100)
2727

2828
regime = dict(type='training', vis_only=False)

tests/test_pipeline.py

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import torch
2+
3+
from torchdet3d.evaluation import (compute_average_distance, compute_metrics_per_cls,
4+
compute_2d_based_iou, compute_accuracy)
5+
6+
from torchdet3d.losses import WingLoss, ADD_loss, DiagLoss
7+
from torchdet3d.builders import (build_loss, build_optimizer, build_scheduler, build_loader,
8+
build_model, AVAILABLE_LOSS, AVAILABLE_OPTIMS, AVAILABLE_SCHEDS)
9+
from torchdet3d.utils import read_py_config
10+
11+
12+
class TestCasesPipeline:
13+
gt_kps = torch.rand(128,9,2)
14+
test_kps = torch.rand(128,9,2, requires_grad=True)
15+
gt_cats = torch.randint(0,9,(128,))
16+
test_cats = torch.rand(128,9)
17+
config = read_py_config("./configs/default_config.py")
18+
19+
def test_metrics(self):
20+
ADD, SADD = compute_average_distance(self.test_kps, self.gt_kps)
21+
metrics = compute_metrics_per_cls(self.test_kps, self.gt_kps, self.test_cats, self.gt_cats)
22+
IOU = compute_2d_based_iou(self.test_kps, self.gt_kps)
23+
acc = compute_accuracy(self.test_cats, self.gt_cats)
24+
assert 0 <= ADD <= 1 and 0 <= SADD <= 1 and 0 <= IOU <= 1 and 0 <= acc <= 1
25+
assert len(metrics) == 9 and len(metrics[0]) == 4
26+
27+
def test_losses(self):
28+
for loss in [WingLoss(), ADD_loss(), DiagLoss()]:
29+
input_ = torch.sigmoid(torch.randn(512, 9, 2, requires_grad=True))
30+
target = torch.sigmoid(torch.randn(512, 9, 2))
31+
output = loss(input_, target)
32+
assert not torch.any(torch.isnan(output))
33+
output.backward()
34+
35+
def test_builders(self):
36+
for loss_ in AVAILABLE_LOSS:
37+
if loss_ != 'cross_entropy':
38+
self.config['loss']['names']=[loss_, 'cross_entropy']
39+
self.config.loss.coeffs=([1.],[1.])
40+
regress_criterions, class_criterions = build_loss(self.config)
41+
assert len(regress_criterions) == 1 and len(class_criterions) == 1
42+
model = build_model(self.config)
43+
assert model is not None
44+
for optim_ in AVAILABLE_OPTIMS:
45+
self.config['optim']['name'] = optim_
46+
optimizer = build_optimizer(self.config, model)
47+
assert optimizer is not None
48+
for schd in AVAILABLE_SCHEDS:
49+
self.config['scheduler']['name'] = schd
50+
scheduler = build_scheduler(self.config, optimizer)
51+
assert scheduler is not None
52+
53+
def test_random_inference(self):
54+
model = build_model(self.config)
55+
image = torch.rand(128,3,224,224)
56+
kp, cat = model(image, self.gt_cats)
57+
assert kp.shape == (128,9,2)
58+
assert cat.shape == (128,9)

torchdet3d/builders/__init__.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from .loss_builder import build_loss
2-
from .optim_builder import build_optimizer
3-
from .scheduler_builder import build_scheduler
1+
from .loss_builder import build_loss, AVAILABLE_LOSS
2+
from .optim_builder import build_optimizer, AVAILABLE_OPTIMS
3+
from .scheduler_builder import build_scheduler, AVAILABLE_SCHEDS
44
from .loader_builder import build_loader, build_augmentations
55
from .model_builder import build_model

torchdet3d/builders/loss_builder.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import torch
22
from torchdet3d.losses import DiagLoss, ADD_loss, WingLoss
33

4-
__AVAILABLE_LOSS = ['smoothl1', 'cross_entropy', 'diag_loss', 'mse', 'add_loss', 'wing']
4+
AVAILABLE_LOSS = ['smoothl1', 'cross_entropy', 'diag_loss', 'mse', 'add_loss', 'wing']
55

66

77
def build_loss(cfg):
88
"build losses in right order"
99
regress_criterions = []
1010
class_criterions = []
1111
for loss_name in cfg.loss.names:
12-
assert loss_name in __AVAILABLE_LOSS
12+
assert loss_name in AVAILABLE_LOSS
1313
if loss_name == 'cross_entropy':
1414
class_criterions.append(torch.nn.CrossEntropyLoss())
1515
elif loss_name == 'smoothl1':

torchdet3d/builders/optim_builder.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import torch
22

3-
__AVAILABLE_OPTIMS = ['sgd', 'rmsprop', 'adam', 'adadelta']
3+
AVAILABLE_OPTIMS = ['sgd', 'rmsprop', 'adam', 'adadelta']
44

55
def build_optimizer(cfg, net):
6-
assert cfg.optim.name in __AVAILABLE_OPTIMS
6+
assert cfg.optim.name in AVAILABLE_OPTIMS
77
if cfg.optim.name == 'adadelta':
88
optim = torch.optim.Adadelta(net.parameters(), lr=cfg.optim.lr, rho=cfg.optim.rho,
99
weight_decay=cfg.optim.wd)

torchdet3d/builders/scheduler_builder.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import torch
22

3-
__AVAILABLE_SCHEDS = ['cosine', 'exp', 'stepLR', 'multistepLR']
3+
AVAILABLE_SCHEDS = ['cosine', 'exp', 'stepLR', 'multistepLR']
44

55
def build_scheduler(cfg, optimizer):
66
if cfg.scheduler.name is None:
77
return None
88

9-
assert cfg.scheduler.name in __AVAILABLE_SCHEDS
9+
assert cfg.scheduler.name in AVAILABLE_SCHEDS
1010
if cfg.scheduler.name == 'cosine':
1111
sched = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer,
1212
T_max=cfg.data.max_epochs,

torchdet3d/evaluation/evaluate.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def val(self, epoch=None):
100100
IOU = compute_2d_based_iou(pred_kp, gt_kp)
101101
acc = compute_accuracy(pred_cats, gt_cats)
102102

103-
for cl, ADD_cls, SADD_cls, acc_cls in compute_metrics_per_cls(pred_kp, gt_kp, gt_cats, pred_cats):
103+
for cl, ADD_cls, SADD_cls, acc_cls in compute_metrics_per_cls(pred_kp, gt_kp, pred_cats, gt_cats):
104104
ADD_cls_meter[cl].update(ADD_cls, imgs.size(0))
105105
SADD_cls_meter[cl].update(SADD_cls, imgs.size(0))
106106
acc_cls_meter[cl].update(acc_cls, imgs.size(0))

torchdet3d/evaluation/metrics.py

+11-12
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,34 @@
77

88
from torchdet3d.utils import lift_2d
99

10-
10+
@torch.no_grad()
1111
def compute_average_distance(pred_kp, gt_kp, num_keypoint=9, **kwargs):
1212
"""Computes Average Distance (ADD) metric."""
13-
detached_pred_kp = pred_kp.detach()
14-
detached_gt_kp = gt_kp.detach()
1513
add_distance = 0.
1614
# compute
17-
add_distance = torch.mean(torch.linalg.norm(detached_pred_kp - detached_gt_kp, dim=2))
15+
add_distance = torch.mean(torch.linalg.norm(pred_kp - gt_kp, dim=2))
1816

1917
# Computes the symmetric version of the average distance metric.
20-
add_sym_distance = torch.zeros((detached_pred_kp.shape[0])).to(detached_pred_kp.device)
18+
add_sym_distance = torch.zeros((pred_kp.shape[0])).to(pred_kp.device)
2119
for i in range(num_keypoint):
2220
# Find nearest vertex in gt_kp
23-
distance = torch.linalg.norm(detached_pred_kp[:, i, :] - detached_gt_kp[:, i, :], dim=1)
21+
distance = torch.linalg.norm(pred_kp[:, i, :] - gt_kp[:, i, :], dim=1)
2422
for j in range(num_keypoint):
25-
d = torch.linalg.norm(detached_pred_kp[:, i, :] - detached_gt_kp[:, j, :], dim=1)
23+
d = torch.linalg.norm(pred_kp[:, i, :] - gt_kp[:, j, :], dim=1)
2624
distance = torch.where(d < distance, d, distance)
2725
add_sym_distance += distance
2826

2927
# average by num keypoints, then mean by batch
3028
add_sym_distance = torch.mean(add_sym_distance / num_keypoint)
3129
return add_distance.item(), add_sym_distance.item()
3230

31+
@torch.no_grad()
3332
def compute_accuracy(pred_cats, gt_cats, **kwargs):
34-
detached_pred_cats = pred_cats.detach()
35-
detached_gt_cats = gt_cats.detach() if isinstance(gt_cats, torch.Tensor) else gt_cats
36-
detached_pred_cats = torch.argmax(detached_pred_cats, dim=1)
37-
return torch.mean((detached_pred_cats == detached_gt_cats).float()).item()
33+
pred_cats = torch.argmax(pred_cats, dim=1)
34+
return torch.mean((pred_cats == gt_cats).float()).item()
3835

39-
def compute_metrics_per_cls(pred_kp, gt_kp, gt_cats, pred_cats, **kwargs):
36+
@torch.no_grad()
37+
def compute_metrics_per_cls(pred_kp, gt_kp, pred_cats, gt_cats, **kwargs):
4038
classes = torch.unique(gt_cats)
4139
computed_metrics = []
4240
for cl in classes:
@@ -50,6 +48,7 @@ def compute_metrics_per_cls(pred_kp, gt_kp, gt_cats, pred_cats, **kwargs):
5048

5149
return computed_metrics
5250

51+
@torch.no_grad()
5352
def compute_2d_based_iou(pred_kp: torch.Tensor, gt_kp: torch.Tensor):
5453
assert len(pred_kp.shape) == 3
5554
bs = pred_kp.shape[0]

torchdet3d/losses/regression_losses.py

-12
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,3 @@ def parse_losses(self, pred_kp, gt_kp,
113113
print(f"classification coefficient changed : {self.lam_cls}")
114114

115115
return self.lam_reg * sum(regress_loss) + self.lam_cls * sum(class_loss)
116-
117-
def test():
118-
import torch.nn.functional as F
119-
for loss in [WingLoss()]:
120-
input_ = F.sigmoid(torch.randn(3, 9, 2, requires_grad=True))
121-
target = F.sigmoid(torch.randn(3, 9, 2))
122-
output = loss(input_, target)
123-
ic(output)
124-
output.backward()
125-
126-
if __name__ == '__main__':
127-
test()

0 commit comments

Comments
 (0)