以下內容為結合李沐老師的課程和教材補充的學習筆記,以及對課后練習的一些思考,自留回顧,也供同學之人交流參考。
本節課程地址:數據集_嗶哩嗶哩_bilibili
本節教材地址:13.6. 目標檢測數據集 — 動手學深度學習 2.0.0 documentation
本節開源代碼:…>d2l-zh>pytorch>chapter_optimization>object-detection-dataset.ipynb
目標檢測數據集
目標檢測領域沒有像MNIST和Fashion-MNIST那樣的小數據集。
為了快速測試目標檢測模型,[我們收集并標記了一個小型數據集]。
首先,我們拍攝了一組香蕉的照片,并生成了1000張不同角度和大小的香蕉圖像。
然后,我們在一些背景圖片的隨機位置上放一張香蕉的圖像。
最后,我們在圖片上為這些香蕉標記了邊界框。
[下載數據集]
包含所有圖像和CSV標簽文件的香蕉檢測數據集可以直接從互聯網下載。
%matplotlib inline
import os
import pandas as pd
import torch
import torchvision
from d2l import torch as d2l
#@save
d2l.DATA_HUB['banana-detection'] = (d2l.DATA_URL + 'banana-detection.zip','5de26c8fce5ccdea9f91267273464dc968d20d72')
讀取數據集
通過read_data_bananas
函數,我們[讀取香蕉檢測數據集]。
該數據集包括一個的CSV文件,內含目標類別標簽和位于左上角和右下角的真實邊界框坐標。
#@save
def read_data_bananas(is_train=True):"""讀取香蕉檢測數據集中的圖像和標簽"""data_dir = d2l.download_extract('banana-detection')csv_fname = os.path.join(data_dir, 'bananas_train' if is_trainelse 'bananas_val', 'label.csv')csv_data = pd.read_csv(csv_fname)csv_data = csv_data.set_index('img_name')images, targets = [], []for img_name, target in csv_data.iterrows():images.append(torchvision.io.read_image(os.path.join(data_dir, 'bananas_train' if is_train else'bananas_val', 'images', f'{img_name}')))# 這里的target包含(類別,左上角x,左上角y,右下角x,右下角y),# 其中所有圖像都具有相同的香蕉類(索引為0)targets.append(list(target))# /256將像素坐標從[0,256]歸一化到[0,1]return images, torch.tensor(targets).unsqueeze(1) / 256
通過使用read_data_bananas
函數讀取圖像和標簽,以下BananasDataset
類別將允許我們[創建一個自定義Dataset
實例]來加載香蕉檢測數據集。
#@save
class BananasDataset(torch.utils.data.Dataset):"""一個用于加載香蕉檢測數據集的自定義數據集"""def __init__(self, is_train):self.features, self.labels = read_data_bananas(is_train)print('read ' + str(len(self.features)) + (f' training examples' ifis_train else f' validation examples'))def __getitem__(self, idx):return (self.features[idx].float(), self.labels[idx])def __len__(self):return len(self.features)
最后,我們定義load_data_bananas
函數,來[為訓練集和測試集返回兩個數據加載器實例]。對于測試集,無須按隨機順序讀取它。
#@save
def load_data_bananas(batch_size):"""加載香蕉檢測數據集"""train_iter = torch.utils.data.DataLoader(BananasDataset(is_train=True),batch_size, shuffle=True)val_iter = torch.utils.data.DataLoader(BananasDataset(is_train=False),batch_size)return train_iter, val_iter
讓我們[讀取一個小批量,并打印其中的圖像和標簽的形狀]。
圖像的小批量的形狀為(批量大小、通道數、高度、寬度),看起來很眼熟:它與我們之前圖像分類任務中的相同。
標簽的小批量的形狀為(批量大小,mmm,5),其中mmm是數據集的任何圖像中邊界框可能出現的最大數量。
小批量計算雖然高效,但它要求每張圖像含有相同數量的邊界框,以便放在同一個批量中。
通常來說,圖像可能擁有不同數量個邊界框;因此,在達到mmm之前,邊界框少于mmm的圖像將被非法邊界框填充。
這樣,每個邊界框的標簽將被長度為5的數組表示。
數組中的第一個元素是邊界框中對象的類別,其中-1表示用于填充的非法邊界框。
數組的其余四個元素是邊界框左上角和右下角的(xxx,yyy)坐標值(值域在0~1之間)。
對于香蕉數據集而言,由于每張圖像上只有一個邊界框,因此m=1m=1m=1。
batch_size, edge_size = 32, 256
train_iter, _ = load_data_bananas(batch_size)
# 取出第一個batch
batch = next(iter(train_iter))
batch[0].shape, batch[1].shape
read 1000 training examples
read 100 validation examples(torch.Size([32, 3, 256, 256]), torch.Size([32, 1, 5]))
[演示]
讓我們展示10幅帶有真實邊界框的圖像。
我們可以看到在所有這些圖像中香蕉的旋轉角度、大小和位置都有所不同。
當然,這只是一個簡單的人工數據集,實踐中真實世界的數據集通常要復雜得多。
# 因為每個像素值的范圍是[0, 255],0是純黑,255是純白
# /255是將像素值從[0, 255]?歸一化??到[0, 1]
imgs = (batch[0][0:10].permute(0, 2, 3, 1)) / 255
axes = d2l.show_images(imgs, 2, 5, scale=2)
for ax, label in zip(axes, batch[1][0:10]):# * edge_size返回原尺寸d2l.show_bboxes(ax, [label[0][1:5] * edge_size], colors=['w'])
小結
- 我們收集的香蕉檢測數據集可用于演示目標檢測模型。
- 用于目標檢測的數據加載與圖像分類的數據加載類似。但是,在目標檢測中,標簽還包含真實邊界框的信息,它不出現在圖像分類中。
練習
- 在香蕉檢測數據集中演示其他帶有真實邊界框的圖像。它們在邊界框和目標方面有什么不同?
解:
不同圖像中的邊界框的縮放比scale、寬高比ratio、旋轉角度以及在圖像中的位置不同,與背景圖的色彩對比度也不同。
- 假設我們想要將數據增強(例如隨機裁剪)應用于目標檢測。它與圖像分類中的有什么不同?提示:如果裁剪的圖像只包含物體的一小部分會怎樣?
解:
對于圖像分類任務,僅需增強圖像,且保證圖像分類的主體可識別即可。
但對于目標檢測任務,需要同時增強圖像和邊界框,并且需要同步調整邊界框坐標,同時需要保證目標以及目標相關圖像的完整性,否則可能導致數據增強后圖像檢測無效。因此,目標檢測的數據增強要求更高。