PyTorch 自定義數(shù)據(jù)集

準備數(shù)據(jù)

準備 COCO128 數(shù)據(jù)集讲逛,其是 COCO train2017 前 128 個數(shù)據(jù)薪棒。按 YOLOv5 組織的目錄:

$ tree ~/datasets/coco128 -L 2
/home/john/datasets/coco128
├── images
│   └── train2017
│       ├── ...
│       └── 000000000650.jpg
├── labels
│   └── train2017
│       ├── ...
│       └── 000000000650.txt
├── LICENSE
└── README.txt

詳見 Train Custom Data

定義 Dataset

torch.utils.data.Dataset 是一個數(shù)據(jù)集的抽象類初坠。自定義數(shù)據(jù)集時,需繼承 Dataset 并覆蓋如下方法:

  • __len__: len(dataset) 獲取數(shù)據(jù)集大小城榛。
  • __getitem__: dataset[i] 訪問第 i 個數(shù)據(jù)芽腾。

詳見:

自定義實現(xiàn) YOLOv5 數(shù)據(jù)集的例子:

import os
from pathlib import Path
from typing import Any, Callable, Optional, Tuple

import numpy as np
import torch
import torchvision
from PIL import Image


class YOLOv5(torchvision.datasets.vision.VisionDataset):

  def __init__(
    self,
    root: str,
    name: str,
    transform: Optional[Callable] = None,
    target_transform: Optional[Callable] = None,
    transforms: Optional[Callable] = None,
  ) -> None:
    super(YOLOv5, self).__init__(root, transforms, transform, target_transform)
    images_dir = Path(root) / 'images' / name
    labels_dir = Path(root) / 'labels' / name
    self.images = [n for n in images_dir.iterdir()]
    self.labels = []
    for image in self.images:
      base, _ = os.path.splitext(os.path.basename(image))
      label = labels_dir / f'{base}.txt'
      self.labels.append(label if label.exists() else None)

  def __getitem__(self, idx: int) -> Tuple[Any, Any]:
    img = Image.open(self.images[idx]).convert('RGB')

    label_file = self.labels[idx]
    if label_file is not None:  # found
      with open(label_file, 'r') as f:
        labels = [x.split() for x in f.read().strip().splitlines()]
        labels = np.array(labels, dtype=np.float32)
    else:  # missing
      labels = np.zeros((0, 5), dtype=np.float32)

    boxes = []
    classes = []
    for label in labels:
      x, y, w, h = label[1:]
      boxes.append([
        (x - w/2) * img.width,
        (y - h/2) * img.height,
        (x + w/2) * img.width,
        (y + h/2) * img.height])
      classes.append(label[0])

    target = {}
    target["boxes"] = torch.as_tensor(boxes, dtype=torch.float32)
    target["labels"] = torch.as_tensor(classes, dtype=torch.int64)

    if self.transforms is not None:
      img, target = self.transforms(img, target)

    return img, target

  def __len__(self) -> int:
    return len(self.images)

以上實現(xiàn),繼承了 VisionDataset 子類疏唾。其 __getitem__ 返回了:

  • image: PIL Image, 大小為 (H, W)
  • target: dict, 含以下字段:
    • boxes (FloatTensor[N, 4]): 真實標注框 [x1, y1, x2, y2], x 范圍 [0,W], y 范圍 [0,H]
    • labels (Int64Tensor[N]): 上述標注框的類別標識

讀取 Dataset

dataset = YOLOv5(Path.home() / 'datasets/coco128', 'train2017')
print(f'dataset: {len(dataset)}')
print(f'dataset[0]: {dataset[0]}')

輸出:

