user3002166
user3002166

Reputation: 730

fiftyone dataset with pytorch dataloader

I want to do an initial training on the bounding boxes from a bigger, public dataset - fiftyone looks liek a decent starting point, but I'm having some issues with getting it to work with pytorch - I think it must be something minor that I'm missing here, I tried following the official github. I start to suspect the examples in this github is outdated somehow, because even when I try to use the example class it fails. The issue is with the access methods, where the only quasi numerical option is dataset.first(), dataset.last()

The issue: The dataloader is throwing an exception KeyError: 'Accessing samples by numeric index is not supported. Use sample IDs, filepaths, slices, boolean arrays, or a boolean ViewExpression instead'
I have modified the example slightly, just so it only uses car subset:

class FiftyOneDS(torch.utils.data.Dataset):
    def __init__(
                self
                , fiftyone_ds
                , transforms = None
                , gt_field = "ground_truth"
                , classes = None
    ):
        self.samples = fiftyone_ds
        self.transforms = transforms
        self.gt_field = gt_field
        self.classes = classes  # don't care
        self.img_paths = self.samples.values("filepath")
        
    def __getitem__(self, idx):
        img_path = self.img_paths[idx]
        sample = self.samples[idx]
        metadata = sample.metadata
        img = Image.open(img_path).convert("RGB")
        boxes = []
        labels = []
        detections = sample[self.gt_field].detections
        for det in detections:
            if det["label"] != "car":
                continue
            category_id = self.labels_map_rev[det.label]
            coco_obj = fouc.COCOObject.from_label(
                det, metadata, category_id=category_id,
            )
            x, y, w, h = coco_obj.bbox
            boxes.append([x, y, x + w, y + h])
            labels.append(coco_obj.category_id)
        target = {}
        target["boxes"] = torch.as_tensor(boxes, dtype=torch.float32)
        target["labels"] = torch.as_tensor(labels, dtype=torch.int64)
        target["image_id"] = torch.as_tensor([idx])
        if self.transforms is not None:
            img, target = self.transforms(img, target)
        return img, target
    
        
    def __len__(self):
        return len(self.img_paths)

Then use the dataset via a snippet (this appears to be working ok):

carset = FiftyOneDS(dataset)
print("type:", type(torch_dataset_test))
# type: <class 'fiftyone.core.view.DatasetView'>
print("first elem:", torch_dataset_test[0])
# KeyError: 'Accessing samples by numeric index is not supported. Use sample IDs, filepaths, slices, boolean arrays, or a boolean ViewExpression instead'

How do I rewrite my dataset class to work with pytorch dataloaders?

UPDATE:

The solution, but seems dirty to me: (writing from memory) The key part is storing the filename list as a list and referencing from there

class FiftyOneDS(torch.utils.data.Dataset):
    def __init__(ds, <args>):
        self.samples = ds
        self._impaths = self.samples.values("filepath")

    def __getitem__(self, idx):
        impath = self._impaths[idx]
        img = Image.open(img_path).convert("RGB")


Upvotes: 1

Views: 187

Answers (1)

Daniel Gural
Daniel Gural

Reputation: 1

FiftyOne doesn't support index slicing as the error is suggesting. The solution can be passing in the filepath instead.

sample = self.samples[img_path]

Should do the trick. Read more here https://docs.voxel51.com/user_guide/using_views.html#slicing

Upvotes: 0

Related Questions