Download dataset.py from YMmim/object-detection-scratch: direct link, hf CLI and curl.
- Browser
- Download file 5.36 kB
-
https://huggingface.co/YMmim/object-detection-scratch/resolve/main/dataset.py
- Command line
-
hf download hf://YMmim/object-detection-scratch/dataset.py
-
curl -L -o dataset.py https://huggingface.co/YMmim/object-detection-scratch/resolve/main/dataset.py
5.36 kB
| """ | |
| Faster R-CNN ๋ฐ๋ฐ๋ฅ ๊ตฌํ โ [1/5] ๋ฐ์ดํฐ์ (Pascal VOC) | |
| ========================================================= | |
| Pascal VOC 2007/2012 ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด (์ด๋ฏธ์ง, ๋ฐ์ค, ๋ผ๋ฒจ)์ ๋ฐํํ๋ค. | |
| VOC ์ด๋ ธํ ์ด์ ์ XML ํ์์ด๋ฉฐ, ๊ฐ ๊ฐ์ฒด๋ง๋ค ๋ค์์ ๋ด๋๋ค: | |
| - name : ํด๋์ค ์ด๋ฆ (์: 'person', 'car') | |
| - bndbox : xmin, ymin, xmax, ymax (์ข์๋จยท์ฐํ๋จ ํฝ์ ์ขํ) | |
| - difficult : ํ๋ณ ์ด๋ ค์ด ๊ฐ์ฒด ํ์(ํ์ต ์ ๋ณดํต ์ ์ธ) | |
| ํต์ฌ ๊ฐ๋ : | |
| - ๋ฐ์ค ์ขํ๋ [x1, y1, x2, y2] ์ ๋ ํฝ์ ์ขํ๋ก ํต์ผํ๋ค. | |
| - ์ด๋ฏธ์ง๋ฅผ ๋ฆฌ์ฌ์ด์ฆํ๋ฉด ๋ฐ์ค๋ ๊ฐ์ ๋น์จ๋ก ์ค์ผ์ผํด์ผ ํ๋ค. | |
| """ | |
| import os | |
| import xml.etree.ElementTree as ET | |
| import torch | |
| from torch.utils.data import Dataset | |
| from PIL import Image | |
| import torchvision.transforms.functional as F | |
| # Pascal VOC 20๊ฐ ํด๋์ค (์ธ๋ฑ์ค 0์ ๋ฐฐ๊ฒฝ์ผ๋ก ์์ฝ โ ํด๋์ค๋ 1๋ถํฐ) | |
| VOC_CLASSES = [ | |
| "aeroplane", "bicycle", "bird", "boat", "bottle", | |
| "bus", "car", "cat", "chair", "cow", | |
| "diningtable", "dog", "horse", "motorbike", "person", | |
| "pottedplant", "sheep", "sofa", "train", "tvmonitor", | |
| ] | |
| # ์ด๋ฆ โ ์ธ๋ฑ์ค (๋ฐฐ๊ฒฝ=0 ์ด๋ฏ๋ก +1) | |
| CLASS_TO_IDX = {name: i + 1 for i, name in enumerate(VOC_CLASSES)} | |
| NUM_CLASSES = len(VOC_CLASSES) + 1 # +1 = ๋ฐฐ๊ฒฝ(background) | |
| class VOCDataset(Dataset): | |
| """ | |
| Pascal VOC ๊ฐ์ฒดํ์ง ๋ฐ์ดํฐ์ . | |
| Args: | |
| root: VOCdevkit/VOC2007 (๋๋ VOC2012) ๊ฒฝ๋ก | |
| split: 'train' | 'val' | 'trainval' | 'test' | |
| min_size: ๋ฆฌ์ฌ์ด์ฆ ์ ์ด๋ฏธ์ง ์งง์ ๋ณ์ ๋ชฉํ ๊ธธ์ด | |
| max_size: ๊ธด ๋ณ์ ์ต๋ ๊ธธ์ด(๋น์จ ์ ์งํ๋ฉฐ ์ํ ์ ์ฉ) | |
| keep_difficult: difficult=1 ๊ฐ์ฒด๋ฅผ ํฌํจํ ์ง ์ฌ๋ถ(ํ์ต ์ False ๊ถ์ฅ) | |
| """ | |
| def __init__(self, root, split="trainval", min_size=600, max_size=1000, | |
| keep_difficult=False): | |
| self.root = root | |
| self.min_size = min_size | |
| self.max_size = max_size | |
| self.keep_difficult = keep_difficult | |
| # ImageSets/Main/<split>.txt ์ ์ด๋ฏธ์ง ID ๋ชฉ๋ก์ด ์๋ค. | |
| split_file = os.path.join(root, "ImageSets", "Main", f"{split}.txt") | |
| with open(split_file) as f: | |
| self.ids = [line.strip() for line in f if line.strip()] | |
| def __len__(self): | |
| return len(self.ids) | |
| def _load_annotation(self, img_id): | |
| """XML์ ํ์ฑํด ๋ฐ์ค์ ๋ผ๋ฒจ์ ๋ฝ๋๋ค.""" | |
| ann_path = os.path.join(self.root, "Annotations", f"{img_id}.xml") | |
| tree = ET.parse(ann_path) | |
| boxes, labels = [], [] | |
| for obj in tree.findall("object"): | |
| difficult = int(obj.findtext("difficult", "0")) | |
| if difficult and not self.keep_difficult: | |
| continue | |
| name = obj.findtext("name").strip().lower() | |
| if name not in CLASS_TO_IDX: | |
| continue | |
| bnd = obj.find("bndbox") | |
| # VOC ์ขํ๋ 1๋ถํฐ ์์ โ 0-๊ธฐ๋ฐ์ผ๋ก ๋ณด์ (-1) | |
| x1 = float(bnd.findtext("xmin")) - 1 | |
| y1 = float(bnd.findtext("ymin")) - 1 | |
| x2 = float(bnd.findtext("xmax")) - 1 | |
| y2 = float(bnd.findtext("ymax")) - 1 | |
| boxes.append([x1, y1, x2, y2]) | |
| labels.append(CLASS_TO_IDX[name]) | |
| boxes = torch.as_tensor(boxes, dtype=torch.float32).reshape(-1, 4) | |
| labels = torch.as_tensor(labels, dtype=torch.int64) | |
| return boxes, labels | |
| def _resize(self, img, boxes): | |
| """ | |
| ์งง์ ๋ณ์ min_size๋ก ๋ง์ถ๋, ๊ธด ๋ณ์ด max_size๋ฅผ ๋์ง ์๋๋ก ์ค์ผ์ผ. | |
| ๋ฐ์ค๋ ๊ฐ์ ๋น์จ๋ก ์กฐ์ ํ๋ค. (Faster R-CNN ์๋ ผ๋ฌธ ๋ฐฉ์) | |
| """ | |
| w, h = img.size | |
| short, long = min(w, h), max(w, h) | |
| scale = self.min_size / short | |
| if long * scale > self.max_size: | |
| scale = self.max_size / long | |
| new_w, new_h = int(round(w * scale)), int(round(h * scale)) | |
| img = img.resize((new_w, new_h), Image.BILINEAR) | |
| if boxes.numel() > 0: | |
| boxes = boxes * scale # ๋ฐ์ค๋ ๋์ผ ๋ฐฐ์จ ์ ์ฉ | |
| return img, boxes, scale | |
| def __getitem__(self, idx): | |
| img_id = self.ids[idx] | |
| img_path = os.path.join(self.root, "JPEGImages", f"{img_id}.jpg") | |
| img = Image.open(img_path).convert("RGB") | |
| boxes, labels = self._load_annotation(img_id) | |
| img, boxes, scale = self._resize(img, boxes) | |
| # ํ ์ ๋ณํ + ImageNet ์ ๊ทํ(๋ฐฑ๋ณธ์ด ImageNet ์ฌ์ ํ์ต์ด๋ฏ๋ก) | |
| img = F.to_tensor(img) | |
| img = F.normalize(img, | |
| mean=[0.485, 0.456, 0.406], | |
| std=[0.229, 0.224, 0.225]) | |
| target = { | |
| "boxes": boxes, # [N,4] ์ ๋ ํฝ์ (๋ฆฌ์ฌ์ด์ฆ ํ) | |
| "labels": labels, # [N] 1..20 (0=๋ฐฐ๊ฒฝ) | |
| "image_id": img_id, | |
| "scale": scale, # ํ๊ฐ ์ ์๋ณธ ์ขํ๋ก ๋๋๋ฆด ๋ ์ฌ์ฉ | |
| } | |
| return img, target | |
| def collate_fn(batch): | |
| """ | |
| ์ด๋ฏธ์ง๋ง๋ค ํฌ๊ธฐ๊ฐ ๋ฌ๋ผ ๊ธฐ๋ณธ collate๋ก ๋ชป ๋ฌถ๋๋ค. | |
| ๋ฆฌ์คํธ ํํ๋ก ๊ทธ๋๋ก ๋๊ธฐ๊ณ , ๋ชจ๋ธ ๋ด๋ถ์์ ์ฒ๋ฆฌํ๋ค. | |
| (๊ฐ๋จํ๋ฅผ ์ํด batch_size=1 ์ฌ์ฉ์ ๊ถ์ฅ) | |
| """ | |
| imgs, targets = list(zip(*batch)) | |
| return list(imgs), list(targets) | |