-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2f714e6
commit be7b020
Showing
13 changed files
with
604 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
Object Detection | ||
====== | ||
|
||
Object detection is a computer vision technique for locating instances of objects in images or videos. Object detection algorithms typically leverage machine learning or deep learning to produce meaningful results. | ||
|
||
In these examples, we will use Starwhale to evaluate a set of object detection models on COCO datasets. | ||
|
||
Thanks to [ultralytics](https://github.com/ultralytics/ultralytics), it makes Starwhale Model Evaluation on YOLO easily. | ||
|
||
Links | ||
------ | ||
|
||
- Github Example Code: <https://github.com/star-whale/starwhale/tree/main/example/object-detection> | ||
- Starwhale Cloud Demo: <https://cloud.starwhale.cn/projects/397/overview> | ||
|
||
What we learn | ||
------ | ||
|
||
- build Starwhale Dataset by Starwhale Python SDK and use Starwhale Dataset Web Viewer. | ||
|
||
Models | ||
------ | ||
|
||
- [YOLO](https://docs.ultralytics.com/): We will compare YOLOv8-{n,s,m,l,x} and YOLOv6-{n,s,m,l,l6} model evaluations. | ||
|
||
Datasets | ||
------ | ||
|
||
- [COCO128](https://github.com/ultralytics/ultralytics/blob/main/ultralytics/cfg/datasets/coco128.yaml) | ||
|
||
- Introduction: Ultralytics COCO8 is a small, but versatile object detection dataset composed of the first 128 images of the COCO train 2017 set. This dataset is ideal for testing and debugging object detection models. | ||
- Size: Validation images 128. | ||
- Dataset build command: | ||
|
||
```bash | ||
swcli runtime activate object-detection | ||
python3 datasets/coco128.py | ||
``` | ||
|
||
- [COCO_val2017](https://cocodataset.org/#download) | ||
|
||
- Introduction: The COCO (Common Objects in Context) dataset is a large-scale object detection, segmentation, and captioning dataset. It is designed to encourage research on a wide variety of object categories and is commonly used for benchmarking computer vision models. The dataset comprises 80 object categories. | ||
- Size: Validation images 5,000. | ||
- Dataset build command: | ||
|
||
```bash | ||
swcli runtime activate object-detection | ||
python3 datasets/coco_val2017.py | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
data/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
from __future__ import annotations | ||
|
||
from pathlib import Path | ||
|
||
from utils import download, extract_zip, get_name_by_coco_category_id | ||
|
||
from starwhale import Image, dataset, BoundingBox, init_logger | ||
from starwhale.utils import console | ||
|
||
init_logger(3) | ||
|
||
ROOT = Path(__file__).parent | ||
DATA_DIR = ROOT / "data" / "coco128" | ||
|
||
# Copy from https://www.kaggle.com/datasets/ultralytics/coco128. | ||
|
||
|
||
def build() -> None: | ||
_zip_path = DATA_DIR / "coco128.zip" | ||
download("https://ultralytics.com/assets/coco128.zip", _zip_path) | ||
extract_zip( | ||
_zip_path, DATA_DIR, DATA_DIR / "coco129/images/train2017/000000000650.jpg" | ||
) | ||
|
||
with dataset("coco128") as ds: | ||
for img_path in (DATA_DIR / "coco128/images/train2017").glob("*.jpg"): | ||
name = img_path.name.split(".jpg")[0] | ||
|
||
# YOLO Darknet format: https://docs.plainsight.ai/labels/exporting-labels/yolo | ||
# Format: <object-class> <x_center> <y_center> <width> <height> | ||
# Meaning: object-class> - zero-based index representing the class in obj.names from 0 to (classes-1). | ||
# <x_center> <y_center> <width> <height> - float values relative to width and height of image, it can be equal from (0.0 to 1.0]. | ||
# <x_center> = <absolute_x> / <image_width> | ||
# <height> = <absolute_height> / <image_height> | ||
|
||
annotations = [] | ||
image = Image(img_path) | ||
i_width, i_height = image.to_pil().size | ||
|
||
label_path = DATA_DIR / "coco128/labels/train2017" / f"{name}.txt" | ||
if not label_path.exists(): | ||
continue | ||
|
||
for line in label_path.read_text().splitlines(): | ||
class_id, x, y, w, h = line.split() | ||
class_id, x, y, w, h = ( | ||
int(class_id), | ||
float(x), | ||
float(y), | ||
float(w), | ||
float(h), | ||
) | ||
annotations.append( | ||
{ | ||
"class_id": class_id, | ||
"class_name": get_name_by_coco_category_id(class_id), | ||
"darknet_bbox": [x, y, w, h], | ||
"bbox": BoundingBox( | ||
x=(x - w / 2) * i_width, | ||
y=(y - h / 2) * i_height, | ||
width=w * i_width, | ||
height=h * i_height, | ||
), | ||
} | ||
) | ||
|
||
ds[name] = {"image": image, "annotations": annotations} | ||
|
||
console.print("commit dataset...") | ||
ds.commit() | ||
|
||
console.print(f"{ds} has been built successfully!") | ||
|
||
|
||
if __name__ == "__main__": | ||
build() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
from __future__ import annotations | ||
|
||
import json | ||
from pathlib import Path | ||
from collections import defaultdict | ||
|
||
from tqdm import tqdm | ||
from utils import download, extract_zip, get_name_by_coco_category_id | ||
from ultralytics.data.converter import coco91_to_coco80_class | ||
|
||
from starwhale import Image, dataset, init_logger | ||
from starwhale.utils import console | ||
from starwhale.base.data_type import BoundingBox | ||
|
||
init_logger(3) | ||
|
||
ROOT = Path(__file__).parent | ||
DATA_DIR = ROOT / "data" / "coco2017" | ||
|
||
# The coco2017 val set is from https://cocodataset.org/#download. | ||
|
||
|
||
def build() -> None: | ||
_zip_path = DATA_DIR / "val2017.zip" | ||
download( | ||
"https://starwhale-examples.oss-cn-beijing.aliyuncs.com/dataset/coco2017/val2017.zip", | ||
_zip_path, | ||
) | ||
extract_zip(_zip_path, DATA_DIR, DATA_DIR / "val2017/000000000139.jpg") | ||
|
||
_zip_path = DATA_DIR / "annotations_trainval2017.zip" | ||
download( | ||
"https://starwhale-examples.oss-cn-beijing.aliyuncs.com/dataset/coco2017/annotations_trainval2017.zip", | ||
_zip_path, | ||
) | ||
json_path = DATA_DIR / "annotations/instances_val2017.json" | ||
extract_zip(_zip_path, DATA_DIR, json_path) | ||
|
||
coco_classes = coco91_to_coco80_class() | ||
|
||
with json_path.open() as f: | ||
content = json.load(f) | ||
annotations = defaultdict(list) | ||
for ann in content["annotations"]: | ||
class_id = coco_classes[ann["category_id"] - 1] | ||
annotations[ann["image_id"]].append( | ||
{ | ||
"bbox": BoundingBox(*ann["bbox"]), | ||
"class_id": class_id, | ||
"class_name": get_name_by_coco_category_id(class_id), | ||
} | ||
) | ||
|
||
with dataset("coco_val2017") as ds: | ||
for image in tqdm(content["images"]): | ||
name = image["file_name"].split(".jpg")[0] | ||
for ann in annotations[image["id"]]: | ||
bbox = ann["bbox"] | ||
ann["darknet_bbox"] = [ | ||
(bbox.x + bbox.width / 2) / image["width"], | ||
(bbox.y + bbox.height / 2) / image["height"], | ||
bbox.width / image["width"], | ||
bbox.height / image["height"], | ||
] | ||
ds[name] = { | ||
"image": Image(DATA_DIR / "val2017" / image["file_name"]), | ||
"annotations": annotations[image["id"]], | ||
} | ||
console.print("commit dataset...") | ||
ds.commit() | ||
|
||
console.print(f"{ds} has been built successfully!") | ||
|
||
|
||
if __name__ == "__main__": | ||
build() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
from __future__ import annotations | ||
|
||
import zipfile | ||
from pathlib import Path | ||
|
||
import requests | ||
from tqdm import tqdm | ||
|
||
from starwhale.utils import console | ||
|
||
_COCO_CLASSES_MAP = { | ||
0: "person", | ||
1: "bicycle", | ||
2: "car", | ||
3: "motorcycle", | ||
4: "airplane", | ||
5: "bus", | ||
6: "train", | ||
7: "truck", | ||
8: "boat", | ||
9: "traffic light", | ||
10: "fire hydrant", | ||
11: "stop sign", | ||
12: "parking meter", | ||
13: "bench", | ||
14: "bird", | ||
15: "cat", | ||
16: "dog", | ||
17: "horse", | ||
18: "sheep", | ||
19: "cow", | ||
20: "elephant", | ||
21: "bear", | ||
22: "zebra", | ||
23: "giraffe", | ||
24: "backpack", | ||
25: "umbrella", | ||
26: "handbag", | ||
27: "tie", | ||
28: "suitcase", | ||
29: "frisbee", | ||
30: "skis", | ||
31: "snowboard", | ||
32: "sports ball", | ||
33: "kite", | ||
34: "baseball bat", | ||
35: "baseball glove", | ||
36: "skateboard", | ||
37: "surfboard", | ||
38: "tennis racket", | ||
39: "bottle", | ||
40: "wine glass", | ||
41: "cup", | ||
42: "fork", | ||
43: "knife", | ||
44: "spoon", | ||
45: "bowl", | ||
46: "banana", | ||
47: "apple", | ||
48: "sandwich", | ||
49: "orange", | ||
50: "broccoli", | ||
51: "carrot", | ||
52: "hot dog", | ||
53: "pizza", | ||
54: "donut", | ||
55: "cake", | ||
56: "chair", | ||
57: "couch", | ||
58: "potted plant", | ||
59: "bed", | ||
60: "dining table", | ||
61: "toilet", | ||
62: "tv", | ||
63: "laptop", | ||
64: "mouse", | ||
65: "remote", | ||
66: "keyboard", | ||
67: "cell phone", | ||
68: "microwave", | ||
69: "oven", | ||
70: "toaster", | ||
71: "sink", | ||
72: "refrigerator", | ||
73: "book", | ||
74: "clock", | ||
75: "vase", | ||
76: "scissors", | ||
77: "teddy bear", | ||
78: "hair drier", | ||
79: "toothbrush", | ||
} | ||
|
||
|
||
def get_name_by_coco_category_id(category_id: int | None) -> str: | ||
return ( | ||
_COCO_CLASSES_MAP[category_id] if category_id is not None else "uncategorized" | ||
) | ||
|
||
|
||
def extract_zip(from_path: Path, to_path: Path, chk_path: Path) -> None: | ||
if chk_path.exists(): | ||
console.log(f"skip extract {from_path}, dir {chk_path} already exists") | ||
return | ||
|
||
with zipfile.ZipFile(from_path, "r", zipfile.ZIP_STORED) as z: | ||
for file in tqdm( | ||
iterable=z.namelist(), | ||
total=len(z.namelist()), | ||
desc=f"extract {from_path.name}", | ||
): | ||
z.extract(member=file, path=to_path) | ||
|
||
|
||
def download(url: str, to_path: Path) -> None: | ||
if to_path.exists(): | ||
console.log(f"skip download {url}, file {to_path} already exists") | ||
return | ||
|
||
to_path.parent.mkdir(parents=True, exist_ok=True) | ||
|
||
with requests.get(url, timeout=60, stream=True) as r: | ||
r.raise_for_status() | ||
size = int(r.headers.get("content-length", 0)) | ||
with tqdm( | ||
iterable=r.iter_content(chunk_size=1024), | ||
total=size, | ||
unit="B", | ||
unit_scale=True, | ||
desc=f"download {url}", | ||
) as pbar: | ||
with open(to_path, "wb") as f: | ||
for chunk in pbar: | ||
f.write(chunk) | ||
pbar.update(len(chunk)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
checkpoints/* | ||
runs/* | ||
flagged/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
runs/* | ||
checkpoints/cache/* |
Empty file.
Oops, something went wrong.