How do I wrap my own recordings?#

If you have your own recordings on disk and want to make use of Tonic for quick dataloading and applying transformations, then you can wrap them in a custom class. The easiest option is to make use of a torchvision DatasetFolder class. If that doesn’t apply in your case, you can write your own class, where you provide a minimum set of methods __init__, __getitem__ and __len__ and you are good to go. This notebook is about a template class that reads event recordings from local numpy files. We’ll start by creating some dummy files.

import numpy as np
from tonic import Dataset, transforms

sensor_size = (200, 100, 2)
n_recordings = 10


def create_random_input(
    sensor_size=sensor_size,
    n_events=10000,
    dtype=np.dtype([("x", int), ("y", int), ("t", int), ("p", int)]),
):
    events = np.zeros(n_events, dtype=dtype)
    events["x"] = np.random.rand(n_events) * sensor_size[0]
    events["y"] = np.random.rand(n_events) * sensor_size[1]
    events["p"] = np.random.rand(n_events) * sensor_size[2]
    events["t"] = np.sort(np.random.rand(n_events) * 1e6)
    return events


[
    np.save(f"../tutorials/data/recording{i}.npy", create_random_input())
    for i in range(n_recordings)
];
class MyRecordings(Dataset):
    sensor_size = (
        200,
        100,
        2,
    )  # the sensor size of the event camera or the number of channels of the silicon cochlear that was used
    ordering = (
        "xytp"  # the order in which your event channels are provided in your recordings
    )

    def __init__(
        self,
        train=True,
        transform=None,
        target_transform=None,
    ):
        super(MyRecordings, self).__init__(
            save_to='./', transform=transform, target_transform=target_transform
        )
        self.train = train

        # replace the strings with your training/testing file locations or pass as an argument
        if train:
            self.filenames = [
                f"../tutorials/data/recording{i}.npy" for i in range(n_recordings)
            ]
        else:
            raise NotImplementedError

    def __getitem__(self, index):
        events = np.load(self.filenames[index])

        if self.transform is not None:
            events = self.transform(events)

        return events

    def __len__(self):
        return len(self.filenames)

Depending on the format of your recording files, your implementation might look a bit different. Oftentimes you will have a separate file for each recording. Or you might want to also load some image or IMU data. You can have a look at already existing datasets for some inspiration. :class:DVSGesture loads from multiple numpy files, :class:DAVISDATA or :class:VPR load events and other data from rosbag files, :class:NCARS loads eventstream files and :class:ASLDVS reads from matlab files.

Afterwards you can call certain samples from the dataset or use a DataLoader wrapper, which will make use of __getitem__ and __len__ functions internally.

dataset = MyRecordings(train=True, transform=transforms.NumpyAsType(int))
events = dataset[5]

import torch

dataloader = torch.utils.data.DataLoader(dataset, shuffle=True)
events = next(iter(dataloader))
print(events)
tensor([[[   196,     59,     71,      1],
         [     6,     34,     74,      1],
         [    12,     90,    238,      0],
         ...,
         [   158,     74, 999640,      1],
         [   167,      7, 999838,      0],
         [   199,     84, 999989,      0]]])