Get started with the OPU

There are three ways to process data with an OPU: - lightonml with numpy.ndarray - lightonml with torch.Tensor - lightonopu with numpy.ndarray or torch.Tensor

[1]:
import numpy as np
import torch

Lightonml with numpy arrays

There is an OPUMap class in lightonml.projections.sklearn that can process numpy.ndarrays and is built to be scikit-learn compatible: it can be embedded in pipelines, cross-validated, etc.

[2]:
from lightonml.projections.sklearn import OPUMap
[3]:
numpy_data = np.random.randint(0, 2, size=(3000, 10000), dtype=np.uint8)
opumap_np = OPUMap(n_components=10000)
[4]:
output = opumap_np.transform(numpy_data)
output
[4]:
array([[ 29,  26,   5, ...,  21,  52,  98],
       [ 37,  12,  30, ...,  90, 109,  86],
       [ 10,   3,   9, ...,  36,  69,  71],
       ...,
       [ 67,  21,  13, ...,  21,  65,  37],
       [ 42,  10,  23, ...,  55, 110,  87],
       [ 69,  26,   9, ..., 106,  89, 132]], dtype=uint8)

Since we are going to use a different object to “talk” with the OPU, we have to release the resource.

[5]:
opumap_np.opu.close()

Lightonml with torch tensors

A second OPUMap interface is available in lightonml.projections.torch. In this case OPUMap behaves as a torch.nn.Module: the object can be called on data. Alternatively, it is still possible to call .transform.

Note that the optical processing is not differentiable, so this operation will break the computational graph: gradients are not propagated through the .transform method.

[6]:
from lightonml.projections.torch import OPUMap
[7]:
torch_data = torch.randint(0, 2, size=(3000, 10000), dtype=torch.uint8)
opumap_torch = OPUMap(n_components=10000)
OPU output is detached from the computational graph.
[8]:
output = opumap_torch.transform(torch_data)
output
[8]:
tensor([[  6,   3,   5,  ...,  10,  45,  79],
        [ 28,  52,  17,  ...,  22,  74, 170],
        [ 10,  40,  38,  ...,  27,  30,  52],
        ...,
        [ 36,  12,   4,  ...,  24,  54,  96],
        [ 19,  37,  39,  ...,  17, 130, 163],
        [ 10,   5,  13,  ...,  49,  94, 111]], dtype=torch.uint8)
[9]:
output = opumap_torch(torch_data)
output
[9]:
tensor([[  5,   3,   6,  ...,   9,  44,  78],
        [ 27,  52,  18,  ...,  23,  73, 168],
        [ 13,  42,  37,  ...,  25,  29,  51],
        ...,
        [ 32,  12,   5,  ...,  23,  56, 105],
        [ 17,  34,  37,  ...,  17, 137, 171],
        [ 13,   4,  17,  ...,  55, 104, 119]], dtype=torch.uint8)
[10]:
opumap_torch.opu.close()

Lightonopu with numpy arrays or torch tensors

A lower-level class is lightonopu.OPU, used internally in OPUMap classes. This class does not offer fancy features for compatibility with third-party frameworks, but it is more versatile and can accept both numpy.ndarray and torch.Tensor.

In the case of OPU, the user needs to call .transform1d if the input data is a collection of vectors, or .transform2d if it is a collection of matrices.

In OPUMap classes, .transform automatically dispatches to .transform1d or .transform2d.

[11]:
from lightonopu import OPU
[12]:
opu = OPU(n_components=10000)
[13]:
y_np = opu.transform1d(numpy_data)
y_np
[13]:
array([[ 26,  25,   5, ...,  19,  49,  98],
       [ 37,  13,  27, ...,  90, 110,  83],
       [ 13,   4,   9, ...,  35,  66,  71],
       ...,
       [ 75,  23,  14, ...,  21,  60,  38],
       [ 43,  10,  22, ...,  51, 107,  81],
       [ 71,  27,   9, ...,  91,  86, 125]], dtype=uint8)
[14]:
y_torch = opu.transform1d(torch_data)
y_torch
[14]:
tensor([[  6,   2,   5,  ...,   9,  43,  77],
        [ 27,  51,  18,  ...,  25,  73, 164],
        [ 11,  40,  39,  ...,  25,  28,  49],
        ...,
        [ 34,  12,   4,  ...,  23,  56,  94],
        [ 19,  35,  38,  ...,  16, 129, 165],
        [ 11,   5,  15,  ...,  51,  97, 113]], dtype=torch.uint8)
[15]:
data_2d = np.random.randint(0, 2, size=(3000, 900, 900), dtype=np.uint8)
y = opu.transform2d(data_2d)
y
[15]:
array([[ 95,  59,  39, ...,  75,  95, 134],
       [ 37,  13,  63, ...,  26,  90, 114],
       [ 17,   7,  40, ...,  68, 179, 179],
       ...,
       [ 64,  26,  37, ...,  47, 137,  67],
       [ 86,  47,  42, ...,  31,  81,  97],
       [ 18,  21,  30, ...,  51,  46,  46]], dtype=uint8)