Skip to content

Commit e6fc9a7

Browse files
committed
Merge branch 'master' of github.com:adursun/wsddn.pytorch
2 parents c853974 + 0c45e83 commit e6fc9a7

File tree

9 files changed

+46
-153
lines changed

9 files changed

+46
-153
lines changed

Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ FROM nvidia/cuda:10.0-devel-ubuntu18.04
33
WORKDIR /ws
44

55
COPY requirements.txt /ws/
6-
COPY install_detectron2.sh /ws/
76

87
RUN apt update && apt install -y apt-utils git vim libsm6 libxext6 libxrender-dev python3 python3-dev python3-pip
98
RUN pip3 install -r requirements.txt

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
```
1111
./prepare.sh
12-
docker run --gpus all -v `pwd`:/ws -it wsddn.pytorch /bin/bash
12+
docker run --gpus all --ipc=host -v `pwd`:/ws -it wsddn.pytorch /bin/bash
1313
```
1414

1515
## Jupyter

install_detectron2.sh

Lines changed: 0 additions & 8 deletions
This file was deleted.

prepare.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ wget http://pjreddie.com/media/files/VOCtest_06-Nov-2007.tar -P data/
88
mkdir data/VOCtest_06-Nov-2007
99
tar xf data/VOCtest_06-Nov-2007.tar --directory data/VOCtest_06-Nov-2007/
1010

11-
# download and extract selective search windows boxes
12-
wget http://www.cs.cmu.edu/~spurushw/hw2_files/selective_search_data.tar -P data/
13-
tar xf data/selective_search_data.tar --directory data/
11+
# download and extract edgeboxes proposals
12+
wget https://groups.inf.ed.ac.uk/hbilen-data/data/WSDDN/EdgeBoxesVOC2007test.mat -P data/
13+
wget https://groups.inf.ed.ac.uk/hbilen-data/data/WSDDN/EdgeBoxesVOC2007trainval.mat -P data/
1414

1515
# download pretrained alexnet weights
1616
wget https://download.pytorch.org/models/alexnet-owt-4df8aa71.pth -P states/

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ black==19.3b0
88
isort==4.3.21
99
albumentations==0.4.3
1010
Cython==0.29.14
11+
rope==0.14.0

src/datasets.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
from scipy.io import loadmat
88
from torch.utils.data import Dataset
99

10-
from utils import TRANSFORMS, prepare, swap_axes
10+
from utils import TRANSFORMS, filter_small_boxes, prepare, swap_axes
1111

1212

13-
class VOCandSSW(Dataset):
13+
class VocAndEb(Dataset):
1414

1515
CLASS2ID = {
1616
"aeroplane": 0,
@@ -36,36 +36,35 @@ class VOCandSSW(Dataset):
3636
}
3737

3838
def __init__(self, split, scales):
39-
assert split in ["trainval", "test"], "`split` should be in [train, test]"
39+
assert split in ["trainval", "test"], "`split` should be in [trainval, test]"
4040

4141
self.split = split
4242
self.scales = scales
4343

44-
loaded_mat = loadmat(f"../data/selective_search_data/voc_2007_{self.split}.mat")
45-
self.ssw_boxes = loaded_mat["boxes"][0]
46-
self.ssw_scores = loaded_mat["boxScores"][0]
44+
loaded_mat = loadmat(f"../data/EdgeBoxesVOC2007{self.split}.mat")
45+
self.eb_boxes = loaded_mat["boxes"][0]
46+
self.eb_scores = loaded_mat["boxScores"][0]
47+
self.ids = [str(id_[0]) for id_ in loaded_mat["images"][0]]
4748

4849
voc_dir = f"../data/VOC{self.split}_06-Nov-2007/VOCdevkit/VOC2007"
49-
self.ids = [
50-
id_.strip() for id_ in open(f"{voc_dir}/ImageSets/Main/{self.split}.txt")
51-
]
5250
self.img_paths = [f"{voc_dir}/JPEGImages/{id_}.jpg" for id_ in self.ids]
5351
self.annotation_paths = [f"{voc_dir}/Annotations/{id_}.xml" for id_ in self.ids]
5452

