O *Dataset* de Detecção de Objetos ================================== Não existem pequenos conjuntos de dados, como MNIST ou Fashion-MNIST, no campo de detecção de objetos. Para testar os modelos rapidamente, vamos montar um pequeno conjunto de dados. Primeiro, geramos 1000 imagens de banana de diferentes ângulos e tamanhos usando bananas grátis de nosso escritório. Em seguida, coletamos uma série de imagens de fundo e colocamos uma imagem de banana em uma posição aleatória em cada imagem. Baixando Dataset ---------------- O conjunto de dados de detecção de banana com todas as imagens e arquivos de rótulo csv pode ser baixado diretamente da Internet. .. raw:: html
mxnetpytorch
.. raw:: html
.. code:: python %matplotlib inline import os import pandas as pd from mxnet import gluon, image, np, npx from d2l import mxnet as d2l npx.set_np() #@save d2l.DATA_HUB['banana-detection'] = (d2l.DATA_URL + 'banana-detection.zip', '5de26c8fce5ccdea9f91267273464dc968d20d72') .. raw:: html
.. raw:: html
.. code:: python %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') .. raw:: html
.. raw:: html
Lendo o Dataset --------------- Vamos ler o conjunto de dados de detecção de objetos na função ``read_data_bananas``. O conjunto de dados inclui um arquivo csv para rótulos de classe de destino e coordenadas de caixa delimitadora de verdade fundamental no formato ``corner``. Definimos ``BananasDataset`` para criar a instância do ``Dataset`` e finalmente definimos a função ``load_data_bananas`` para retornar os carregadores de dados. Não há necessidade de ler o conjunto de dados de teste em ordem aleatória. .. raw:: html
mxnetpytorch
.. raw:: html
.. code:: python #@save def read_data_bananas(is_train=True): """Read the bananas dataset images and labels.""" data_dir = d2l.download_extract('banana-detection') csv_fname = os.path.join(data_dir, 'bananas_train' if is_train else '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(image.imread( os.path.join(data_dir, 'bananas_train' if is_train else 'bananas_val', 'images', f'{img_name}'))) # Since all images have same object class i.e. category '0', # the `label` column corresponds to the only object i.e. banana # The target is as follows : (`label`, `xmin`, `ymin`, `xmax`, `ymax`) targets.append(list(target)) return images, np.expand_dims(np.array(targets), 1) / 256 #@save class BananasDataset(gluon.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' if is_train else f' validation examples')) def __getitem__(self, idx): return (self.features[idx].astype('float32').transpose(2, 0, 1), self.labels[idx]) def __len__(self): return len(self.features) #@save def load_data_bananas(batch_size): """Load the bananas dataset.""" train_iter = gluon.data.DataLoader(BananasDataset(is_train=True), batch_size, shuffle=True) val_iter = gluon.data.DataLoader(BananasDataset(is_train=False), batch_size) return (train_iter, val_iter) .. raw:: html
.. raw:: html
.. code:: python #@save def read_data_bananas(is_train=True): """Read the bananas dataset images and labels.""" data_dir = d2l.download_extract('banana-detection') csv_fname = os.path.join(data_dir, 'bananas_train' if is_train else '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}'))) # Since all images have same object class i.e. category '0', # the `label` column corresponds to the only object i.e. banana # The target is as follows : (`label`, `xmin`, `ymin`, `xmax`, `ymax`) targets.append(list(target)) return images, torch.tensor(targets).unsqueeze(1) / 256 #@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' if is_train else f' validation examples')) def __getitem__(self, idx): return (self.features[idx].float(), self.labels[idx]) def __len__(self): return len(self.features) #@save def load_data_bananas(batch_size): """Load the bananas dataset.""" 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) .. raw:: html
.. raw:: html
Abaixo, lemos um minibatch e imprimimos o formato da imagem e do *label*. A forma da imagem é a mesma da experiência anterior (tamanho do lote, número de canais, altura, largura). O formato do rótulo é (tamanho do lote, :math:`m`, 5), onde :math:`m` é igual ao número máximo de caixas delimitadoras contidas em uma única imagem no conjunto de dados. Embora o cálculo do minibatch seja muito eficiente, ele exige que cada imagem contenha o mesmo número de caixas delimitadoras para que possam ser colocadas no mesmo lote. Como cada imagem pode ter um número diferente de caixas delimitadoras, podemos adicionar caixas delimitadoras ilegais às imagens que possuem menos de :math:`m` caixas delimitadoras até que cada imagem contenha :math:`m` caixas delimitadoras. Assim, podemos ler um minibatch de imagens a cada vez. O rótulo de cada caixa delimitadora na imagem é representado por um tensor de comprimento 5. O primeiro elemento no tensor é a categoria do objeto contido na caixa delimitadora. Quando o valor é -1, a caixa delimitadora é uma caixa delimitadora ilegal para fins de preenchimento. Os quatro elementos restantes da matriz representam as coordenadas do eixo :math:`x, y` do canto superior esquerdo da caixa delimitadora e as coordenadas do eixo :math:`x, y` do canto inferior direito da caixa delimitadora (o intervalo de valores é entre 0 e 1). O conjunto de dados da banana aqui tem apenas uma caixa delimitadora por imagem, então :math:`m = 1`. .. raw:: html
mxnetpytorch
.. raw:: html
.. code:: python batch_size, edge_size = 32, 256 train_iter, _ = load_data_bananas(batch_size) batch = next(iter(train_iter)) batch[0].shape, batch[1].shape .. parsed-literal:: :class: output Downloading ../data/banana-detection.zip from http://d2l-data.s3-accelerate.amazonaws.com/banana-detection.zip... read 1000 training examples read 100 validation examples .. parsed-literal:: :class: output ((32, 3, 256, 256), (32, 1, 5)) .. raw:: html
.. raw:: html
.. code:: python batch_size, edge_size = 32, 256 train_iter, _ = load_data_bananas(batch_size) batch = next(iter(train_iter)) batch[0].shape, batch[1].shape .. parsed-literal:: :class: output Downloading ../data/banana-detection.zip from http://d2l-data.s3-accelerate.amazonaws.com/banana-detection.zip... read 1000 training examples read 100 validation examples .. parsed-literal:: :class: output (torch.Size([32, 3, 256, 256]), torch.Size([32, 1, 5])) .. raw:: html
.. raw:: html
Demonstração ------------ Temos dez imagens com caixas delimitadoras. Podemos ver que o ângulo, o tamanho e a posição da banana são diferentes em cada imagem. Claro, este é um conjunto de dados artificial simples. Na prática, os dados geralmente são muito mais complicados. .. raw:: html
mxnetpytorch
.. raw:: html
.. code:: python imgs = (batch[0][0:10].transpose(0, 2, 3, 1)) / 255 axes = d2l.show_images(imgs, 2, 5, scale=2) for ax, label in zip(axes, batch[1][0:10]): d2l.show_bboxes(ax, [label[0][1:5] * edge_size], colors=['w']) .. figure:: output_object-detection-dataset_641ef0_30_0.png .. raw:: html
.. raw:: html
.. code:: python 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]): d2l.show_bboxes(ax, [label[0][1:5] * edge_size], colors=['w']) .. figure:: output_object-detection-dataset_641ef0_33_0.png .. raw:: html
.. raw:: html
Resumo ------ - O conjunto de dados de detecção de banana que sintetizamos pode ser usado para testar modelos de detecção de objetos. - A leitura de dados para detecção de objetos é semelhante àquela para classificação de imagens. No entanto, depois de introduzirmos as caixas delimitadoras, a forma do rótulo e o aumento da imagem (por exemplo, corte aleatório) são alterados. Exercícios ---------- 1. Referindo-se à documentação do MXNet, quais são os parâmetros para os construtores das classes ``image.ImageDetIter`` e ``image.CreateDetAugmenter``? Qual é o seu significado? .. raw:: html
mxnetpytorch
.. raw:: html
`Discussões `__ .. raw:: html
.. raw:: html
`Discussões `__ .. raw:: html
.. raw:: html
.. raw:: html