def to_device(data, device=None, dtype=None, non_blocking=False, copy=False):
    'Change the device of object recursively'
    if isinstance(data, dict):
        return {k: to_device(v, device, dtype, non_blocking, copy) for (k, v) in data.items()}
    elif (dataclasses.is_dataclass(data) and (not isinstance(data, type))):
        return type(data)(*[to_device(v, device, dtype, non_blocking, copy) for v in dataclasses.astuple(data)])
    elif (isinstance(data, tuple) and (type(data) is not tuple)):
        return type(data)(*[to_device(o, device, dtype, non_blocking, copy) for o in data])
    elif isinstance(data, (list, tuple)):
        return type(data)((to_device(v, device, dtype, non_blocking, copy) for v in data))
    elif isinstance(data, np.ndarray):
        return to_device(torch.from_numpy(data), device, dtype, non_blocking, copy)
    elif isinstance(data, torch.Tensor):
        return data.to(device, dtype, non_blocking, copy)
    else:
        return data
Change the device of object recursively
def to_device(data, device=None, dtype=None, non_blocking=False, copy=False):
    
    if isinstance(data, dict):
        return {k: to_device(v, device, dtype, non_blocking, copy) for (k, v) in data.items()}
    elif (dataclasses.is_dataclass(data) and (not isinstance(data, type))):
        return type(data)(*[to_device(v, device, dtype, non_blocking, copy) for v in dataclasses.astuple(data)])
    elif (isinstance(data, tuple) and (type(data) is not tuple)):
        return type(data)(*[to_device(o, device, dtype, non_blocking, copy) for o in data])
    elif isinstance(data, (list, tuple)):
        return type(data)((to_device(v, device, dtype, non_blocking, copy) for v in data))
    elif isinstance(data, np.ndarray):
        return to_device(torch.from_numpy(data), device, dtype, non_blocking, copy)
    elif isinstance(data, torch.Tensor):
        return data.to(device, dtype, non_blocking, copy)
    else:
        return data