5553
def get_boxes_and_scores(self, i):
5654
# (box_count, 4)
5755
# dtype: float32
5856
# box format: (y_min, x_min, y_max, x_max)
59-
boxes = self.ssw_boxes[i].astype(np.float32)
57+
boxes = self.eb_boxes[i].astype(np.float32)
6058

6159
# box format: (x_min, y_min, x_max, y_max)
6260
# this can be improved
6361
boxes = swap_axes(boxes)
62+
mask = filter_small_boxes(boxes, 20)
6463

6564
# (box_count, 1)
6665
# dtype: float64
67-
scores = self.ssw_scores[i]
68-
return boxes, scores
66+
scores = self.eb_scores[i]
67+
return boxes[mask], scores[mask]
6968

7069
def get_target(self, gt_labels):
7170
target = np.full(20, 0, dtype=np.float32)

src/evaluate.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
import torch
44
from torch.utils.data import DataLoader
55

6-
from datasets import VOCandSSW
6+
from datasets import VocAndEb
77
from network import WSDDN
8-
from utils import evaluate, evaluate_detectron2
8+
from utils import evaluate
99

1010
SCALES = [480, 576, 688, 864, 1200]
1111
DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
@@ -21,8 +21,6 @@
2121

2222
print("State is loaded")
2323

24-
test_ds = VOCandSSW("test", SCALES) # len = 4952
25-
test_dl = DataLoader(test_ds, batch_size=None, shuffle=False, num_workers=1)
26-
27-
# evaluate_detectron2(net, test_dl)
24+
test_ds = VocAndEb("test", SCALES) # len = 4952
25+
test_dl = DataLoader(test_ds, batch_size=None, shuffle=False, num_workers=4)
2826
evaluate(net, test_dl)

src/train.py

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
from torch import optim
88
from torch.optim.lr_scheduler import MultiStepLR
99
from torch.utils.data import DataLoader
10+
from tqdm import tqdm
1011

11-
from datasets import VOCandSSW
12+
from datasets import VocAndEb
1213
from network import WSDDN
1314
from utils import evaluate
1415

@@ -38,11 +39,11 @@
3839
SAVE_STATE_PER_EPOCH = 5
3940

4041
# Create dataset and data loader
41-
train_ds = VOCandSSW("trainval", SCALES) # len = 5011
42-
test_ds = VOCandSSW("test", SCALES) # len = 4952
42+
train_ds = VocAndEb("trainval", SCALES) # len = 5011
43+
test_ds = VocAndEb("test", SCALES) # len = 4952
4344

44-
train_dl = DataLoader(train_ds, batch_size=1, shuffle=True, num_workers=1)
45-
test_dl = DataLoader(test_ds, batch_size=None, shuffle=False, num_workers=1)
45+
train_dl = DataLoader(train_ds, batch_size=1, shuffle=True, num_workers=4)
46+
test_dl = DataLoader(test_ds, batch_size=None, shuffle=False, num_workers=4)
4647

4748
# Create the network
4849
net = WSDDN()
@@ -60,16 +61,7 @@
6061
scheduler.last_epoch = OFFSET
6162

6263
# Train the model
63-
for epoch in range(OFFSET + 1, EPOCHS + 1):
64-
65-
print(
66-
"Epoch",
67-
epoch,
68-
"started at",
69-
datetime.now(),
70-
"with lr =",
71-
scheduler.get_lr(),
72-
)
64+
for epoch in tqdm(range(OFFSET + 1, EPOCHS + 1), "Total"):
7365

7466
epoch_loss = 0.0
7567

