Skip to content
This repository was archived by the owner on Aug 19, 2023. It is now read-only.

Commit c5f49f0

Browse files
committed
Merge branch 'debug-map'
2 parents 4caf4a7 + d520bb8 commit c5f49f0

File tree

12 files changed

+590
-216
lines changed

12 files changed

+590
-216
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,6 @@ ENV/
9898

9999
# mypy
100100
.mypy_cache/
101+
102+
*.zip
103+
*.pt

README.md

Lines changed: 108 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,113 @@
11
# pytorch-retinanet
22

3-
WIP
43

4+
Pytorch implementation of RetinaNet object detection as described in [Focal Loss for Dense Object Detection](https://arxiv.org/abs/1708.02002) by Tsung-Yi Lin, Priya Goyal, Ross Girshick, Kaiming He and Piotr Dollár.
55

6-
# dependencies
76

8-
sudo pip install cffi
9-
sudo pip install pandas
10-
sudo pip install pycocotools
11-
sudo pip install cython
12-
sudo pip install pycocotools
13-
sudo apt-get install tk-dev
14-
sudo apt-get install python-tk
15-
sudo pip install opencv-python
16-
sudo pip install requests
7+
## Results
8+
Currently, this repo achieves 33.7% mAP at 600px resolution with a Resnet-50 backbone. The published result is 34.0% mAP. The difference is likely due to the use of Adam optimizer instead of SGD with weight decay.
9+
10+
## Installation
11+
12+
1) Clone this repo
13+
14+
2) Install the required packages:
15+
16+
```
17+
apt-get install tk-dev python-tk
18+
```
19+
20+
3) Install the python packages:
21+
22+
```
23+
pip install cffi
24+
25+
pip install pandas
26+
27+
pip install pycocotools
28+
29+
pip install cython
30+
31+
pip install pycocotools
32+
33+
pip install opencv-python
34+
35+
pip install requests
36+
37+
```
38+
39+
4) Build the NMS extension.
40+
41+
## Training
42+
43+
The network can be trained using the `train.py` script. Currently, two dataloaders are available: COCO and CSV. For training on coco, use
44+
45+
```
46+
python train.py coco <path/to/coco>
47+
```
48+
49+
For training using a custom dataset, with annotations in CSV format (see below), use
50+
51+
```
52+
python train.py csv <path/to/annotations.csv> <path/to/classes.csv>
53+
```
54+
55+
## Visualization
56+
57+
To visualize the network detection, use `test.py`.
58+
59+
## CSV datasets
60+
The `CSVGenerator` provides an easy way to define your own datasets.
61+
It uses two CSV files: one file containing annotations and one file containing a class name to ID mapping.
62+
63+
### Annotations format
64+
The CSV file with annotations should contain one annotation per line.
65+
Images with multiple bounding boxes should use one row per bounding box.
66+
Note that indexing for pixel values starts at 0.
67+
The expected format of each line is:
68+
```
69+
path/to/image.jpg,x1,y1,x2,y2,class_name
70+
```
71+
72+
Some images may not contain any labeled objects.
73+
To add these images to the dataset as negative examples,
74+
add an annotation where `x1`, `y1`, `x2`, `y2` and `class_name` are all empty:
75+
```
76+
path/to/image.jpg,,,,,
77+
```
78+
79+
A full example:
80+
```
81+
/data/imgs/img_001.jpg,837,346,981,456,cow
82+
/data/imgs/img_002.jpg,215,312,279,391,cat
83+
/data/imgs/img_002.jpg,22,5,89,84,bird
84+
/data/imgs/img_003.jpg,,,,,
85+
```
86+
87+
This defines a dataset with 3 images.
88+
`img_001.jpg` contains a cow.
89+
`img_002.jpg` contains a cat and a bird.
90+
`img_003.jpg` contains no interesting objects/animals.
91+
92+
93+
### Class mapping format
94+
The class name to ID mapping file should contain one mapping per line.
95+
Each line should use the following format:
96+
```
97+
class_name,id
98+
```
99+
100+
Indexing for classes starts at 0.
101+
Do not include a background class as it is implicit.
102+
103+
For example:
104+
```
105+
cow,0
106+
cat,1
107+
bird,2
108+
```
109+
110+
## Acknowledgements
111+
112+
- Significant amounts of code are borrowed from the [keras retinanet implementation](https://github.com/fizyr/keras-retinanet)
113+
- The NMS module used is from the [pytorch faster-rcnn implementation](https://github.com/ruotianluo/pytorch-faster-rcnn)

anchors.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,3 @@
1-
"""
2-
Copyright 2017-2018 Fizyr (https://fizyr.com)
3-
4-
Licensed under the Apache License, Version 2.0 (the "License");
5-
you may not use this file except in compliance with the License.
6-
You may obtain a copy of the License at
7-
8-
http://www.apache.org/licenses/LICENSE-2.0
9-
10-
Unless required by applicable law or agreed to in writing, software
11-
distributed under the License is distributed on an "AS IS" BASIS,
12-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
See the License for the specific language governing permissions and
14-
limitations under the License.
15-
"""
16-
171
import numpy as np
182
import torch
193
import torch.nn as nn
@@ -51,7 +35,6 @@ def forward(self, image):
5135
all_anchors = np.expand_dims(all_anchors, axis=0)
5236

5337
return torch.from_numpy(all_anchors.astype(np.float32)).cuda()
54-
#return torch.autograd.Variable(torch.cuda.FloatTensor(all_anchors), requires_grad=False)
5538

5639
def generate_anchors(base_size=16, ratios=None, scales=None):
5740
"""

coco_eval.py

Lines changed: 60 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -7,96 +7,80 @@
77
import json
88
import os
99

10+
import torch
1011

1112
def evaluate_coco(dataset, model, threshold=0.05):
1213

1314
model.eval()
15+
16+
with torch.no_grad():
1417

15-
# start collecting results
16-
results = []
17-
image_ids = []
18+
# start collecting results
19+
results = []
20+
image_ids = []
1821

19-
for index in range(len(dataset)):
20-
data = dataset[index]
21-
scale = data['scale']
22+
for index in range(len(dataset)):
23+
data = dataset[index]
24+
scale = data['scale']
2225

23-
# run network
24-
scores, labels, boxes = model(data['img'].permute(2, 0, 1).cuda().float().unsqueeze(dim=0))
25-
scores = scores.cpu()
26-
labels = labels.cpu()
27-
boxes = boxes.cpu()
26+
# run network
27+
scores, labels, boxes = model(data['img'].permute(2, 0, 1).cuda().float().unsqueeze(dim=0))
28+
scores = scores.cpu()
29+
labels = labels.cpu()
30+
boxes = boxes.cpu()
2831

29-
# correct boxes for image scale
30-
boxes /= scale
32+
# correct boxes for image scale
33+
boxes /= scale
3134

32-
# change to (x, y, w, h) (MS COCO standard)
33-
boxes[:, 2] -= boxes[:, 0]
34-
boxes[:, 3] -= boxes[:, 1]
35+
# change to (x, y, w, h) (MS COCO standard)
36+
boxes[:, 2] -= boxes[:, 0]
37+
boxes[:, 3] -= boxes[:, 1]
3538

36-
# compute predicted labels and scores
37-
#for box, score, label in zip(boxes[0], scores[0], labels[0]):
38-
for box_id in range(boxes.shape[0]):
39-
score = float(scores[box_id])
40-
label = int(labels[box_id])
41-
box = boxes[box_id, :]
39+
# compute predicted labels and scores
40+
#for box, score, label in zip(boxes[0], scores[0], labels[0]):
41+
for box_id in range(boxes.shape[0]):
42+
score = float(scores[box_id])
43+
label = int(labels[box_id])
44+
box = boxes[box_id, :]
4245

43-
# scores are sorted, so we can break
44-
if score < threshold:
45-
break
46+
# scores are sorted, so we can break
47+
if score < threshold:
48+
break
4649

47-
# append detection for each positively labeled class
48-
image_result = {
49-
'image_id' : dataset.image_ids[index],
50-
'category_id' : dataset.label_to_coco_label(label),
51-
'score' : float(score),
52-
'bbox' : box.tolist(),
53-
}
50+
# append detection for each positively labeled class
51+
image_result = {
52+
'image_id' : dataset.image_ids[index],
53+
'category_id' : dataset.label_to_coco_label(label),
54+
'score' : float(score),
55+
'bbox' : box.tolist(),
56+
}
5457

55-
# append detection to results
56-
results.append(image_result)
58+
# append detection to results
59+
results.append(image_result)
5760

58-
# append image to list of processed images
59-
image_ids.append(dataset.image_ids[index])
61+
# append image to list of processed images
62+
image_ids.append(dataset.image_ids[index])
6063

61-
# print progress
62-
print('{}/{}'.format(index, len(dataset)), end='\r')
64+
# print progress
65+
print('{}/{}'.format(index, len(dataset)), end='\r')
6366

64-
if not len(results):
65-
return
67+
if not len(results):
68+
return
69+
70+
# write output
71+
json.dump(results, open('{}_bbox_results.json'.format(dataset.set_name), 'w'), indent=4)
72+
73+
# load results in COCO evaluation tool
74+
coco_true = dataset.coco
75+
coco_pred = coco_true.loadRes('{}_bbox_results.json'.format(dataset.set_name))
6676

67-
# write output
68-
json.dump(results, open('{}_bbox_results.json'.format(dataset.set_name), 'w'), indent=4)
69-
json.dump(image_ids, open('{}_processed_image_ids.json'.format(dataset.set_name), 'w'), indent=4)
70-
71-
# load results in COCO evaluation tool
72-
coco_true = dataset.coco
73-
coco_pred = coco_true.loadRes('{}_bbox_results.json'.format(dataset.set_name))
74-
75-
# run COCO evaluation
76-
coco_eval = COCOeval(coco_true, coco_pred, 'bbox')
77-
coco_eval.params.imgIds = image_ids
78-
coco_eval.evaluate()
79-
coco_eval.accumulate()
80-
coco_eval.summarize()
81-
82-
coco_tag = ['AP @[ IoU=0.50:0.95 | area= all | maxDets=100 ]',
83-
'AP @[ IoU=0.50 | area= all | maxDets=100 ]',
84-
'AP @[ IoU=0.75 | area= all | maxDets=100 ]',
85-
'AP @[ IoU=0.50:0.95 | area= small | maxDets=100 ]',
86-
'AP @[ IoU=0.50:0.95 | area=medium | maxDets=100 ]',
87-
'AP @[ IoU=0.50:0.95 | area= large | maxDets=100 ]',
88-
'AR @[ IoU=0.50:0.95 | area= all | maxDets= 1 ]',
89-
'AR @[ IoU=0.50:0.95 | area= all | maxDets= 10 ]',
90-
'AR @[ IoU=0.50:0.95 | area= all | maxDets=100 ]',
91-
'AR @[ IoU=0.50:0.95 | area= small | maxDets=100 ]',
92-
'AR @[ IoU=0.50:0.95 | area=medium | maxDets=100 ]',
93-
'AR @[ IoU=0.50:0.95 | area= large | maxDets=100 ]']
94-
95-
coco_eval_stats = coco_eval.stats
96-
97-
for index, result in enumerate(coco_eval_stats):
98-
print('{}. {}: {}'.format(index + 1, coco_tag[index], coco_eval_stats[index]))
99-
100-
model.train()
101-
102-
return
77+
# run COCO evaluation
78+
coco_eval = COCOeval(coco_true, coco_pred, 'bbox')
79+
coco_eval.params.imgIds = image_ids
80+
coco_eval.evaluate()
81+
coco_eval.accumulate()
82+
coco_eval.summarize()
83+
84+
model.train()
85+
86+
return

0 commit comments

Comments
 (0)