dataset: 128
dataset[0]: (<PIL.Image.Image image mode=RGB size=640x480 at 0x7F6F9464ADF0>, {'boxes': tensor([[249.7296, 200.5402, 460.5399, 249.1901],
        [448.1702, 363.7198, 471.1501, 406.2300],
        ...
        [  0.0000, 188.8901, 172.6400, 280.9003]]), 'labels': tensor([44, 51, 51, 51, 51, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45,
        45, 50, 50, 50, 51, 51, 60, 42, 44, 45, 45, 45, 50, 51, 51, 51, 51, 51,
        51, 44, 50, 50, 50, 45])})

預覽:

image

使用 DataLoader

訓練需要批量提取數(shù)據(jù)蓄氧,可以使用 DataLoader :

dataset = YOLOv5(Path.home() / 'datasets/coco128', 'train2017',
  transform=torchvision.transforms.Compose([
    torchvision.transforms.ToTensor()
  ]))

dataloader = DataLoader(dataset, batch_size=64, shuffle=True,
                        collate_fn=lambda batch: tuple(zip(*batch)))

for batch_i, (images, targets) in enumerate(dataloader):
  print(f'batch {batch_i}, images {len(images)}, targets {len(targets)}')
  print(f'  images[0]: shape={images[0].shape}')
  print(f'  targets[0]: {targets[0]}')

輸出:

batch 0, images 64, targets 64
  images[0]: shape=torch.Size([3, 480, 640])
  targets[0]: {'boxes': tensor([[249.7296, 200.5402, 460.5399, 249.1901],
        [448.1702, 363.7198, 471.1501, 406.2300],
        ...
        [  0.0000, 188.8901, 172.6400, 280.9003]]), 'labels': tensor([44, 51, 51, 51, 51, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45,
        45, 50, 50, 50, 51, 51, 60, 42, 44, 45, 45, 45, 50, 51, 51, 51, 51, 51,
        51, 44, 50, 50, 50, 45])}
batch 1, images 64, targets 64
  images[0]: shape=torch.Size([3, 248, 640])
  targets[0]: {'boxes': tensor([[337.9299, 167.8500, 378.6999, 191.3100],
        [383.5398, 148.4501, 452.6598, 191.4701],
        [467.9299, 149.9001, 540.8099, 193.2401],
        [196.3898, 142.7200, 271.6896, 190.0999],
        [134.3901, 154.5799, 193.9299, 189.1699],
        [ 89.5299, 162.1901, 124.3798, 188.3301],
        [  1.6701, 154.9299,  56.8400, 188.3700]]), 'labels': tensor([20, 20, 20, 20, 20, 20, 20])}

源碼

參考

APIs:

GoCoding 個人實踐的經(jīng)驗分享,可關注公眾號槐脏!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末喉童,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子顿天,更是在濱河造成了極大的恐慌堂氯,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件牌废,死亡現(xiàn)場離奇詭異咽白,居然都是意外死亡,警方通過查閱死者的電腦和手機鸟缕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門晶框,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人懂从,你說我怎么就攤上這事授段。” “怎么了莫绣?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵畴蒲,是天一觀的道長。 經(jīng)常有香客問我对室,道長模燥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任掩宜,我火速辦了婚禮蔫骂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘牺汤。我一直安慰自己辽旋,他們只是感情好,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著补胚,像睡著了一般码耐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上溶其,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天骚腥,我揣著相機與錄音,去河邊找鬼瓶逃。 笑死束铭,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的厢绝。 我是一名探鬼主播契沫,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼昔汉!你這毒婦竟也來了懈万?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤靶病,失蹤者是張志新(化名)和其女友劉穎钞速,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嫡秕,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年苹威,在試婚紗的時候發(fā)現(xiàn)自己被綠了昆咽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡牙甫,死狀恐怖掷酗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情窟哺,我是刑警寧澤泻轰,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站且轨,受9級特大地震影響浮声,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旋奢,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一泳挥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧至朗,春花似錦屉符、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唆香。三九已至,卻和暖如春吨艇,著一層夾襖步出監(jiān)牢的瞬間躬它,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工秸应, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留虑凛,地道東北人。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓软啼,卻偏偏與公主長得像桑谍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子祸挪,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容