@@ -79,7 +71,7 @@
7971
batch_boxes,
8072
batch_scores,
8173
batch_target,
82-
) in train_dl:
74+
) in tqdm(train_dl, f"Epoch {epoch}"):
8375
optimizer.zero_grad()
8476

8577
batch_imgs, batch_boxes, batch_scores, batch_target = (
@@ -99,14 +91,12 @@
9991
if epoch % SAVE_STATE_PER_EPOCH == 0:
10092
path = f"../states/epoch_{epoch}.pt"
10193
torch.save(net.state_dict(), path)
102-
print("State saved to", path)
94+
tqdm.write(f"State saved to {path}")
10395

104-
print("Avg loss is", epoch_loss / len(train_ds))
96+
tqdm.write(f"Avg loss is {epoch_loss / len(train_ds)}")
10597

10698
if epoch % EVAL_PER_EPOCH == 0:
107-
print("Evaluation started at", datetime.now())
99+
tqdm.write(f"Evaluation started at {datetime.now()}")
108100
evaluate(net, test_dl)
109101

110-
print("Epoch", epoch, "completed at", datetime.now(), "\n")
111-
112102
scheduler.step()

src/utils.py

Lines changed: 15 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import logging
22
import random
3-
import tqdm
43
from collections import defaultdict
54
from datetime import datetime
65

@@ -13,8 +12,7 @@
1312
from PIL import Image
1413
from torchvision import transforms
1514
from torchvision.ops import nms
16-
17-
from detectron2.evaluation import PascalVOCDetectionEvaluator
15+
from tqdm import tqdm
1816

1917
# this is duplicate
2018
DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
@@ -56,95 +54,6 @@ def prepare(img, boxes, max_dim=None, xflip=False, gt_boxes=None, gt_labels=None
5654
return img, boxes, gt_boxes
5755

5856

59-
def evaluate_detectron2(net, dataloader):
60-
CLASSES = [
61-
"aeroplane",
62-
"bicycle",
63-
"bird",
64-
"boat",
65-
"bottle",
66-
"bus",
67-
"car",
68-
"cat",
69-
"chair",
70-
"cow",
71-
"diningtable",
72-
"dog",
73-
"horse",
74-
"motorbike",
75-
"person",
76-
"pottedplant",
77-
"sheep",
78-
"sofa",
79-
"train",
80-
"tvmonitor",
81-
]
82-
83-
class Detectron2VOCEvaluator(PascalVOCDetectionEvaluator):
84-
def __init__(self):
85-
self._dataset_name = "voc_2007_test"
86-
self._anno_file_template = (
87-
"/ws/data/VOCtest_06-Nov-2007/VOCdevkit/VOC2007/Annotations/{}.xml"
88-
)
89-
self._image_set_path = (
90-
"/ws/data/VOCtest_06-Nov-2007/VOCdevkit/VOC2007/ImageSets/Main/test.txt"
91-
)
92-
self._class_names = CLASSES
93-
self._is_2007 = True
94-
self._cpu_device = torch.device("cpu")
95-
self._logger = logging.getLogger(__name__)
96-
self._predictions = defaultdict(list)
97-
98-
evaluator = Detectron2VOCEvaluator()
99-
100-
print("Evaluation started at", datetime.now())
101-
102-
with torch.no_grad():
103-
104-
net.eval()
105-
106-
# check img_id -> batch or single
107-
108-
for (img_id, img, boxes, scores, gt_boxes, gt_labels) in dataloader:
109-
boxes, scores, gt_boxes, gt_labels = (
110-
boxes.numpy(),
111-
scores.numpy(),
112-
gt_boxes.numpy(),
113-
gt_labels.numpy(),
114-
)
115-
116-
batch_imgs, batch_boxes, batch_scores = (
117-
np2gpu(img, DEVICE),
118-
np2gpu(boxes, DEVICE),
119-
np2gpu(scores, DEVICE),
120-
)
121-
122-
combined_scores, pred_boxes = net(batch_imgs, batch_boxes, batch_scores)
123-
124-
for i in range(20):
125-
region_scores = combined_scores[:, i]
126-
127-
selected_indices = nms(pred_boxes, region_scores, 0.4)
128-
129-
resulting_boxes = pred_boxes[selected_indices].cpu().numpy()[:300]
130-
resulting_scores = region_scores[selected_indices].cpu().numpy()[:300]
131-
resulting_scores *= np.squeeze(scores[: len(resulting_scores)])
132-
133-
for j, resulting_box in enumerate(resulting_boxes):
134-
evaluator._predictions[i].append(
135-
f"{img_id} {resulting_scores[j]:.3f} {resulting_box[0] + 1:.1f} {resulting_box[1] + 1:.1f} {resulting_box[2]:.1f} {resulting_box[3]:.1f}"
136-
)
137-
138-
print("Predictions completed at", datetime.now())
139-
140-
net.train()
141-
142-
result = evaluator.evaluate()
143-
144-
print("Evaluation completed at", datetime.now())
145-
print(result)
146-
147-
14857
def evaluate(net, dataloader):
14958
"""Evaluates network."""
15059
with torch.no_grad():
@@ -156,7 +65,9 @@ def evaluate(net, dataloader):
15665
total_gt_boxes = []
15766
total_gt_labels = []
15867

159-
for (img_id, img, boxes, scores, gt_boxes, gt_labels) in tqdm.tqdm(dataloader, "Evaluating..."):
68+
for (img_id, img, boxes, scores, gt_boxes, gt_labels) in tqdm(
69+
dataloader, "Evaluation"
70+
):
16071
boxes, scores, gt_boxes, gt_labels = (
16172
boxes.numpy(),
16273
scores.numpy(),
@@ -172,6 +83,7 @@ def evaluate(net, dataloader):
17283
np2gpu(gt_labels, DEVICE),
17384
)
17485

86+
# why batch_boxes is not used and pred_boxes is returned
17587
combined_scores, pred_boxes = net(batch_imgs, batch_boxes, batch_scores)
17688

17789
batch_pred_boxes = []
@@ -180,13 +92,15 @@ def evaluate(net, dataloader):
18092

18193
for i in range(20):
18294
region_scores = combined_scores[:, i]
183-
selected_indices = nms(pred_boxes, region_scores, 0.4)
95+
score_mask = region_scores > 1e-3
96+
97+
selected_scores = region_scores[score_mask]
98+
selected_boxes = pred_boxes[score_mask]
99+
nms_mask = nms(selected_boxes, selected_scores, 0.4)
184100

185-
batch_pred_boxes.append(pred_boxes[selected_indices].cpu().numpy())
186-
batch_pred_scores.append(region_scores[selected_indices].cpu().numpy())
187-
batch_pred_labels.append(
188-
np.full(len(selected_indices), i, dtype=np.int32)
189-
)
101+
batch_pred_boxes.append(selected_boxes[nms_mask].cpu().numpy())
102+
batch_pred_scores.append(selected_scores[nms_mask].cpu().numpy())
103+
batch_pred_labels.append(np.full(len(nms_mask), i, dtype=np.int32))
190104

191105
total_pred_boxes.append(np.concatenate(batch_pred_boxes, axis=0))
192106
total_pred_scores.append(np.concatenate(batch_pred_scores, axis=0))
@@ -222,8 +136,8 @@ def filter_small_boxes(boxes, min_size):
222136
"""Filters out small boxes."""
223137
w = boxes[:, 2] - boxes[:, 0]
224138
h = boxes[:, 3] - boxes[:, 1]
225-
keep = np.where((w >= min_size) & (h > min_size))[0]
226-
return keep
139+
mask = (w >= min_size) & (h >= min_size)
140+
return mask
227141

228142

229143
def hflip(img, boxes, gt_boxes=None):

0 commit comments

Comments
 (0)