Skip to content

Fix: pokerdvs.py uses a deprecated dataset link and code #323

Description

@a-ayesh

Error

Traceback (most recent call last):
  File "/Users/ayesh/Desktop/t1cir/temp.py", line 3, in <module>
    poker_train = tonic.datasets.POKERDVS(save_to='./data', train=True)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ayesh/.local/share/uv/python/cpython-3.11.12-macos-aarch64-none/lib/python3.11/urllib/request.py", line 1351, in do_open
    raise URLError(err)
urllib.error.URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known>

Problem

pokerdvs.py attempts to install the dataset from https://nextcloud.lenzgregor.com/s/ which has pre-separated train and test sets. However, the link is seemingly deprecated and doesn't resolve to any downloadable resources.

This is important as NIR includes a key practical example for snnTorch to Norse (Sim2Sim) which involves downloading and loading the dataset, defining and training the model, and exporting to NIR.

Solution

The entire pokerdvs.py file's code can essentially be replaced with the code block below to get things working.
Note: This method uses the direct download link referenced in http://www2.imse-cnm.csic.es/caviar/POKERDVS.html and creates train/test pairs locally using a naive approach.

import tonic
from tonic.dataset import Dataset
from tonic.io import get_aer_events_from_file, read_aedat_header_from_file, make_structured_array
import random

def read_pokerdvs_aedat(filename):
    """Read .aedat file for POKERDVS dataset (35x35 sensor).
    
    Parameters:
        filename: Path to .aedat file
        
    Returns:
        events: numpy structured array with (t, x, y, p) ordering
    """
    data_version, data_start, _ = read_aedat_header_from_file(filename)
    all_events = get_aer_events_from_file(filename, data_version, data_start)
    
    all_addr = all_events["address"]
    t = all_events["timeStamp"]
    
    # Bit encoding for 35x35 sensor: x in bits 8-13, y in bits 1-6, p in bit 0
    # This pattern gives x range 0-31, y range 0-31 (valid for 35x35)
    x = (all_addr >> 8) & 0x3F  # 6 bits for x (0-63, but we'll clip to 0-34)
    y = (all_addr >> 1) & 0x3F  # 6 bits for y (0-63, but we'll clip to 0-34)
    p = all_addr & 1
    
    # Clip to sensor size (35x35)
    x = np.clip(x, 0, 34)
    y = np.clip(y, 0, 34)
    
    # Create structured array with (t, x, y, p) ordering as expected by POKERDVS
    dtype = np.dtype([("t", int), ("x", int), ("y", int), ("p", int)])
    events = make_structured_array(t, x, y, p, dtype=dtype)
    
    return events


class POKERDVS(Dataset):
    """Custom POKERDVS dataset class that works with the new data source.
    
    Events have (txyp) ordering.
    """
    
    classes = ["cl", "he", "di", "sp"]
    int_classes = {"cl": 0, "he": 1, "di": 2, "sp": 3}
    sensor_size = (35, 35, 2)
    dtype = np.dtype([("t", int), ("x", int), ("y", int), ("p", int)])
    ordering = dtype.names
    
    def __init__(
        self,
        save_to: str,
        train: bool = True,
        transform=None,
        target_transform=None,
        transforms=None,
        train_split_ratio: float = 0.8,
        seed: int = 42,
    ):
        super().__init__(
            save_to,
            transform=transform,
            target_transform=target_transform,
            transforms=transforms,
        )
        
        self.train = train
        self.train_split_ratio = train_split_ratio
        
        # Set up paths
        self.poker_dvs_dir = os.path.join(save_to, "poker_dvs")
        
        # Download and extract if needed
        if not os.path.exists(self.poker_dvs_dir):
            self._download_and_extract()
        
        # Load all files
        self._load_files(seed)
    
    def _download_and_extract(self):
        """Download and extract the dataset."""
        url = "http://www2.imse-cnm.csic.es/caviar/POKER_DVS/poker_dvs.tar.gz"
        os.makedirs(self.location_on_system, exist_ok=True)
        tar_path = os.path.join(self.location_on_system, "poker_dvs.tar.gz")
        
        if not os.path.exists(tar_path):
            print("Downloading poker_dvs.tar.gz...")
            urllib.request.urlretrieve(url, tar_path)
            print("Download complete.")
        
        print("Extracting poker_dvs.tar.gz...")
        os.makedirs(self.poker_dvs_dir, exist_ok=True)
        with tarfile.open(tar_path, "r:gz") as tar:
            tar.extractall(path=self.poker_dvs_dir)
        print("Extraction complete.")
    
    def _load_files(self, seed: int):
        """Load all .aedat files and split into train/test."""
        # Collect all files with their labels
        file_label_pairs = []
        
        for filename in sorted(os.listdir(self.poker_dvs_dir)):
            if not filename.endswith(".aedat"):
                continue
            
            # Extract class from filename
            if filename.startswith("xclub"):
                label = self.int_classes["cl"]
            elif filename.startswith("xheart"):
                label = self.int_classes["he"]
            elif filename.startswith("xdiamond"):
                label = self.int_classes["di"]
            elif filename.startswith("xspade"):
                label = self.int_classes["sp"]
            else:
                continue
            
            filepath = os.path.join(self.poker_dvs_dir, filename)
            file_label_pairs.append((filepath, label))
        
        # Split into train/test
        random.seed(seed)
        random.shuffle(file_label_pairs)
        
        split_idx = int(len(file_label_pairs) * self.train_split_ratio)
        
        if self.train:
            file_label_pairs = file_label_pairs[:split_idx]
        else:
            file_label_pairs = file_label_pairs[split_idx:]
        
        # Store file paths and labels (lazy loading)
        self.file_paths = [fp for fp, _ in file_label_pairs]
        self.targets = [label for _, label in file_label_pairs]
    
    def __getitem__(self, index):
        """Returns a tuple of (events, target)."""
        filepath = self.file_paths[index]
        events = read_pokerdvs_aedat(filepath)
        target = self.targets[index]
        
        if self.transform is not None:
            events = self.transform(events)
        if self.target_transform is not None:
            target = self.target_transform(target)
        if self.transforms is not None:
            events, target = self.transforms(events, target)
        
        return events, target
    
    def __len__(self):
        return len(self.file_paths)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions