Reputation: 730
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?
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
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